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