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
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) && is_banned(cptr, member->channel, member))
724 return member->channel->chname;
732 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
733 * with the parameters in pbuf.
735 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
736 struct Channel *chptr, struct Membership *member)
738 int previous_parameter = 0;
745 if (chptr->mode.mode & MODE_SECRET)
747 else if (chptr->mode.mode & MODE_PRIVATE)
749 if (chptr->mode.mode & MODE_MODERATED)
751 if (chptr->mode.mode & MODE_TOPICLIMIT)
753 if (chptr->mode.mode & MODE_INVITEONLY)
755 if (chptr->mode.mode & MODE_NOPRIVMSGS)
757 if (chptr->mode.mode & MODE_REGONLY)
759 if (chptr->mode.limit) {
761 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
762 previous_parameter = 1;
765 if (*chptr->mode.key) {
767 if (previous_parameter)
769 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
770 strcat(pbuf, chptr->mode.key);
773 previous_parameter = 1;
775 if (*chptr->mode.apass) {
777 if (previous_parameter)
779 if (IsServer(cptr)) {
780 strcat(pbuf, chptr->mode.apass);
783 previous_parameter = 1;
785 if (*chptr->mode.upass) {
787 if (previous_parameter)
789 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
790 strcat(pbuf, chptr->mode.upass);
797 int compare_member_oplevel(const void *mp1, const void *mp2)
799 struct Membership const* member1 = *(struct Membership const**)mp1;
800 struct Membership const* member2 = *(struct Membership const**)mp2;
801 if (member1->oplevel == member2->oplevel)
803 return (member1->oplevel < member2->oplevel) ? -1 : 1;
807 * send "cptr" a full list of the modes for channel chptr.
809 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
811 /* The order in which modes are generated is now mandatory */
812 static unsigned int current_flags[4] =
813 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
819 struct Membership* member;
821 char modebuf[MODEBUFLEN];
822 char parabuf[MODEBUFLEN];
824 int number_of_ops = 0;
825 int opped_members_index = 0;
826 struct Membership** opped_members = NULL;
827 int last_oplevel = 0;
832 if (IsLocalChannel(chptr->chname))
835 member = chptr->members;
836 lp2 = chptr->banlist;
838 *modebuf = *parabuf = '\0';
839 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
841 for (first = 1; full; first = 0) /* Loop for multiple messages */
843 full = 0; /* Assume by default we get it
844 all in one message */
846 /* (Continued) prefix: "<Y> B <channel> <TS>" */
847 /* is there any better way we can do this? */
848 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
849 chptr->creationtime);
851 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
854 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
855 msgq_append(&me, mb, " %s", modebuf);
858 msgq_append(&me, mb, " %s", parabuf);
862 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
864 * First find all opless members.
865 * Run 2 times over all members, to group the members with
866 * and without voice together.
867 * Then run 2 times over all opped members (which are ordered
868 * by op-level) to also group voice and non-voice together.
870 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
874 if (flag_cnt < 2 && IsChanOp(member))
877 * The first loop (to find all non-voice/op), we count the ops.
878 * The second loop (to find all voiced non-ops), store the ops
879 * in a dynamic array.
884 opped_members[opped_members_index++] = member;
886 /* Only handle the members with the flags that we are interested in. */
887 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
889 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
890 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
892 full = 1; /* Make sure we continue after
894 /* Ensure the new BURST line contains the current
895 * ":mode", except when there is no mode yet. */
896 new_mode = (flag_cnt > 0) ? 1 : 0;
897 break; /* Do not add this member to this message */
899 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
900 first = 0; /* From now on, use commas to add new nicks */
903 * Do we have a nick with a new mode ?
904 * Or are we starting a new BURST line?
909 * This means we are at the _first_ member that has only
910 * voice, or the first member that has only ops, or the
911 * first member that has voice and ops (so we get here
912 * at most three times, plus once for every start of
913 * a continued BURST line where only these modes is current.
914 * In the two cases where the current mode includes ops,
915 * we need to add the _absolute_ value of the oplevel to the mode.
917 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
920 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
922 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
924 /* append the absolute value of the oplevel */
925 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
926 last_oplevel = member->oplevel;
929 msgq_append(&me, mb, tbuf);
932 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
935 * This can't be the first member of a (continued) BURST
936 * message because then either flag_cnt == 0 or new_mode == 1
937 * Now we need to append the incremental value of the oplevel.
939 char tbuf[2 + MAXOPLEVELDIGITS];
940 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
941 last_oplevel = member->oplevel;
942 msgq_append(&me, mb, tbuf);
945 /* Go to the next `member'. */
947 member = member->next_member;
949 member = opped_members[++opped_members_index];
954 /* Point `member' at the start of the list again. */
957 member = chptr->members;
958 /* Now, after one loop, we know the number of ops and can
959 * allocate the dynamic array with pointer to the ops. */
960 opped_members = (struct Membership**)
961 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
962 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
966 /* At the end of the second loop, sort the opped members with
967 * increasing op-level, so that we will output them in the
968 * correct order (and all op-level increments stay positive) */
970 qsort(opped_members, number_of_ops,
971 sizeof(struct Membership*), compare_member_oplevel);
972 /* The third and fourth loop run only over the opped members. */
973 member = opped_members[(opped_members_index = 0)];
976 } /* loop over 0,+v,+o,+ov */
980 /* Attach all bans, space seperated " :%ban ban ..." */
981 for (first = 2; lp2; lp2 = lp2->next)
983 len = strlen(lp2->value.ban.banstr);
984 if (msgq_bufleft(mb) < len + 1 + first)
985 /* The +1 stands for the added ' '.
986 * The +first stands for the added ":%".
992 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
993 lp2->value.ban.banstr);
998 send_buffer(cptr, mb, 0); /* Send this message */
1000 } /* Continue when there was something
1001 that didn't fit (full==1) */
1003 MyFree(opped_members);
1009 * by Carlo Wood (Run), 05 Oct 1998.
1013 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1014 * When the user name or host name are too long (USERLEN and HOSTLEN
1015 * respectively) then they are cut off at the start with a '*'.
1017 * The following transformations are made:
1019 * 1) xxx -> nick!*@*
1020 * 2) xxx.xxx -> *!*@host
1021 * 3) xxx!yyy -> nick!user@*
1022 * 4) xxx@yyy -> *!user@host
1023 * 5) xxx!yyy@zzz -> nick!user@host
1025 char *pretty_mask(char *mask)
1027 static char star[2] = { '*', 0 };
1028 static char retmask[NUH_BUFSIZE];
1029 char *last_dot = NULL;
1032 /* Case 1: default */
1037 /* Do a _single_ pass through the characters of the mask: */
1038 for (ptr = mask; *ptr; ++ptr)
1042 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1046 else if (*ptr == '@')
1048 /* Case 4: Found last '@' (without finding a '!' yet) */
1053 else if (*ptr == '.')
1055 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1065 /* Case 4 or 5: Found last '@' */
1071 if (user == star && last_dot)
1081 char *nick_end = (user != star) ? user - 1 : ptr;
1082 if (nick_end - nick > NICKLEN)
1088 char *user_end = (host != star) ? host - 1 : ptr;
1089 if (user_end - user > USERLEN)
1091 user = user_end - USERLEN;
1096 if (host != star && ptr - host > HOSTLEN)
1098 host = ptr - HOSTLEN;
1101 return make_nick_user_host(retmask, nick, user, host);
1104 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1111 for (lp = chptr->banlist; lp; lp = lp->next)
1112 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1113 lp->value.ban.who, lp->value.ban.when);
1115 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1118 /* We are now treating the <key> part of /join <channel list> <key> as a key
1119 * ring; that is, we try one key against the actual channel key, and if that
1120 * doesn't work, we try the next one, and so on. -Kev -Texaco
1121 * Returns: 0 on match, 1 otherwise
1122 * This version contributed by SeKs <intru@info.polymtl.ca>
1124 static int compall(char *key, char *keyring)
1129 p1 = key; /* point to the key... */
1130 while (*p1 && *p1 == *keyring)
1131 { /* step through the key and ring until they
1137 if (!*p1 && (!*keyring || *keyring == ','))
1138 /* ok, if we're at the end of the and also at the end of one of the keys
1139 in the keyring, we have a match */
1142 if (!*keyring) /* if we're at the end of the key ring, there
1143 weren't any matches, so we return 1 */
1146 /* Not at the end of the key ring, so step
1147 through to the next key in the ring: */
1148 while (*keyring && *(keyring++) != ',');
1150 goto top; /* and check it against the key */
1153 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1156 int overrideJoin = 0;
1159 * Now a banned user CAN join if invited -- Nemesi
1160 * Now a user CAN escape channel limit if invited -- bfriendly
1161 * Now a user CAN escape anything if invited -- Isomer
1164 for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1165 if (lp->value.chptr == chptr)
1168 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1169 a HACK(4) notice will be sent if he would not have been supposed
1170 to join normally. */
1171 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1172 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1173 compall("OVERRIDE",key) == 0)
1174 overrideJoin = MAGIC_OPER_OVERRIDE;
1176 if (chptr->mode.mode & MODE_INVITEONLY)
1177 return overrideJoin + ERR_INVITEONLYCHAN;
1179 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1180 return overrideJoin + ERR_CHANNELISFULL;
1182 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1183 return overrideJoin + ERR_NEEDREGGEDNICK;
1185 if (is_banned(sptr, chptr, NULL))
1186 return overrideJoin + ERR_BANNEDFROMCHAN;
1189 * now using compall (above) to test against a whole key ring -Kev
1191 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1192 return overrideJoin + ERR_BADCHANNELKEY;
1195 return ERR_DONTCHEAT;
1201 * Remove bells and commas from channel name
1203 void clean_channelname(char *cn)
1207 for (i = 0; cn[i]; i++) {
1208 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1212 if (IsChannelLower(cn[i])) {
1213 cn[i] = ToLower(cn[i]);
1219 if ((unsigned char)(cn[i]) == 0xd0)
1220 cn[i] = (char) 0xf0;
1227 * Get Channel block for i (and allocate a new channel
1228 * block, if it didn't exists before).
1230 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1232 struct Channel *chptr;
1235 if (EmptyString(chname))
1238 len = strlen(chname);
1239 if (MyUser(cptr) && len > CHANNELLEN)
1242 *(chname + CHANNELLEN) = '\0';
1244 if ((chptr = FindChannel(chname)))
1246 if (flag == CGT_CREATE)
1248 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1250 ++UserStats.channels;
1251 memset(chptr, 0, sizeof(struct Channel));
1252 strcpy(chptr->chname, chname);
1253 if (GlobalChannelList)
1254 GlobalChannelList->prev = chptr;
1256 chptr->next = GlobalChannelList;
1257 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1258 GlobalChannelList = chptr;
1264 void add_invite(struct Client *cptr, struct Channel *chptr)
1266 struct SLink *inv, **tmp;
1268 del_invite(cptr, chptr);
1270 * Delete last link in chain if the list is max length
1272 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1273 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1274 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1276 * Add client to channel invite list
1279 inv->value.cptr = cptr;
1280 inv->next = chptr->invites;
1281 chptr->invites = inv;
1283 * Add channel to the end of the client invite list
1285 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1287 inv->value.chptr = chptr;
1290 (cli_user(cptr))->invites++;
1294 * Delete Invite block from channel invite list and client invite list
1296 void del_invite(struct Client *cptr, struct Channel *chptr)
1298 struct SLink **inv, *tmp;
1300 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1301 if (tmp->value.cptr == cptr)
1306 (cli_user(cptr))->invites--;
1310 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1311 if (tmp->value.chptr == chptr)
1320 /* List and skip all channels that are listen */
1321 void list_next_channels(struct Client *cptr, int nr)
1323 struct ListingArgs *args = cli_listing(cptr);
1324 struct Channel *chptr = args->chptr;
1325 chptr->mode.mode &= ~MODE_LISTED;
1326 while (is_listed(chptr) || --nr >= 0)
1328 for (; chptr; chptr = chptr->next)
1330 if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1331 SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1333 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1334 chptr->creationtime > args->min_time &&
1335 chptr->creationtime < args->max_time &&
1336 (!args->topic_limits || (*chptr->topic &&
1337 chptr->topic_time > args->min_topic_time &&
1338 chptr->topic_time < args->max_topic_time)))
1340 if (ShowChannel(cptr,chptr))
1341 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1343 chptr = chptr->next;
1349 MyFree(cli_listing(cptr));
1350 cli_listing(cptr) = NULL;
1351 send_reply(cptr, RPL_LISTEND);
1357 (cli_listing(cptr))->chptr = chptr;
1358 chptr->mode.mode |= MODE_LISTED;
1371 * X --a--> A --b--> B --d--> D
1375 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1376 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1378 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1379 * Remove the user immediately when no users are left on the channel.
1380 * b) On server B : remove the user (who/lp) from the channel, send a
1381 * PART upstream (to A) and pass on the KICK.
1382 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1383 * channel, and pass on the KICK.
1384 * d) On server D : remove the user (who/lp) from the channel, and pass on
1388 * - Setting the ZOMBIE flag never hurts, we either remove the
1389 * client after that or we don't.
1390 * - The KICK message was already passed on, as should be in all cases.
1391 * - `who' is removed in all cases except case a) when users are left.
1392 * - A PART is only sent upstream in case b).
1398 * 1 --- 2 --- 3 --- 4 --- 5
1402 * We also need to turn 'who' into a zombie on servers 1 and 6,
1403 * because a KICK from 'who' (kicking someone else in that direction)
1404 * can arrive there afterwards - which should not be bounced itself.
1405 * Therefore case a) also applies for servers 1 and 6.
1409 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1410 struct Client* sptr, struct Channel* chptr)
1412 assert(0 != member);
1417 /* Default for case a): */
1420 /* Case b) or c) ?: */
1421 if (MyUser(who)) /* server 4 */
1423 if (IsServer(cptr)) /* Case b) ? */
1424 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1425 remove_user_from_channel(who, chptr);
1428 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1430 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1431 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1432 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1434 remove_user_from_channel(who, chptr);
1439 /* Case a) (servers 1, 2, 3 and 6) */
1440 if (channel_all_zombies(chptr))
1441 remove_user_from_channel(who, chptr);
1443 /* XXX Can't actually call Debug here; if the channel is all zombies,
1444 * chptr will no longer exist when we get here.
1445 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1449 int number_of_zombies(struct Channel *chptr)
1451 struct Membership* member;
1455 for (member = chptr->members; member; member = member->next_member) {
1456 if (IsZombie(member))
1463 * This helper function builds an argument string in strptr, consisting
1464 * of the original string, a space, and str1 and str2 concatenated (if,
1465 * of course, str2 is not NULL)
1468 build_string(char *strptr, int *strptr_i, const char *str1,
1469 const char *str2, char c)
1472 strptr[(*strptr_i)++] = c;
1475 strptr[(*strptr_i)++] = *(str1++);
1479 strptr[(*strptr_i)++] = *(str2++);
1481 strptr[(*strptr_i)] = '\0';
1485 * This is the workhorse of our ModeBuf suite; this actually generates the
1486 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1489 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1491 /* we only need the flags that don't take args right now */
1492 static int flags[] = {
1493 /* MODE_CHANOP, 'o', */
1494 /* MODE_VOICE, 'v', */
1497 MODE_MODERATED, 'm',
1498 MODE_TOPICLIMIT, 't',
1499 MODE_INVITEONLY, 'i',
1500 MODE_NOPRIVMSGS, 'n',
1502 /* MODE_KEY, 'k', */
1503 /* MODE_BAN, 'b', */
1504 /* MODE_LIMIT, 'l', */
1505 /* MODE_APASS, 'A', */
1506 /* MODE_UPASS, 'u', */
1512 struct Client *app_source; /* where the MODE appears to come from */
1514 char addbuf[20]; /* accumulates +psmtin, etc. */
1516 char rembuf[20]; /* accumulates -psmtin, etc. */
1518 char *bufptr; /* we make use of indirection to simplify the code */
1521 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1523 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1525 char *strptr; /* more indirection to simplify the code */
1528 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1531 char limitbuf[20]; /* convert limits to strings */
1533 unsigned int limitdel = MODE_LIMIT;
1537 /* If the ModeBuf is empty, we have nothing to do */
1538 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1541 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1543 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1546 app_source = mbuf->mb_source;
1549 * Account for user we're bouncing; we have to get it in on the first
1550 * bounced MODE, or we could have problems
1552 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1553 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1555 /* Calculate the simple flags */
1556 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1557 if (*flag_p & mbuf->mb_add)
1558 addbuf[addbuf_i++] = flag_p[1];
1559 else if (*flag_p & mbuf->mb_rem)
1560 rembuf[rembuf_i++] = flag_p[1];
1563 /* Now go through the modes with arguments... */
1564 for (i = 0; i < mbuf->mb_count; i++) {
1565 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1567 bufptr_i = &addbuf_i;
1570 bufptr_i = &rembuf_i;
1573 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1574 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1576 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1577 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1579 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1580 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1582 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1583 tmp = strlen(MB_STRING(mbuf, i));
1585 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1586 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1589 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1601 bufptr[(*bufptr_i)++] = mode_char;
1602 totalbuflen -= tmp + 1;
1604 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1605 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1606 strlen(MB_STRING(mbuf, i)));
1608 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1609 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1611 bufptr[(*bufptr_i)++] = 'k';
1612 totalbuflen -= tmp + 1;
1614 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1615 /* if it's a limit, we also format the number */
1616 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1618 tmp = strlen(limitbuf);
1620 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1621 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1623 bufptr[(*bufptr_i)++] = 'l';
1624 totalbuflen -= tmp + 1;
1629 /* terminate the mode strings */
1630 addbuf[addbuf_i] = '\0';
1631 rembuf[rembuf_i] = '\0';
1633 /* If we're building a user visible MODE or HACK... */
1634 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1635 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1636 MODEBUF_DEST_LOG)) {
1637 /* Set up the parameter strings */
1643 for (i = 0; i < mbuf->mb_count; i++) {
1644 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1647 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1649 strptr_i = &addstr_i;
1652 strptr_i = &remstr_i;
1655 /* deal with clients... */
1656 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1657 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1659 /* deal with bans... */
1660 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1661 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1663 /* deal with keys... */
1664 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1665 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1666 "*" : MB_STRING(mbuf, i), 0, ' ');
1668 /* deal with invisible passwords */
1669 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1670 build_string(strptr, strptr_i, "*", 0, ' ');
1673 * deal with limit; note we cannot include the limit parameter if we're
1676 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1677 (MODE_ADD | MODE_LIMIT))
1678 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1681 /* send the messages off to their destination */
1682 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1683 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1685 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1686 mbuf->mb_source : app_source),
1687 mbuf->mb_channel->chname,
1688 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1689 addbuf, remstr, addstr,
1690 mbuf->mb_channel->creationtime);
1692 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1693 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1694 "%s%s%s%s%s%s [%Tu]",
1695 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1696 mbuf->mb_source : app_source),
1697 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1698 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1699 mbuf->mb_channel->creationtime);
1701 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1702 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1704 #ifdef HEAD_IN_SAND_SNOTICES
1705 cli_name(mbuf->mb_source),
1707 cli_name(app_source),
1709 mbuf->mb_channel->chname,
1710 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1711 addbuf, remstr, addstr,
1712 mbuf->mb_channel->creationtime);
1714 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1715 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1716 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1717 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1718 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1720 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1721 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1722 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1723 rembuf_i ? "-" : "", rembuf,
1724 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1727 /* Now are we supposed to propagate to other servers? */
1728 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1729 /* set up parameter string */
1736 * limit is supressed if we're removing it; we have to figure out which
1737 * direction is the direction for it to be removed, though...
1739 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1741 for (i = 0; i < mbuf->mb_count; i++) {
1742 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1745 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1747 strptr_i = &addstr_i;
1750 strptr_i = &remstr_i;
1753 /* deal with modes that take clients */
1754 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1755 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1757 /* deal with modes that take strings */
1758 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1759 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1762 * deal with the limit. Logic here is complicated; if HACK2 is set,
1763 * we're bouncing the mode, so sense is reversed, and we have to
1764 * include the original limit if it looks like it's being removed
1766 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1767 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1770 /* we were told to deop the source */
1771 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1772 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1773 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1774 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1776 /* mark that we've done this, so we don't do it again */
1777 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1780 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1781 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1782 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1783 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1784 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1785 addbuf, remstr, addstr);
1786 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1788 * If HACK2 was set, we're bouncing; we send the MODE back to the
1789 * connection we got it from with the senses reversed and a TS of 0;
1792 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1793 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1794 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1795 mbuf->mb_channel->creationtime);
1798 * We're propagating a normal MODE command to the rest of the network;
1799 * we send the actual channel TS unless this is a HACK3 or a HACK4
1801 if (IsServer(mbuf->mb_source))
1802 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1803 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1804 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1805 addbuf, remstr, addstr,
1806 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1807 mbuf->mb_channel->creationtime);
1809 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1810 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1811 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1812 addbuf, remstr, addstr);
1816 /* We've drained the ModeBuf... */
1821 /* reinitialize the mode-with-arg slots */
1822 for (i = 0; i < MAXMODEPARAMS; i++) {
1823 /* If we saved any, pack them down */
1824 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1825 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1826 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1828 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1830 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1831 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1833 MB_TYPE(mbuf, i) = 0;
1834 MB_UINT(mbuf, i) = 0;
1837 /* If we're supposed to flush it all, do so--all hail tail recursion */
1838 if (all && mbuf->mb_count)
1839 return modebuf_flush_int(mbuf, 1);
1845 * This routine just initializes a ModeBuf structure with the information
1846 * needed and the options given.
1849 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1850 struct Client *connect, struct Channel *chan, unsigned int dest)
1855 assert(0 != source);
1859 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1863 mbuf->mb_source = source;
1864 mbuf->mb_connect = connect;
1865 mbuf->mb_channel = chan;
1866 mbuf->mb_dest = dest;
1869 /* clear each mode-with-parameter slot */
1870 for (i = 0; i < MAXMODEPARAMS; i++) {
1871 MB_TYPE(mbuf, i) = 0;
1872 MB_UINT(mbuf, i) = 0;
1877 * This routine simply adds modes to be added or deleted; do a binary OR
1878 * with either MODE_ADD or MODE_DEL
1881 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1884 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1886 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1887 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1889 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1892 if (mode & MODE_ADD) {
1893 mbuf->mb_rem &= ~mode;
1894 mbuf->mb_add |= mode;
1896 mbuf->mb_add &= ~mode;
1897 mbuf->mb_rem |= mode;
1902 * This routine adds a mode to be added or deleted that takes a unsigned
1903 * int parameter; mode may *only* be the relevant mode flag ORed with one
1904 * of MODE_ADD or MODE_DEL
1907 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1910 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1912 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1913 MB_UINT(mbuf, mbuf->mb_count) = uint;
1915 /* when we've reached the maximal count, flush the buffer */
1916 if (++mbuf->mb_count >=
1917 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1918 modebuf_flush_int(mbuf, 0);
1922 * This routine adds a mode to be added or deleted that takes a string
1923 * parameter; mode may *only* be the relevant mode flag ORed with one of
1924 * MODE_ADD or MODE_DEL
1927 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1931 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1933 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1934 MB_STRING(mbuf, mbuf->mb_count) = string;
1936 /* when we've reached the maximal count, flush the buffer */
1937 if (++mbuf->mb_count >=
1938 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1939 modebuf_flush_int(mbuf, 0);
1943 * This routine adds a mode to be added or deleted that takes a client
1944 * parameter; mode may *only* be the relevant mode flag ORed with one of
1945 * MODE_ADD or MODE_DEL
1948 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1949 struct Client *client)
1952 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1954 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1955 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1957 /* when we've reached the maximal count, flush the buffer */
1958 if (++mbuf->mb_count >=
1959 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1960 modebuf_flush_int(mbuf, 0);
1964 * This is the exported binding for modebuf_flush()
1967 modebuf_flush(struct ModeBuf *mbuf)
1969 return modebuf_flush_int(mbuf, 1);
1973 * This extracts the simple modes contained in mbuf
1976 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1978 static int flags[] = {
1979 /* MODE_CHANOP, 'o', */
1980 /* MODE_VOICE, 'v', */
1983 MODE_MODERATED, 'm',
1984 MODE_TOPICLIMIT, 't',
1985 MODE_INVITEONLY, 'i',
1986 MODE_NOPRIVMSGS, 'n',
1990 /* MODE_BAN, 'b', */
1996 int i, bufpos = 0, len;
1998 char *key = 0, limitbuf[20];
1999 char *apass = 0, *upass = 0;
2008 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2009 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2010 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2012 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2013 key = MB_STRING(mbuf, i);
2014 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2015 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2016 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2017 upass = MB_STRING(mbuf, i);
2018 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2019 apass = MB_STRING(mbuf, i);
2026 buf[bufpos++] = '+'; /* start building buffer */
2028 for (flag_p = flags; flag_p[0]; flag_p += 2)
2030 buf[bufpos++] = flag_p[1];
2032 for (i = 0, len = bufpos; i < len; i++) {
2034 build_string(buf, &bufpos, key, 0, ' ');
2035 else if (buf[i] == 'l')
2036 build_string(buf, &bufpos, limitbuf, 0, ' ');
2037 else if (buf[i] == 'u')
2038 build_string(buf, &bufpos, upass, 0, ' ');
2039 else if (buf[i] == 'A')
2040 build_string(buf, &bufpos, apass, 0, ' ');
2049 * Simple function to invalidate bans
2052 mode_ban_invalidate(struct Channel *chan)
2054 struct Membership *member;
2056 for (member = chan->members; member; member = member->next_member)
2057 ClearBanValid(member);
2061 * Simple function to drop invite structures
2064 mode_invite_clear(struct Channel *chan)
2066 while (chan->invites)
2067 del_invite(chan->invites->value.cptr, chan);
2070 /* What we've done for mode_parse so far... */
2071 #define DONE_LIMIT 0x01 /* We've set the limit */
2072 #define DONE_KEY 0x02 /* We've set the key */
2073 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2074 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2075 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2076 #define DONE_UPASS 0x20 /* We've set user pass */
2077 #define DONE_APASS 0x40 /* We've set admin pass */
2080 struct ModeBuf *mbuf;
2081 struct Client *cptr;
2082 struct Client *sptr;
2083 struct Channel *chptr;
2084 struct Membership *member;
2095 struct SLink banlist[MAXPARA];
2098 struct Client *client;
2099 } cli_change[MAXPARA];
2103 * Here's a helper function to deal with sending along "Not oper" or
2104 * "Not member" messages
2107 send_notoper(struct ParseState *state)
2109 if (state->done & DONE_NOTOPER)
2112 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2113 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2115 state->done |= DONE_NOTOPER;
2119 * Helper function to convert limits
2122 mode_parse_limit(struct ParseState *state, int *flag_p)
2124 unsigned int t_limit;
2126 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2127 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2130 if (state->parc <= 0) { /* warn if not enough args */
2131 if (MyUser(state->sptr))
2132 need_more_params(state->sptr, "MODE +l");
2136 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2140 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2141 (!t_limit || t_limit == state->chptr->mode.limit))
2144 t_limit = state->chptr->mode.limit;
2146 /* If they're not an oper, they can't change modes */
2147 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2148 send_notoper(state);
2152 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2154 state->done |= DONE_LIMIT;
2159 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2161 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2162 if (state->dir & MODE_ADD) {
2163 state->chptr->mode.mode |= flag_p[0];
2164 state->chptr->mode.limit = t_limit;
2166 state->chptr->mode.mode &= ~flag_p[0];
2167 state->chptr->mode.limit = 0;
2173 * Helper function to convert keys
2176 mode_parse_key(struct ParseState *state, int *flag_p)
2181 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2184 if (state->parc <= 0) { /* warn if not enough args */
2185 if (MyUser(state->sptr))
2186 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2191 t_str = state->parv[state->args_used++]; /* grab arg */
2195 /* If they're not an oper, they can't change modes */
2196 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2197 send_notoper(state);
2201 if (state->done & DONE_KEY) /* allow key to be set only once */
2203 state->done |= DONE_KEY;
2207 /* clean up the key string */
2209 while (*++s > ' ' && *s != ':' && --t_len)
2213 if (!*t_str) { /* warn if empty */
2214 if (MyUser(state->sptr))
2215 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2223 /* can't add a key if one is set, nor can one remove the wrong key */
2224 if (!(state->flags & MODE_PARSE_FORCE))
2225 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2226 (state->dir == MODE_DEL &&
2227 ircd_strcmp(state->chptr->mode.key, t_str))) {
2228 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2232 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2233 !ircd_strcmp(state->chptr->mode.key, t_str))
2234 return; /* no key change */
2236 if (state->flags & MODE_PARSE_BOUNCE) {
2237 if (*state->chptr->mode.key) /* reset old key */
2238 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2239 state->chptr->mode.key, 0);
2240 else /* remove new bogus key */
2241 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2242 } else /* send new key */
2243 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2245 if (state->flags & MODE_PARSE_SET) {
2246 if (state->dir == MODE_ADD) /* set the new key */
2247 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2248 else /* remove the old key */
2249 *state->chptr->mode.key = '\0';
2254 * Helper function to convert user passes
2257 mode_parse_upass(struct ParseState *state, int *flag_p)
2262 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2265 if (state->parc <= 0) { /* warn if not enough args */
2266 if (MyUser(state->sptr))
2267 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2272 t_str = state->parv[state->args_used++]; /* grab arg */
2276 /* If they're not an oper, they can't change modes */
2277 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2278 send_notoper(state);
2282 /* If they are not the channel manager, they are not allowed to change it */
2283 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2284 if (*state->chptr->mode.apass) {
2285 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2286 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2288 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2289 "Re-create the channel. The channel must be *empty* for",
2290 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2291 "before it can be recreated.");
2296 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2298 state->done |= DONE_UPASS;
2300 t_len = PASSLEN + 1;
2302 /* clean up the upass string */
2304 while (*++s > ' ' && *s != ':' && --t_len)
2308 if (!*t_str) { /* warn if empty */
2309 if (MyUser(state->sptr))
2310 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2318 if (!(state->flags & MODE_PARSE_FORCE))
2319 /* can't add the upass while apass is not set */
2320 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2321 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2324 /* can't add a upass if one is set, nor can one remove the wrong upass */
2325 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2326 (state->dir == MODE_DEL &&
2327 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2328 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2332 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2333 !ircd_strcmp(state->chptr->mode.upass, t_str))
2334 return; /* no upass change */
2336 if (state->flags & MODE_PARSE_BOUNCE) {
2337 if (*state->chptr->mode.upass) /* reset old upass */
2338 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2339 state->chptr->mode.upass, 0);
2340 else /* remove new bogus upass */
2341 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2342 } else /* send new upass */
2343 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2345 if (state->flags & MODE_PARSE_SET) {
2346 if (state->dir == MODE_ADD) /* set the new upass */
2347 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2348 else /* remove the old upass */
2349 *state->chptr->mode.upass = '\0';
2354 * Helper function to convert admin passes
2357 mode_parse_apass(struct ParseState *state, int *flag_p)
2362 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2365 if (state->parc <= 0) { /* warn if not enough args */
2366 if (MyUser(state->sptr))
2367 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2372 t_str = state->parv[state->args_used++]; /* grab arg */
2376 /* If they're not an oper, they can't change modes */
2377 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2378 send_notoper(state);
2382 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2383 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2384 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2388 /* If they are not the channel manager, they are not allowed to change it */
2389 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2390 if (*state->chptr->mode.apass) {
2391 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2392 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2394 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2395 "Re-create the channel. The channel must be *empty* for",
2396 "at least a whole minute", "before it can be recreated.");
2401 if (state->done & DONE_APASS) /* allow apass to be set only once */
2403 state->done |= DONE_APASS;
2405 t_len = PASSLEN + 1;
2407 /* clean up the apass string */
2409 while (*++s > ' ' && *s != ':' && --t_len)
2413 if (!*t_str) { /* warn if empty */
2414 if (MyUser(state->sptr))
2415 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2423 if (!(state->flags & MODE_PARSE_FORCE)) {
2424 /* can't remove the apass while upass is still set */
2425 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2426 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2429 /* can't add an apass if one is set, nor can one remove the wrong apass */
2430 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2431 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2432 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2437 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2438 !ircd_strcmp(state->chptr->mode.apass, t_str))
2439 return; /* no apass change */
2441 if (state->flags & MODE_PARSE_BOUNCE) {
2442 if (*state->chptr->mode.apass) /* reset old apass */
2443 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2444 state->chptr->mode.apass, 0);
2445 else /* remove new bogus apass */
2446 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2447 } else /* send new apass */
2448 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2450 if (state->flags & MODE_PARSE_SET) {
2451 if (state->dir == MODE_ADD) { /* set the new apass */
2452 /* Make it VERY clear to the user that this is a one-time password */
2453 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2454 if (MyUser(state->sptr)) {
2455 send_reply(state->sptr, RPL_APASSWARN,
2456 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2457 "Are you SURE you want to use this as Admin password? ",
2458 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2459 send_reply(state->sptr, RPL_APASSWARN,
2460 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2461 "\" to remove the password and then immediately set a new one. "
2462 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2463 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2464 "Now set the channel user password (+u).");
2466 } else { /* remove the old apass */
2467 *state->chptr->mode.apass = '\0';
2468 if (MyUser(state->sptr))
2469 send_reply(state->sptr, RPL_APASSWARN,
2470 "WARNING: You removed the channel Admin password MODE (+A). ",
2471 "If you would disconnect or leave the channel without setting a new password then you will ",
2472 "not be able to set it again and lose ownership of this channel! ",
2473 "SET A NEW PASSWORD NOW!", "");
2479 * Helper function to convert bans
2482 mode_parse_ban(struct ParseState *state, int *flag_p)
2485 struct SLink *ban, *newban = 0;
2487 if (state->parc <= 0) { /* Not enough args, send ban list */
2488 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2489 send_ban_list(state->sptr, state->chptr);
2490 state->done |= DONE_BANLIST;
2496 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2499 t_str = state->parv[state->args_used++]; /* grab arg */
2503 /* If they're not an oper, they can't change modes */
2504 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2505 send_notoper(state);
2509 if ((s = strchr(t_str, ' ')))
2512 if (!*t_str || *t_str == ':') { /* warn if empty */
2513 if (MyUser(state->sptr))
2514 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2519 t_str = collapse(pretty_mask(t_str));
2521 /* remember the ban for the moment... */
2522 if (state->dir == MODE_ADD) {
2523 newban = state->banlist + (state->numbans++);
2526 DupString(newban->value.ban.banstr, t_str);
2527 newban->value.ban.who = cli_name(state->sptr);
2528 newban->value.ban.when = TStime();
2530 newban->flags = CHFL_BAN | MODE_ADD;
2532 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2533 newban->flags |= CHFL_BAN_IPMASK;
2536 if (!state->chptr->banlist) {
2537 state->chptr->banlist = newban; /* add our ban with its flags */
2538 state->done |= DONE_BANCLEAN;
2542 /* Go through all bans */
2543 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2544 /* first, clean the ban flags up a bit */
2545 if (!(state->done & DONE_BANCLEAN))
2546 /* Note: We're overloading *lots* of bits here; be careful! */
2547 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2551 * MODE_ADD - Ban was added; if we're bouncing modes,
2552 * then we'll remove it below; otherwise,
2553 * we'll have to allocate a real ban
2555 * MODE_DEL - Ban was marked for deletion; if we're
2556 * bouncing modes, we'll have to re-add it,
2557 * otherwise, we'll have to remove it
2559 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2560 * with a ban already set; if we're
2561 * bouncing modes, we'll have to bounce
2562 * this one; otherwise, we'll just ignore
2563 * it when we process added bans
2566 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2567 ban->flags |= MODE_DEL; /* delete one ban */
2569 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2571 } else if (state->dir == MODE_ADD) {
2572 /* if the ban already exists, don't worry about it */
2573 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2574 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2575 MyFree(newban->value.ban.banstr); /* stopper a leak */
2576 state->numbans--; /* deallocate last ban */
2577 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2579 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2580 if (!(ban->flags & MODE_DEL))
2581 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2582 } else if (!mmatch(t_str, ban->value.ban.banstr))
2583 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2585 if (!ban->next && (newban->flags & MODE_ADD))
2587 ban->next = newban; /* add our ban with its flags */
2588 break; /* get out of loop */
2592 state->done |= DONE_BANCLEAN;
2596 * This is the bottom half of the ban processor
2599 mode_process_bans(struct ParseState *state)
2601 struct SLink *ban, *newban, *prevban, *nextban;
2607 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2609 banlen = strlen(ban->value.ban.banstr);
2611 nextban = ban->next;
2613 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2615 prevban->next = 0; /* Break the list; ban isn't a real ban */
2617 state->chptr->banlist = 0;
2622 MyFree(ban->value.ban.banstr);
2625 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2626 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2627 ban->value.ban.banstr,
2628 state->flags & MODE_PARSE_SET);
2630 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2631 if (prevban) /* clip it out of the list... */
2632 prevban->next = ban->next;
2634 state->chptr->banlist = ban->next;
2639 MyFree(ban->value.ban.who);
2643 continue; /* next ban; keep prevban like it is */
2645 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2646 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2648 prevban->next = 0; /* Break the list; ban isn't a real ban */
2650 state->chptr->banlist = 0;
2652 /* If we're supposed to ignore it, do so. */
2653 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2654 !(state->flags & MODE_PARSE_BOUNCE)) {
2658 MyFree(ban->value.ban.banstr);
2660 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2661 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2662 count > feature_int(FEAT_MAXBANS))) {
2663 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2664 ban->value.ban.banstr);
2668 MyFree(ban->value.ban.banstr);
2670 /* add the ban to the buffer */
2671 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2672 ban->value.ban.banstr,
2673 !(state->flags & MODE_PARSE_SET));
2675 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2676 newban = make_link();
2677 newban->value.ban.banstr = ban->value.ban.banstr;
2678 DupString(newban->value.ban.who, ban->value.ban.who);
2679 newban->value.ban.when = ban->value.ban.when;
2680 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2682 newban->next = state->chptr->banlist; /* and link it in */
2683 state->chptr->banlist = newban;
2692 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2694 if (changed) /* if we changed the ban list, we must invalidate the bans */
2695 mode_ban_invalidate(state->chptr);
2699 * Helper function to process client changes
2702 mode_parse_client(struct ParseState *state, int *flag_p)
2705 struct Client *acptr;
2708 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2711 if (state->parc <= 0) /* return if not enough args */
2714 t_str = state->parv[state->args_used++]; /* grab arg */
2718 /* If they're not an oper, they can't change modes */
2719 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2720 send_notoper(state);
2724 if (MyUser(state->sptr)) /* find client we're manipulating */
2725 acptr = find_chasing(state->sptr, t_str, NULL);
2727 acptr = findNUser(t_str);
2730 return; /* find_chasing() already reported an error to the user */
2732 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2733 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2734 state->cli_change[i].flag & flag_p[0]))
2735 break; /* found a slot */
2737 /* Store what we're doing to them */
2738 state->cli_change[i].flag = state->dir | flag_p[0];
2739 state->cli_change[i].client = acptr;
2743 * Helper function to process the changed client list
2746 mode_process_clients(struct ParseState *state)
2749 struct Membership *member;
2751 for (i = 0; state->cli_change[i].flag; i++) {
2752 assert(0 != state->cli_change[i].client);
2754 /* look up member link */
2755 if (!(member = find_member_link(state->chptr,
2756 state->cli_change[i].client)) ||
2757 (MyUser(state->sptr) && IsZombie(member))) {
2758 if (MyUser(state->sptr))
2759 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2760 cli_name(state->cli_change[i].client),
2761 state->chptr->chname);
2765 if ((state->cli_change[i].flag & MODE_ADD &&
2766 (state->cli_change[i].flag & member->status)) ||
2767 (state->cli_change[i].flag & MODE_DEL &&
2768 !(state->cli_change[i].flag & member->status)))
2769 continue; /* no change made, don't do anything */
2771 /* see if the deop is allowed */
2772 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2773 (MODE_DEL | MODE_CHANOP)) {
2774 /* prevent +k users from being deopped */
2775 if (IsChannelService(state->cli_change[i].client)) {
2776 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2777 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2779 (IsServer(state->sptr) ? cli_name(state->sptr) :
2780 cli_name((cli_user(state->sptr))->server)));
2782 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2783 send_reply(state->sptr, ERR_ISCHANSERVICE,
2784 cli_name(state->cli_change[i].client),
2785 state->chptr->chname);
2790 /* check deop for local user */
2791 if (MyUser(state->sptr)) {
2793 /* don't allow local opers to be deopped on local channels */
2794 if (MyUser(state->sptr) &&
2795 state->cli_change[i].client != state->sptr &&
2796 IsLocalChannel(state->chptr->chname) &&
2797 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2798 send_reply(state->sptr, ERR_ISOPERLCHAN,
2799 cli_name(state->cli_change[i].client),
2800 state->chptr->chname);
2804 if (feature_bool(FEAT_OPLEVELS)) {
2805 /* don't allow to deop members with an op level that is <= our own level */
2806 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2808 && OpLevel(member) <= OpLevel(state->member)) {
2809 int equal = (OpLevel(member) == OpLevel(state->member));
2810 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2811 cli_name(state->cli_change[i].client),
2812 state->chptr->chname,
2813 OpLevel(state->member), OpLevel(member),
2814 "deop", equal ? "the same" : "a higher");
2821 /* set op-level of member being opped */
2822 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2823 (MODE_ADD | MODE_CHANOP)) {
2824 /* If on a channel with upass set, someone with level x gives ops to someone else,
2825 then that person gets level x-1. On other channels, where upass is not set,
2826 the level stays the same. */
2827 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2828 /* Someone being opped by a server gets op-level 0 */
2829 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2830 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2833 /* accumulate the change */
2834 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2835 state->cli_change[i].client);
2837 /* actually effect the change */
2838 if (state->flags & MODE_PARSE_SET) {
2839 if (state->cli_change[i].flag & MODE_ADD) {
2840 member->status |= (state->cli_change[i].flag &
2841 (MODE_CHANOP | MODE_VOICE));
2842 if (state->cli_change[i].flag & MODE_CHANOP)
2843 ClearDeopped(member);
2845 member->status &= ~(state->cli_change[i].flag &
2846 (MODE_CHANOP | MODE_VOICE));
2848 } /* for (i = 0; state->cli_change[i].flags; i++) */
2852 * Helper function to process the simple modes
2855 mode_parse_mode(struct ParseState *state, int *flag_p)
2857 /* If they're not an oper, they can't change modes */
2858 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2859 send_notoper(state);
2866 if (state->dir == MODE_ADD) {
2867 state->add |= flag_p[0];
2868 state->del &= ~flag_p[0];
2870 if (flag_p[0] & MODE_SECRET) {
2871 state->add &= ~MODE_PRIVATE;
2872 state->del |= MODE_PRIVATE;
2873 } else if (flag_p[0] & MODE_PRIVATE) {
2874 state->add &= ~MODE_SECRET;
2875 state->del |= MODE_SECRET;
2878 state->add &= ~flag_p[0];
2879 state->del |= flag_p[0];
2882 assert(0 == (state->add & state->del));
2883 assert((MODE_SECRET | MODE_PRIVATE) !=
2884 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2888 * This routine is intended to parse MODE or OPMODE commands and effect the
2889 * changes (or just build the bounce buffer). We pass the starting offset
2893 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2894 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2895 struct Membership* member)
2897 static int chan_flags[] = {
2902 MODE_MODERATED, 'm',
2903 MODE_TOPICLIMIT, 't',
2904 MODE_INVITEONLY, 'i',
2905 MODE_NOPRIVMSGS, 'n',
2918 unsigned int t_mode;
2920 struct ParseState state;
2931 state.chptr = chptr;
2932 state.member = member;
2935 state.flags = flags;
2936 state.dir = MODE_ADD;
2940 state.args_used = 0;
2941 state.max_args = MAXMODEPARAMS;
2944 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2945 state.banlist[i].next = 0;
2946 state.banlist[i].value.ban.banstr = 0;
2947 state.banlist[i].value.ban.who = 0;
2948 state.banlist[i].value.ban.when = 0;
2949 state.banlist[i].flags = 0;
2950 state.cli_change[i].flag = 0;
2951 state.cli_change[i].client = 0;
2954 modestr = state.parv[state.args_used++];
2958 for (; *modestr; modestr++) {
2959 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2960 if (flag_p[1] == *modestr)
2963 if (!flag_p[0]) { /* didn't find it? complain and continue */
2964 if (MyUser(state.sptr))
2965 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2970 case '+': /* switch direction to MODE_ADD */
2971 case '-': /* switch direction to MODE_DEL */
2972 state.dir = flag_p[0];
2975 case 'l': /* deal with limits */
2976 mode_parse_limit(&state, flag_p);
2979 case 'k': /* deal with keys */
2980 mode_parse_key(&state, flag_p);
2983 case 'A': /* deal with Admin passes */
2984 if (feature_bool(FEAT_OPLEVELS))
2985 mode_parse_apass(&state, flag_p);
2988 case 'u': /* deal with user passes */
2989 if (feature_bool(FEAT_OPLEVELS))
2990 mode_parse_upass(&state, flag_p);
2993 case 'b': /* deal with bans */
2994 mode_parse_ban(&state, flag_p);
2997 case 'o': /* deal with ops/voice */
2999 mode_parse_client(&state, flag_p);
3002 default: /* deal with other modes */
3003 mode_parse_mode(&state, flag_p);
3005 } /* switch (*modestr) */
3006 } /* for (; *modestr; modestr++) */
3008 if (state.flags & MODE_PARSE_BURST)
3009 break; /* don't interpret any more arguments */
3011 if (state.parc > 0) { /* process next argument in string */
3012 modestr = state.parv[state.args_used++];
3016 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3019 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3020 break; /* we're then going to bounce the mode! */
3022 recv_ts = atoi(modestr);
3024 if (recv_ts && recv_ts < state.chptr->creationtime)
3025 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3027 break; /* break out of while loop */
3028 } else if (state.flags & MODE_PARSE_STRICT ||
3029 (MyUser(state.sptr) && state.max_args <= 0)) {
3030 state.parc++; /* we didn't actually gobble the argument */
3032 break; /* break out of while loop */
3035 } /* while (*modestr) */
3038 * the rest of the function finishes building resultant MODEs; if the
3039 * origin isn't a member or an oper, skip it.
3041 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3042 return state.args_used; /* tell our parent how many args we gobbled */
3044 t_mode = state.chptr->mode.mode;
3046 if (state.del & t_mode) { /* delete any modes to be deleted... */
3047 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3049 t_mode &= ~state.del;
3051 if (state.add & ~t_mode) { /* add any modes to be added... */
3052 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3054 t_mode |= state.add;
3057 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3058 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3059 !(t_mode & MODE_INVITEONLY))
3060 mode_invite_clear(state.chptr);
3062 state.chptr->mode.mode = t_mode;
3065 if (state.flags & MODE_PARSE_WIPEOUT) {
3066 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3067 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3068 state.chptr->mode.limit);
3069 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3070 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3071 state.chptr->mode.key, 0);
3072 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3073 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3074 state.chptr->mode.upass, 0);
3075 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3076 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3077 state.chptr->mode.apass, 0);
3080 if (state.done & DONE_BANCLEAN) /* process bans */
3081 mode_process_bans(&state);
3083 /* process client changes */
3084 if (state.cli_change[0].flag)
3085 mode_process_clients(&state);
3087 return state.args_used; /* tell our parent how many args we gobbled */
3091 * Initialize a join buffer
3094 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3095 struct Client *connect, unsigned int type, char *comment,
3101 assert(0 != source);
3102 assert(0 != connect);
3104 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3105 jbuf->jb_connect = connect;
3106 jbuf->jb_type = type;
3107 jbuf->jb_comment = comment;
3108 jbuf->jb_create = create;
3110 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3111 type == JOINBUF_TYPE_PART ||
3112 type == JOINBUF_TYPE_PARTALL) ?
3113 STARTJOINLEN : STARTCREATELEN) +
3114 (comment ? strlen(comment) + 2 : 0));
3116 for (i = 0; i < MAXJOINARGS; i++)
3117 jbuf->jb_channels[i] = 0;
3121 * Add a channel to the join buffer
3124 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3132 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3133 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3138 is_local = IsLocalChannel(chan->chname);
3140 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3141 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3142 /* Send notification to channel */
3143 if (!(flags & CHFL_ZOMBIE))
3144 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3145 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3146 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3147 else if (MyUser(jbuf->jb_source))
3148 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3149 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3150 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3151 /* XXX: Shouldn't we send a PART here anyway? */
3152 /* to users on the channel? Why? From their POV, the user isn't on
3153 * the channel anymore anyway. We don't send to servers until below,
3154 * when we gang all the channel parts together. Note that this is
3155 * exactly the same logic, albeit somewhat more concise, as was in
3156 * the original m_part.c */
3158 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3159 is_local) /* got to remove user here */
3160 remove_user_from_channel(jbuf->jb_source, chan);
3162 /* Add user to channel */
3163 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3165 /* send notification to all servers */
3166 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3167 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3168 "%H %Tu", chan, chan->creationtime);
3170 /* Send the notification to the channel */
3171 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3173 /* send an op, too, if needed */
3174 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3175 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3176 chan, jbuf->jb_source);
3179 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3180 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3181 return; /* don't send to remote */
3183 /* figure out if channel name will cause buffer to be overflowed */
3184 len = chan ? strlen(chan->chname) + 1 : 2;
3185 if (jbuf->jb_strlen + len > BUFSIZE)
3186 joinbuf_flush(jbuf);
3188 /* add channel to list of channels to send and update counts */
3189 jbuf->jb_channels[jbuf->jb_count++] = chan;
3190 jbuf->jb_strlen += len;
3192 /* if we've used up all slots, flush */
3193 if (jbuf->jb_count >= MAXJOINARGS)
3194 joinbuf_flush(jbuf);
3198 * Flush the channel list to remote servers
3201 joinbuf_flush(struct JoinBuf *jbuf)
3203 char chanlist[BUFSIZE];
3207 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3208 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3209 return 0; /* no joins to process */
3211 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3212 build_string(chanlist, &chanlist_i,
3213 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3214 i == 0 ? '\0' : ',');
3215 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3216 /* Remove user from channel */
3217 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3219 jbuf->jb_channels[i] = 0; /* mark slot empty */
3222 jbuf->jb_count = 0; /* reset base counters */
3223 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3224 STARTJOINLEN : STARTCREATELEN) +
3225 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3227 /* and send the appropriate command */
3228 switch (jbuf->jb_type) {
3229 case JOINBUF_TYPE_CREATE:
3230 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3231 "%s %Tu", chanlist, jbuf->jb_create);
3234 case JOINBUF_TYPE_PART:
3235 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3236 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3244 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3245 int IsInvited(struct Client* cptr, const void* chptr)
3249 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3250 if (lp->value.chptr == chptr)