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_reply.h"
35 #include "ircd_snprintf.h"
36 #include "ircd_string.h"
43 #include "querycmds.h"
60 struct Channel* GlobalChannelList = 0;
62 static unsigned int membershipAllocCount;
63 static struct Membership* membershipFreeList;
65 void del_invite(struct Client *, struct Channel *);
67 const char* const PartFmt1 = ":%s " MSG_PART " %s";
68 const char* const PartFmt2 = ":%s " MSG_PART " %s :%s";
69 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
70 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
73 static struct SLink* next_ban;
74 static struct SLink* prev_ban;
75 static struct SLink* removed_bans_list;
78 * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
79 * but the only way to do it without changing set_mode intensively.
81 int LocalChanOperMode = 0;
85 * return the length (>=0) of a chain of links.
87 static int list_length(struct SLink *lp)
91 for (; lp; lp = lp->next)
97 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
103 /* Servers don't have member links */
104 if (IsServer(cptr)||IsMe(cptr))
107 /* +k users are typically on a LOT of channels. So we iterate over who
108 * is in the channel. X/W are +k and are in about 5800 channels each.
109 * however there are typically no more than 1000 people in a channel
112 if (IsChannelService(cptr)) {
115 assert(m->channel == chptr);
121 /* Users on the other hand aren't allowed on more than 15 channels. 50%
122 * of users that are on channels are on 2 or less, 95% are on 7 or less,
123 * and 99% are on 10 or less.
126 m = (cli_user(cptr))->channel;
128 assert(m->user == cptr);
129 if (m->channel == chptr)
138 * find_chasing - Find the client structure for a nick name (user)
139 * using history mechanism if necessary. If the client is not found, an error
140 * message (NO SUCH NICK) is generated. If the client was found
141 * through the history, chasing will be 1 and otherwise 0.
143 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
145 struct Client* who = FindClient(user);
152 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
153 send_reply(sptr, ERR_NOSUCHNICK, user);
162 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
163 * as the parameters. If NULL, they become "*".
165 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
166 static char *make_nick_user_host(char *namebuf, const char *nick,
167 const char *name, const char *host)
169 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
174 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
175 * IP-number as the parameters. If NULL, they become "*".
177 #define NUI_BUFSIZE (NICKLEN + USERLEN + 16 + 3)
178 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
181 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name,
182 ircd_ntoa((const char*) &ip));
187 * Subtract one user from channel i (and free channel
188 * block, if channel became empty).
189 * Returns: true (1) if channel still has members.
190 * false (0) if the channel is now empty.
192 int sub1_from_channel(struct Channel* chptr)
194 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
196 assert(0 != chptr->members);
204 * Also channels without Apass set need to be kept alive,
205 * otherwise Bad Guys(tm) would be able to takeover
206 * existing channels too easily, and then set an Apass!
207 * However, if a channel without Apass becomes empty
208 * then we try to be kind to them and remove possible
211 chptr->mode.mode &= ~MODE_INVITEONLY;
212 chptr->mode.limit = 0;
214 * We do NOT reset a possible key or bans because when
215 * the 'channel owners' can't get in because of a key
216 * or ban then apparently there was a fight/takeover
217 * on the channel and we want them to contact IRC opers
218 * who then will educate them on the use of Apass/upass.
221 if (feature_bool(FEAT_OPLEVELS)) {
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 */
227 destruct_channel(chptr);
232 int destruct_channel(struct Channel* chptr)
237 assert(0 == chptr->members);
239 /* Channel became (or was) empty: Remove channel */
240 if (is_listed(chptr))
243 for (i = 0; i <= HighestFd; i++)
245 struct Client *acptr = 0;
246 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
247 (cli_listing(acptr))->chptr == chptr)
249 list_next_channels(acptr, 1);
250 break; /* Only one client can list a channel */
255 * Now, find all invite links from channel structure
257 while ((tmp = chptr->invites))
258 del_invite(tmp->value.cptr, chptr);
260 tmp = chptr->banlist;
265 MyFree(obtmp->value.ban.banstr);
266 MyFree(obtmp->value.ban.who);
270 chptr->prev->next = chptr->next;
272 GlobalChannelList = chptr->next;
274 chptr->next->prev = chptr->prev;
276 --UserStats.channels;
278 * make sure that channel actually got removed from hash table
280 assert(chptr->hnext == chptr);
288 * `cptr' must be the client adding the ban.
290 * If `change' is true then add `banid' to channel `chptr'.
291 * Returns 0 if the ban was added.
292 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
293 * Return -1 otherwise.
295 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
296 * when `change' is false, otherwise they will be removed from the banlist.
297 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
298 * respectively will return these bans until NULL is returned.
300 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
301 * is reset (unless a non-zero value is returned, in which case the
302 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
306 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
307 int change, int firsttime)
312 int removed_bans = 0;
313 int len = strlen(banid);
318 assert(0 == prev_ban);
319 assert(0 == removed_bans_list);
323 for (banp = &chptr->banlist; *banp;)
325 len += strlen((*banp)->value.ban.banstr);
327 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
329 if (!strcmp((*banp)->value.ban.banstr, banid))
331 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
335 else if (!mmatch((*banp)->value.ban.banstr, banid))
337 if (!mmatch(banid, (*banp)->value.ban.banstr))
339 struct SLink *tmp = *banp;
345 len -= strlen(tmp->value.ban.banstr);
348 /* These will be sent to the user later as -b */
349 tmp->next = removed_bans_list;
350 removed_bans_list = tmp;
353 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
355 tmp->flags |= CHFL_BAN_OVERLAPPED;
366 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
367 banp = &(*banp)->next;
370 if (MyUser(cptr) && !removed_bans &&
371 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
372 (cnt >= feature_int(FEAT_MAXBANS))))
374 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
380 struct Membership* member;
382 ban->next = chptr->banlist;
384 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
385 assert(0 != ban->value.ban.banstr);
386 strcpy(ban->value.ban.banstr, banid);
388 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
389 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 tmphost[HOSTLEN + 1];
446 char nu_host[NUH_BUFSIZE];
447 char nu_realhost[NUH_BUFSIZE];
448 char nu_ip[NUI_BUFSIZE];
456 if (member && IsBanValid(member))
457 return IsBanned(member);
459 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
460 (cli_user(cptr))->host);
463 if (HasHiddenHost(cptr))
465 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
466 (cli_user(cptr))->username,
467 cli_user(cptr)->realhost);
471 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
472 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
473 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
474 cli_user(cptr)->username,
479 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
480 if ((tmp->flags & CHFL_BAN_IPMASK)) {
482 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
483 (cli_user(cptr))->username, cli_ip(cptr));
484 if (match(tmp->value.ban.banstr, ip_s) == 0)
487 else if (match(tmp->value.ban.banstr, s) == 0)
489 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
505 return (tmp != NULL);
509 * adds a user to a channel by adding another link to the channels member
512 void add_user_to_channel(struct Channel* chptr, struct Client* who,
513 unsigned int flags, int oplevel)
520 struct Membership* member = membershipFreeList;
522 membershipFreeList = member->next_member;
524 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
525 ++membershipAllocCount;
530 member->channel = chptr;
531 member->status = flags;
532 member->oplevel = oplevel;
534 member->next_member = chptr->members;
535 if (member->next_member)
536 member->next_member->prev_member = member;
537 member->prev_member = 0;
538 chptr->members = member;
540 member->next_channel = (cli_user(who))->channel;
541 if (member->next_channel)
542 member->next_channel->prev_channel = member;
543 member->prev_channel = 0;
544 (cli_user(who))->channel = member;
546 if (chptr->destruct_event)
547 remove_destruct_event(chptr);
549 ++((cli_user(who))->joined);
553 static int remove_member_from_channel(struct Membership* member)
555 struct Channel* chptr;
557 chptr = member->channel;
559 * unlink channel member list
561 if (member->next_member)
562 member->next_member->prev_member = member->prev_member;
563 if (member->prev_member)
564 member->prev_member->next_member = member->next_member;
566 member->channel->members = member->next_member;
569 * unlink client channel list
571 if (member->next_channel)
572 member->next_channel->prev_channel = member->prev_channel;
573 if (member->prev_channel)
574 member->prev_channel->next_channel = member->next_channel;
576 (cli_user(member->user))->channel = member->next_channel;
578 --(cli_user(member->user))->joined;
580 member->next_member = membershipFreeList;
581 membershipFreeList = member;
583 return sub1_from_channel(chptr);
586 static int channel_all_zombies(struct Channel* chptr)
588 struct Membership* member;
590 for (member = chptr->members; member; member = member->next_member) {
591 if (!IsZombie(member))
598 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
601 struct Membership* member;
604 if ((member = find_member_link(chptr, cptr))) {
605 if (remove_member_from_channel(member)) {
606 if (channel_all_zombies(chptr)) {
608 * XXX - this looks dangerous but isn't if we got the referential
609 * integrity right for channels
611 while (remove_member_from_channel(chptr->members))
618 void remove_user_from_all_channels(struct Client* cptr)
620 struct Membership* chan;
622 assert(0 != cli_user(cptr));
624 while ((chan = (cli_user(cptr))->channel))
625 remove_user_from_channel(cptr, chan->channel);
628 int is_chan_op(struct Client *cptr, struct Channel *chptr)
630 struct Membership* member;
632 if ((member = find_member_link(chptr, cptr)))
633 return (!IsZombie(member) && IsChanOp(member));
638 int is_zombie(struct Client *cptr, struct Channel *chptr)
640 struct Membership* member;
644 if ((member = find_member_link(chptr, cptr)))
645 return IsZombie(member);
649 int has_voice(struct Client* cptr, struct Channel* chptr)
651 struct Membership* member;
654 if ((member = find_member_link(chptr, cptr)))
655 return (!IsZombie(member) && HasVoice(member));
660 int member_can_send_to_channel(struct Membership* member)
664 /* Discourage using the Apass to get op. They should use the upass. */
665 if (IsChannelManager(member) && *member->channel->mode.upass)
668 if (IsVoicedOrOpped(member))
671 * If it's moderated, and you aren't a priviledged user, you can't
674 if (member->channel->mode.mode & MODE_MODERATED)
677 * If you're banned then you can't speak either.
678 * but because of the amount of CPU time that is_banned chews
679 * we only check it for our clients.
681 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
686 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr)
688 struct Membership *member;
691 * Servers can always speak on channels.
696 member = find_channel_member(cptr, chptr);
699 * You can't speak if you're off channel, and it is +n (no external messages)
703 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
704 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
707 return !is_banned(cptr, chptr, NULL);
709 return member_can_send_to_channel(member);
713 * find_no_nickchange_channel
714 * if a member and not (opped or voiced) and (banned or moderated)
715 * return the name of the first channel banned on
717 const char* find_no_nickchange_channel(struct Client* cptr)
720 struct Membership* member;
721 for (member = (cli_user(cptr))->channel; member;
722 member = member->next_channel) {
723 if (!IsVoicedOrOpped(member) &&
724 (is_banned(cptr, member->channel, member) ||
725 (member->channel->mode.mode & MODE_MODERATED)))
726 return member->channel->chname;
734 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
735 * with the parameters in pbuf.
737 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
738 struct Channel *chptr, struct Membership *member)
740 int previous_parameter = 0;
747 if (chptr->mode.mode & MODE_SECRET)
749 else if (chptr->mode.mode & MODE_PRIVATE)
751 if (chptr->mode.mode & MODE_MODERATED)
753 if (chptr->mode.mode & MODE_TOPICLIMIT)
755 if (chptr->mode.mode & MODE_INVITEONLY)
757 if (chptr->mode.mode & MODE_NOPRIVMSGS)
759 if (chptr->mode.mode & MODE_REGONLY)
761 if (chptr->mode.limit) {
763 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
764 previous_parameter = 1;
767 if (*chptr->mode.key) {
769 if (previous_parameter)
771 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
772 strcat(pbuf, chptr->mode.key);
775 previous_parameter = 1;
777 if (*chptr->mode.apass) {
779 if (previous_parameter)
781 if (IsServer(cptr)) {
782 strcat(pbuf, chptr->mode.apass);
785 previous_parameter = 1;
787 if (*chptr->mode.upass) {
789 if (previous_parameter)
791 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
792 strcat(pbuf, chptr->mode.upass);
799 int compare_member_oplevel(const void *mp1, const void *mp2)
801 struct Membership const* member1 = *(struct Membership const**)mp1;
802 struct Membership const* member2 = *(struct Membership const**)mp2;
803 if (member1->oplevel == member2->oplevel)
805 return (member1->oplevel < member2->oplevel) ? -1 : 1;
809 * send "cptr" a full list of the modes for channel chptr.
811 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
813 /* The order in which modes are generated is now mandatory */
814 static unsigned int current_flags[4] =
815 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
821 struct Membership* member;
823 char modebuf[MODEBUFLEN];
824 char parabuf[MODEBUFLEN];
826 int number_of_ops = 0;
827 int opped_members_index = 0;
828 struct Membership** opped_members = NULL;
829 int last_oplevel = 0;
834 if (IsLocalChannel(chptr->chname))
837 member = chptr->members;
838 lp2 = chptr->banlist;
840 *modebuf = *parabuf = '\0';
841 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
843 for (first = 1; full; first = 0) /* Loop for multiple messages */
845 full = 0; /* Assume by default we get it
846 all in one message */
848 /* (Continued) prefix: "<Y> B <channel> <TS>" */
849 /* is there any better way we can do this? */
850 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
851 chptr->creationtime);
853 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
856 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
857 msgq_append(&me, mb, " %s", modebuf);
860 msgq_append(&me, mb, " %s", parabuf);
864 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
866 * First find all opless members.
867 * Run 2 times over all members, to group the members with
868 * and without voice together.
869 * Then run 2 times over all opped members (which are ordered
870 * by op-level) to also group voice and non-voice together.
872 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
876 if (flag_cnt < 2 && IsChanOp(member))
879 * The first loop (to find all non-voice/op), we count the ops.
880 * The second loop (to find all voiced non-ops), store the ops
881 * in a dynamic array.
886 opped_members[opped_members_index++] = member;
888 /* Only handle the members with the flags that we are interested in. */
889 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
891 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
892 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
894 full = 1; /* Make sure we continue after
896 /* Ensure the new BURST line contains the current
897 * ":mode", except when there is no mode yet. */
898 new_mode = (flag_cnt > 0) ? 1 : 0;
899 break; /* Do not add this member to this message */
901 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
902 first = 0; /* From now on, use commas to add new nicks */
905 * Do we have a nick with a new mode ?
906 * Or are we starting a new BURST line?
911 * This means we are at the _first_ member that has only
912 * voice, or the first member that has only ops, or the
913 * first member that has voice and ops (so we get here
914 * at most three times, plus once for every start of
915 * a continued BURST line where only these modes is current.
916 * In the two cases where the current mode includes ops,
917 * we need to add the _absolute_ value of the oplevel to the mode.
919 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
922 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
924 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
926 /* append the absolute value of the oplevel */
927 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
928 last_oplevel = member->oplevel;
931 msgq_append(&me, mb, tbuf);
934 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
937 * This can't be the first member of a (continued) BURST
938 * message because then either flag_cnt == 0 or new_mode == 1
939 * Now we need to append the incremental value of the oplevel.
941 char tbuf[2 + MAXOPLEVELDIGITS];
942 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
943 last_oplevel = member->oplevel;
944 msgq_append(&me, mb, tbuf);
947 /* Go to the next `member'. */
949 member = member->next_member;
951 member = opped_members[++opped_members_index];
956 /* Point `member' at the start of the list again. */
959 member = chptr->members;
960 /* Now, after one loop, we know the number of ops and can
961 * allocate the dynamic array with pointer to the ops. */
962 opped_members = (struct Membership**)
963 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
964 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
968 /* At the end of the second loop, sort the opped members with
969 * increasing op-level, so that we will output them in the
970 * correct order (and all op-level increments stay positive) */
972 qsort(opped_members, number_of_ops,
973 sizeof(struct Membership*), compare_member_oplevel);
974 /* The third and fourth loop run only over the opped members. */
975 member = opped_members[(opped_members_index = 0)];
978 } /* loop over 0,+v,+o,+ov */
982 /* Attach all bans, space seperated " :%ban ban ..." */
983 for (first = 2; lp2; lp2 = lp2->next)
985 len = strlen(lp2->value.ban.banstr);
986 if (msgq_bufleft(mb) < len + 1 + first)
987 /* The +1 stands for the added ' '.
988 * The +first stands for the added ":%".
994 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
995 lp2->value.ban.banstr);
1000 send_buffer(cptr, mb, 0); /* Send this message */
1002 } /* Continue when there was something
1003 that didn't fit (full==1) */
1005 MyFree(opped_members);
1011 * by Carlo Wood (Run), 05 Oct 1998.
1015 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1016 * When the user name or host name are too long (USERLEN and HOSTLEN
1017 * respectively) then they are cut off at the start with a '*'.
1019 * The following transformations are made:
1021 * 1) xxx -> nick!*@*
1022 * 2) xxx.xxx -> *!*@host
1023 * 3) xxx!yyy -> nick!user@*
1024 * 4) xxx@yyy -> *!user@host
1025 * 5) xxx!yyy@zzz -> nick!user@host
1027 char *pretty_mask(char *mask)
1029 static char star[2] = { '*', 0 };
1030 static char retmask[NUH_BUFSIZE];
1031 char *last_dot = NULL;
1034 /* Case 1: default */
1039 /* Do a _single_ pass through the characters of the mask: */
1040 for (ptr = mask; *ptr; ++ptr)
1044 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1048 else if (*ptr == '@')
1050 /* Case 4: Found last '@' (without finding a '!' yet) */
1055 else if (*ptr == '.')
1057 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1067 /* Case 4 or 5: Found last '@' */
1073 if (user == star && last_dot)
1083 char *nick_end = (user != star) ? user - 1 : ptr;
1084 if (nick_end - nick > NICKLEN)
1090 char *user_end = (host != star) ? host - 1 : ptr;
1091 if (user_end - user > USERLEN)
1093 user = user_end - USERLEN;
1098 if (host != star && ptr - host > HOSTLEN)
1100 host = ptr - HOSTLEN;
1103 return make_nick_user_host(retmask, nick, user, host);
1106 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1113 for (lp = chptr->banlist; lp; lp = lp->next)
1114 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1115 lp->value.ban.who, lp->value.ban.when);
1117 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1120 /* We are now treating the <key> part of /join <channel list> <key> as a key
1121 * ring; that is, we try one key against the actual channel key, and if that
1122 * doesn't work, we try the next one, and so on. -Kev -Texaco
1123 * Returns: 0 on match, 1 otherwise
1124 * This version contributed by SeKs <intru@info.polymtl.ca>
1126 static int compall(char *key, char *keyring)
1131 p1 = key; /* point to the key... */
1132 while (*p1 && *p1 == *keyring)
1133 { /* step through the key and ring until they
1139 if (!*p1 && (!*keyring || *keyring == ','))
1140 /* ok, if we're at the end of the and also at the end of one of the keys
1141 in the keyring, we have a match */
1144 if (!*keyring) /* if we're at the end of the key ring, there
1145 weren't any matches, so we return 1 */
1148 /* Not at the end of the key ring, so step
1149 through to the next key in the ring: */
1150 while (*keyring && *(keyring++) != ',');
1152 goto top; /* and check it against the key */
1155 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1158 int overrideJoin = 0;
1161 * Now a banned user CAN join if invited -- Nemesi
1162 * Now a user CAN escape channel limit if invited -- bfriendly
1163 * Now a user CAN escape anything if invited -- Isomer
1166 for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1167 if (lp->value.chptr == chptr)
1170 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1171 a HACK(4) notice will be sent if he would not have been supposed
1172 to join normally. */
1173 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1174 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1175 compall("OVERRIDE",key) == 0)
1176 overrideJoin = MAGIC_OPER_OVERRIDE;
1178 if (chptr->mode.mode & MODE_INVITEONLY)
1179 return overrideJoin + ERR_INVITEONLYCHAN;
1181 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1182 return overrideJoin + ERR_CHANNELISFULL;
1184 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1185 return overrideJoin + ERR_NEEDREGGEDNICK;
1187 if (is_banned(sptr, chptr, NULL))
1188 return overrideJoin + ERR_BANNEDFROMCHAN;
1191 * now using compall (above) to test against a whole key ring -Kev
1193 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1194 return overrideJoin + ERR_BADCHANNELKEY;
1197 return ERR_DONTCHEAT;
1203 * Remove bells and commas from channel name
1205 void clean_channelname(char *cn)
1209 for (i = 0; cn[i]; i++) {
1210 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1214 if (IsChannelLower(cn[i])) {
1215 cn[i] = ToLower(cn[i]);
1221 if ((unsigned char)(cn[i]) == 0xd0)
1222 cn[i] = (char) 0xf0;
1229 * Get Channel block for i (and allocate a new channel
1230 * block, if it didn't exists before).
1232 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1234 struct Channel *chptr;
1237 if (EmptyString(chname))
1240 len = strlen(chname);
1241 if (MyUser(cptr) && len > CHANNELLEN)
1244 *(chname + CHANNELLEN) = '\0';
1246 if ((chptr = FindChannel(chname)))
1248 if (flag == CGT_CREATE)
1250 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1252 ++UserStats.channels;
1253 memset(chptr, 0, sizeof(struct Channel));
1254 strcpy(chptr->chname, chname);
1255 if (GlobalChannelList)
1256 GlobalChannelList->prev = chptr;
1258 chptr->next = GlobalChannelList;
1259 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1260 GlobalChannelList = chptr;
1266 void add_invite(struct Client *cptr, struct Channel *chptr)
1268 struct SLink *inv, **tmp;
1270 del_invite(cptr, chptr);
1272 * Delete last link in chain if the list is max length
1274 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1275 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1276 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1278 * Add client to channel invite list
1281 inv->value.cptr = cptr;
1282 inv->next = chptr->invites;
1283 chptr->invites = inv;
1285 * Add channel to the end of the client invite list
1287 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1289 inv->value.chptr = chptr;
1292 (cli_user(cptr))->invites++;
1296 * Delete Invite block from channel invite list and client invite list
1298 void del_invite(struct Client *cptr, struct Channel *chptr)
1300 struct SLink **inv, *tmp;
1302 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1303 if (tmp->value.cptr == cptr)
1308 (cli_user(cptr))->invites--;
1312 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1313 if (tmp->value.chptr == chptr)
1322 /* List and skip all channels that are listen */
1323 void list_next_channels(struct Client *cptr, int nr)
1325 struct ListingArgs *args = cli_listing(cptr);
1326 struct Channel *chptr = args->chptr;
1327 chptr->mode.mode &= ~MODE_LISTED;
1328 while (is_listed(chptr) || --nr >= 0)
1330 for (; chptr; chptr = chptr->next)
1332 if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1333 SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1335 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1336 chptr->creationtime > args->min_time &&
1337 chptr->creationtime < args->max_time &&
1338 (!args->topic_limits || (*chptr->topic &&
1339 chptr->topic_time > args->min_topic_time &&
1340 chptr->topic_time < args->max_topic_time)))
1342 if (ShowChannel(cptr,chptr))
1343 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1345 chptr = chptr->next;
1351 MyFree(cli_listing(cptr));
1352 cli_listing(cptr) = NULL;
1353 send_reply(cptr, RPL_LISTEND);
1359 (cli_listing(cptr))->chptr = chptr;
1360 chptr->mode.mode |= MODE_LISTED;
1373 * X --a--> A --b--> B --d--> D
1377 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1378 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1380 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1381 * Remove the user immediately when no users are left on the channel.
1382 * b) On server B : remove the user (who/lp) from the channel, send a
1383 * PART upstream (to A) and pass on the KICK.
1384 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1385 * channel, and pass on the KICK.
1386 * d) On server D : remove the user (who/lp) from the channel, and pass on
1390 * - Setting the ZOMBIE flag never hurts, we either remove the
1391 * client after that or we don't.
1392 * - The KICK message was already passed on, as should be in all cases.
1393 * - `who' is removed in all cases except case a) when users are left.
1394 * - A PART is only sent upstream in case b).
1400 * 1 --- 2 --- 3 --- 4 --- 5
1404 * We also need to turn 'who' into a zombie on servers 1 and 6,
1405 * because a KICK from 'who' (kicking someone else in that direction)
1406 * can arrive there afterwards - which should not be bounced itself.
1407 * Therefore case a) also applies for servers 1 and 6.
1411 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1412 struct Client* sptr, struct Channel* chptr)
1414 assert(0 != member);
1419 /* Default for case a): */
1422 /* Case b) or c) ?: */
1423 if (MyUser(who)) /* server 4 */
1425 if (IsServer(cptr)) /* Case b) ? */
1426 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1427 remove_user_from_channel(who, chptr);
1430 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1432 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1433 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1434 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1436 remove_user_from_channel(who, chptr);
1441 /* Case a) (servers 1, 2, 3 and 6) */
1442 if (channel_all_zombies(chptr))
1443 remove_user_from_channel(who, chptr);
1445 /* XXX Can't actually call Debug here; if the channel is all zombies,
1446 * chptr will no longer exist when we get here.
1447 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1451 int number_of_zombies(struct Channel *chptr)
1453 struct Membership* member;
1457 for (member = chptr->members; member; member = member->next_member) {
1458 if (IsZombie(member))
1465 * This helper function builds an argument string in strptr, consisting
1466 * of the original string, a space, and str1 and str2 concatenated (if,
1467 * of course, str2 is not NULL)
1470 build_string(char *strptr, int *strptr_i, const char *str1,
1471 const char *str2, char c)
1474 strptr[(*strptr_i)++] = c;
1477 strptr[(*strptr_i)++] = *(str1++);
1481 strptr[(*strptr_i)++] = *(str2++);
1483 strptr[(*strptr_i)] = '\0';
1487 * This is the workhorse of our ModeBuf suite; this actually generates the
1488 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1491 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1493 /* we only need the flags that don't take args right now */
1494 static int flags[] = {
1495 /* MODE_CHANOP, 'o', */
1496 /* MODE_VOICE, 'v', */
1499 MODE_MODERATED, 'm',
1500 MODE_TOPICLIMIT, 't',
1501 MODE_INVITEONLY, 'i',
1502 MODE_NOPRIVMSGS, 'n',
1504 /* MODE_KEY, 'k', */
1505 /* MODE_BAN, 'b', */
1506 /* MODE_LIMIT, 'l', */
1507 /* MODE_APASS, 'A', */
1508 /* MODE_UPASS, 'u', */
1514 struct Client *app_source; /* where the MODE appears to come from */
1516 char addbuf[20]; /* accumulates +psmtin, etc. */
1518 char rembuf[20]; /* accumulates -psmtin, etc. */
1520 char *bufptr; /* we make use of indirection to simplify the code */
1523 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1525 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1527 char *strptr; /* more indirection to simplify the code */
1530 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1533 char limitbuf[20]; /* convert limits to strings */
1535 unsigned int limitdel = MODE_LIMIT;
1539 /* If the ModeBuf is empty, we have nothing to do */
1540 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1543 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1545 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1548 app_source = mbuf->mb_source;
1551 * Account for user we're bouncing; we have to get it in on the first
1552 * bounced MODE, or we could have problems
1554 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1555 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1557 /* Calculate the simple flags */
1558 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1559 if (*flag_p & mbuf->mb_add)
1560 addbuf[addbuf_i++] = flag_p[1];
1561 else if (*flag_p & mbuf->mb_rem)
1562 rembuf[rembuf_i++] = flag_p[1];
1565 /* Now go through the modes with arguments... */
1566 for (i = 0; i < mbuf->mb_count; i++) {
1567 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1569 bufptr_i = &addbuf_i;
1572 bufptr_i = &rembuf_i;
1575 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1576 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1578 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1579 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1581 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1582 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1584 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1585 tmp = strlen(MB_STRING(mbuf, i));
1587 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1588 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1591 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1603 bufptr[(*bufptr_i)++] = mode_char;
1604 totalbuflen -= tmp + 1;
1606 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1607 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1608 strlen(MB_STRING(mbuf, i)));
1610 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1611 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1613 bufptr[(*bufptr_i)++] = 'k';
1614 totalbuflen -= tmp + 1;
1616 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1617 /* if it's a limit, we also format the number */
1618 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1620 tmp = strlen(limitbuf);
1622 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1623 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1625 bufptr[(*bufptr_i)++] = 'l';
1626 totalbuflen -= tmp + 1;
1631 /* terminate the mode strings */
1632 addbuf[addbuf_i] = '\0';
1633 rembuf[rembuf_i] = '\0';
1635 /* If we're building a user visible MODE or HACK... */
1636 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1637 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1638 MODEBUF_DEST_LOG)) {
1639 /* Set up the parameter strings */
1645 for (i = 0; i < mbuf->mb_count; i++) {
1646 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1649 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1651 strptr_i = &addstr_i;
1654 strptr_i = &remstr_i;
1657 /* deal with clients... */
1658 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1659 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1661 /* deal with bans... */
1662 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1663 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1665 /* deal with keys... */
1666 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1667 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1668 "*" : MB_STRING(mbuf, i), 0, ' ');
1670 /* deal with invisible passwords */
1671 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1672 build_string(strptr, strptr_i, "*", 0, ' ');
1675 * deal with limit; note we cannot include the limit parameter if we're
1678 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1679 (MODE_ADD | MODE_LIMIT))
1680 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1683 /* send the messages off to their destination */
1684 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1685 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1687 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1688 mbuf->mb_source : app_source),
1689 mbuf->mb_channel->chname,
1690 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1691 addbuf, remstr, addstr,
1692 mbuf->mb_channel->creationtime);
1694 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1695 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1696 "%s%s%s%s%s%s [%Tu]",
1697 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1698 mbuf->mb_source : app_source),
1699 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1700 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1701 mbuf->mb_channel->creationtime);
1703 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1704 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1706 #ifdef HEAD_IN_SAND_SNOTICES
1707 cli_name(mbuf->mb_source),
1709 cli_name(app_source),
1711 mbuf->mb_channel->chname,
1712 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1713 addbuf, remstr, addstr,
1714 mbuf->mb_channel->creationtime);
1716 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1717 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1718 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1719 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1720 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1722 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1723 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1724 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1725 rembuf_i ? "-" : "", rembuf,
1726 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1729 /* Now are we supposed to propagate to other servers? */
1730 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1731 /* set up parameter string */
1738 * limit is supressed if we're removing it; we have to figure out which
1739 * direction is the direction for it to be removed, though...
1741 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1743 for (i = 0; i < mbuf->mb_count; i++) {
1744 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1747 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1749 strptr_i = &addstr_i;
1752 strptr_i = &remstr_i;
1755 /* deal with modes that take clients */
1756 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1757 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1759 /* deal with modes that take strings */
1760 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1761 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1764 * deal with the limit. Logic here is complicated; if HACK2 is set,
1765 * we're bouncing the mode, so sense is reversed, and we have to
1766 * include the original limit if it looks like it's being removed
1768 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1769 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1772 /* we were told to deop the source */
1773 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1774 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1775 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1776 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1778 /* mark that we've done this, so we don't do it again */
1779 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1782 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1783 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1784 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1785 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1786 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1787 addbuf, remstr, addstr);
1788 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1790 * If HACK2 was set, we're bouncing; we send the MODE back to the
1791 * connection we got it from with the senses reversed and a TS of 0;
1794 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1795 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1796 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1797 mbuf->mb_channel->creationtime);
1800 * We're propagating a normal MODE command to the rest of the network;
1801 * we send the actual channel TS unless this is a HACK3 or a HACK4
1803 if (IsServer(mbuf->mb_source))
1804 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1805 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1806 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1807 addbuf, remstr, addstr,
1808 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1809 mbuf->mb_channel->creationtime);
1811 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1812 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1813 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1814 addbuf, remstr, addstr);
1818 /* We've drained the ModeBuf... */
1823 /* reinitialize the mode-with-arg slots */
1824 for (i = 0; i < MAXMODEPARAMS; i++) {
1825 /* If we saved any, pack them down */
1826 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1827 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1828 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1830 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1832 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1833 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1835 MB_TYPE(mbuf, i) = 0;
1836 MB_UINT(mbuf, i) = 0;
1839 /* If we're supposed to flush it all, do so--all hail tail recursion */
1840 if (all && mbuf->mb_count)
1841 return modebuf_flush_int(mbuf, 1);
1847 * This routine just initializes a ModeBuf structure with the information
1848 * needed and the options given.
1851 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1852 struct Client *connect, struct Channel *chan, unsigned int dest)
1857 assert(0 != source);
1861 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1865 mbuf->mb_source = source;
1866 mbuf->mb_connect = connect;
1867 mbuf->mb_channel = chan;
1868 mbuf->mb_dest = dest;
1871 /* clear each mode-with-parameter slot */
1872 for (i = 0; i < MAXMODEPARAMS; i++) {
1873 MB_TYPE(mbuf, i) = 0;
1874 MB_UINT(mbuf, i) = 0;
1879 * This routine simply adds modes to be added or deleted; do a binary OR
1880 * with either MODE_ADD or MODE_DEL
1883 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1886 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1888 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1889 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1891 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1894 if (mode & MODE_ADD) {
1895 mbuf->mb_rem &= ~mode;
1896 mbuf->mb_add |= mode;
1898 mbuf->mb_add &= ~mode;
1899 mbuf->mb_rem |= mode;
1904 * This routine adds a mode to be added or deleted that takes a unsigned
1905 * int parameter; mode may *only* be the relevant mode flag ORed with one
1906 * of MODE_ADD or MODE_DEL
1909 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1912 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1914 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1915 MB_UINT(mbuf, mbuf->mb_count) = uint;
1917 /* when we've reached the maximal count, flush the buffer */
1918 if (++mbuf->mb_count >=
1919 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1920 modebuf_flush_int(mbuf, 0);
1924 * This routine adds a mode to be added or deleted that takes a string
1925 * parameter; mode may *only* be the relevant mode flag ORed with one of
1926 * MODE_ADD or MODE_DEL
1929 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1933 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1935 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1936 MB_STRING(mbuf, mbuf->mb_count) = string;
1938 /* when we've reached the maximal count, flush the buffer */
1939 if (++mbuf->mb_count >=
1940 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1941 modebuf_flush_int(mbuf, 0);
1945 * This routine adds a mode to be added or deleted that takes a client
1946 * parameter; mode may *only* be the relevant mode flag ORed with one of
1947 * MODE_ADD or MODE_DEL
1950 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1951 struct Client *client)
1954 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1956 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1957 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1959 /* when we've reached the maximal count, flush the buffer */
1960 if (++mbuf->mb_count >=
1961 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1962 modebuf_flush_int(mbuf, 0);
1966 * This is the exported binding for modebuf_flush()
1969 modebuf_flush(struct ModeBuf *mbuf)
1971 return modebuf_flush_int(mbuf, 1);
1975 * This extracts the simple modes contained in mbuf
1978 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1980 static int flags[] = {
1981 /* MODE_CHANOP, 'o', */
1982 /* MODE_VOICE, 'v', */
1985 MODE_MODERATED, 'm',
1986 MODE_TOPICLIMIT, 't',
1987 MODE_INVITEONLY, 'i',
1988 MODE_NOPRIVMSGS, 'n',
1992 /* MODE_BAN, 'b', */
1998 int i, bufpos = 0, len;
2000 char *key = 0, limitbuf[20];
2001 char *apass = 0, *upass = 0;
2010 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2011 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2012 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2014 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2015 key = MB_STRING(mbuf, i);
2016 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2017 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2018 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2019 upass = MB_STRING(mbuf, i);
2020 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2021 apass = MB_STRING(mbuf, i);
2028 buf[bufpos++] = '+'; /* start building buffer */
2030 for (flag_p = flags; flag_p[0]; flag_p += 2)
2032 buf[bufpos++] = flag_p[1];
2034 for (i = 0, len = bufpos; i < len; i++) {
2036 build_string(buf, &bufpos, key, 0, ' ');
2037 else if (buf[i] == 'l')
2038 build_string(buf, &bufpos, limitbuf, 0, ' ');
2039 else if (buf[i] == 'u')
2040 build_string(buf, &bufpos, upass, 0, ' ');
2041 else if (buf[i] == 'A')
2042 build_string(buf, &bufpos, apass, 0, ' ');
2051 * Simple function to invalidate bans
2054 mode_ban_invalidate(struct Channel *chan)
2056 struct Membership *member;
2058 for (member = chan->members; member; member = member->next_member)
2059 ClearBanValid(member);
2063 * Simple function to drop invite structures
2066 mode_invite_clear(struct Channel *chan)
2068 while (chan->invites)
2069 del_invite(chan->invites->value.cptr, chan);
2072 /* What we've done for mode_parse so far... */
2073 #define DONE_LIMIT 0x01 /* We've set the limit */
2074 #define DONE_KEY 0x02 /* We've set the key */
2075 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2076 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2077 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2078 #define DONE_UPASS 0x20 /* We've set user pass */
2079 #define DONE_APASS 0x40 /* We've set admin pass */
2082 struct ModeBuf *mbuf;
2083 struct Client *cptr;
2084 struct Client *sptr;
2085 struct Channel *chptr;
2086 struct Membership *member;
2097 struct SLink banlist[MAXPARA];
2100 struct Client *client;
2101 } cli_change[MAXPARA];
2105 * Here's a helper function to deal with sending along "Not oper" or
2106 * "Not member" messages
2109 send_notoper(struct ParseState *state)
2111 if (state->done & DONE_NOTOPER)
2114 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2115 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2117 state->done |= DONE_NOTOPER;
2121 * Helper function to convert limits
2124 mode_parse_limit(struct ParseState *state, int *flag_p)
2126 unsigned int t_limit;
2128 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2129 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2132 if (state->parc <= 0) { /* warn if not enough args */
2133 if (MyUser(state->sptr))
2134 need_more_params(state->sptr, "MODE +l");
2138 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2142 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2143 (!t_limit || t_limit == state->chptr->mode.limit))
2146 t_limit = state->chptr->mode.limit;
2148 /* If they're not an oper, they can't change modes */
2149 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2150 send_notoper(state);
2154 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2156 state->done |= DONE_LIMIT;
2161 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2163 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2164 if (state->dir & MODE_ADD) {
2165 state->chptr->mode.mode |= flag_p[0];
2166 state->chptr->mode.limit = t_limit;
2168 state->chptr->mode.mode &= ~flag_p[0];
2169 state->chptr->mode.limit = 0;
2175 * Helper function to convert keys
2178 mode_parse_key(struct ParseState *state, int *flag_p)
2183 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2186 if (state->parc <= 0) { /* warn if not enough args */
2187 if (MyUser(state->sptr))
2188 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2193 t_str = state->parv[state->args_used++]; /* grab arg */
2197 /* If they're not an oper, they can't change modes */
2198 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2199 send_notoper(state);
2203 if (state->done & DONE_KEY) /* allow key to be set only once */
2205 state->done |= DONE_KEY;
2209 /* clean up the key string */
2211 while (*++s > ' ' && *s != ':' && --t_len)
2215 if (!*t_str) { /* warn if empty */
2216 if (MyUser(state->sptr))
2217 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2225 /* can't add a key if one is set, nor can one remove the wrong key */
2226 if (!(state->flags & MODE_PARSE_FORCE))
2227 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2228 (state->dir == MODE_DEL &&
2229 ircd_strcmp(state->chptr->mode.key, t_str))) {
2230 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2234 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2235 !ircd_strcmp(state->chptr->mode.key, t_str))
2236 return; /* no key change */
2238 if (state->flags & MODE_PARSE_BOUNCE) {
2239 if (*state->chptr->mode.key) /* reset old key */
2240 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2241 state->chptr->mode.key, 0);
2242 else /* remove new bogus key */
2243 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2244 } else /* send new key */
2245 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2247 if (state->flags & MODE_PARSE_SET) {
2248 if (state->dir == MODE_ADD) /* set the new key */
2249 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2250 else /* remove the old key */
2251 *state->chptr->mode.key = '\0';
2256 * Helper function to convert user passes
2259 mode_parse_upass(struct ParseState *state, int *flag_p)
2264 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2267 if (state->parc <= 0) { /* warn if not enough args */
2268 if (MyUser(state->sptr))
2269 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2274 t_str = state->parv[state->args_used++]; /* grab arg */
2278 /* If they're not an oper, they can't change modes */
2279 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2280 send_notoper(state);
2284 /* If they are not the channel manager, they are not allowed to change it */
2285 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2286 if (*state->chptr->mode.apass) {
2287 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2288 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2290 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2291 "Re-create the channel. The channel must be *empty* for",
2292 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2293 "before it can be recreated.");
2298 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2300 state->done |= DONE_UPASS;
2302 t_len = PASSLEN + 1;
2304 /* clean up the upass string */
2306 while (*++s > ' ' && *s != ':' && --t_len)
2310 if (!*t_str) { /* warn if empty */
2311 if (MyUser(state->sptr))
2312 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2320 if (!(state->flags & MODE_PARSE_FORCE))
2321 /* can't add the upass while apass is not set */
2322 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2323 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2326 /* can't add a upass if one is set, nor can one remove the wrong upass */
2327 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2328 (state->dir == MODE_DEL &&
2329 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2330 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2334 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2335 !ircd_strcmp(state->chptr->mode.upass, t_str))
2336 return; /* no upass change */
2338 if (state->flags & MODE_PARSE_BOUNCE) {
2339 if (*state->chptr->mode.upass) /* reset old upass */
2340 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2341 state->chptr->mode.upass, 0);
2342 else /* remove new bogus upass */
2343 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2344 } else /* send new upass */
2345 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2347 if (state->flags & MODE_PARSE_SET) {
2348 if (state->dir == MODE_ADD) /* set the new upass */
2349 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2350 else /* remove the old upass */
2351 *state->chptr->mode.upass = '\0';
2356 * Helper function to convert admin passes
2359 mode_parse_apass(struct ParseState *state, int *flag_p)
2364 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2367 if (state->parc <= 0) { /* warn if not enough args */
2368 if (MyUser(state->sptr))
2369 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2374 t_str = state->parv[state->args_used++]; /* grab arg */
2378 /* If they're not an oper, they can't change modes */
2379 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2380 send_notoper(state);
2384 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2385 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2386 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2390 /* If they are not the channel manager, they are not allowed to change it */
2391 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2392 if (*state->chptr->mode.apass) {
2393 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2394 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2396 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2397 "Re-create the channel. The channel must be *empty* for",
2398 "at least a whole minute", "before it can be recreated.");
2403 if (state->done & DONE_APASS) /* allow apass to be set only once */
2405 state->done |= DONE_APASS;
2407 t_len = PASSLEN + 1;
2409 /* clean up the apass string */
2411 while (*++s > ' ' && *s != ':' && --t_len)
2415 if (!*t_str) { /* warn if empty */
2416 if (MyUser(state->sptr))
2417 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2425 if (!(state->flags & MODE_PARSE_FORCE)) {
2426 /* can't remove the apass while upass is still set */
2427 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2428 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2431 /* can't add an apass if one is set, nor can one remove the wrong apass */
2432 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2433 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2434 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2439 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2440 !ircd_strcmp(state->chptr->mode.apass, t_str))
2441 return; /* no apass change */
2443 if (state->flags & MODE_PARSE_BOUNCE) {
2444 if (*state->chptr->mode.apass) /* reset old apass */
2445 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2446 state->chptr->mode.apass, 0);
2447 else /* remove new bogus apass */
2448 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2449 } else /* send new apass */
2450 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2452 if (state->flags & MODE_PARSE_SET) {
2453 if (state->dir == MODE_ADD) { /* set the new apass */
2454 /* Make it VERY clear to the user that this is a one-time password */
2455 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2456 if (MyUser(state->sptr)) {
2457 send_reply(state->sptr, RPL_APASSWARN,
2458 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2459 "Are you SURE you want to use this as Admin password? ",
2460 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2461 send_reply(state->sptr, RPL_APASSWARN,
2462 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2463 "\" to remove the password and then immediately set a new one. "
2464 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2465 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2466 "Now set the channel user password (+u).");
2468 } else { /* remove the old apass */
2469 *state->chptr->mode.apass = '\0';
2470 if (MyUser(state->sptr))
2471 send_reply(state->sptr, RPL_APASSWARN,
2472 "WARNING: You removed the channel Admin password MODE (+A). ",
2473 "If you would disconnect or leave the channel without setting a new password then you will ",
2474 "not be able to set it again and lose ownership of this channel! ",
2475 "SET A NEW PASSWORD NOW!", "");
2481 * Helper function to convert bans
2484 mode_parse_ban(struct ParseState *state, int *flag_p)
2487 struct SLink *ban, *newban = 0;
2489 if (state->parc <= 0) { /* Not enough args, send ban list */
2490 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2491 send_ban_list(state->sptr, state->chptr);
2492 state->done |= DONE_BANLIST;
2498 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2501 t_str = state->parv[state->args_used++]; /* grab arg */
2505 /* If they're not an oper, they can't change modes */
2506 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2507 send_notoper(state);
2511 if ((s = strchr(t_str, ' ')))
2514 if (!*t_str || *t_str == ':') { /* warn if empty */
2515 if (MyUser(state->sptr))
2516 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2521 t_str = collapse(pretty_mask(t_str));
2523 /* remember the ban for the moment... */
2524 if (state->dir == MODE_ADD) {
2525 newban = state->banlist + (state->numbans++);
2528 DupString(newban->value.ban.banstr, t_str);
2529 newban->value.ban.who = cli_name(state->sptr);
2530 newban->value.ban.when = TStime();
2532 newban->flags = CHFL_BAN | MODE_ADD;
2534 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2535 newban->flags |= CHFL_BAN_IPMASK;
2538 if (!state->chptr->banlist) {
2539 state->chptr->banlist = newban; /* add our ban with its flags */
2540 state->done |= DONE_BANCLEAN;
2544 /* Go through all bans */
2545 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2546 /* first, clean the ban flags up a bit */
2547 if (!(state->done & DONE_BANCLEAN))
2548 /* Note: We're overloading *lots* of bits here; be careful! */
2549 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2553 * MODE_ADD - Ban was added; if we're bouncing modes,
2554 * then we'll remove it below; otherwise,
2555 * we'll have to allocate a real ban
2557 * MODE_DEL - Ban was marked for deletion; if we're
2558 * bouncing modes, we'll have to re-add it,
2559 * otherwise, we'll have to remove it
2561 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2562 * with a ban already set; if we're
2563 * bouncing modes, we'll have to bounce
2564 * this one; otherwise, we'll just ignore
2565 * it when we process added bans
2568 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2569 ban->flags |= MODE_DEL; /* delete one ban */
2571 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2573 } else if (state->dir == MODE_ADD) {
2574 /* if the ban already exists, don't worry about it */
2575 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2576 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2577 MyFree(newban->value.ban.banstr); /* stopper a leak */
2578 state->numbans--; /* deallocate last ban */
2579 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2581 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2582 if (!(ban->flags & MODE_DEL))
2583 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2584 } else if (!mmatch(t_str, ban->value.ban.banstr))
2585 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2587 if (!ban->next && (newban->flags & MODE_ADD))
2589 ban->next = newban; /* add our ban with its flags */
2590 break; /* get out of loop */
2594 state->done |= DONE_BANCLEAN;
2598 * This is the bottom half of the ban processor
2601 mode_process_bans(struct ParseState *state)
2603 struct SLink *ban, *newban, *prevban, *nextban;
2609 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2611 banlen = strlen(ban->value.ban.banstr);
2613 nextban = ban->next;
2615 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2617 prevban->next = 0; /* Break the list; ban isn't a real ban */
2619 state->chptr->banlist = 0;
2624 MyFree(ban->value.ban.banstr);
2627 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2628 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2629 ban->value.ban.banstr,
2630 state->flags & MODE_PARSE_SET);
2632 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2633 if (prevban) /* clip it out of the list... */
2634 prevban->next = ban->next;
2636 state->chptr->banlist = ban->next;
2641 MyFree(ban->value.ban.who);
2645 continue; /* next ban; keep prevban like it is */
2647 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2648 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2650 prevban->next = 0; /* Break the list; ban isn't a real ban */
2652 state->chptr->banlist = 0;
2654 /* If we're supposed to ignore it, do so. */
2655 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2656 !(state->flags & MODE_PARSE_BOUNCE)) {
2660 MyFree(ban->value.ban.banstr);
2662 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2663 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2664 count > feature_int(FEAT_MAXBANS))) {
2665 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2666 ban->value.ban.banstr);
2670 MyFree(ban->value.ban.banstr);
2672 /* add the ban to the buffer */
2673 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2674 ban->value.ban.banstr,
2675 !(state->flags & MODE_PARSE_SET));
2677 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2678 newban = make_link();
2679 newban->value.ban.banstr = ban->value.ban.banstr;
2680 DupString(newban->value.ban.who, ban->value.ban.who);
2681 newban->value.ban.when = ban->value.ban.when;
2682 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2684 newban->next = state->chptr->banlist; /* and link it in */
2685 state->chptr->banlist = newban;
2694 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2696 if (changed) /* if we changed the ban list, we must invalidate the bans */
2697 mode_ban_invalidate(state->chptr);
2701 * Helper function to process client changes
2704 mode_parse_client(struct ParseState *state, int *flag_p)
2707 struct Client *acptr;
2710 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2713 if (state->parc <= 0) /* return if not enough args */
2716 t_str = state->parv[state->args_used++]; /* grab arg */
2720 /* If they're not an oper, they can't change modes */
2721 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2722 send_notoper(state);
2726 if (MyUser(state->sptr)) /* find client we're manipulating */
2727 acptr = find_chasing(state->sptr, t_str, NULL);
2729 acptr = findNUser(t_str);
2732 return; /* find_chasing() already reported an error to the user */
2734 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2735 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2736 state->cli_change[i].flag & flag_p[0]))
2737 break; /* found a slot */
2739 /* Store what we're doing to them */
2740 state->cli_change[i].flag = state->dir | flag_p[0];
2741 state->cli_change[i].client = acptr;
2745 * Helper function to process the changed client list
2748 mode_process_clients(struct ParseState *state)
2751 struct Membership *member;
2753 for (i = 0; state->cli_change[i].flag; i++) {
2754 assert(0 != state->cli_change[i].client);
2756 /* look up member link */
2757 if (!(member = find_member_link(state->chptr,
2758 state->cli_change[i].client)) ||
2759 (MyUser(state->sptr) && IsZombie(member))) {
2760 if (MyUser(state->sptr))
2761 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2762 cli_name(state->cli_change[i].client),
2763 state->chptr->chname);
2767 if ((state->cli_change[i].flag & MODE_ADD &&
2768 (state->cli_change[i].flag & member->status)) ||
2769 (state->cli_change[i].flag & MODE_DEL &&
2770 !(state->cli_change[i].flag & member->status)))
2771 continue; /* no change made, don't do anything */
2773 /* see if the deop is allowed */
2774 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2775 (MODE_DEL | MODE_CHANOP)) {
2776 /* prevent +k users from being deopped */
2777 if (IsChannelService(state->cli_change[i].client)) {
2778 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2779 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2781 (IsServer(state->sptr) ? cli_name(state->sptr) :
2782 cli_name((cli_user(state->sptr))->server)));
2784 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2785 send_reply(state->sptr, ERR_ISCHANSERVICE,
2786 cli_name(state->cli_change[i].client),
2787 state->chptr->chname);
2792 /* check deop for local user */
2793 if (MyUser(state->sptr)) {
2795 /* don't allow local opers to be deopped on local channels */
2796 if (MyUser(state->sptr) &&
2797 state->cli_change[i].client != state->sptr &&
2798 IsLocalChannel(state->chptr->chname) &&
2799 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2800 send_reply(state->sptr, ERR_ISOPERLCHAN,
2801 cli_name(state->cli_change[i].client),
2802 state->chptr->chname);
2806 if (feature_bool(FEAT_OPLEVELS)) {
2807 /* don't allow to deop members with an op level that is <= our own level */
2808 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2810 && OpLevel(member) <= OpLevel(state->member)) {
2811 int equal = (OpLevel(member) == OpLevel(state->member));
2812 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2813 cli_name(state->cli_change[i].client),
2814 state->chptr->chname,
2815 OpLevel(state->member), OpLevel(member),
2816 "deop", equal ? "the same" : "a higher");
2823 /* set op-level of member being opped */
2824 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2825 (MODE_ADD | MODE_CHANOP)) {
2826 /* If on a channel with upass set, someone with level x gives ops to someone else,
2827 then that person gets level x-1. On other channels, where upass is not set,
2828 the level stays the same. */
2829 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2830 /* Someone being opped by a server gets op-level 0 */
2831 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2832 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2835 /* accumulate the change */
2836 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2837 state->cli_change[i].client);
2839 /* actually effect the change */
2840 if (state->flags & MODE_PARSE_SET) {
2841 if (state->cli_change[i].flag & MODE_ADD) {
2842 member->status |= (state->cli_change[i].flag &
2843 (MODE_CHANOP | MODE_VOICE));
2844 if (state->cli_change[i].flag & MODE_CHANOP)
2845 ClearDeopped(member);
2847 member->status &= ~(state->cli_change[i].flag &
2848 (MODE_CHANOP | MODE_VOICE));
2850 } /* for (i = 0; state->cli_change[i].flags; i++) */
2854 * Helper function to process the simple modes
2857 mode_parse_mode(struct ParseState *state, int *flag_p)
2859 /* If they're not an oper, they can't change modes */
2860 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2861 send_notoper(state);
2868 if (state->dir == MODE_ADD) {
2869 state->add |= flag_p[0];
2870 state->del &= ~flag_p[0];
2872 if (flag_p[0] & MODE_SECRET) {
2873 state->add &= ~MODE_PRIVATE;
2874 state->del |= MODE_PRIVATE;
2875 } else if (flag_p[0] & MODE_PRIVATE) {
2876 state->add &= ~MODE_SECRET;
2877 state->del |= MODE_SECRET;
2880 state->add &= ~flag_p[0];
2881 state->del |= flag_p[0];
2884 assert(0 == (state->add & state->del));
2885 assert((MODE_SECRET | MODE_PRIVATE) !=
2886 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2890 * This routine is intended to parse MODE or OPMODE commands and effect the
2891 * changes (or just build the bounce buffer). We pass the starting offset
2895 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2896 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2897 struct Membership* member)
2899 static int chan_flags[] = {
2904 MODE_MODERATED, 'm',
2905 MODE_TOPICLIMIT, 't',
2906 MODE_INVITEONLY, 'i',
2907 MODE_NOPRIVMSGS, 'n',
2920 unsigned int t_mode;
2922 struct ParseState state;
2933 state.chptr = chptr;
2934 state.member = member;
2937 state.flags = flags;
2938 state.dir = MODE_ADD;
2942 state.args_used = 0;
2943 state.max_args = MAXMODEPARAMS;
2946 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2947 state.banlist[i].next = 0;
2948 state.banlist[i].value.ban.banstr = 0;
2949 state.banlist[i].value.ban.who = 0;
2950 state.banlist[i].value.ban.when = 0;
2951 state.banlist[i].flags = 0;
2952 state.cli_change[i].flag = 0;
2953 state.cli_change[i].client = 0;
2956 modestr = state.parv[state.args_used++];
2960 for (; *modestr; modestr++) {
2961 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2962 if (flag_p[1] == *modestr)
2965 if (!flag_p[0]) { /* didn't find it? complain and continue */
2966 if (MyUser(state.sptr))
2967 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2972 case '+': /* switch direction to MODE_ADD */
2973 case '-': /* switch direction to MODE_DEL */
2974 state.dir = flag_p[0];
2977 case 'l': /* deal with limits */
2978 mode_parse_limit(&state, flag_p);
2981 case 'k': /* deal with keys */
2982 mode_parse_key(&state, flag_p);
2985 case 'A': /* deal with Admin passes */
2986 if (feature_bool(FEAT_OPLEVELS))
2987 mode_parse_apass(&state, flag_p);
2990 case 'u': /* deal with user passes */
2991 if (feature_bool(FEAT_OPLEVELS))
2992 mode_parse_upass(&state, flag_p);
2995 case 'b': /* deal with bans */
2996 mode_parse_ban(&state, flag_p);
2999 case 'o': /* deal with ops/voice */
3001 mode_parse_client(&state, flag_p);
3004 default: /* deal with other modes */
3005 mode_parse_mode(&state, flag_p);
3007 } /* switch (*modestr) */
3008 } /* for (; *modestr; modestr++) */
3010 if (state.flags & MODE_PARSE_BURST)
3011 break; /* don't interpret any more arguments */
3013 if (state.parc > 0) { /* process next argument in string */
3014 modestr = state.parv[state.args_used++];
3018 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3021 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3022 break; /* we're then going to bounce the mode! */
3024 recv_ts = atoi(modestr);
3026 if (recv_ts && recv_ts < state.chptr->creationtime)
3027 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3029 break; /* break out of while loop */
3030 } else if (state.flags & MODE_PARSE_STRICT ||
3031 (MyUser(state.sptr) && state.max_args <= 0)) {
3032 state.parc++; /* we didn't actually gobble the argument */
3034 break; /* break out of while loop */
3037 } /* while (*modestr) */
3040 * the rest of the function finishes building resultant MODEs; if the
3041 * origin isn't a member or an oper, skip it.
3043 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3044 return state.args_used; /* tell our parent how many args we gobbled */
3046 t_mode = state.chptr->mode.mode;
3048 if (state.del & t_mode) { /* delete any modes to be deleted... */
3049 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3051 t_mode &= ~state.del;
3053 if (state.add & ~t_mode) { /* add any modes to be added... */
3054 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3056 t_mode |= state.add;
3059 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3060 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3061 !(t_mode & MODE_INVITEONLY))
3062 mode_invite_clear(state.chptr);
3064 state.chptr->mode.mode = t_mode;
3067 if (state.flags & MODE_PARSE_WIPEOUT) {
3068 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3069 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3070 state.chptr->mode.limit);
3071 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3072 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3073 state.chptr->mode.key, 0);
3074 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3075 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3076 state.chptr->mode.upass, 0);
3077 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3078 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3079 state.chptr->mode.apass, 0);
3082 if (state.done & DONE_BANCLEAN) /* process bans */
3083 mode_process_bans(&state);
3085 /* process client changes */
3086 if (state.cli_change[0].flag)
3087 mode_process_clients(&state);
3089 return state.args_used; /* tell our parent how many args we gobbled */
3093 * Initialize a join buffer
3096 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3097 struct Client *connect, unsigned int type, char *comment,
3103 assert(0 != source);
3104 assert(0 != connect);
3106 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3107 jbuf->jb_connect = connect;
3108 jbuf->jb_type = type;
3109 jbuf->jb_comment = comment;
3110 jbuf->jb_create = create;
3112 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3113 type == JOINBUF_TYPE_PART ||
3114 type == JOINBUF_TYPE_PARTALL) ?
3115 STARTJOINLEN : STARTCREATELEN) +
3116 (comment ? strlen(comment) + 2 : 0));
3118 for (i = 0; i < MAXJOINARGS; i++)
3119 jbuf->jb_channels[i] = 0;
3123 * Add a channel to the join buffer
3126 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3134 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3135 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3140 is_local = IsLocalChannel(chan->chname);
3142 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3143 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3144 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3145 if (IsUserParting(member))
3147 SetUserParting(member);
3149 /* Send notification to channel */
3150 if (!(flags & CHFL_ZOMBIE))
3151 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3152 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3153 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3154 else if (MyUser(jbuf->jb_source))
3155 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3156 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3157 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3158 /* XXX: Shouldn't we send a PART here anyway? */
3159 /* to users on the channel? Why? From their POV, the user isn't on
3160 * the channel anymore anyway. We don't send to servers until below,
3161 * when we gang all the channel parts together. Note that this is
3162 * exactly the same logic, albeit somewhat more concise, as was in
3163 * the original m_part.c */
3165 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3166 is_local) /* got to remove user here */
3167 remove_user_from_channel(jbuf->jb_source, chan);
3169 /* Add user to channel */
3170 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3172 /* send notification to all servers */
3173 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3174 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3175 "%H %Tu", chan, chan->creationtime);
3177 /* Send the notification to the channel */
3178 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3180 /* send an op, too, if needed */
3181 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3182 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3183 chan, jbuf->jb_source);
3186 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3187 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3188 return; /* don't send to remote */
3190 /* figure out if channel name will cause buffer to be overflowed */
3191 len = chan ? strlen(chan->chname) + 1 : 2;
3192 if (jbuf->jb_strlen + len > BUFSIZE)
3193 joinbuf_flush(jbuf);
3195 /* add channel to list of channels to send and update counts */
3196 jbuf->jb_channels[jbuf->jb_count++] = chan;
3197 jbuf->jb_strlen += len;
3199 /* if we've used up all slots, flush */
3200 if (jbuf->jb_count >= MAXJOINARGS)
3201 joinbuf_flush(jbuf);
3205 * Flush the channel list to remote servers
3208 joinbuf_flush(struct JoinBuf *jbuf)
3210 char chanlist[BUFSIZE];
3214 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3215 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3216 return 0; /* no joins to process */
3218 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3219 build_string(chanlist, &chanlist_i,
3220 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3221 i == 0 ? '\0' : ',');
3222 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3223 /* Remove user from channel */
3224 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3226 jbuf->jb_channels[i] = 0; /* mark slot empty */
3229 jbuf->jb_count = 0; /* reset base counters */
3230 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3231 STARTJOINLEN : STARTCREATELEN) +
3232 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3234 /* and send the appropriate command */
3235 switch (jbuf->jb_type) {
3236 case JOINBUF_TYPE_CREATE:
3237 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3238 "%s %Tu", chanlist, jbuf->jb_create);
3241 case JOINBUF_TYPE_PART:
3242 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3243 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3251 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3252 int IsInvited(struct Client* cptr, const void* chptr)
3256 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3257 if (lp->value.chptr == chptr)