]> jfr.im git - solanum.git/blame - src/channel.c
Do not allow forward channels for +qeI, as in ircd-seven.
[solanum.git] / src / channel.c
CommitLineData
212380e3
AC
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
AC
25 */
26
27#include "stdinc.h"
212380e3 28#include "channel.h"
392ae75c 29#include "chmode.h"
212380e3
AC
30#include "client.h"
31#include "common.h"
32#include "hash.h"
33#include "hook.h"
4562c604 34#include "match.h"
212380e3
AC
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"
4016731b 43#include "logger.h"
212380e3 44
18e4d421 45struct config_channel_entry ConfigChannel;
c3d10343 46rb_dlink_list global_channel_list;
b617afdc
VY
47static rb_bh *channel_heap;
48static rb_bh *ban_heap;
49static rb_bh *topic_heap;
50static rb_bh *member_heap;
51
212380e3
AC
52static int channel_capabs[] = { CAP_EX, CAP_IE,
53 CAP_SERVICE,
54 CAP_TS6
55};
56
57#define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
58#define NCHCAP_COMBOS (1 << NCHCAPS)
59
60static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
61
62static void free_topic(struct Channel *chptr);
63
64static int h_can_join;
0aa36c5f 65static int h_can_send;
749d8c11 66int h_get_channel_access;
212380e3
AC
67
68/* init_channels()
69 *
70 * input -
71 * output -
72 * side effects - initialises the various blockheaps
73 */
74void
75init_channels(void)
76{
c608a061
AC
77 channel_heap = rb_bh_create(sizeof(struct Channel), CHANNEL_HEAP_SIZE, "channel_heap");
78 ban_heap = rb_bh_create(sizeof(struct Ban), BAN_HEAP_SIZE, "ban_heap");
79 topic_heap = rb_bh_create(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE, "topic_heap");
80 member_heap = rb_bh_create(sizeof(struct membership), MEMBER_HEAP_SIZE, "member_heap");
212380e3
AC
81
82 h_can_join = register_hook("can_join");
0aa36c5f 83 h_can_send = register_hook("can_send");
749d8c11 84 h_get_channel_access = register_hook("get_channel_access");
212380e3
AC
85}
86
87/*
88 * allocate_channel - Allocates a channel
89 */
90struct Channel *
91allocate_channel(const char *chname)
92{
93 struct Channel *chptr;
398b6a73 94 chptr = rb_bh_alloc(channel_heap);
47a03750 95 chptr->chname = rb_strdup(chname);
212380e3
AC
96 return (chptr);
97}
98
99void
100free_channel(struct Channel *chptr)
101{
637c4932 102 rb_free(chptr->chname);
78e6b731 103 rb_free(chptr->mode_lock);
398b6a73 104 rb_bh_free(channel_heap, chptr);
212380e3
AC
105}
106
107struct Ban *
765d839d 108allocate_ban(const char *banstr, const char *who, const char *forward)
212380e3
AC
109{
110 struct Ban *bptr;
398b6a73 111 bptr = rb_bh_alloc(ban_heap);
47a03750
VY
112 bptr->banstr = rb_strdup(banstr);
113 bptr->who = rb_strdup(who);
765d839d 114 bptr->forward = forward ? rb_strdup(forward) : NULL;
212380e3
AC
115
116 return (bptr);
117}
118
119void
120free_ban(struct Ban *bptr)
121{
637c4932
VY
122 rb_free(bptr->banstr);
123 rb_free(bptr->who);
765d839d 124 rb_free(bptr->forward);
398b6a73 125 rb_bh_free(ban_heap, bptr);
212380e3
AC
126}
127
27912fd4
AC
128/*
129 * send_channel_join()
130 *
131 * input - channel to join, client joining.
132 * output - none
133 * side effects - none
134 */
135void
136send_channel_join(struct Channel *chptr, struct Client *client_p)
137{
138 if (!IsClient(client_p))
139 return;
140
92052a5c
AC
141 sendto_channel_local_with_capability(ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN, chptr, ":%s!%s@%s JOIN %s",
142 client_p->name, client_p->username, client_p->host, chptr->chname);
143
26e9dd93 144 sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_EXTENDED_JOIN, NOCAPS, chptr, ":%s!%s@%s JOIN %s %s :%s",
92052a5c
AC
145 client_p->name, client_p->username, client_p->host, chptr->chname,
146 EmptyString(client_p->user->suser) ? "*" : client_p->user->suser,
26e9dd93 147 client_p->info);
27912fd4 148}
212380e3
AC
149
150/* find_channel_membership()
151 *
152 * input - channel to find them in, client to find
153 * output - membership of client in channel, else NULL
154 * side effects -
155 */
156struct membership *
157find_channel_membership(struct Channel *chptr, struct Client *client_p)
158{
159 struct membership *msptr;
330fc5c1 160 rb_dlink_node *ptr;
212380e3
AC
161
162 if(!IsClient(client_p))
163 return NULL;
164
165 /* Pick the most efficient list to use to be nice to things like
166 * CHANSERV which could be in a large number of channels
167 */
330fc5c1 168 if(rb_dlink_list_length(&chptr->members) < rb_dlink_list_length(&client_p->user->channel))
212380e3 169 {
5cefa1d6 170 RB_DLINK_FOREACH(ptr, chptr->members.head)
212380e3
AC
171 {
172 msptr = ptr->data;
173
174 if(msptr->client_p == client_p)
175 return msptr;
176 }
177 }
178 else
179 {
5cefa1d6 180 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3
AC
181 {
182 msptr = ptr->data;
183
184 if(msptr->chptr == chptr)
185 return msptr;
186 }
187 }
188
189 return NULL;
190}
191
192/* find_channel_status()
193 *
194 * input - membership to get status for, whether we can combine flags
195 * output - flags of user on channel
196 * side effects -
197 */
198const char *
199find_channel_status(struct membership *msptr, int combine)
200{
201 static char buffer[3];
202 char *p;
203
204 p = buffer;
205
206 if(is_chanop(msptr))
207 {
208 if(!combine)
209 return "@";
210 *p++ = '@';
211 }
212
213 if(is_voiced(msptr))
214 *p++ = '+';
215
216 *p = '\0';
217 return buffer;
218}
219
220/* add_user_to_channel()
221 *
222 * input - channel to add client to, client to add, channel flags
223 * output -
224 * side effects - user is added to channel
225 */
226void
227add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
228{
229 struct membership *msptr;
230
231 s_assert(client_p->user != NULL);
232 if(client_p->user == NULL)
233 return;
234
398b6a73 235 msptr = rb_bh_alloc(member_heap);
212380e3
AC
236
237 msptr->chptr = chptr;
238 msptr->client_p = client_p;
239 msptr->flags = flags;
240
330fc5c1
AC
241 rb_dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
242 rb_dlinkAdd(msptr, &msptr->channode, &chptr->members);
212380e3
AC
243
244 if(MyClient(client_p))
330fc5c1 245 rb_dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
212380e3
AC
246}
247
248/* remove_user_from_channel()
249 *
250 * input - membership pointer to remove from channel
251 * output -
252 * side effects - membership (thus user) is removed from channel
253 */
254void
255remove_user_from_channel(struct membership *msptr)
256{
257 struct Client *client_p;
258 struct Channel *chptr;
259 s_assert(msptr != NULL);
260 if(msptr == NULL)
261 return;
262
263 client_p = msptr->client_p;
264 chptr = msptr->chptr;
265
330fc5c1
AC
266 rb_dlinkDelete(&msptr->usernode, &client_p->user->channel);
267 rb_dlinkDelete(&msptr->channode, &chptr->members);
212380e3
AC
268
269 if(client_p->servptr == &me)
330fc5c1 270 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
212380e3 271
330fc5c1 272 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
212380e3
AC
273 destroy_channel(chptr);
274
398b6a73 275 rb_bh_free(member_heap, msptr);
212380e3
AC
276
277 return;
278}
279
280/* remove_user_from_channels()
281 *
282 * input - user to remove from all channels
283 * output -
284 * side effects - user is removed from all channels
285 */
286void
287remove_user_from_channels(struct Client *client_p)
288{
289 struct Channel *chptr;
290 struct membership *msptr;
330fc5c1 291 rb_dlink_node *ptr;
637c4932 292 rb_dlink_node *next_ptr;
212380e3
AC
293
294 if(client_p == NULL)
295 return;
296
637c4932 297 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
212380e3
AC
298 {
299 msptr = ptr->data;
300 chptr = msptr->chptr;
301
330fc5c1 302 rb_dlinkDelete(&msptr->channode, &chptr->members);
212380e3
AC
303
304 if(client_p->servptr == &me)
330fc5c1 305 rb_dlinkDelete(&msptr->locchannode, &chptr->locmembers);
212380e3 306
330fc5c1 307 if(!(chptr->mode.mode & MODE_PERMANENT) && rb_dlink_list_length(&chptr->members) <= 0)
212380e3
AC
308 destroy_channel(chptr);
309
398b6a73 310 rb_bh_free(member_heap, msptr);
212380e3
AC
311 }
312
313 client_p->user->channel.head = client_p->user->channel.tail = NULL;
314 client_p->user->channel.length = 0;
315}
316
317/* invalidate_bancache_user()
318 *
319 * input - user to invalidate ban cache for
320 * output -
321 * side effects - ban cache is invalidated for all memberships of that user
322 * to be used after a nick change
323 */
324void
325invalidate_bancache_user(struct Client *client_p)
326{
327 struct membership *msptr;
330fc5c1 328 rb_dlink_node *ptr;
212380e3
AC
329
330 if(client_p == NULL)
331 return;
332
5cefa1d6 333 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3
AC
334 {
335 msptr = ptr->data;
336 msptr->bants = 0;
337 msptr->flags &= ~CHFL_BANNED;
338 }
339}
340
341/* check_channel_name()
342 *
343 * input - channel name
344 * output - 1 if valid channel name, else 0
345 * side effects -
346 */
347int
348check_channel_name(const char *name)
349{
350 s_assert(name != NULL);
351 if(name == NULL)
352 return 0;
353
354 for (; *name; ++name)
355 {
356 if(!IsChanChar(*name))
357 return 0;
358 }
359
360 return 1;
361}
362
363/* free_channel_list()
364 *
330fc5c1 365 * input - rb_dlink list to free
212380e3
AC
366 * output -
367 * side effects - list of b/e/I modes is cleared
368 */
369void
330fc5c1 370free_channel_list(rb_dlink_list * list)
212380e3 371{
330fc5c1 372 rb_dlink_node *ptr;
637c4932 373 rb_dlink_node *next_ptr;
212380e3
AC
374 struct Ban *actualBan;
375
637c4932 376 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
212380e3
AC
377 {
378 actualBan = ptr->data;
379 free_ban(actualBan);
380 }
381
382 list->head = list->tail = NULL;
383 list->length = 0;
384}
385
386/* destroy_channel()
387 *
388 * input - channel to destroy
389 * output -
390 * side effects - channel is obliterated
391 */
392void
393destroy_channel(struct Channel *chptr)
394{
637c4932 395 rb_dlink_node *ptr, *next_ptr;
212380e3 396
637c4932 397 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
212380e3
AC
398 {
399 del_invite(chptr, ptr->data);
400 }
401
402 /* free all bans/exceptions/denies */
403 free_channel_list(&chptr->banlist);
404 free_channel_list(&chptr->exceptlist);
405 free_channel_list(&chptr->invexlist);
fea1ad52 406 free_channel_list(&chptr->quietlist);
212380e3
AC
407
408 /* Free the topic */
409 free_topic(chptr);
410
330fc5c1 411 rb_dlinkDelete(&chptr->node, &global_channel_list);
212380e3
AC
412 del_from_channel_hash(chptr->chname, chptr);
413 free_channel(chptr);
414}
415
416/* channel_pub_or_secret()
417 *
418 * input - channel
419 * output - "=" if public, "@" if secret, else "*"
420 * side effects -
421 */
422static const char *
423channel_pub_or_secret(struct Channel *chptr)
424{
425 if(PubChannel(chptr))
426 return ("=");
427 else if(SecretChannel(chptr))
428 return ("@");
429 return ("*");
430}
431
432/* channel_member_names()
433 *
434 * input - channel to list, client to list to, show endofnames
435 * output -
436 * side effects - client is given list of users on channel
437 */
438void
439channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
440{
441 struct membership *msptr;
442 struct Client *target_p;
330fc5c1 443 rb_dlink_node *ptr;
212380e3
AC
444 char lbuf[BUFSIZE];
445 char *t;
446 int mlen;
447 int tlen;
448 int cur_len;
449 int is_member;
450 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
451
452 if(ShowChannel(client_p, chptr))
453 {
454 is_member = IsMember(client_p, chptr);
455
b2f0da88 456 cur_len = mlen = rb_sprintf(lbuf, form_str(RPL_NAMREPLY),
212380e3
AC
457 me.name, client_p->name,
458 channel_pub_or_secret(chptr), chptr->chname);
459
460 t = lbuf + cur_len;
461
5cefa1d6 462 RB_DLINK_FOREACH(ptr, chptr->members.head)
212380e3
AC
463 {
464 msptr = ptr->data;
465 target_p = msptr->client_p;
466
467 if(IsInvisible(target_p) && !is_member)
468 continue;
469
470 /* space, possible "@+" prefix */
471 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
472 {
473 *(t - 1) = '\0';
474 sendto_one(client_p, "%s", lbuf);
475 cur_len = mlen;
476 t = lbuf + mlen;
477 }
478
b2f0da88 479 tlen = rb_sprintf(t, "%s%s ", find_channel_status(msptr, stack),
212380e3
AC
480 target_p->name);
481
482 cur_len += tlen;
483 t += tlen;
484 }
485
486 /* The old behaviour here was to always output our buffer,
487 * even if there are no clients we can show. This happens
488 * when a client does "NAMES" with no parameters, and all
489 * the clients on a -sp channel are +i. I dont see a good
490 * reason for keeping that behaviour, as it just wastes
491 * bandwidth. --anfl
492 */
493 if(cur_len != mlen)
494 {
495 *(t - 1) = '\0';
496 sendto_one(client_p, "%s", lbuf);
497 }
498 }
499
500 if(show_eon)
501 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
502 me.name, client_p->name, chptr->chname);
503}
504
505/* del_invite()
506 *
507 * input - channel to remove invite from, client to remove
508 * output -
509 * side effects - user is removed from invite list, if exists
510 */
511void
512del_invite(struct Channel *chptr, struct Client *who)
513{
330fc5c1
AC
514 rb_dlinkFindDestroy(who, &chptr->invites);
515 rb_dlinkFindDestroy(chptr, &who->user->invited);
212380e3
AC
516}
517
518/* is_banned()
519 *
520 * input - channel to check bans for, user to check bans against
521 * optional prebuilt buffers
522 * output - 1 if banned, else 0
523 * side effects -
524 */
525int
526is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
765d839d 527 const char *s, const char *s2, const char **forward)
212380e3
AC
528{
529 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
530 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
531 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
532 char *s3 = NULL;
330fc5c1 533 rb_dlink_node *ptr;
212380e3
AC
534 struct Ban *actualBan = NULL;
535 struct Ban *actualExcept = NULL;
536
537 if(!MyClient(who))
538 return 0;
539
540 /* if the buffers havent been built, do it here */
541 if(s == NULL)
542 {
b2f0da88
AC
543 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
544 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
212380e3
AC
545
546 s = src_host;
547 s2 = src_iphost;
548 }
549 if(who->localClient->mangledhost != NULL)
550 {
551 /* if host mangling mode enabled, also check their real host */
552 if(!strcmp(who->host, who->localClient->mangledhost))
553 {
b2f0da88 554 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
212380e3
AC
555 s3 = src_althost;
556 }
557 /* if host mangling mode not enabled and no other spoof,
558 * also check the mangled form of their host */
559 else if (!IsDynSpoof(who))
560 {
b2f0da88 561 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
212380e3
AC
562 s3 = src_althost;
563 }
564 }
565
5cefa1d6 566 RB_DLINK_FOREACH(ptr, chptr->banlist.head)
212380e3
AC
567 {
568 actualBan = ptr->data;
569 if(match(actualBan->banstr, s) ||
570 match(actualBan->banstr, s2) ||
571 match_cidr(actualBan->banstr, s2) ||
572 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
573 (s3 != NULL && match(actualBan->banstr, s3)))
574 break;
575 else
576 actualBan = NULL;
577 }
578
579 if((actualBan != NULL) && ConfigChannel.use_except)
580 {
5cefa1d6 581 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
212380e3
AC
582 {
583 actualExcept = ptr->data;
584
585 /* theyre exempted.. */
586 if(match(actualExcept->banstr, s) ||
587 match(actualExcept->banstr, s2) ||
588 match_cidr(actualExcept->banstr, s2) ||
589 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
590 (s3 != NULL && match(actualExcept->banstr, s3)))
591 {
592 /* cache the fact theyre not banned */
593 if(msptr != NULL)
594 {
595 msptr->bants = chptr->bants;
596 msptr->flags &= ~CHFL_BANNED;
597 }
598
599 return CHFL_EXCEPTION;
600 }
601 }
602 }
603
604 /* cache the banned/not banned status */
605 if(msptr != NULL)
606 {
607 msptr->bants = chptr->bants;
608
609 if(actualBan != NULL)
610 {
611 msptr->flags |= CHFL_BANNED;
612 return CHFL_BAN;
613 }
614 else
615 {
616 msptr->flags &= ~CHFL_BANNED;
617 return 0;
618 }
619 }
620
765d839d
EM
621 if (actualBan && actualBan->forward && forward)
622 *forward = actualBan->forward;
623
212380e3
AC
624 return ((actualBan ? CHFL_BAN : 0));
625}
626
627/* is_quieted()
628 *
629 * input - channel to check bans for, user to check bans against
630 * optional prebuilt buffers
631 * output - 1 if banned, else 0
632 * side effects -
633 */
634int
635is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
636 const char *s, const char *s2)
637{
638 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
639 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
640 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
641 char *s3 = NULL;
330fc5c1 642 rb_dlink_node *ptr;
212380e3
AC
643 struct Ban *actualBan = NULL;
644 struct Ban *actualExcept = NULL;
645
646 if(!MyClient(who))
647 return 0;
648
649 /* if the buffers havent been built, do it here */
650 if(s == NULL)
651 {
b2f0da88
AC
652 rb_sprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
653 rb_sprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
212380e3
AC
654
655 s = src_host;
656 s2 = src_iphost;
657 }
658 if(who->localClient->mangledhost != NULL)
659 {
660 /* if host mangling mode enabled, also check their real host */
661 if(!strcmp(who->host, who->localClient->mangledhost))
662 {
b2f0da88 663 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
212380e3
AC
664 s3 = src_althost;
665 }
666 /* if host mangling mode not enabled and no other spoof,
667 * also check the mangled form of their host */
668 else if (!IsDynSpoof(who))
669 {
b2f0da88 670 rb_sprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
212380e3
AC
671 s3 = src_althost;
672 }
673 }
674
5cefa1d6 675 RB_DLINK_FOREACH(ptr, chptr->quietlist.head)
212380e3
AC
676 {
677 actualBan = ptr->data;
678 if(match(actualBan->banstr, s) ||
679 match(actualBan->banstr, s2) ||
680 match_cidr(actualBan->banstr, s2) ||
681 match_extban(actualBan->banstr, who, chptr, CHFL_QUIET) ||
682 (s3 != NULL && match(actualBan->banstr, s3)))
683 break;
684 else
685 actualBan = NULL;
686 }
687
688 if((actualBan != NULL) && ConfigChannel.use_except)
689 {
5cefa1d6 690 RB_DLINK_FOREACH(ptr, chptr->exceptlist.head)
212380e3
AC
691 {
692 actualExcept = ptr->data;
693
694 /* theyre exempted.. */
695 if(match(actualExcept->banstr, s) ||
696 match(actualExcept->banstr, s2) ||
697 match_cidr(actualExcept->banstr, s2) ||
698 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
699 (s3 != NULL && match(actualExcept->banstr, s3)))
700 {
701 /* cache the fact theyre not banned */
702 if(msptr != NULL)
703 {
704 msptr->bants = chptr->bants;
705 msptr->flags &= ~CHFL_BANNED;
706 }
707
708 return CHFL_EXCEPTION;
709 }
710 }
711 }
712
713 /* cache the banned/not banned status */
714 if(msptr != NULL)
715 {
716 msptr->bants = chptr->bants;
717
718 if(actualBan != NULL)
719 {
720 msptr->flags |= CHFL_BANNED;
721 return CHFL_BAN;
722 }
723 else
724 {
725 msptr->flags &= ~CHFL_BANNED;
726 return 0;
727 }
728 }
729
730 return ((actualBan ? CHFL_BAN : 0));
731}
732
733/* can_join()
734 *
735 * input - client to check, channel to check for, key
765d839d 736 * output - reason for not being able to join, else 0, channel name to forward to
212380e3 737 * side effects -
a63f7af7 738 * caveats - this function should only be called on a local user.
212380e3
AC
739 */
740int
765d839d 741can_join(struct Client *source_p, struct Channel *chptr, char *key, char **forward)
212380e3 742{
330fc5c1
AC
743 rb_dlink_node *invite = NULL;
744 rb_dlink_node *ptr;
212380e3
AC
745 struct Ban *invex = NULL;
746 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
747 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
748 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
749 int use_althost = 0;
1ebf4db4 750 int i = 0;
212380e3
AC
751 hook_data_channel moduledata;
752
753 s_assert(source_p->localClient != NULL);
754
8bb19bd7
AC
755 moduledata.client = source_p;
756 moduledata.chptr = chptr;
757 moduledata.approved = 0;
758
b2f0da88
AC
759 rb_sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
760 rb_sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
212380e3
AC
761 if(source_p->localClient->mangledhost != NULL)
762 {
763 /* if host mangling mode enabled, also check their real host */
764 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
765 {
b2f0da88 766 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
212380e3
AC
767 use_althost = 1;
768 }
769 /* if host mangling mode not enabled and no other spoof,
770 * also check the mangled form of their host */
771 else if (!IsDynSpoof(source_p))
772 {
b2f0da88 773 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
212380e3
AC
774 use_althost = 1;
775 }
776 }
777
765d839d 778 if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == CHFL_BAN)
8bb19bd7
AC
779 {
780 moduledata.approved = ERR_BANNEDFROMCHAN;
781 goto finish_join_check;
782 }
212380e3 783
765d839d
EM
784 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
785 {
786 moduledata.approved = ERR_BADCHANNELKEY;
787 goto finish_join_check;
788 }
789
790 /* All checks from this point on will forward... */
791 if(forward)
792 *forward = chptr->mode.forward;
793
212380e3
AC
794 if(chptr->mode.mode & MODE_INVITEONLY)
795 {
5cefa1d6 796 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
212380e3 797 {
1ebf4db4 798 if(invite->data == chptr)
212380e3
AC
799 break;
800 }
1ebf4db4 801 if(invite == NULL)
212380e3
AC
802 {
803 if(!ConfigChannel.use_invex)
8bb19bd7 804 moduledata.approved = ERR_INVITEONLYCHAN;
5cefa1d6 805 RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
212380e3
AC
806 {
807 invex = ptr->data;
808 if(match(invex->banstr, src_host)
809 || match(invex->banstr, src_iphost)
810 || match_cidr(invex->banstr, src_iphost)
811 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
812 || (use_althost && match(invex->banstr, src_althost)))
813 break;
814 }
815 if(ptr == NULL)
8bb19bd7 816 moduledata.approved = ERR_INVITEONLYCHAN;
212380e3
AC
817 }
818 }
819
212380e3 820 if(chptr->mode.limit &&
330fc5c1 821 rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
1ebf4db4 822 i = ERR_CHANNELISFULL;
212380e3 823 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
1ebf4db4 824 i = ERR_NEEDREGGEDNICK;
212380e3 825 /* join throttling stuff --nenolod */
1ebf4db4 826 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
212380e3 827 {
e3354945 828 if ((rb_current_time() - chptr->join_delta <=
212380e3
AC
829 chptr->mode.join_time) && (chptr->join_count >=
830 chptr->mode.join_num))
1ebf4db4
JT
831 i = ERR_THROTTLE;
832 }
833
834 /* allow /invite to override +l/+r/+j also -- jilles */
835 if (i != 0 && invite == NULL)
836 {
5cefa1d6 837 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
1ebf4db4
JT
838 {
839 if(invite->data == chptr)
840 break;
841 }
842 if (invite == NULL)
8bb19bd7 843 moduledata.approved = i;
212380e3
AC
844 }
845
8bb19bd7 846finish_join_check:
212380e3
AC
847 call_hook(h_can_join, &moduledata);
848
849 return moduledata.approved;
850}
851
852/* can_send()
853 *
854 * input - user to check in channel, membership pointer
855 * output - whether can explicitly send or not, else CAN_SEND_NONOP
856 * side effects -
857 */
858int
859can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
860{
0aa36c5f
AC
861 hook_data_channel_approval moduledata;
862
863 moduledata.approved = CAN_SEND_NONOP;
864
212380e3
AC
865 if(IsServer(source_p) || IsService(source_p))
866 return CAN_SEND_OPV;
867
868 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
869 !IsOper(source_p) && !IsExemptResv(source_p))
0aa36c5f 870 moduledata.approved = CAN_SEND_NO;
212380e3
AC
871
872 if(msptr == NULL)
873 {
874 msptr = find_channel_membership(chptr, source_p);
875
876 if(msptr == NULL)
877 {
878 /* if its +m or +n and theyre not in the channel,
879 * they cant send. we dont check bans here because
880 * theres no possibility of caching them --fl
881 */
882 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
0aa36c5f 883 moduledata.approved = CAN_SEND_NO;
212380e3 884 else
0aa36c5f 885 moduledata.approved = CAN_SEND_NONOP;
b697041e
AC
886
887 return moduledata.approved;
212380e3
AC
888 }
889 }
890
212380e3 891 if(chptr->mode.mode & MODE_MODERATED)
0aa36c5f 892 moduledata.approved = CAN_SEND_NO;
212380e3
AC
893
894 if(MyClient(source_p))
895 {
896 /* cached can_send */
897 if(msptr->bants == chptr->bants)
898 {
899 if(can_send_banned(msptr))
0aa36c5f 900 moduledata.approved = CAN_SEND_NO;
212380e3 901 }
765d839d 902 else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == CHFL_BAN
212380e3 903 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
0aa36c5f 904 moduledata.approved = CAN_SEND_NO;
212380e3
AC
905 }
906
e06988c6
AC
907 if(is_chanop_voiced(msptr))
908 moduledata.approved = CAN_SEND_OPV;
909
f4b52a0a
EM
910 moduledata.client = source_p;
911 moduledata.chptr = msptr->chptr;
912 moduledata.msptr = msptr;
913 moduledata.target = NULL;
914
0aa36c5f
AC
915 call_hook(h_can_send, &moduledata);
916
917 return moduledata.approved;
212380e3
AC
918}
919
15484f02
BG
920/*
921 * flood_attack_channel
922 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
923 * says NOTICE must not auto reply
924 * - pointer to source Client
925 * - pointer to target channel
926 * output - 1 if target is under flood attack
927 * side effects - check for flood attack on target chptr
928 */
929int
930flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
931{
932 int delta;
933
934 if(GlobalSetOptions.floodcount && MyClient(source_p))
935 {
936 if((chptr->first_received_message_time + 1) < rb_current_time())
937 {
938 delta = rb_current_time() - chptr->first_received_message_time;
939 chptr->received_number_of_privmsgs -= delta;
940 chptr->first_received_message_time = rb_current_time();
941 if(chptr->received_number_of_privmsgs <= 0)
942 {
943 chptr->received_number_of_privmsgs = 0;
944 chptr->flood_noticed = 0;
945 }
946 }
947
948 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
949 || chptr->flood_noticed)
950 {
951 if(chptr->flood_noticed == 0)
952 {
953 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
954 "Possible Flooder %s[%s@%s] on %s target: %s",
955 source_p->name, source_p->username,
956 source_p->orighost,
957 source_p->servptr->name, chptr->chname);
958 chptr->flood_noticed = 1;
959
960 /* Add a bit of penalty */
961 chptr->received_number_of_privmsgs += 2;
962 }
963 if(MyClient(source_p) && (p_or_n != 1))
964 sendto_one(source_p,
965 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
966 me.name, source_p->name, chptr->chname);
967 return 1;
968 }
969 else
970 chptr->received_number_of_privmsgs++;
971 }
972
973 return 0;
974}
975
212380e3
AC
976/* find_bannickchange_channel()
977 * Input: client to check
978 * Output: channel preventing nick change
979 */
980struct Channel *
981find_bannickchange_channel(struct Client *client_p)
982{
983 struct Channel *chptr;
984 struct membership *msptr;
330fc5c1 985 rb_dlink_node *ptr;
212380e3
AC
986 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
987 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
988
989 if (!MyClient(client_p))
990 return NULL;
991
b2f0da88
AC
992 rb_sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
993 rb_sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
212380e3 994
5cefa1d6 995 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3
AC
996 {
997 msptr = ptr->data;
998 chptr = msptr->chptr;
999 if (is_chanop_voiced(msptr))
1000 continue;
1001 /* cached can_send */
1002 if (msptr->bants == chptr->bants)
1003 {
1004 if (can_send_banned(msptr))
1005 return chptr;
1006 }
765d839d 1007 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == CHFL_BAN
212380e3
AC
1008 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
1009 return chptr;
1010 }
1011 return NULL;
1012}
1013
1014/* void check_spambot_warning(struct Client *source_p)
1015 * Input: Client to check, channel name or NULL if this is a part.
1016 * Output: none
1017 * Side-effects: Updates the client's oper_warn_count_down, warns the
1018 * IRC operators if necessary, and updates join_leave_countdown as
1019 * needed.
1020 */
1021void
1022check_spambot_warning(struct Client *source_p, const char *name)
1023{
1024 int t_delta;
1025 int decrement_count;
1026 if((GlobalSetOptions.spam_num &&
1027 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
1028 {
1029 if(source_p->localClient->oper_warn_count_down > 0)
1030 source_p->localClient->oper_warn_count_down--;
1031 else
1032 source_p->localClient->oper_warn_count_down = 0;
e0c1f4ec
JT
1033 if(source_p->localClient->oper_warn_count_down == 0 &&
1034 name != NULL)
212380e3
AC
1035 {
1036 /* Its already known as a possible spambot */
e0c1f4ec
JT
1037 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
1038 "User %s (%s@%s) trying to join %s is a possible spambot",
1039 source_p->name,
1040 source_p->username, source_p->orighost, name);
212380e3
AC
1041 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
1042 }
1043 }
1044 else
1045 {
1046 if((t_delta =
e3354945 1047 (rb_current_time() - source_p->localClient->last_leave_time)) >
212380e3
AC
1048 JOIN_LEAVE_COUNT_EXPIRE_TIME)
1049 {
1050 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
981586df
JT
1051 if(name != NULL)
1052 ;
1053 else if(decrement_count > source_p->localClient->join_leave_count)
212380e3
AC
1054 source_p->localClient->join_leave_count = 0;
1055 else
1056 source_p->localClient->join_leave_count -= decrement_count;
1057 }
1058 else
1059 {
e3354945 1060 if((rb_current_time() -
212380e3
AC
1061 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
1062 {
1063 /* oh, its a possible spambot */
1064 source_p->localClient->join_leave_count++;
1065 }
1066 }
1067 if(name != NULL)
e3354945 1068 source_p->localClient->last_join_time = rb_current_time();
212380e3 1069 else
e3354945 1070 source_p->localClient->last_leave_time = rb_current_time();
212380e3
AC
1071 }
1072}
1073
1074/* check_splitmode()
1075 *
1076 * input -
1077 * output -
1078 * side effects - compares usercount and servercount against their split
1079 * values and adjusts splitmode accordingly
1080 */
1081void
1082check_splitmode(void *unused)
1083{
1084 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
1085 {
1086 /* not split, we're being asked to check now because someone
1087 * has left
1088 */
1089 if(!splitmode)
1090 {
1091 if(eob_count < split_servers || Count.total < split_users)
1092 {
1093 splitmode = 1;
1094 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1095 "Network split, activating splitmode");
c608a061 1096 check_splitmode_ev = rb_event_addish("check_splitmode", check_splitmode, NULL, 2);
212380e3
AC
1097 }
1098 }
1099 /* in splitmode, check whether its finished */
1100 else if(eob_count >= split_servers && Count.total >= split_users)
1101 {
1102 splitmode = 0;
1103
1104 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1105 "Network rejoined, deactivating splitmode");
1106
c608a061 1107 rb_event_delete(check_splitmode_ev);
6a309903 1108 check_splitmode_ev = NULL;
212380e3
AC
1109 }
1110 }
1111}
1112
1113
1114/* allocate_topic()
1115 *
1116 * input - channel to allocate topic for
1117 * output - 1 on success, else 0
1118 * side effects - channel gets a topic allocated
1119 */
1120static void
1121allocate_topic(struct Channel *chptr)
1122{
1123 void *ptr;
1124
1125 if(chptr == NULL)
1126 return;
1127
398b6a73 1128 ptr = rb_bh_alloc(topic_heap);
212380e3
AC
1129
1130 /* Basically we allocate one large block for the topic and
1131 * the topic info. We then split it up into two and shove it
1132 * in the chptr
1133 */
1134 chptr->topic = ptr;
1135 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1136 *chptr->topic = '\0';
1137 *chptr->topic_info = '\0';
1138}
1139
1140/* free_topic()
1141 *
1142 * input - channel which has topic to free
1143 * output -
1144 * side effects - channels topic is free'd
1145 */
1146static void
1147free_topic(struct Channel *chptr)
1148{
1149 void *ptr;
1150
1151 if(chptr == NULL || chptr->topic == NULL)
1152 return;
1153
1154 /* This is safe for now - If you change allocate_topic you
1155 * MUST change this as well
1156 */
1157 ptr = chptr->topic;
398b6a73 1158 rb_bh_free(topic_heap, ptr);
212380e3
AC
1159 chptr->topic = NULL;
1160 chptr->topic_info = NULL;
1161}
1162
1163/* set_channel_topic()
1164 *
1165 * input - channel, topic to set, topic info and topic ts
1166 * output -
1167 * side effects - channels topic, topic info and TS are set.
1168 */
1169void
1170set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1171{
1172 if(strlen(topic) > 0)
1173 {
1174 if(chptr->topic == NULL)
1175 allocate_topic(chptr);
f427c8b0
VY
1176 rb_strlcpy(chptr->topic, topic, TOPICLEN + 1);
1177 rb_strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
212380e3
AC
1178 chptr->topic_time = topicts;
1179 }
1180 else
1181 {
1182 if(chptr->topic != NULL)
1183 free_topic(chptr);
1184 chptr->topic_time = 0;
1185 }
1186}
1187
3b8a6350 1188/* channel_modes()
212380e3
AC
1189 *
1190 * inputs - pointer to channel
1191 * - pointer to client
f1e35c19
JT
1192 * output - string with simple modes
1193 * side effects - result from previous calls overwritten
212380e3
AC
1194 *
1195 * Stolen from ShadowIRCd 4 --nenolod
1196 */
1197const char *
3b8a6350 1198channel_modes(struct Channel *chptr, struct Client *client_p)
212380e3
AC
1199{
1200 int i;
1201 char buf1[BUFSIZE];
1202 char buf2[BUFSIZE];
1203 static char final[BUFSIZE];
1204 char *mbuf = buf1;
1205 char *pbuf = buf2;
1206
1207 *mbuf++ = '+';
1208 *pbuf = '\0';
1209
efccc22c 1210 for (i = 0; i < 256; i++)
3b8a6350 1211 if(chptr->mode.mode & chmode_flags[i])
efccc22c 1212 *mbuf++ = i;
212380e3 1213
3b8a6350 1214 if(chptr->mode.limit)
212380e3
AC
1215 {
1216 *mbuf++ = 'l';
1217
f1e35c19 1218 if(!IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350 1219 pbuf += rb_sprintf(pbuf, " %d", chptr->mode.limit);
212380e3
AC
1220 }
1221
3b8a6350 1222 if(*chptr->mode.key)
212380e3
AC
1223 {
1224 *mbuf++ = 'k';
1225
f1e35c19 1226 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350 1227 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.key);
212380e3
AC
1228 }
1229
3b8a6350 1230 if(chptr->mode.join_num)
212380e3
AC
1231 {
1232 *mbuf++ = 'j';
1233
f1e35c19 1234 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350
SB
1235 pbuf += rb_sprintf(pbuf, " %d:%d", chptr->mode.join_num,
1236 chptr->mode.join_time);
212380e3
AC
1237 }
1238
2da6f6eb
JT
1239 if(*chptr->mode.forward &&
1240 (ConfigChannel.use_forward || !IsClient(client_p)))
212380e3
AC
1241 {
1242 *mbuf++ = 'f';
1243
f1e35c19 1244 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350 1245 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.forward);
212380e3
AC
1246 }
1247
1248 *mbuf = '\0';
1249
f427c8b0 1250 rb_strlcpy(final, buf1, sizeof final);
1f9de103 1251 rb_strlcat(final, buf2, sizeof final);
212380e3
AC
1252 return final;
1253}
1254
1255/* Now lets do some stuff to keep track of what combinations of
1256 * servers exist...
1257 * Note that the number of combinations doubles each time you add
1258 * something to this list. Each one is only quick if no servers use that
1259 * combination, but if the numbers get too high here MODE will get too
1260 * slow. I suggest if you get more than 7 here, you consider getting rid
1261 * of some and merging or something. If it wasn't for irc+cs we would
1262 * probably not even need to bother about most of these, but unfortunately
1263 * we do. -A1kmm
1264 */
1265
1266/* void init_chcap_usage_counts(void)
1267 *
1268 * Inputs - none
1269 * Output - none
1270 * Side-effects - Initialises the usage counts to zero. Fills in the
1271 * chcap_yes and chcap_no combination tables.
1272 */
1273void
1274init_chcap_usage_counts(void)
1275{
1276 unsigned long m, c, y, n;
1277
1278 memset(chcap_combos, 0, sizeof(chcap_combos));
1279
1280 /* For every possible combination */
1281 for (m = 0; m < NCHCAP_COMBOS; m++)
1282 {
1283 /* Check each capab */
1284 for (c = y = n = 0; c < NCHCAPS; c++)
1285 {
1286 if((m & (1 << c)) == 0)
1287 n |= channel_capabs[c];
1288 else
1289 y |= channel_capabs[c];
1290 }
1291 chcap_combos[m].cap_yes = y;
1292 chcap_combos[m].cap_no = n;
1293 }
1294}
1295
1296/* void set_chcap_usage_counts(struct Client *serv_p)
1297 * Input: serv_p; The client whose capabs to register.
1298 * Output: none
1299 * Side-effects: Increments the usage counts for the correct capab
1300 * combination.
1301 */
1302void
1303set_chcap_usage_counts(struct Client *serv_p)
1304{
1305 int n;
1306
1307 for (n = 0; n < NCHCAP_COMBOS; n++)
1308 {
1309 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1310 NotCapable(serv_p, chcap_combos[n].cap_no))
1311 {
1312 chcap_combos[n].count++;
1313 return;
1314 }
1315 }
1316
1317 /* This should be impossible -A1kmm. */
1318 s_assert(0);
1319}
1320
1321/* void set_chcap_usage_counts(struct Client *serv_p)
1322 *
1323 * Inputs - serv_p; The client whose capabs to register.
1324 * Output - none
1325 * Side-effects - Decrements the usage counts for the correct capab
1326 * combination.
1327 */
1328void
1329unset_chcap_usage_counts(struct Client *serv_p)
1330{
1331 int n;
1332
1333 for (n = 0; n < NCHCAP_COMBOS; n++)
1334 {
1335 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1336 NotCapable(serv_p, chcap_combos[n].cap_no))
1337 {
1338 /* Hopefully capabs can't change dynamically or anything... */
1339 s_assert(chcap_combos[n].count > 0);
1340
1341 if(chcap_combos[n].count > 0)
1342 chcap_combos[n].count--;
1343 return;
1344 }
1345 }
1346
1347 /* This should be impossible -A1kmm. */
1348 s_assert(0);
1349}
1350
1351/* void send_cap_mode_changes(struct Client *client_p,
1352 * struct Client *source_p,
1353 * struct Channel *chptr, int cap, int nocap)
1354 * Input: The client sending(client_p), the source client(source_p),
1355 * the channel to send mode changes for(chptr)
1356 * Output: None.
1357 * Side-effects: Sends the appropriate mode changes to capable servers.
1358 *
1359 * Reverted back to my original design, except that we now keep a count
1360 * of the number of servers which each combination as an optimisation, so
1361 * the capabs combinations which are not needed are not worked out. -A1kmm
1362 */
1363void
1364send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1365 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1366{
1367 static char modebuf[BUFSIZE];
1368 static char parabuf[BUFSIZE];
1369 int i, mbl, pbl, nc, mc, preflen, len;
1370 char *pbuf;
1371 const char *arg;
1372 int dir;
1373 int j;
1374 int cap;
1375 int nocap;
1376 int arglen;
1377
1378 /* Now send to servers... */
1379 for (j = 0; j < NCHCAP_COMBOS; j++)
1380 {
1381 if(chcap_combos[j].count == 0)
1382 continue;
1383
1384 mc = 0;
1385 nc = 0;
1386 pbl = 0;
1387 parabuf[0] = 0;
1388 pbuf = parabuf;
1389 dir = MODE_QUERY;
1390
1391 cap = chcap_combos[j].cap_yes;
1392 nocap = chcap_combos[j].cap_no;
1393
469c9689
AC
1394 mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
1395 use_id(source_p), (long) chptr->channelts,
1396 chptr->chname);
212380e3
AC
1397
1398 /* loop the list of - modes we have */
1399 for (i = 0; i < mode_count; i++)
1400 {
1401 /* if they dont support the cap we need, or they do support a cap they
1402 * cant have, then dont add it to the modebuf.. that way they wont see
1403 * the mode
1404 */
1405 if((mode_changes[i].letter == 0) ||
1406 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1407 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1408 continue;
1409
fd44b851
JT
1410 if(!EmptyString(mode_changes[i].id))
1411 arg = mode_changes[i].id;
1412 else
1413 arg = mode_changes[i].arg;
212380e3
AC
1414
1415 if(arg)
1416 {
1417 arglen = strlen(arg);
1418
1419 /* dont even think about it! --fl */
1420 if(arglen > MODEBUFLEN - 5)
1421 continue;
1422 }
1423
1424 /* if we're creeping past the buf size, we need to send it and make
1425 * another line for the other modes
1426 * XXX - this could give away server topology with uids being
1427 * different lengths, but not much we can do, except possibly break
1428 * them as if they were the longest of the nick or uid at all times,
1429 * which even then won't work as we don't always know the uid -A1kmm.
1430 */
1431 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1432 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1433 {
1434 if(nc != 0)
1435 sendto_server(client_p, chptr, cap, nocap,
1436 "%s %s", modebuf, parabuf);
1437 nc = 0;
1438 mc = 0;
1439
1440 mbl = preflen;
1441 pbl = 0;
1442 pbuf = parabuf;
1443 parabuf[0] = 0;
1444 dir = MODE_QUERY;
1445 }
1446
1447 if(dir != mode_changes[i].dir)
1448 {
1449 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1450 dir = mode_changes[i].dir;
1451 }
1452
1453 modebuf[mbl++] = mode_changes[i].letter;
1454 modebuf[mbl] = 0;
1455 nc++;
1456
1457 if(arg != NULL)
1458 {
b2f0da88 1459 len = rb_sprintf(pbuf, "%s ", arg);
212380e3
AC
1460 pbuf += len;
1461 pbl += len;
1462 mc++;
1463 }
1464 }
1465
1466 if(pbl && parabuf[pbl - 1] == ' ')
1467 parabuf[pbl - 1] = 0;
1468
1469 if(nc != 0)
1470 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
1471 }
1472}
dca9e552
JT
1473
1474void
1475resv_chan_forcepart(const char *name, const char *reason, int temp_time)
1476{
1477 rb_dlink_node *ptr;
1478 rb_dlink_node *next_ptr;
1479 struct Channel *chptr;
1480 struct membership *msptr;
1481 struct Client *target_p;
1482
1483 if(!ConfigChannel.resv_forcepart)
1484 return;
1485
1486 /* for each user on our server in the channel list
1487 * send them a PART, and notify opers.
1488 */
1489 chptr = find_channel(name);
1490 if(chptr != NULL)
1491 {
1492 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
1493 {
1494 msptr = ptr->data;
1495 target_p = msptr->client_p;
1496
1497 if(IsExemptResv(target_p))
1498 continue;
1499
1500 sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
1501 ":%s PART %s", target_p->id, chptr->chname);
1502
1503 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
1504 target_p->name, target_p->username,
1505 target_p->host, chptr->chname, target_p->name);
1506
1507 remove_user_from_channel(msptr);
1508
1509 /* notify opers & user they were removed from the channel */
1510 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1511 "Forced PART for %s!%s@%s from %s (%s)",
1512 target_p->name, target_p->username,
1513 target_p->host, name, reason);
1514
1515 if(temp_time > 0)
1516 sendto_one_notice(target_p, ":*** Channel %s is temporarily unavailable on this server.",
1517 name);
1518 else
1519 sendto_one_notice(target_p, ":*** Channel %s is no longer available on this server.",
1520 name);
1521 }
1522 }
1523}