]> jfr.im git - irc/rqf/shadowircd.git/blame - src/channel.c
[svn] Merge old trunk r2065,r2067:
[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 *
f1e35c19 24 * $Id: channel.c 3432 2007-04-26 23:01:16Z 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);
96 DupNString(chptr->chname, chname, CHANNELLEN);
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);
112 DupNString(bptr->banstr, banstr, BANLEN);
113 DupNString(bptr->who, who, BANLEN);
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);
387
388 /* Free the topic */
389 free_topic(chptr);
390
391 dlinkDelete(&chptr->node, &global_channel_list);
392 del_from_channel_hash(chptr->chname, chptr);
393 free_channel(chptr);
394}
395
396/* channel_pub_or_secret()
397 *
398 * input - channel
399 * output - "=" if public, "@" if secret, else "*"
400 * side effects -
401 */
402static const char *
403channel_pub_or_secret(struct Channel *chptr)
404{
405 if(PubChannel(chptr))
406 return ("=");
407 else if(SecretChannel(chptr))
408 return ("@");
409 return ("*");
410}
411
412/* channel_member_names()
413 *
414 * input - channel to list, client to list to, show endofnames
415 * output -
416 * side effects - client is given list of users on channel
417 */
418void
419channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
420{
421 struct membership *msptr;
422 struct Client *target_p;
423 dlink_node *ptr;
424 char lbuf[BUFSIZE];
425 char *t;
426 int mlen;
427 int tlen;
428 int cur_len;
429 int is_member;
430 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
431
432 if(ShowChannel(client_p, chptr))
433 {
434 is_member = IsMember(client_p, chptr);
435
436 cur_len = mlen = ircsprintf(lbuf, form_str(RPL_NAMREPLY),
437 me.name, client_p->name,
438 channel_pub_or_secret(chptr), chptr->chname);
439
440 t = lbuf + cur_len;
441
442 DLINK_FOREACH(ptr, chptr->members.head)
443 {
444 msptr = ptr->data;
445 target_p = msptr->client_p;
446
447 if(IsInvisible(target_p) && !is_member)
448 continue;
449
450 /* space, possible "@+" prefix */
451 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
452 {
453 *(t - 1) = '\0';
454 sendto_one(client_p, "%s", lbuf);
455 cur_len = mlen;
456 t = lbuf + mlen;
457 }
458
459 tlen = ircsprintf(t, "%s%s ", find_channel_status(msptr, stack),
460 target_p->name);
461
462 cur_len += tlen;
463 t += tlen;
464 }
465
466 /* The old behaviour here was to always output our buffer,
467 * even if there are no clients we can show. This happens
468 * when a client does "NAMES" with no parameters, and all
469 * the clients on a -sp channel are +i. I dont see a good
470 * reason for keeping that behaviour, as it just wastes
471 * bandwidth. --anfl
472 */
473 if(cur_len != mlen)
474 {
475 *(t - 1) = '\0';
476 sendto_one(client_p, "%s", lbuf);
477 }
478 }
479
480 if(show_eon)
481 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
482 me.name, client_p->name, chptr->chname);
483}
484
485/* del_invite()
486 *
487 * input - channel to remove invite from, client to remove
488 * output -
489 * side effects - user is removed from invite list, if exists
490 */
491void
492del_invite(struct Channel *chptr, struct Client *who)
493{
494 dlinkFindDestroy(who, &chptr->invites);
495 dlinkFindDestroy(chptr, &who->user->invited);
496}
497
498/* is_banned()
499 *
500 * input - channel to check bans for, user to check bans against
501 * optional prebuilt buffers
502 * output - 1 if banned, else 0
503 * side effects -
504 */
505int
506is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
507 const char *s, const char *s2)
508{
509 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
510 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
511 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
512 char *s3 = NULL;
513 dlink_node *ptr;
514 struct Ban *actualBan = NULL;
515 struct Ban *actualExcept = NULL;
516
517 if(!MyClient(who))
518 return 0;
519
520 /* if the buffers havent been built, do it here */
521 if(s == NULL)
522 {
523 ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
524 ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
525
526 s = src_host;
527 s2 = src_iphost;
528 }
529 if(who->localClient->mangledhost != NULL)
530 {
531 /* if host mangling mode enabled, also check their real host */
532 if(!strcmp(who->host, who->localClient->mangledhost))
533 {
534 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
535 s3 = src_althost;
536 }
537 /* if host mangling mode not enabled and no other spoof,
538 * also check the mangled form of their host */
539 else if (!IsDynSpoof(who))
540 {
541 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
542 s3 = src_althost;
543 }
544 }
545
546 DLINK_FOREACH(ptr, chptr->banlist.head)
547 {
548 actualBan = ptr->data;
549 if(match(actualBan->banstr, s) ||
550 match(actualBan->banstr, s2) ||
551 match_cidr(actualBan->banstr, s2) ||
552 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
553 (s3 != NULL && match(actualBan->banstr, s3)))
554 break;
555 else
556 actualBan = NULL;
557 }
558
559 if((actualBan != NULL) && ConfigChannel.use_except)
560 {
561 DLINK_FOREACH(ptr, chptr->exceptlist.head)
562 {
563 actualExcept = ptr->data;
564
565 /* theyre exempted.. */
566 if(match(actualExcept->banstr, s) ||
567 match(actualExcept->banstr, s2) ||
568 match_cidr(actualExcept->banstr, s2) ||
569 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
570 (s3 != NULL && match(actualExcept->banstr, s3)))
571 {
572 /* cache the fact theyre not banned */
573 if(msptr != NULL)
574 {
575 msptr->bants = chptr->bants;
576 msptr->flags &= ~CHFL_BANNED;
577 }
578
579 return CHFL_EXCEPTION;
580 }
581 }
582 }
583
584 /* cache the banned/not banned status */
585 if(msptr != NULL)
586 {
587 msptr->bants = chptr->bants;
588
589 if(actualBan != NULL)
590 {
591 msptr->flags |= CHFL_BANNED;
592 return CHFL_BAN;
593 }
594 else
595 {
596 msptr->flags &= ~CHFL_BANNED;
597 return 0;
598 }
599 }
600
601 return ((actualBan ? CHFL_BAN : 0));
602}
603
604/* is_quieted()
605 *
606 * input - channel to check bans for, user to check bans against
607 * optional prebuilt buffers
608 * output - 1 if banned, else 0
609 * side effects -
610 */
611int
612is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
613 const char *s, const char *s2)
614{
615 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
616 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
617 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
618 char *s3 = NULL;
619 dlink_node *ptr;
620 struct Ban *actualBan = NULL;
621 struct Ban *actualExcept = NULL;
622
623 if(!MyClient(who))
624 return 0;
625
626 /* if the buffers havent been built, do it here */
627 if(s == NULL)
628 {
629 ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
630 ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
631
632 s = src_host;
633 s2 = src_iphost;
634 }
635 if(who->localClient->mangledhost != NULL)
636 {
637 /* if host mangling mode enabled, also check their real host */
638 if(!strcmp(who->host, who->localClient->mangledhost))
639 {
640 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
641 s3 = src_althost;
642 }
643 /* if host mangling mode not enabled and no other spoof,
644 * also check the mangled form of their host */
645 else if (!IsDynSpoof(who))
646 {
647 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
648 s3 = src_althost;
649 }
650 }
651
652 DLINK_FOREACH(ptr, chptr->quietlist.head)
653 {
654 actualBan = ptr->data;
655 if(match(actualBan->banstr, s) ||
656 match(actualBan->banstr, s2) ||
657 match_cidr(actualBan->banstr, s2) ||
658 match_extban(actualBan->banstr, who, chptr, CHFL_QUIET) ||
659 (s3 != NULL && match(actualBan->banstr, s3)))
660 break;
661 else
662 actualBan = NULL;
663 }
664
665 if((actualBan != NULL) && ConfigChannel.use_except)
666 {
667 DLINK_FOREACH(ptr, chptr->exceptlist.head)
668 {
669 actualExcept = ptr->data;
670
671 /* theyre exempted.. */
672 if(match(actualExcept->banstr, s) ||
673 match(actualExcept->banstr, s2) ||
674 match_cidr(actualExcept->banstr, s2) ||
675 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
676 (s3 != NULL && match(actualExcept->banstr, s3)))
677 {
678 /* cache the fact theyre not banned */
679 if(msptr != NULL)
680 {
681 msptr->bants = chptr->bants;
682 msptr->flags &= ~CHFL_BANNED;
683 }
684
685 return CHFL_EXCEPTION;
686 }
687 }
688 }
689
690 /* cache the banned/not banned status */
691 if(msptr != NULL)
692 {
693 msptr->bants = chptr->bants;
694
695 if(actualBan != NULL)
696 {
697 msptr->flags |= CHFL_BANNED;
698 return CHFL_BAN;
699 }
700 else
701 {
702 msptr->flags &= ~CHFL_BANNED;
703 return 0;
704 }
705 }
706
707 return ((actualBan ? CHFL_BAN : 0));
708}
709
710/* can_join()
711 *
712 * input - client to check, channel to check for, key
713 * output - reason for not being able to join, else 0
714 * side effects -
715 */
716int
717can_join(struct Client *source_p, struct Channel *chptr, char *key)
718{
1ebf4db4 719 dlink_node *invite = NULL;
212380e3 720 dlink_node *ptr;
721 struct Ban *invex = NULL;
722 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
723 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
724 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
725 int use_althost = 0;
1ebf4db4 726 int i = 0;
212380e3 727 hook_data_channel moduledata;
728
729 s_assert(source_p->localClient != NULL);
730
731 ircsprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
732 ircsprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
733 if(source_p->localClient->mangledhost != NULL)
734 {
735 /* if host mangling mode enabled, also check their real host */
736 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
737 {
738 ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
739 use_althost = 1;
740 }
741 /* if host mangling mode not enabled and no other spoof,
742 * also check the mangled form of their host */
743 else if (!IsDynSpoof(source_p))
744 {
745 ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
746 use_althost = 1;
747 }
748 }
749
750 if((is_banned(chptr, source_p, NULL, src_host, src_iphost)) == CHFL_BAN)
751 return (ERR_BANNEDFROMCHAN);
752
753 if(chptr->mode.mode & MODE_INVITEONLY)
754 {
1ebf4db4 755 DLINK_FOREACH(invite, source_p->user->invited.head)
212380e3 756 {
1ebf4db4 757 if(invite->data == chptr)
212380e3 758 break;
759 }
1ebf4db4 760 if(invite == NULL)
212380e3 761 {
762 if(!ConfigChannel.use_invex)
763 return (ERR_INVITEONLYCHAN);
764 DLINK_FOREACH(ptr, chptr->invexlist.head)
765 {
766 invex = ptr->data;
767 if(match(invex->banstr, src_host)
768 || match(invex->banstr, src_iphost)
769 || match_cidr(invex->banstr, src_iphost)
770 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
771 || (use_althost && match(invex->banstr, src_althost)))
772 break;
773 }
774 if(ptr == NULL)
775 return (ERR_INVITEONLYCHAN);
776 }
777 }
778
779 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
780 return (ERR_BADCHANNELKEY);
781
782 if(chptr->mode.limit &&
783 dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
1ebf4db4 784 i = ERR_CHANNELISFULL;
212380e3 785 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
1ebf4db4 786 i = ERR_NEEDREGGEDNICK;
212380e3 787 /* join throttling stuff --nenolod */
1ebf4db4 788 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
212380e3 789 {
790 if ((CurrentTime - chptr->join_delta <=
791 chptr->mode.join_time) && (chptr->join_count >=
792 chptr->mode.join_num))
1ebf4db4 793 i = ERR_THROTTLE;
794 }
795
796 /* allow /invite to override +l/+r/+j also -- jilles */
797 if (i != 0 && invite == NULL)
798 {
799 DLINK_FOREACH(invite, source_p->user->invited.head)
800 {
801 if(invite->data == chptr)
802 break;
803 }
804 if (invite == NULL)
805 return i;
212380e3 806 }
807
808 moduledata.client = source_p;
809 moduledata.chptr = chptr;
810 moduledata.approved = 0;
811
812 call_hook(h_can_join, &moduledata);
813
814 return moduledata.approved;
815}
816
817/* can_send()
818 *
819 * input - user to check in channel, membership pointer
820 * output - whether can explicitly send or not, else CAN_SEND_NONOP
821 * side effects -
822 */
823int
824can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
825{
826 if(IsServer(source_p) || IsService(source_p))
827 return CAN_SEND_OPV;
828
829 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
830 !IsOper(source_p) && !IsExemptResv(source_p))
831 return CAN_SEND_NO;
832
833 if(msptr == NULL)
834 {
835 msptr = find_channel_membership(chptr, source_p);
836
837 if(msptr == NULL)
838 {
839 /* if its +m or +n and theyre not in the channel,
840 * they cant send. we dont check bans here because
841 * theres no possibility of caching them --fl
842 */
843 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
844 return CAN_SEND_NO;
845 else
846 return CAN_SEND_NONOP;
847 }
848 }
849
850 if(is_chanop_voiced(msptr))
851 return CAN_SEND_OPV;
852
853 if(chptr->mode.mode & MODE_MODERATED)
854 return CAN_SEND_NO;
855
856 if(MyClient(source_p))
857 {
858 /* cached can_send */
859 if(msptr->bants == chptr->bants)
860 {
861 if(can_send_banned(msptr))
862 return CAN_SEND_NO;
863 }
864 else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
865 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
866 return CAN_SEND_NO;
867 }
868
869 return CAN_SEND_NONOP;
870}
871
872/* find_bannickchange_channel()
873 * Input: client to check
874 * Output: channel preventing nick change
875 */
876struct Channel *
877find_bannickchange_channel(struct Client *client_p)
878{
879 struct Channel *chptr;
880 struct membership *msptr;
881 dlink_node *ptr;
882 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
883 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
884
885 if (!MyClient(client_p))
886 return NULL;
887
888 ircsprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
889 ircsprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
890
891 DLINK_FOREACH(ptr, client_p->user->channel.head)
892 {
893 msptr = ptr->data;
894 chptr = msptr->chptr;
895 if (is_chanop_voiced(msptr))
896 continue;
897 /* cached can_send */
898 if (msptr->bants == chptr->bants)
899 {
900 if (can_send_banned(msptr))
901 return chptr;
902 }
903 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN
904 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
905 return chptr;
906 }
907 return NULL;
908}
909
910/* void check_spambot_warning(struct Client *source_p)
911 * Input: Client to check, channel name or NULL if this is a part.
912 * Output: none
913 * Side-effects: Updates the client's oper_warn_count_down, warns the
914 * IRC operators if necessary, and updates join_leave_countdown as
915 * needed.
916 */
917void
918check_spambot_warning(struct Client *source_p, const char *name)
919{
920 int t_delta;
921 int decrement_count;
922 if((GlobalSetOptions.spam_num &&
923 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
924 {
925 if(source_p->localClient->oper_warn_count_down > 0)
926 source_p->localClient->oper_warn_count_down--;
927 else
928 source_p->localClient->oper_warn_count_down = 0;
929 if(source_p->localClient->oper_warn_count_down == 0)
930 {
931 /* Its already known as a possible spambot */
932 if(name != NULL)
933 sendto_realops_snomask(SNO_BOTS, L_ALL,
934 "User %s (%s@%s) trying to join %s is a possible spambot",
935 source_p->name,
63aecfb9 936 source_p->username, source_p->orighost, name);
212380e3 937 else
938 sendto_realops_snomask(SNO_BOTS, L_ALL,
939 "User %s (%s@%s) is a possible spambot",
940 source_p->name,
63aecfb9 941 source_p->username, source_p->orighost);
212380e3 942 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
943 }
944 }
945 else
946 {
947 if((t_delta =
948 (CurrentTime - source_p->localClient->last_leave_time)) >
949 JOIN_LEAVE_COUNT_EXPIRE_TIME)
950 {
951 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
952 if(decrement_count > source_p->localClient->join_leave_count)
953 source_p->localClient->join_leave_count = 0;
954 else
955 source_p->localClient->join_leave_count -= decrement_count;
956 }
957 else
958 {
959 if((CurrentTime -
960 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
961 {
962 /* oh, its a possible spambot */
963 source_p->localClient->join_leave_count++;
964 }
965 }
966 if(name != NULL)
967 source_p->localClient->last_join_time = CurrentTime;
968 else
969 source_p->localClient->last_leave_time = CurrentTime;
970 }
971}
972
973/* check_splitmode()
974 *
975 * input -
976 * output -
977 * side effects - compares usercount and servercount against their split
978 * values and adjusts splitmode accordingly
979 */
980void
981check_splitmode(void *unused)
982{
983 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
984 {
985 /* not split, we're being asked to check now because someone
986 * has left
987 */
988 if(!splitmode)
989 {
990 if(eob_count < split_servers || Count.total < split_users)
991 {
992 splitmode = 1;
993 sendto_realops_snomask(SNO_GENERAL, L_ALL,
994 "Network split, activating splitmode");
995 eventAddIsh("check_splitmode", check_splitmode, NULL, 2);
996 }
997 }
998 /* in splitmode, check whether its finished */
999 else if(eob_count >= split_servers && Count.total >= split_users)
1000 {
1001 splitmode = 0;
1002
1003 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1004 "Network rejoined, deactivating splitmode");
1005
1006 eventDelete(check_splitmode, NULL);
1007 }
1008 }
1009}
1010
1011
1012/* allocate_topic()
1013 *
1014 * input - channel to allocate topic for
1015 * output - 1 on success, else 0
1016 * side effects - channel gets a topic allocated
1017 */
1018static void
1019allocate_topic(struct Channel *chptr)
1020{
1021 void *ptr;
1022
1023 if(chptr == NULL)
1024 return;
1025
1026 ptr = BlockHeapAlloc(topic_heap);
1027
1028 /* Basically we allocate one large block for the topic and
1029 * the topic info. We then split it up into two and shove it
1030 * in the chptr
1031 */
1032 chptr->topic = ptr;
1033 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1034 *chptr->topic = '\0';
1035 *chptr->topic_info = '\0';
1036}
1037
1038/* free_topic()
1039 *
1040 * input - channel which has topic to free
1041 * output -
1042 * side effects - channels topic is free'd
1043 */
1044static void
1045free_topic(struct Channel *chptr)
1046{
1047 void *ptr;
1048
1049 if(chptr == NULL || chptr->topic == NULL)
1050 return;
1051
1052 /* This is safe for now - If you change allocate_topic you
1053 * MUST change this as well
1054 */
1055 ptr = chptr->topic;
1056 BlockHeapFree(topic_heap, ptr);
1057 chptr->topic = NULL;
1058 chptr->topic_info = NULL;
1059}
1060
1061/* set_channel_topic()
1062 *
1063 * input - channel, topic to set, topic info and topic ts
1064 * output -
1065 * side effects - channels topic, topic info and TS are set.
1066 */
1067void
1068set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1069{
1070 if(strlen(topic) > 0)
1071 {
1072 if(chptr->topic == NULL)
1073 allocate_topic(chptr);
1074 strlcpy(chptr->topic, topic, TOPICLEN + 1);
1075 strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
1076 chptr->topic_time = topicts;
1077 }
1078 else
1079 {
1080 if(chptr->topic != NULL)
1081 free_topic(chptr);
1082 chptr->topic_time = 0;
1083 }
1084}
1085
1086static const struct mode_letter
1087{
1088 const unsigned int mode;
1089 const unsigned char letter;
1090} flags[] =
1091{
1092 {MODE_INVITEONLY, 'i'},
1093 {MODE_MODERATED, 'm'},
1094 {MODE_NOPRIVMSGS, 'n'},
1095 {MODE_PRIVATE, 'p'},
1096 {MODE_SECRET, 's'},
1097 {MODE_TOPICLIMIT, 't'},
1098 {MODE_NOCOLOR, 'c'},
1099 {MODE_FREEINVITE, 'g'},
1100 {MODE_OPMODERATE, 'z'},
1101 {MODE_EXLIMIT, 'L'},
1102 {MODE_PERMANENT, 'P'},
1103 {MODE_FREETARGET, 'F'},
1104 {MODE_DISFORWARD, 'Q'},
1105 {MODE_REGONLY, 'r'},
1106 {0, '\0'}
1107};
1108
1109/* channel_modes()
1110 *
1111 * inputs - pointer to channel
1112 * - pointer to client
f1e35c19 1113 * output - string with simple modes
1114 * side effects - result from previous calls overwritten
212380e3 1115 *
1116 * Stolen from ShadowIRCd 4 --nenolod
1117 */
1118const char *
1119channel_modes(struct Channel *chptr, struct Client *client_p)
1120{
1121 int i;
1122 char buf1[BUFSIZE];
1123 char buf2[BUFSIZE];
1124 static char final[BUFSIZE];
1125 char *mbuf = buf1;
1126 char *pbuf = buf2;
1127
1128 *mbuf++ = '+';
1129 *pbuf = '\0';
1130
1131 for (i = 0; flags[i].mode; ++i)
1132 if(chptr->mode.mode & flags[i].mode)
1133 *mbuf++ = flags[i].letter;
1134
1135 if(chptr->mode.limit)
1136 {
1137 *mbuf++ = 'l';
1138
f1e35c19 1139 if(!IsClient(client_p) || IsMember(client_p, chptr))
1140 pbuf += ircsprintf(pbuf, " %d", chptr->mode.limit);
212380e3 1141 }
1142
1143 if(*chptr->mode.key)
1144 {
1145 *mbuf++ = 'k';
1146
f1e35c19 1147 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1148 pbuf += ircsprintf(pbuf, " %s", chptr->mode.key);
212380e3 1149 }
1150
1151 if(chptr->mode.join_num)
1152 {
1153 *mbuf++ = 'j';
1154
f1e35c19 1155 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1156 pbuf += ircsprintf(pbuf, " %d:%d", chptr->mode.join_num,
212380e3 1157 chptr->mode.join_time);
1158 }
1159
f1e35c19 1160 if(*chptr->mode.forward && (ConfigChannel.use_forward || !IsClient(client_p)))
212380e3 1161 {
1162 *mbuf++ = 'f';
1163
f1e35c19 1164 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
1165 pbuf += ircsprintf(pbuf, " %s", chptr->mode.forward);
212380e3 1166 }
1167
1168 *mbuf = '\0';
1169
f1e35c19 1170 strlcpy(final, buf1, sizeof final);
1171 strlcat(final, buf2, sizeof final);
212380e3 1172 return final;
1173}
1174
1175/* Now lets do some stuff to keep track of what combinations of
1176 * servers exist...
1177 * Note that the number of combinations doubles each time you add
1178 * something to this list. Each one is only quick if no servers use that
1179 * combination, but if the numbers get too high here MODE will get too
1180 * slow. I suggest if you get more than 7 here, you consider getting rid
1181 * of some and merging or something. If it wasn't for irc+cs we would
1182 * probably not even need to bother about most of these, but unfortunately
1183 * we do. -A1kmm
1184 */
1185
1186/* void init_chcap_usage_counts(void)
1187 *
1188 * Inputs - none
1189 * Output - none
1190 * Side-effects - Initialises the usage counts to zero. Fills in the
1191 * chcap_yes and chcap_no combination tables.
1192 */
1193void
1194init_chcap_usage_counts(void)
1195{
1196 unsigned long m, c, y, n;
1197
1198 memset(chcap_combos, 0, sizeof(chcap_combos));
1199
1200 /* For every possible combination */
1201 for (m = 0; m < NCHCAP_COMBOS; m++)
1202 {
1203 /* Check each capab */
1204 for (c = y = n = 0; c < NCHCAPS; c++)
1205 {
1206 if((m & (1 << c)) == 0)
1207 n |= channel_capabs[c];
1208 else
1209 y |= channel_capabs[c];
1210 }
1211 chcap_combos[m].cap_yes = y;
1212 chcap_combos[m].cap_no = n;
1213 }
1214}
1215
1216/* void set_chcap_usage_counts(struct Client *serv_p)
1217 * Input: serv_p; The client whose capabs to register.
1218 * Output: none
1219 * Side-effects: Increments the usage counts for the correct capab
1220 * combination.
1221 */
1222void
1223set_chcap_usage_counts(struct Client *serv_p)
1224{
1225 int n;
1226
1227 for (n = 0; n < NCHCAP_COMBOS; n++)
1228 {
1229 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1230 NotCapable(serv_p, chcap_combos[n].cap_no))
1231 {
1232 chcap_combos[n].count++;
1233 return;
1234 }
1235 }
1236
1237 /* This should be impossible -A1kmm. */
1238 s_assert(0);
1239}
1240
1241/* void set_chcap_usage_counts(struct Client *serv_p)
1242 *
1243 * Inputs - serv_p; The client whose capabs to register.
1244 * Output - none
1245 * Side-effects - Decrements the usage counts for the correct capab
1246 * combination.
1247 */
1248void
1249unset_chcap_usage_counts(struct Client *serv_p)
1250{
1251 int n;
1252
1253 for (n = 0; n < NCHCAP_COMBOS; n++)
1254 {
1255 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1256 NotCapable(serv_p, chcap_combos[n].cap_no))
1257 {
1258 /* Hopefully capabs can't change dynamically or anything... */
1259 s_assert(chcap_combos[n].count > 0);
1260
1261 if(chcap_combos[n].count > 0)
1262 chcap_combos[n].count--;
1263 return;
1264 }
1265 }
1266
1267 /* This should be impossible -A1kmm. */
1268 s_assert(0);
1269}
1270
1271/* void send_cap_mode_changes(struct Client *client_p,
1272 * struct Client *source_p,
1273 * struct Channel *chptr, int cap, int nocap)
1274 * Input: The client sending(client_p), the source client(source_p),
1275 * the channel to send mode changes for(chptr)
1276 * Output: None.
1277 * Side-effects: Sends the appropriate mode changes to capable servers.
1278 *
1279 * Reverted back to my original design, except that we now keep a count
1280 * of the number of servers which each combination as an optimisation, so
1281 * the capabs combinations which are not needed are not worked out. -A1kmm
1282 */
1283void
1284send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1285 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1286{
1287 static char modebuf[BUFSIZE];
1288 static char parabuf[BUFSIZE];
1289 int i, mbl, pbl, nc, mc, preflen, len;
1290 char *pbuf;
1291 const char *arg;
1292 int dir;
1293 int j;
1294 int cap;
1295 int nocap;
1296 int arglen;
1297
1298 /* Now send to servers... */
1299 for (j = 0; j < NCHCAP_COMBOS; j++)
1300 {
1301 if(chcap_combos[j].count == 0)
1302 continue;
1303
1304 mc = 0;
1305 nc = 0;
1306 pbl = 0;
1307 parabuf[0] = 0;
1308 pbuf = parabuf;
1309 dir = MODE_QUERY;
1310
1311 cap = chcap_combos[j].cap_yes;
1312 nocap = chcap_combos[j].cap_no;
1313
1314 if(cap & CAP_TS6)
1315 mbl = preflen = ircsprintf(modebuf, ":%s TMODE %ld %s ",
1316 use_id(source_p), (long) chptr->channelts,
1317 chptr->chname);
1318 else
1319 mbl = preflen = ircsprintf(modebuf, ":%s MODE %s ",
1320 source_p->name, chptr->chname);
1321
1322 /* loop the list of - modes we have */
1323 for (i = 0; i < mode_count; i++)
1324 {
1325 /* if they dont support the cap we need, or they do support a cap they
1326 * cant have, then dont add it to the modebuf.. that way they wont see
1327 * the mode
1328 */
1329 if((mode_changes[i].letter == 0) ||
1330 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1331 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1332 continue;
1333
1334 if((cap & CAP_TS6) && !EmptyString(mode_changes[i].id))
1335 arg = mode_changes[i].id;
1336 else
1337 arg = mode_changes[i].arg;
1338
1339 if(arg)
1340 {
1341 arglen = strlen(arg);
1342
1343 /* dont even think about it! --fl */
1344 if(arglen > MODEBUFLEN - 5)
1345 continue;
1346 }
1347
1348 /* if we're creeping past the buf size, we need to send it and make
1349 * another line for the other modes
1350 * XXX - this could give away server topology with uids being
1351 * different lengths, but not much we can do, except possibly break
1352 * them as if they were the longest of the nick or uid at all times,
1353 * which even then won't work as we don't always know the uid -A1kmm.
1354 */
1355 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1356 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1357 {
1358 if(nc != 0)
1359 sendto_server(client_p, chptr, cap, nocap,
1360 "%s %s", modebuf, parabuf);
1361 nc = 0;
1362 mc = 0;
1363
1364 mbl = preflen;
1365 pbl = 0;
1366 pbuf = parabuf;
1367 parabuf[0] = 0;
1368 dir = MODE_QUERY;
1369 }
1370
1371 if(dir != mode_changes[i].dir)
1372 {
1373 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1374 dir = mode_changes[i].dir;
1375 }
1376
1377 modebuf[mbl++] = mode_changes[i].letter;
1378 modebuf[mbl] = 0;
1379 nc++;
1380
1381 if(arg != NULL)
1382 {
1383 len = ircsprintf(pbuf, "%s ", arg);
1384 pbuf += len;
1385 pbl += len;
1386 mc++;
1387 }
1388 }
1389
1390 if(pbl && parabuf[pbl - 1] == ' ')
1391 parabuf[pbl - 1] = 0;
1392
1393 if(nc != 0)
1394 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
1395 }
1396}