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