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