ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel.c
Revision: 8431
Committed: Tue Mar 27 18:49:15 2018 UTC (7 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 31518 byte(s)
Log Message:
- Stylistic changes

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 8431 --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 8431 channel_member_names(struct Client *client_p, struct Channel *chptr, int show_eon)
380 adx 30 {
381 michael 7687 dlink_node *node;
382 michael 4388 char buf[IRCD_BUFSIZE + 1] = "";
383 adx 30 char *t = NULL, *start = NULL;
384     int tlen = 0;
385 michael 6681 const int is_member = IsMember(client_p, chptr);
386     const int multi_prefix = HasCap(client_p, CAP_MULTI_PREFIX) != 0;
387     const int uhnames = HasCap(client_p, CAP_UHNAMES) != 0;
388 adx 30
389 michael 6681 assert(IsClient(client_p));
390 michael 5590
391 adx 30 if (PubChannel(chptr) || is_member)
392     {
393 michael 4388 t = buf + snprintf(buf, sizeof(buf), numeric_form(RPL_NAMREPLY),
394 michael 6681 me.name, client_p->name,
395 michael 4618 channel_pub_or_secret(chptr), chptr->name);
396 adx 30 start = t;
397    
398 michael 4800 DLINK_FOREACH(node, chptr->members.head)
399 adx 30 {
400 michael 4815 const struct Membership *member = node->data;
401 adx 30
402 michael 4815 if (HasUMode(member->client_p, UMODE_INVISIBLE) && !is_member)
403 adx 30 continue;
404    
405 michael 8431 if (uhnames)
406 michael 4815 tlen = strlen(member->client_p->name) + strlen(member->client_p->username) +
407     strlen(member->client_p->host) + 3; /* +3 for ! + @ + space */
408 michael 8431 else
409     tlen = strlen(member->client_p->name) + 1; /* +1 for space */
410 adx 30
411 michael 8431 if (multi_prefix)
412 michael 506 {
413 michael 4815 if (member->flags & CHFL_CHANOP)
414 michael 506 ++tlen;
415 michael 4815 if (member->flags & CHFL_HALFOP)
416 michael 506 ++tlen;
417 michael 4815 if (member->flags & CHFL_VOICE)
418 michael 506 ++tlen;
419     }
420 michael 8431 else
421     {
422     if (member->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
423     ++tlen;
424     }
425 michael 506
426 michael 4388 if (t + tlen - buf > IRCD_BUFSIZE - 2)
427 adx 30 {
428     *(t - 1) = '\0';
429 michael 6681 sendto_one(client_p, "%s", buf);
430 adx 30 t = start;
431     }
432    
433 michael 8431 if (uhnames)
434 michael 4815 t += sprintf(t, "%s%s!%s@%s ", get_member_status(member, multi_prefix),
435     member->client_p->name, member->client_p->username,
436     member->client_p->host);
437 michael 8431 else
438     t += sprintf(t, "%s%s ", get_member_status(member, multi_prefix),
439     member->client_p->name);
440 adx 30 }
441    
442 michael 3215 if (tlen)
443 adx 30 {
444     *(t - 1) = '\0';
445 michael 6681 sendto_one(client_p, "%s", buf);
446 adx 30 }
447     }
448    
449     if (show_eon)
450 michael 6681 sendto_one_numeric(client_p, &me, RPL_ENDOFNAMES, chptr->name);
451 adx 30 }
452    
453 michael 7549 static struct Invite *
454     find_invite(struct Channel *chptr, struct Client *client_p)
455     {
456     dlink_node *node, *node_next;
457     dlink_list *list;
458    
459 michael 7793 /* Take the shortest of the two lists */
460 michael 7549 if (dlink_list_length(&client_p->connection->invited) < dlink_list_length(&chptr->invites))
461     list = &client_p->connection->invited;
462     else
463     list = &chptr->invites;
464    
465     DLINK_FOREACH_SAFE(node, node_next, list->head)
466     {
467     struct Invite *invite = node->data;
468    
469 michael 7793 if (ConfigChannel.invite_expire_time &&
470     ConfigChannel.invite_expire_time + invite->when < CurrentTime)
471     del_invite(invite);
472     else if (invite->chptr == chptr && invite->client_p == client_p)
473 michael 7549 return invite;
474     }
475    
476     return NULL;
477     }
478    
479 michael 3308 /*! \brief Adds client to invite list
480 michael 6681 * \param chptr Pointer to channel block
481     * \param client_p Pointer to client to add invite to
482 adx 30 */
483     void
484 michael 6681 add_invite(struct Channel *chptr, struct Client *client_p)
485 adx 30 {
486 michael 8431 struct Invite *invite;
487     if ((invite = find_invite(chptr, client_p)))
488 michael 7549 del_invite(invite);
489 adx 30
490 michael 8385 invite = xcalloc(sizeof(*invite));
491 michael 7549 invite->client_p = client_p;
492     invite->chptr = chptr;
493     invite->when = CurrentTime;
494    
495 michael 7542 /* Delete last link in chain if the list is max length */
496     while (dlink_list_length(&client_p->connection->invited) &&
497 michael 7766 dlink_list_length(&client_p->connection->invited) >= ConfigChannel.max_invites)
498 michael 7549 del_invite(client_p->connection->invited.tail->data);
499 adx 30
500 michael 3308 /* Add client to channel invite list */
501 michael 7549 dlinkAdd(invite, &invite->chan_node, &chptr->invites);
502 adx 30
503 michael 3308 /* Add channel to the end of the client invite list */
504 michael 7549 dlinkAdd(invite, &invite->user_node, &client_p->connection->invited);
505 adx 30 }
506    
507     /*! \brief Delete Invite block from channel invite list
508     * and client invite list
509 michael 7549 * \param invite Pointer to Invite struct
510 adx 30 */
511     void
512 michael 7549 del_invite(struct Invite *invite)
513 adx 30 {
514 michael 7549 dlinkDelete(&invite->user_node, &invite->client_p->connection->invited);
515     dlinkDelete(&invite->chan_node, &invite->chptr->invites);
516 adx 30
517 michael 7549 /* Release memory pointed to by 'invite' */
518 michael 8385 xfree(invite);
519 adx 30 }
520    
521 michael 7762 /*! \brief Removes and frees all Invite blocks from a list
522     * \param list Pointer to a dlink_list
523 michael 4811 */
524     void
525 michael 7762 clear_invite_list(dlink_list *list)
526 michael 4811 {
527 michael 7762 while (list->head)
528     del_invite(list->head->data);
529 michael 4811 }
530    
531 adx 30 /* get_member_status()
532     *
533     * inputs - pointer to struct Membership
534     * - YES if we can combine different flags
535     * output - string either @, +, % or "" depending on whether
536     * chanop, voiced or user
537     * side effects -
538     *
539     * NOTE: Returned string is usually a static buffer
540 michael 7997 * (like in client_get_name)
541 adx 30 */
542     const char *
543 michael 4815 get_member_status(const struct Membership *member, const int combine)
544 adx 30 {
545 michael 6904 static char buffer[CMEMBER_STATUS_FLAGS_LEN + 1]; /* +1 for \0 */
546 michael 1902 char *p = buffer;
547 adx 30
548 michael 4815 if (member->flags & CHFL_CHANOP)
549 adx 30 {
550     if (!combine)
551     return "@";
552     *p++ = '@';
553     }
554    
555 michael 4815 if (member->flags & CHFL_HALFOP)
556 adx 30 {
557     if (!combine)
558     return "%";
559     *p++ = '%';
560     }
561    
562 michael 4815 if (member->flags & CHFL_VOICE)
563 adx 30 *p++ = '+';
564     *p = '\0';
565    
566     return buffer;
567     }
568    
569     /*!
570 michael 6681 * \param client_p Pointer to Client to check
571     * \param list Pointer to ban list to search
572 adx 30 * \return 1 if ban found for given n!u\@h mask, 0 otherwise
573     */
574     static int
575 michael 7345 find_bmask(const struct Client *client_p, const dlink_list *list)
576 adx 30 {
577 michael 7687 dlink_node *node;
578 adx 30
579 michael 4800 DLINK_FOREACH(node, list->head)
580 adx 30 {
581 michael 4815 const struct Ban *ban = node->data;
582 adx 30
583 michael 6681 if (!match(ban->name, client_p->name) && !match(ban->user, client_p->username))
584 michael 371 {
585 michael 4815 switch (ban->type)
586 michael 371 {
587     case HM_HOST:
588 michael 6681 if (!match(ban->host, client_p->host) || !match(ban->host, client_p->sockhost))
589 michael 371 return 1;
590     break;
591     case HM_IPV4:
592 michael 6681 if (client_p->connection->aftype == AF_INET)
593     if (match_ipv4(&client_p->connection->ip, &ban->addr, ban->bits))
594 michael 371 return 1;
595     break;
596     case HM_IPV6:
597 michael 6681 if (client_p->connection->aftype == AF_INET6)
598     if (match_ipv6(&client_p->connection->ip, &ban->addr, ban->bits))
599 michael 371 return 1;
600     break;
601     default:
602     assert(0);
603     }
604     }
605 adx 30 }
606    
607     return 0;
608     }
609    
610     /*!
611 michael 6681 * \param chptr Pointer to channel block
612     * \param client_p Pointer to client to check access fo
613 adx 30 * \return 0 if not banned, 1 otherwise
614     */
615     int
616 michael 6681 is_banned(const struct Channel *chptr, const struct Client *client_p)
617 adx 30 {
618 michael 6681 if (find_bmask(client_p, &chptr->banlist))
619     if (!find_bmask(client_p, &chptr->exceptlist))
620 michael 632 return 1;
621 adx 30
622 michael 632 return 0;
623 adx 30 }
624    
625 michael 3308 /*! Tests if a client can join a certain channel
626 michael 6681 * \param client_p Pointer to client attempting to join
627 michael 3308 * \param chptr Pointer to channel
628     * \param key Key sent by client attempting to join if present
629 adx 30 * \return ERR_BANNEDFROMCHAN, ERR_INVITEONLYCHAN, ERR_CHANNELISFULL
630     * or 0 if allowed to join.
631     */
632 michael 6881 static int
633 michael 7549 can_join(struct Client *client_p, struct Channel *chptr, const char *key)
634 adx 30 {
635 michael 8044 if (HasCMode(chptr, MODE_SSLONLY) && !HasUMode(client_p, UMODE_SSL))
636 michael 1150 return ERR_SSLONLYCHAN;
637    
638 michael 8044 if (HasCMode(chptr, MODE_REGONLY) && !HasUMode(client_p, UMODE_REGISTERED))
639 michael 1173 return ERR_NEEDREGGEDNICK;
640    
641 michael 8044 if (HasCMode(chptr, MODE_OPERONLY) && !HasUMode(client_p, UMODE_OPER))
642 michael 1150 return ERR_OPERONLYCHAN;
643    
644 michael 8044 if (HasCMode(chptr, MODE_INVITEONLY))
645 michael 7549 if (!find_invite(chptr, client_p))
646 michael 6681 if (!find_bmask(client_p, &chptr->invexlist))
647 adx 30 return ERR_INVITEONLYCHAN;
648    
649 michael 1430 if (chptr->mode.key[0] && (!key || strcmp(chptr->mode.key, key)))
650 adx 30 return ERR_BADCHANNELKEY;
651    
652     if (chptr->mode.limit && dlink_list_length(&chptr->members) >=
653     chptr->mode.limit)
654     return ERR_CHANNELISFULL;
655    
656 michael 6681 if (is_banned(chptr, client_p))
657 michael 2208 return ERR_BANNEDFROMCHAN;
658    
659 michael 1834 return 0;
660 adx 30 }
661    
662     int
663 michael 4815 has_member_flags(const struct Membership *member, const unsigned int flags)
664 adx 30 {
665 michael 4815 return member && (member->flags & flags);
666 adx 30 }
667    
668     struct Membership *
669     find_channel_link(struct Client *client_p, struct Channel *chptr)
670     {
671 michael 7914 dlink_node *node;
672 adx 30
673     if (!IsClient(client_p))
674     return NULL;
675    
676 michael 2567 if (dlink_list_length(&chptr->members) < dlink_list_length(&client_p->channel))
677     {
678 michael 4800 DLINK_FOREACH(node, chptr->members.head)
679     if (((struct Membership *)node->data)->client_p == client_p)
680     return node->data;
681 michael 2567 }
682     else
683     {
684 michael 4800 DLINK_FOREACH(node, client_p->channel.head)
685     if (((struct Membership *)node->data)->chptr == chptr)
686     return node->data;
687 michael 2567 }
688 adx 30
689     return NULL;
690     }
691    
692 michael 4783 /*! Checks if a message contains control codes
693 michael 3888 * \param message The actual message string the client wants to send
694     * \return 1 if the message does contain any control codes, 0 otherwise
695 michael 1937 */
696     static int
697     msg_has_ctrls(const char *message)
698     {
699     const unsigned char *p = (const unsigned char *)message;
700    
701     for (; *p; ++p)
702     {
703     if (*p > 31 || *p == 1)
704 michael 3952 continue; /* No control code or CTCP */
705 michael 1937
706 michael 3888 if (*p == 27) /* Escape */
707 michael 1937 {
708 michael 3888 /* ISO 2022 charset shift sequence */
709 michael 1937 if (*(p + 1) == '$' ||
710     *(p + 1) == '(')
711     {
712     ++p;
713     continue;
714     }
715     }
716    
717 michael 3888 return 1; /* Control code */
718 michael 1937 }
719    
720 michael 4783 return 0; /* No control code found */
721 michael 1937 }
722    
723 michael 3308 /*! Tests if a client can send to a channel
724     * \param chptr Pointer to Channel struct
725 michael 6681 * \param client_p Pointer to Client struct
726 michael 4815 * \param member Pointer to Membership struct (can be NULL)
727 michael 3308 * \param message The actual message string the client wants to send
728 adx 30 * \return CAN_SEND_OPV if op or voiced on channel\n
729     * CAN_SEND_NONOP if can send to channel but is not an op\n
730 michael 1173 * ERR_CANNOTSENDTOCHAN or ERR_NEEDREGGEDNICK if they cannot send to channel\n
731 adx 30 */
732     int
733 michael 6681 can_send(struct Channel *chptr, struct Client *client_p,
734 michael 6858 struct Membership *member, const char *message, int notice)
735 adx 30 {
736 michael 7282 const struct ResvItem *resv = NULL;
737 michael 1858
738 michael 6681 if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE))
739 adx 30 return CAN_SEND_OPV;
740    
741 michael 7054 if (MyConnect(client_p) && !HasFlag(client_p, FLAGS_EXEMPTRESV))
742 michael 6681 if (!(HasUMode(client_p, UMODE_OPER) && HasOFlag(client_p, OPER_FLAG_JOIN_RESV)))
743 michael 7282 if ((resv = resv_find(chptr->name, match)) && !resv_exempt_find(client_p, resv))
744 michael 1834 return ERR_CANNOTSENDTOCHAN;
745 adx 30
746 michael 8044 if (HasCMode(chptr, MODE_NOCTRL) && msg_has_ctrls(message))
747 michael 1944 return ERR_NOCTRLSONCHAN;
748 michael 4884
749 michael 8044 if (HasCMode(chptr, MODE_NOCTCP))
750 michael 5465 if (*message == '\001' && strncmp(message + 1, "ACTION ", 7))
751 michael 5464 return ERR_NOCTCP;
752    
753 michael 6681 if (member || (member = find_channel_link(client_p, chptr)))
754 michael 5583 if (member->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
755 adx 30 return CAN_SEND_OPV;
756 michael 4884
757 michael 8044 if (!member && HasCMode(chptr, MODE_NOPRIVMSGS))
758 michael 2441 return ERR_CANNOTSENDTOCHAN;
759 michael 4884
760 michael 8044 if (HasCMode(chptr, MODE_MODERATED))
761 michael 1944 return ERR_CANNOTSENDTOCHAN;
762 michael 4884
763 michael 8044 if (HasCMode(chptr, MODE_MODREG) && !HasUMode(client_p, UMODE_REGISTERED))
764 michael 1944 return ERR_NEEDREGGEDNICK;
765 adx 30
766 michael 8044 if (HasCMode(chptr, MODE_NONOTICE) && notice)
767 michael 6858 return ERR_CANNOTSENDTOCHAN;
768    
769 michael 3308 /* Cache can send if banned */
770 michael 7054 if (MyConnect(client_p))
771 michael 1944 {
772 michael 4815 if (member)
773 adx 30 {
774 michael 4815 if (member->flags & CHFL_BAN_SILENCED)
775 michael 1834 return ERR_CANNOTSENDTOCHAN;
776 adx 30
777 michael 4815 if (!(member->flags & CHFL_BAN_CHECKED))
778 adx 30 {
779 michael 6681 if (is_banned(chptr, client_p))
780 adx 30 {
781 michael 5583 member->flags |= (CHFL_BAN_CHECKED | CHFL_BAN_SILENCED);
782 michael 1834 return ERR_CANNOTSENDTOCHAN;
783 adx 30 }
784    
785 michael 4815 member->flags |= CHFL_BAN_CHECKED;
786 adx 30 }
787     }
788 michael 6681 else if (is_banned(chptr, client_p))
789 michael 1941 return ERR_CANNOTSENDTOCHAN;
790     }
791 adx 30
792     return CAN_SEND_NONOP;
793     }
794    
795     /*! \brief Updates the client's oper_warn_count_down, warns the
796     * IRC operators if necessary, and updates
797     * join_leave_countdown as needed.
798 michael 6682 * \param client_p Pointer to struct Client to check
799 michael 3308 * \param name Channel name or NULL if this is a part.
800 adx 30 */
801     void
802 michael 6682 check_spambot_warning(struct Client *client_p, const char *name)
803 adx 30 {
804 michael 8274 if (GlobalSetOptions.spam_num &&
805     (client_p->connection->join_leave_count >= GlobalSetOptions.spam_num))
806 adx 30 {
807 michael 6682 if (client_p->connection->oper_warn_count_down > 0)
808     client_p->connection->oper_warn_count_down--;
809 adx 30 else
810 michael 6682 client_p->connection->oper_warn_count_down = 0;
811 adx 30
812 michael 6682 if (client_p->connection->oper_warn_count_down == 0)
813 adx 30 {
814 michael 3308 /* It's already known as a possible spambot */
815 michael 3235 if (name)
816 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
817 adx 30 "User %s (%s@%s) trying to join %s is a possible spambot",
818 michael 6682 client_p->name, client_p->username,
819     client_p->host, name);
820 adx 30 else
821 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
822 adx 30 "User %s (%s@%s) is a possible spambot",
823 michael 6682 client_p->name, client_p->username,
824     client_p->host);
825     client_p->connection->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
826 adx 30 }
827     }
828     else
829     {
830 michael 8276 int t_delta = CurrentTime - client_p->connection->last_leave_time;
831     if (t_delta > JOIN_LEAVE_COUNT_EXPIRE_TIME)
832 adx 30 {
833 michael 8276 int decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
834 michael 6682 if (decrement_count > client_p->connection->join_leave_count)
835     client_p->connection->join_leave_count = 0;
836 adx 30 else
837 michael 6682 client_p->connection->join_leave_count -= decrement_count;
838 adx 30 }
839     else
840     {
841 michael 6682 if ((CurrentTime - (client_p->connection->last_join_time)) <
842 adx 30 GlobalSetOptions.spam_time)
843 michael 6682 client_p->connection->join_leave_count++; /* It's a possible spambot */
844 adx 30 }
845    
846 michael 3215 if (name)
847 michael 6682 client_p->connection->last_join_time = CurrentTime;
848 adx 30 else
849 michael 6682 client_p->connection->last_leave_time = CurrentTime;
850 adx 30 }
851     }
852    
853 michael 3308 /*! \brief Sets the channel topic for a certain channel
854 adx 30 * \param chptr Pointer to struct Channel
855     * \param topic The topic string
856     * \param topic_info n!u\@h formatted string of the topic setter
857 michael 3308 * \param topicts Timestamp on the topic
858     * \param local Whether the topic is set by a local client
859 adx 30 */
860     void
861 michael 3941 channel_set_topic(struct Channel *chptr, const char *topic,
862 michael 7330 const char *topic_info, uintmax_t topicts, int local)
863 adx 30 {
864 michael 1751 if (local)
865 michael 4340 strlcpy(chptr->topic, topic, IRCD_MIN(sizeof(chptr->topic), ConfigServerInfo.max_topic_length + 1));
866 michael 1751 else
867     strlcpy(chptr->topic, topic, sizeof(chptr->topic));
868    
869 michael 1203 strlcpy(chptr->topic_info, topic_info, sizeof(chptr->topic_info));
870 michael 2345 chptr->topic_time = topicts;
871 adx 30 }
872 michael 3912
873     void
874 michael 8367 channel_do_join(struct Client *client_p, char *chan_list, char *key_list)
875 michael 3912 {
876     char *p = NULL;
877 michael 7282 const struct ResvItem *resv = NULL;
878 michael 6682 const struct ClassItem *const class = get_class_ptr(&client_p->connection->confs);
879 michael 3912 unsigned int flags = 0;
880    
881 michael 6682 assert(IsClient(client_p));
882 michael 5590
883 michael 7908 for (const char *name = strtok_r(chan_list, ",", &p); name;
884     name = strtok_r(NULL, ",", &p))
885 michael 3912 {
886     const char *key = NULL;
887    
888     /* If we have any more keys, take the first for this channel. */
889     if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
890     *key_list++ = '\0';
891    
892     /* Empty keys are the same as no keys. */
893     if (key && *key == '\0')
894     key = NULL;
895    
896 michael 7908 if (!channel_check_name(name, 1))
897 michael 3912 {
898 michael 7908 sendto_one_numeric(client_p, &me, ERR_BADCHANNAME, name);
899 michael 3912 continue;
900     }
901    
902 michael 6682 if (!HasFlag(client_p, FLAGS_EXEMPTRESV) &&
903     !(HasUMode(client_p, UMODE_OPER) && HasOFlag(client_p, OPER_FLAG_JOIN_RESV)) &&
904 michael 7908 ((resv = resv_find(name, match)) && !resv_exempt_find(client_p, resv)))
905 michael 3912 {
906 michael 7908 sendto_one_numeric(client_p, &me, ERR_CHANBANREASON, name, resv->reason);
907 michael 4151 sendto_realops_flags(UMODE_REJ, L_ALL, SEND_NOTICE,
908 michael 3912 "Forbidding reserved channel %s from user %s",
909 michael 7997 name, client_get_name(client_p, HIDE_IP));
910 michael 3912 continue;
911     }
912    
913 michael 6682 if (dlink_list_length(&client_p->channel) >=
914 michael 3933 ((class->max_channels) ? class->max_channels : ConfigChannel.max_channels))
915 michael 3912 {
916 michael 7908 sendto_one_numeric(client_p, &me, ERR_TOOMANYCHANNELS, name);
917 michael 3912 break;
918     }
919    
920 michael 8431 struct Channel *chptr;
921     if ((chptr = hash_find_channel(name)))
922 michael 3912 {
923 michael 6682 if (IsMember(client_p, chptr))
924 michael 3912 continue;
925    
926 michael 7557 /* can_join() checks for +i, +l, key, bans, etc. */
927     int ret = can_join(client_p, chptr, key);
928     if (ret)
929 michael 3912 {
930 michael 7557 sendto_one_numeric(client_p, &me, ret, chptr->name);
931 michael 3912 continue;
932     }
933    
934     /*
935     * This should never be the case unless there is some sort of
936     * persistant channels.
937     */
938 michael 4977 if (!dlink_list_length(&chptr->members))
939 michael 3912 flags = CHFL_CHANOP;
940     else
941     flags = 0;
942     }
943     else
944     {
945     flags = CHFL_CHANOP;
946 michael 7908 chptr = channel_make(name);
947 michael 3912 }
948    
949 michael 6682 if (!HasUMode(client_p, UMODE_OPER))
950     check_spambot_warning(client_p, chptr->name);
951 michael 3912
952 michael 6682 add_user_to_channel(chptr, client_p, flags, 1);
953 michael 3912
954     /*
955 michael 5545 * Set timestamp if appropriate, and propagate
956 michael 3912 */
957     if (flags == CHFL_CHANOP)
958     {
959 michael 4818 chptr->creationtime = CurrentTime;
960 michael 8044 AddCMode(chptr, MODE_TOPICLIMIT);
961     AddCMode(chptr, MODE_NOPRIVMSGS);
962 michael 3912
963 michael 6782 sendto_server(client_p, 0, 0, ":%s SJOIN %ju %s +nt :@%s",
964     me.id, chptr->creationtime,
965 michael 6682 chptr->name, client_p->id);
966 michael 3912
967     /*
968     * Notify all other users on the new channel
969     */
970 michael 6759 sendto_channel_local(NULL, chptr, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
971     client_p->name, client_p->username,
972 michael 6827 client_p->host, chptr->name, client_p->account, client_p->info);
973 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
974     client_p->name, client_p->username,
975     client_p->host, chptr->name);
976     sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s MODE %s +nt",
977 michael 4618 me.name, chptr->name);
978 michael 3912
979 michael 6682 if (client_p->away[0])
980 michael 6759 sendto_channel_local(client_p, chptr, 0, CAP_AWAY_NOTIFY, 0,
981     ":%s!%s@%s AWAY :%s",
982     client_p->name, client_p->username,
983     client_p->host, client_p->away);
984 michael 3912 }
985     else
986     {
987 michael 6782 sendto_server(client_p, 0, 0, ":%s JOIN %ju %s +",
988     client_p->id, chptr->creationtime,
989 michael 4618 chptr->name);
990 michael 3912
991 michael 6759 sendto_channel_local(NULL, chptr, 0, CAP_EXTENDED_JOIN, 0, ":%s!%s@%s JOIN %s %s :%s",
992     client_p->name, client_p->username,
993 michael 6827 client_p->host, chptr->name, client_p->account, client_p->info);
994 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, CAP_EXTENDED_JOIN, ":%s!%s@%s JOIN :%s",
995     client_p->name, client_p->username,
996     client_p->host, chptr->name);
997 michael 4792
998 michael 6682 if (client_p->away[0])
999 michael 6759 sendto_channel_local(client_p, chptr, 0, CAP_AWAY_NOTIFY, 0,
1000     ":%s!%s@%s AWAY :%s",
1001     client_p->name, client_p->username,
1002     client_p->host, client_p->away);
1003 michael 3912 }
1004    
1005 michael 8431 struct Invite *invite;
1006     if ((invite = find_invite(chptr, client_p)))
1007 michael 7549 del_invite(invite);
1008 michael 3912
1009     if (chptr->topic[0])
1010     {
1011 michael 6682 sendto_one_numeric(client_p, &me, RPL_TOPIC, chptr->name, chptr->topic);
1012     sendto_one_numeric(client_p, &me, RPL_TOPICWHOTIME, chptr->name,
1013 michael 3912 chptr->topic_info, chptr->topic_time);
1014     }
1015    
1016 michael 6682 channel_member_names(client_p, chptr, 1);
1017 michael 3912
1018 michael 6682 client_p->connection->last_join_time = CurrentTime;
1019 michael 3912 }
1020     }
1021    
1022     /*! \brief Removes a client from a specific channel
1023 michael 7612 * \param client_p Pointer to client to remove
1024 michael 3912 * \param name Name of channel to remove from
1025     * \param reason Part reason to show
1026     */
1027     static void
1028 michael 6682 channel_part_one_client(struct Client *client_p, const char *name, const char *reason)
1029 michael 3912 {
1030     struct Channel *chptr = NULL;
1031 michael 4815 struct Membership *member = NULL;
1032 michael 3912
1033     if ((chptr = hash_find_channel(name)) == NULL)
1034     {
1035 michael 6682 sendto_one_numeric(client_p, &me, ERR_NOSUCHCHANNEL, name);
1036 michael 3912 return;
1037     }
1038    
1039 michael 6682 if ((member = find_channel_link(client_p, chptr)) == NULL)
1040 michael 3912 {
1041 michael 6682 sendto_one_numeric(client_p, &me, ERR_NOTONCHANNEL, chptr->name);
1042 michael 3912 return;
1043     }
1044    
1045 michael 6682 if (MyConnect(client_p) && !HasUMode(client_p, UMODE_OPER))
1046     check_spambot_warning(client_p, NULL);
1047 michael 3912
1048     /*
1049     * Remove user from the old channel (if any)
1050     * only allow /part reasons in -m chans
1051     */
1052 michael 6682 if (*reason && (!MyConnect(client_p) ||
1053 michael 6906 ((client_p->connection->firsttime +
1054     ConfigGeneral.anti_spam_exit_message_time) < CurrentTime &&
1055     can_send(chptr, client_p, member, reason, 0) < 0)))
1056 michael 3912 {
1057 michael 6682 sendto_server(client_p, 0, 0, ":%s PART %s :%s",
1058     client_p->id, chptr->name, reason);
1059 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s!%s@%s PART %s :%s",
1060 michael 6682 client_p->name, client_p->username,
1061     client_p->host, chptr->name, reason);
1062 michael 3912 }
1063     else
1064     {
1065 michael 6682 sendto_server(client_p, 0, 0, ":%s PART %s",
1066     client_p->id, chptr->name);
1067 michael 6759 sendto_channel_local(NULL, chptr, 0, 0, 0, ":%s!%s@%s PART %s",
1068 michael 6682 client_p->name, client_p->username,
1069     client_p->host, chptr->name);
1070 michael 3912 }
1071    
1072 michael 4815 remove_user_from_channel(member);
1073 michael 3912 }
1074    
1075     void
1076 michael 6682 channel_do_part(struct Client *client_p, char *channel, const char *reason)
1077 michael 3912 {
1078 michael 7797 char *p = NULL;
1079 michael 4785 char buf[KICKLEN + 1] = "";
1080 michael 3912
1081 michael 6682 assert(IsClient(client_p));
1082 michael 5590
1083 michael 3937 if (!EmptyString(reason))
1084 michael 4785 strlcpy(buf, reason, sizeof(buf));
1085 michael 3912
1086 michael 7797 for (const char *name = strtok_r(channel, ",", &p); name;
1087     name = strtok_r(NULL, ",", &p))
1088 michael 6682 channel_part_one_client(client_p, name, buf);
1089 michael 3912 }

Properties

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