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