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