]> jfr.im git - irc/rqf/shadowircd.git/blame - src/channel.c
[svn] Fix desyncs with very long extbans. Bans can now be upto 195 chars long.
[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
49extern dlink_list global_channel_list;
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;
137 dlink_node *ptr;
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 */
145 if(dlink_list_length(&chptr->members) < dlink_list_length(&client_p->user->channel))
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
218 dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
219 dlinkAdd(msptr, &msptr->channode, &chptr->members);
220
221 if(MyClient(client_p))
222 dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
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
243 dlinkDelete(&msptr->usernode, &client_p->user->channel);
244 dlinkDelete(&msptr->channode, &chptr->members);
245
246 if(client_p->servptr == &me)
247 dlinkDelete(&msptr->locchannode, &chptr->locmembers);
248
249 chptr->users_last = CurrentTime;
250
251 if(!(chptr->mode.mode & MODE_PERMANENT) && dlink_list_length(&chptr->members) <= 0)
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;
270 dlink_node *ptr;
271 dlink_node *next_ptr;
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
281 dlinkDelete(&msptr->channode, &chptr->members);
282
283 if(client_p->servptr == &me)
284 dlinkDelete(&msptr->locchannode, &chptr->locmembers);
285
286 chptr->users_last = CurrentTime;
287
288 if(!(chptr->mode.mode & MODE_PERMANENT) && dlink_list_length(&chptr->members) <= 0)
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;
309 dlink_node *ptr;
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 *
346 * input - dlink list to free
347 * output -
348 * side effects - list of b/e/I modes is cleared
349 */
350void
351free_channel_list(dlink_list * list)
352{
353 dlink_node *ptr;
354 dlink_node *next_ptr;
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{
376 dlink_node *ptr, *next_ptr;
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
392 dlinkDelete(&chptr->node, &global_channel_list);
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;
424 dlink_node *ptr;
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
437 cur_len = mlen = ircsprintf(lbuf, form_str(RPL_NAMREPLY),
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
460 tlen = ircsprintf(t, "%s%s ", find_channel_status(msptr, stack),
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{
495 dlinkFindDestroy(who, &chptr->invites);
496 dlinkFindDestroy(chptr, &who->user->invited);
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;
514 dlink_node *ptr;
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 {
524 ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
525 ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
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 {
535 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
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 {
542 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
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;
620 dlink_node *ptr;
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 {
630 ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
631 ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
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 {
641 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
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 {
648 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
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{
1ebf4db4 720 dlink_node *invite = NULL;
212380e3 721 dlink_node *ptr;
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
732 ircsprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
733 ircsprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
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 {
739 ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
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 {
746 ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
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 &&
784 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;
882 dlink_node *ptr;
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
889 ircsprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
890 ircsprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
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)
934 sendto_realops_snomask(SNO_BOTS, L_ALL,
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
939 sendto_realops_snomask(SNO_BOTS, L_ALL,
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
1087static const struct mode_letter
1088{
1089 const unsigned int mode;
1090 const unsigned char letter;
1091} flags[] =
1092{
1093 {MODE_INVITEONLY, 'i'},
1094 {MODE_MODERATED, 'm'},
1095 {MODE_NOPRIVMSGS, 'n'},
1096 {MODE_PRIVATE, 'p'},
1097 {MODE_SECRET, 's'},
1098 {MODE_TOPICLIMIT, 't'},
1099 {MODE_NOCOLOR, 'c'},
1100 {MODE_FREEINVITE, 'g'},
1101 {MODE_OPMODERATE, 'z'},
1102 {MODE_EXLIMIT, 'L'},
1103 {MODE_PERMANENT, 'P'},
1104 {MODE_FREETARGET, 'F'},
1105 {MODE_DISFORWARD, 'Q'},
1106 {MODE_REGONLY, 'r'},
1107 {0, '\0'}
1108};
1109
1110/* channel_modes()
1111 *
1112 * inputs - pointer to channel
1113 * - pointer to client
f1e35c19 1114 * output - string with simple modes
1115 * side effects - result from previous calls overwritten
212380e3 1116 *
1117 * Stolen from ShadowIRCd 4 --nenolod
1118 */
1119const char *
1120channel_modes(struct Channel *chptr, struct Client *client_p)
1121{
1122 int i;
1123 char buf1[BUFSIZE];
1124 char buf2[BUFSIZE];
1125 static char final[BUFSIZE];
1126 char *mbuf = buf1;
1127 char *pbuf = buf2;
1128
1129 *mbuf++ = '+';
1130 *pbuf = '\0';
1131
1132 for (i = 0; flags[i].mode; ++i)
1133 if(chptr->mode.mode & flags[i].mode)
1134 *mbuf++ = flags[i].letter;
1135
1136 if(chptr->mode.limit)
1137 {
1138 *mbuf++ = 'l';
1139
f1e35c19 1140 if(!IsClient(client_p) || IsMember(client_p, chptr))
1141 pbuf += ircsprintf(pbuf, " %d", chptr->mode.limit);
212380e3 1142 }
1143
1144 if(*chptr->mode.key)
1145 {
1146 *mbuf++ = 'k';
1147
f1e35c19 1148 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1149 pbuf += ircsprintf(pbuf, " %s", chptr->mode.key);
212380e3 1150 }
1151
1152 if(chptr->mode.join_num)
1153 {
1154 *mbuf++ = 'j';
1155
f1e35c19 1156 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1157 pbuf += ircsprintf(pbuf, " %d:%d", chptr->mode.join_num,
212380e3 1158 chptr->mode.join_time);
1159 }
1160
f1e35c19 1161 if(*chptr->mode.forward && (ConfigChannel.use_forward || !IsClient(client_p)))
212380e3 1162 {
1163 *mbuf++ = 'f';
1164
f1e35c19 1165 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1166 pbuf += ircsprintf(pbuf, " %s", chptr->mode.forward);
212380e3 1167 }
1168
1169 *mbuf = '\0';
1170
f1e35c19 1171 strlcpy(final, buf1, sizeof final);
1172 strlcat(final, buf2, sizeof final);
212380e3 1173 return final;
1174}
1175
1176/* Now lets do some stuff to keep track of what combinations of
1177 * servers exist...
1178 * Note that the number of combinations doubles each time you add
1179 * something to this list. Each one is only quick if no servers use that
1180 * combination, but if the numbers get too high here MODE will get too
1181 * slow. I suggest if you get more than 7 here, you consider getting rid
1182 * of some and merging or something. If it wasn't for irc+cs we would
1183 * probably not even need to bother about most of these, but unfortunately
1184 * we do. -A1kmm
1185 */
1186
1187/* void init_chcap_usage_counts(void)
1188 *
1189 * Inputs - none
1190 * Output - none
1191 * Side-effects - Initialises the usage counts to zero. Fills in the
1192 * chcap_yes and chcap_no combination tables.
1193 */
1194void
1195init_chcap_usage_counts(void)
1196{
1197 unsigned long m, c, y, n;
1198
1199 memset(chcap_combos, 0, sizeof(chcap_combos));
1200
1201 /* For every possible combination */
1202 for (m = 0; m < NCHCAP_COMBOS; m++)
1203 {
1204 /* Check each capab */
1205 for (c = y = n = 0; c < NCHCAPS; c++)
1206 {
1207 if((m & (1 << c)) == 0)
1208 n |= channel_capabs[c];
1209 else
1210 y |= channel_capabs[c];
1211 }
1212 chcap_combos[m].cap_yes = y;
1213 chcap_combos[m].cap_no = n;
1214 }
1215}
1216
1217/* void set_chcap_usage_counts(struct Client *serv_p)
1218 * Input: serv_p; The client whose capabs to register.
1219 * Output: none
1220 * Side-effects: Increments the usage counts for the correct capab
1221 * combination.
1222 */
1223void
1224set_chcap_usage_counts(struct Client *serv_p)
1225{
1226 int n;
1227
1228 for (n = 0; n < NCHCAP_COMBOS; n++)
1229 {
1230 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1231 NotCapable(serv_p, chcap_combos[n].cap_no))
1232 {
1233 chcap_combos[n].count++;
1234 return;
1235 }
1236 }
1237
1238 /* This should be impossible -A1kmm. */
1239 s_assert(0);
1240}
1241
1242/* void set_chcap_usage_counts(struct Client *serv_p)
1243 *
1244 * Inputs - serv_p; The client whose capabs to register.
1245 * Output - none
1246 * Side-effects - Decrements the usage counts for the correct capab
1247 * combination.
1248 */
1249void
1250unset_chcap_usage_counts(struct Client *serv_p)
1251{
1252 int n;
1253
1254 for (n = 0; n < NCHCAP_COMBOS; n++)
1255 {
1256 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1257 NotCapable(serv_p, chcap_combos[n].cap_no))
1258 {
1259 /* Hopefully capabs can't change dynamically or anything... */
1260 s_assert(chcap_combos[n].count > 0);
1261
1262 if(chcap_combos[n].count > 0)
1263 chcap_combos[n].count--;
1264 return;
1265 }
1266 }
1267
1268 /* This should be impossible -A1kmm. */
1269 s_assert(0);
1270}
1271
1272/* void send_cap_mode_changes(struct Client *client_p,
1273 * struct Client *source_p,
1274 * struct Channel *chptr, int cap, int nocap)
1275 * Input: The client sending(client_p), the source client(source_p),
1276 * the channel to send mode changes for(chptr)
1277 * Output: None.
1278 * Side-effects: Sends the appropriate mode changes to capable servers.
1279 *
1280 * Reverted back to my original design, except that we now keep a count
1281 * of the number of servers which each combination as an optimisation, so
1282 * the capabs combinations which are not needed are not worked out. -A1kmm
1283 */
1284void
1285send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1286 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1287{
1288 static char modebuf[BUFSIZE];
1289 static char parabuf[BUFSIZE];
1290 int i, mbl, pbl, nc, mc, preflen, len;
1291 char *pbuf;
1292 const char *arg;
1293 int dir;
1294 int j;
1295 int cap;
1296 int nocap;
1297 int arglen;
1298
1299 /* Now send to servers... */
1300 for (j = 0; j < NCHCAP_COMBOS; j++)
1301 {
1302 if(chcap_combos[j].count == 0)
1303 continue;
1304
1305 mc = 0;
1306 nc = 0;
1307 pbl = 0;
1308 parabuf[0] = 0;
1309 pbuf = parabuf;
1310 dir = MODE_QUERY;
1311
1312 cap = chcap_combos[j].cap_yes;
1313 nocap = chcap_combos[j].cap_no;
1314
1315 if(cap & CAP_TS6)
1316 mbl = preflen = ircsprintf(modebuf, ":%s TMODE %ld %s ",
1317 use_id(source_p), (long) chptr->channelts,
1318 chptr->chname);
1319 else
1320 mbl = preflen = ircsprintf(modebuf, ":%s MODE %s ",
1321 source_p->name, chptr->chname);
1322
1323 /* loop the list of - modes we have */
1324 for (i = 0; i < mode_count; i++)
1325 {
1326 /* if they dont support the cap we need, or they do support a cap they
1327 * cant have, then dont add it to the modebuf.. that way they wont see
1328 * the mode
1329 */
1330 if((mode_changes[i].letter == 0) ||
1331 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1332 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1333 continue;
1334
1335 if((cap & CAP_TS6) && !EmptyString(mode_changes[i].id))
1336 arg = mode_changes[i].id;
1337 else
1338 arg = mode_changes[i].arg;
1339
1340 if(arg)
1341 {
1342 arglen = strlen(arg);
1343
1344 /* dont even think about it! --fl */
1345 if(arglen > MODEBUFLEN - 5)
1346 continue;
1347 }
1348
1349 /* if we're creeping past the buf size, we need to send it and make
1350 * another line for the other modes
1351 * XXX - this could give away server topology with uids being
1352 * different lengths, but not much we can do, except possibly break
1353 * them as if they were the longest of the nick or uid at all times,
1354 * which even then won't work as we don't always know the uid -A1kmm.
1355 */
1356 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1357 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1358 {
1359 if(nc != 0)
1360 sendto_server(client_p, chptr, cap, nocap,
1361 "%s %s", modebuf, parabuf);
1362 nc = 0;
1363 mc = 0;
1364
1365 mbl = preflen;
1366 pbl = 0;
1367 pbuf = parabuf;
1368 parabuf[0] = 0;
1369 dir = MODE_QUERY;
1370 }
1371
1372 if(dir != mode_changes[i].dir)
1373 {
1374 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1375 dir = mode_changes[i].dir;
1376 }
1377
1378 modebuf[mbl++] = mode_changes[i].letter;
1379 modebuf[mbl] = 0;
1380 nc++;
1381
1382 if(arg != NULL)
1383 {
1384 len = ircsprintf(pbuf, "%s ", arg);
1385 pbuf += len;
1386 pbl += len;
1387 mc++;
1388 }
1389 }
1390
1391 if(pbl && parabuf[pbl - 1] == ' ')
1392 parabuf[pbl - 1] = 0;
1393
1394 if(nc != 0)
1395 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
1396 }
1397}