]> jfr.im git - solanum.git/blame - src/channel.c
sasl: reformat the other messages consistently
[solanum.git] / src / 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{
674 return is_banned_list(chptr, &chptr->banlist, who, msptr, s, s2,
675 forward);
676}
677
212380e3
AC
678/* is_quieted()
679 *
680 * input - channel to check bans for, user to check bans against
681 * optional prebuilt buffers
682 * output - 1 if banned, else 0
683 * side effects -
684 */
685int
686is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
687 const char *s, const char *s2)
688{
a14de124
JT
689 return is_banned_list(chptr, &chptr->quietlist, who, msptr, s, s2,
690 NULL);
212380e3
AC
691}
692
693/* can_join()
694 *
695 * input - client to check, channel to check for, key
765d839d 696 * output - reason for not being able to join, else 0, channel name to forward to
212380e3 697 * side effects -
a63f7af7 698 * caveats - this function should only be called on a local user.
212380e3
AC
699 */
700int
fe74401b 701can_join(struct Client *source_p, struct Channel *chptr, const char *key, const char **forward)
212380e3 702{
330fc5c1
AC
703 rb_dlink_node *invite = NULL;
704 rb_dlink_node *ptr;
212380e3
AC
705 struct Ban *invex = NULL;
706 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
707 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
708 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
709 int use_althost = 0;
1ebf4db4 710 int i = 0;
212380e3
AC
711 hook_data_channel moduledata;
712
713 s_assert(source_p->localClient != NULL);
714
8bb19bd7
AC
715 moduledata.client = source_p;
716 moduledata.chptr = chptr;
717 moduledata.approved = 0;
718
b2f0da88
AC
719 rb_sprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
720 rb_sprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
212380e3
AC
721 if(source_p->localClient->mangledhost != NULL)
722 {
723 /* if host mangling mode enabled, also check their real host */
724 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
725 {
b2f0da88 726 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
212380e3
AC
727 use_althost = 1;
728 }
729 /* if host mangling mode not enabled and no other spoof,
730 * also check the mangled form of their host */
731 else if (!IsDynSpoof(source_p))
732 {
b2f0da88 733 rb_sprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
212380e3
AC
734 use_althost = 1;
735 }
736 }
737
765d839d 738 if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == CHFL_BAN)
8bb19bd7
AC
739 {
740 moduledata.approved = ERR_BANNEDFROMCHAN;
741 goto finish_join_check;
742 }
212380e3 743
765d839d
EM
744 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
745 {
746 moduledata.approved = ERR_BADCHANNELKEY;
747 goto finish_join_check;
748 }
749
750 /* All checks from this point on will forward... */
751 if(forward)
752 *forward = chptr->mode.forward;
753
212380e3
AC
754 if(chptr->mode.mode & MODE_INVITEONLY)
755 {
5cefa1d6 756 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
212380e3 757 {
1ebf4db4 758 if(invite->data == chptr)
212380e3
AC
759 break;
760 }
1ebf4db4 761 if(invite == NULL)
212380e3
AC
762 {
763 if(!ConfigChannel.use_invex)
8bb19bd7 764 moduledata.approved = ERR_INVITEONLYCHAN;
5cefa1d6 765 RB_DLINK_FOREACH(ptr, chptr->invexlist.head)
212380e3
AC
766 {
767 invex = ptr->data;
768 if(match(invex->banstr, src_host)
769 || match(invex->banstr, src_iphost)
770 || match_cidr(invex->banstr, src_iphost)
771 || match_extban(invex->banstr, source_p, chptr, CHFL_INVEX)
772 || (use_althost && match(invex->banstr, src_althost)))
773 break;
774 }
775 if(ptr == NULL)
8bb19bd7 776 moduledata.approved = ERR_INVITEONLYCHAN;
212380e3
AC
777 }
778 }
779
212380e3 780 if(chptr->mode.limit &&
330fc5c1 781 rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
1ebf4db4 782 i = ERR_CHANNELISFULL;
212380e3 783 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
1ebf4db4 784 i = ERR_NEEDREGGEDNICK;
212380e3 785 /* join throttling stuff --nenolod */
1ebf4db4 786 else if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
212380e3 787 {
55abcbb2 788 if ((rb_current_time() - chptr->join_delta <=
212380e3
AC
789 chptr->mode.join_time) && (chptr->join_count >=
790 chptr->mode.join_num))
1ebf4db4
JT
791 i = ERR_THROTTLE;
792 }
793
794 /* allow /invite to override +l/+r/+j also -- jilles */
795 if (i != 0 && invite == NULL)
796 {
5cefa1d6 797 RB_DLINK_FOREACH(invite, source_p->user->invited.head)
1ebf4db4
JT
798 {
799 if(invite->data == chptr)
800 break;
801 }
802 if (invite == NULL)
8bb19bd7 803 moduledata.approved = i;
212380e3
AC
804 }
805
8bb19bd7 806finish_join_check:
212380e3
AC
807 call_hook(h_can_join, &moduledata);
808
809 return moduledata.approved;
810}
811
812/* can_send()
813 *
814 * input - user to check in channel, membership pointer
815 * output - whether can explicitly send or not, else CAN_SEND_NONOP
816 * side effects -
817 */
818int
819can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
820{
0aa36c5f
AC
821 hook_data_channel_approval moduledata;
822
823 moduledata.approved = CAN_SEND_NONOP;
824
212380e3
AC
825 if(IsServer(source_p) || IsService(source_p))
826 return CAN_SEND_OPV;
827
828 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
829 !IsOper(source_p) && !IsExemptResv(source_p))
0aa36c5f 830 moduledata.approved = CAN_SEND_NO;
212380e3
AC
831
832 if(msptr == NULL)
833 {
834 msptr = find_channel_membership(chptr, source_p);
835
836 if(msptr == NULL)
837 {
838 /* if its +m or +n and theyre not in the channel,
839 * they cant send. we dont check bans here because
840 * theres no possibility of caching them --fl
841 */
842 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED)
0aa36c5f 843 moduledata.approved = CAN_SEND_NO;
212380e3 844 else
0aa36c5f 845 moduledata.approved = CAN_SEND_NONOP;
b697041e
AC
846
847 return moduledata.approved;
212380e3
AC
848 }
849 }
850
212380e3 851 if(chptr->mode.mode & MODE_MODERATED)
0aa36c5f 852 moduledata.approved = CAN_SEND_NO;
212380e3
AC
853
854 if(MyClient(source_p))
855 {
856 /* cached can_send */
857 if(msptr->bants == chptr->bants)
858 {
859 if(can_send_banned(msptr))
0aa36c5f 860 moduledata.approved = CAN_SEND_NO;
212380e3 861 }
765d839d 862 else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == CHFL_BAN
212380e3 863 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
0aa36c5f 864 moduledata.approved = CAN_SEND_NO;
212380e3
AC
865 }
866
e06988c6
AC
867 if(is_chanop_voiced(msptr))
868 moduledata.approved = CAN_SEND_OPV;
869
f4b52a0a
EM
870 moduledata.client = source_p;
871 moduledata.chptr = msptr->chptr;
872 moduledata.msptr = msptr;
873 moduledata.target = NULL;
874
0aa36c5f
AC
875 call_hook(h_can_send, &moduledata);
876
877 return moduledata.approved;
212380e3
AC
878}
879
15484f02
BG
880/*
881 * flood_attack_channel
882 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
883 * says NOTICE must not auto reply
55abcbb2 884 * - pointer to source Client
15484f02
BG
885 * - pointer to target channel
886 * output - 1 if target is under flood attack
887 * side effects - check for flood attack on target chptr
888 */
889int
890flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
891{
892 int delta;
893
894 if(GlobalSetOptions.floodcount && MyClient(source_p))
895 {
896 if((chptr->first_received_message_time + 1) < rb_current_time())
897 {
898 delta = rb_current_time() - chptr->first_received_message_time;
899 chptr->received_number_of_privmsgs -= delta;
900 chptr->first_received_message_time = rb_current_time();
901 if(chptr->received_number_of_privmsgs <= 0)
902 {
903 chptr->received_number_of_privmsgs = 0;
904 chptr->flood_noticed = 0;
905 }
906 }
907
908 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
909 || chptr->flood_noticed)
910 {
911 if(chptr->flood_noticed == 0)
912 {
913 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
914 "Possible Flooder %s[%s@%s] on %s target: %s",
915 source_p->name, source_p->username,
916 source_p->orighost,
917 source_p->servptr->name, chptr->chname);
918 chptr->flood_noticed = 1;
919
920 /* Add a bit of penalty */
921 chptr->received_number_of_privmsgs += 2;
922 }
923 if(MyClient(source_p) && (p_or_n != 1))
924 sendto_one(source_p,
925 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
926 me.name, source_p->name, chptr->chname);
927 return 1;
928 }
929 else
930 chptr->received_number_of_privmsgs++;
931 }
932
933 return 0;
934}
935
212380e3
AC
936/* find_bannickchange_channel()
937 * Input: client to check
938 * Output: channel preventing nick change
939 */
940struct Channel *
941find_bannickchange_channel(struct Client *client_p)
942{
943 struct Channel *chptr;
944 struct membership *msptr;
330fc5c1 945 rb_dlink_node *ptr;
212380e3
AC
946 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
947 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
948
949 if (!MyClient(client_p))
950 return NULL;
951
b2f0da88
AC
952 rb_sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
953 rb_sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
212380e3 954
5cefa1d6 955 RB_DLINK_FOREACH(ptr, client_p->user->channel.head)
212380e3
AC
956 {
957 msptr = ptr->data;
958 chptr = msptr->chptr;
959 if (is_chanop_voiced(msptr))
960 continue;
961 /* cached can_send */
962 if (msptr->bants == chptr->bants)
963 {
964 if (can_send_banned(msptr))
965 return chptr;
966 }
765d839d 967 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == CHFL_BAN
212380e3
AC
968 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
969 return chptr;
970 }
971 return NULL;
972}
973
974/* void check_spambot_warning(struct Client *source_p)
975 * Input: Client to check, channel name or NULL if this is a part.
976 * Output: none
977 * Side-effects: Updates the client's oper_warn_count_down, warns the
978 * IRC operators if necessary, and updates join_leave_countdown as
979 * needed.
980 */
981void
982check_spambot_warning(struct Client *source_p, const char *name)
983{
984 int t_delta;
985 int decrement_count;
986 if((GlobalSetOptions.spam_num &&
987 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
988 {
989 if(source_p->localClient->oper_warn_count_down > 0)
990 source_p->localClient->oper_warn_count_down--;
991 else
992 source_p->localClient->oper_warn_count_down = 0;
e0c1f4ec
JT
993 if(source_p->localClient->oper_warn_count_down == 0 &&
994 name != NULL)
212380e3
AC
995 {
996 /* Its already known as a possible spambot */
e0c1f4ec
JT
997 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
998 "User %s (%s@%s) trying to join %s is a possible spambot",
999 source_p->name,
1000 source_p->username, source_p->orighost, name);
212380e3
AC
1001 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
1002 }
1003 }
1004 else
1005 {
1006 if((t_delta =
e3354945 1007 (rb_current_time() - source_p->localClient->last_leave_time)) >
212380e3
AC
1008 JOIN_LEAVE_COUNT_EXPIRE_TIME)
1009 {
1010 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
981586df
JT
1011 if(name != NULL)
1012 ;
1013 else if(decrement_count > source_p->localClient->join_leave_count)
212380e3
AC
1014 source_p->localClient->join_leave_count = 0;
1015 else
1016 source_p->localClient->join_leave_count -= decrement_count;
1017 }
1018 else
1019 {
e3354945 1020 if((rb_current_time() -
212380e3
AC
1021 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
1022 {
1023 /* oh, its a possible spambot */
1024 source_p->localClient->join_leave_count++;
1025 }
1026 }
1027 if(name != NULL)
e3354945 1028 source_p->localClient->last_join_time = rb_current_time();
212380e3 1029 else
e3354945 1030 source_p->localClient->last_leave_time = rb_current_time();
212380e3
AC
1031 }
1032}
1033
1034/* check_splitmode()
1035 *
1036 * input -
1037 * output -
1038 * side effects - compares usercount and servercount against their split
1039 * values and adjusts splitmode accordingly
1040 */
1041void
1042check_splitmode(void *unused)
1043{
1044 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
1045 {
1046 /* not split, we're being asked to check now because someone
1047 * has left
1048 */
1049 if(!splitmode)
1050 {
1051 if(eob_count < split_servers || Count.total < split_users)
1052 {
1053 splitmode = 1;
1054 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1055 "Network split, activating splitmode");
c608a061 1056 check_splitmode_ev = rb_event_addish("check_splitmode", check_splitmode, NULL, 2);
212380e3
AC
1057 }
1058 }
1059 /* in splitmode, check whether its finished */
1060 else if(eob_count >= split_servers && Count.total >= split_users)
1061 {
1062 splitmode = 0;
1063
1064 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1065 "Network rejoined, deactivating splitmode");
1066
c608a061 1067 rb_event_delete(check_splitmode_ev);
6a309903 1068 check_splitmode_ev = NULL;
212380e3
AC
1069 }
1070 }
1071}
1072
1073
1074/* allocate_topic()
1075 *
1076 * input - channel to allocate topic for
1077 * output - 1 on success, else 0
1078 * side effects - channel gets a topic allocated
1079 */
1080static void
1081allocate_topic(struct Channel *chptr)
1082{
1083 void *ptr;
1084
1085 if(chptr == NULL)
1086 return;
1087
398b6a73 1088 ptr = rb_bh_alloc(topic_heap);
212380e3
AC
1089
1090 /* Basically we allocate one large block for the topic and
1091 * the topic info. We then split it up into two and shove it
55abcbb2 1092 * in the chptr
212380e3
AC
1093 */
1094 chptr->topic = ptr;
1095 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1096 *chptr->topic = '\0';
1097 *chptr->topic_info = '\0';
1098}
1099
1100/* free_topic()
1101 *
1102 * input - channel which has topic to free
1103 * output -
1104 * side effects - channels topic is free'd
1105 */
1106static void
1107free_topic(struct Channel *chptr)
1108{
1109 void *ptr;
1110
1111 if(chptr == NULL || chptr->topic == NULL)
1112 return;
1113
1114 /* This is safe for now - If you change allocate_topic you
1115 * MUST change this as well
1116 */
1117 ptr = chptr->topic;
398b6a73 1118 rb_bh_free(topic_heap, ptr);
212380e3
AC
1119 chptr->topic = NULL;
1120 chptr->topic_info = NULL;
1121}
1122
1123/* set_channel_topic()
1124 *
1125 * input - channel, topic to set, topic info and topic ts
1126 * output -
1127 * side effects - channels topic, topic info and TS are set.
1128 */
1129void
1130set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1131{
1132 if(strlen(topic) > 0)
1133 {
1134 if(chptr->topic == NULL)
1135 allocate_topic(chptr);
f427c8b0
VY
1136 rb_strlcpy(chptr->topic, topic, TOPICLEN + 1);
1137 rb_strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
212380e3
AC
1138 chptr->topic_time = topicts;
1139 }
1140 else
1141 {
1142 if(chptr->topic != NULL)
1143 free_topic(chptr);
1144 chptr->topic_time = 0;
1145 }
1146}
1147
3b8a6350 1148/* channel_modes()
212380e3
AC
1149 *
1150 * inputs - pointer to channel
1151 * - pointer to client
f1e35c19
JT
1152 * output - string with simple modes
1153 * side effects - result from previous calls overwritten
212380e3
AC
1154 *
1155 * Stolen from ShadowIRCd 4 --nenolod
1156 */
1157const char *
3b8a6350 1158channel_modes(struct Channel *chptr, struct Client *client_p)
212380e3
AC
1159{
1160 int i;
1161 char buf1[BUFSIZE];
1162 char buf2[BUFSIZE];
1163 static char final[BUFSIZE];
1164 char *mbuf = buf1;
1165 char *pbuf = buf2;
1166
1167 *mbuf++ = '+';
1168 *pbuf = '\0';
1169
efccc22c 1170 for (i = 0; i < 256; i++)
3b8a6350 1171 if(chptr->mode.mode & chmode_flags[i])
efccc22c 1172 *mbuf++ = i;
212380e3 1173
3b8a6350 1174 if(chptr->mode.limit)
212380e3
AC
1175 {
1176 *mbuf++ = 'l';
1177
f1e35c19 1178 if(!IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350 1179 pbuf += rb_sprintf(pbuf, " %d", chptr->mode.limit);
212380e3
AC
1180 }
1181
3b8a6350 1182 if(*chptr->mode.key)
212380e3
AC
1183 {
1184 *mbuf++ = 'k';
1185
f1e35c19 1186 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350 1187 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.key);
212380e3
AC
1188 }
1189
3b8a6350 1190 if(chptr->mode.join_num)
212380e3
AC
1191 {
1192 *mbuf++ = 'j';
1193
f1e35c19 1194 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350
SB
1195 pbuf += rb_sprintf(pbuf, " %d:%d", chptr->mode.join_num,
1196 chptr->mode.join_time);
212380e3
AC
1197 }
1198
2da6f6eb
JT
1199 if(*chptr->mode.forward &&
1200 (ConfigChannel.use_forward || !IsClient(client_p)))
212380e3
AC
1201 {
1202 *mbuf++ = 'f';
1203
f1e35c19 1204 if(pbuf > buf2 || !IsClient(client_p) || IsMember(client_p, chptr))
3b8a6350 1205 pbuf += rb_sprintf(pbuf, " %s", chptr->mode.forward);
212380e3
AC
1206 }
1207
1208 *mbuf = '\0';
1209
f427c8b0 1210 rb_strlcpy(final, buf1, sizeof final);
1f9de103 1211 rb_strlcat(final, buf2, sizeof final);
212380e3
AC
1212 return final;
1213}
1214
212380e3
AC
1215/* void send_cap_mode_changes(struct Client *client_p,
1216 * struct Client *source_p,
1217 * struct Channel *chptr, int cap, int nocap)
1218 * Input: The client sending(client_p), the source client(source_p),
1219 * the channel to send mode changes for(chptr)
1220 * Output: None.
1221 * Side-effects: Sends the appropriate mode changes to capable servers.
1222 *
1223 * Reverted back to my original design, except that we now keep a count
1224 * of the number of servers which each combination as an optimisation, so
1225 * the capabs combinations which are not needed are not worked out. -A1kmm
346fba92
AC
1226 *
1227 * Removed most code here because we don't need to be compatible with ircd
1228 * 2.8.21+CSr and stuff. --nenolod
212380e3
AC
1229 */
1230void
1231send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1232 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1233{
1234 static char modebuf[BUFSIZE];
1235 static char parabuf[BUFSIZE];
1236 int i, mbl, pbl, nc, mc, preflen, len;
1237 char *pbuf;
1238 const char *arg;
346fba92 1239 int dir;
212380e3
AC
1240 int arglen;
1241
1242 /* Now send to servers... */
346fba92
AC
1243 mc = 0;
1244 nc = 0;
1245 pbl = 0;
1246 parabuf[0] = 0;
1247 pbuf = parabuf;
1248 dir = MODE_QUERY;
1249
1250 mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
1251 use_id(source_p), (long) chptr->channelts,
1252 chptr->chname);
1253
1254 /* loop the list of - modes we have */
1255 for (i = 0; i < mode_count; i++)
212380e3 1256 {
346fba92
AC
1257 /* if they dont support the cap we need, or they do support a cap they
1258 * cant have, then dont add it to the modebuf.. that way they wont see
1259 * the mode
1260 */
1261 if (mode_changes[i].letter == 0)
212380e3
AC
1262 continue;
1263
346fba92
AC
1264 if (!EmptyString(mode_changes[i].id))
1265 arg = mode_changes[i].id;
1266 else
1267 arg = mode_changes[i].arg;
212380e3 1268
346fba92 1269 if(arg)
212380e3 1270 {
346fba92 1271 arglen = strlen(arg);
212380e3 1272
346fba92
AC
1273 /* dont even think about it! --fl */
1274 if(arglen > MODEBUFLEN - 5)
1275 continue;
1276 }
212380e3 1277
346fba92
AC
1278 /* if we're creeping past the buf size, we need to send it and make
1279 * another line for the other modes
1280 * XXX - this could give away server topology with uids being
1281 * different lengths, but not much we can do, except possibly break
1282 * them as if they were the longest of the nick or uid at all times,
1283 * which even then won't work as we don't always know the uid -A1kmm.
1284 */
1285 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1286 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1287 {
1288 if(nc != 0)
51452a37 1289 sendto_server(client_p, chptr, NOCAPS, NOCAPS,
346fba92
AC
1290 "%s %s", modebuf, parabuf);
1291 nc = 0;
1292 mc = 0;
1293
1294 mbl = preflen;
1295 pbl = 0;
1296 pbuf = parabuf;
1297 parabuf[0] = 0;
1298 dir = MODE_QUERY;
1299 }
212380e3 1300
346fba92
AC
1301 if(dir != mode_changes[i].dir)
1302 {
1303 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1304 dir = mode_changes[i].dir;
1305 }
212380e3 1306
346fba92
AC
1307 modebuf[mbl++] = mode_changes[i].letter;
1308 modebuf[mbl] = 0;
1309 nc++;
212380e3 1310
346fba92
AC
1311 if(arg != NULL)
1312 {
1313 len = rb_sprintf(pbuf, "%s ", arg);
1314 pbuf += len;
1315 pbl += len;
1316 mc++;
212380e3 1317 }
346fba92 1318 }
212380e3 1319
346fba92
AC
1320 if(pbl && parabuf[pbl - 1] == ' ')
1321 parabuf[pbl - 1] = 0;
212380e3 1322
346fba92 1323 if(nc != 0)
51452a37 1324 sendto_server(client_p, chptr, NOCAPS, NOCAPS, "%s %s", modebuf, parabuf);
212380e3 1325}
dca9e552 1326
346fba92 1327void
dca9e552
JT
1328resv_chan_forcepart(const char *name, const char *reason, int temp_time)
1329{
1330 rb_dlink_node *ptr;
1331 rb_dlink_node *next_ptr;
1332 struct Channel *chptr;
1333 struct membership *msptr;
1334 struct Client *target_p;
1335
1336 if(!ConfigChannel.resv_forcepart)
1337 return;
1338
1339 /* for each user on our server in the channel list
1340 * send them a PART, and notify opers.
1341 */
1342 chptr = find_channel(name);
1343 if(chptr != NULL)
1344 {
1345 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
1346 {
1347 msptr = ptr->data;
1348 target_p = msptr->client_p;
1349
1350 if(IsExemptResv(target_p))
1351 continue;
1352
1353 sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
1354 ":%s PART %s", target_p->id, chptr->chname);
1355
1356 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
1357 target_p->name, target_p->username,
1358 target_p->host, chptr->chname, target_p->name);
1359
1360 remove_user_from_channel(msptr);
1361
1362 /* notify opers & user they were removed from the channel */
1363 sendto_realops_snomask(SNO_GENERAL, L_ALL,
1364 "Forced PART for %s!%s@%s from %s (%s)",
55abcbb2 1365 target_p->name, target_p->username,
dca9e552
JT
1366 target_p->host, name, reason);
1367
1368 if(temp_time > 0)
1369 sendto_one_notice(target_p, ":*** Channel %s is temporarily unavailable on this server.",
1370 name);
1371 else
1372 sendto_one_notice(target_p, ":*** Channel %s is no longer available on this server.",
1373 name);
1374 }
1375 }
1376}