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