ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel.c
Revision: 8385
Committed: Fri Mar 16 20:09:55 2018 UTC (7 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 31536 byte(s)
Log Message:
- Rip out mempool

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 8279 * Copyright (c) 1997-2018 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * USA
20     */
21    
22     /*! \file channel.c
23     * \brief Responsible for managing channels, members, bans and topics
24 knight 31 * \version $Id$
25 adx 30 */
26    
27     #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "channel.h"
30     #include "channel_mode.h"
31     #include "client.h"
32     #include "hash.h"
33 michael 1632 #include "conf.h"
34 michael 7234 #include "conf_resv.h"
35 michael 371 #include "hostmask.h"
36 adx 30 #include "irc_string.h"
37     #include "ircd.h"
38     #include "numeric.h"
39 michael 3347 #include "server.h"
40 adx 30 #include "send.h"
41     #include "event.h"
42     #include "memory.h"
43 michael 3347 #include "misc.h"
44 adx 30
45 michael 3235
46 michael 3944 dlink_list channel_list;
47 adx 30
48    
49 michael 3308 /*! \brief Adds a user to a channel by adding another link to the
50 adx 30 * channels member chain.
51 michael 3308 * \param chptr Pointer to channel to add client to
52 michael 6681 * \param client_p Pointer to client (who) to add
53 michael 3308 * \param flags Flags for chanops etc
54     * \param flood_ctrl Whether to count this join in flood calculations
55 adx 30 */
56     void
57 michael 6681 add_user_to_channel(struct Channel *chptr, struct Client *client_p,
58 adx 30 unsigned int flags, int flood_ctrl)
59     {
60 michael 6681 assert(IsClient(client_p));
61 michael 5590
62 michael 7779 if (GlobalSetOptions.joinfloodtime)
63 adx 30 {
64     if (flood_ctrl)
65 michael 3250 ++chptr->number_joined;
66 adx 30
67     chptr->number_joined -= (CurrentTime - chptr->last_join_time) *
68     (((float)GlobalSetOptions.joinfloodcount) /
69     (float)GlobalSetOptions.joinfloodtime);
70    
71     if (chptr->number_joined <= 0)
72     {
73     chptr->number_joined = 0;
74     ClearJoinFloodNoticed(chptr);
75     }
76     else if (chptr->number_joined >= GlobalSetOptions.joinfloodcount)
77     {
78     chptr->number_joined = GlobalSetOptions.joinfloodcount;
79    
80     if (!IsSetJoinFloodNoticed(chptr))
81     {
82     SetJoinFloodNoticed(chptr);
83 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
84 adx 30 "Possible Join Flooder %s on %s target: %s",
85 michael 7997 client_get_name(client_p, HIDE_IP),
86 michael 6681 client_p->servptr->name, chptr->name);
87 adx 30 }
88     }
89    
90     chptr->last_join_time = CurrentTime;
91     }
92    
93 michael 8385 struct Membership *member = xcalloc(sizeof(*member));
94 michael 6681 member->client_p = client_p;
95 michael 4815 member->chptr = chptr;
96     member->flags = flags;
97 adx 30
98 michael 4815 dlinkAdd(member, &member->channode, &chptr->members);
99 michael 4170
100 michael 6681 if (MyConnect(client_p))
101 michael 4815 dlinkAdd(member, &member->locchannode, &chptr->locmembers);
102 michael 4170
103 michael 6681 dlinkAdd(member, &member->usernode, &client_p->channel);
104 adx 30 }
105    
106 michael 3308 /*! \brief Deletes an user from a channel by removing a link in the
107 adx 30 * channels member chain.
108 michael 3308 * \param member Pointer to Membership struct
109 adx 30 */
110     void
111     remove_user_from_channel(struct Membership *member)
112     {
113 michael 4977 struct Client *const client_p = member->client_p;
114     struct Channel *const chptr = member->chptr;
115 adx 30
116     dlinkDelete(&member->channode, &chptr->members);
117 michael 4170
118     if (MyConnect(client_p))
119     dlinkDelete(&member->locchannode, &chptr->locmembers);
120    
121 adx 30 dlinkDelete(&member->usernode, &client_p->channel);
122    
123 michael 8385 xfree(member);
124 adx 30
125 michael 1011 if (chptr->members.head == NULL)
126 michael 6373 channel_free(chptr);
127 adx 30 }
128    
129 michael 6373 /* channel_send_members()
130 adx 30 *
131     * inputs -
132     * output - NONE
133     * side effects -
134     */
135     static void
136 michael 6373 channel_send_members(struct Client *client_p, const struct Channel *chptr,
137 michael 7797 const char *modebuf, const char *parabuf)
138 adx 30 {
139 michael 8059 dlink_node *node;
140 michael 4388 char buf[IRCD_BUFSIZE] = "";
141 adx 30 int tlen; /* length of text to append */
142     char *t, *start; /* temp char pointer */
143    
144 michael 6782 start = t = buf + snprintf(buf, sizeof(buf), ":%s SJOIN %ju %s %s %s:",
145     me.id, chptr->creationtime,
146 michael 4618 chptr->name, modebuf, parabuf);
147 adx 30
148 michael 4800 DLINK_FOREACH(node, chptr->members.head)
149 adx 30 {
150 michael 4815 const struct Membership *member = node->data;
151 adx 30
152 michael 4815 tlen = strlen(member->client_p->id) + 1; /* +1 for space */
153 adx 30
154 michael 4815 if (member->flags & CHFL_CHANOP)
155 michael 3250 ++tlen;
156 michael 4815 if (member->flags & CHFL_HALFOP)
157 michael 3250 ++tlen;
158 michael 4815 if (member->flags & CHFL_VOICE)
159 michael 3250 ++tlen;
160 adx 30
161 michael 3250 /*
162     * Space will be converted into CR, but we also need space for LF..
163 michael 3782 * That's why we use '- 1' here -adx
164 michael 3250 */
165 michael 1330 if (t + tlen - buf > IRCD_BUFSIZE - 1)
166 adx 30 {
167 michael 3250 *(t - 1) = '\0'; /* Kill the space and terminate the string */
168 adx 30 sendto_one(client_p, "%s", buf);
169     t = start;
170     }
171    
172 michael 4815 if (member->flags & CHFL_CHANOP)
173 michael 3140 *t++ = '@';
174 michael 4815 if (member->flags & CHFL_HALFOP)
175 michael 3140 *t++ = '%';
176 michael 4815 if (member->flags & CHFL_VOICE)
177 adx 356 *t++ = '+';
178 adx 30
179 michael 4815 strcpy(t, member->client_p->id);
180 michael 3135
181 adx 30 t += strlen(t);
182     *t++ = ' ';
183     }
184    
185 michael 3250 /* Should always be non-NULL unless we have a kind of persistent channels */
186 michael 3235 if (chptr->members.head)
187 michael 3250 t--; /* Take the space out */
188 adx 30 *t = '\0';
189     sendto_one(client_p, "%s", buf);
190     }
191    
192 michael 3308 /*! \brief Sends +b/+e/+I
193     * \param client_p Client pointer to server
194     * \param chptr Pointer to channel
195 michael 3997 * \param list Pointer to list of modes to send
196 michael 3308 * \param flag Char flag flagging type of mode. Currently this can be 'b', e' or 'I'
197 adx 30 */
198     static void
199 michael 6373 channel_send_mask_list(struct Client *client_p, const struct Channel *chptr,
200     const dlink_list *list, const char flag)
201 adx 30 {
202 michael 7687 dlink_node *node;
203 michael 4388 char mbuf[IRCD_BUFSIZE] = "";
204 michael 3215 char pbuf[IRCD_BUFSIZE] = "";
205 michael 3523 int tlen, mlen, cur_len;
206 michael 3144 char *pp = pbuf;
207 adx 30
208 michael 7012 if (!dlink_list_length(list))
209 adx 30 return;
210    
211 michael 6782 mlen = snprintf(mbuf, sizeof(mbuf), ":%s BMASK %ju %s %c :", me.id,
212     chptr->creationtime, chptr->name, flag);
213 michael 3135 cur_len = mlen;
214 adx 30
215 michael 4800 DLINK_FOREACH(node, list->head)
216 adx 30 {
217 michael 4815 const struct Ban *ban = node->data;
218 adx 30
219 michael 4815 tlen = ban->len + 3; /* +3 for ! + @ + space */
220 adx 30
221     /*
222 michael 3996 * Send buffer and start over if we cannot fit another ban
223 adx 30 */
224 michael 3135 if (cur_len + (tlen - 1) > IRCD_BUFSIZE - 2)
225 adx 30 {
226 michael 3250 *(pp - 1) = '\0'; /* Get rid of trailing space on buffer */
227 michael 4388 sendto_one(client_p, "%s%s", mbuf, pbuf);
228 adx 30
229 michael 3135 cur_len = mlen;
230 adx 30 pp = pbuf;
231     }
232    
233 michael 4815 pp += sprintf(pp, "%s!%s@%s ", ban->name, ban->user, ban->host);
234 adx 30 cur_len += tlen;
235     }
236    
237 michael 3250 *(pp - 1) = '\0'; /* Get rid of trailing space on buffer */
238 michael 4388 sendto_one(client_p, "%s%s", mbuf, pbuf);
239 adx 30 }
240    
241 michael 3308 /*! \brief Send "client_p" a full list of the modes for channel chptr
242     * \param client_p Pointer to client client_p
243     * \param chptr Pointer to channel pointer
244 adx 30 */
245     void
246 michael 6373 channel_send_modes(struct Client *client_p, struct Channel *chptr)
247 adx 30 {
248 michael 3145 char modebuf[MODEBUFLEN] = "";
249     char parabuf[MODEBUFLEN] = "";
250    
251 adx 30 channel_modes(chptr, client_p, modebuf, parabuf);
252 michael 6373 channel_send_members(client_p, chptr, modebuf, parabuf);
253 adx 30
254 michael 6373 channel_send_mask_list(client_p, chptr, &chptr->banlist, 'b');
255     channel_send_mask_list(client_p, chptr, &chptr->exceptlist, 'e');
256     channel_send_mask_list(client_p, chptr, &chptr->invexlist, 'I');
257 adx 30 }
258    
259 michael 3308 /*! \brief Check channel name for invalid characters
260     * \param name Pointer to channel name string
261     * \param local Indicates whether it's a local or remote creation
262 michael 632 * \return 0 if invalid, 1 otherwise
263 adx 30 */
264     int
265 michael 6373 channel_check_name(const char *name, const int local)
266 adx 30 {
267 michael 632 const char *p = name;
268 michael 3421
269 michael 5590 assert(!EmptyString(p));
270 adx 30
271 michael 632 if (!IsChanPrefix(*p))
272     return 0;
273 adx 30
274 db 633 if (!local || !ConfigChannel.disable_fake_channels)
275 michael 632 {
276     while (*++p)
277 db 634 if (!IsChanChar(*p))
278 michael 632 return 0;
279     }
280     else
281     {
282     while (*++p)
283 db 634 if (!IsVisibleChanChar(*p))
284 michael 632 return 0;
285     }
286    
287 michael 3421 return p - name <= CHANNELLEN;
288 adx 30 }
289    
290     void
291 michael 4815 remove_ban(struct Ban *ban, dlink_list *list)
292 adx 30 {
293 michael 4815 dlinkDelete(&ban->node, list);
294 michael 8385 xfree(ban);
295 adx 30 }
296    
297 michael 6373 /* channel_free_mask_list()
298 adx 30 *
299     * inputs - pointer to dlink_list
300     * output - NONE
301     * side effects -
302     */
303 michael 6373 static void
304     channel_free_mask_list(dlink_list *list)
305 adx 30 {
306 michael 7266 while (list->head)
307     {
308     struct Ban *ban = list->head->data;
309     remove_ban(ban, list);
310     }
311 adx 30 }
312    
313 michael 4618 /*! \brief Get Channel block for name (and allocate a new channel
314 adx 30 * block, if it didn't exist before)
315 michael 4618 * \param name Channel name
316 michael 3308 * \return Channel block
317 adx 30 */
318     struct Channel *
319 michael 6373 channel_make(const char *name)
320 adx 30 {
321 michael 4618 assert(!EmptyString(name));
322 adx 30
323 michael 8385 struct Channel *chptr = xcalloc(sizeof(*chptr));
324 michael 3308 /* Doesn't hurt to set it here */
325 michael 4818 chptr->creationtime = CurrentTime;
326 michael 632 chptr->last_join_time = CurrentTime;
327 adx 30
328 michael 8027 /* Cache channel name length to avoid repetitive strlen() calls. */
329 michael 6982 chptr->name_len = strlcpy(chptr->name, name, sizeof(chptr->name));
330     if (chptr->name_len >= sizeof(chptr->name))
331     chptr->name_len = sizeof(chptr->name) - 1;
332 michael 6990
333 michael 3944 dlinkAdd(chptr, &chptr->node, &channel_list);
334 adx 30 hash_add_channel(chptr);
335    
336     return chptr;
337     }
338    
339 michael 3308 /*! \brief Walk through this channel, and destroy it.
340     * \param chptr Channel pointer
341 adx 30 */
342     void
343 michael 6373 channel_free(struct Channel *chptr)
344 adx 30 {
345 michael 7762 clear_invite_list(&chptr->invites);
346 adx 30
347 michael 3308 /* Free ban/exception/invex lists */
348 michael 6373 channel_free_mask_list(&chptr->banlist);
349     channel_free_mask_list(&chptr->exceptlist);
350     channel_free_mask_list(&chptr->invexlist);
351 adx 30
352 michael 3944 dlinkDelete(&chptr->node, &channel_list);
353 adx 30 hash_del_channel(chptr);
354    
355 michael 8385 xfree(chptr);
356 adx 30 }
357    
358     /*!
359 michael 3308 * \param chptr Pointer to channel
360     * \return String pointer "=" if public, "@" if secret else "*"
361 adx 30 */
362     static const char *
363 michael 1013 channel_pub_or_secret(const struct Channel *chptr)
364 adx 30 {
365     if (SecretChannel(chptr))
366     return "@";
367     if (PrivateChannel(chptr))
368     return "*";
369     return "=";
370     }
371    
372     /*! \brief lists all names on given channel
373 michael 6681 * \param client_p Pointer to client struct requesting names
374 michael 3308 * \param chptr Pointer to channel block
375     * \param show_eon Show RPL_ENDOFNAMES numeric or not
376 adx 30 * (don't want it with /names with no params)
377     */
378     void
379 michael 6681 channel_member_names(struct Client *client_p, struct Channel *chptr,
380 adx 30 int show_eon)
381     {
382 michael 7687 dlink_node *node;
383 michael 4388 char buf[IRCD_BUFSIZE + 1] = "";
384 adx 30 char *t = NULL, *start = NULL;
385     int tlen = 0;
386 michael 6681 const int is_member = IsMember(client_p, chptr);
387     const int multi_prefix = HasCap(client_p, CAP_MULTI_PREFIX) != 0;
388     const int uhnames = HasCap(client_p, CAP_UHNAMES) != 0;
389 adx 30
390 michael 6681 assert(IsClient(client_p));
391 michael 5590
392 adx 30 if (PubChannel(chptr) || is_member)
393     {
394 michael 4388 t = buf + snprintf(buf, sizeof(buf), numeric_form(RPL_NAMREPLY),
395 michael 6681 me.name, client_p->name,
396 michael 4618 channel_pub_or_secret(chptr), chptr->name);
397 adx 30 start = t;
398    
399 michael 4800 DLINK_FOREACH(node, chptr->members.head)
400 adx 30 {
401 michael 4815 const struct Membership *member = node->data;
402 adx 30
403 michael 4815 if (HasUMode(member->client_p, UMODE_INVISIBLE) && !is_member)
404 adx 30 continue;
405    
406 michael 2910 if (!uhnames)
407 michael 4815 tlen = strlen(member->client_p->name) + 1; /* +1 for space */
408 michael 2910 else
409 michael 4815 tlen = strlen(member->client_p->name) + strlen(member->client_p->username) +
410     strlen(member->client_p->host) + 3; /* +3 for ! + @ + space */
411 adx 30
412 michael 506 if (!multi_prefix)
413     {
414 michael 4815 if (member->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
415 michael 506 ++tlen;
416     }
417     else
418     {
419 michael 4815 if (member->flags & CHFL_CHANOP)
420 michael 506 ++tlen;
421 michael 4815 if (member->flags & CHFL_HALFOP)
422 michael 506 ++tlen;
423 michael 4815 if (member->flags & CHFL_VOICE)
424 michael 506 ++tlen;
425     }
426    
427 michael 4388 if (t + tlen - buf > IRCD_BUFSIZE - 2)
428 adx 30 {
429     *(t - 1) = '\0';
430 michael 6681 sendto_one(client_p, "%s", buf);
431 adx 30 t = start;
432     }
433    
434 michael 2910 if (!uhnames)
435 michael 4815 t += sprintf(t, "%s%s ", get_member_status(member, multi_prefix),
436     member->client_p->name);
437 michael 2910 else
438 michael 4815 t += sprintf(t, "%s%s!%s@%s ", get_member_status(member, multi_prefix),
439     member->client_p->name, member->client_p->username,
440     member->client_p->host);
441 adx 30 }
442    
443 michael 3215 if (tlen)
444 adx 30 {
445     *(t - 1) = '\0';
446 michael 6681 sendto_one(client_p, "%s", buf);
447 adx 30 }
448     }
449    
450     if (show_eon)
451 michael 6681 sendto_one_numeric(client_p, &me, RPL_ENDOFNAMES, chptr->name);
452 adx 30 }
453    
454 michael 7549 static struct Invite *
455     find_invite(struct Channel *chptr, struct Client *client_p)
456     {
457     dlink_node *node, *node_next;
458     dlink_list *list;
459    
460 michael 7793 /* Take the shortest of the two lists */
461 michael 7549 if (dlink_list_length(&client_p->connection->invited) < dlink_list_length(&chptr->invites))
462     list = &client_p->connection->invited;
463     else
464     list = &chptr->invites;
465    
466     DLINK_FOREACH_SAFE(node, node_next, list->head)
467     {
468     struct Invite *invite = node->data;
469    
470 michael 7793 if (ConfigChannel.invite_expire_time &&
471     ConfigChannel.invite_expire_time + invite->when < CurrentTime)
472     del_invite(invite);
473     else if (invite->chptr == chptr && invite->client_p == client_p)
474 michael 7549 return invite;
475     }
476    
477     return NULL;
478     }
479    
480 michael 3308 /*! \brief Adds client to invite list
481 michael 6681 * \param chptr Pointer to channel block
482     * \param client_p Pointer to client to add invite to
483 adx 30 */
484     void
485 michael 6681 add_invite(struct Channel *chptr, struct Client *client_p)
486 adx 30 {
487 michael 8024 struct Invite *invite = find_invite(chptr, client_p);
488     if (invite)
489 michael 7549 del_invite(invite);
490 adx 30
491 michael 8385 invite = xcalloc(sizeof(*invite));
492 michael 7549 invite->client_p = client_p;
493     invite->chptr = chptr;
494     invite->when = CurrentTime;
495    
496 michael 7542 /* Delete last link in chain if the list is max length */
497     while (dlink_list_length(&client_p->connection->invited) &&
498 michael 7766 dlink_list_length(&client_p->connection->invited) >= ConfigChannel.max_invites)
499 michael 7549 del_invite(client_p->connection->invited.tail->data);
500 adx 30
501 michael 3308 /* Add client to channel invite list */
502 michael 7549 dlinkAdd(invite, &invite->chan_node, &chptr->invites);
503 adx 30
504 michael 3308 /* Add channel to the end of the client invite list */
505 michael 7549 dlinkAdd(invite, &invite->user_node, &client_p->connection->invited);
506 adx 30 }
507    
508     /*! \brief Delete Invite block from channel invite list
509     * and client invite list
510 michael 7549 * \param invite Pointer to Invite struct
511 adx 30 */
512     void
513 michael 7549 del_invite(struct Invite *invite)
514 adx 30 {
515 michael 7549 dlinkDelete(&invite->user_node, &invite->client_p->connection->invited);
516     dlinkDelete(&invite->chan_node, &invite->chptr->invites);
517 adx 30
518 michael 7549 /* Release memory pointed to by 'invite' */
519 michael 8385 xfree(invite);
520 adx 30 }
521    
522 michael 7762 /*! \brief Removes and frees all Invite blocks from a list
523     * \param list Pointer to a dlink_list
524 michael 4811 */
525     void
526 michael 7762 clear_invite_list(dlink_list *list)
527 michael 4811 {
528 michael 7762 while (list->head)
529     del_invite(list->head->data);
530 michael 4811 }
531    
532 adx 30 /* get_member_status()
533     *
534     * inputs - pointer to struct Membership
535     * - YES if we can combine different flags
536     * output - string either @, +, % or "" depending on whether
537     * chanop, voiced or user
538     * side effects -
539     *
540     * NOTE: Returned string is usually a static buffer
541 michael 7997 * (like in client_get_name)
542 adx 30 */
543     const char *
544 michael 4815 get_member_status(const struct Membership *member, const int combine)
545 adx 30 {
546 michael 6904 static char buffer[CMEMBER_STATUS_FLAGS_LEN + 1]; /* +1 for \0 */
547 michael 1902 char *p = buffer;
548 adx 30
549 michael 4815 if (member->flags & CHFL_CHANOP)
550 adx 30 {
551     if (!combine)
552     return "@";
553     *p++ = '@';
554     }
555    
556 michael 4815 if (member->flags & CHFL_HALFOP)
557 adx 30 {
558     if (!combine)
559     return "%";
560     *p++ = '%';
561     }
562    
563 michael 4815 if (member->flags & CHFL_VOICE)
564 adx 30 *p++ = '+';
565     *p = '\0';
566    
567     return buffer;
568     }
569    
570     /*!
571 michael 6681 * \param client_p Pointer to Client to check
572     * \param list Pointer to ban list to search
573 adx 30 * \return 1 if ban found for given n!u\@h mask, 0 otherwise
574     */
575     static int
576 michael 7345 find_bmask(const struct Client *client_p, const dlink_list *list)
577 adx 30 {
578 michael 7687 dlink_node *node;
579 adx 30
580 michael 4800 DLINK_FOREACH(node, list->head)
581 adx 30 {
582 michael 4815 const struct Ban *ban = node->data;
583 adx 30
584 michael 6681 if (!match(ban->name, client_p->name) && !match(ban->user, client_p->username))
585 michael 371 {
586 michael 4815 switch (ban->type)
587 michael 371 {
588     case HM_HOST:
589 michael 6681 if (!match(ban->host, client_p->host) || !match(ban->host, client_p->sockhost))
590 michael 371 return 1;
591     break;
592     case HM_IPV4:
593 michael 6681 if (client_p->connection->aftype == AF_INET)
594     if (match_ipv4(&client_p->connection->ip, &ban->addr, ban->bits))
595 michael 371 return 1;
596     break;
597     case HM_IPV6:
598 michael 6681 if (client_p->connection->aftype == AF_INET6)
599     if (match_ipv6(&client_p->connection->ip, &ban->addr, ban->bits))
600 michael 371 return 1;
601     break;
602     default:
603     assert(0);
604     }
605     }
606 adx 30 }
607    
608     return 0;
609     }
610    
611     /*!
612 michael 6681 * \param chptr Pointer to channel block
613     * \param client_p Pointer to client to check access fo
614 adx 30 * \return 0 if not banned, 1 otherwise
615     */
616     int
617 michael 6681 is_banned(const struct Channel *chptr, const struct Client *client_p)
618 adx 30 {
619 michael 6681 if (find_bmask(client_p, &chptr->banlist))
620     if (!find_bmask(client_p, &chptr->exceptlist))
621 michael 632 return 1;
622 adx 30
623 michael 632 return 0;
624 adx 30 }
625    
626 michael 3308 /*! Tests if a client can join a certain channel
627 michael 6681 * \param client_p Pointer to client attempting to join
628 michael 3308 * \param chptr Pointer to channel
629     * \param key Key sent by client attempting to join if present
630 adx 30 * \return ERR_BANNEDFROMCHAN, ERR_INVITEONLYCHAN, ERR_CHANNELISFULL
631     * or 0 if allowed to join.
632     */
633 michael 6881 static int
634 michael 7549 can_join(struct Client *client_p, struct Channel *chptr, const char *key)
635 adx 30 {
636 michael 8044 if (HasCMode(chptr, MODE_SSLONLY) && !HasUMode(client_p, UMODE_SSL))
637 michael 1150 return ERR_SSLONLYCHAN;
638    
639 michael 8044 if (HasCMode(chptr, MODE_REGONLY) && !HasUMode(client_p, UMODE_REGISTERED))
640 michael 1173 return ERR_NEEDREGGEDNICK;
641    
642 michael 8044 if (HasCMode(chptr, MODE_OPERONLY) && !HasUMode(client_p, UMODE_OPER))
643 michael 1150 return ERR_OPERONLYCHAN;
644    
645 michael 8044 if (HasCMode(chptr, MODE_INVITEONLY))
646 michael 7549 if (!find_invite(chptr, client_p))
647 michael 6681 if (!find_bmask(client_p, &chptr->invexlist))
648 adx 30 return ERR_INVITEONLYCHAN;
649    
650 michael 1430 if (chptr->mode.key[0] && (!key || strcmp(chptr->mode.key, key)))
651 adx 30 return ERR_BADCHANNELKEY;
652    
653     if (chptr->mode.limit && dlink_list_length(&chptr->members) >=
654     chptr->mode.limit)
655     return ERR_CHANNELISFULL;
656    
657 michael 6681 if (is_banned(chptr, client_p))
658 michael 2208 return ERR_BANNEDFROMCHAN;
659    
660 michael 1834 return 0;
661 adx 30 }
662    
663     int
664 michael 4815 has_member_flags(const struct Membership *member, const unsigned int flags)
665 adx 30 {
666 michael 4815 return member && (member->flags & flags);
667 adx 30 }
668    
669     struct Membership *
670     find_channel_link(struct Client *client_p, struct Channel *chptr)
671     {
672 michael 7914 dlink_node *node;
673 adx 30
674     if (!IsClient(client_p))
675     return NULL;
676    
677 michael 2567 if (dlink_list_length(&chptr->members) < dlink_list_length(&client_p->channel))
678     {
679 michael 4800 DLINK_FOREACH(node, chptr->members.head)
680     if (((struct Membership *)node->data)->client_p == client_p)
681     return node->data;
682 michael 2567 }
683     else
684     {
685 michael 4800 DLINK_FOREACH(node, client_p->channel.head)
686     if (((struct Membership *)node->data)->chptr == chptr)
687     return node->data;
688 michael 2567 }
689 adx 30
690     return NULL;
691     }
692    
693 michael 4783 /*! Checks if a message contains control codes
694 michael 3888 * \param message The actual message string the client wants to send
695     * \return 1 if the message does contain any control codes, 0 otherwise
696 michael 1937 */
697     static int
698     msg_has_ctrls(const char *message)
699     {
700     const unsigned char *p = (const unsigned char *)message;
701    
702     for (; *p; ++p)
703     {
704     if (*p > 31 || *p == 1)
705 michael 3952 continue; /* No control code or CTCP */
706 michael 1937
707 michael 3888 if (*p == 27) /* Escape */
708 michael 1937 {
709 michael 3888 /* ISO 2022 charset shift sequence */
710 michael 1937 if (*(p + 1) == '$' ||
711     *(p + 1) == '(')
712     {
713     ++p;
714     continue;
715     }
716     }
717    
718 michael 3888 return 1; /* Control code */
719 michael 1937 }
720    
721 michael 4783 return 0; /* No control code found */
722 michael 1937 }
723    
724 michael 3308 /*! Tests if a client can send to a channel
725     * \param chptr Pointer to Channel struct
726 michael 6681 * \param client_p Pointer to Client struct
727 michael 4815 * \param member Pointer to Membership struct (can be NULL)
728 michael 3308 * \param message The actual message string the client wants to send
729 adx 30 * \return CAN_SEND_OPV if op or voiced on channel\n
730     * CAN_SEND_NONOP if can send to channel but is not an op\n
731 michael 1173 * ERR_CANNOTSENDTOCHAN or ERR_NEEDREGGEDNICK if they cannot send to channel\n
732 adx 30 */
733     int
734 michael 6681 can_send(struct Channel *chptr, struct Client *client_p,
735 michael 6858 struct Membership *member, const char *message, int notice)
736 adx 30 {
737 michael 7282 const struct ResvItem *resv = NULL;
738 michael 1858
739 michael 6681 if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE))
740 adx 30 return CAN_SEND_OPV;
741    
742 michael 7054 if (MyConnect(client_p) && !HasFlag(client_p, FLAGS_EXEMPTRESV))
743 michael 6681 if (!(HasUMode(client_p, UMODE_OPER) && HasOFlag(client_p, OPER_FLAG_JOIN_RESV)))
744 michael 7282 if ((resv = resv_find(chptr->name, match)) && !resv_exempt_find(client_p, resv))
745 michael 1834 return ERR_CANNOTSENDTOCHAN;
746 adx 30
747 michael 8044 if (HasCMode(chptr, MODE_NOCTRL) && msg_has_ctrls(message))
748 michael 1944 return ERR_NOCTRLSONCHAN;
749 michael 4884
750 michael 8044 if (HasCMode(chptr, MODE_NOCTCP))
751 michael 5465 if (*message == '\001' && strncmp(message + 1, "ACTION ", 7))
752 michael 5464 return ERR_NOCTCP;
753    
754 michael 6681 if (member || (member = find_channel_link(client_p, chptr)))
755 michael 5583 if (member->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
756 adx 30 return CAN_SEND_OPV;
757 michael 4884
758 michael 8044 if (!member && HasCMode(chptr, MODE_NOPRIVMSGS))
759 michael 2441 return ERR_CANNOTSENDTOCHAN;
760 michael 4884
761 michael 8044 if (HasCMode(chptr, MODE_MODERATED))
762 michael 1944 return ERR_CANNOTSENDTOCHAN;
763 michael 4884
764 michael 8044 if (HasCMode(chptr, MODE_MODREG) && !HasUMode(client_p, UMODE_REGISTERED))
765 michael 1944 return ERR_NEEDREGGEDNICK;
766 adx 30
767 michael 8044 if (HasCMode(chptr, MODE_NONOTICE) && notice)
768 michael 6858 return ERR_CANNOTSENDTOCHAN;
769    
770 michael 3308 /* Cache can send if banned */
771 michael 7054 if (MyConnect(client_p))
772 michael 1944 {
773 michael 4815 if (member)
774 adx 30 {
775 michael 4815 if (member->flags & CHFL_BAN_SILENCED)
776 michael 1834 return ERR_CANNOTSENDTOCHAN;
777 adx 30
778 michael 4815 if (!(member->flags & CHFL_BAN_CHECKED))
779 adx 30 {
780 michael 6681 if (is_banned(chptr, client_p))
781 adx 30 {
782 michael 5583 member->flags |= (CHFL_BAN_CHECKED | CHFL_BAN_SILENCED);
783 michael 1834 return ERR_CANNOTSENDTOCHAN;
784 adx 30 }
785    
786 michael 4815 member->flags |= CHFL_BAN_CHECKED;
787 adx 30 }
788     }
789 michael 6681 else if (is_banned(chptr, client_p))
790 michael 1941 return ERR_CANNOTSENDTOCHAN;
791     }
792 adx 30
793     return CAN_SEND_NONOP;
794     }
795    
796     /*! \brief Updates the client's oper_warn_count_down, warns the
797     * IRC operators if necessary, and updates
798     * join_leave_countdown as needed.
799 michael 6682 * \param client_p Pointer to struct Client to check
800 michael 3308 * \param name Channel name or NULL if this is a part.
801 adx 30 */
802     void
803 michael 6682 check_spambot_warning(struct Client *client_p, const char *name)
804 adx 30 {
805 michael 8274 if (GlobalSetOptions.spam_num &&
806     (client_p->connection->join_leave_count >= GlobalSetOptions.spam_num))
807 adx 30 {
808 michael 6682 if (client_p->connection->oper_warn_count_down > 0)
809     client_p->connection->oper_warn_count_down--;
810 adx 30 else
811 michael 6682 client_p->connection->oper_warn_count_down = 0;
812 adx 30
813 michael 6682 if (client_p->connection->oper_warn_count_down == 0)
814 adx 30 {
815 michael 3308 /* It's already known as a possible spambot */
816 michael 3235 if (name)
817 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
818 adx 30 "User %s (%s@%s) trying to join %s is a possible spambot",
819 michael 6682 client_p->name, client_p->username,
820     client_p->host, name);
821 adx 30 else
822 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
823 adx 30 "User %s (%s@%s) is a possible spambot",
824 michael 6682 client_p->name, client_p->username,
825     client_p->host);
826     client_p->connection->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
827 adx 30 }
828     }
829     else
830     {
831 michael 8276 int t_delta = CurrentTime - client_p->connection->last_leave_time;
832     if (t_delta > JOIN_LEAVE_COUNT_EXPIRE_TIME)
833 adx 30 {
834 michael 8276 int decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
835 michael 6682 if (decrement_count > client_p->connection->join_leave_count)
836     client_p->connection->join_leave_count = 0;
837 adx 30 else
838 michael 6682 client_p->connection->join_leave_count -= decrement_count;
839 adx 30 }
840     else
841     {
842 michael 6682 if ((CurrentTime - (client_p->connection->last_join_time)) <
843 adx 30 GlobalSetOptions.spam_time)
844 michael 6682 client_p->connection->join_leave_count++; /* It's a possible spambot */
845 adx 30 }
846    
847 michael 3215 if (name)
848 michael 6682 client_p->connection->last_join_time = CurrentTime;
849 adx 30 else
850 michael 6682 client_p->connection->last_leave_time = CurrentTime;
851 adx 30 }
852     }
853    
854 michael 3308 /*! \brief Sets the channel topic for a certain channel
855 adx 30 * \param chptr Pointer to struct Channel
856     * \param topic The topic string
857     * \param topic_info n!u\@h formatted string of the topic setter
858 michael 3308 * \param topicts Timestamp on the topic
859     * \param local Whether the topic is set by a local client
860 adx 30 */
861     void
862 michael 3941 channel_set_topic(struct Channel *chptr, const char *topic,
863 michael 7330 const char *topic_info, uintmax_t topicts, int local)
864 adx 30 {
865 michael 1751 if (local)
866 michael 4340 strlcpy(chptr->topic, topic, IRCD_MIN(sizeof(chptr->topic), ConfigServerInfo.max_topic_length + 1));
867 michael 1751 else
868     strlcpy(chptr->topic, topic, sizeof(chptr->topic));
869    
870 michael 1203 strlcpy(chptr->topic_info, topic_info, sizeof(chptr->topic_info));
871 michael 2345 chptr->topic_time = topicts;
872 adx 30 }
873 michael 3912
874     void
875 michael 8367 channel_do_join(struct Client *client_p, char *chan_list, char *key_list)
876 michael 3912 {
877     char *p = NULL;
878 michael 7282 const struct ResvItem *resv = NULL;
879 michael 6682 const struct ClassItem *const class = get_class_ptr(&client_p->connection->confs);
880 michael 3912 unsigned int flags = 0;
881    
882 michael 6682 assert(IsClient(client_p));
883 michael 5590
884 michael 7908 for (const char *name = strtok_r(chan_list, ",", &p); name;
885     name = strtok_r(NULL, ",", &p))
886 michael 3912 {
887     const char *key = NULL;
888    
889     /* If we have any more keys, take the first for this channel. */
890     if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
891     *key_list++ = '\0';
892    
893     /* Empty keys are the same as no keys. */
894     if (key && *key == '\0')
895     key = NULL;
896    
897 michael 7908 if (!channel_check_name(name, 1))
898 michael 3912 {
899 michael 7908 sendto_one_numeric(client_p, &me, ERR_BADCHANNAME, name);
900 michael 3912 continue;
901     }
902    
903 michael 6682 if (!HasFlag(client_p, FLAGS_EXEMPTRESV) &&
904     !(HasUMode(client_p, UMODE_OPER) && HasOFlag(client_p, OPER_FLAG_JOIN_RESV)) &&
905 michael 7908 ((resv = resv_find(name, match)) && !resv_exempt_find(client_p, resv)))
906 michael 3912 {
907 michael 7908 sendto_one_numeric(client_p, &me, ERR_CHANBANREASON, name, resv->reason);
908 michael 4151 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
909 michael 3912 "Forbidding reserved channel %s from user %s",
910 michael 7997 name, client_get_name(client_p, HIDE_IP));
911 michael 3912 continue;
912     }
913    
914 michael 6682 if (dlink_list_length(&client_p->channel) >=
915 michael 3933 ((class->max_channels) ? class->max_channels : ConfigChannel.max_channels))
916 michael 3912 {
917 michael 7908 sendto_one_numeric(client_p, &me, ERR_TOOMANYCHANNELS, name);
918 michael 3912 break;
919     }
920    
921 michael 8024 struct Channel *chptr = hash_find_channel(name);
922     if (chptr)
923 michael 3912 {
924 michael 6682 if (IsMember(client_p, chptr))
925 michael 3912 continue;
926    
927 michael 7557 /* can_join() checks for +i, +l, key, bans, etc. */
928     int ret = can_join(client_p, chptr, key);
929     if (ret)
930 michael 3912 {
931 michael 7557 sendto_one_numeric(client_p, &me, ret, chptr->name);
932 michael 3912 continue;
933     }
934    
935     /*
936     * This should never be the case unless there is some sort of
937     * persistant channels.
938     */
939 michael 4977 if (!dlink_list_length(&chptr->members))
940 michael 3912 flags = CHFL_CHANOP;
941     else
942     flags = 0;
943     }
944     else
945     {
946     flags = CHFL_CHANOP;
947 michael 7908 chptr = channel_make(name);
948 michael 3912 }
949    
950 michael 6682 if (!HasUMode(client_p, UMODE_OPER))
951     check_spambot_warning(client_p, chptr->name);
952 michael 3912
953 michael 6682 add_user_to_channel(chptr, client_p, flags, 1);
954 michael 3912
955     /*
956 michael 5545 * Set timestamp if appropriate, and propagate
957 michael 3912 */
958     if (flags == CHFL_CHANOP)
959     {
960 michael 4818 chptr->creationtime = CurrentTime;
961 michael 8044 AddCMode(chptr, MODE_TOPICLIMIT);
962     AddCMode(chptr, MODE_NOPRIVMSGS);
963 michael 3912
964 michael 6782 sendto_server(client_p, 0, 0, ":%s SJOIN %ju %s +nt :@%s",
965     me.id, chptr->creationtime,
966 michael 6682 chptr->name, client_p->id);
967 michael 3912
968     /*
969     * Notify all other users on the new channel
970     */
971 michael 6759 sendto_channel_local(NULL, chptr, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
972     client_p->name, client_p->username,
973 michael 6827 client_p->host, chptr->name, client_p->account, client_p->info);
974 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
975     client_p->name, client_p->username,
976     client_p->host, chptr->name);
977     sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s MODE %s +nt",
978 michael 4618 me.name, chptr->name);
979 michael 3912
980 michael 6682 if (client_p->away[0])
981 michael 6759 sendto_channel_local(client_p, chptr, 0, CAP_AWAY_NOTIFY, 0,
982     ":%s!%s@%s AWAY :%s",
983     client_p->name, client_p->username,
984     client_p->host, client_p->away);
985 michael 3912 }
986     else
987     {
988 michael 6782 sendto_server(client_p, 0, 0, ":%s JOIN %ju %s +",
989     client_p->id, chptr->creationtime,
990 michael 4618 chptr->name);
991 michael 3912
992 michael 6759 sendto_channel_local(NULL, chptr, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
993     client_p->name, client_p->username,
994 michael 6827 client_p->host, chptr->name, client_p->account, client_p->info);
995 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
996     client_p->name, client_p->username,
997     client_p->host, chptr->name);
998 michael 4792
999 michael 6682 if (client_p->away[0])
1000 michael 6759 sendto_channel_local(client_p, chptr, 0, CAP_AWAY_NOTIFY, 0,
1001     ":%s!%s@%s AWAY :%s",
1002     client_p->name, client_p->username,
1003     client_p->host, client_p->away);
1004 michael 3912 }
1005    
1006 michael 7549 struct Invite *invite = find_invite(chptr, client_p);
1007     if (invite)
1008     del_invite(invite);
1009 michael 3912
1010     if (chptr->topic[0])
1011     {
1012 michael 6682 sendto_one_numeric(client_p, &me, RPL_TOPIC, chptr->name, chptr->topic);
1013     sendto_one_numeric(client_p, &me, RPL_TOPICWHOTIME, chptr->name,
1014 michael 3912 chptr->topic_info, chptr->topic_time);
1015     }
1016    
1017 michael 6682 channel_member_names(client_p, chptr, 1);
1018 michael 3912
1019 michael 6682 client_p->connection->last_join_time = CurrentTime;
1020 michael 3912 }
1021     }
1022    
1023     /*! \brief Removes a client from a specific channel
1024 michael 7612 * \param client_p Pointer to client to remove
1025 michael 3912 * \param name Name of channel to remove from
1026     * \param reason Part reason to show
1027     */
1028     static void
1029 michael 6682 channel_part_one_client(struct Client *client_p, const char *name, const char *reason)
1030 michael 3912 {
1031     struct Channel *chptr = NULL;
1032 michael 4815 struct Membership *member = NULL;
1033 michael 3912
1034     if ((chptr = hash_find_channel(name)) == NULL)
1035     {
1036 michael 6682 sendto_one_numeric(client_p, &me, ERR_NOSUCHCHANNEL, name);
1037 michael 3912 return;
1038     }
1039    
1040 michael 6682 if ((member = find_channel_link(client_p, chptr)) == NULL)
1041 michael 3912 {
1042 michael 6682 sendto_one_numeric(client_p, &me, ERR_NOTONCHANNEL, chptr->name);
1043 michael 3912 return;
1044     }
1045    
1046 michael 6682 if (MyConnect(client_p) && !HasUMode(client_p, UMODE_OPER))
1047     check_spambot_warning(client_p, NULL);
1048 michael 3912
1049     /*
1050     * Remove user from the old channel (if any)
1051     * only allow /part reasons in -m chans
1052     */
1053 michael 6682 if (*reason && (!MyConnect(client_p) ||
1054 michael 6906 ((client_p->connection->firsttime +
1055     ConfigGeneral.anti_spam_exit_message_time) < CurrentTime &&
1056     can_send(chptr, client_p, member, reason, 0) < 0)))
1057 michael 3912 {
1058 michael 6682 sendto_server(client_p, 0, 0, ":%s PART %s :%s",
1059     client_p->id, chptr->name, reason);
1060 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s!%s@%s PART %s :%s",
1061 michael 6682 client_p->name, client_p->username,
1062     client_p->host, chptr->name, reason);
1063 michael 3912 }
1064     else
1065     {
1066 michael 6682 sendto_server(client_p, 0, 0, ":%s PART %s",
1067     client_p->id, chptr->name);
1068 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s!%s@%s PART %s",
1069 michael 6682 client_p->name, client_p->username,
1070     client_p->host, chptr->name);
1071 michael 3912 }
1072    
1073 michael 4815 remove_user_from_channel(member);
1074 michael 3912 }
1075    
1076     void
1077 michael 6682 channel_do_part(struct Client *client_p, char *channel, const char *reason)
1078 michael 3912 {
1079 michael 7797 char *p = NULL;
1080 michael 4785 char buf[KICKLEN + 1] = "";
1081 michael 3912
1082 michael 6682 assert(IsClient(client_p));
1083 michael 5590
1084 michael 3937 if (!EmptyString(reason))
1085 michael 4785 strlcpy(buf, reason, sizeof(buf));
1086 michael 3912
1087 michael 7797 for (const char *name = strtok_r(channel, ",", &p); name;
1088     name = strtok_r(NULL, ",", &p))
1089 michael 6682 channel_part_one_client(client_p, name, buf);
1090 michael 3912 }

Properties

Name Value
svn:eol-style native
svn:keywords Id