Restore stats_spy hook that was removed in commit 401f2454671ca233e35b0e6e4f3fa4c43cd...
[seven-1.x.git] / src / channel.c
blob5948585fa2d5251e5df2c3a0364da2ee037f732c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * channel.c: Controls channels.
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
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.
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.
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
25 #include "stdinc.h"
26 #include "tools.h"
27 #include "channel.h"
28 #include "client.h"
29 #include "common.h"
30 #include "hash.h"
31 #include "hook.h"
32 #include "irc_string.h"
33 #include "sprintf_irc.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "s_serv.h" /* captab */
37 #include "s_user.h"
38 #include "send.h"
39 #include "whowas.h"
40 #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
41 #include "s_newconf.h"
42 #include "event.h"
43 #include "memory.h"
44 #include "balloc.h"
45 #include "s_log.h"
47 extern dlink_list global_channel_list;
49 extern struct config_channel_entry ConfigChannel;
50 extern BlockHeap *channel_heap;
51 extern BlockHeap *ban_heap;
52 extern BlockHeap *topic_heap;
53 extern BlockHeap *member_heap;
55 static int channel_capabs[] = { CAP_EX, CAP_IE,
56 CAP_SERVICE,
57 CAP_TS6
60 #define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
61 #define NCHCAP_COMBOS (1 << NCHCAPS)
63 static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
65 static void free_topic(struct Channel *chptr);
67 static int h_can_join;
69 /* init_channels()
71 * input -
72 * output -
73 * side effects - initialises the various blockheaps
75 void
76 init_channels(void)
78 channel_heap = BlockHeapCreate(sizeof(struct Channel), CHANNEL_HEAP_SIZE);
79 ban_heap = BlockHeapCreate(sizeof(struct Ban), BAN_HEAP_SIZE);
80 topic_heap = BlockHeapCreate(TOPICLEN + 1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE);
81 member_heap = BlockHeapCreate(sizeof(struct membership), MEMBER_HEAP_SIZE);
83 h_can_join = register_hook("can_join");
87 * allocate_channel - Allocates a channel
89 struct Channel *
90 allocate_channel(const char *chname)
92 struct Channel *chptr;
93 chptr = BlockHeapAlloc(channel_heap);
94 DupNString(chptr->chname, chname, CHANNELLEN);
95 return (chptr);
98 void
99 free_channel(struct Channel *chptr)
101 MyFree(chptr->chname);
102 BlockHeapFree(channel_heap, chptr);
105 struct Ban *
106 allocate_ban(const char *banstr, const char *who)
108 struct Ban *bptr;
109 bptr = BlockHeapAlloc(ban_heap);
110 DupNString(bptr->banstr, banstr, BANLEN);
111 DupNString(bptr->who, who, BANLEN);
113 return (bptr);
116 void
117 free_ban(struct Ban *bptr)
119 MyFree(bptr->banstr);
120 MyFree(bptr->who);
121 BlockHeapFree(ban_heap, bptr);
125 /* find_channel_membership()
127 * input - channel to find them in, client to find
128 * output - membership of client in channel, else NULL
129 * side effects -
131 struct membership *
132 find_channel_membership(struct Channel *chptr, struct Client *client_p)
134 struct membership *msptr;
135 dlink_node *ptr;
137 if(!IsClient(client_p))
138 return NULL;
140 DLINK_FOREACH(ptr, client_p->user->channel.head)
142 msptr = ptr->data;
143 if(msptr->chptr == chptr)
144 return msptr;
147 return NULL;
150 /* find_channel_status()
152 * input - membership to get status for, whether we can combine flags
153 * output - flags of user on channel
154 * side effects -
156 const char *
157 find_channel_status(struct membership *msptr, int combine)
159 static char buffer[3];
160 char *p;
162 p = buffer;
164 if(is_real_chanop(msptr))
166 if(!combine)
167 return "@";
168 *p++ = '@';
171 if(is_voiced(msptr))
172 *p++ = '+';
174 *p = '\0';
175 return buffer;
178 /* add_user_to_channel()
180 * input - channel to add client to, client to add, channel flags
181 * output -
182 * side effects - user is added to channel
184 void
185 add_user_to_channel(struct Channel *chptr, struct Client *client_p, int flags)
187 struct membership *msptr;
189 s_assert(client_p->user != NULL);
190 if(client_p->user == NULL)
191 return;
193 msptr = BlockHeapAlloc(member_heap);
195 msptr->chptr = chptr;
196 msptr->client_p = client_p;
197 msptr->flags = flags;
199 dlinkAdd(msptr, &msptr->usernode, &client_p->user->channel);
200 dlinkAdd(msptr, &msptr->channode, &chptr->members);
202 if(MyClient(client_p))
203 dlinkAdd(msptr, &msptr->locchannode, &chptr->locmembers);
206 /* remove_user_from_channel()
208 * input - membership pointer to remove from channel
209 * output -
210 * side effects - membership (thus user) is removed from channel
212 void
213 remove_user_from_channel(struct membership *msptr)
215 struct Client *client_p;
216 struct Channel *chptr;
217 s_assert(msptr != NULL);
218 if(msptr == NULL)
219 return;
221 client_p = msptr->client_p;
222 chptr = msptr->chptr;
224 dlinkDelete(&msptr->usernode, &client_p->user->channel);
225 dlinkDelete(&msptr->channode, &chptr->members);
227 if(client_p->servptr == &me)
228 dlinkDelete(&msptr->locchannode, &chptr->locmembers);
230 chptr->users_last = CurrentTime;
232 if(!(chptr->mode.mode & MODE_PERMANENT) && dlink_list_length(&chptr->members) <= 0)
233 destroy_channel(chptr);
235 BlockHeapFree(member_heap, msptr);
237 return;
240 /* remove_user_from_channels()
242 * input - user to remove from all channels
243 * output -
244 * side effects - user is removed from all channels
246 void
247 remove_user_from_channels(struct Client *client_p)
249 struct Channel *chptr;
250 struct membership *msptr;
251 dlink_node *ptr;
252 dlink_node *next_ptr;
254 if(client_p == NULL)
255 return;
257 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->user->channel.head)
259 msptr = ptr->data;
260 chptr = msptr->chptr;
262 dlinkDelete(&msptr->channode, &chptr->members);
264 if(client_p->servptr == &me)
265 dlinkDelete(&msptr->locchannode, &chptr->locmembers);
267 chptr->users_last = CurrentTime;
269 if(!(chptr->mode.mode & MODE_PERMANENT) && dlink_list_length(&chptr->members) <= 0)
270 destroy_channel(chptr);
272 BlockHeapFree(member_heap, msptr);
275 client_p->user->channel.head = client_p->user->channel.tail = NULL;
276 client_p->user->channel.length = 0;
279 /* invalidate_bancache_user()
281 * input - user to invalidate ban cache for
282 * output -
283 * side effects - ban cache is invalidated for all memberships of that user
284 * to be used after a nick change
286 void
287 invalidate_bancache_user(struct Client *client_p)
289 struct membership *msptr;
290 dlink_node *ptr;
292 if(client_p == NULL)
293 return;
295 DLINK_FOREACH(ptr, client_p->user->channel.head)
297 msptr = ptr->data;
298 msptr->bants = 0;
299 msptr->flags &= ~CHFL_BANNED;
303 /* check_channel_name()
305 * input - channel name
306 * output - 1 if valid channel name, else 0
307 * side effects -
310 check_channel_name(const char *name)
312 s_assert(name != NULL);
313 if(name == NULL)
314 return 0;
316 for (; *name; ++name)
318 if(!IsChanChar(*name))
319 return 0;
322 return 1;
325 /* free_channel_list()
327 * input - dlink list to free
328 * output -
329 * side effects - list of b/e/I modes is cleared
331 void
332 free_channel_list(dlink_list * list)
334 dlink_node *ptr;
335 dlink_node *next_ptr;
336 struct Ban *actualBan;
338 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
340 actualBan = ptr->data;
341 free_ban(actualBan);
344 list->head = list->tail = NULL;
345 list->length = 0;
348 /* destroy_channel()
350 * input - channel to destroy
351 * output -
352 * side effects - channel is obliterated
354 void
355 destroy_channel(struct Channel *chptr)
357 dlink_node *ptr, *next_ptr;
359 DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
361 del_invite(chptr, ptr->data);
364 /* free all bans/exceptions/denies */
365 free_channel_list(&chptr->banlist);
366 free_channel_list(&chptr->exceptlist);
367 free_channel_list(&chptr->invexlist);
369 /* Free the topic */
370 free_topic(chptr);
372 dlinkDelete(&chptr->node, &global_channel_list);
373 del_from_channel_hash(chptr->chname, chptr);
374 free_channel(chptr);
377 /* channel_pub_or_secret()
379 * input - channel
380 * output - "=" if public, "@" if secret, else "*"
381 * side effects -
383 static const char *
384 channel_pub_or_secret(struct Channel *chptr)
386 if(PubChannel(chptr))
387 return ("=");
388 else if(SecretChannel(chptr))
389 return ("@");
390 return ("*");
393 /* channel_member_names()
395 * input - channel to list, client to list to, show endofnames
396 * output -
397 * side effects - client is given list of users on channel
399 void
400 channel_member_names(struct Channel *chptr, struct Client *client_p, int show_eon)
402 struct membership *msptr;
403 struct Client *target_p;
404 dlink_node *ptr;
405 char lbuf[BUFSIZE];
406 char *t;
407 int mlen;
408 int tlen;
409 int cur_len;
410 int is_member;
411 int stack = IsCapable(client_p, CLICAP_MULTI_PREFIX);
413 if(ShowChannel(client_p, chptr))
415 is_member = IsMember(client_p, chptr);
417 cur_len = mlen = ircsprintf(lbuf, form_str(RPL_NAMREPLY),
418 me.name, client_p->name,
419 channel_pub_or_secret(chptr), chptr->chname);
421 t = lbuf + cur_len;
423 DLINK_FOREACH(ptr, chptr->members.head)
425 msptr = ptr->data;
426 target_p = msptr->client_p;
428 if(IsInvisible(target_p) && !is_member)
429 continue;
431 /* space, possible "@+" prefix */
432 if(cur_len + strlen(target_p->name) + 3 >= BUFSIZE - 3)
434 *(t - 1) = '\0';
435 sendto_one(client_p, "%s", lbuf);
436 cur_len = mlen;
437 t = lbuf + mlen;
440 tlen = ircsprintf(t, "%s%s ", find_channel_status(msptr, stack),
441 target_p->name);
443 cur_len += tlen;
444 t += tlen;
447 /* The old behaviour here was to always output our buffer,
448 * even if there are no clients we can show. This happens
449 * when a client does "NAMES" with no parameters, and all
450 * the clients on a -sp channel are +i. I dont see a good
451 * reason for keeping that behaviour, as it just wastes
452 * bandwidth. --anfl
454 if(cur_len != mlen)
456 *(t - 1) = '\0';
457 sendto_one(client_p, "%s", lbuf);
461 if(show_eon)
462 sendto_one(client_p, form_str(RPL_ENDOFNAMES),
463 me.name, client_p->name, chptr->chname);
466 /* del_invite()
468 * input - channel to remove invite from, client to remove
469 * output -
470 * side effects - user is removed from invite list, if exists
472 void
473 del_invite(struct Channel *chptr, struct Client *who)
475 dlinkFindDestroy(who, &chptr->invites);
476 dlinkFindDestroy(chptr, &who->user->invited);
479 /* is_banned()
481 * input - channel to check bans for, user to check bans against
482 * optional prebuilt buffers
483 * output - 1 if banned, else 0
484 * side effects -
487 is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
488 const char *s, const char *s2)
490 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
491 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
492 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
493 char *s3 = NULL;
494 dlink_node *ptr;
495 struct Ban *actualBan = NULL;
496 struct Ban *actualExcept = NULL;
498 if(!MyClient(who))
499 return 0;
501 /* if the buffers havent been built, do it here */
502 if(s == NULL)
504 ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
505 ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
507 s = src_host;
508 s2 = src_iphost;
510 if(who->localClient->mangledhost != NULL)
512 /* if host mangling mode enabled, also check their real host */
513 if(!strcmp(who->host, who->localClient->mangledhost))
515 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
516 s3 = src_althost;
518 /* if host mangling mode not enabled and no other spoof,
519 * also check the mangled form of their host */
520 else if (!IsDynSpoof(who))
522 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
523 s3 = src_althost;
527 DLINK_FOREACH(ptr, chptr->banlist.head)
529 actualBan = ptr->data;
530 if(match(actualBan->banstr, s) ||
531 match(actualBan->banstr, s2) ||
532 match_cidr(actualBan->banstr, s2) ||
533 match_extban(actualBan->banstr, who, chptr, CHFL_BAN) ||
534 (s3 != NULL && match(actualBan->banstr, s3)))
535 break;
536 else
537 actualBan = NULL;
540 if((actualBan != NULL) && ConfigChannel.use_except)
542 DLINK_FOREACH(ptr, chptr->exceptlist.head)
544 actualExcept = ptr->data;
546 /* theyre exempted.. */
547 if(match(actualExcept->banstr, s) ||
548 match(actualExcept->banstr, s2) ||
549 match_cidr(actualExcept->banstr, s2) ||
550 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
551 (s3 != NULL && match(actualBan->banstr, s3)))
553 /* cache the fact theyre not banned */
554 if(msptr != NULL)
556 msptr->bants = chptr->bants;
557 msptr->flags &= ~CHFL_BANNED;
560 return CHFL_EXCEPTION;
565 /* cache the banned/not banned status */
566 if(msptr != NULL)
568 msptr->bants = chptr->bants;
570 if(actualBan != NULL)
572 msptr->flags |= CHFL_BANNED;
573 return CHFL_BAN;
575 else
577 msptr->flags &= ~CHFL_BANNED;
578 return 0;
582 return ((actualBan ? CHFL_BAN : 0));
585 /* is_quieted()
587 * input - channel to check bans for, user to check bans against
588 * optional prebuilt buffers
589 * output - 1 if banned, else 0
590 * side effects -
593 is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
594 const char *s, const char *s2)
596 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
597 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
598 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
599 char *s3 = NULL;
600 dlink_node *ptr;
601 struct Ban *actualBan = NULL;
602 struct Ban *actualExcept = NULL;
604 if(!MyClient(who))
605 return 0;
607 /* if the buffers havent been built, do it here */
608 if(s == NULL)
610 ircsprintf(src_host, "%s!%s@%s", who->name, who->username, who->host);
611 ircsprintf(src_iphost, "%s!%s@%s", who->name, who->username, who->sockhost);
613 s = src_host;
614 s2 = src_iphost;
616 if(who->localClient->mangledhost != NULL)
618 /* if host mangling mode enabled, also check their real host */
619 if(!strcmp(who->host, who->localClient->mangledhost))
621 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->orighost);
622 s3 = src_althost;
624 /* if host mangling mode not enabled and no other spoof,
625 * also check the mangled form of their host */
626 else if (!IsDynSpoof(who))
628 ircsprintf(src_althost, "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
629 s3 = src_althost;
633 DLINK_FOREACH(ptr, chptr->quietlist.head)
635 actualBan = ptr->data;
636 if(match(actualBan->banstr, s) ||
637 match(actualBan->banstr, s2) ||
638 match_cidr(actualBan->banstr, s2) ||
639 match_extban(actualBan->banstr, who, chptr, CHFL_QUIET) ||
640 (s3 != NULL && match(actualBan->banstr, s3)))
641 break;
642 else
643 actualBan = NULL;
646 if((actualBan != NULL) && ConfigChannel.use_except)
648 DLINK_FOREACH(ptr, chptr->exceptlist.head)
650 actualExcept = ptr->data;
652 /* theyre exempted.. */
653 if(match(actualExcept->banstr, s) ||
654 match(actualExcept->banstr, s2) ||
655 match_cidr(actualExcept->banstr, s2) ||
656 match_extban(actualExcept->banstr, who, chptr, CHFL_EXCEPTION) ||
657 (s3 != NULL && match(actualBan->banstr, s3)))
659 /* cache the fact theyre not banned */
660 if(msptr != NULL)
662 msptr->bants = chptr->bants;
663 msptr->flags &= ~CHFL_BANNED;
666 return CHFL_EXCEPTION;
671 /* cache the banned/not banned status */
672 if(msptr != NULL)
674 msptr->bants = chptr->bants;
676 if(actualBan != NULL)
678 msptr->flags |= CHFL_BANNED;
679 return CHFL_BAN;
681 else
683 msptr->flags &= ~CHFL_BANNED;
684 return 0;
688 return ((actualBan ? CHFL_BAN : 0));
691 /* can_join()
693 * input - client to check, channel to check for, key
694 * output - reason for not being able to join, else 0
695 * side effects -
698 can_join(struct Client *source_p, struct Channel *chptr, char *key)
700 dlink_node *lp;
701 dlink_node *ptr;
702 struct Ban *invex = NULL;
703 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
704 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
705 char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
706 int use_althost = 0;
707 hook_data_channel moduledata;
709 s_assert(source_p->localClient != NULL);
711 if(IsOverride(source_p))
712 return 0;
714 ircsprintf(src_host, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
715 ircsprintf(src_iphost, "%s!%s@%s", source_p->name, source_p->username, source_p->sockhost);
716 if(source_p->localClient->mangledhost != NULL)
718 /* if host mangling mode enabled, also check their real host */
719 if(!strcmp(source_p->host, source_p->localClient->mangledhost))
721 ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->orighost);
722 use_althost = 1;
724 /* if host mangling mode not enabled and no other spoof,
725 * also check the mangled form of their host */
726 else if (!IsDynSpoof(source_p))
728 ircsprintf(src_althost, "%s!%s@%s", source_p->name, source_p->username, source_p->localClient->mangledhost);
729 use_althost = 1;
733 if((is_banned(chptr, source_p, NULL, src_host, src_iphost)) == CHFL_BAN)
734 return (ERR_BANNEDFROMCHAN);
736 if(chptr->mode.mode & MODE_INVITEONLY)
738 DLINK_FOREACH(lp, source_p->user->invited.head)
740 if(lp->data == chptr)
741 break;
743 if(lp == NULL)
745 if(!ConfigChannel.use_invex)
746 return (ERR_INVITEONLYCHAN);
747 DLINK_FOREACH(ptr, chptr->invexlist.head)
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;
757 if(ptr == NULL)
758 return (ERR_INVITEONLYCHAN);
762 if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
763 return (ERR_BADCHANNELKEY);
765 if(chptr->mode.limit &&
766 dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
767 return (ERR_CHANNELISFULL);
769 if(chptr->mode.mode & MODE_REGONLY && EmptyString(source_p->user->suser))
770 return ERR_NEEDREGGEDNICK;
772 /* join throttling stuff --nenolod */
773 if(chptr->mode.join_num > 0 && chptr->mode.join_time > 0)
775 if ((CurrentTime - chptr->join_delta <=
776 chptr->mode.join_time) && (chptr->join_count >=
777 chptr->mode.join_num))
778 return ERR_THROTTLE;
781 moduledata.client = source_p;
782 moduledata.chptr = chptr;
783 moduledata.approved = 0;
785 call_hook(h_can_join, &moduledata);
787 return moduledata.approved;
790 /* can_send()
792 * input - user to check in channel, membership pointer
793 * output - whether can explicitly send or not, else CAN_SEND_NONOP
794 * side effects -
797 can_send(struct Channel *chptr, struct Client *source_p, struct membership *msptr)
799 if(IsServer(source_p) || IsService(source_p))
800 return CAN_SEND_OPV;
802 if(MyClient(source_p) && hash_find_resv(chptr->chname) &&
803 !IsOperStaffer(source_p) && !IsExemptResv(source_p))
804 return CAN_SEND_NO;
806 if(msptr == NULL)
808 msptr = find_channel_membership(chptr, source_p);
810 if(msptr == NULL)
812 /* if its +m or +n and theyre not in the channel,
813 * they cant send. we dont check bans here because
814 * theres no possibility of caching them --fl
816 if(chptr->mode.mode & MODE_NOPRIVMSGS || chptr->mode.mode & MODE_MODERATED
817 || ((chptr->mode.mode & MODE_QUIETUNID) && !*source_p->user->suser))
818 return CAN_SEND_NO;
819 else
820 return CAN_SEND_NONOP;
824 if(is_chanop_voiced(msptr) || IsOverride(source_p))
825 return CAN_SEND_OPV;
827 if(chptr->mode.mode & MODE_MODERATED)
828 return CAN_SEND_NO;
830 if(MyClient(source_p))
832 /* cached can_send */
833 if(msptr->bants == chptr->bants)
835 if(can_send_banned(msptr))
836 return CAN_SEND_NO;
838 else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
839 || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
840 return CAN_SEND_NO;
843 return CAN_SEND_NONOP;
846 /* find_bannickchange_channel()
847 * Input: client to check
848 * Output: channel preventing nick change
850 struct Channel *
851 find_bannickchange_channel(struct Client *client_p)
853 struct Channel *chptr;
854 struct membership *msptr;
855 dlink_node *ptr;
856 char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
857 char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
859 if (!MyClient(client_p))
860 return NULL;
862 ircsprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
863 ircsprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
865 DLINK_FOREACH(ptr, client_p->user->channel.head)
867 msptr = ptr->data;
868 chptr = msptr->chptr;
869 if (is_chanop_voiced(msptr))
870 continue;
871 /* cached can_send */
872 if (msptr->bants == chptr->bants)
874 if (can_send_banned(msptr))
875 return chptr;
877 else if (is_banned(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN
878 || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
879 return chptr;
881 return NULL;
884 /* void check_spambot_warning(struct Client *source_p)
885 * Input: Client to check, channel name or NULL if this is a part.
886 * Output: none
887 * Side-effects: Updates the client's oper_warn_count_down, warns the
888 * IRC operators if necessary, and updates join_leave_countdown as
889 * needed.
891 void
892 check_spambot_warning(struct Client *source_p, const char *name)
894 int t_delta;
895 int decrement_count;
896 if((GlobalSetOptions.spam_num &&
897 (source_p->localClient->join_leave_count >= GlobalSetOptions.spam_num)))
899 if(source_p->localClient->oper_warn_count_down > 0)
900 source_p->localClient->oper_warn_count_down--;
901 else
902 source_p->localClient->oper_warn_count_down = 0;
903 if(source_p->localClient->oper_warn_count_down == 0)
905 /* Its already known as a possible spambot */
906 if(name != NULL)
907 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
908 "User %s (%s@%s) trying to join %s is a possible spambot",
909 source_p->name,
910 source_p->username, source_p->host, name);
911 else
912 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
913 "User %s (%s@%s) is a possible spambot",
914 source_p->name,
915 source_p->username, source_p->host);
916 source_p->localClient->oper_warn_count_down = OPER_SPAM_COUNTDOWN;
919 else
921 if((t_delta =
922 (CurrentTime - source_p->localClient->last_leave_time)) >
923 JOIN_LEAVE_COUNT_EXPIRE_TIME)
925 decrement_count = (t_delta / JOIN_LEAVE_COUNT_EXPIRE_TIME);
926 if(decrement_count > source_p->localClient->join_leave_count)
927 source_p->localClient->join_leave_count = 0;
928 else
929 source_p->localClient->join_leave_count -= decrement_count;
931 else
933 if((CurrentTime -
934 (source_p->localClient->last_join_time)) < GlobalSetOptions.spam_time)
936 /* oh, its a possible spambot */
937 source_p->localClient->join_leave_count++;
940 if(name != NULL)
941 source_p->localClient->last_join_time = CurrentTime;
942 else
943 source_p->localClient->last_leave_time = CurrentTime;
947 /* check_splitmode()
949 * input -
950 * output -
951 * side effects - compares usercount and servercount against their split
952 * values and adjusts splitmode accordingly
954 void
955 check_splitmode(void *unused)
957 if(splitchecking && (ConfigChannel.no_join_on_split || ConfigChannel.no_create_on_split))
959 /* not split, we're being asked to check now because someone
960 * has left
962 if(!splitmode)
964 if(eob_count < split_servers || Count.total < split_users)
966 splitmode = 1;
967 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
968 "Network split, activating splitmode");
969 eventAddIsh("check_splitmode", check_splitmode, NULL, 2);
972 /* in splitmode, check whether its finished */
973 else if(eob_count >= split_servers && Count.total >= split_users)
975 splitmode = 0;
977 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
978 "Network rejoined, deactivating splitmode");
980 eventDelete(check_splitmode, NULL);
986 /* allocate_topic()
988 * input - channel to allocate topic for
989 * output - 1 on success, else 0
990 * side effects - channel gets a topic allocated
992 static void
993 allocate_topic(struct Channel *chptr)
995 void *ptr;
997 if(chptr == NULL)
998 return;
1000 ptr = BlockHeapAlloc(topic_heap);
1002 /* Basically we allocate one large block for the topic and
1003 * the topic info. We then split it up into two and shove it
1004 * in the chptr
1006 chptr->topic = ptr;
1007 chptr->topic_info = (char *) ptr + TOPICLEN + 1;
1008 *chptr->topic = '\0';
1009 *chptr->topic_info = '\0';
1012 /* free_topic()
1014 * input - channel which has topic to free
1015 * output -
1016 * side effects - channels topic is free'd
1018 static void
1019 free_topic(struct Channel *chptr)
1021 void *ptr;
1023 if(chptr == NULL || chptr->topic == NULL)
1024 return;
1026 /* This is safe for now - If you change allocate_topic you
1027 * MUST change this as well
1029 ptr = chptr->topic;
1030 BlockHeapFree(topic_heap, ptr);
1031 chptr->topic = NULL;
1032 chptr->topic_info = NULL;
1035 /* set_channel_topic()
1037 * input - channel, topic to set, topic info and topic ts
1038 * output -
1039 * side effects - channels topic, topic info and TS are set.
1041 void
1042 set_channel_topic(struct Channel *chptr, const char *topic, const char *topic_info, time_t topicts)
1044 if(strlen(topic) > 0)
1046 if(chptr->topic == NULL)
1047 allocate_topic(chptr);
1048 strlcpy(chptr->topic, topic, TOPICLEN + 1);
1049 strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
1050 chptr->topic_time = topicts;
1052 else
1054 if(chptr->topic != NULL)
1055 free_topic(chptr);
1056 chptr->topic_time = 0;
1060 const struct mode_letter channel_flags[] =
1062 {MODE_INVITEONLY, 'i'},
1063 {MODE_MODERATED, 'm'},
1064 {MODE_NOPRIVMSGS, 'n'},
1065 {MODE_PRIVATE, 'p'},
1066 {MODE_SECRET, 's'},
1067 {MODE_TOPICLIMIT, 't'},
1068 {MODE_NOCOLOR, 'c'},
1069 {MODE_FREEINVITE, 'g'},
1070 {MODE_OPMODERATE, 'z'},
1071 {MODE_PERMANENT, 'P'},
1072 {MODE_FREETARGET, 'F'},
1073 {MODE_DISFORWARD, 'Q'},
1074 {MODE_REGONLY, 'r'},
1075 {MODE_QUIETUNID, 'R'},
1076 {0, '\0'}
1079 /* channel_modes()
1081 * inputs - pointer to channel
1082 * - pointer to client
1083 * output - NONE
1084 * side effects - write the "simple" list of channel modes for channel
1085 * chptr onto buffer mbuf with the parameters in pbuf.
1087 * Stolen from ShadowIRCd 4 --nenolod
1089 const char *
1090 channel_modes(struct Channel *chptr, struct Client *client_p)
1092 int i;
1093 char buf1[BUFSIZE];
1094 char buf2[BUFSIZE];
1095 static char final[BUFSIZE];
1096 char *mbuf = buf1;
1097 char *pbuf = buf2;
1099 *mbuf++ = '+';
1100 *pbuf = '\0';
1102 for (i = 0; channel_flags[i].mode; ++i)
1103 if(chptr->mode.mode & channel_flags[i].mode)
1104 *mbuf++ = channel_flags[i].letter;
1106 if(chptr->mode.limit)
1108 *mbuf++ = 'l';
1110 if(IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
1111 pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
1114 if(chptr->mode.banlimit)
1116 *mbuf++ = 'L';
1118 if(IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
1119 pbuf += ircsprintf(pbuf, "%d ", chptr->mode.banlimit);
1122 if(*chptr->mode.key)
1124 *mbuf++ = 'k';
1126 if(*pbuf || IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
1127 pbuf += ircsprintf(pbuf, "%s ", chptr->mode.key);
1130 if(chptr->mode.join_num)
1132 *mbuf++ = 'j';
1134 if(*pbuf || IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
1135 pbuf += ircsprintf(pbuf, "%d:%d ", chptr->mode.join_num,
1136 chptr->mode.join_time);
1139 if(*chptr->mode.forward)
1141 *mbuf++ = 'f';
1143 if(*pbuf || IsMember(client_p, chptr) || IsServer(client_p) || IsMe(client_p))
1144 pbuf += ircsprintf(pbuf, "%s ", chptr->mode.forward);
1147 *mbuf = '\0';
1149 ircsprintf(final, "%s %s", buf1, buf2);
1150 return final;
1153 /* Now lets do some stuff to keep track of what combinations of
1154 * servers exist...
1155 * Note that the number of combinations doubles each time you add
1156 * something to this list. Each one is only quick if no servers use that
1157 * combination, but if the numbers get too high here MODE will get too
1158 * slow. I suggest if you get more than 7 here, you consider getting rid
1159 * of some and merging or something. If it wasn't for irc+cs we would
1160 * probably not even need to bother about most of these, but unfortunately
1161 * we do. -A1kmm
1164 /* void init_chcap_usage_counts(void)
1166 * Inputs - none
1167 * Output - none
1168 * Side-effects - Initialises the usage counts to zero. Fills in the
1169 * chcap_yes and chcap_no combination tables.
1171 void
1172 init_chcap_usage_counts(void)
1174 unsigned long m, c, y, n;
1176 memset(chcap_combos, 0, sizeof(chcap_combos));
1178 /* For every possible combination */
1179 for (m = 0; m < NCHCAP_COMBOS; m++)
1181 /* Check each capab */
1182 for (c = y = n = 0; c < NCHCAPS; c++)
1184 if((m & (1 << c)) == 0)
1185 n |= channel_capabs[c];
1186 else
1187 y |= channel_capabs[c];
1189 chcap_combos[m].cap_yes = y;
1190 chcap_combos[m].cap_no = n;
1194 /* void set_chcap_usage_counts(struct Client *serv_p)
1195 * Input: serv_p; The client whose capabs to register.
1196 * Output: none
1197 * Side-effects: Increments the usage counts for the correct capab
1198 * combination.
1200 void
1201 set_chcap_usage_counts(struct Client *serv_p)
1203 int n;
1205 for (n = 0; n < NCHCAP_COMBOS; n++)
1207 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1208 NotCapable(serv_p, chcap_combos[n].cap_no))
1210 chcap_combos[n].count++;
1211 return;
1215 /* This should be impossible -A1kmm. */
1216 s_assert(0);
1219 /* void set_chcap_usage_counts(struct Client *serv_p)
1221 * Inputs - serv_p; The client whose capabs to register.
1222 * Output - none
1223 * Side-effects - Decrements the usage counts for the correct capab
1224 * combination.
1226 void
1227 unset_chcap_usage_counts(struct Client *serv_p)
1229 int n;
1231 for (n = 0; n < NCHCAP_COMBOS; n++)
1233 if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
1234 NotCapable(serv_p, chcap_combos[n].cap_no))
1236 /* Hopefully capabs can't change dynamically or anything... */
1237 s_assert(chcap_combos[n].count > 0);
1239 if(chcap_combos[n].count > 0)
1240 chcap_combos[n].count--;
1241 return;
1245 /* This should be impossible -A1kmm. */
1246 s_assert(0);
1249 /* void send_cap_mode_changes(struct Client *client_p,
1250 * struct Client *source_p,
1251 * struct Channel *chptr, int cap, int nocap)
1252 * Input: The client sending(client_p), the source client(source_p),
1253 * the channel to send mode changes for(chptr)
1254 * Output: None.
1255 * Side-effects: Sends the appropriate mode changes to capable servers.
1257 * Reverted back to my original design, except that we now keep a count
1258 * of the number of servers which each combination as an optimisation, so
1259 * the capabs combinations which are not needed are not worked out. -A1kmm
1261 void
1262 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1263 struct Channel *chptr, struct ChModeChange mode_changes[], int mode_count)
1265 static char modebuf[BUFSIZE];
1266 static char parabuf[BUFSIZE];
1267 int i, mbl, pbl, nc, mc, preflen, len;
1268 char *pbuf;
1269 const char *arg;
1270 int dir;
1271 int j;
1272 int cap;
1273 int nocap;
1274 int arglen;
1276 /* Now send to servers... */
1277 for (j = 0; j < NCHCAP_COMBOS; j++)
1279 if(chcap_combos[j].count == 0)
1280 continue;
1282 mc = 0;
1283 nc = 0;
1284 pbl = 0;
1285 parabuf[0] = 0;
1286 pbuf = parabuf;
1287 dir = MODE_QUERY;
1289 cap = chcap_combos[j].cap_yes;
1290 nocap = chcap_combos[j].cap_no;
1292 if(cap & CAP_TS6)
1293 mbl = preflen = ircsprintf(modebuf, ":%s TMODE %ld %s ",
1294 use_id(source_p), (long) chptr->channelts,
1295 chptr->chname);
1296 else
1297 mbl = preflen = ircsprintf(modebuf, ":%s MODE %s ",
1298 source_p->name, chptr->chname);
1300 /* loop the list of - modes we have */
1301 for (i = 0; i < mode_count; i++)
1303 /* if they dont support the cap we need, or they do support a cap they
1304 * cant have, then dont add it to the modebuf.. that way they wont see
1305 * the mode
1307 if((mode_changes[i].letter == 0) ||
1308 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1309 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1310 continue;
1312 if((cap & CAP_TS6) && !EmptyString(mode_changes[i].id))
1313 arg = mode_changes[i].id;
1314 else
1315 arg = mode_changes[i].arg;
1317 if(arg)
1319 arglen = strlen(arg);
1321 /* dont even think about it! --fl */
1322 if(arglen > MODEBUFLEN - 5)
1323 continue;
1326 /* if we're creeping past the buf size, we need to send it and make
1327 * another line for the other modes
1328 * XXX - this could give away server topology with uids being
1329 * different lengths, but not much we can do, except possibly break
1330 * them as if they were the longest of the nick or uid at all times,
1331 * which even then won't work as we don't always know the uid -A1kmm.
1333 if(arg && ((mc == MAXMODEPARAMSSERV) ||
1334 ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
1336 if(nc != 0)
1337 sendto_server(client_p, chptr, cap, nocap,
1338 "%s %s", modebuf, parabuf);
1339 nc = 0;
1340 mc = 0;
1342 mbl = preflen;
1343 pbl = 0;
1344 pbuf = parabuf;
1345 parabuf[0] = 0;
1346 dir = MODE_QUERY;
1349 if(dir != mode_changes[i].dir)
1351 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1352 dir = mode_changes[i].dir;
1355 modebuf[mbl++] = mode_changes[i].letter;
1356 modebuf[mbl] = 0;
1357 nc++;
1359 if(arg != NULL)
1361 len = ircsprintf(pbuf, "%s ", arg);
1362 pbuf += len;
1363 pbl += len;
1364 mc++;
1368 if(pbl && parabuf[pbl - 1] == ' ')
1369 parabuf[pbl - 1] = 0;
1371 if(nc != 0)
1372 sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);