]> jfr.im git - irc/rqf/shadowircd.git/blob - src/channel.c
Fix some part of IPv6 dline checking.
[irc/rqf/shadowircd.git] / src / channel.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * channel.c: Controls channels.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: channel.c 3580 2007-11-07 23:45:14Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "channel.h"
29 #include "client.h"
30 #include "common.h"
31 #include "hash.h"
32 #include "hook.h"
33 #include "match.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "s_serv.h" /* captab */
37 #include "s_user.h"
38 #include "send.h"
39 #include "whowas.h"
40 #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
41 #include "s_newconf.h"
42 #include "logger.h"
43
44 struct config_channel_entry ConfigChannel;
45 rb_dlink_list global_channel_list;
46 static rb_bh *channel_heap;
47 static rb_bh *ban_heap;
48 static rb_bh *topic_heap;
49 static rb_bh *member_heap;
50
51 static int channel_capabs[] = { CAP_EX, CAP_IE,
52 CAP_SERVICE,
53 CAP_TS6
54 };
55
56 #define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
57 #define NCHCAP_COMBOS (1 << NCHCAPS)
58
59 static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
60
61 static void free_topic(struct Channel *chptr);
62
63 static int h_can_join;
64
65 /* init_channels()
66 *
67 * input -
68 * output -
69 * side effects - initialises the various blockheaps
70 */
71 void
72 init_channels(void)
73 {
74 channel_heap = rb_bh_create(sizeof(struct Channel), CHANNEL_HEAP_SIZE, "channel_heap");
75 ban_heap = rb_bh_create(sizeof(struct Ban), BAN_HEAP_SIZE, "ban_heap");
76 topic_heap = rb_bh_create(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE, "topic_heap");
77 member_heap = rb_bh_create(sizeof(struct membership), MEMBER_HEAP_SIZE, "member_heap");
78
79 h_can_join = register_hook("can_join");
80 }
81
82 /*
83 * allocate_channel - Allocates a channel
84 */
85 struct Channel *
86 allocate_channel(const char *chname)
87 {
88 struct Channel *chptr;
89 chptr = rb_bh_alloc(channel_heap);
90 chptr->chname = rb_strdup(chname);
91 return (chptr);
92 }
93
94 void
95 free_channel(struct Channel *chptr)
96 {
97 rb_free(chptr->chname);
98 rb_bh_free(channel_heap, chptr);
99 }
100
101 struct Ban *
102 allocate_ban(const char *banstr, const char *who)
103 {
104 struct Ban *bptr;
105 bptr = rb_bh_alloc(ban_heap);
106 bptr->banstr = rb_strdup(banstr);
107 bptr->who = rb_strdup(who);
108
109 return (bptr);
110 }
111
112 void
113 free_ban(struct Ban *bptr)
114 {
115 rb_free(bptr->banstr);
116 rb_free(bptr->who);
117 rb_bh_free(ban_heap, bptr);
118 }
119
120
121 /* find_channel_membership()
122 *
123 * input - channel to find them in, client to find
124 * output - membership of client in channel, else NULL
125 * side effects -
126 */
127 struct membership *
128 find_channel_membership(struct Channel *chptr, struct Client *client_p)
129 {
130 struct membership *msptr;
131 rb_dlink_node *ptr;
132
133 if(!IsClient(client_p))
134 return NULL;
135
136 /* Pick the most efficient list to use to be nice to things like
137 * CHANSERV which could be in a large number of channels
138 */
139 if(rb_dlink_list_length(&chptr->members) < rb_dlink_list_length(&client_p->user->channel))
140 {
141 RB_DLINK_FOREACH(ptr, chptr->members.head)
142 {
143 msptr = ptr->data;
144
145 if(msptr->client_p == client_p)
146 return msptr;
147 }
148 }
149 else
150 {
151 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
152 {
153 msptr = ptr->data;
154
155 if(msptr->chptr == chptr)
156 return msptr;
157 }
158 }
159
160 return NULL;
161 }
162
163 /* find_channel_status()
164 *
165 * input - membership to get status for, whether we can combine flags
166 * output - flags of user on channel
167 * side effects -
168 */
169 const char *
170 find_channel_status(struct membership *msptr, int combine)
171 {
172 static char buffer[3];
173 char *p;
174
175 p = buffer;
176
177 if(is_chanop(msptr))
178 {
179 if(!combine)
180 return "@";
181 *p++ = '@';
182 }
183
184 if(is_voiced(msptr))
185 *p++ = '+';
186
187 *p = '\0';
188 return buffer;
189 }
190
191 /* add_user_to_channel()
192 *
193 * input - channel to add client to, client to add, channel flags
194 * output -
195 * side effects - user is added to channel
196 */
197 void
198 add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
199 {
200 struct membership *msptr;
201
202 s_assert(client_p->user != NULL);
203 if(client_p->user == NULL)
204 return;
205
206 msptr = rb_bh_alloc(member_heap);
207
208 msptr->chptr = chptr;
209 msptr->client_p = client_p;
210 msptr->flags = flags;
211
212 rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
213 rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
214
215 if(MyClient(client_p))
216 rb_dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
217 }
218
219 /* remove_user_from_channel()
220 *
221 * input - membership pointer to remove from channel
222 * output -
223 * side effects - membership (thus user) is removed from channel
224 */
225 void
226 remove_user_from_channel(struct membership *msptr)
227 {
228 struct Client *client_p;
229 struct Channel *chptr;
230 s_assert(msptr != NULL);
231 if(msptr == NULL)
232 return;
233
234 client_p = msptr->client_p;
235 chptr = msptr->chptr;
236
237 rb_dlinkDelete(&msptr->usernode, &client_p->user->channel);
238 rb_dlinkDelete(&msptr->channode, &chptr->members);
239
240 if(client_p->servptr == &me)
241 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
242
243 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
244 destroy_channel(chptr);
245
246 rb_bh_free(member_heap, msptr);
247
248 return;
249 }
250
251 /* remove_user_from_channels()
252 *
253 * input - user to remove from all channels
254 * output -
255 * side effects - user is removed from all channels
256 */
257 void
258 remove_user_from_channels(struct Client *client_p)
259 {
260 struct Channel *chptr;
261 struct membership *msptr;
262 rb_dlink_node *ptr;
263 rb_dlink_node *next_ptr;
264
265 if(client_p == NULL)
266 return;
267
268 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
269 {
270 msptr = ptr->data;
271 chptr = msptr->chptr;
272
273 rb_dlinkDelete(&msptr->channode, &chptr->members);
274
275 if(client_p->servptr == &me)
276 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
277
278 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
279 destroy_channel(chptr);
280
281 rb_bh_free(member_heap, msptr);
282 }
283
284 client_p->user->channel.head = client_p->user->channel.tail = NULL;
285 client_p->user->channel.length = 0;
286 }
287
288 /* invalidate_bancache_user()
289 *
290 * input - user to invalidate ban cache for
291 * output -
292 * side effects - ban cache is invalidated for all memberships of that user
293 * to be used after a nick change
294 */
295 void
296 invalidate_bancache_user(struct Client *client_p)
297 {
298 struct membership *msptr;
299 rb_dlink_node *ptr;
300
301 if(client_p == NULL)
302 return;
303
304 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
305 {
306 msptr = ptr->data;
307 msptr->bants = 0;
308 msptr->flags &= ~CHFL_BANNED;
309 }
310 }
311
312 /* check_channel_name()
313 *
314 * input - channel name
315 * output - 1 if valid channel name, else 0
316 * side effects -
317 */
318 int
319 check_channel_name(const char *name)
320 {
321 s_assert(name != NULL);
322 if(name == NULL)
323 return 0;
324
325 for (; *name; ++name)
326 {
327 if(!IsChanChar(*name))
328 return 0;
329 }
330
331 return 1;
332 }
333
334 /* free_channel_list()
335 *
336 * input - rb_dlink list to free
337 * output -
338 * side effects - list of b/e/I modes is cleared
339 */
340 void
341 free_channel_list(rb_dlink_list * list)
342 {
343 rb_dlink_node *ptr;
344 rb_dlink_node *next_ptr;
345 struct Ban *actualBan;
346
347 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
348 {
349 actualBan = ptr->data;
350 free_ban(actualBan);
351 }
352
353 list->head = list->tail = NULL;
354 list->length = 0;
355 }
356
357 /* destroy_channel()
358 *
359 * input - channel to destroy
360 * output -
361 * side effects - channel is obliterated
362 */
363 void
364 destroy_channel(struct Channel *chptr)
365 {
366 rb_dlink_node *ptr, *next_ptr;
367
368 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
369 {
370 del_invite(chptr, ptr->data);
371 }
372
373 /* free all bans/exceptions/denies */
374 free_channel_list(&chptr->banlist);
375 free_channel_list(&chptr->exceptlist);
376 free_channel_list(&chptr->invexlist);
377 free_channel_list(&chptr->quietlist);
378
379 /* Free the topic */
380 free_topic(chptr);
381
382 rb_dlinkDelete(&chptr->node, &global_channel_list);
383 del_from_channel_hash(chptr->chname, chptr);
384 free_channel(chptr);
385 }
386
387 /* channel_pub_or_secret()
388 *
389 * input - channel
390 * output - "=" if public, "@" if secret, else "*"
391 * side effects -
392 */
393 static const char *
394 channel_pub_or_secret(struct Channel *chptr)
395 {
396 if(PubChannel(chptr))
397 return ("=");
398 else if(SecretChannel(chptr))
399 return ("@");
400 return ("*");
401 }
402
403 /* channel_member_names()
404 *
405 * input - channel to list, client to list to, show endofnames
406 * output -
407 * side effects - client is given list of users on channel
408 */
409 void
410 channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
411 {
412 struct membership *msptr;
413 struct Client *target_p;
414 rb_dlink_node *ptr;
415 char lbuf[BUFSIZE];
416 char *t;
417 int mlen;
418 int tlen;
419 int cur_len;
420 int is_member;
421 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
422
423 if(ShowChannel(client_p, chptr))
424 {
425 is_member = IsMember(client_p, chptr);
426
427 cur_len = mlen = rb_sprintf(lbuf, form_str(RPL_NAMREPLY),
428 me.name, client_p->name,
429 channel_pub_or_secret(chptr), chptr->chname);
430
431 t = lbuf + cur_len;
432
433 RB_DLINK_FOREACH(ptr, chptr->members.head)
434 {
435 msptr = ptr->data;
436 target_p = msptr->client_p;
437
438 if(IsInvisible(target_p) && !is_member)
439 continue;
440
441 /* space, possible "@+" prefix */
442 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
443 {
444 *(t - 1) = '\0';
445 sendto_one(client_p, "%s", lbuf);
446 cur_len = mlen;
447 t = lbuf + mlen;
448 }
449
450 tlen = rb_sprintf(t, "%s%s ", find_channel_status(msptr, stack),
451 target_p->name);
452
453 cur_len += tlen;
454 t += tlen;
455 }
456
457 /* The old behaviour here was to always output our buffer,
458 * even if there are no clients we can show. This happens
459 * when a client does "NAMES" with no parameters, and all
460 * the clients on a -sp channel are +i. I dont see a good
461 * reason for keeping that behaviour, as it just wastes
462 * bandwidth. --anfl
463 */
464 if(cur_len != mlen)
465 {
466 *(t - 1) = '\0';
467 sendto_one(client_p, "%s", lbuf);
468 }
469 }
470
471 if(show_eon)
472 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
473 me.name, client_p->name, chptr->chname);
474 }
475
476 /* del_invite()
477 *
478 * input - channel to remove invite from, client to remove
479 * output -
480 * side effects - user is removed from invite list, if exists
481 */
482 void
483 del_invite(struct Channel *chptr, struct Client *who)
484 {
485 rb_dlinkFindDestroy(who, &chptr->invites);
486 rb_dlinkFindDestroy(chptr, &who->user->invited);
487 }
488
489 /* is_banned()
490 *
491 * input - channel to check bans for, user to check bans against
492 * optional prebuilt buffers
493 * output - 1 if banned, else 0
494 * side effects -
495 */
496 int
497 is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
498 const char *s, const char *s2)
499 {
500 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
501 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
502 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
503 char *s3 = NULL;
504 rb_dlink_node *ptr;
505 struct Ban *actualBan = NULL;
506 struct Ban *actualExcept = NULL;
507
508 if(!MyClient(who))
509 return 0;
510
511 /* if the buffers havent been built, do it here */
512 if(s == NULL)
513 {
514 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
515 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
516
517 s = src_host;
518 s2 = src_iphost;
519 }
520 if(who->localClient->mangledhost != NULL)
521 {
522 /* if host mangling mode enabled, also check their real host */
523 if(!strcmp(who->host, who->localClient->mangledhost))
524 {
525 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
526 s3 = src_althost;
527 }
528 /* if host mangling mode not enabled and no other spoof,
529 * also check the mangled form of their host */
530 else if (!IsDynSpoof(who))
531 {
532 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
533 s3 = src_althost;
534 }
535 }
536
537 RB_DLINK_FOREACH(ptr, chptr->banlist.head)
538 {
539 actualBan = ptr->data;
540 if(match(actualBan->banstr, s) ||
541 match(actualBan->banstr, s2) ||
542 match_cidr(actualBan->banstr, s2) ||
543 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
544 (s3 != NULL && match(actualBan->banstr, s3)))
545 break;
546 else
547 actualBan = NULL;
548 }
549
550 if((actualBan != NULL) && ConfigChannel.use_except)
551 {
552 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
553 {
554 actualExcept = ptr->data;
555
556 /* theyre exempted.. */
557 if(match(actualExcept->banstr, s) ||
558 match(actualExcept->banstr, s2) ||
559 match_cidr(actualExcept->banstr, s2) ||
560 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
561 (s3 != NULL && match(actualExcept->banstr, s3)))
562 {
563 /* cache the fact theyre not banned */
564 if(msptr != NULL)
565 {
566 msptr->bants = chptr->bants;
567 msptr->flags &= ~CHFL_BANNED;
568 }
569
570 return CHFL_EXCEPTION;
571 }
572 }
573 }
574
575 /* cache the banned/not banned status */
576 if(msptr != NULL)
577 {
578 msptr->bants = chptr->bants;
579
580 if(actualBan != NULL)
581 {
582 msptr->flags |= CHFL_BANNED;
583 return CHFL_BAN;
584 }
585 else
586 {
587 msptr->flags &= ~CHFL_BANNED;
588 return 0;
589 }
590 }
591
592 return ((actualBan ? CHFL_BAN : 0));
593 }
594
595 /* is_quieted()
596 *
597 * input - channel to check bans for, user to check bans against
598 * optional prebuilt buffers
599 * output - 1 if banned, else 0
600 * side effects -
601 */
602 int
603 is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
604 const char *s, const char *s2)
605 {
606 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
607 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
608 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
609 char *s3 = NULL;
610 rb_dlink_node *ptr;
611 struct Ban *actualBan = NULL;
612 struct Ban *actualExcept = NULL;
613
614 if(!MyClient(who))
615 return 0;
616
617 /* if the buffers havent been built, do it here */
618 if(s == NULL)
619 {
620 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
621 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
622
623 s = src_host;
624 s2 = src_iphost;
625 }
626 if(who->localClient->mangledhost != NULL)
627 {
628 /* if host mangling mode enabled, also check their real host */
629 if(!strcmp(who->host, who->localClient->mangledhost))
630 {
631 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
632 s3 = src_althost;
633 }
634 /* if host mangling mode not enabled and no other spoof,
635 * also check the mangled form of their host */
636 else if (!IsDynSpoof(who))
637 {
638 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
639 s3 = src_althost;
640 }
641 }
642
643 RB_DLINK_FOREACH(ptr, chptr->quietlist.head)
644 {
645 actualBan = ptr->data;
646 if(match(actualBan->banstr, s) ||
647 match(actualBan->banstr, s2) ||
648 match_cidr(actualBan->banstr, s2) ||
649 match_extban(actualBan->banstr, who, chptr, CHFL_QUIET) ||
650 (s3 != NULL && match(actualBan->banstr, s3)))
651 break;
652 else
653 actualBan = NULL;
654 }
655
656 if((actualBan != NULL) && ConfigChannel.use_except)
657 {
658 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
659 {
660 actualExcept = ptr->data;
661
662 /* theyre exempted.. */
663 if(match(actualExcept->banstr, s) ||
664 match(actualExcept->banstr, s2) ||
665 match_cidr(actualExcept->banstr, s2) ||
666 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
667 (s3 != NULL && match(actualExcept->banstr, s3)))
668 {
669 /* cache the fact theyre not banned */
670 if(msptr != NULL)
671 {
672 msptr->bants = chptr->bants;
673 msptr->flags &= ~CHFL_BANNED;
674 }
675
676 return CHFL_EXCEPTION;
677 }
678 }
679 }
680
681 /* cache the banned/not banned status */
682 if(msptr != NULL)
683 {
684 msptr->bants = chptr->bants;
685
686 if(actualBan != NULL)
687 {
688 msptr->flags |= CHFL_BANNED;
689 return CHFL_BAN;
690 }
691 else
692 {
693 msptr->flags &= ~CHFL_BANNED;
694 return 0;
695 }
696 }
697
698 return ((actualBan ? CHFL_BAN : 0));
699 }
700
701 /* can_join()
702 *
703 * input - client to check, channel to check for, key
704 * output - reason for not being able to join, else 0
705 * side effects -
706 */
707 int
708 can_join(struct Client *source_p, struct Channel *chptr, char *key)
709 {
710 rb_dlink_node *invite = NULL;
711 rb_dlink_node *ptr;
712 struct Ban *invex = NULL;
713 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
714 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
715 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
716 int use_althost = 0;
717 int i = 0;
718 hook_data_channel moduledata;
719
720 s_assert(source_p->localClient != NULL);
721
722 rb_sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
723 rb_sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
724 if(source_p->localClient->mangledhost != NULL)
725 {
726 /* if host mangling mode enabled, also check their real host */
727 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
728 {
729 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
730 use_althost = 1;
731 }
732 /* if host mangling mode not enabled and no other spoof,
733 * also check the mangled form of their host */
734 else if (!IsDynSpoof(source_p))
735 {
736 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
737 use_althost = 1;
738 }
739 }
740
741 if((is_banned(chptr, source_p, NULL, src_host, src_iphost)) == CHFL_BAN)
742 return (ERR_BANNEDFROMCHAN);
743
744 if(chptr->mode.mode & MODE_INVITEONLY)
745 {
746 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
747 {
748 if(invite->data == chptr)
749 break;
750 }
751 if(invite == NULL)
752 {
753 if(!ConfigChannel.use_invex)
754 return (ERR_INVITEONLYCHAN);
755 RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
756 {
757 invex = ptr->data;
758 if(match(invex->banstr, src_host)
759 || match(invex->banstr, src_iphost)
760 || match_cidr(invex->banstr, src_iphost)
761 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
762 || (use_althost && match(invex->banstr, src_althost)))
763 break;
764 }
765 if(ptr == NULL)
766 return (ERR_INVITEONLYCHAN);
767 }
768 }
769
770 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
771 return (ERR_BADCHANNELKEY);
772
773 if(chptr->mode.limit &&
774 rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
775 i = ERR_CHANNELISFULL;
776 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
777 i = ERR_NEEDREGGEDNICK;
778 /* join throttling stuff --nenolod */
779 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
780 {
781 if ((rb_current_time() - chptr->join_delta <=
782 chptr->mode.join_time) && (chptr->join_count >=
783 chptr->mode.join_num))
784 i = ERR_THROTTLE;
785 }
786
787 /* allow /invite to override +l/+r/+j also -- jilles */
788 if (i != 0 && invite == NULL)
789 {
790 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
791 {
792 if(invite->data == chptr)
793 break;
794 }
795 if (invite == NULL)
796 return i;
797 }
798
799 moduledata.client = source_p;
800 moduledata.chptr = chptr;
801 moduledata.approved = 0;
802
803 call_hook(h_can_join, &moduledata);
804
805 return moduledata.approved;
806 }
807
808 /* can_send()
809 *
810 * input - user to check in channel, membership pointer
811 * output - whether can explicitly send or not, else CAN_SEND_NONOP
812 * side effects -
813 */
814 int
815 can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
816 {
817 if(IsServer(source_p) || IsService(source_p))
818 return CAN_SEND_OPV;
819
820 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
821 !IsOper(source_p) && !IsExemptResv(source_p))
822 return CAN_SEND_NO;
823
824 if(msptr == NULL)
825 {
826 msptr = find_channel_membership(chptr, source_p);
827
828 if(msptr == NULL)
829 {
830 /* if its +m or +n and theyre not in the channel,
831 * they cant send. we dont check bans here because
832 * theres no possibility of caching them --fl
833 */
834 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
835 return CAN_SEND_NO;
836 else
837 return CAN_SEND_NONOP;
838 }
839 }
840
841 if(is_chanop_voiced(msptr))
842 return CAN_SEND_OPV;
843
844 if(chptr->mode.mode & MODE_MODERATED)
845 return CAN_SEND_NO;
846
847 if(MyClient(source_p))
848 {
849 /* cached can_send */
850 if(msptr->bants == chptr->bants)
851 {
852 if(can_send_banned(msptr))
853 return CAN_SEND_NO;
854 }
855 else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
856 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
857 return CAN_SEND_NO;
858 }
859
860 return CAN_SEND_NONOP;
861 }
862
863 /* find_bannickchange_channel()
864 * Input: client to check
865 * Output: channel preventing nick change
866 */
867 struct Channel *
868 find_bannickchange_channel(struct Client *client_p)
869 {
870 struct Channel *chptr;
871 struct membership *msptr;
872 rb_dlink_node *ptr;
873 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
874 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
875
876 if (!MyClient(client_p))
877 return NULL;
878
879 rb_sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
880 rb_sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
881
882 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
883 {
884 msptr = ptr->data;
885 chptr = msptr->chptr;
886 if (is_chanop_voiced(msptr))
887 continue;
888 /* cached can_send */
889 if (msptr->bants == chptr->bants)
890 {
891 if (can_send_banned(msptr))
892 return chptr;
893 }
894 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN
895 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
896 return chptr;
897 }
898 return NULL;
899 }
900
901 /* void check_spambot_warning(struct Client *source_p)
902 * Input: Client to check, channel name or NULL if this is a part.
903 * Output: none
904 * Side-effects: Updates the client's oper_warn_count_down, warns the
905 * IRC operators if necessary, and updates join_leave_countdown as
906 * needed.
907 */
908 void
909 check_spambot_warning(struct Client *source_p, const char *name)
910 {
911 int t_delta;
912 int decrement_count;
913 if((GlobalSetOptions.spam_num &&
914 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
915 {
916 if(source_p->localClient->oper_warn_count_down > 0)
917 source_p->localClient->oper_warn_count_down--;
918 else
919 source_p->localClient->oper_warn_count_down = 0;
920 if(source_p->localClient->oper_warn_count_down == 0)
921 {
922 /* Its already known as a possible spambot */
923 if(name != NULL)
924 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
925 "User %s (%s@%s) trying to join %s is a possible spambot",
926 source_p->name,
927 source_p->username, source_p->orighost, name);
928 else
929 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
930 "User %s (%s@%s) is a possible spambot",
931 source_p->name,
932 source_p->username, source_p->orighost);
933 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
934 }
935 }
936 else
937 {
938 if((t_delta =
939 (rb_current_time() - source_p->localClient->last_leave_time)) >
940 JOIN_LEAVE_COUNT_EXPIRE_TIME)
941 {
942 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
943 if(decrement_count > source_p->localClient->join_leave_count)
944 source_p->localClient->join_leave_count = 0;
945 else
946 source_p->localClient->join_leave_count -= decrement_count;
947 }
948 else
949 {
950 if((rb_current_time() -
951 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
952 {
953 /* oh, its a possible spambot */
954 source_p->localClient->join_leave_count++;
955 }
956 }
957 if(name != NULL)
958 source_p->localClient->last_join_time = rb_current_time();
959 else
960 source_p->localClient->last_leave_time = rb_current_time();
961 }
962 }
963
964 /* check_splitmode()
965 *
966 * input -
967 * output -
968 * side effects - compares usercount and servercount against their split
969 * values and adjusts splitmode accordingly
970 */
971 void
972 check_splitmode(void *unused)
973 {
974 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
975 {
976 /* not split, we're being asked to check now because someone
977 * has left
978 */
979 if(!splitmode)
980 {
981 if(eob_count < split_servers || Count.total < split_users)
982 {
983 splitmode = 1;
984 sendto_realops_snomask(SNO_GENERAL, L_ALL,
985 "Network split, activating splitmode");
986 check_splitmode_ev = rb_event_addish("check_splitmode", check_splitmode, NULL, 2);
987 }
988 }
989 /* in splitmode, check whether its finished */
990 else if(eob_count >= split_servers && Count.total >= split_users)
991 {
992 splitmode = 0;
993
994 sendto_realops_snomask(SNO_GENERAL, L_ALL,
995 "Network rejoined, deactivating splitmode");
996
997 rb_event_delete(check_splitmode_ev);
998 check_splitmode_ev = NULL;
999 }
1000 }
1001 }
1002
1003
1004 /* allocate_topic()
1005 *
1006 * input - channel to allocate topic for
1007 * output - 1 on success, else 0
1008 * side effects - channel gets a topic allocated
1009 */
1010 static void
1011 allocate_topic(struct Channel *chptr)
1012 {
1013 void *ptr;
1014
1015 if(chptr == NULL)
1016 return;
1017
1018 ptr = rb_bh_alloc(topic_heap);
1019
1020 /* Basically we allocate one large block for the topic and
1021 * the topic info. We then split it up into two and shove it
1022 * in the chptr
1023 */
1024 chptr->topic = ptr;
1025 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1026 *chptr->topic = '\0';
1027 *chptr->topic_info = '\0';
1028 }
1029
1030 /* free_topic()
1031 *
1032 * input - channel which has topic to free
1033 * output -
1034 * side effects - channels topic is free'd
1035 */
1036 static void
1037 free_topic(struct Channel *chptr)
1038 {
1039 void *ptr;
1040
1041 if(chptr == NULL || chptr->topic == NULL)
1042 return;
1043
1044 /* This is safe for now - If you change allocate_topic you
1045 * MUST change this as well
1046 */
1047 ptr = chptr->topic;
1048 rb_bh_free(topic_heap, ptr);
1049 chptr->topic = NULL;
1050 chptr->topic_info = NULL;
1051 }
1052
1053 /* set_channel_topic()
1054 *
1055 * input - channel, topic to set, topic info and topic ts
1056 * output -
1057 * side effects - channels topic, topic info and TS are set.
1058 */
1059 void
1060 set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1061 {
1062 if(strlen(topic) > 0)
1063 {
1064 if(chptr->topic == NULL)
1065 allocate_topic(chptr);
1066 rb_strlcpy(chptr->topic, topic, TOPICLEN + 1);
1067 rb_strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
1068 chptr->topic_time = topicts;
1069 }
1070 else
1071 {
1072 if(chptr->topic != NULL)
1073 free_topic(chptr);
1074 chptr->topic_time = 0;
1075 }
1076 }
1077
1078 /* channel_modes()
1079 *
1080 * inputs - pointer to channel
1081 * - pointer to client
1082 * output - string with simple modes
1083 * side effects - result from previous calls overwritten
1084 *
1085 * Stolen from ShadowIRCd 4 --nenolod
1086 */
1087 const char *
1088 channel_modes(struct Channel *chptr, struct Client *client_p)
1089 {
1090 int i;
1091 char buf1[BUFSIZE];
1092 char buf2[BUFSIZE];
1093 static char final[BUFSIZE];
1094 char *mbuf = buf1;
1095 char *pbuf = buf2;
1096
1097 *mbuf++ = '+';
1098 *pbuf = '\0';
1099
1100 for (i = 0; i < 256; i++)
1101 if(chptr->mode.mode & chmode_flags[i])
1102 *mbuf++ = i;
1103
1104 if(chptr->mode.limit)
1105 {
1106 *mbuf++ = 'l';
1107
1108 if(!IsClient(client_p) || IsMember(client_p, chptr))
1109 pbuf += rb_sprintf(pbuf, " %d", chptr->mode.limit);
1110 }
1111
1112 if(*chptr->mode.key)
1113 {
1114 *mbuf++ = 'k';
1115
1116 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1117 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.key);
1118 }
1119
1120 if(chptr->mode.join_num)
1121 {
1122 *mbuf++ = 'j';
1123
1124 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1125 pbuf += rb_sprintf(pbuf, " %d:%d", chptr->mode.join_num,
1126 chptr->mode.join_time);
1127 }
1128
1129 if(*chptr->mode.forward && (ConfigChannel.use_forward || !IsClient(client_p)))
1130 {
1131 *mbuf++ = 'f';
1132
1133 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1134 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.forward);
1135 }
1136
1137 *mbuf = '\0';
1138
1139 rb_strlcpy(final, buf1, sizeof final);
1140 rb_strlcat(final, buf2, sizeof final);
1141 return final;
1142 }
1143
1144 /* Now lets do some stuff to keep track of what combinations of
1145 * servers exist...
1146 * Note that the number of combinations doubles each time you add
1147 * something to this list. Each one is only quick if no servers use that
1148 * combination, but if the numbers get too high here MODE will get too
1149 * slow. I suggest if you get more than 7 here, you consider getting rid
1150 * of some and merging or something. If it wasn't for irc+cs we would
1151 * probably not even need to bother about most of these, but unfortunately
1152 * we do. -A1kmm
1153 */
1154
1155 /* void init_chcap_usage_counts(void)
1156 *
1157 * Inputs - none
1158 * Output - none
1159 * Side-effects - Initialises the usage counts to zero. Fills in the
1160 * chcap_yes and chcap_no combination tables.
1161 */
1162 void
1163 init_chcap_usage_counts(void)
1164 {
1165 unsigned long m, c, y, n;
1166
1167 memset(chcap_combos, 0, sizeof(chcap_combos));
1168
1169 /* For every possible combination */
1170 for (m = 0; m < NCHCAP_COMBOS; m++)
1171 {
1172 /* Check each capab */
1173 for (c = y = n = 0; c < NCHCAPS; c++)
1174 {
1175 if((m & (1 << c)) == 0)
1176 n |= channel_capabs[c];
1177 else
1178 y |= channel_capabs[c];
1179 }
1180 chcap_combos[m].cap_yes = y;
1181 chcap_combos[m].cap_no = n;
1182 }
1183 }
1184
1185 /* void set_chcap_usage_counts(struct Client *serv_p)
1186 * Input: serv_p; The client whose capabs to register.
1187 * Output: none
1188 * Side-effects: Increments the usage counts for the correct capab
1189 * combination.
1190 */
1191 void
1192 set_chcap_usage_counts(struct Client *serv_p)
1193 {
1194 int n;
1195
1196 for (n = 0; n < NCHCAP_COMBOS; n++)
1197 {
1198 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1199 NotCapable(serv_p, chcap_combos[n].cap_no))
1200 {
1201 chcap_combos[n].count++;
1202 return;
1203 }
1204 }
1205
1206 /* This should be impossible -A1kmm. */
1207 s_assert(0);
1208 }
1209
1210 /* void set_chcap_usage_counts(struct Client *serv_p)
1211 *
1212 * Inputs - serv_p; The client whose capabs to register.
1213 * Output - none
1214 * Side-effects - Decrements the usage counts for the correct capab
1215 * combination.
1216 */
1217 void
1218 unset_chcap_usage_counts(struct Client *serv_p)
1219 {
1220 int n;
1221
1222 for (n = 0; n < NCHCAP_COMBOS; n++)
1223 {
1224 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1225 NotCapable(serv_p, chcap_combos[n].cap_no))
1226 {
1227 /* Hopefully capabs can't change dynamically or anything... */
1228 s_assert(chcap_combos[n].count > 0);
1229
1230 if(chcap_combos[n].count > 0)
1231 chcap_combos[n].count--;
1232 return;
1233 }
1234 }
1235
1236 /* This should be impossible -A1kmm. */
1237 s_assert(0);
1238 }
1239
1240 /* void send_cap_mode_changes(struct Client *client_p,
1241 * struct Client *source_p,
1242 * struct Channel *chptr, int cap, int nocap)
1243 * Input: The client sending(client_p), the source client(source_p),
1244 * the channel to send mode changes for(chptr)
1245 * Output: None.
1246 * Side-effects: Sends the appropriate mode changes to capable servers.
1247 *
1248 * Reverted back to my original design, except that we now keep a count
1249 * of the number of servers which each combination as an optimisation, so
1250 * the capabs combinations which are not needed are not worked out. -A1kmm
1251 */
1252 void
1253 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1254 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1255 {
1256 static char modebuf[BUFSIZE];
1257 static char parabuf[BUFSIZE];
1258 int i, mbl, pbl, nc, mc, preflen, len;
1259 char *pbuf;
1260 const char *arg;
1261 int dir;
1262 int j;
1263 int cap;
1264 int nocap;
1265 int arglen;
1266
1267 /* Now send to servers... */
1268 for (j = 0; j < NCHCAP_COMBOS; j++)
1269 {
1270 if(chcap_combos[j].count == 0)
1271 continue;
1272
1273 mc = 0;
1274 nc = 0;
1275 pbl = 0;
1276 parabuf[0] = 0;
1277 pbuf = parabuf;
1278 dir = MODE_QUERY;
1279
1280 cap = chcap_combos[j].cap_yes;
1281 nocap = chcap_combos[j].cap_no;
1282
1283 mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
1284 use_id(source_p), (long) chptr->channelts,
1285 chptr->chname);
1286
1287 /* loop the list of - modes we have */
1288 for (i = 0; i < mode_count; i++)
1289 {
1290 /* if they dont support the cap we need, or they do support a cap they
1291 * cant have, then dont add it to the modebuf.. that way they wont see
1292 * the mode
1293 */
1294 if((mode_changes[i].letter == 0) ||
1295 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1296 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1297 continue;
1298
1299 if(!EmptyString(mode_changes[i].id))
1300 arg = mode_changes[i].id;
1301 else
1302 arg = mode_changes[i].arg;
1303
1304 if(arg)
1305 {
1306 arglen = strlen(arg);
1307
1308 /* dont even think about it! --fl */
1309 if(arglen > MODEBUFLEN - 5)
1310 continue;
1311 }
1312
1313 /* if we're creeping past the buf size, we need to send it and make
1314 * another line for the other modes
1315 * XXX - this could give away server topology with uids being
1316 * different lengths, but not much we can do, except possibly break
1317 * them as if they were the longest of the nick or uid at all times,
1318 * which even then won't work as we don't always know the uid -A1kmm.
1319 */
1320 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1321 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1322 {
1323 if(nc != 0)
1324 sendto_server(client_p, chptr, cap, nocap,
1325 "%s %s", modebuf, parabuf);
1326 nc = 0;
1327 mc = 0;
1328
1329 mbl = preflen;
1330 pbl = 0;
1331 pbuf = parabuf;
1332 parabuf[0] = 0;
1333 dir = MODE_QUERY;
1334 }
1335
1336 if(dir != mode_changes[i].dir)
1337 {
1338 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1339 dir = mode_changes[i].dir;
1340 }
1341
1342 modebuf[mbl++] = mode_changes[i].letter;
1343 modebuf[mbl] = 0;
1344 nc++;
1345
1346 if(arg != NULL)
1347 {
1348 len = rb_sprintf(pbuf, "%s ", arg);
1349 pbuf += len;
1350 pbl += len;
1351 mc++;
1352 }
1353 }
1354
1355 if(pbl && parabuf[pbl - 1] == ' ')
1356 parabuf[pbl - 1] = 0;
1357
1358 if(nc != 0)
1359 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
1360 }
1361 }