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