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
32 #include "irc_string.h"
33 #include "sprintf_irc.h"
36 #include "s_serv.h" /* captab */
40 #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
41 #include "s_newconf.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
,
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
;
73 * side effects - initialises the various blockheaps
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
90 allocate_channel(const char *chname
)
92 struct Channel
*chptr
;
93 chptr
= BlockHeapAlloc(channel_heap
);
94 DupNString(chptr
->chname
, chname
, CHANNELLEN
);
99 free_channel(struct Channel
*chptr
)
101 MyFree(chptr
->chname
);
102 BlockHeapFree(channel_heap
, chptr
);
106 allocate_ban(const char *banstr
, const char *who
)
109 bptr
= BlockHeapAlloc(ban_heap
);
110 DupNString(bptr
->banstr
, banstr
, BANLEN
);
111 DupNString(bptr
->who
, who
, BANLEN
);
117 free_ban(struct Ban
*bptr
)
119 MyFree(bptr
->banstr
);
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
132 find_channel_membership(struct Channel
*chptr
, struct Client
*client_p
)
134 struct membership
*msptr
;
137 if(!IsClient(client_p
))
140 DLINK_FOREACH(ptr
, client_p
->user
->channel
.head
)
143 if(msptr
->chptr
== chptr
)
150 /* find_channel_status()
152 * input - membership to get status for, whether we can combine flags
153 * output - flags of user on channel
157 find_channel_status(struct membership
*msptr
, int combine
)
159 static char buffer
[3];
164 if(is_real_chanop(msptr
))
178 /* add_user_to_channel()
180 * input - channel to add client to, client to add, channel flags
182 * side effects - user is added to channel
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
)
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
210 * side effects - membership (thus user) is removed from channel
213 remove_user_from_channel(struct membership
*msptr
)
215 struct Client
*client_p
;
216 struct Channel
*chptr
;
217 s_assert(msptr
!= NULL
);
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
);
240 /* remove_user_from_channels()
242 * input - user to remove from all channels
244 * side effects - user is removed from all channels
247 remove_user_from_channels(struct Client
*client_p
)
249 struct Channel
*chptr
;
250 struct membership
*msptr
;
252 dlink_node
*next_ptr
;
257 DLINK_FOREACH_SAFE(ptr
, next_ptr
, client_p
->user
->channel
.head
)
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
283 * side effects - ban cache is invalidated for all memberships of that user
284 * to be used after a nick change
287 invalidate_bancache_user(struct Client
*client_p
)
289 struct membership
*msptr
;
295 DLINK_FOREACH(ptr
, client_p
->user
->channel
.head
)
299 msptr
->flags
&= ~CHFL_BANNED
;
303 /* check_channel_name()
305 * input - channel name
306 * output - 1 if valid channel name, else 0
310 check_channel_name(const char *name
)
312 s_assert(name
!= NULL
);
316 for (; *name
; ++name
)
318 if(!IsChanChar(*name
))
325 /* free_channel_list()
327 * input - dlink list to free
329 * side effects - list of b/e/I modes is cleared
332 free_channel_list(dlink_list
* list
)
335 dlink_node
*next_ptr
;
336 struct Ban
*actualBan
;
338 DLINK_FOREACH_SAFE(ptr
, next_ptr
, list
->head
)
340 actualBan
= ptr
->data
;
344 list
->head
= list
->tail
= NULL
;
350 * input - channel to destroy
352 * side effects - channel is obliterated
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
);
372 dlinkDelete(&chptr
->node
, &global_channel_list
);
373 del_from_channel_hash(chptr
->chname
, chptr
);
377 /* channel_pub_or_secret()
380 * output - "=" if public, "@" if secret, else "*"
384 channel_pub_or_secret(struct Channel
*chptr
)
386 if(PubChannel(chptr
))
388 else if(SecretChannel(chptr
))
393 /* channel_member_names()
395 * input - channel to list, client to list to, show endofnames
397 * side effects - client is given list of users on channel
400 channel_member_names(struct Channel
*chptr
, struct Client
*client_p
, int show_eon
)
402 struct membership
*msptr
;
403 struct Client
*target_p
;
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
);
423 DLINK_FOREACH(ptr
, chptr
->members
.head
)
426 target_p
= msptr
->client_p
;
428 if(IsInvisible(target_p
) && !is_member
)
431 /* space, possible "@+" prefix */
432 if(cur_len
+ strlen(target_p
->name
) + 3 >= BUFSIZE
- 3)
435 sendto_one(client_p
, "%s", lbuf
);
440 tlen
= ircsprintf(t
, "%s%s ", find_channel_status(msptr
, stack
),
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
457 sendto_one(client_p
, "%s", lbuf
);
462 sendto_one(client_p
, form_str(RPL_ENDOFNAMES
),
463 me
.name
, client_p
->name
, chptr
->chname
);
468 * input - channel to remove invite from, client to remove
470 * side effects - user is removed from invite list, if exists
473 del_invite(struct Channel
*chptr
, struct Client
*who
)
475 dlinkFindDestroy(who
, &chptr
->invites
);
476 dlinkFindDestroy(chptr
, &who
->user
->invited
);
481 * input - channel to check bans for, user to check bans against
482 * optional prebuilt buffers
483 * output - 1 if banned, else 0
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];
495 struct Ban
*actualBan
= NULL
;
496 struct Ban
*actualExcept
= NULL
;
501 /* if the buffers havent been built, do it here */
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
);
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
);
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
);
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
)))
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 */
556 msptr
->bants
= chptr
->bants
;
557 msptr
->flags
&= ~CHFL_BANNED
;
560 return CHFL_EXCEPTION
;
565 /* cache the banned/not banned status */
568 msptr
->bants
= chptr
->bants
;
570 if(actualBan
!= NULL
)
572 msptr
->flags
|= CHFL_BANNED
;
577 msptr
->flags
&= ~CHFL_BANNED
;
582 return ((actualBan
? CHFL_BAN
: 0));
587 * input - channel to check bans for, user to check bans against
588 * optional prebuilt buffers
589 * output - 1 if banned, else 0
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];
601 struct Ban
*actualBan
= NULL
;
602 struct Ban
*actualExcept
= NULL
;
607 /* if the buffers havent been built, do it here */
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
);
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
);
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
);
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
)))
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 */
662 msptr
->bants
= chptr
->bants
;
663 msptr
->flags
&= ~CHFL_BANNED
;
666 return CHFL_EXCEPTION
;
671 /* cache the banned/not banned status */
674 msptr
->bants
= chptr
->bants
;
676 if(actualBan
!= NULL
)
678 msptr
->flags
|= CHFL_BANNED
;
683 msptr
->flags
&= ~CHFL_BANNED
;
688 return ((actualBan
? CHFL_BAN
: 0));
693 * input - client to check, channel to check for, key
694 * output - reason for not being able to join, else 0
698 can_join(struct Client
*source_p
, struct Channel
*chptr
, char *key
)
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];
707 hook_data_channel moduledata
;
709 s_assert(source_p
->localClient
!= NULL
);
711 if(IsOverride(source_p
))
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
);
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
);
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
)
745 if(!ConfigChannel
.use_invex
)
746 return (ERR_INVITEONLYCHAN
);
747 DLINK_FOREACH(ptr
, chptr
->invexlist
.head
)
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
)))
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
))
781 moduledata
.client
= source_p
;
782 moduledata
.chptr
= chptr
;
783 moduledata
.approved
= 0;
785 call_hook(h_can_join
, &moduledata
);
787 return moduledata
.approved
;
792 * input - user to check in channel, membership pointer
793 * output - whether can explicitly send or not, else CAN_SEND_NONOP
797 can_send(struct Channel
*chptr
, struct Client
*source_p
, struct membership
*msptr
)
799 if(IsServer(source_p
) || IsService(source_p
))
802 if(MyClient(source_p
) && hash_find_resv(chptr
->chname
) &&
803 !IsOperStaffer(source_p
) && !IsExemptResv(source_p
))
808 msptr
= find_channel_membership(chptr
, source_p
);
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
))
820 return CAN_SEND_NONOP
;
824 if(is_chanop_voiced(msptr
) || IsOverride(source_p
))
827 if(chptr
->mode
.mode
& MODE_MODERATED
)
830 if(MyClient(source_p
))
832 /* cached can_send */
833 if(msptr
->bants
== chptr
->bants
)
835 if(can_send_banned(msptr
))
838 else if(is_banned(chptr
, source_p
, msptr
, NULL
, NULL
) == CHFL_BAN
839 || is_quieted(chptr
, source_p
, msptr
, NULL
, NULL
) == CHFL_BAN
)
843 return CAN_SEND_NONOP
;
846 /* find_bannickchange_channel()
847 * Input: client to check
848 * Output: channel preventing nick change
851 find_bannickchange_channel(struct Client
*client_p
)
853 struct Channel
*chptr
;
854 struct membership
*msptr
;
856 char src_host
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
857 char src_iphost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
859 if (!MyClient(client_p
))
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
)
868 chptr
= msptr
->chptr
;
869 if (is_chanop_voiced(msptr
))
871 /* cached can_send */
872 if (msptr
->bants
== chptr
->bants
)
874 if (can_send_banned(msptr
))
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
)
884 /* void check_spambot_warning(struct Client *source_p)
885 * Input: Client to check, channel name or NULL if this is a part.
887 * Side-effects: Updates the client's oper_warn_count_down, warns the
888 * IRC operators if necessary, and updates join_leave_countdown as
892 check_spambot_warning(struct Client
*source_p
, const char *name
)
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
--;
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 */
907 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
908 "User %s (%s@%s) trying to join %s is a possible spambot",
910 source_p
->username
, source_p
->host
, name
);
912 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
913 "User %s (%s@%s) is a possible spambot",
915 source_p
->username
, source_p
->host
);
916 source_p
->localClient
->oper_warn_count_down
= OPER_SPAM_COUNTDOWN
;
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;
929 source_p
->localClient
->join_leave_count
-= decrement_count
;
934 (source_p
->localClient
->last_join_time
)) < GlobalSetOptions
.spam_time
)
936 /* oh, its a possible spambot */
937 source_p
->localClient
->join_leave_count
++;
941 source_p
->localClient
->last_join_time
= CurrentTime
;
943 source_p
->localClient
->last_leave_time
= CurrentTime
;
951 * side effects - compares usercount and servercount against their split
952 * values and adjusts splitmode accordingly
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
964 if(eob_count
< split_servers
|| Count
.total
< split_users
)
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
)
977 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
978 "Network rejoined, deactivating splitmode");
980 eventDelete(check_splitmode
, NULL
);
988 * input - channel to allocate topic for
989 * output - 1 on success, else 0
990 * side effects - channel gets a topic allocated
993 allocate_topic(struct Channel
*chptr
)
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
1007 chptr
->topic_info
= (char *) ptr
+ TOPICLEN
+ 1;
1008 *chptr
->topic
= '\0';
1009 *chptr
->topic_info
= '\0';
1014 * input - channel which has topic to free
1016 * side effects - channels topic is free'd
1019 free_topic(struct Channel
*chptr
)
1023 if(chptr
== NULL
|| chptr
->topic
== NULL
)
1026 /* This is safe for now - If you change allocate_topic you
1027 * MUST change this as well
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
1039 * side effects - channels topic, topic info and TS are set.
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
;
1054 if(chptr
->topic
!= NULL
)
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'},
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'},
1081 * inputs - pointer to channel
1082 * - pointer to client
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
1090 channel_modes(struct Channel
*chptr
, struct Client
*client_p
)
1095 static char final
[BUFSIZE
];
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
)
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
)
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
)
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
)
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
)
1143 if(*pbuf
|| IsMember(client_p
, chptr
) || IsServer(client_p
) || IsMe(client_p
))
1144 pbuf
+= ircsprintf(pbuf
, "%s ", chptr
->mode
.forward
);
1149 ircsprintf(final
, "%s %s", buf1
, buf2
);
1153 /* Now lets do some stuff to keep track of what combinations of
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
1164 /* void init_chcap_usage_counts(void)
1168 * Side-effects - Initialises the usage counts to zero. Fills in the
1169 * chcap_yes and chcap_no combination tables.
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
];
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.
1197 * Side-effects: Increments the usage counts for the correct capab
1201 set_chcap_usage_counts(struct Client
*serv_p
)
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
++;
1215 /* This should be impossible -A1kmm. */
1219 /* void set_chcap_usage_counts(struct Client *serv_p)
1221 * Inputs - serv_p; The client whose capabs to register.
1223 * Side-effects - Decrements the usage counts for the correct capab
1227 unset_chcap_usage_counts(struct Client
*serv_p
)
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
--;
1245 /* This should be impossible -A1kmm. */
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)
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
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
;
1276 /* Now send to servers... */
1277 for (j
= 0; j
< NCHCAP_COMBOS
; j
++)
1279 if(chcap_combos
[j
].count
== 0)
1289 cap
= chcap_combos
[j
].cap_yes
;
1290 nocap
= chcap_combos
[j
].cap_no
;
1293 mbl
= preflen
= ircsprintf(modebuf
, ":%s TMODE %ld %s ",
1294 use_id(source_p
), (long) chptr
->channelts
,
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
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
))
1312 if((cap
& CAP_TS6
) && !EmptyString(mode_changes
[i
].id
))
1313 arg
= mode_changes
[i
].id
;
1315 arg
= mode_changes
[i
].arg
;
1319 arglen
= strlen(arg
);
1321 /* dont even think about it! --fl */
1322 if(arglen
> MODEBUFLEN
- 5)
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))))
1337 sendto_server(client_p
, chptr
, cap
, nocap
,
1338 "%s %s", modebuf
, parabuf
);
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
;
1361 len
= ircsprintf(pbuf
, "%s ", arg
);
1368 if(pbl
&& parabuf
[pbl
- 1] == ' ')
1369 parabuf
[pbl
- 1] = 0;
1372 sendto_server(client_p
, chptr
, cap
, nocap
, "%s %s", modebuf
, parabuf
);