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
24 * $Id: channel.c 3580 2007-11-07 23:45:14Z jilles $
36 #include "s_serv.h" /* captab */
40 #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
41 #include "s_newconf.h"
44 static int channel_capabs
[] = { CAP_EX
, CAP_IE
,
49 #define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
50 #define NCHCAP_COMBOS (1 << NCHCAPS)
52 static struct ChCapCombo chcap_combos
[NCHCAP_COMBOS
];
54 static void free_topic(struct Channel
*chptr
);
56 static int h_can_join
;
62 * side effects - initialises the various blockheaps
67 channel_heap
= rb_bh_create(sizeof(struct Channel
), CHANNEL_HEAP_SIZE
, "channel_heap");
68 ban_heap
= rb_bh_create(sizeof(struct Ban
), BAN_HEAP_SIZE
, "ban_heap");
69 topic_heap
= rb_bh_create(TOPICLEN
+ 1 + USERHOST_REPLYLEN
, TOPIC_HEAP_SIZE
, "topic_heap");
70 member_heap
= rb_bh_create(sizeof(struct membership
), MEMBER_HEAP_SIZE
, "member_heap");
72 h_can_join
= register_hook("can_join");
76 * allocate_channel - Allocates a channel
79 allocate_channel(const char *chname
)
81 struct Channel
*chptr
;
82 chptr
= rb_bh_alloc(channel_heap
);
83 chptr
->chname
= rb_strdup(chname
);
88 free_channel(struct Channel
*chptr
)
90 rb_free(chptr
->chname
);
91 rb_bh_free(channel_heap
, chptr
);
95 allocate_ban(const char *banstr
, const char *who
)
98 bptr
= rb_bh_alloc(ban_heap
);
99 bptr
->banstr
= rb_strdup(banstr
);
100 bptr
->who
= rb_strdup(who
);
106 free_ban(struct Ban
*bptr
)
108 rb_free(bptr
->banstr
);
110 rb_bh_free(ban_heap
, bptr
);
114 /* find_channel_membership()
116 * input - channel to find them in, client to find
117 * output - membership of client in channel, else NULL
121 find_channel_membership(struct Channel
*chptr
, struct Client
*client_p
)
123 struct membership
*msptr
;
126 if(!IsClient(client_p
))
129 /* Pick the most efficient list to use to be nice to things like
130 * CHANSERV which could be in a large number of channels
132 if(rb_dlink_list_length(&chptr
->members
) < rb_dlink_list_length(&client_p
->user
->channel
))
134 RB_DLINK_FOREACH(ptr
, chptr
->members
.head
)
138 if(msptr
->client_p
== client_p
)
144 RB_DLINK_FOREACH(ptr
, client_p
->user
->channel
.head
)
148 if(msptr
->chptr
== chptr
)
156 /* find_channel_status()
158 * input - membership to get status for, whether we can combine flags
159 * output - flags of user on channel
163 find_channel_status(struct membership
*msptr
, int combine
)
165 static char buffer
[3];
184 /* add_user_to_channel()
186 * input - channel to add client to, client to add, channel flags
188 * side effects - user is added to channel
191 add_user_to_channel(struct Channel
*chptr
, struct Client
*client_p
, int flags
)
193 struct membership
*msptr
;
195 s_assert(client_p
->user
!= NULL
);
196 if(client_p
->user
== NULL
)
199 msptr
= rb_bh_alloc(member_heap
);
201 msptr
->chptr
= chptr
;
202 msptr
->client_p
= client_p
;
203 msptr
->flags
= flags
;
205 rb_dlinkAdd(msptr
, &msptr
->usernode
, &client_p
->user
->channel
);
206 rb_dlinkAdd(msptr
, &msptr
->channode
, &chptr
->members
);
208 if(MyClient(client_p
))
209 rb_dlinkAdd(msptr
, &msptr
->locchannode
, &chptr
->locmembers
);
212 /* remove_user_from_channel()
214 * input - membership pointer to remove from channel
216 * side effects - membership (thus user) is removed from channel
219 remove_user_from_channel(struct membership
*msptr
)
221 struct Client
*client_p
;
222 struct Channel
*chptr
;
223 s_assert(msptr
!= NULL
);
227 client_p
= msptr
->client_p
;
228 chptr
= msptr
->chptr
;
230 rb_dlinkDelete(&msptr
->usernode
, &client_p
->user
->channel
);
231 rb_dlinkDelete(&msptr
->channode
, &chptr
->members
);
233 if(client_p
->servptr
== &me
)
234 rb_dlinkDelete(&msptr
->locchannode
, &chptr
->locmembers
);
236 chptr
->users_last
= rb_current_time();
238 if(!(chptr
->mode
.mode
& MODE_PERMANENT
) && rb_dlink_list_length(&chptr
->members
) <= 0)
239 destroy_channel(chptr
);
241 rb_bh_free(member_heap
, msptr
);
246 /* remove_user_from_channels()
248 * input - user to remove from all channels
250 * side effects - user is removed from all channels
253 remove_user_from_channels(struct Client
*client_p
)
255 struct Channel
*chptr
;
256 struct membership
*msptr
;
258 rb_dlink_node
*next_ptr
;
263 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, client_p
->user
->channel
.head
)
266 chptr
= msptr
->chptr
;
268 rb_dlinkDelete(&msptr
->channode
, &chptr
->members
);
270 if(client_p
->servptr
== &me
)
271 rb_dlinkDelete(&msptr
->locchannode
, &chptr
->locmembers
);
273 chptr
->users_last
= rb_current_time();
275 if(!(chptr
->mode
.mode
& MODE_PERMANENT
) && rb_dlink_list_length(&chptr
->members
) <= 0)
276 destroy_channel(chptr
);
278 rb_bh_free(member_heap
, msptr
);
281 client_p
->user
->channel
.head
= client_p
->user
->channel
.tail
= NULL
;
282 client_p
->user
->channel
.length
= 0;
285 /* invalidate_bancache_user()
287 * input - user to invalidate ban cache for
289 * side effects - ban cache is invalidated for all memberships of that user
290 * to be used after a nick change
293 invalidate_bancache_user(struct Client
*client_p
)
295 struct membership
*msptr
;
301 RB_DLINK_FOREACH(ptr
, client_p
->user
->channel
.head
)
305 msptr
->flags
&= ~CHFL_BANNED
;
309 /* check_channel_name()
311 * input - channel name
312 * output - 1 if valid channel name, else 0
316 check_channel_name(const char *name
)
318 s_assert(name
!= NULL
);
322 for (; *name
; ++name
)
324 if(!IsChanChar(*name
))
331 /* free_channel_list()
333 * input - rb_dlink list to free
335 * side effects - list of b/e/I modes is cleared
338 free_channel_list(rb_dlink_list
* list
)
341 rb_dlink_node
*next_ptr
;
342 struct Ban
*actualBan
;
344 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, list
->head
)
346 actualBan
= ptr
->data
;
350 list
->head
= list
->tail
= NULL
;
356 * input - channel to destroy
358 * side effects - channel is obliterated
361 destroy_channel(struct Channel
*chptr
)
363 rb_dlink_node
*ptr
, *next_ptr
;
365 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, chptr
->invites
.head
)
367 del_invite(chptr
, ptr
->data
);
370 /* free all bans/exceptions/denies */
371 free_channel_list(&chptr
->banlist
);
372 free_channel_list(&chptr
->exceptlist
);
373 free_channel_list(&chptr
->invexlist
);
374 free_channel_list(&chptr
->quietlist
);
379 rb_dlinkDelete(&chptr
->node
, &global_channel_list
);
380 del_from_channel_hash(chptr
->chname
, chptr
);
384 /* channel_pub_or_secret()
387 * output - "=" if public, "@" if secret, else "*"
391 channel_pub_or_secret(struct Channel
*chptr
)
393 if(PubChannel(chptr
))
395 else if(SecretChannel(chptr
))
400 /* channel_member_names()
402 * input - channel to list, client to list to, show endofnames
404 * side effects - client is given list of users on channel
407 channel_member_names(struct Channel
*chptr
, struct Client
*client_p
, int show_eon
)
409 struct membership
*msptr
;
410 struct Client
*target_p
;
418 int stack
= IsCapable(client_p
, CLICAP_MULTI_PREFIX
);
420 if(ShowChannel(client_p
, chptr
))
422 is_member
= IsMember(client_p
, chptr
);
424 cur_len
= mlen
= rb_sprintf(lbuf
, form_str(RPL_NAMREPLY
),
425 me
.name
, client_p
->name
,
426 channel_pub_or_secret(chptr
), chptr
->chname
);
430 RB_DLINK_FOREACH(ptr
, chptr
->members
.head
)
433 target_p
= msptr
->client_p
;
435 if(IsInvisible(target_p
) && !is_member
)
438 /* space, possible "@+" prefix */
439 if(cur_len
+ strlen(target_p
->name
) + 3 >= BUFSIZE
- 3)
442 sendto_one(client_p
, "%s", lbuf
);
447 tlen
= rb_sprintf(t
, "%s%s ", find_channel_status(msptr
, stack
),
454 /* The old behaviour here was to always output our buffer,
455 * even if there are no clients we can show. This happens
456 * when a client does "NAMES" with no parameters, and all
457 * the clients on a -sp channel are +i. I dont see a good
458 * reason for keeping that behaviour, as it just wastes
464 sendto_one(client_p
, "%s", lbuf
);
469 sendto_one(client_p
, form_str(RPL_ENDOFNAMES
),
470 me
.name
, client_p
->name
, chptr
->chname
);
475 * input - channel to remove invite from, client to remove
477 * side effects - user is removed from invite list, if exists
480 del_invite(struct Channel
*chptr
, struct Client
*who
)
482 rb_dlinkFindDestroy(who
, &chptr
->invites
);
483 rb_dlinkFindDestroy(chptr
, &who
->user
->invited
);
488 * input - channel to check bans for, user to check bans against
489 * optional prebuilt buffers
490 * output - 1 if banned, else 0
494 is_banned(struct Channel
*chptr
, struct Client
*who
, struct membership
*msptr
,
495 const char *s
, const char *s2
)
497 char src_host
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
498 char src_iphost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
499 char src_althost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
502 struct Ban
*actualBan
= NULL
;
503 struct Ban
*actualExcept
= NULL
;
508 /* if the buffers havent been built, do it here */
511 rb_sprintf(src_host
, "%s!%s@%s", who
->name
, who
->username
, who
->host
);
512 rb_sprintf(src_iphost
, "%s!%s@%s", who
->name
, who
->username
, who
->sockhost
);
517 if(who
->localClient
->mangledhost
!= NULL
)
519 /* if host mangling mode enabled, also check their real host */
520 if(!strcmp(who
->host
, who
->localClient
->mangledhost
))
522 rb_sprintf(src_althost
, "%s!%s@%s", who
->name
, who
->username
, who
->orighost
);
525 /* if host mangling mode not enabled and no other spoof,
526 * also check the mangled form of their host */
527 else if (!IsDynSpoof(who
))
529 rb_sprintf(src_althost
, "%s!%s@%s", who
->name
, who
->username
, who
->localClient
->mangledhost
);
534 RB_DLINK_FOREACH(ptr
, chptr
->banlist
.head
)
536 actualBan
= ptr
->data
;
537 if(match(actualBan
->banstr
, s
) ||
538 match(actualBan
->banstr
, s2
) ||
539 match_cidr(actualBan
->banstr
, s2
) ||
540 match_extban(actualBan
->banstr
, who
, chptr
, CHFL_BAN
) ||
541 (s3
!= NULL
&& match(actualBan
->banstr
, s3
)))
547 if((actualBan
!= NULL
) && ConfigChannel
.use_except
)
549 RB_DLINK_FOREACH(ptr
, chptr
->exceptlist
.head
)
551 actualExcept
= ptr
->data
;
553 /* theyre exempted.. */
554 if(match(actualExcept
->banstr
, s
) ||
555 match(actualExcept
->banstr
, s2
) ||
556 match_cidr(actualExcept
->banstr
, s2
) ||
557 match_extban(actualExcept
->banstr
, who
, chptr
, CHFL_EXCEPTION
) ||
558 (s3
!= NULL
&& match(actualExcept
->banstr
, s3
)))
560 /* cache the fact theyre not banned */
563 msptr
->bants
= chptr
->bants
;
564 msptr
->flags
&= ~CHFL_BANNED
;
567 return CHFL_EXCEPTION
;
572 /* cache the banned/not banned status */
575 msptr
->bants
= chptr
->bants
;
577 if(actualBan
!= NULL
)
579 msptr
->flags
|= CHFL_BANNED
;
584 msptr
->flags
&= ~CHFL_BANNED
;
589 return ((actualBan
? CHFL_BAN
: 0));
594 * input - channel to check bans for, user to check bans against
595 * optional prebuilt buffers
596 * output - 1 if banned, else 0
600 is_quieted(struct Channel
*chptr
, struct Client
*who
, struct membership
*msptr
,
601 const char *s
, const char *s2
)
603 char src_host
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
604 char src_iphost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
605 char src_althost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
608 struct Ban
*actualBan
= NULL
;
609 struct Ban
*actualExcept
= NULL
;
614 /* if the buffers havent been built, do it here */
617 rb_sprintf(src_host
, "%s!%s@%s", who
->name
, who
->username
, who
->host
);
618 rb_sprintf(src_iphost
, "%s!%s@%s", who
->name
, who
->username
, who
->sockhost
);
623 if(who
->localClient
->mangledhost
!= NULL
)
625 /* if host mangling mode enabled, also check their real host */
626 if(!strcmp(who
->host
, who
->localClient
->mangledhost
))
628 rb_sprintf(src_althost
, "%s!%s@%s", who
->name
, who
->username
, who
->orighost
);
631 /* if host mangling mode not enabled and no other spoof,
632 * also check the mangled form of their host */
633 else if (!IsDynSpoof(who
))
635 rb_sprintf(src_althost
, "%s!%s@%s", who
->name
, who
->username
, who
->localClient
->mangledhost
);
640 RB_DLINK_FOREACH(ptr
, chptr
->quietlist
.head
)
642 actualBan
= ptr
->data
;
643 if(match(actualBan
->banstr
, s
) ||
644 match(actualBan
->banstr
, s2
) ||
645 match_cidr(actualBan
->banstr
, s2
) ||
646 match_extban(actualBan
->banstr
, who
, chptr
, CHFL_QUIET
) ||
647 (s3
!= NULL
&& match(actualBan
->banstr
, s3
)))
653 if((actualBan
!= NULL
) && ConfigChannel
.use_except
)
655 RB_DLINK_FOREACH(ptr
, chptr
->exceptlist
.head
)
657 actualExcept
= ptr
->data
;
659 /* theyre exempted.. */
660 if(match(actualExcept
->banstr
, s
) ||
661 match(actualExcept
->banstr
, s2
) ||
662 match_cidr(actualExcept
->banstr
, s2
) ||
663 match_extban(actualExcept
->banstr
, who
, chptr
, CHFL_EXCEPTION
) ||
664 (s3
!= NULL
&& match(actualExcept
->banstr
, s3
)))
666 /* cache the fact theyre not banned */
669 msptr
->bants
= chptr
->bants
;
670 msptr
->flags
&= ~CHFL_BANNED
;
673 return CHFL_EXCEPTION
;
678 /* cache the banned/not banned status */
681 msptr
->bants
= chptr
->bants
;
683 if(actualBan
!= NULL
)
685 msptr
->flags
|= CHFL_BANNED
;
690 msptr
->flags
&= ~CHFL_BANNED
;
695 return ((actualBan
? CHFL_BAN
: 0));
700 * input - client to check, channel to check for, key
701 * output - reason for not being able to join, else 0
705 can_join(struct Client
*source_p
, struct Channel
*chptr
, char *key
)
707 rb_dlink_node
*invite
= NULL
;
709 struct Ban
*invex
= NULL
;
710 char src_host
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
711 char src_iphost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
712 char src_althost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
715 hook_data_channel moduledata
;
717 s_assert(source_p
->localClient
!= NULL
);
719 rb_sprintf(src_host
, "%s!%s@%s", source_p
->name
, source_p
->username
, source_p
->host
);
720 rb_sprintf(src_iphost
, "%s!%s@%s", source_p
->name
, source_p
->username
, source_p
->sockhost
);
721 if(source_p
->localClient
->mangledhost
!= NULL
)
723 /* if host mangling mode enabled, also check their real host */
724 if(!strcmp(source_p
->host
, source_p
->localClient
->mangledhost
))
726 rb_sprintf(src_althost
, "%s!%s@%s", source_p
->name
, source_p
->username
, source_p
->orighost
);
729 /* if host mangling mode not enabled and no other spoof,
730 * also check the mangled form of their host */
731 else if (!IsDynSpoof(source_p
))
733 rb_sprintf(src_althost
, "%s!%s@%s", source_p
->name
, source_p
->username
, source_p
->localClient
->mangledhost
);
738 if((is_banned(chptr
, source_p
, NULL
, src_host
, src_iphost
)) == CHFL_BAN
)
739 return (ERR_BANNEDFROMCHAN
);
741 if(chptr
->mode
.mode
& MODE_INVITEONLY
)
743 RB_DLINK_FOREACH(invite
, source_p
->user
->invited
.head
)
745 if(invite
->data
== chptr
)
750 if(!ConfigChannel
.use_invex
)
751 return (ERR_INVITEONLYCHAN
);
752 RB_DLINK_FOREACH(ptr
, chptr
->invexlist
.head
)
755 if(match(invex
->banstr
, src_host
)
756 || match(invex
->banstr
, src_iphost
)
757 || match_cidr(invex
->banstr
, src_iphost
)
758 || match_extban(invex
->banstr
, source_p
, chptr
, CHFL_INVEX
)
759 || (use_althost
&& match(invex
->banstr
, src_althost
)))
763 return (ERR_INVITEONLYCHAN
);
767 if(*chptr
->mode
.key
&& (EmptyString(key
) || irccmp(chptr
->mode
.key
, key
)))
768 return (ERR_BADCHANNELKEY
);
770 if(chptr
->mode
.limit
&&
771 rb_dlink_list_length(&chptr
->members
) >= (unsigned long) chptr
->mode
.limit
)
772 i
= ERR_CHANNELISFULL
;
773 if(chptr
->mode
.mode
& MODE_REGONLY
&& EmptyString(source_p
->user
->suser
))
774 i
= ERR_NEEDREGGEDNICK
;
775 /* join throttling stuff --nenolod */
776 else if(chptr
->mode
.join_num
> 0 && chptr
->mode
.join_time
> 0)
778 if ((rb_current_time() - chptr
->join_delta
<=
779 chptr
->mode
.join_time
) && (chptr
->join_count
>=
780 chptr
->mode
.join_num
))
784 /* allow /invite to override +l/+r/+j also -- jilles */
785 if (i
!= 0 && invite
== NULL
)
787 RB_DLINK_FOREACH(invite
, source_p
->user
->invited
.head
)
789 if(invite
->data
== chptr
)
796 moduledata
.client
= source_p
;
797 moduledata
.chptr
= chptr
;
798 moduledata
.approved
= 0;
800 call_hook(h_can_join
, &moduledata
);
802 return moduledata
.approved
;
807 * input - user to check in channel, membership pointer
808 * output - whether can explicitly send or not, else CAN_SEND_NONOP
812 can_send(struct Channel
*chptr
, struct Client
*source_p
, struct membership
*msptr
)
814 if(IsServer(source_p
) || IsService(source_p
))
817 if(MyClient(source_p
) && hash_find_resv(chptr
->chname
) &&
818 !IsOper(source_p
) && !IsExemptResv(source_p
))
823 msptr
= find_channel_membership(chptr
, source_p
);
827 /* if its +m or +n and theyre not in the channel,
828 * they cant send. we dont check bans here because
829 * theres no possibility of caching them --fl
831 if(chptr
->mode
.mode
& MODE_NOPRIVMSGS
|| chptr
->mode
.mode
& MODE_MODERATED
)
834 return CAN_SEND_NONOP
;
838 if(is_chanop_voiced(msptr
))
841 if(chptr
->mode
.mode
& MODE_MODERATED
)
844 if(MyClient(source_p
))
846 /* cached can_send */
847 if(msptr
->bants
== chptr
->bants
)
849 if(can_send_banned(msptr
))
852 else if(is_banned(chptr
, source_p
, msptr
, NULL
, NULL
) == CHFL_BAN
853 || is_quieted(chptr
, source_p
, msptr
, NULL
, NULL
) == CHFL_BAN
)
857 return CAN_SEND_NONOP
;
860 /* find_bannickchange_channel()
861 * Input: client to check
862 * Output: channel preventing nick change
865 find_bannickchange_channel(struct Client
*client_p
)
867 struct Channel
*chptr
;
868 struct membership
*msptr
;
870 char src_host
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
871 char src_iphost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 6];
873 if (!MyClient(client_p
))
876 rb_sprintf(src_host
, "%s!%s@%s", client_p
->name
, client_p
->username
, client_p
->host
);
877 rb_sprintf(src_iphost
, "%s!%s@%s", client_p
->name
, client_p
->username
, client_p
->sockhost
);
879 RB_DLINK_FOREACH(ptr
, client_p
->user
->channel
.head
)
882 chptr
= msptr
->chptr
;
883 if (is_chanop_voiced(msptr
))
885 /* cached can_send */
886 if (msptr
->bants
== chptr
->bants
)
888 if (can_send_banned(msptr
))
891 else if (is_banned(chptr
, client_p
, msptr
, src_host
, src_iphost
) == CHFL_BAN
892 || is_quieted(chptr
, client_p
, msptr
, src_host
, src_iphost
) == CHFL_BAN
)
898 /* void check_spambot_warning(struct Client *source_p)
899 * Input: Client to check, channel name or NULL if this is a part.
901 * Side-effects: Updates the client's oper_warn_count_down, warns the
902 * IRC operators if necessary, and updates join_leave_countdown as
906 check_spambot_warning(struct Client
*source_p
, const char *name
)
910 if((GlobalSetOptions
.spam_num
&&
911 (source_p
->localClient
->join_leave_count
>= GlobalSetOptions
.spam_num
)))
913 if(source_p
->localClient
->oper_warn_count_down
> 0)
914 source_p
->localClient
->oper_warn_count_down
--;
916 source_p
->localClient
->oper_warn_count_down
= 0;
917 if(source_p
->localClient
->oper_warn_count_down
== 0)
919 /* Its already known as a possible spambot */
921 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
922 "User %s (%s@%s) trying to join %s is a possible spambot",
924 source_p
->username
, source_p
->orighost
, name
);
926 sendto_realops_snomask(SNO_BOTS
, L_NETWIDE
,
927 "User %s (%s@%s) is a possible spambot",
929 source_p
->username
, source_p
->orighost
);
930 source_p
->localClient
->oper_warn_count_down
= OPER_SPAM_COUNTDOWN
;
936 (rb_current_time() - source_p
->localClient
->last_leave_time
)) >
937 JOIN_LEAVE_COUNT_EXPIRE_TIME
)
939 decrement_count
= (t_delta
/ JOIN_LEAVE_COUNT_EXPIRE_TIME
);
940 if(decrement_count
> source_p
->localClient
->join_leave_count
)
941 source_p
->localClient
->join_leave_count
= 0;
943 source_p
->localClient
->join_leave_count
-= decrement_count
;
947 if((rb_current_time() -
948 (source_p
->localClient
->last_join_time
)) < GlobalSetOptions
.spam_time
)
950 /* oh, its a possible spambot */
951 source_p
->localClient
->join_leave_count
++;
955 source_p
->localClient
->last_join_time
= rb_current_time();
957 source_p
->localClient
->last_leave_time
= rb_current_time();
965 * side effects - compares usercount and servercount against their split
966 * values and adjusts splitmode accordingly
969 check_splitmode(void *unused
)
971 if(splitchecking
&& (ConfigChannel
.no_join_on_split
|| ConfigChannel
.no_create_on_split
))
973 /* not split, we're being asked to check now because someone
978 if(eob_count
< split_servers
|| Count
.total
< split_users
)
981 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
982 "Network split, activating splitmode");
983 check_splitmode_ev
= rb_event_addish("check_splitmode", check_splitmode
, NULL
, 2);
986 /* in splitmode, check whether its finished */
987 else if(eob_count
>= split_servers
&& Count
.total
>= split_users
)
991 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
992 "Network rejoined, deactivating splitmode");
994 rb_event_delete(check_splitmode_ev
);
1002 * input - channel to allocate topic for
1003 * output - 1 on success, else 0
1004 * side effects - channel gets a topic allocated
1007 allocate_topic(struct Channel
*chptr
)
1014 ptr
= rb_bh_alloc(topic_heap
);
1016 /* Basically we allocate one large block for the topic and
1017 * the topic info. We then split it up into two and shove it
1021 chptr
->topic_info
= (char *) ptr
+ TOPICLEN
+ 1;
1022 *chptr
->topic
= '\0';
1023 *chptr
->topic_info
= '\0';
1028 * input - channel which has topic to free
1030 * side effects - channels topic is free'd
1033 free_topic(struct Channel
*chptr
)
1037 if(chptr
== NULL
|| chptr
->topic
== NULL
)
1040 /* This is safe for now - If you change allocate_topic you
1041 * MUST change this as well
1044 rb_bh_free(topic_heap
, ptr
);
1045 chptr
->topic
= NULL
;
1046 chptr
->topic_info
= NULL
;
1049 /* set_channel_topic()
1051 * input - channel, topic to set, topic info and topic ts
1053 * side effects - channels topic, topic info and TS are set.
1056 set_channel_topic(struct Channel
*chptr
, const char *topic
, const char *topic_info
, time_t topicts
)
1058 if(strlen(topic
) > 0)
1060 if(chptr
->topic
== NULL
)
1061 allocate_topic(chptr
);
1062 rb_strlcpy(chptr
->topic
, topic
, TOPICLEN
+ 1);
1063 rb_strlcpy(chptr
->topic_info
, topic_info
, USERHOST_REPLYLEN
);
1064 chptr
->topic_time
= topicts
;
1068 if(chptr
->topic
!= NULL
)
1070 chptr
->topic_time
= 0;
1074 const struct mode_letter chmode_flags
[] =
1076 {MODE_INVITEONLY
, 'i'},
1077 {MODE_MODERATED
, 'm'},
1078 {MODE_NOPRIVMSGS
, 'n'},
1079 {MODE_PRIVATE
, 'p'},
1081 {MODE_TOPICLIMIT
, 't'},
1082 {MODE_NOCOLOR
, 'c'},
1083 {MODE_FREEINVITE
, 'g'},
1084 {MODE_OPMODERATE
, 'z'},
1085 {MODE_EXLIMIT
, 'L'},
1086 {MODE_PERMANENT
, 'P'},
1087 {MODE_FREETARGET
, 'F'},
1088 {MODE_DISFORWARD
, 'Q'},
1089 {MODE_REGONLY
, 'r'},
1095 * inputs - pointer to channel
1096 * - pointer to client
1097 * output - string with simple modes
1098 * side effects - result from previous calls overwritten
1100 * Stolen from ShadowIRCd 4 --nenolod
1103 channel_modes(struct Channel
*chptr
, struct Client
*client_p
)
1108 static char final
[BUFSIZE
];
1115 for (i
= 0; chmode_flags
[i
].mode
; ++i
)
1116 if(chptr
->mode
.mode
& chmode_flags
[i
].mode
)
1117 *mbuf
++ = chmode_flags
[i
].letter
;
1119 if(chptr
->mode
.limit
)
1123 if(!IsClient(client_p
) || IsMember(client_p
, chptr
))
1124 pbuf
+= rb_sprintf(pbuf
, " %d", chptr
->mode
.limit
);
1127 if(*chptr
->mode
.key
)
1131 if(pbuf
> buf2
|| !IsClient(client_p
) || IsMember(client_p
, chptr
))
1132 pbuf
+= rb_sprintf(pbuf
, " %s", chptr
->mode
.key
);
1135 if(chptr
->mode
.join_num
)
1139 if(pbuf
> buf2
|| !IsClient(client_p
) || IsMember(client_p
, chptr
))
1140 pbuf
+= rb_sprintf(pbuf
, " %d:%d", chptr
->mode
.join_num
,
1141 chptr
->mode
.join_time
);
1144 if(*chptr
->mode
.forward
&& (ConfigChannel
.use_forward
|| !IsClient(client_p
)))
1148 if(pbuf
> buf2
|| !IsClient(client_p
) || IsMember(client_p
, chptr
))
1149 pbuf
+= rb_sprintf(pbuf
, " %s", chptr
->mode
.forward
);
1154 rb_strlcpy(final
, buf1
, sizeof final
);
1155 rb_strlcat(final
, buf2
, sizeof final
);
1159 /* Now lets do some stuff to keep track of what combinations of
1161 * Note that the number of combinations doubles each time you add
1162 * something to this list. Each one is only quick if no servers use that
1163 * combination, but if the numbers get too high here MODE will get too
1164 * slow. I suggest if you get more than 7 here, you consider getting rid
1165 * of some and merging or something. If it wasn't for irc+cs we would
1166 * probably not even need to bother about most of these, but unfortunately
1170 /* void init_chcap_usage_counts(void)
1174 * Side-effects - Initialises the usage counts to zero. Fills in the
1175 * chcap_yes and chcap_no combination tables.
1178 init_chcap_usage_counts(void)
1180 unsigned long m
, c
, y
, n
;
1182 memset(chcap_combos
, 0, sizeof(chcap_combos
));
1184 /* For every possible combination */
1185 for (m
= 0; m
< NCHCAP_COMBOS
; m
++)
1187 /* Check each capab */
1188 for (c
= y
= n
= 0; c
< NCHCAPS
; c
++)
1190 if((m
& (1 << c
)) == 0)
1191 n
|= channel_capabs
[c
];
1193 y
|= channel_capabs
[c
];
1195 chcap_combos
[m
].cap_yes
= y
;
1196 chcap_combos
[m
].cap_no
= n
;
1200 /* void set_chcap_usage_counts(struct Client *serv_p)
1201 * Input: serv_p; The client whose capabs to register.
1203 * Side-effects: Increments the usage counts for the correct capab
1207 set_chcap_usage_counts(struct Client
*serv_p
)
1211 for (n
= 0; n
< NCHCAP_COMBOS
; n
++)
1213 if(IsCapable(serv_p
, chcap_combos
[n
].cap_yes
) &&
1214 NotCapable(serv_p
, chcap_combos
[n
].cap_no
))
1216 chcap_combos
[n
].count
++;
1221 /* This should be impossible -A1kmm. */
1225 /* void set_chcap_usage_counts(struct Client *serv_p)
1227 * Inputs - serv_p; The client whose capabs to register.
1229 * Side-effects - Decrements the usage counts for the correct capab
1233 unset_chcap_usage_counts(struct Client
*serv_p
)
1237 for (n
= 0; n
< NCHCAP_COMBOS
; n
++)
1239 if(IsCapable(serv_p
, chcap_combos
[n
].cap_yes
) &&
1240 NotCapable(serv_p
, chcap_combos
[n
].cap_no
))
1242 /* Hopefully capabs can't change dynamically or anything... */
1243 s_assert(chcap_combos
[n
].count
> 0);
1245 if(chcap_combos
[n
].count
> 0)
1246 chcap_combos
[n
].count
--;
1251 /* This should be impossible -A1kmm. */
1255 /* void send_cap_mode_changes(struct Client *client_p,
1256 * struct Client *source_p,
1257 * struct Channel *chptr, int cap, int nocap)
1258 * Input: The client sending(client_p), the source client(source_p),
1259 * the channel to send mode changes for(chptr)
1261 * Side-effects: Sends the appropriate mode changes to capable servers.
1263 * Reverted back to my original design, except that we now keep a count
1264 * of the number of servers which each combination as an optimisation, so
1265 * the capabs combinations which are not needed are not worked out. -A1kmm
1268 send_cap_mode_changes(struct Client
*client_p
, struct Client
*source_p
,
1269 struct Channel
*chptr
, struct ChModeChange mode_changes
[], int mode_count
)
1271 static char modebuf
[BUFSIZE
];
1272 static char parabuf
[BUFSIZE
];
1273 int i
, mbl
, pbl
, nc
, mc
, preflen
, len
;
1282 /* Now send to servers... */
1283 for (j
= 0; j
< NCHCAP_COMBOS
; j
++)
1285 if(chcap_combos
[j
].count
== 0)
1295 cap
= chcap_combos
[j
].cap_yes
;
1296 nocap
= chcap_combos
[j
].cap_no
;
1299 mbl
= preflen
= rb_sprintf(modebuf
, ":%s TMODE %ld %s ",
1300 use_id(source_p
), (long) chptr
->channelts
,
1303 mbl
= preflen
= rb_sprintf(modebuf
, ":%s MODE %s ",
1304 source_p
->name
, chptr
->chname
);
1306 /* loop the list of - modes we have */
1307 for (i
= 0; i
< mode_count
; i
++)
1309 /* if they dont support the cap we need, or they do support a cap they
1310 * cant have, then dont add it to the modebuf.. that way they wont see
1313 if((mode_changes
[i
].letter
== 0) ||
1314 ((cap
& mode_changes
[i
].caps
) != mode_changes
[i
].caps
)
1315 || ((nocap
& mode_changes
[i
].nocaps
) != mode_changes
[i
].nocaps
))
1318 if((cap
& CAP_TS6
) && !EmptyString(mode_changes
[i
].id
))
1319 arg
= mode_changes
[i
].id
;
1321 arg
= mode_changes
[i
].arg
;
1325 arglen
= strlen(arg
);
1327 /* dont even think about it! --fl */
1328 if(arglen
> MODEBUFLEN
- 5)
1332 /* if we're creeping past the buf size, we need to send it and make
1333 * another line for the other modes
1334 * XXX - this could give away server topology with uids being
1335 * different lengths, but not much we can do, except possibly break
1336 * them as if they were the longest of the nick or uid at all times,
1337 * which even then won't work as we don't always know the uid -A1kmm.
1339 if(arg
&& ((mc
== MAXMODEPARAMSSERV
) ||
1340 ((mbl
+ pbl
+ arglen
+ 4) > (BUFSIZE
- 3))))
1343 sendto_server(client_p
, chptr
, cap
, nocap
,
1344 "%s %s", modebuf
, parabuf
);
1355 if(dir
!= mode_changes
[i
].dir
)
1357 modebuf
[mbl
++] = (mode_changes
[i
].dir
== MODE_ADD
) ? '+' : '-';
1358 dir
= mode_changes
[i
].dir
;
1361 modebuf
[mbl
++] = mode_changes
[i
].letter
;
1367 len
= rb_sprintf(pbuf
, "%s ", arg
);
1374 if(pbl
&& parabuf
[pbl
- 1] == ' ')
1375 parabuf
[pbl
- 1] = 0;
1378 sendto_server(client_p
, chptr
, cap
, nocap
, "%s %s", modebuf
, parabuf
);