2 * IRC - Internet Relay Chat, ircd/channel.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Co Center
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "destruct_event.h"
29 #include "ircd_alloc.h"
30 #include "ircd_chattr.h"
31 #include "ircd_defs.h"
32 #include "ircd_features.h"
34 #include "ircd_policy.h"
35 #include "ircd_reply.h"
36 #include "ircd_snprintf.h"
37 #include "ircd_string.h"
44 #include "querycmds.h"
61 struct Channel* GlobalChannelList = 0;
63 static unsigned int membershipAllocCount;
64 static struct Membership* membershipFreeList;
66 void del_invite(struct Client *, struct Channel *);
68 const char* const PartFmt1 = ":%s " MSG_PART " %s";
69 const char* const PartFmt2 = ":%s " MSG_PART " %s :%s";
70 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
71 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
74 static struct SLink* next_ban;
75 static struct SLink* prev_ban;
76 static struct SLink* removed_bans_list;
79 * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
80 * but the only way to do it without changing set_mode intensively.
82 int LocalChanOperMode = 0;
86 * return the length (>=0) of a chain of links.
88 static int list_length(struct SLink *lp)
92 for (; lp; lp = lp->next)
98 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
100 struct Membership *m;
104 /* Servers don't have member links */
105 if (IsServer(cptr)||IsMe(cptr))
108 /* +k users are typically on a LOT of channels. So we iterate over who
109 * is in the channel. X/W are +k and are in about 5800 channels each.
110 * however there are typically no more than 1000 people in a channel
113 if (IsChannelService(cptr)) {
116 assert(m->channel == chptr);
122 /* Users on the other hand aren't allowed on more than 15 channels. 50%
123 * of users that are on channels are on 2 or less, 95% are on 7 or less,
124 * and 99% are on 10 or less.
127 m = (cli_user(cptr))->channel;
129 assert(m->user == cptr);
130 if (m->channel == chptr)
139 * find_chasing - Find the client structure for a nick name (user)
140 * using history mechanism if necessary. If the client is not found, an error
141 * message (NO SUCH NICK) is generated. If the client was found
142 * through the history, chasing will be 1 and otherwise 0.
144 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
146 struct Client* who = FindClient(user);
153 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
154 send_reply(sptr, ERR_NOSUCHNICK, user);
163 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
164 * as the parameters. If NULL, they become "*".
166 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
167 static char *make_nick_user_host(char *namebuf, const char *nick,
168 const char *name, const char *host)
170 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
175 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
176 * IP-number as the parameters. If NULL, they become "*".
178 #define NUI_BUFSIZE (NICKLEN + USERLEN + 16 + 3)
179 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
182 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name,
183 ircd_ntoa((const char*) &ip));
188 * Subtract one user from channel i (and free channel
189 * block, if channel became empty).
190 * Returns: true (1) if channel still has members.
191 * false (0) if the channel is now empty.
193 int sub1_from_channel(struct Channel* chptr)
195 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
197 assert(0 != chptr->members);
205 * Also channels without Apass set need to be kept alive,
206 * otherwise Bad Guys(tm) would be able to takeover
207 * existing channels too easily, and then set an Apass!
208 * However, if a channel without Apass becomes empty
209 * then we try to be kind to them and remove possible
212 chptr->mode.mode &= ~MODE_INVITEONLY;
213 chptr->mode.limit = 0;
215 * We do NOT reset a possible key or bans because when
216 * the 'channel owners' can't get in because of a key
217 * or ban then apparently there was a fight/takeover
218 * on the channel and we want them to contact IRC opers
219 * who then will educate them on the use of Apass/upass.
222 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
223 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
225 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
230 int destruct_channel(struct Channel* chptr)
235 assert(0 == chptr->members);
237 /* Channel became (or was) empty: Remove channel */
238 if (is_listed(chptr))
241 for (i = 0; i <= HighestFd; i++)
243 struct Client *acptr = 0;
244 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
245 (cli_listing(acptr))->chptr == chptr)
247 list_next_channels(acptr, 1);
248 break; /* Only one client can list a channel */
253 * Now, find all invite links from channel structure
255 while ((tmp = chptr->invites))
256 del_invite(tmp->value.cptr, chptr);
258 tmp = chptr->banlist;
263 MyFree(obtmp->value.ban.banstr);
264 MyFree(obtmp->value.ban.who);
268 chptr->prev->next = chptr->next;
270 GlobalChannelList = chptr->next;
272 chptr->next->prev = chptr->prev;
274 --UserStats.channels;
276 * make sure that channel actually got removed from hash table
278 assert(chptr->hnext == chptr);
286 * `cptr' must be the client adding the ban.
288 * If `change' is true then add `banid' to channel `chptr'.
289 * Returns 0 if the ban was added.
290 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
291 * Return -1 otherwise.
293 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
294 * when `change' is false, otherwise they will be removed from the banlist.
295 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
296 * respectively will return these bans until NULL is returned.
298 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
299 * is reset (unless a non-zero value is returned, in which case the
300 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
304 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
305 int change, int firsttime)
310 int removed_bans = 0;
311 int len = strlen(banid);
316 assert(0 == prev_ban);
317 assert(0 == removed_bans_list);
321 for (banp = &chptr->banlist; *banp;)
323 len += strlen((*banp)->value.ban.banstr);
325 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
327 if (!strcmp((*banp)->value.ban.banstr, banid))
329 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
333 else if (!mmatch((*banp)->value.ban.banstr, banid))
335 if (!mmatch(banid, (*banp)->value.ban.banstr))
337 struct SLink *tmp = *banp;
343 len -= strlen(tmp->value.ban.banstr);
346 /* These will be sent to the user later as -b */
347 tmp->next = removed_bans_list;
348 removed_bans_list = tmp;
351 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
353 tmp->flags |= CHFL_BAN_OVERLAPPED;
364 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
365 banp = &(*banp)->next;
368 if (MyUser(cptr) && !removed_bans &&
369 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
370 (cnt >= feature_int(FEAT_MAXBANS))))
372 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
378 struct Membership* member;
380 ban->next = chptr->banlist;
382 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
383 assert(0 != ban->value.ban.banstr);
384 strcpy(ban->value.ban.banstr, banid);
386 #ifdef HEAD_IN_SAND_BANWHO
388 DupString(ban->value.ban.who, cli_name(&me));
391 DupString(ban->value.ban.who, cli_name(cptr));
392 assert(0 != ban->value.ban.who);
394 ban->value.ban.when = TStime();
395 ban->flags = CHFL_BAN; /* This bit is never used I think... */
396 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
397 ban->flags |= CHFL_BAN_IPMASK;
398 chptr->banlist = ban;
401 * Erase ban-valid-bit
403 for (member = chptr->members; member; member = member->next_member)
404 ClearBanValid(member); /* `ban' == channel member ! */
409 struct SLink *next_removed_overlapped_ban(void)
411 struct SLink *tmp = removed_bans_list;
414 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
415 MyFree(prev_ban->value.ban.banstr);
416 MyFree(prev_ban->value.ban.who);
421 removed_bans_list = removed_bans_list->next;
427 * find_channel_member - returns Membership * if a person is joined and not a zombie
429 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
431 struct Membership* member;
434 member = find_member_link(chptr, cptr);
435 return (member && !IsZombie(member)) ? member : 0;
439 * is_banned - a non-zero value if banned else 0.
441 static int is_banned(struct Client *cptr, struct Channel *chptr,
442 struct Membership* member)
445 char nu_host[NUH_BUFSIZE];
446 char nu_realhost[NUH_BUFSIZE];
447 char nu_ip[NUI_BUFSIZE];
455 if (member && IsBanValid(member))
456 return IsBanned(member);
458 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
459 (cli_user(cptr))->host);
460 if (HasHiddenHost(cptr))
461 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
462 (cli_user(cptr))->username,
463 cli_user(cptr)->realhost);
465 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
466 if ((tmp->flags & CHFL_BAN_IPMASK)) {
468 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
469 (cli_user(cptr))->username, cli_ip(cptr));
470 if (match(tmp->value.ban.banstr, ip_s) == 0)
473 else if (match(tmp->value.ban.banstr, s) == 0)
475 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
491 return (tmp != NULL);
495 * adds a user to a channel by adding another link to the channels member
498 void add_user_to_channel(struct Channel* chptr, struct Client* who,
499 unsigned int flags, int oplevel)
506 struct Membership* member = membershipFreeList;
508 membershipFreeList = member->next_member;
510 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
511 ++membershipAllocCount;
516 member->channel = chptr;
517 member->status = flags;
518 member->oplevel = oplevel;
520 member->next_member = chptr->members;
521 if (member->next_member)
522 member->next_member->prev_member = member;
523 member->prev_member = 0;
524 chptr->members = member;
526 member->next_channel = (cli_user(who))->channel;
527 if (member->next_channel)
528 member->next_channel->prev_channel = member;
529 member->prev_channel = 0;
530 (cli_user(who))->channel = member;
532 if (chptr->destruct_event)
533 remove_destruct_event(chptr);
535 ++((cli_user(who))->joined);
539 static int remove_member_from_channel(struct Membership* member)
541 struct Channel* chptr;
543 chptr = member->channel;
545 * unlink channel member list
547 if (member->next_member)
548 member->next_member->prev_member = member->prev_member;
549 if (member->prev_member)
550 member->prev_member->next_member = member->next_member;
552 member->channel->members = member->next_member;
555 * unlink client channel list
557 if (member->next_channel)
558 member->next_channel->prev_channel = member->prev_channel;
559 if (member->prev_channel)
560 member->prev_channel->next_channel = member->next_channel;
562 (cli_user(member->user))->channel = member->next_channel;
564 --(cli_user(member->user))->joined;
566 member->next_member = membershipFreeList;
567 membershipFreeList = member;
569 return sub1_from_channel(chptr);
572 static int channel_all_zombies(struct Channel* chptr)
574 struct Membership* member;
576 for (member = chptr->members; member; member = member->next_member) {
577 if (!IsZombie(member))
584 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
587 struct Membership* member;
590 if ((member = find_member_link(chptr, cptr))) {
591 if (remove_member_from_channel(member)) {
592 if (channel_all_zombies(chptr)) {
594 * XXX - this looks dangerous but isn't if we got the referential
595 * integrity right for channels
597 while (remove_member_from_channel(chptr->members))
604 void remove_user_from_all_channels(struct Client* cptr)
606 struct Membership* chan;
608 assert(0 != cli_user(cptr));
610 while ((chan = (cli_user(cptr))->channel))
611 remove_user_from_channel(cptr, chan->channel);
614 int is_chan_op(struct Client *cptr, struct Channel *chptr)
616 struct Membership* member;
618 if ((member = find_member_link(chptr, cptr)))
619 return (!IsZombie(member) && IsChanOp(member));
624 int is_zombie(struct Client *cptr, struct Channel *chptr)
626 struct Membership* member;
630 if ((member = find_member_link(chptr, cptr)))
631 return IsZombie(member);
635 int has_voice(struct Client* cptr, struct Channel* chptr)
637 struct Membership* member;
640 if ((member = find_member_link(chptr, cptr)))
641 return (!IsZombie(member) && HasVoice(member));
646 int member_can_send_to_channel(struct Membership* member)
650 /* Discourage using the Apass to get op. They should use the upass. */
651 if (IsChannelManager(member) && *member->channel->mode.upass)
654 if (IsVoicedOrOpped(member))
657 * If it's moderated, and you aren't a priviledged user, you can't
660 if (member->channel->mode.mode & MODE_MODERATED)
663 * If you're banned then you can't speak either.
664 * but because of the amount of CPU time that is_banned chews
665 * we only check it for our clients.
667 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
672 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr)
674 struct Membership *member;
677 * Servers can always speak on channels.
682 member = find_channel_member(cptr, chptr);
685 * You can't speak if your off channel, if the channel is modeless, or
686 * +n (no external messages) or +m (moderated).
689 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
690 IsModelessChannel(chptr->chname) ||
691 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
694 return !is_banned(cptr, chptr, NULL);
696 return member_can_send_to_channel(member);
700 * find_no_nickchange_channel
701 * if a member and not opped or voiced and banned
702 * return the name of the first channel banned on
704 const char* find_no_nickchange_channel(struct Client* cptr)
707 struct Membership* member;
708 for (member = (cli_user(cptr))->channel; member;
709 member = member->next_channel) {
710 if (!IsVoicedOrOpped(member) && is_banned(cptr, member->channel, member))
711 return member->channel->chname;
719 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
720 * with the parameters in pbuf.
722 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
723 struct Channel *chptr, struct Membership *member)
725 int previous_parameter = 0;
732 if (chptr->mode.mode & MODE_SECRET)
734 else if (chptr->mode.mode & MODE_PRIVATE)
736 if (chptr->mode.mode & MODE_MODERATED)
738 if (chptr->mode.mode & MODE_TOPICLIMIT)
740 if (chptr->mode.mode & MODE_INVITEONLY)
742 if (chptr->mode.mode & MODE_NOPRIVMSGS)
744 if (chptr->mode.mode & MODE_REGONLY)
746 if (chptr->mode.limit) {
748 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
749 previous_parameter = 1;
752 if (*chptr->mode.key) {
754 if (previous_parameter)
756 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
757 strcat(pbuf, chptr->mode.key);
760 previous_parameter = 1;
762 if (*chptr->mode.apass) {
764 if (previous_parameter)
766 if (IsServer(cptr)) {
767 strcat(pbuf, chptr->mode.apass);
770 previous_parameter = 1;
772 if (*chptr->mode.upass) {
774 if (previous_parameter)
776 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
777 strcat(pbuf, chptr->mode.upass);
784 int compare_member_oplevel(const void *mp1, const void *mp2)
786 struct Membership const* member1 = *(struct Membership const**)mp1;
787 struct Membership const* member2 = *(struct Membership const**)mp2;
788 if (member1->oplevel == member2->oplevel)
790 return (member1->oplevel < member2->oplevel) ? -1 : 1;
794 * send "cptr" a full list of the modes for channel chptr.
796 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
798 /* The order in which modes are generated is now mandatory */
799 static unsigned int current_flags[4] =
800 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
806 struct Membership* member;
808 char modebuf[MODEBUFLEN];
809 char parabuf[MODEBUFLEN];
811 int number_of_ops = 0;
812 int opped_members_index = 0;
813 struct Membership** opped_members = NULL;
814 int last_oplevel = 0;
819 if (IsLocalChannel(chptr->chname))
822 member = chptr->members;
823 lp2 = chptr->banlist;
825 *modebuf = *parabuf = '\0';
826 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
828 for (first = 1; full; first = 0) /* Loop for multiple messages */
830 full = 0; /* Assume by default we get it
831 all in one message */
833 /* (Continued) prefix: "<Y> B <channel> <TS>" */
834 /* is there any better way we can do this? */
835 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
836 chptr->creationtime);
838 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
841 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
842 msgq_append(&me, mb, " %s", modebuf);
845 msgq_append(&me, mb, " %s", parabuf);
849 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
851 * First find all opless members.
852 * Run 2 times over all members, to group the members with
853 * and without voice together.
854 * Then run 2 times over all opped members (which are ordered
855 * by op-level) to also group voice and non-voice together.
857 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
861 if (flag_cnt < 2 && IsChanOp(member))
864 * The first loop (to find all non-voice/op), we count the ops.
865 * The second loop (to find all voiced non-ops), store the ops
866 * in a dynamic array.
871 opped_members[opped_members_index++] = member;
873 /* Only handle the members with the flags that we are interested in. */
874 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
876 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
877 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
879 full = 1; /* Make sure we continue after
881 /* Ensure the new BURST line contains the current
882 * ":mode", except when there is no mode yet. */
883 new_mode = (flag_cnt > 0) ? 1 : 0;
884 break; /* Do not add this member to this message */
886 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
887 first = 0; /* From now on, use commas to add new nicks */
890 * Do we have a nick with a new mode ?
891 * Or are we starting a new BURST line?
896 * This means we are at the _first_ member that has only
897 * voice, or the first member that has only ops, or the
898 * first member that has voice and ops (so we get here
899 * at most three times, plus once for every start of
900 * a continued BURST line where only these modes is current.
901 * In the two cases where the current mode includes ops,
902 * we need to add the _absolute_ value of the oplevel to the mode.
904 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
907 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
909 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
911 /* append the absolute value of the oplevel */
912 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
913 last_oplevel = member->oplevel;
916 msgq_append(&me, mb, tbuf);
919 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
922 * This can't be the first member of a (continued) BURST
923 * message because then either flag_cnt == 0 or new_mode == 1
924 * Now we need to append the incremental value of the oplevel.
926 char tbuf[2 + MAXOPLEVELDIGITS];
927 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
928 last_oplevel = member->oplevel;
929 msgq_append(&me, mb, tbuf);
932 /* Go to the next `member'. */
934 member = member->next_member;
936 member = opped_members[++opped_members_index];
941 /* Point `member' at the start of the list again. */
944 member = chptr->members;
945 /* Now, after one loop, we know the number of ops and can
946 * allocate the dynamic array with pointer to the ops. */
947 opped_members = (struct Membership**)
948 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
949 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
953 /* At the end of the second loop, sort the opped members with
954 * increasing op-level, so that we will output them in the
955 * correct order (and all op-level increments stay positive) */
957 qsort(opped_members, number_of_ops,
958 sizeof(struct Membership*), compare_member_oplevel);
959 /* The third and fourth loop run only over the opped members. */
960 member = opped_members[(opped_members_index = 0)];
963 } /* loop over 0,+v,+o,+ov */
967 /* Attach all bans, space seperated " :%ban ban ..." */
968 for (first = 2; lp2; lp2 = lp2->next)
970 len = strlen(lp2->value.ban.banstr);
971 if (msgq_bufleft(mb) < len + 1 + first)
972 /* The +1 stands for the added ' '.
973 * The +first stands for the added ":%".
979 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
980 lp2->value.ban.banstr);
985 send_buffer(cptr, mb, 0); /* Send this message */
987 } /* Continue when there was something
988 that didn't fit (full==1) */
990 MyFree(opped_members);
996 * by Carlo Wood (Run), 05 Oct 1998.
1000 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1001 * When the user name or host name are too long (USERLEN and HOSTLEN
1002 * respectively) then they are cut off at the start with a '*'.
1004 * The following transformations are made:
1006 * 1) xxx -> nick!*@*
1007 * 2) xxx.xxx -> *!*@host
1008 * 3) xxx!yyy -> nick!user@*
1009 * 4) xxx@yyy -> *!user@host
1010 * 5) xxx!yyy@zzz -> nick!user@host
1012 char *pretty_mask(char *mask)
1014 static char star[2] = { '*', 0 };
1015 static char retmask[NUH_BUFSIZE];
1016 char *last_dot = NULL;
1019 /* Case 1: default */
1024 /* Do a _single_ pass through the characters of the mask: */
1025 for (ptr = mask; *ptr; ++ptr)
1029 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1033 else if (*ptr == '@')
1035 /* Case 4: Found last '@' (without finding a '!' yet) */
1040 else if (*ptr == '.')
1042 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1052 /* Case 4 or 5: Found last '@' */
1058 if (user == star && last_dot)
1068 char *nick_end = (user != star) ? user - 1 : ptr;
1069 if (nick_end - nick > NICKLEN)
1075 char *user_end = (host != star) ? host - 1 : ptr;
1076 if (user_end - user > USERLEN)
1078 user = user_end - USERLEN;
1083 if (host != star && ptr - host > HOSTLEN)
1085 host = ptr - HOSTLEN;
1088 return make_nick_user_host(retmask, nick, user, host);
1091 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1098 for (lp = chptr->banlist; lp; lp = lp->next)
1099 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1100 lp->value.ban.who, lp->value.ban.when);
1102 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1105 /* We are now treating the <key> part of /join <channel list> <key> as a key
1106 * ring; that is, we try one key against the actual channel key, and if that
1107 * doesn't work, we try the next one, and so on. -Kev -Texaco
1108 * Returns: 0 on match, 1 otherwise
1109 * This version contributed by SeKs <intru@info.polymtl.ca>
1111 static int compall(char *key, char *keyring)
1116 p1 = key; /* point to the key... */
1117 while (*p1 && *p1 == *keyring)
1118 { /* step through the key and ring until they
1124 if (!*p1 && (!*keyring || *keyring == ','))
1125 /* ok, if we're at the end of the and also at the end of one of the keys
1126 in the keyring, we have a match */
1129 if (!*keyring) /* if we're at the end of the key ring, there
1130 weren't any matches, so we return 1 */
1133 /* Not at the end of the key ring, so step
1134 through to the next key in the ring: */
1135 while (*keyring && *(keyring++) != ',');
1137 goto top; /* and check it against the key */
1140 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1143 int overrideJoin = 0;
1146 * Now a banned user CAN join if invited -- Nemesi
1147 * Now a user CAN escape channel limit if invited -- bfriendly
1148 * Now a user CAN escape anything if invited -- Isomer
1151 for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1152 if (lp->value.chptr == chptr)
1155 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1156 a HACK(4) notice will be sent if he would not have been supposed
1157 to join normally. */
1158 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1159 !BadPtr(key) && compall("OVERRIDE",key) == 0)
1160 overrideJoin = MAGIC_OPER_OVERRIDE;
1162 if (chptr->mode.mode & MODE_INVITEONLY)
1163 return overrideJoin + ERR_INVITEONLYCHAN;
1165 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1166 return overrideJoin + ERR_CHANNELISFULL;
1168 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1169 return overrideJoin + ERR_NEEDREGGEDNICK;
1171 if (is_banned(sptr, chptr, NULL))
1172 return overrideJoin + ERR_BANNEDFROMCHAN;
1175 * now using compall (above) to test against a whole key ring -Kev
1177 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1178 return overrideJoin + ERR_BADCHANNELKEY;
1181 return ERR_DONTCHEAT;
1187 * Remove bells and commas from channel name
1189 void clean_channelname(char *cn)
1193 for (i = 0; cn[i]; i++) {
1194 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1198 if (IsChannelLower(cn[i])) {
1199 cn[i] = ToLower(cn[i]);
1205 if ((unsigned char)(cn[i]) == 0xd0)
1206 cn[i] = (char) 0xf0;
1213 * Get Channel block for i (and allocate a new channel
1214 * block, if it didn't exists before).
1216 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1218 struct Channel *chptr;
1221 if (EmptyString(chname))
1224 len = strlen(chname);
1225 if (MyUser(cptr) && len > CHANNELLEN)
1228 *(chname + CHANNELLEN) = '\0';
1230 if ((chptr = FindChannel(chname)))
1232 if (flag == CGT_CREATE)
1234 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1236 ++UserStats.channels;
1237 memset(chptr, 0, sizeof(struct Channel));
1238 strcpy(chptr->chname, chname);
1239 if (GlobalChannelList)
1240 GlobalChannelList->prev = chptr;
1242 chptr->next = GlobalChannelList;
1243 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1244 GlobalChannelList = chptr;
1250 void add_invite(struct Client *cptr, struct Channel *chptr)
1252 struct SLink *inv, **tmp;
1254 del_invite(cptr, chptr);
1256 * Delete last link in chain if the list is max length
1258 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1259 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1260 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1262 * Add client to channel invite list
1265 inv->value.cptr = cptr;
1266 inv->next = chptr->invites;
1267 chptr->invites = inv;
1269 * Add channel to the end of the client invite list
1271 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1273 inv->value.chptr = chptr;
1276 (cli_user(cptr))->invites++;
1280 * Delete Invite block from channel invite list and client invite list
1282 void del_invite(struct Client *cptr, struct Channel *chptr)
1284 struct SLink **inv, *tmp;
1286 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1287 if (tmp->value.cptr == cptr)
1292 (cli_user(cptr))->invites--;
1296 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1297 if (tmp->value.chptr == chptr)
1306 /* List and skip all channels that are listen */
1307 void list_next_channels(struct Client *cptr, int nr)
1309 struct ListingArgs *args = cli_listing(cptr);
1310 struct Channel *chptr = args->chptr;
1311 chptr->mode.mode &= ~MODE_LISTED;
1312 while (is_listed(chptr) || --nr >= 0)
1314 for (; chptr; chptr = chptr->next)
1316 if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1317 SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1319 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1320 chptr->creationtime > args->min_time &&
1321 chptr->creationtime < args->max_time &&
1322 (!args->topic_limits || (*chptr->topic &&
1323 chptr->topic_time > args->min_topic_time &&
1324 chptr->topic_time < args->max_topic_time)))
1326 if (ShowChannel(cptr,chptr))
1327 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1329 chptr = chptr->next;
1335 MyFree(cli_listing(cptr));
1336 cli_listing(cptr) = NULL;
1337 send_reply(cptr, RPL_LISTEND);
1343 (cli_listing(cptr))->chptr = chptr;
1344 chptr->mode.mode |= MODE_LISTED;
1357 * X --a--> A --b--> B --d--> D
1361 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1362 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1364 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1365 * Remove the user immediately when no users are left on the channel.
1366 * b) On server B : remove the user (who/lp) from the channel, send a
1367 * PART upstream (to A) and pass on the KICK.
1368 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1369 * channel, and pass on the KICK.
1370 * d) On server D : remove the user (who/lp) from the channel, and pass on
1374 * - Setting the ZOMBIE flag never hurts, we either remove the
1375 * client after that or we don't.
1376 * - The KICK message was already passed on, as should be in all cases.
1377 * - `who' is removed in all cases except case a) when users are left.
1378 * - A PART is only sent upstream in case b).
1384 * 1 --- 2 --- 3 --- 4 --- 5
1388 * We also need to turn 'who' into a zombie on servers 1 and 6,
1389 * because a KICK from 'who' (kicking someone else in that direction)
1390 * can arrive there afterwards - which should not be bounced itself.
1391 * Therefore case a) also applies for servers 1 and 6.
1395 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1396 struct Client* sptr, struct Channel* chptr)
1398 assert(0 != member);
1403 /* Default for case a): */
1406 /* Case b) or c) ?: */
1407 if (MyUser(who)) /* server 4 */
1409 if (IsServer(cptr)) /* Case b) ? */
1410 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1411 remove_user_from_channel(who, chptr);
1414 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1416 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1417 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1418 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1420 remove_user_from_channel(who, chptr);
1425 /* Case a) (servers 1, 2, 3 and 6) */
1426 if (channel_all_zombies(chptr))
1427 remove_user_from_channel(who, chptr);
1429 /* XXX Can't actually call Debug here; if the channel is all zombies,
1430 * chptr will no longer exist when we get here.
1431 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1435 int number_of_zombies(struct Channel *chptr)
1437 struct Membership* member;
1441 for (member = chptr->members; member; member = member->next_member) {
1442 if (IsZombie(member))
1449 * This helper function builds an argument string in strptr, consisting
1450 * of the original string, a space, and str1 and str2 concatenated (if,
1451 * of course, str2 is not NULL)
1454 build_string(char *strptr, int *strptr_i, char *str1, char *str2, char c)
1457 strptr[(*strptr_i)++] = c;
1460 strptr[(*strptr_i)++] = *(str1++);
1464 strptr[(*strptr_i)++] = *(str2++);
1466 strptr[(*strptr_i)] = '\0';
1470 * This is the workhorse of our ModeBuf suite; this actually generates the
1471 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1474 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1476 /* we only need the flags that don't take args right now */
1477 static int flags[] = {
1478 /* MODE_CHANOP, 'o', */
1479 /* MODE_VOICE, 'v', */
1482 MODE_MODERATED, 'm',
1483 MODE_TOPICLIMIT, 't',
1484 MODE_INVITEONLY, 'i',
1485 MODE_NOPRIVMSGS, 'n',
1487 /* MODE_KEY, 'k', */
1488 /* MODE_BAN, 'b', */
1489 /* MODE_LIMIT, 'l', */
1490 /* MODE_APASS, 'A', */
1491 /* MODE_UPASS, 'u', */
1497 struct Client *app_source; /* where the MODE appears to come from */
1499 char addbuf[20]; /* accumulates +psmtin, etc. */
1501 char rembuf[20]; /* accumulates -psmtin, etc. */
1503 char *bufptr; /* we make use of indirection to simplify the code */
1506 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1508 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1510 char *strptr; /* more indirection to simplify the code */
1513 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1516 char limitbuf[20]; /* convert limits to strings */
1518 unsigned int limitdel = MODE_LIMIT;
1522 /* If the ModeBuf is empty, we have nothing to do */
1523 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1526 /* Ok, if we were given the OPMODE flag, hide the source if its a user */
1527 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE && !IsServer(mbuf->mb_source))
1530 app_source = mbuf->mb_source;
1533 * Account for user we're bouncing; we have to get it in on the first
1534 * bounced MODE, or we could have problems
1536 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1537 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1539 /* Calculate the simple flags */
1540 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1541 if (*flag_p & mbuf->mb_add)
1542 addbuf[addbuf_i++] = flag_p[1];
1543 else if (*flag_p & mbuf->mb_rem)
1544 rembuf[rembuf_i++] = flag_p[1];
1547 /* Now go through the modes with arguments... */
1548 for (i = 0; i < mbuf->mb_count; i++) {
1549 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1551 bufptr_i = &addbuf_i;
1554 bufptr_i = &rembuf_i;
1557 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1558 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1560 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1561 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1563 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1564 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1566 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1567 tmp = strlen(MB_STRING(mbuf, i));
1569 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1570 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1573 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1585 bufptr[(*bufptr_i)++] = mode_char;
1586 totalbuflen -= tmp + 1;
1588 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1589 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1590 strlen(MB_STRING(mbuf, i)));
1592 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1593 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1595 bufptr[(*bufptr_i)++] = 'k';
1596 totalbuflen -= tmp + 1;
1598 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1599 /* if it's a limit, we also format the number */
1600 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1602 tmp = strlen(limitbuf);
1604 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1605 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1607 bufptr[(*bufptr_i)++] = 'l';
1608 totalbuflen -= tmp + 1;
1613 /* terminate the mode strings */
1614 addbuf[addbuf_i] = '\0';
1615 rembuf[rembuf_i] = '\0';
1617 /* If we're building a user visible MODE or HACK... */
1618 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1619 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1620 MODEBUF_DEST_LOG)) {
1621 /* Set up the parameter strings */
1627 for (i = 0; i < mbuf->mb_count; i++) {
1628 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1631 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1633 strptr_i = &addstr_i;
1636 strptr_i = &remstr_i;
1639 /* deal with clients... */
1640 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1641 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1643 /* deal with bans... */
1644 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1645 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1647 /* deal with keys... */
1648 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1649 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1650 "*" : MB_STRING(mbuf, i), 0, ' ');
1652 /* deal with invisible passwords */
1653 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1654 build_string(strptr, strptr_i, "*", 0, ' ');
1657 * deal with limit; note we cannot include the limit parameter if we're
1660 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1661 (MODE_ADD | MODE_LIMIT))
1662 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1665 /* send the messages off to their destination */
1666 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1667 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1669 #ifdef HEAD_IN_SAND_SNOTICES
1670 cli_name(mbuf->mb_source),
1672 cli_name(app_source),
1674 mbuf->mb_channel->chname,
1675 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1676 addbuf, remstr, addstr,
1677 mbuf->mb_channel->creationtime);
1679 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1680 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1681 "%s%s%s%s%s%s [%Tu]",
1682 #ifdef HEAD_IN_SAND_SNOTICES
1683 cli_name(mbuf->mb_source),
1685 cli_name(app_source),
1687 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1688 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1689 mbuf->mb_channel->creationtime);
1691 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1692 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1694 #ifdef HEAD_IN_SAND_SNOTICES
1695 cli_name(mbuf->mb_source),
1697 cli_name(app_source),
1699 mbuf->mb_channel->chname,
1700 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1701 addbuf, remstr, addstr,
1702 mbuf->mb_channel->creationtime);
1704 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1705 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1706 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1707 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1708 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1710 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1711 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1712 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1713 rembuf_i ? "-" : "", rembuf,
1714 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1717 /* Now are we supposed to propagate to other servers? */
1718 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1719 /* set up parameter string */
1726 * limit is supressed if we're removing it; we have to figure out which
1727 * direction is the direction for it to be removed, though...
1729 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1731 for (i = 0; i < mbuf->mb_count; i++) {
1732 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1735 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1737 strptr_i = &addstr_i;
1740 strptr_i = &remstr_i;
1743 /* deal with modes that take clients */
1744 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1745 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1747 /* deal with modes that take strings */
1748 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1749 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1752 * deal with the limit. Logic here is complicated; if HACK2 is set,
1753 * we're bouncing the mode, so sense is reversed, and we have to
1754 * include the original limit if it looks like it's being removed
1756 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1757 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1760 /* we were told to deop the source */
1761 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1762 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1763 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1764 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1766 /* mark that we've done this, so we don't do it again */
1767 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1770 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1771 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1772 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1773 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1774 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1775 addbuf, remstr, addstr);
1776 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1778 * If HACK2 was set, we're bouncing; we send the MODE back to the
1779 * connection we got it from with the senses reversed and a TS of 0;
1782 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1783 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1784 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1785 mbuf->mb_channel->creationtime);
1788 * We're propagating a normal MODE command to the rest of the network;
1789 * we send the actual channel TS unless this is a HACK3 or a HACK4
1791 if (IsServer(mbuf->mb_source))
1792 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1793 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1794 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1795 addbuf, remstr, addstr,
1796 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1797 mbuf->mb_channel->creationtime);
1799 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1800 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1801 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1802 addbuf, remstr, addstr);
1806 /* We've drained the ModeBuf... */
1811 /* reinitialize the mode-with-arg slots */
1812 for (i = 0; i < MAXMODEPARAMS; i++) {
1813 /* If we saved any, pack them down */
1814 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1815 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1816 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1818 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1820 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1821 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1823 MB_TYPE(mbuf, i) = 0;
1824 MB_UINT(mbuf, i) = 0;
1827 /* If we're supposed to flush it all, do so--all hail tail recursion */
1828 if (all && mbuf->mb_count)
1829 return modebuf_flush_int(mbuf, 1);
1835 * This routine just initializes a ModeBuf structure with the information
1836 * needed and the options given.
1839 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1840 struct Client *connect, struct Channel *chan, unsigned int dest)
1845 assert(0 != source);
1851 mbuf->mb_source = source;
1852 mbuf->mb_connect = connect;
1853 mbuf->mb_channel = chan;
1854 mbuf->mb_dest = dest;
1857 /* clear each mode-with-parameter slot */
1858 for (i = 0; i < MAXMODEPARAMS; i++) {
1859 MB_TYPE(mbuf, i) = 0;
1860 MB_UINT(mbuf, i) = 0;
1865 * This routine simply adds modes to be added or deleted; do a binary OR
1866 * with either MODE_ADD or MODE_DEL
1869 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1872 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1874 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1875 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1877 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1880 if (mode & MODE_ADD) {
1881 mbuf->mb_rem &= ~mode;
1882 mbuf->mb_add |= mode;
1884 mbuf->mb_add &= ~mode;
1885 mbuf->mb_rem |= mode;
1890 * This routine adds a mode to be added or deleted that takes a unsigned
1891 * int parameter; mode may *only* be the relevant mode flag ORed with one
1892 * of MODE_ADD or MODE_DEL
1895 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1898 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1900 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1901 MB_UINT(mbuf, mbuf->mb_count) = uint;
1903 /* when we've reached the maximal count, flush the buffer */
1904 if (++mbuf->mb_count >=
1905 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1906 modebuf_flush_int(mbuf, 0);
1910 * This routine adds a mode to be added or deleted that takes a string
1911 * parameter; mode may *only* be the relevant mode flag ORed with one of
1912 * MODE_ADD or MODE_DEL
1915 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1919 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1921 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1922 MB_STRING(mbuf, mbuf->mb_count) = string;
1924 /* when we've reached the maximal count, flush the buffer */
1925 if (++mbuf->mb_count >=
1926 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1927 modebuf_flush_int(mbuf, 0);
1931 * This routine adds a mode to be added or deleted that takes a client
1932 * parameter; mode may *only* be the relevant mode flag ORed with one of
1933 * MODE_ADD or MODE_DEL
1936 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1937 struct Client *client)
1940 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1942 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1943 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1945 /* when we've reached the maximal count, flush the buffer */
1946 if (++mbuf->mb_count >=
1947 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1948 modebuf_flush_int(mbuf, 0);
1952 * This is the exported binding for modebuf_flush()
1955 modebuf_flush(struct ModeBuf *mbuf)
1957 return modebuf_flush_int(mbuf, 1);
1961 * This extracts the simple modes contained in mbuf
1964 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1966 static int flags[] = {
1967 /* MODE_CHANOP, 'o', */
1968 /* MODE_VOICE, 'v', */
1971 MODE_MODERATED, 'm',
1972 MODE_TOPICLIMIT, 't',
1973 MODE_INVITEONLY, 'i',
1974 MODE_NOPRIVMSGS, 'n',
1978 /* MODE_BAN, 'b', */
1984 int i, bufpos = 0, len;
1986 char *key = 0, limitbuf[20];
1987 char *apass, *upass;
1996 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
1997 if (MB_TYPE(mbuf, i) & MODE_ADD) {
1998 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2000 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2001 key = MB_STRING(mbuf, i);
2002 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2003 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2004 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2005 upass = MB_STRING(mbuf, i);
2006 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2007 apass = MB_STRING(mbuf, i);
2014 buf[bufpos++] = '+'; /* start building buffer */
2016 for (flag_p = flags; flag_p[0]; flag_p += 2)
2018 buf[bufpos++] = flag_p[1];
2020 for (i = 0, len = bufpos; i < len; i++) {
2022 build_string(buf, &bufpos, key, 0, ' ');
2023 else if (buf[i] == 'l')
2024 build_string(buf, &bufpos, limitbuf, 0, ' ');
2025 else if (buf[i] == 'u')
2026 build_string(buf, &bufpos, upass, 0, ' ');
2027 else if (buf[i] == 'A')
2028 build_string(buf, &bufpos, apass, 0, ' ');
2037 * Simple function to invalidate bans
2040 mode_ban_invalidate(struct Channel *chan)
2042 struct Membership *member;
2044 for (member = chan->members; member; member = member->next_member)
2045 ClearBanValid(member);
2049 * Simple function to drop invite structures
2052 mode_invite_clear(struct Channel *chan)
2054 while (chan->invites)
2055 del_invite(chan->invites->value.cptr, chan);
2058 /* What we've done for mode_parse so far... */
2059 #define DONE_LIMIT 0x01 /* We've set the limit */
2060 #define DONE_KEY 0x02 /* We've set the key */
2061 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2062 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2063 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2064 #define DONE_UPASS 0x20 /* We've set user pass */
2065 #define DONE_APASS 0x40 /* We've set admin pass */
2068 struct ModeBuf *mbuf;
2069 struct Client *cptr;
2070 struct Client *sptr;
2071 struct Channel *chptr;
2072 struct Membership *member;
2083 struct SLink banlist[MAXPARA];
2086 struct Client *client;
2087 } cli_change[MAXPARA];
2091 * Here's a helper function to deal with sending along "Not oper" or
2092 * "Not member" messages
2095 send_notoper(struct ParseState *state)
2097 if (state->done & DONE_NOTOPER)
2100 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2101 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2103 state->done |= DONE_NOTOPER;
2107 * Helper function to convert limits
2110 mode_parse_limit(struct ParseState *state, int *flag_p)
2112 unsigned int t_limit;
2114 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2115 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2118 if (state->parc <= 0) { /* warn if not enough args */
2119 if (MyUser(state->sptr))
2120 need_more_params(state->sptr, "MODE +l");
2124 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2128 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2129 (!t_limit || t_limit == state->chptr->mode.limit))
2132 t_limit = state->chptr->mode.limit;
2134 /* If they're not an oper, they can't change modes */
2135 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2136 send_notoper(state);
2140 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2142 state->done |= DONE_LIMIT;
2147 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2149 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2150 if (state->dir & MODE_ADD) {
2151 state->chptr->mode.mode |= flag_p[0];
2152 state->chptr->mode.limit = t_limit;
2154 state->chptr->mode.mode &= ~flag_p[0];
2155 state->chptr->mode.limit = 0;
2161 * Helper function to convert keys
2164 mode_parse_key(struct ParseState *state, int *flag_p)
2169 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2172 if (state->parc <= 0) { /* warn if not enough args */
2173 if (MyUser(state->sptr))
2174 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2179 t_str = state->parv[state->args_used++]; /* grab arg */
2183 /* If they're not an oper, they can't change modes */
2184 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2185 send_notoper(state);
2189 if (state->done & DONE_KEY) /* allow key to be set only once */
2191 state->done |= DONE_KEY;
2195 /* clean up the key string */
2197 while (*++s > ' ' && *s != ':' && --t_len)
2201 if (!*t_str) { /* warn if empty */
2202 if (MyUser(state->sptr))
2203 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2211 /* can't add a key if one is set, nor can one remove the wrong key */
2212 if (!(state->flags & MODE_PARSE_FORCE))
2213 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2214 (state->dir == MODE_DEL &&
2215 ircd_strcmp(state->chptr->mode.key, t_str))) {
2216 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2220 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2221 !ircd_strcmp(state->chptr->mode.key, t_str))
2222 return; /* no key change */
2224 if (state->flags & MODE_PARSE_BOUNCE) {
2225 if (*state->chptr->mode.key) /* reset old key */
2226 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2227 state->chptr->mode.key, 0);
2228 else /* remove new bogus key */
2229 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2230 } else /* send new key */
2231 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2233 if (state->flags & MODE_PARSE_SET) {
2234 if (state->dir == MODE_ADD) /* set the new key */
2235 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2236 else /* remove the old key */
2237 *state->chptr->mode.key = '\0';
2242 * Helper function to convert user passes
2245 mode_parse_upass(struct ParseState *state, int *flag_p)
2250 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2253 if (state->parc <= 0) { /* warn if not enough args */
2254 if (MyUser(state->sptr))
2255 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2260 t_str = state->parv[state->args_used++]; /* grab arg */
2264 /* If they're not an oper, they can't change modes */
2265 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2266 send_notoper(state);
2270 /* If they are not the channel manager, they are not allowed to change it */
2271 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2272 if (*state->chptr->mode.apass) {
2273 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2274 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2276 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2277 "Re-create the channel. The channel must be *empty* for",
2278 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2279 "before it can be recreated.");
2284 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2286 state->done |= DONE_UPASS;
2288 t_len = PASSLEN + 1;
2290 /* clean up the upass string */
2292 while (*++s > ' ' && *s != ':' && --t_len)
2296 if (!*t_str) { /* warn if empty */
2297 if (MyUser(state->sptr))
2298 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2306 if (!(state->flags & MODE_PARSE_FORCE))
2307 /* can't add the upass while apass is not set */
2308 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2309 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2312 /* can't add a upass if one is set, nor can one remove the wrong upass */
2313 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2314 (state->dir == MODE_DEL &&
2315 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2316 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2320 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2321 !ircd_strcmp(state->chptr->mode.upass, t_str))
2322 return; /* no upass change */
2324 if (state->flags & MODE_PARSE_BOUNCE) {
2325 if (*state->chptr->mode.upass) /* reset old upass */
2326 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2327 state->chptr->mode.upass, 0);
2328 else /* remove new bogus upass */
2329 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2330 } else /* send new upass */
2331 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2333 if (state->flags & MODE_PARSE_SET) {
2334 if (state->dir == MODE_ADD) /* set the new upass */
2335 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2336 else /* remove the old upass */
2337 *state->chptr->mode.upass = '\0';
2342 * Helper function to convert admin passes
2345 mode_parse_apass(struct ParseState *state, int *flag_p)
2350 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2353 if (state->parc <= 0) { /* warn if not enough args */
2354 if (MyUser(state->sptr))
2355 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2360 t_str = state->parv[state->args_used++]; /* grab arg */
2364 /* If they're not an oper, they can't change modes */
2365 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2366 send_notoper(state);
2370 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2371 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2372 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2376 /* If they are not the channel manager, they are not allowed to change it */
2377 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2378 if (*state->chptr->mode.apass) {
2379 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2380 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2382 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2383 "Re-create the channel. The channel must be *empty* for",
2384 "at least a whole minute", "before it can be recreated.");
2389 if (state->done & DONE_APASS) /* allow apass to be set only once */
2391 state->done |= DONE_APASS;
2393 t_len = PASSLEN + 1;
2395 /* clean up the apass string */
2397 while (*++s > ' ' && *s != ':' && --t_len)
2401 if (!*t_str) { /* warn if empty */
2402 if (MyUser(state->sptr))
2403 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2411 if (!(state->flags & MODE_PARSE_FORCE)) {
2412 /* can't remove the apass while upass is still set */
2413 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2414 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2417 /* can't add an apass if one is set, nor can one remove the wrong apass */
2418 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2419 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2420 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2425 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2426 !ircd_strcmp(state->chptr->mode.apass, t_str))
2427 return; /* no apass change */
2429 if (state->flags & MODE_PARSE_BOUNCE) {
2430 if (*state->chptr->mode.apass) /* reset old apass */
2431 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2432 state->chptr->mode.apass, 0);
2433 else /* remove new bogus apass */
2434 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2435 } else /* send new apass */
2436 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2438 if (state->flags & MODE_PARSE_SET) {
2439 if (state->dir == MODE_ADD) { /* set the new apass */
2440 /* Make it VERY clear to the user that this is a one-time password */
2441 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2442 if (MyUser(state->sptr)) {
2443 send_reply(state->sptr, RPL_APASSWARN,
2444 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2445 "Are you SURE you want to use this as Admin password? ",
2446 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2447 send_reply(state->sptr, RPL_APASSWARN,
2448 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2449 "\" to remove the password and then immediately set a new one. "
2450 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2451 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2452 "Now set the channel user password (+u).");
2454 } else { /* remove the old apass */
2455 *state->chptr->mode.apass = '\0';
2456 if (MyUser(state->sptr))
2457 send_reply(state->sptr, RPL_APASSWARN,
2458 "WARNING: You removed the channel Admin password MODE (+A). ",
2459 "If you would disconnect or leave the channel without setting a new password then you will ",
2460 "not be able to set it again and lose ownership of this channel! ",
2461 "SET A NEW PASSWORD NOW!", "");
2467 * Helper function to convert bans
2470 mode_parse_ban(struct ParseState *state, int *flag_p)
2473 struct SLink *ban, *newban = 0;
2475 if (state->parc <= 0) { /* Not enough args, send ban list */
2476 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2477 send_ban_list(state->sptr, state->chptr);
2478 state->done |= DONE_BANLIST;
2484 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2487 t_str = state->parv[state->args_used++]; /* grab arg */
2491 /* If they're not an oper, they can't change modes */
2492 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2493 send_notoper(state);
2497 if ((s = strchr(t_str, ' ')))
2500 if (!*t_str || *t_str == ':') { /* warn if empty */
2501 if (MyUser(state->sptr))
2502 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2507 t_str = collapse(pretty_mask(t_str));
2509 /* remember the ban for the moment... */
2510 if (state->dir == MODE_ADD) {
2511 newban = state->banlist + (state->numbans++);
2514 DupString(newban->value.ban.banstr, t_str);
2515 newban->value.ban.who = cli_name(state->sptr);
2516 newban->value.ban.when = TStime();
2518 newban->flags = CHFL_BAN | MODE_ADD;
2520 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2521 newban->flags |= CHFL_BAN_IPMASK;
2524 if (!state->chptr->banlist) {
2525 state->chptr->banlist = newban; /* add our ban with its flags */
2526 state->done |= DONE_BANCLEAN;
2530 /* Go through all bans */
2531 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2532 /* first, clean the ban flags up a bit */
2533 if (!(state->done & DONE_BANCLEAN))
2534 /* Note: We're overloading *lots* of bits here; be careful! */
2535 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2539 * MODE_ADD - Ban was added; if we're bouncing modes,
2540 * then we'll remove it below; otherwise,
2541 * we'll have to allocate a real ban
2543 * MODE_DEL - Ban was marked for deletion; if we're
2544 * bouncing modes, we'll have to re-add it,
2545 * otherwise, we'll have to remove it
2547 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2548 * with a ban already set; if we're
2549 * bouncing modes, we'll have to bounce
2550 * this one; otherwise, we'll just ignore
2551 * it when we process added bans
2554 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2555 ban->flags |= MODE_DEL; /* delete one ban */
2557 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2559 } else if (state->dir == MODE_ADD) {
2560 /* if the ban already exists, don't worry about it */
2561 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2562 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2563 MyFree(newban->value.ban.banstr); /* stopper a leak */
2564 state->numbans--; /* deallocate last ban */
2565 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2567 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2568 if (!(ban->flags & MODE_DEL))
2569 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2570 } else if (!mmatch(t_str, ban->value.ban.banstr))
2571 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2573 if (!ban->next && (newban->flags & MODE_ADD)) {
2574 ban->next = newban; /* add our ban with its flags */
2575 break; /* get out of loop */
2579 state->done |= DONE_BANCLEAN;
2583 * This is the bottom half of the ban processor
2586 mode_process_bans(struct ParseState *state)
2588 struct SLink *ban, *newban, *prevban, *nextban;
2594 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2596 banlen = strlen(ban->value.ban.banstr);
2598 nextban = ban->next;
2600 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2602 prevban->next = 0; /* Break the list; ban isn't a real ban */
2604 state->chptr->banlist = 0;
2609 MyFree(ban->value.ban.banstr);
2612 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2613 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2614 ban->value.ban.banstr,
2615 state->flags & MODE_PARSE_SET);
2617 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2618 if (prevban) /* clip it out of the list... */
2619 prevban->next = ban->next;
2621 state->chptr->banlist = ban->next;
2626 MyFree(ban->value.ban.who);
2630 continue; /* next ban; keep prevban like it is */
2632 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2633 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2635 prevban->next = 0; /* Break the list; ban isn't a real ban */
2637 state->chptr->banlist = 0;
2639 /* If we're supposed to ignore it, do so. */
2640 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2641 !(state->flags & MODE_PARSE_BOUNCE)) {
2645 MyFree(ban->value.ban.banstr);
2647 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2648 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2649 count >= feature_int(FEAT_MAXBANS))) {
2650 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2651 ban->value.ban.banstr);
2655 MyFree(ban->value.ban.banstr);
2657 /* add the ban to the buffer */
2658 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2659 ban->value.ban.banstr,
2660 !(state->flags & MODE_PARSE_SET));
2662 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2663 newban = make_link();
2664 newban->value.ban.banstr = ban->value.ban.banstr;
2665 DupString(newban->value.ban.who, ban->value.ban.who);
2666 newban->value.ban.when = ban->value.ban.when;
2667 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2669 newban->next = state->chptr->banlist; /* and link it in */
2670 state->chptr->banlist = newban;
2679 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2681 if (changed) /* if we changed the ban list, we must invalidate the bans */
2682 mode_ban_invalidate(state->chptr);
2686 * Helper function to process client changes
2689 mode_parse_client(struct ParseState *state, int *flag_p)
2692 struct Client *acptr;
2695 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2698 if (state->parc <= 0) /* return if not enough args */
2701 t_str = state->parv[state->args_used++]; /* grab arg */
2705 /* If they're not an oper, they can't change modes */
2706 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2707 send_notoper(state);
2711 if (MyUser(state->sptr)) /* find client we're manipulating */
2712 acptr = find_chasing(state->sptr, t_str, NULL);
2714 acptr = findNUser(t_str);
2717 return; /* find_chasing() already reported an error to the user */
2719 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2720 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2721 state->cli_change[i].flag & flag_p[0]))
2722 break; /* found a slot */
2724 /* Store what we're doing to them */
2725 state->cli_change[i].flag = state->dir | flag_p[0];
2726 state->cli_change[i].client = acptr;
2730 * Helper function to process the changed client list
2733 mode_process_clients(struct ParseState *state)
2736 struct Membership *member;
2738 for (i = 0; state->cli_change[i].flag; i++) {
2739 assert(0 != state->cli_change[i].client);
2741 /* look up member link */
2742 if (!(member = find_member_link(state->chptr,
2743 state->cli_change[i].client)) ||
2744 (MyUser(state->sptr) && IsZombie(member))) {
2745 if (MyUser(state->sptr))
2746 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2747 cli_name(state->cli_change[i].client),
2748 state->chptr->chname);
2752 if ((state->cli_change[i].flag & MODE_ADD &&
2753 (state->cli_change[i].flag & member->status)) ||
2754 (state->cli_change[i].flag & MODE_DEL &&
2755 !(state->cli_change[i].flag & member->status)))
2756 continue; /* no change made, don't do anything */
2758 /* see if the deop is allowed */
2759 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2760 (MODE_DEL | MODE_CHANOP)) {
2761 /* prevent +k users from being deopped */
2762 if (IsChannelService(state->cli_change[i].client)) {
2763 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2764 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2766 (IsServer(state->sptr) ? cli_name(state->sptr) :
2767 cli_name((cli_user(state->sptr))->server)));
2769 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2770 send_reply(state->sptr, ERR_ISCHANSERVICE,
2771 cli_name(state->cli_change[i].client),
2772 state->chptr->chname);
2777 /* check deop for local user */
2778 if (MyUser(state->sptr)) {
2780 /* don't allow local opers to be deopped on local channels */
2781 if (state->cli_change[i].client != state->sptr &&
2782 IsLocalChannel(state->chptr->chname) &&
2783 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2784 send_reply(state->sptr, ERR_ISOPERLCHAN,
2785 cli_name(state->cli_change[i].client),
2786 state->chptr->chname);
2790 /* don't allow to deop members with an op level that is <= our own level */
2791 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2793 && OpLevel(member) <= OpLevel(state->member)) {
2794 int equal = (OpLevel(member) == OpLevel(state->member));
2795 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2796 cli_name(state->cli_change[i].client),
2797 state->chptr->chname,
2798 OpLevel(state->member), OpLevel(member),
2799 "deop", equal ? "the same" : "a higher");
2805 /* set op-level of member being opped */
2806 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2807 (MODE_ADD | MODE_CHANOP)) {
2808 /* If on a channel with upass set, someone with level x gives ops to someone else,
2809 then that person gets level x-1. On other channels, where upass is not set,
2810 the level stays the same. */
2811 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2812 /* Someone being opped by a server gets op-level 0 */
2813 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2814 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2817 /* accumulate the change */
2818 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2819 state->cli_change[i].client);
2821 /* actually effect the change */
2822 if (state->flags & MODE_PARSE_SET) {
2823 if (state->cli_change[i].flag & MODE_ADD) {
2824 member->status |= (state->cli_change[i].flag &
2825 (MODE_CHANOP | MODE_VOICE));
2826 if (state->cli_change[i].flag & MODE_CHANOP)
2827 ClearDeopped(member);
2829 member->status &= ~(state->cli_change[i].flag &
2830 (MODE_CHANOP | MODE_VOICE));
2832 } /* for (i = 0; state->cli_change[i].flags; i++) */
2836 * Helper function to process the simple modes
2839 mode_parse_mode(struct ParseState *state, int *flag_p)
2841 /* If they're not an oper, they can't change modes */
2842 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2843 send_notoper(state);
2850 if (state->dir == MODE_ADD) {
2851 state->add |= flag_p[0];
2852 state->del &= ~flag_p[0];
2854 if (flag_p[0] & MODE_SECRET) {
2855 state->add &= ~MODE_PRIVATE;
2856 state->del |= MODE_PRIVATE;
2857 } else if (flag_p[0] & MODE_PRIVATE) {
2858 state->add &= ~MODE_SECRET;
2859 state->del |= MODE_SECRET;
2862 state->add &= ~flag_p[0];
2863 state->del |= flag_p[0];
2866 assert(0 == (state->add & state->del));
2867 assert((MODE_SECRET | MODE_PRIVATE) !=
2868 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2872 * This routine is intended to parse MODE or OPMODE commands and effect the
2873 * changes (or just build the bounce buffer). We pass the starting offset
2877 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2878 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2879 struct Membership* member)
2881 static int chan_flags[] = {
2886 MODE_MODERATED, 'm',
2887 MODE_TOPICLIMIT, 't',
2888 MODE_INVITEONLY, 'i',
2889 MODE_NOPRIVMSGS, 'n',
2902 unsigned int t_mode;
2904 struct ParseState state;
2915 state.chptr = chptr;
2916 state.member = member;
2919 state.flags = flags;
2920 state.dir = MODE_ADD;
2924 state.args_used = 0;
2925 state.max_args = MAXMODEPARAMS;
2928 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2929 state.banlist[i].next = 0;
2930 state.banlist[i].value.ban.banstr = 0;
2931 state.banlist[i].value.ban.who = 0;
2932 state.banlist[i].value.ban.when = 0;
2933 state.banlist[i].flags = 0;
2934 state.cli_change[i].flag = 0;
2935 state.cli_change[i].client = 0;
2938 modestr = state.parv[state.args_used++];
2942 for (; *modestr; modestr++) {
2943 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2944 if (flag_p[1] == *modestr)
2947 if (!flag_p[0]) { /* didn't find it? complain and continue */
2948 if (MyUser(state.sptr))
2949 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2954 case '+': /* switch direction to MODE_ADD */
2955 case '-': /* switch direction to MODE_DEL */
2956 state.dir = flag_p[0];
2959 case 'l': /* deal with limits */
2960 mode_parse_limit(&state, flag_p);
2963 case 'k': /* deal with keys */
2964 mode_parse_key(&state, flag_p);
2967 case 'A': /* deal with Admin passes */
2968 mode_parse_apass(&state, flag_p);
2971 case 'u': /* deal with user passes */
2972 mode_parse_upass(&state, flag_p);
2975 case 'b': /* deal with bans */
2976 mode_parse_ban(&state, flag_p);
2979 case 'o': /* deal with ops/voice */
2981 mode_parse_client(&state, flag_p);
2984 default: /* deal with other modes */
2985 mode_parse_mode(&state, flag_p);
2987 } /* switch (*modestr) */
2988 } /* for (; *modestr; modestr++) */
2990 if (state.flags & MODE_PARSE_BURST)
2991 break; /* don't interpret any more arguments */
2993 if (state.parc > 0) { /* process next argument in string */
2994 modestr = state.parv[state.args_used++];
2998 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3001 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3002 break; /* we're then going to bounce the mode! */
3004 recv_ts = atoi(modestr);
3006 if (recv_ts && recv_ts < state.chptr->creationtime)
3007 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3009 break; /* break out of while loop */
3010 } else if (state.flags & MODE_PARSE_STRICT ||
3011 (MyUser(state.sptr) && state.max_args <= 0)) {
3012 state.parc++; /* we didn't actually gobble the argument */
3014 break; /* break out of while loop */
3017 } /* while (*modestr) */
3020 * the rest of the function finishes building resultant MODEs; if the
3021 * origin isn't a member or an oper, skip it.
3023 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3024 return state.args_used; /* tell our parent how many args we gobbled */
3026 t_mode = state.chptr->mode.mode;
3028 if (state.del & t_mode) { /* delete any modes to be deleted... */
3029 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3031 t_mode &= ~state.del;
3033 if (state.add & ~t_mode) { /* add any modes to be added... */
3034 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3036 t_mode |= state.add;
3039 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3040 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3041 !(t_mode & MODE_INVITEONLY))
3042 mode_invite_clear(state.chptr);
3044 state.chptr->mode.mode = t_mode;
3047 if (state.flags & MODE_PARSE_WIPEOUT) {
3048 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3049 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3050 state.chptr->mode.limit);
3051 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3052 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3053 state.chptr->mode.key, 0);
3054 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3055 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3056 state.chptr->mode.upass, 0);
3057 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3058 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3059 state.chptr->mode.apass, 0);
3062 if (state.done & DONE_BANCLEAN) /* process bans */
3063 mode_process_bans(&state);
3065 /* process client changes */
3066 if (state.cli_change[0].flag)
3067 mode_process_clients(&state);
3069 return state.args_used; /* tell our parent how many args we gobbled */
3073 * Initialize a join buffer
3076 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3077 struct Client *connect, unsigned int type, char *comment,
3083 assert(0 != source);
3084 assert(0 != connect);
3086 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3087 jbuf->jb_connect = connect;
3088 jbuf->jb_type = type;
3089 jbuf->jb_comment = comment;
3090 jbuf->jb_create = create;
3092 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3093 type == JOINBUF_TYPE_PART ||
3094 type == JOINBUF_TYPE_PARTALL) ?
3095 STARTJOINLEN : STARTCREATELEN) +
3096 (comment ? strlen(comment) + 2 : 0));
3098 for (i = 0; i < MAXJOINARGS; i++)
3099 jbuf->jb_channels[i] = 0;
3103 * Add a channel to the join buffer
3106 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3113 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3114 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3119 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3120 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3121 /* Send notification to channel */
3122 if (!(flags & CHFL_ZOMBIE))
3123 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3124 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3125 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3126 else if (MyUser(jbuf->jb_source))
3127 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3128 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3129 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3130 /* XXX: Shouldn't we send a PART here anyway? */
3131 /* to users on the channel? Why? From their POV, the user isn't on
3132 * the channel anymore anyway. We don't send to servers until below,
3133 * when we gang all the channel parts together. Note that this is
3134 * exactly the same logic, albeit somewhat more concise, as was in
3135 * the original m_part.c */
3137 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3138 IsLocalChannel(chan->chname)) /* got to remove user here */
3139 remove_user_from_channel(jbuf->jb_source, chan);
3141 /* Add user to channel */
3142 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3144 /* send notification to all servers */
3145 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname))
3146 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3147 "%H %Tu", chan, chan->creationtime);
3149 /* Send the notification to the channel */
3150 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3152 /* send an op, too, if needed */
3153 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE &&
3154 !IsModelessChannel(chan->chname))
3155 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3156 chan, jbuf->jb_source);
3159 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || IsLocalChannel(chan->chname))
3160 return; /* don't send to remote */
3162 /* figure out if channel name will cause buffer to be overflowed */
3163 len = chan ? strlen(chan->chname) + 1 : 2;
3164 if (jbuf->jb_strlen + len > BUFSIZE)
3165 joinbuf_flush(jbuf);
3167 /* add channel to list of channels to send and update counts */
3168 jbuf->jb_channels[jbuf->jb_count++] = chan;
3169 jbuf->jb_strlen += len;
3171 /* if we've used up all slots, flush */
3172 if (jbuf->jb_count >= MAXJOINARGS)
3173 joinbuf_flush(jbuf);
3177 * Flush the channel list to remote servers
3180 joinbuf_flush(struct JoinBuf *jbuf)
3182 char chanlist[BUFSIZE];
3186 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3187 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3188 return 0; /* no joins to process */
3190 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3191 build_string(chanlist, &chanlist_i,
3192 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3193 i == 0 ? '\0' : ',');
3194 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3195 /* Remove user from channel */
3196 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3198 jbuf->jb_channels[i] = 0; /* mark slot empty */
3201 jbuf->jb_count = 0; /* reset base counters */
3202 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3203 STARTJOINLEN : STARTCREATELEN) +
3204 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3206 /* and send the appropriate command */
3207 switch (jbuf->jb_type) {
3208 case JOINBUF_TYPE_CREATE:
3209 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3210 "%s %Tu", chanlist, jbuf->jb_create);
3213 case JOINBUF_TYPE_PART:
3214 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3215 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,