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