]> jfr.im git - irc/rqf/shadowircd.git/blame - src/channel.c
Really fix the ugly-ass desync by re-adding some code i accidentally
[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"
212380e3 28#include "channel.h"
fba62b01 29#include "chmode.h"
212380e3 30#include "client.h"
31#include "common.h"
32#include "hash.h"
33#include "hook.h"
13ae2f4b 34#include "match.h"
212380e3 35#include "ircd.h"
36#include "numeric.h"
37#include "s_serv.h" /* captab */
38#include "s_user.h"
39#include "send.h"
40#include "whowas.h"
41#include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
42#include "s_newconf.h"
d3455e2c 43#include "logger.h"
3472ff3f 44#include "packet.h"
212380e3 45
9813daca 46struct config_channel_entry ConfigChannel;
1a218aaf 47rb_dlink_list global_channel_list;
5475a932
VY
48static rb_bh *channel_heap;
49static rb_bh *ban_heap;
50static rb_bh *topic_heap;
51static rb_bh *member_heap;
52
212380e3 53static int channel_capabs[] = { CAP_EX, CAP_IE,
54 CAP_SERVICE,
55 CAP_TS6
56};
57
58#define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
59#define NCHCAP_COMBOS (1 << NCHCAPS)
60
61static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
62
63static void free_topic(struct Channel *chptr);
64
65static int h_can_join;
67b90240
JH
66static int h_can_create_channel;
67static int h_channel_join;
212380e3 68
69/* init_channels()
70 *
71 * input -
72 * output -
73 * side effects - initialises the various blockheaps
74 */
75void
76init_channels(void)
77{
dd9be678
WP
78 channel_heap = rb_bh_create(sizeof(struct Channel), CHANNEL_HEAP_SIZE, "channel_heap");
79 ban_heap = rb_bh_create(sizeof(struct Ban), BAN_HEAP_SIZE, "ban_heap");
80 topic_heap = rb_bh_create(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE, "topic_heap");
81 member_heap = rb_bh_create(sizeof(struct membership), MEMBER_HEAP_SIZE, "member_heap");
212380e3 82
83 h_can_join = register_hook("can_join");
67b90240
JH
84 h_channel_join = register_hook("channel_join");
85 h_can_create_channel = register_hook("can_create_channel");
212380e3 86}
87
88/*
89 * allocate_channel - Allocates a channel
90 */
91struct Channel *
92allocate_channel(const char *chname)
93{
94 struct Channel *chptr;
6e9b4415 95 chptr = rb_bh_alloc(channel_heap);
62d28946 96 chptr->chname = rb_strdup(chname);
212380e3 97 return (chptr);
98}
99
100void
101free_channel(struct Channel *chptr)
102{
90a3c35b 103 rb_free(chptr->chname);
6e9b4415 104 rb_bh_free(channel_heap, chptr);
212380e3 105}
106
107struct Ban *
108allocate_ban(const char *banstr, const char *who)
109{
110 struct Ban *bptr;
6e9b4415 111 bptr = rb_bh_alloc(ban_heap);
62d28946
VY
112 bptr->banstr = rb_strdup(banstr);
113 bptr->who = rb_strdup(who);
212380e3 114
115 return (bptr);
116}
117
118void
119free_ban(struct Ban *bptr)
120{
90a3c35b
VY
121 rb_free(bptr->banstr);
122 rb_free(bptr->who);
6e9b4415 123 rb_bh_free(ban_heap, bptr);
212380e3 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 {
8e69bb4e 147 RB_DLINK_FOREACH(ptr, chptr->members.head)
212380e3 148 {
149 msptr = ptr->data;
150
151 if(msptr->client_p == client_p)
152 return msptr;
153 }
154 }
155 else
156 {
8e69bb4e 157 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3 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{
b8643345 178 static char buffer[5];
212380e3 179 char *p;
180
181 p = buffer;
182
b8643345
G
183 if(is_owner(msptr))
184 {
185 if(!combine)
186 return "!";
187 *p++ = '!';
188 }
189
212380e3 190 if(is_chanop(msptr))
191 {
192 if(!combine)
193 return "@";
194 *p++ = '@';
195 }
196
b8643345
G
197 if(is_halfop(msptr))
198 {
199 if(!combine)
200 return "%";
201 *p++ = '%';
202 }
203
212380e3 204 if(is_voiced(msptr))
205 *p++ = '+';
206
207 *p = '\0';
208 return buffer;
209}
210
40c6b59b
G
211/* is_halfop()
212 *
213 * input - membership to check for halfops
214 * output - 1 if the user is halfopped, 0 if the user is not or halfop
215 * is disabled.
216 * side effects -
217 *
218 */
219int
220is_halfop(struct membership *msptr)
221{
40c6b59b
G
222 if(!ConfigChannel.use_halfop)
223 return 0;
82f8e812
G
224 if(is_chmode_h(msptr))
225 return 1;
40c6b59b
G
226 else
227 return 0;
228}
229
230/* is_owner()
231 *
232 * input - membership to check for owner
233 * output - 1 if the user is an owner, 0 if the user is not or owner
234 * is disabled.
235 * side effects -
236 *
237 */
238int
239is_owner(struct membership *msptr)
240{
40c6b59b
G
241 if(!ConfigChannel.use_owner)
242 return 0;
82f8e812
G
243 if(is_chmode_a(msptr))
244 return 1;
40c6b59b
G
245 else
246 return 0;
247}
248
d1c7eccf
G
249/* is_any_op()
250 *
251 * input - membership to check for ops
252 * output - 1 if the user is op, halfop, or owner, 0 elsewise
253 * side effects -
254 */
d1c7eccf
G
255int
256is_any_op(struct membership *msptr)
257{
40c6b59b 258 if(is_chanop(msptr) || is_halfop(msptr) || is_owner(msptr))
d1c7eccf
G
259 return 1;
260 else
261 return 0;
262}
263
bbc69733
G
264/* is_chanop_voiced()
265 *
266 * input - memebership to check for status
267 * output - 1 if the user is op, halfop, owner, or voice, 0 elsewise
268 * side effects -
269 */
270int
271is_chanop_voiced(struct membership *msptr)
272{
40c6b59b 273 if(is_chanop(msptr) || is_voiced(msptr) || is_halfop(msptr) || is_owner(msptr))
bbc69733
G
274 return 1;
275 else
276 return 0;
277}
278
b3b2ed97
G
279/* can_kick_deop()
280 *
281 * input - two memeberships
282 * output - 1 if the first memebership can kick/deop the second, 0 elsewise
283 * side effects -
284 */
285int
286can_kick_deop(struct membership *source, struct membership *target)
287{
40c6b59b 288 if(is_chanop(source) && !is_owner(target))
b3b2ed97 289 return 1;
40c6b59b
G
290 else if(is_halfop(source) && !is_any_op(target))
291 return 1;
292 else if(is_owner(source))
293 return 1;
294
295 return 0;
b3b2ed97
G
296}
297
212380e3 298/* add_user_to_channel()
299 *
300 * input - channel to add client to, client to add, channel flags
301 * output -
302 * side effects - user is added to channel
303 */
304void
305add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
306{
307 struct membership *msptr;
308
309 s_assert(client_p->user != NULL);
310 if(client_p->user == NULL)
311 return;
312
6e9b4415 313 msptr = rb_bh_alloc(member_heap);
212380e3 314
315 msptr->chptr = chptr;
316 msptr->client_p = client_p;
317 msptr->flags = flags;
318
af81d5a0
WP
319 rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
320 rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
212380e3 321
322 if(MyClient(client_p))
af81d5a0 323 rb_dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
212380e3 324}
325
326/* remove_user_from_channel()
327 *
328 * input - membership pointer to remove from channel
329 * output -
330 * side effects - membership (thus user) is removed from channel
331 */
332void
333remove_user_from_channel(struct membership *msptr)
334{
335 struct Client *client_p;
336 struct Channel *chptr;
337 s_assert(msptr != NULL);
338 if(msptr == NULL)
339 return;
340
341 client_p = msptr->client_p;
342 chptr = msptr->chptr;
343
af81d5a0
WP
344 rb_dlinkDelete(&msptr->usernode, &client_p->user->channel);
345 rb_dlinkDelete(&msptr->channode, &chptr->members);
212380e3 346
347 if(client_p->servptr == &me)
af81d5a0 348 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
212380e3 349
af81d5a0 350 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
212380e3 351 destroy_channel(chptr);
352
6e9b4415 353 rb_bh_free(member_heap, msptr);
212380e3 354
355 return;
356}
357
358/* remove_user_from_channels()
359 *
360 * input - user to remove from all channels
361 * output -
362 * side effects - user is removed from all channels
363 */
364void
365remove_user_from_channels(struct Client *client_p)
366{
367 struct Channel *chptr;
368 struct membership *msptr;
af81d5a0 369 rb_dlink_node *ptr;
90a3c35b 370 rb_dlink_node *next_ptr;
212380e3 371
372 if(client_p == NULL)
373 return;
374
90a3c35b 375 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
212380e3 376 {
377 msptr = ptr->data;
378 chptr = msptr->chptr;
379
af81d5a0 380 rb_dlinkDelete(&msptr->channode, &chptr->members);
212380e3 381
382 if(client_p->servptr == &me)
af81d5a0 383 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
212380e3 384
af81d5a0 385 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
212380e3 386 destroy_channel(chptr);
387
6e9b4415 388 rb_bh_free(member_heap, msptr);
212380e3 389 }
390
391 client_p->user->channel.head = client_p->user->channel.tail = NULL;
392 client_p->user->channel.length = 0;
393}
394
395/* invalidate_bancache_user()
396 *
397 * input - user to invalidate ban cache for
398 * output -
399 * side effects - ban cache is invalidated for all memberships of that user
400 * to be used after a nick change
401 */
402void
403invalidate_bancache_user(struct Client *client_p)
404{
405 struct membership *msptr;
af81d5a0 406 rb_dlink_node *ptr;
212380e3 407
408 if(client_p == NULL)
409 return;
410
8e69bb4e 411 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3 412 {
413 msptr = ptr->data;
414 msptr->bants = 0;
415 msptr->flags &= ~CHFL_BANNED;
416 }
417}
418
419/* check_channel_name()
420 *
421 * input - channel name
422 * output - 1 if valid channel name, else 0
423 * side effects -
424 */
425int
426check_channel_name(const char *name)
427{
428 s_assert(name != NULL);
429 if(name == NULL)
430 return 0;
431
432 for (; *name; ++name)
433 {
434 if(!IsChanChar(*name))
435 return 0;
436 }
437
438 return 1;
439}
440
441/* free_channel_list()
442 *
af81d5a0 443 * input - rb_dlink list to free
212380e3 444 * output -
445 * side effects - list of b/e/I modes is cleared
446 */
447void
af81d5a0 448free_channel_list(rb_dlink_list * list)
212380e3 449{
af81d5a0 450 rb_dlink_node *ptr;
90a3c35b 451 rb_dlink_node *next_ptr;
212380e3 452 struct Ban *actualBan;
453
90a3c35b 454 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
212380e3 455 {
456 actualBan = ptr->data;
457 free_ban(actualBan);
458 }
459
460 list->head = list->tail = NULL;
461 list->length = 0;
462}
463
464/* destroy_channel()
465 *
466 * input - channel to destroy
467 * output -
468 * side effects - channel is obliterated
469 */
470void
471destroy_channel(struct Channel *chptr)
472{
90a3c35b 473 rb_dlink_node *ptr, *next_ptr;
212380e3 474
90a3c35b 475 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
212380e3 476 {
477 del_invite(chptr, ptr->data);
478 }
479
480 /* free all bans/exceptions/denies */
481 free_channel_list(&chptr->banlist);
482 free_channel_list(&chptr->exceptlist);
483 free_channel_list(&chptr->invexlist);
fea1ad52 484 free_channel_list(&chptr->quietlist);
212380e3 485
486 /* Free the topic */
487 free_topic(chptr);
488
af81d5a0 489 rb_dlinkDelete(&chptr->node, &global_channel_list);
212380e3 490 del_from_channel_hash(chptr->chname, chptr);
491 free_channel(chptr);
492}
493
494/* channel_pub_or_secret()
495 *
496 * input - channel
497 * output - "=" if public, "@" if secret, else "*"
498 * side effects -
499 */
500static const char *
501channel_pub_or_secret(struct Channel *chptr)
502{
503 if(PubChannel(chptr))
504 return ("=");
505 else if(SecretChannel(chptr))
506 return ("@");
507 return ("*");
508}
509
510/* channel_member_names()
511 *
512 * input - channel to list, client to list to, show endofnames
513 * output -
514 * side effects - client is given list of users on channel
515 */
516void
517channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
518{
519 struct membership *msptr;
520 struct Client *target_p;
af81d5a0 521 rb_dlink_node *ptr;
212380e3 522 char lbuf[BUFSIZE];
523 char *t;
524 int mlen;
525 int tlen;
526 int cur_len;
527 int is_member;
528 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
529
530 if(ShowChannel(client_p, chptr))
531 {
532 is_member = IsMember(client_p, chptr);
533
38e6acdd 534 cur_len = mlen = rb_sprintf(lbuf, form_str(RPL_NAMREPLY),
212380e3 535 me.name, client_p->name,
536 channel_pub_or_secret(chptr), chptr->chname);
537
538 t = lbuf + cur_len;
539
8e69bb4e 540 RB_DLINK_FOREACH(ptr, chptr->members.head)
212380e3 541 {
542 msptr = ptr->data;
543 target_p = msptr->client_p;
544
545 if(IsInvisible(target_p) && !is_member)
546 continue;
547
548 /* space, possible "@+" prefix */
549 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
550 {
551 *(t - 1) = '\0';
552 sendto_one(client_p, "%s", lbuf);
553 cur_len = mlen;
554 t = lbuf + mlen;
555 }
556
38e6acdd 557 tlen = rb_sprintf(t, "%s%s ", find_channel_status(msptr, stack),
212380e3 558 target_p->name);
559
560 cur_len += tlen;
561 t += tlen;
562 }
563
564 /* The old behaviour here was to always output our buffer,
565 * even if there are no clients we can show. This happens
566 * when a client does "NAMES" with no parameters, and all
567 * the clients on a -sp channel are +i. I dont see a good
568 * reason for keeping that behaviour, as it just wastes
569 * bandwidth. --anfl
570 */
571 if(cur_len != mlen)
572 {
573 *(t - 1) = '\0';
574 sendto_one(client_p, "%s", lbuf);
575 }
576 }
577
578 if(show_eon)
579 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
580 me.name, client_p->name, chptr->chname);
581}
582
583/* del_invite()
584 *
585 * input - channel to remove invite from, client to remove
586 * output -
587 * side effects - user is removed from invite list, if exists
588 */
589void
590del_invite(struct Channel *chptr, struct Client *who)
591{
af81d5a0
WP
592 rb_dlinkFindDestroy(who, &chptr->invites);
593 rb_dlinkFindDestroy(chptr, &who->user->invited);
212380e3 594}
595
596/* is_banned()
597 *
598 * input - channel to check bans for, user to check bans against
599 * optional prebuilt buffers
600 * output - 1 if banned, else 0
601 * side effects -
602 */
603int
604is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
605 const char *s, const char *s2)
606{
607 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
608 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
609 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
610 char *s3 = NULL;
af81d5a0 611 rb_dlink_node *ptr;
212380e3 612 struct Ban *actualBan = NULL;
613 struct Ban *actualExcept = NULL;
614
615 if(!MyClient(who))
616 return 0;
617
618 /* if the buffers havent been built, do it here */
619 if(s == NULL)
620 {
38e6acdd
WP
621 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
622 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
212380e3 623
624 s = src_host;
625 s2 = src_iphost;
626 }
627 if(who->localClient->mangledhost != NULL)
628 {
629 /* if host mangling mode enabled, also check their real host */
630 if(!strcmp(who->host, who->localClient->mangledhost))
631 {
38e6acdd 632 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
212380e3 633 s3 = src_althost;
634 }
635 /* if host mangling mode not enabled and no other spoof,
636 * also check the mangled form of their host */
637 else if (!IsDynSpoof(who))
638 {
38e6acdd 639 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
212380e3 640 s3 = src_althost;
641 }
642 }
643
8e69bb4e 644 RB_DLINK_FOREACH(ptr, chptr->banlist.head)
212380e3 645 {
646 actualBan = ptr->data;
647 if(match(actualBan->banstr, s) ||
648 match(actualBan->banstr, s2) ||
649 match_cidr(actualBan->banstr, s2) ||
650 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
651 (s3 != NULL && match(actualBan->banstr, s3)))
652 break;
653 else
654 actualBan = NULL;
655 }
656
657 if((actualBan != NULL) && ConfigChannel.use_except)
658 {
8e69bb4e 659 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
212380e3 660 {
661 actualExcept = ptr->data;
662
663 /* theyre exempted.. */
664 if(match(actualExcept->banstr, s) ||
665 match(actualExcept->banstr, s2) ||
666 match_cidr(actualExcept->banstr, s2) ||
667 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
668 (s3 != NULL && match(actualExcept->banstr, s3)))
669 {
670 /* cache the fact theyre not banned */
671 if(msptr != NULL)
672 {
673 msptr->bants = chptr->bants;
674 msptr->flags &= ~CHFL_BANNED;
675 }
676
677 return CHFL_EXCEPTION;
678 }
679 }
680 }
681
682 /* cache the banned/not banned status */
683 if(msptr != NULL)
684 {
685 msptr->bants = chptr->bants;
686
687 if(actualBan != NULL)
688 {
689 msptr->flags |= CHFL_BANNED;
690 return CHFL_BAN;
691 }
692 else
693 {
694 msptr->flags &= ~CHFL_BANNED;
695 return 0;
696 }
697 }
698
699 return ((actualBan ? CHFL_BAN : 0));
700}
701
702/* is_quieted()
703 *
704 * input - channel to check bans for, user to check bans against
705 * optional prebuilt buffers
706 * output - 1 if banned, else 0
707 * side effects -
708 */
709int
710is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
711 const char *s, const char *s2)
712{
713 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
714 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
715 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
716 char *s3 = NULL;
af81d5a0 717 rb_dlink_node *ptr;
212380e3 718 struct Ban *actualBan = NULL;
719 struct Ban *actualExcept = NULL;
720
721 if(!MyClient(who))
722 return 0;
723
724 /* if the buffers havent been built, do it here */
725 if(s == NULL)
726 {
38e6acdd
WP
727 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
728 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
212380e3 729
730 s = src_host;
731 s2 = src_iphost;
732 }
733 if(who->localClient->mangledhost != NULL)
734 {
735 /* if host mangling mode enabled, also check their real host */
736 if(!strcmp(who->host, who->localClient->mangledhost))
737 {
38e6acdd 738 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
212380e3 739 s3 = src_althost;
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(who))
744 {
38e6acdd 745 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
212380e3 746 s3 = src_althost;
747 }
748 }
749
8e69bb4e 750 RB_DLINK_FOREACH(ptr, chptr->quietlist.head)
212380e3 751 {
752 actualBan = ptr->data;
753 if(match(actualBan->banstr, s) ||
754 match(actualBan->banstr, s2) ||
755 match_cidr(actualBan->banstr, s2) ||
756 match_extban(actualBan->banstr, who, chptr, CHFL_QUIET) ||
757 (s3 != NULL && match(actualBan->banstr, s3)))
758 break;
759 else
760 actualBan = NULL;
761 }
762
763 if((actualBan != NULL) && ConfigChannel.use_except)
764 {
8e69bb4e 765 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
212380e3 766 {
767 actualExcept = ptr->data;
768
769 /* theyre exempted.. */
770 if(match(actualExcept->banstr, s) ||
771 match(actualExcept->banstr, s2) ||
772 match_cidr(actualExcept->banstr, s2) ||
773 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
774 (s3 != NULL && match(actualExcept->banstr, s3)))
775 {
776 /* cache the fact theyre not banned */
777 if(msptr != NULL)
778 {
779 msptr->bants = chptr->bants;
780 msptr->flags &= ~CHFL_BANNED;
781 }
782
783 return CHFL_EXCEPTION;
784 }
785 }
786 }
787
788 /* cache the banned/not banned status */
789 if(msptr != NULL)
790 {
791 msptr->bants = chptr->bants;
792
793 if(actualBan != NULL)
794 {
795 msptr->flags |= CHFL_BANNED;
796 return CHFL_BAN;
797 }
798 else
799 {
800 msptr->flags &= ~CHFL_BANNED;
801 return 0;
802 }
803 }
804
805 return ((actualBan ? CHFL_BAN : 0));
806}
807
808/* can_join()
809 *
810 * input - client to check, channel to check for, key
811 * output - reason for not being able to join, else 0
812 * side effects -
813 */
814int
815can_join(struct Client *source_p, struct Channel *chptr, char *key)
816{
af81d5a0
WP
817 rb_dlink_node *invite = NULL;
818 rb_dlink_node *ptr;
212380e3 819 struct Ban *invex = NULL;
820 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
821 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
822 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
823 int use_althost = 0;
1ebf4db4 824 int i = 0;
212380e3 825 hook_data_channel moduledata;
826
827 s_assert(source_p->localClient != NULL);
828
13a467bb
JH
829 if(IsOverride(source_p))
830 return 0;
831
38e6acdd
WP
832 rb_sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
833 rb_sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
212380e3 834 if(source_p->localClient->mangledhost != NULL)
835 {
836 /* if host mangling mode enabled, also check their real host */
837 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
838 {
38e6acdd 839 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
212380e3 840 use_althost = 1;
841 }
842 /* if host mangling mode not enabled and no other spoof,
843 * also check the mangled form of their host */
844 else if (!IsDynSpoof(source_p))
845 {
38e6acdd 846 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
212380e3 847 use_althost = 1;
848 }
849 }
850
851 if((is_banned(chptr, source_p, NULL, src_host, src_iphost)) == CHFL_BAN)
852 return (ERR_BANNEDFROMCHAN);
853
854 if(chptr->mode.mode & MODE_INVITEONLY)
855 {
8e69bb4e 856 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
212380e3 857 {
1ebf4db4 858 if(invite->data == chptr)
212380e3 859 break;
860 }
1ebf4db4 861 if(invite == NULL)
212380e3 862 {
863 if(!ConfigChannel.use_invex)
864 return (ERR_INVITEONLYCHAN);
8e69bb4e 865 RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
212380e3 866 {
867 invex = ptr->data;
868 if(match(invex->banstr, src_host)
869 || match(invex->banstr, src_iphost)
870 || match_cidr(invex->banstr, src_iphost)
871 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
872 || (use_althost && match(invex->banstr, src_althost)))
873 break;
874 }
875 if(ptr == NULL)
876 return (ERR_INVITEONLYCHAN);
877 }
878 }
879
880 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
881 return (ERR_BADCHANNELKEY);
882
883 if(chptr->mode.limit &&
af81d5a0 884 rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
1ebf4db4 885 i = ERR_CHANNELISFULL;
212380e3 886 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
1ebf4db4 887 i = ERR_NEEDREGGEDNICK;
212380e3 888 /* join throttling stuff --nenolod */
1ebf4db4 889 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
212380e3 890 {
9f6bbe3c 891 if ((rb_current_time() - chptr->join_delta <=
212380e3 892 chptr->mode.join_time) && (chptr->join_count >=
893 chptr->mode.join_num))
1ebf4db4 894 i = ERR_THROTTLE;
895 }
896
897 /* allow /invite to override +l/+r/+j also -- jilles */
898 if (i != 0 && invite == NULL)
899 {
8e69bb4e 900 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
1ebf4db4 901 {
902 if(invite->data == chptr)
903 break;
904 }
905 if (invite == NULL)
906 return i;
212380e3 907 }
908
909 moduledata.client = source_p;
910 moduledata.chptr = chptr;
911 moduledata.approved = 0;
912
913 call_hook(h_can_join, &moduledata);
914
915 return moduledata.approved;
916}
917
918/* can_send()
919 *
920 * input - user to check in channel, membership pointer
921 * output - whether can explicitly send or not, else CAN_SEND_NONOP
922 * side effects -
923 */
924int
925can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
926{
927 if(IsServer(source_p) || IsService(source_p))
928 return CAN_SEND_OPV;
929
930 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
931 !IsOper(source_p) && !IsExemptResv(source_p))
932 return CAN_SEND_NO;
933
934 if(msptr == NULL)
935 {
936 msptr = find_channel_membership(chptr, source_p);
937
938 if(msptr == NULL)
939 {
940 /* if its +m or +n and theyre not in the channel,
941 * they cant send. we dont check bans here because
942 * theres no possibility of caching them --fl
943 */
944 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
945 return CAN_SEND_NO;
946 else
947 return CAN_SEND_NONOP;
948 }
949 }
950
951 if(is_chanop_voiced(msptr))
952 return CAN_SEND_OPV;
953
13a467bb
JH
954 if(IsOverride(source_p))
955 return CAN_SEND_NONOP;
956
212380e3 957 if(chptr->mode.mode & MODE_MODERATED)
958 return CAN_SEND_NO;
959
960 if(MyClient(source_p))
961 {
962 /* cached can_send */
963 if(msptr->bants == chptr->bants)
964 {
965 if(can_send_banned(msptr))
966 return CAN_SEND_NO;
967 }
968 else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
969 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
970 return CAN_SEND_NO;
971 }
972
973 return CAN_SEND_NONOP;
974}
975
976/* find_bannickchange_channel()
977 * Input: client to check
978 * Output: channel preventing nick change
979 */
980struct Channel *
981find_bannickchange_channel(struct Client *client_p)
982{
983 struct Channel *chptr;
984 struct membership *msptr;
af81d5a0 985 rb_dlink_node *ptr;
212380e3 986 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
987 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
988
13a467bb 989 if (!MyClient(client_p) || IsOverride(client_p))
212380e3 990 return NULL;
991
38e6acdd
WP
992 rb_sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
993 rb_sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
212380e3 994
8e69bb4e 995 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3 996 {
997 msptr = ptr->data;
998 chptr = msptr->chptr;
999 if (is_chanop_voiced(msptr))
1000 continue;
1001 /* cached can_send */
1002 if (msptr->bants == chptr->bants)
1003 {
1004 if (can_send_banned(msptr))
1005 return chptr;
1006 }
1007 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN
1008 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
1009 return chptr;
1010 }
1011 return NULL;
1012}
1013
afd4834b
G
1014/* find_nonickchange_channel()
1015 * Input: client to check
1016 * Output: channel preventing nick change
1017 */
1018struct Channel *
1019find_nonickchange_channel(struct Client *client_p)
1020{
1021 struct Channel *chptr;
1022 struct membership *msptr;
1023 rb_dlink_node *ptr;
1024
1025 if (!MyClient(client_p))
1026 return NULL;
1027
1028 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
1029 {
1030 msptr = ptr->data;
1031 chptr = msptr->chptr;
5ad94b50 1032 if (chptr->mode.mode & MODE_NONICK && (!ConfigChannel.exempt_cmode_N || !is_any_op(msptr)))
afd4834b
G
1033 return chptr;
1034 }
1035 return NULL;
1036}
1037
212380e3 1038/* void check_spambot_warning(struct Client *source_p)
1039 * Input: Client to check, channel name or NULL if this is a part.
1040 * Output: none
1041 * Side-effects: Updates the client's oper_warn_count_down, warns the
1042 * IRC operators if necessary, and updates join_leave_countdown as
1043 * needed.
1044 */
1045void
1046check_spambot_warning(struct Client *source_p, const char *name)
1047{
1048 int t_delta;
1049 int decrement_count;
1050 if((GlobalSetOptions.spam_num &&
1051 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
1052 {
1053 if(source_p->localClient->oper_warn_count_down > 0)
1054 source_p->localClient->oper_warn_count_down--;
1055 else
1056 source_p->localClient->oper_warn_count_down = 0;
05d8a68c
JT
1057 if(source_p->localClient->oper_warn_count_down == 0 &&
1058 name != NULL)
212380e3 1059 {
1060 /* Its already known as a possible spambot */
05d8a68c
JT
1061 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
1062 "User %s (%s@%s) trying to join %s is a possible spambot",
1063 source_p->name,
1064 source_p->username, source_p->orighost, name);
212380e3 1065 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
1066 }
1067 }
1068 else
1069 {
1070 if((t_delta =
9f6bbe3c 1071 (rb_current_time() - source_p->localClient->last_leave_time)) >
212380e3 1072 JOIN_LEAVE_COUNT_EXPIRE_TIME)
1073 {
1074 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
b6698246
JT
1075 if(name != NULL)
1076 ;
1077 else if(decrement_count > source_p->localClient->join_leave_count)
212380e3 1078 source_p->localClient->join_leave_count = 0;
1079 else
1080 source_p->localClient->join_leave_count -= decrement_count;
1081 }
1082 else
1083 {
9f6bbe3c 1084 if((rb_current_time() -
212380e3 1085 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
1086 {
1087 /* oh, its a possible spambot */
1088 source_p->localClient->join_leave_count++;
1089 }
1090 }
1091 if(name != NULL)
9f6bbe3c 1092 source_p->localClient->last_join_time = rb_current_time();
212380e3 1093 else
9f6bbe3c 1094 source_p->localClient->last_leave_time = rb_current_time();
212380e3 1095 }
1096}
1097
1098/* check_splitmode()
1099 *
1100 * input -
1101 * output -
1102 * side effects - compares usercount and servercount against their split
1103 * values and adjusts splitmode accordingly
1104 */
1105void
1106check_splitmode(void *unused)
1107{
1108 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
1109 {
1110 /* not split, we're being asked to check now because someone
1111 * has left
1112 */
1113 if(!splitmode)
1114 {
1115 if(eob_count < split_servers || Count.total < split_users)
1116 {
1117 splitmode = 1;
1118 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1119 "Network split, activating splitmode");
dd9be678 1120 check_splitmode_ev = rb_event_addish("check_splitmode", check_splitmode, NULL, 2);
212380e3 1121 }
1122 }
1123 /* in splitmode, check whether its finished */
1124 else if(eob_count >= split_servers && Count.total >= split_users)
1125 {
1126 splitmode = 0;
1127
1128 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1129 "Network rejoined, deactivating splitmode");
1130
dd9be678 1131 rb_event_delete(check_splitmode_ev);
0ae330b4 1132 check_splitmode_ev = NULL;
212380e3 1133 }
1134 }
1135}
1136
1137
1138/* allocate_topic()
1139 *
1140 * input - channel to allocate topic for
1141 * output - 1 on success, else 0
1142 * side effects - channel gets a topic allocated
1143 */
1144static void
1145allocate_topic(struct Channel *chptr)
1146{
1147 void *ptr;
1148
1149 if(chptr == NULL)
1150 return;
1151
6e9b4415 1152 ptr = rb_bh_alloc(topic_heap);
212380e3 1153
1154 /* Basically we allocate one large block for the topic and
1155 * the topic info. We then split it up into two and shove it
1156 * in the chptr
1157 */
1158 chptr->topic = ptr;
1159 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1160 *chptr->topic = '\0';
1161 *chptr->topic_info = '\0';
1162}
1163
1164/* free_topic()
1165 *
1166 * input - channel which has topic to free
1167 * output -
1168 * side effects - channels topic is free'd
1169 */
1170static void
1171free_topic(struct Channel *chptr)
1172{
1173 void *ptr;
1174
1175 if(chptr == NULL || chptr->topic == NULL)
1176 return;
1177
1178 /* This is safe for now - If you change allocate_topic you
1179 * MUST change this as well
1180 */
1181 ptr = chptr->topic;
6e9b4415 1182 rb_bh_free(topic_heap, ptr);
212380e3 1183 chptr->topic = NULL;
1184 chptr->topic_info = NULL;
1185}
1186
1187/* set_channel_topic()
1188 *
1189 * input - channel, topic to set, topic info and topic ts
1190 * output -
1191 * side effects - channels topic, topic info and TS are set.
1192 */
1193void
1194set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1195{
1196 if(strlen(topic) > 0)
1197 {
1198 if(chptr->topic == NULL)
1199 allocate_topic(chptr);
907468c4
VY
1200 rb_strlcpy(chptr->topic, topic, TOPICLEN + 1);
1201 rb_strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
212380e3 1202 chptr->topic_time = topicts;
1203 }
1204 else
1205 {
1206 if(chptr->topic != NULL)
1207 free_topic(chptr);
1208 chptr->topic_time = 0;
1209 }
1210}
1211
c279d43b
G
1212/* has_common_channel()
1213 *
1214 * input - pointer to client
1215 * - pointer to another client
1216 * output - 1 if the two have a channel in common, 0 elsewise
1217 * side effects - none
1218 */
1219int
1220has_common_channel(struct Client *client1, struct Client *client2)
1221{
1222 rb_dlink_node *ptr;
1223
1224 RB_DLINK_FOREACH(ptr, client1->user->channel.head)
1225 {
1226 if(IsMember(client2, ((struct membership *)ptr->data)->chptr))
1227 return 1;
1228 }
99c78094 1229 return 0;
c279d43b
G
1230}
1231
212380e3 1232/* channel_modes()
1233 *
1234 * inputs - pointer to channel
1235 * - pointer to client
f1e35c19 1236 * output - string with simple modes
1237 * side effects - result from previous calls overwritten
212380e3 1238 *
1239 * Stolen from ShadowIRCd 4 --nenolod
1240 */
1241const char *
1242channel_modes(struct Channel *chptr, struct Client *client_p)
1243{
1244 int i;
1245 char buf1[BUFSIZE];
1246 char buf2[BUFSIZE];
1247 static char final[BUFSIZE];
1248 char *mbuf = buf1;
1249 char *pbuf = buf2;
1250
1251 *mbuf++ = '+';
1252 *pbuf = '\0';
1253
75818939 1254 for (i = 0; i < 256; i++)
1cdd8fdf 1255 {
565f4362 1256 if(chmode_table[i].set_func == chm_hidden && !IsOper(client_p) && IsClient(client_p))
1cdd8fdf 1257 continue;
75818939
VY
1258 if(chptr->mode.mode & chmode_flags[i])
1259 *mbuf++ = i;
1cdd8fdf 1260 }
212380e3 1261
1262 if(chptr->mode.limit)
1263 {
1264 *mbuf++ = 'l';
1265
f1e35c19 1266 if(!IsClient(client_p) || IsMember(client_p, chptr))
38e6acdd 1267 pbuf += rb_sprintf(pbuf, " %d", chptr->mode.limit);
212380e3 1268 }
1269
1270 if(*chptr->mode.key)
1271 {
1272 *mbuf++ = 'k';
1273
f1e35c19 1274 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
38e6acdd 1275 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.key);
212380e3 1276 }
1277
1278 if(chptr->mode.join_num)
1279 {
1280 *mbuf++ = 'j';
1281
f1e35c19 1282 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
38e6acdd 1283 pbuf += rb_sprintf(pbuf, " %d:%d", chptr->mode.join_num,
212380e3 1284 chptr->mode.join_time);
1285 }
1286
f1e35c19 1287 if(*chptr->mode.forward && (ConfigChannel.use_forward || !IsClient(client_p)))
212380e3 1288 {
1289 *mbuf++ = 'f';
1290
f1e35c19 1291 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
38e6acdd 1292 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.forward);
212380e3 1293 }
1294
1295 *mbuf = '\0';
1296
907468c4 1297 rb_strlcpy(final, buf1, sizeof final);
a64c5173 1298 rb_strlcat(final, buf2, sizeof final);
212380e3 1299 return final;
1300}
1301
1302/* Now lets do some stuff to keep track of what combinations of
1303 * servers exist...
1304 * Note that the number of combinations doubles each time you add
1305 * something to this list. Each one is only quick if no servers use that
1306 * combination, but if the numbers get too high here MODE will get too
1307 * slow. I suggest if you get more than 7 here, you consider getting rid
1308 * of some and merging or something. If it wasn't for irc+cs we would
1309 * probably not even need to bother about most of these, but unfortunately
1310 * we do. -A1kmm
1311 */
1312
1313/* void init_chcap_usage_counts(void)
1314 *
1315 * Inputs - none
1316 * Output - none
1317 * Side-effects - Initialises the usage counts to zero. Fills in the
1318 * chcap_yes and chcap_no combination tables.
1319 */
1320void
1321init_chcap_usage_counts(void)
1322{
1323 unsigned long m, c, y, n;
1324
1325 memset(chcap_combos, 0, sizeof(chcap_combos));
1326
1327 /* For every possible combination */
1328 for (m = 0; m < NCHCAP_COMBOS; m++)
1329 {
1330 /* Check each capab */
1331 for (c = y = n = 0; c < NCHCAPS; c++)
1332 {
1333 if((m & (1 << c)) == 0)
1334 n |= channel_capabs[c];
1335 else
1336 y |= channel_capabs[c];
1337 }
1338 chcap_combos[m].cap_yes = y;
1339 chcap_combos[m].cap_no = n;
1340 }
1341}
1342
1343/* void set_chcap_usage_counts(struct Client *serv_p)
1344 * Input: serv_p; The client whose capabs to register.
1345 * Output: none
1346 * Side-effects: Increments the usage counts for the correct capab
1347 * combination.
1348 */
1349void
1350set_chcap_usage_counts(struct Client *serv_p)
1351{
1352 int n;
1353
1354 for (n = 0; n < NCHCAP_COMBOS; n++)
1355 {
1356 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1357 NotCapable(serv_p, chcap_combos[n].cap_no))
1358 {
1359 chcap_combos[n].count++;
1360 return;
1361 }
1362 }
1363
1364 /* This should be impossible -A1kmm. */
1365 s_assert(0);
1366}
1367
1368/* void set_chcap_usage_counts(struct Client *serv_p)
1369 *
1370 * Inputs - serv_p; The client whose capabs to register.
1371 * Output - none
1372 * Side-effects - Decrements the usage counts for the correct capab
1373 * combination.
1374 */
1375void
1376unset_chcap_usage_counts(struct Client *serv_p)
1377{
1378 int n;
1379
1380 for (n = 0; n < NCHCAP_COMBOS; n++)
1381 {
1382 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1383 NotCapable(serv_p, chcap_combos[n].cap_no))
1384 {
1385 /* Hopefully capabs can't change dynamically or anything... */
1386 s_assert(chcap_combos[n].count > 0);
1387
1388 if(chcap_combos[n].count > 0)
1389 chcap_combos[n].count--;
1390 return;
1391 }
1392 }
1393
1394 /* This should be impossible -A1kmm. */
1395 s_assert(0);
1396}
1397
1398/* void send_cap_mode_changes(struct Client *client_p,
1399 * struct Client *source_p,
1400 * struct Channel *chptr, int cap, int nocap)
1401 * Input: The client sending(client_p), the source client(source_p),
1402 * the channel to send mode changes for(chptr)
1403 * Output: None.
1404 * Side-effects: Sends the appropriate mode changes to capable servers.
1405 *
1406 * Reverted back to my original design, except that we now keep a count
1407 * of the number of servers which each combination as an optimisation, so
1408 * the capabs combinations which are not needed are not worked out. -A1kmm
1409 */
1410void
1411send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1412 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1413{
1414 static char modebuf[BUFSIZE];
1415 static char parabuf[BUFSIZE];
1416 int i, mbl, pbl, nc, mc, preflen, len;
1417 char *pbuf;
1418 const char *arg;
1419 int dir;
1420 int j;
1421 int cap;
1422 int nocap;
1423 int arglen;
1424
1425 /* Now send to servers... */
1426 for (j = 0; j < NCHCAP_COMBOS; j++)
1427 {
1428 if(chcap_combos[j].count == 0)
1429 continue;
1430
1431 mc = 0;
1432 nc = 0;
1433 pbl = 0;
1434 parabuf[0] = 0;
1435 pbuf = parabuf;
1436 dir = MODE_QUERY;
1437
1438 cap = chcap_combos[j].cap_yes;
1439 nocap = chcap_combos[j].cap_no;
1440
9f9b4d7b
WP
1441 mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
1442 use_id(source_p), (long) chptr->channelts,
1443 chptr->chname);
212380e3 1444
1445 /* loop the list of - modes we have */
1446 for (i = 0; i < mode_count; i++)
1447 {
1448 /* if they dont support the cap we need, or they do support a cap they
1449 * cant have, then dont add it to the modebuf.. that way they wont see
1450 * the mode
1451 */
1452 if((mode_changes[i].letter == 0) ||
1453 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1454 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1455 continue;
1456
7592f950
JT
1457 if(!EmptyString(mode_changes[i].id))
1458 arg = mode_changes[i].id;
1459 else
1460 arg = mode_changes[i].arg;
212380e3 1461
1462 if(arg)
1463 {
1464 arglen = strlen(arg);
1465
1466 /* dont even think about it! --fl */
1467 if(arglen > MODEBUFLEN - 5)
1468 continue;
1469 }
1470
1471 /* if we're creeping past the buf size, we need to send it and make
1472 * another line for the other modes
1473 * XXX - this could give away server topology with uids being
1474 * different lengths, but not much we can do, except possibly break
1475 * them as if they were the longest of the nick or uid at all times,
1476 * which even then won't work as we don't always know the uid -A1kmm.
1477 */
1478 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1479 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1480 {
1481 if(nc != 0)
1482 sendto_server(client_p, chptr, cap, nocap,
1483 "%s %s", modebuf, parabuf);
1484 nc = 0;
1485 mc = 0;
1486
1487 mbl = preflen;
1488 pbl = 0;
1489 pbuf = parabuf;
1490 parabuf[0] = 0;
1491 dir = MODE_QUERY;
1492 }
1493
1494 if(dir != mode_changes[i].dir)
1495 {
1496 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1497 dir = mode_changes[i].dir;
1498 }
1499
1500 modebuf[mbl++] = mode_changes[i].letter;
1501 modebuf[mbl] = 0;
1502 nc++;
1503
1504 if(arg != NULL)
1505 {
38e6acdd 1506 len = rb_sprintf(pbuf, "%s ", arg);
212380e3 1507 pbuf += len;
1508 pbl += len;
1509 mc++;
1510 }
1511 }
1512
1513 if(pbl && parabuf[pbl - 1] == ' ')
1514 parabuf[pbl - 1] = 0;
1515
1516 if(nc != 0)
1517 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
1518 }
1519}
080bb5cf
JH
1520
1521/* Check what we will forward to, without sending any notices to the user
1522 * -- jilles
1523 */
1524struct Channel *
1525check_forward(struct Client *source_p, struct Channel *chptr,
1526 char *key)
1527{
1528 int depth = 0, i;
1529
1530 /* User is +Q */
1531 if (IsNoForward(source_p))
1532 return NULL;
1533
1534 while (depth < 16)
1535 {
1536 chptr = find_channel(chptr->mode.forward);
1537 /* Can only forward to existing channels */
1538 if (chptr == NULL)
1539 return NULL;
1540 /* Already on there, show original error message */
1541 if (IsMember(source_p, chptr))
1542 return NULL;
1543 /* Juped. Sending a warning notice would be unfair */
1544 if (hash_find_resv(chptr->chname))
1545 return NULL;
1546 /* Don't forward to +Q channel */
1547 if (chptr->mode.mode & MODE_DISFORWARD)
1548 return NULL;
1549 i = can_join(source_p, chptr, key);
1550 if (i == 0)
1551 return chptr;
1552 if (i != ERR_INVITEONLYCHAN && i != ERR_NEEDREGGEDNICK && i != ERR_THROTTLE && i != ERR_CHANNELISFULL)
1553 return NULL;
1554 depth++;
1555 }
1556
1557 return NULL;
1558}
67b90240 1559
9230426e
JH
1560/*
1561 * do_join_0
1562 *
1563 * inputs - pointer to client doing join 0
1564 * output - NONE
1565 * side effects - Use has decided to join 0. This is legacy
1566 * from the days when channels were numbers not names. *sigh*
9230426e
JH
1567 */
1568void
1569do_join_0(struct Client *client_p, struct Client *source_p)
1570{
1571 struct membership *msptr;
1572 struct Channel *chptr = NULL;
1573 rb_dlink_node *ptr;
1574
1575 /* Finish the flood grace period... */
1576 if(MyClient(source_p) && !IsFloodDone(source_p))
1577 flood_endgrace(source_p);
1578
1579 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s JOIN 0", use_id(source_p));
1580
aa35afbb
JH
1581 while((ptr = source_p->user->channel.head))
1582 {
9230426e
JH
1583 if(source_p->user->channel.head && MyConnect(source_p) &&
1584 !IsOper(source_p) && !IsExemptSpambot(source_p))
1585 check_spambot_warning(source_p, NULL);
1586
9230426e
JH
1587 msptr = ptr->data;
1588 chptr = msptr->chptr;
1589 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s",
1590 source_p->name,
1591 source_p->username, source_p->host, chptr->chname);
1592 remove_user_from_channel(msptr);
1593 }
1594}
1595
1596int
1597check_channel_name_loc(struct Client *source_p, const char *name)
1598{
aa35afbb
JH
1599 const char *p;
1600
9230426e
JH
1601 s_assert(name != NULL);
1602 if(EmptyString(name))
1603 return 0;
1604
1605 if(ConfigFileEntry.disable_fake_channels && !IsOper(source_p))
1606 {
aa35afbb 1607 for(p = name; *p; ++p)
9230426e 1608 {
aa35afbb 1609 if(!IsChanChar(*p) || IsFakeChanChar(*p))
9230426e
JH
1610 return 0;
1611 }
1612 }
1613 else
1614 {
aa35afbb 1615 for(p = name; *p; ++p)
9230426e 1616 {
aa35afbb 1617 if(!IsChanChar(*p))
9230426e
JH
1618 return 0;
1619 }
1620 }
1621
aa35afbb
JH
1622 if(ConfigChannel.only_ascii_channels)
1623 {
1624 for(p = name; *p; ++p)
1625 if(*p < 33 || *p > 126)
1626 return 0;
1627 }
1628
1629
9230426e
JH
1630 return 1;
1631}
1632
824455ab 1633void user_join(struct Client * client_p, struct Client * source_p, const char * channels, const char * keys)
67b90240
JH
1634{
1635 static char jbuf[BUFSIZE];
1636 struct Channel *chptr = NULL;
1637 struct ConfItem *aconf;
1638 char *name;
1639 char *key = NULL;
1640 const char *modes;
1641 int i, flags = 0;
1642 char *p = NULL, *p2 = NULL;
1643 char *chanlist;
1644 char *mykey;
67b90240
JH
1645
1646 jbuf[0] = '\0';
1647
1648 if(channels == NULL)
1649 return;
1650
1651 /* rebuild the list of channels theyre supposed to be joining.
1652 * this code has a side effect of losing keys, but..
1653 */
1654 chanlist = LOCAL_COPY(channels);
1655 for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p))
1656 {
1657 /* check the length and name of channel is ok */
1658 if(!check_channel_name_loc(source_p, name) || (strlen(name) > LOC_CHANNELLEN))
1659 {
1660 sendto_one_numeric(source_p, ERR_BADCHANNAME,
1661 form_str(ERR_BADCHANNAME), (unsigned char *) name);
1662 continue;
1663 }
1664
1665 /* join 0 parts all channels */
1666 if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist)
1667 {
1668 (void) strcpy(jbuf, "0");
1669 continue;
1670 }
1671
1672 /* check it begins with # or &, and local chans are disabled */
0eceaff1
G
1673 else if(!IsChannelName(name) ||
1674 ( !ConfigChannel.use_local_channels && name[0] == '&'))
67b90240
JH
1675 {
1676 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
1677 form_str(ERR_NOSUCHCHANNEL), name);
1678 continue;
1679 }
1680
1681 /* see if its resv'd */
1682 if(!IsExemptResv(source_p) && (aconf = hash_find_resv(name)))
1683 {
1684 sendto_one_numeric(source_p, ERR_BADCHANNAME,
1685 form_str(ERR_BADCHANNAME), name);
1686
1687 /* dont warn for opers */
1688 if(!IsExemptJupe(source_p) && !IsOper(source_p))
1689 sendto_realops_snomask(SNO_SPY, L_NETWIDE,
1690 "User %s (%s@%s) is attempting to join locally juped channel %s (%s)",
1691 source_p->name, source_p->username,
1692 source_p->orighost, name, aconf->passwd);
1693 /* dont update tracking for jupe exempt users, these
1694 * are likely to be spamtrap leaves
1695 */
1696 else if(IsExemptJupe(source_p))
1697 aconf->port--;
1698
1699 continue;
1700 }
1701
1702 if(splitmode && !IsOper(source_p) && (*name != '&') &&
1703 ConfigChannel.no_join_on_split)
1704 {
1705 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
1706 me.name, source_p->name, name);
1707 continue;
1708 }
1709
1710 if(*jbuf)
1711 (void) strcat(jbuf, ",");
1712 (void) rb_strlcat(jbuf, name, sizeof(jbuf));
1713 }
1714
1715 if(keys != NULL)
1716 {
1717 mykey = LOCAL_COPY(keys);
1718 key = rb_strtok_r(mykey, ",", &p2);
1719 }
1720
1721 for(name = rb_strtok_r(jbuf, ",", &p); name;
1722 key = (key) ? rb_strtok_r(NULL, ",", &p2) : NULL, name = rb_strtok_r(NULL, ",", &p))
1723 {
1724 hook_data_channel_activity hook_info;
1725
1726 /* JOIN 0 simply parts all channels the user is in */
1727 if(*name == '0' && !atoi(name))
1728 {
1729 if(source_p->user->channel.head == NULL)
1730 continue;
1731
1732 do_join_0(&me, source_p);
1733 continue;
1734 }
1735
1736 /* look for the channel */
1737 if((chptr = find_channel(name)) != NULL)
1738 {
1739 if(IsMember(source_p, chptr))
1740 continue;
1741
1742 flags = 0;
1743 }
1744 else
1745 {
1746 hook_data_client_approval moduledata;
1747
1748 moduledata.client = source_p;
1749 moduledata.approved = 0;
1750
1751 call_hook(h_can_create_channel, &moduledata);
1752
1753 if(moduledata.approved != 0)
1754 {
1755 sendto_one(source_p, form_str(moduledata.approved),
1756 me.name, source_p->name, name);
1757 continue;
1758 }
1759
1760 if(splitmode && !IsOper(source_p) && (*name != '&') &&
1761 ConfigChannel.no_create_on_split)
1762 {
1763 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
1764 me.name, source_p->name, name);
1765 continue;
1766 }
1767
1768 flags = CHFL_CHANOP;
1769 }
1770
1771 if((rb_dlink_list_length(&source_p->user->channel) >=
1772 (unsigned long) ConfigChannel.max_chans_per_user) &&
1773 (!IsOper(source_p) ||
1774 (rb_dlink_list_length(&source_p->user->channel) >=
1775 (unsigned long) ConfigChannel.max_chans_per_user * 3)))
1776 {
1777 sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
1778 me.name, source_p->name, name);
67b90240
JH
1779 return;
1780 }
1781
67b90240
JH
1782 if(chptr == NULL) /* If I already have a chptr, no point doing this */
1783 {
1784 chptr = get_or_create_channel(source_p, name, NULL);
1785
1786 if(chptr == NULL)
1787 {
1788 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
1789 me.name, source_p->name, name);
67b90240
JH
1790 continue;
1791 }
1792 }
1793
67b90240
JH
1794 /* can_join checks for +i key, bans etc */
1795 if((i = can_join(source_p, chptr, key)))
1796 {
1797 if ((i != ERR_NEEDREGGEDNICK && i != ERR_THROTTLE && i != ERR_INVITEONLYCHAN && i != ERR_CHANNELISFULL) ||
1798 (!ConfigChannel.use_forward || (chptr = check_forward(source_p, chptr, key)) == NULL))
1799 {
1800 /* might be wrong, but is there any other better location for such?
1801 * see extensions/chm_operonly.c for other comments on this
1802 * -- dwr
1803 */
1804 if(i != ERR_CUSTOM)
1805 sendto_one(source_p, form_str(i), me.name, source_p->name, name);
1806
67b90240
JH
1807 continue;
1808 }
1809
1810 sendto_one_numeric(source_p, ERR_LINKCHANNEL, form_str(ERR_LINKCHANNEL), name, chptr->chname);
1811 }
aa35afbb
JH
1812
1813 if(flags == 0 &&
1814 !IsOper(source_p) && !IsExemptSpambot(source_p))
1815 check_spambot_warning(source_p, name);
67b90240
JH
1816
1817 /* add the user to the channel */
1818 add_user_to_channel(chptr, source_p, flags);
1819 if (chptr->mode.join_num &&
1820 rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
1821 {
1822 chptr->join_count = 0;
1823 chptr->join_delta = rb_current_time();
1824 }
1825 chptr->join_count++;
1826
1827 /* we send the user their join here, because we could have to
1828 * send a mode out next.
1829 */
1830 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
1831 source_p->name,
1832 source_p->username, source_p->host, chptr->chname);
1833
1834 /* its a new channel, set +nt and burst. */
1835 if(flags & CHFL_CHANOP)
1836 {
1837 chptr->channelts = rb_current_time();
13ec57db
JH
1838
1839 /* autochanmodes stuff */
1840 if(ConfigChannel.autochanmodes)
1841 {
1842 char * ch;
1843 for(ch = ConfigChannel.autochanmodes; *ch; *ch++)
1844 {
1845 chptr->mode.mode |= chmode_table[*ch].mode_type;
1846 }
1847 }
1848 else
1849 {
1850 chptr->mode.mode |= MODE_TOPICLIMIT;
1851 chptr->mode.mode |= MODE_NOPRIVMSGS;
1852 }
1853
67b90240
JH
1854 modes = channel_modes(chptr, &me);
1855
1856 sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s %s",
1857 me.name, chptr->chname, modes);
1858
1859 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
1860 ":%s SJOIN %ld %s %s :@%s",
1861 me.id, (long) chptr->channelts,
1862 chptr->chname, modes, source_p->id);
1863 }
1864 else
1865 {
1866 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
1867 ":%s JOIN %ld %s +",
1868 use_id(source_p), (long) chptr->channelts,
1869 chptr->chname);
1870 }
1871
1872 del_invite(chptr, source_p);
1873
1874 if(chptr->topic != NULL)
1875 {
1876 sendto_one(source_p, form_str(RPL_TOPIC), me.name,
1877 source_p->name, chptr->chname, chptr->topic);
1878
1879 sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
1880 me.name, source_p->name, chptr->chname,
1881 chptr->topic_info, chptr->topic_time);
1882 }
1883
1884 channel_member_names(chptr, source_p, 1);
1885
67b90240
JH
1886 hook_info.client = source_p;
1887 hook_info.chptr = chptr;
1888 hook_info.key = key;
1889 call_hook(h_channel_join, &hook_info);
1890 }
1891
1892 return;
1893}