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 (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
222 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
224 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
229 int destruct_channel(struct Channel* chptr)
234 assert(0 == chptr->members);
236 /* Channel became (or was) empty: Remove channel */
237 if (is_listed(chptr))
240 for (i = 0; i <= HighestFd; i++)
242 struct Client *acptr = 0;
243 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
244 (cli_listing(acptr))->chptr == chptr)
246 list_next_channels(acptr, 1);
247 break; /* Only one client can list a channel */
252 * Now, find all invite links from channel structure
254 while ((tmp = chptr->invites))
255 del_invite(tmp->value.cptr, chptr);
257 tmp = chptr->banlist;
262 MyFree(obtmp->value.ban.banstr);
263 MyFree(obtmp->value.ban.who);
267 chptr->prev->next = chptr->next;
269 GlobalChannelList = chptr->next;
271 chptr->next->prev = chptr->prev;
273 --UserStats.channels;
275 * make sure that channel actually got removed from hash table
277 assert(chptr->hnext == chptr);
285 * `cptr' must be the client adding the ban.
287 * If `change' is true then add `banid' to channel `chptr'.
288 * Returns 0 if the ban was added.
289 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
290 * Return -1 otherwise.
292 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
293 * when `change' is false, otherwise they will be removed from the banlist.
294 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
295 * respectively will return these bans until NULL is returned.
297 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
298 * is reset (unless a non-zero value is returned, in which case the
299 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
303 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
304 int change, int firsttime)
309 int removed_bans = 0;
310 int len = strlen(banid);
315 assert(0 == prev_ban);
316 assert(0 == removed_bans_list);
320 for (banp = &chptr->banlist; *banp;)
322 len += strlen((*banp)->value.ban.banstr);
324 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
326 if (!strcmp((*banp)->value.ban.banstr, banid))
328 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
332 else if (!mmatch((*banp)->value.ban.banstr, banid))
334 if (!mmatch(banid, (*banp)->value.ban.banstr))
336 struct SLink *tmp = *banp;
342 len -= strlen(tmp->value.ban.banstr);
345 /* These will be sent to the user later as -b */
346 tmp->next = removed_bans_list;
347 removed_bans_list = tmp;
350 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
352 tmp->flags |= CHFL_BAN_OVERLAPPED;
363 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
364 banp = &(*banp)->next;
367 if (MyUser(cptr) && !removed_bans &&
368 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
369 (cnt >= feature_int(FEAT_MAXBANS))))
371 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
377 struct Membership* member;
379 ban->next = chptr->banlist;
381 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
382 assert(0 != ban->value.ban.banstr);
383 strcpy(ban->value.ban.banstr, banid);
385 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
386 DupString(ban->value.ban.who, cli_name(&me));
388 DupString(ban->value.ban.who, cli_name(cptr));
389 assert(0 != ban->value.ban.who);
391 ban->value.ban.when = TStime();
392 ban->flags = CHFL_BAN; /* This bit is never used I think... */
393 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
394 ban->flags |= CHFL_BAN_IPMASK;
395 chptr->banlist = ban;
398 * Erase ban-valid-bit
400 for (member = chptr->members; member; member = member->next_member)
401 ClearBanValid(member); /* `ban' == channel member ! */
406 struct SLink *next_removed_overlapped_ban(void)
408 struct SLink *tmp = removed_bans_list;
411 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
412 MyFree(prev_ban->value.ban.banstr);
413 MyFree(prev_ban->value.ban.who);
418 removed_bans_list = removed_bans_list->next;
424 * find_channel_member - returns Membership * if a person is joined and not a zombie
426 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
428 struct Membership* member;
431 member = find_member_link(chptr, cptr);
432 return (member && !IsZombie(member)) ? member : 0;
436 * is_banned - a non-zero value if banned else 0.
438 static int is_banned(struct Client *cptr, struct Channel *chptr,
439 struct Membership* member)
442 char tmphost[HOSTLEN + 1];
443 char nu_host[NUH_BUFSIZE];
444 char nu_realhost[NUH_BUFSIZE];
445 char nu_ip[NUI_BUFSIZE];
453 if (member && IsBanValid(member))
454 return IsBanned(member);
456 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
457 (cli_user(cptr))->host);
460 if (HasHiddenHost(cptr))
462 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
463 (cli_user(cptr))->username,
464 cli_user(cptr)->realhost);
468 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
469 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
470 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
471 cli_user(cptr)->username,
476 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
477 if ((tmp->flags & CHFL_BAN_IPMASK)) {
479 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
480 (cli_user(cptr))->username, cli_ip(cptr));
481 if (match(tmp->value.ban.banstr, ip_s) == 0)
484 else if (match(tmp->value.ban.banstr, s) == 0)
486 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
502 return (tmp != NULL);
506 * adds a user to a channel by adding another link to the channels member
509 void add_user_to_channel(struct Channel* chptr, struct Client* who,
510 unsigned int flags, int oplevel)
517 struct Membership* member = membershipFreeList;
519 membershipFreeList = member->next_member;
521 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
522 ++membershipAllocCount;
527 member->channel = chptr;
528 member->status = flags;
529 member->oplevel = oplevel;
531 member->next_member = chptr->members;
532 if (member->next_member)
533 member->next_member->prev_member = member;
534 member->prev_member = 0;
535 chptr->members = member;
537 member->next_channel = (cli_user(who))->channel;
538 if (member->next_channel)
539 member->next_channel->prev_channel = member;
540 member->prev_channel = 0;
541 (cli_user(who))->channel = member;
543 if (chptr->destruct_event)
544 remove_destruct_event(chptr);
546 ++((cli_user(who))->joined);
550 static int remove_member_from_channel(struct Membership* member)
552 struct Channel* chptr;
554 chptr = member->channel;
556 * unlink channel member list
558 if (member->next_member)
559 member->next_member->prev_member = member->prev_member;
560 if (member->prev_member)
561 member->prev_member->next_member = member->next_member;
563 member->channel->members = member->next_member;
566 * unlink client channel list
568 if (member->next_channel)
569 member->next_channel->prev_channel = member->prev_channel;
570 if (member->prev_channel)
571 member->prev_channel->next_channel = member->next_channel;
573 (cli_user(member->user))->channel = member->next_channel;
575 --(cli_user(member->user))->joined;
577 member->next_member = membershipFreeList;
578 membershipFreeList = member;
580 return sub1_from_channel(chptr);
583 static int channel_all_zombies(struct Channel* chptr)
585 struct Membership* member;
587 for (member = chptr->members; member; member = member->next_member) {
588 if (!IsZombie(member))
595 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
598 struct Membership* member;
601 if ((member = find_member_link(chptr, cptr))) {
602 if (remove_member_from_channel(member)) {
603 if (channel_all_zombies(chptr)) {
605 * XXX - this looks dangerous but isn't if we got the referential
606 * integrity right for channels
608 while (remove_member_from_channel(chptr->members))
615 void remove_user_from_all_channels(struct Client* cptr)
617 struct Membership* chan;
619 assert(0 != cli_user(cptr));
621 while ((chan = (cli_user(cptr))->channel))
622 remove_user_from_channel(cptr, chan->channel);
625 int is_chan_op(struct Client *cptr, struct Channel *chptr)
627 struct Membership* member;
629 if ((member = find_member_link(chptr, cptr)))
630 return (!IsZombie(member) && IsChanOp(member));
635 int is_zombie(struct Client *cptr, struct Channel *chptr)
637 struct Membership* member;
641 if ((member = find_member_link(chptr, cptr)))
642 return IsZombie(member);
646 int has_voice(struct Client* cptr, struct Channel* chptr)
648 struct Membership* member;
651 if ((member = find_member_link(chptr, cptr)))
652 return (!IsZombie(member) && HasVoice(member));
657 int member_can_send_to_channel(struct Membership* member)
661 /* Discourage using the Apass to get op. They should use the upass. */
662 if (IsChannelManager(member) && *member->channel->mode.upass)
665 if (IsVoicedOrOpped(member))
668 * If it's moderated, and you aren't a priviledged user, you can't
671 if (member->channel->mode.mode & MODE_MODERATED)
674 * If you're banned then you can't speak either.
675 * but because of the amount of CPU time that is_banned chews
676 * we only check it for our clients.
678 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
683 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr)
685 struct Membership *member;
688 * Servers can always speak on channels.
693 member = find_channel_member(cptr, chptr);
696 * You can't speak if you're off channel, and it is +n (no external messages)
700 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
701 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
704 return !is_banned(cptr, chptr, NULL);
706 return member_can_send_to_channel(member);
710 * find_no_nickchange_channel
711 * if a member and not opped or voiced and banned
712 * return the name of the first channel banned on
714 const char* find_no_nickchange_channel(struct Client* cptr)
717 struct Membership* member;
718 for (member = (cli_user(cptr))->channel; member;
719 member = member->next_channel) {
720 if (!IsVoicedOrOpped(member) && is_banned(cptr, member->channel, member))
721 return member->channel->chname;
729 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
730 * with the parameters in pbuf.
732 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
733 struct Channel *chptr, struct Membership *member)
735 int previous_parameter = 0;
742 if (chptr->mode.mode & MODE_SECRET)
744 else if (chptr->mode.mode & MODE_PRIVATE)
746 if (chptr->mode.mode & MODE_MODERATED)
748 if (chptr->mode.mode & MODE_TOPICLIMIT)
750 if (chptr->mode.mode & MODE_INVITEONLY)
752 if (chptr->mode.mode & MODE_NOPRIVMSGS)
754 if (chptr->mode.mode & MODE_REGONLY)
756 if (chptr->mode.limit) {
758 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
759 previous_parameter = 1;
762 if (*chptr->mode.key) {
764 if (previous_parameter)
766 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
767 strcat(pbuf, chptr->mode.key);
770 previous_parameter = 1;
772 if (*chptr->mode.apass) {
774 if (previous_parameter)
776 if (IsServer(cptr)) {
777 strcat(pbuf, chptr->mode.apass);
780 previous_parameter = 1;
782 if (*chptr->mode.upass) {
784 if (previous_parameter)
786 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
787 strcat(pbuf, chptr->mode.upass);
794 int compare_member_oplevel(const void *mp1, const void *mp2)
796 struct Membership const* member1 = *(struct Membership const**)mp1;
797 struct Membership const* member2 = *(struct Membership const**)mp2;
798 if (member1->oplevel == member2->oplevel)
800 return (member1->oplevel < member2->oplevel) ? -1 : 1;
804 * send "cptr" a full list of the modes for channel chptr.
806 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
808 /* The order in which modes are generated is now mandatory */
809 static unsigned int current_flags[4] =
810 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
816 struct Membership* member;
818 char modebuf[MODEBUFLEN];
819 char parabuf[MODEBUFLEN];
821 int number_of_ops = 0;
822 int opped_members_index = 0;
823 struct Membership** opped_members = NULL;
824 int last_oplevel = 0;
829 if (IsLocalChannel(chptr->chname))
832 member = chptr->members;
833 lp2 = chptr->banlist;
835 *modebuf = *parabuf = '\0';
836 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
838 for (first = 1; full; first = 0) /* Loop for multiple messages */
840 full = 0; /* Assume by default we get it
841 all in one message */
843 /* (Continued) prefix: "<Y> B <channel> <TS>" */
844 /* is there any better way we can do this? */
845 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
846 chptr->creationtime);
848 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
851 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
852 msgq_append(&me, mb, " %s", modebuf);
855 msgq_append(&me, mb, " %s", parabuf);
859 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
861 * First find all opless members.
862 * Run 2 times over all members, to group the members with
863 * and without voice together.
864 * Then run 2 times over all opped members (which are ordered
865 * by op-level) to also group voice and non-voice together.
867 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
871 if (flag_cnt < 2 && IsChanOp(member))
874 * The first loop (to find all non-voice/op), we count the ops.
875 * The second loop (to find all voiced non-ops), store the ops
876 * in a dynamic array.
881 opped_members[opped_members_index++] = member;
883 /* Only handle the members with the flags that we are interested in. */
884 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
886 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
887 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
889 full = 1; /* Make sure we continue after
891 /* Ensure the new BURST line contains the current
892 * ":mode", except when there is no mode yet. */
893 new_mode = (flag_cnt > 0) ? 1 : 0;
894 break; /* Do not add this member to this message */
896 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
897 first = 0; /* From now on, use commas to add new nicks */
900 * Do we have a nick with a new mode ?
901 * Or are we starting a new BURST line?
906 * This means we are at the _first_ member that has only
907 * voice, or the first member that has only ops, or the
908 * first member that has voice and ops (so we get here
909 * at most three times, plus once for every start of
910 * a continued BURST line where only these modes is current.
911 * In the two cases where the current mode includes ops,
912 * we need to add the _absolute_ value of the oplevel to the mode.
914 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
917 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
919 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
921 /* append the absolute value of the oplevel */
922 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
923 last_oplevel = member->oplevel;
926 msgq_append(&me, mb, tbuf);
929 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
932 * This can't be the first member of a (continued) BURST
933 * message because then either flag_cnt == 0 or new_mode == 1
934 * Now we need to append the incremental value of the oplevel.
936 char tbuf[2 + MAXOPLEVELDIGITS];
937 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
938 last_oplevel = member->oplevel;
939 msgq_append(&me, mb, tbuf);
942 /* Go to the next `member'. */
944 member = member->next_member;
946 member = opped_members[++opped_members_index];
951 /* Point `member' at the start of the list again. */
954 member = chptr->members;
955 /* Now, after one loop, we know the number of ops and can
956 * allocate the dynamic array with pointer to the ops. */
957 opped_members = (struct Membership**)
958 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
959 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
963 /* At the end of the second loop, sort the opped members with
964 * increasing op-level, so that we will output them in the
965 * correct order (and all op-level increments stay positive) */
967 qsort(opped_members, number_of_ops,
968 sizeof(struct Membership*), compare_member_oplevel);
969 /* The third and fourth loop run only over the opped members. */
970 member = opped_members[(opped_members_index = 0)];
973 } /* loop over 0,+v,+o,+ov */
977 /* Attach all bans, space seperated " :%ban ban ..." */
978 for (first = 2; lp2; lp2 = lp2->next)
980 len = strlen(lp2->value.ban.banstr);
981 if (msgq_bufleft(mb) < len + 1 + first)
982 /* The +1 stands for the added ' '.
983 * The +first stands for the added ":%".
989 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
990 lp2->value.ban.banstr);
995 send_buffer(cptr, mb, 0); /* Send this message */
997 } /* Continue when there was something
998 that didn't fit (full==1) */
1000 MyFree(opped_members);
1006 * by Carlo Wood (Run), 05 Oct 1998.
1010 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1011 * When the user name or host name are too long (USERLEN and HOSTLEN
1012 * respectively) then they are cut off at the start with a '*'.
1014 * The following transformations are made:
1016 * 1) xxx -> nick!*@*
1017 * 2) xxx.xxx -> *!*@host
1018 * 3) xxx!yyy -> nick!user@*
1019 * 4) xxx@yyy -> *!user@host
1020 * 5) xxx!yyy@zzz -> nick!user@host
1022 char *pretty_mask(char *mask)
1024 static char star[2] = { '*', 0 };
1025 static char retmask[NUH_BUFSIZE];
1026 char *last_dot = NULL;
1029 /* Case 1: default */
1034 /* Do a _single_ pass through the characters of the mask: */
1035 for (ptr = mask; *ptr; ++ptr)
1039 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1043 else if (*ptr == '@')
1045 /* Case 4: Found last '@' (without finding a '!' yet) */
1050 else if (*ptr == '.')
1052 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1062 /* Case 4 or 5: Found last '@' */
1068 if (user == star && last_dot)
1078 char *nick_end = (user != star) ? user - 1 : ptr;
1079 if (nick_end - nick > NICKLEN)
1085 char *user_end = (host != star) ? host - 1 : ptr;
1086 if (user_end - user > USERLEN)
1088 user = user_end - USERLEN;
1093 if (host != star && ptr - host > HOSTLEN)
1095 host = ptr - HOSTLEN;
1098 return make_nick_user_host(retmask, nick, user, host);
1101 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1108 for (lp = chptr->banlist; lp; lp = lp->next)
1109 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1110 lp->value.ban.who, lp->value.ban.when);
1112 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1115 /* We are now treating the <key> part of /join <channel list> <key> as a key
1116 * ring; that is, we try one key against the actual channel key, and if that
1117 * doesn't work, we try the next one, and so on. -Kev -Texaco
1118 * Returns: 0 on match, 1 otherwise
1119 * This version contributed by SeKs <intru@info.polymtl.ca>
1121 static int compall(char *key, char *keyring)
1126 p1 = key; /* point to the key... */
1127 while (*p1 && *p1 == *keyring)
1128 { /* step through the key and ring until they
1134 if (!*p1 && (!*keyring || *keyring == ','))
1135 /* ok, if we're at the end of the and also at the end of one of the keys
1136 in the keyring, we have a match */
1139 if (!*keyring) /* if we're at the end of the key ring, there
1140 weren't any matches, so we return 1 */
1143 /* Not at the end of the key ring, so step
1144 through to the next key in the ring: */
1145 while (*keyring && *(keyring++) != ',');
1147 goto top; /* and check it against the key */
1150 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1153 int overrideJoin = 0;
1156 * Now a banned user CAN join if invited -- Nemesi
1157 * Now a user CAN escape channel limit if invited -- bfriendly
1158 * Now a user CAN escape anything if invited -- Isomer
1161 for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1162 if (lp->value.chptr == chptr)
1165 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1166 a HACK(4) notice will be sent if he would not have been supposed
1167 to join normally. */
1168 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1169 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1170 compall("OVERRIDE",key) == 0)
1171 overrideJoin = MAGIC_OPER_OVERRIDE;
1173 if (chptr->mode.mode & MODE_INVITEONLY)
1174 return overrideJoin + ERR_INVITEONLYCHAN;
1176 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1177 return overrideJoin + ERR_CHANNELISFULL;
1179 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1180 return overrideJoin + ERR_NEEDREGGEDNICK;
1182 if (is_banned(sptr, chptr, NULL))
1183 return overrideJoin + ERR_BANNEDFROMCHAN;
1186 * now using compall (above) to test against a whole key ring -Kev
1188 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1189 return overrideJoin + ERR_BADCHANNELKEY;
1192 return ERR_DONTCHEAT;
1198 * Remove bells and commas from channel name
1200 void clean_channelname(char *cn)
1204 for (i = 0; cn[i]; i++) {
1205 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1209 if (IsChannelLower(cn[i])) {
1210 cn[i] = ToLower(cn[i]);
1216 if ((unsigned char)(cn[i]) == 0xd0)
1217 cn[i] = (char) 0xf0;
1224 * Get Channel block for i (and allocate a new channel
1225 * block, if it didn't exists before).
1227 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1229 struct Channel *chptr;
1232 if (EmptyString(chname))
1235 len = strlen(chname);
1236 if (MyUser(cptr) && len > CHANNELLEN)
1239 *(chname + CHANNELLEN) = '\0';
1241 if ((chptr = FindChannel(chname)))
1243 if (flag == CGT_CREATE)
1245 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1247 ++UserStats.channels;
1248 memset(chptr, 0, sizeof(struct Channel));
1249 strcpy(chptr->chname, chname);
1250 if (GlobalChannelList)
1251 GlobalChannelList->prev = chptr;
1253 chptr->next = GlobalChannelList;
1254 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1255 GlobalChannelList = chptr;
1261 void add_invite(struct Client *cptr, struct Channel *chptr)
1263 struct SLink *inv, **tmp;
1265 del_invite(cptr, chptr);
1267 * Delete last link in chain if the list is max length
1269 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1270 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1271 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1273 * Add client to channel invite list
1276 inv->value.cptr = cptr;
1277 inv->next = chptr->invites;
1278 chptr->invites = inv;
1280 * Add channel to the end of the client invite list
1282 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1284 inv->value.chptr = chptr;
1287 (cli_user(cptr))->invites++;
1291 * Delete Invite block from channel invite list and client invite list
1293 void del_invite(struct Client *cptr, struct Channel *chptr)
1295 struct SLink **inv, *tmp;
1297 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1298 if (tmp->value.cptr == cptr)
1303 (cli_user(cptr))->invites--;
1307 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1308 if (tmp->value.chptr == chptr)
1317 /* List and skip all channels that are listen */
1318 void list_next_channels(struct Client *cptr, int nr)
1320 struct ListingArgs *args = cli_listing(cptr);
1321 struct Channel *chptr = args->chptr;
1322 chptr->mode.mode &= ~MODE_LISTED;
1323 while (is_listed(chptr) || --nr >= 0)
1325 for (; chptr; chptr = chptr->next)
1327 if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1328 SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1330 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1331 chptr->creationtime > args->min_time &&
1332 chptr->creationtime < args->max_time &&
1333 (!args->topic_limits || (*chptr->topic &&
1334 chptr->topic_time > args->min_topic_time &&
1335 chptr->topic_time < args->max_topic_time)))
1337 if (ShowChannel(cptr,chptr))
1338 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1340 chptr = chptr->next;
1346 MyFree(cli_listing(cptr));
1347 cli_listing(cptr) = NULL;
1348 send_reply(cptr, RPL_LISTEND);
1354 (cli_listing(cptr))->chptr = chptr;
1355 chptr->mode.mode |= MODE_LISTED;
1368 * X --a--> A --b--> B --d--> D
1372 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1373 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1375 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1376 * Remove the user immediately when no users are left on the channel.
1377 * b) On server B : remove the user (who/lp) from the channel, send a
1378 * PART upstream (to A) and pass on the KICK.
1379 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1380 * channel, and pass on the KICK.
1381 * d) On server D : remove the user (who/lp) from the channel, and pass on
1385 * - Setting the ZOMBIE flag never hurts, we either remove the
1386 * client after that or we don't.
1387 * - The KICK message was already passed on, as should be in all cases.
1388 * - `who' is removed in all cases except case a) when users are left.
1389 * - A PART is only sent upstream in case b).
1395 * 1 --- 2 --- 3 --- 4 --- 5
1399 * We also need to turn 'who' into a zombie on servers 1 and 6,
1400 * because a KICK from 'who' (kicking someone else in that direction)
1401 * can arrive there afterwards - which should not be bounced itself.
1402 * Therefore case a) also applies for servers 1 and 6.
1406 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1407 struct Client* sptr, struct Channel* chptr)
1409 assert(0 != member);
1414 /* Default for case a): */
1417 /* Case b) or c) ?: */
1418 if (MyUser(who)) /* server 4 */
1420 if (IsServer(cptr)) /* Case b) ? */
1421 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1422 remove_user_from_channel(who, chptr);
1425 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1427 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1428 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1429 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1431 remove_user_from_channel(who, chptr);
1436 /* Case a) (servers 1, 2, 3 and 6) */
1437 if (channel_all_zombies(chptr))
1438 remove_user_from_channel(who, chptr);
1440 /* XXX Can't actually call Debug here; if the channel is all zombies,
1441 * chptr will no longer exist when we get here.
1442 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1446 int number_of_zombies(struct Channel *chptr)
1448 struct Membership* member;
1452 for (member = chptr->members; member; member = member->next_member) {
1453 if (IsZombie(member))
1460 * This helper function builds an argument string in strptr, consisting
1461 * of the original string, a space, and str1 and str2 concatenated (if,
1462 * of course, str2 is not NULL)
1465 build_string(char *strptr, int *strptr_i, const char *str1,
1466 const char *str2, char c)
1469 strptr[(*strptr_i)++] = c;
1472 strptr[(*strptr_i)++] = *(str1++);
1476 strptr[(*strptr_i)++] = *(str2++);
1478 strptr[(*strptr_i)] = '\0';
1482 * This is the workhorse of our ModeBuf suite; this actually generates the
1483 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1486 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1488 /* we only need the flags that don't take args right now */
1489 static int flags[] = {
1490 /* MODE_CHANOP, 'o', */
1491 /* MODE_VOICE, 'v', */
1494 MODE_MODERATED, 'm',
1495 MODE_TOPICLIMIT, 't',
1496 MODE_INVITEONLY, 'i',
1497 MODE_NOPRIVMSGS, 'n',
1499 /* MODE_KEY, 'k', */
1500 /* MODE_BAN, 'b', */
1501 /* MODE_LIMIT, 'l', */
1502 /* MODE_APASS, 'A', */
1503 /* MODE_UPASS, 'u', */
1509 struct Client *app_source; /* where the MODE appears to come from */
1511 char addbuf[20]; /* accumulates +psmtin, etc. */
1513 char rembuf[20]; /* accumulates -psmtin, etc. */
1515 char *bufptr; /* we make use of indirection to simplify the code */
1518 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1520 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1522 char *strptr; /* more indirection to simplify the code */
1525 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1528 char limitbuf[20]; /* convert limits to strings */
1530 unsigned int limitdel = MODE_LIMIT;
1534 /* If the ModeBuf is empty, we have nothing to do */
1535 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1538 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1540 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1543 app_source = mbuf->mb_source;
1546 * Account for user we're bouncing; we have to get it in on the first
1547 * bounced MODE, or we could have problems
1549 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1550 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1552 /* Calculate the simple flags */
1553 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1554 if (*flag_p & mbuf->mb_add)
1555 addbuf[addbuf_i++] = flag_p[1];
1556 else if (*flag_p & mbuf->mb_rem)
1557 rembuf[rembuf_i++] = flag_p[1];
1560 /* Now go through the modes with arguments... */
1561 for (i = 0; i < mbuf->mb_count; i++) {
1562 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1564 bufptr_i = &addbuf_i;
1567 bufptr_i = &rembuf_i;
1570 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1571 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1573 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1574 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1576 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1577 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1579 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1580 tmp = strlen(MB_STRING(mbuf, i));
1582 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1583 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1586 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1598 bufptr[(*bufptr_i)++] = mode_char;
1599 totalbuflen -= tmp + 1;
1601 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1602 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1603 strlen(MB_STRING(mbuf, i)));
1605 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1606 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1608 bufptr[(*bufptr_i)++] = 'k';
1609 totalbuflen -= tmp + 1;
1611 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1612 /* if it's a limit, we also format the number */
1613 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1615 tmp = strlen(limitbuf);
1617 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1618 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1620 bufptr[(*bufptr_i)++] = 'l';
1621 totalbuflen -= tmp + 1;
1626 /* terminate the mode strings */
1627 addbuf[addbuf_i] = '\0';
1628 rembuf[rembuf_i] = '\0';
1630 /* If we're building a user visible MODE or HACK... */
1631 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1632 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1633 MODEBUF_DEST_LOG)) {
1634 /* Set up the parameter strings */
1640 for (i = 0; i < mbuf->mb_count; i++) {
1641 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1644 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1646 strptr_i = &addstr_i;
1649 strptr_i = &remstr_i;
1652 /* deal with clients... */
1653 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1654 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1656 /* deal with bans... */
1657 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1658 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1660 /* deal with keys... */
1661 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1662 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1663 "*" : MB_STRING(mbuf, i), 0, ' ');
1665 /* deal with invisible passwords */
1666 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1667 build_string(strptr, strptr_i, "*", 0, ' ');
1670 * deal with limit; note we cannot include the limit parameter if we're
1673 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1674 (MODE_ADD | MODE_LIMIT))
1675 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1678 /* send the messages off to their destination */
1679 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1680 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1682 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1683 mbuf->mb_source : app_source),
1684 mbuf->mb_channel->chname,
1685 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1686 addbuf, remstr, addstr,
1687 mbuf->mb_channel->creationtime);
1689 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1690 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1691 "%s%s%s%s%s%s [%Tu]",
1692 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1693 mbuf->mb_source : app_source),
1694 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1695 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1696 mbuf->mb_channel->creationtime);
1698 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1699 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1701 #ifdef HEAD_IN_SAND_SNOTICES
1702 cli_name(mbuf->mb_source),
1704 cli_name(app_source),
1706 mbuf->mb_channel->chname,
1707 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1708 addbuf, remstr, addstr,
1709 mbuf->mb_channel->creationtime);
1711 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1712 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1713 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1714 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1715 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1717 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1718 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1719 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1720 rembuf_i ? "-" : "", rembuf,
1721 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1724 /* Now are we supposed to propagate to other servers? */
1725 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1726 /* set up parameter string */
1733 * limit is supressed if we're removing it; we have to figure out which
1734 * direction is the direction for it to be removed, though...
1736 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1738 for (i = 0; i < mbuf->mb_count; i++) {
1739 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1742 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1744 strptr_i = &addstr_i;
1747 strptr_i = &remstr_i;
1750 /* deal with modes that take clients */
1751 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1752 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1754 /* deal with modes that take strings */
1755 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1756 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1759 * deal with the limit. Logic here is complicated; if HACK2 is set,
1760 * we're bouncing the mode, so sense is reversed, and we have to
1761 * include the original limit if it looks like it's being removed
1763 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1764 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1767 /* we were told to deop the source */
1768 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1769 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1770 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1771 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1773 /* mark that we've done this, so we don't do it again */
1774 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1777 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1778 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1779 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1780 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1781 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1782 addbuf, remstr, addstr);
1783 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1785 * If HACK2 was set, we're bouncing; we send the MODE back to the
1786 * connection we got it from with the senses reversed and a TS of 0;
1789 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1790 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1791 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1792 mbuf->mb_channel->creationtime);
1795 * We're propagating a normal MODE command to the rest of the network;
1796 * we send the actual channel TS unless this is a HACK3 or a HACK4
1798 if (IsServer(mbuf->mb_source))
1799 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1800 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1801 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1802 addbuf, remstr, addstr,
1803 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1804 mbuf->mb_channel->creationtime);
1806 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1807 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1808 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1809 addbuf, remstr, addstr);
1813 /* We've drained the ModeBuf... */
1818 /* reinitialize the mode-with-arg slots */
1819 for (i = 0; i < MAXMODEPARAMS; i++) {
1820 /* If we saved any, pack them down */
1821 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1822 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1823 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1825 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1827 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1828 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1830 MB_TYPE(mbuf, i) = 0;
1831 MB_UINT(mbuf, i) = 0;
1834 /* If we're supposed to flush it all, do so--all hail tail recursion */
1835 if (all && mbuf->mb_count)
1836 return modebuf_flush_int(mbuf, 1);
1842 * This routine just initializes a ModeBuf structure with the information
1843 * needed and the options given.
1846 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1847 struct Client *connect, struct Channel *chan, unsigned int dest)
1852 assert(0 != source);
1858 mbuf->mb_source = source;
1859 mbuf->mb_connect = connect;
1860 mbuf->mb_channel = chan;
1861 mbuf->mb_dest = dest;
1864 /* clear each mode-with-parameter slot */
1865 for (i = 0; i < MAXMODEPARAMS; i++) {
1866 MB_TYPE(mbuf, i) = 0;
1867 MB_UINT(mbuf, i) = 0;
1872 * This routine simply adds modes to be added or deleted; do a binary OR
1873 * with either MODE_ADD or MODE_DEL
1876 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1879 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1881 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1882 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1884 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1887 if (mode & MODE_ADD) {
1888 mbuf->mb_rem &= ~mode;
1889 mbuf->mb_add |= mode;
1891 mbuf->mb_add &= ~mode;
1892 mbuf->mb_rem |= mode;
1897 * This routine adds a mode to be added or deleted that takes a unsigned
1898 * int parameter; mode may *only* be the relevant mode flag ORed with one
1899 * of MODE_ADD or MODE_DEL
1902 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1905 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1907 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1908 MB_UINT(mbuf, mbuf->mb_count) = uint;
1910 /* when we've reached the maximal count, flush the buffer */
1911 if (++mbuf->mb_count >=
1912 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1913 modebuf_flush_int(mbuf, 0);
1917 * This routine adds a mode to be added or deleted that takes a string
1918 * parameter; mode may *only* be the relevant mode flag ORed with one of
1919 * MODE_ADD or MODE_DEL
1922 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1926 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1928 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1929 MB_STRING(mbuf, mbuf->mb_count) = string;
1931 /* when we've reached the maximal count, flush the buffer */
1932 if (++mbuf->mb_count >=
1933 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1934 modebuf_flush_int(mbuf, 0);
1938 * This routine adds a mode to be added or deleted that takes a client
1939 * parameter; mode may *only* be the relevant mode flag ORed with one of
1940 * MODE_ADD or MODE_DEL
1943 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1944 struct Client *client)
1947 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1949 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1950 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1952 /* when we've reached the maximal count, flush the buffer */
1953 if (++mbuf->mb_count >=
1954 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1955 modebuf_flush_int(mbuf, 0);
1959 * This is the exported binding for modebuf_flush()
1962 modebuf_flush(struct ModeBuf *mbuf)
1964 return modebuf_flush_int(mbuf, 1);
1968 * This extracts the simple modes contained in mbuf
1971 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1973 static int flags[] = {
1974 /* MODE_CHANOP, 'o', */
1975 /* MODE_VOICE, 'v', */
1978 MODE_MODERATED, 'm',
1979 MODE_TOPICLIMIT, 't',
1980 MODE_INVITEONLY, 'i',
1981 MODE_NOPRIVMSGS, 'n',
1985 /* MODE_BAN, 'b', */
1991 int i, bufpos = 0, len;
1993 char *key = 0, limitbuf[20];
1994 char *apass = 0, *upass = 0;
2003 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2004 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2005 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2007 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2008 key = MB_STRING(mbuf, i);
2009 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2010 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2011 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2012 upass = MB_STRING(mbuf, i);
2013 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2014 apass = MB_STRING(mbuf, i);
2021 buf[bufpos++] = '+'; /* start building buffer */
2023 for (flag_p = flags; flag_p[0]; flag_p += 2)
2025 buf[bufpos++] = flag_p[1];
2027 for (i = 0, len = bufpos; i < len; i++) {
2029 build_string(buf, &bufpos, key, 0, ' ');
2030 else if (buf[i] == 'l')
2031 build_string(buf, &bufpos, limitbuf, 0, ' ');
2032 else if (buf[i] == 'u')
2033 build_string(buf, &bufpos, upass, 0, ' ');
2034 else if (buf[i] == 'A')
2035 build_string(buf, &bufpos, apass, 0, ' ');
2044 * Simple function to invalidate bans
2047 mode_ban_invalidate(struct Channel *chan)
2049 struct Membership *member;
2051 for (member = chan->members; member; member = member->next_member)
2052 ClearBanValid(member);
2056 * Simple function to drop invite structures
2059 mode_invite_clear(struct Channel *chan)
2061 while (chan->invites)
2062 del_invite(chan->invites->value.cptr, chan);
2065 /* What we've done for mode_parse so far... */
2066 #define DONE_LIMIT 0x01 /* We've set the limit */
2067 #define DONE_KEY 0x02 /* We've set the key */
2068 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2069 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2070 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2071 #define DONE_UPASS 0x20 /* We've set user pass */
2072 #define DONE_APASS 0x40 /* We've set admin pass */
2075 struct ModeBuf *mbuf;
2076 struct Client *cptr;
2077 struct Client *sptr;
2078 struct Channel *chptr;
2079 struct Membership *member;
2090 struct SLink banlist[MAXPARA];
2093 struct Client *client;
2094 } cli_change[MAXPARA];
2098 * Here's a helper function to deal with sending along "Not oper" or
2099 * "Not member" messages
2102 send_notoper(struct ParseState *state)
2104 if (state->done & DONE_NOTOPER)
2107 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2108 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2110 state->done |= DONE_NOTOPER;
2114 * Helper function to convert limits
2117 mode_parse_limit(struct ParseState *state, int *flag_p)
2119 unsigned int t_limit;
2121 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2122 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2125 if (state->parc <= 0) { /* warn if not enough args */
2126 if (MyUser(state->sptr))
2127 need_more_params(state->sptr, "MODE +l");
2131 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2135 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2136 (!t_limit || t_limit == state->chptr->mode.limit))
2139 t_limit = state->chptr->mode.limit;
2141 /* If they're not an oper, they can't change modes */
2142 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2143 send_notoper(state);
2147 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2149 state->done |= DONE_LIMIT;
2154 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2156 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2157 if (state->dir & MODE_ADD) {
2158 state->chptr->mode.mode |= flag_p[0];
2159 state->chptr->mode.limit = t_limit;
2161 state->chptr->mode.mode &= ~flag_p[0];
2162 state->chptr->mode.limit = 0;
2168 * Helper function to convert keys
2171 mode_parse_key(struct ParseState *state, int *flag_p)
2176 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2179 if (state->parc <= 0) { /* warn if not enough args */
2180 if (MyUser(state->sptr))
2181 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2186 t_str = state->parv[state->args_used++]; /* grab arg */
2190 /* If they're not an oper, they can't change modes */
2191 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2192 send_notoper(state);
2196 if (state->done & DONE_KEY) /* allow key to be set only once */
2198 state->done |= DONE_KEY;
2202 /* clean up the key string */
2204 while (*++s > ' ' && *s != ':' && --t_len)
2208 if (!*t_str) { /* warn if empty */
2209 if (MyUser(state->sptr))
2210 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2218 /* can't add a key if one is set, nor can one remove the wrong key */
2219 if (!(state->flags & MODE_PARSE_FORCE))
2220 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2221 (state->dir == MODE_DEL &&
2222 ircd_strcmp(state->chptr->mode.key, t_str))) {
2223 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2227 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2228 !ircd_strcmp(state->chptr->mode.key, t_str))
2229 return; /* no key change */
2231 if (state->flags & MODE_PARSE_BOUNCE) {
2232 if (*state->chptr->mode.key) /* reset old key */
2233 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2234 state->chptr->mode.key, 0);
2235 else /* remove new bogus key */
2236 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2237 } else /* send new key */
2238 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2240 if (state->flags & MODE_PARSE_SET) {
2241 if (state->dir == MODE_ADD) /* set the new key */
2242 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2243 else /* remove the old key */
2244 *state->chptr->mode.key = '\0';
2249 * Helper function to convert user passes
2252 mode_parse_upass(struct ParseState *state, int *flag_p)
2257 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2260 if (state->parc <= 0) { /* warn if not enough args */
2261 if (MyUser(state->sptr))
2262 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2267 t_str = state->parv[state->args_used++]; /* grab arg */
2271 /* If they're not an oper, they can't change modes */
2272 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2273 send_notoper(state);
2277 /* If they are not the channel manager, they are not allowed to change it */
2278 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2279 if (*state->chptr->mode.apass) {
2280 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2281 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2283 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2284 "Re-create the channel. The channel must be *empty* for",
2285 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2286 "before it can be recreated.");
2291 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2293 state->done |= DONE_UPASS;
2295 t_len = PASSLEN + 1;
2297 /* clean up the upass string */
2299 while (*++s > ' ' && *s != ':' && --t_len)
2303 if (!*t_str) { /* warn if empty */
2304 if (MyUser(state->sptr))
2305 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2313 if (!(state->flags & MODE_PARSE_FORCE))
2314 /* can't add the upass while apass is not set */
2315 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2316 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2319 /* can't add a upass if one is set, nor can one remove the wrong upass */
2320 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2321 (state->dir == MODE_DEL &&
2322 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2323 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2327 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2328 !ircd_strcmp(state->chptr->mode.upass, t_str))
2329 return; /* no upass change */
2331 if (state->flags & MODE_PARSE_BOUNCE) {
2332 if (*state->chptr->mode.upass) /* reset old upass */
2333 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2334 state->chptr->mode.upass, 0);
2335 else /* remove new bogus upass */
2336 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2337 } else /* send new upass */
2338 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2340 if (state->flags & MODE_PARSE_SET) {
2341 if (state->dir == MODE_ADD) /* set the new upass */
2342 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2343 else /* remove the old upass */
2344 *state->chptr->mode.upass = '\0';
2349 * Helper function to convert admin passes
2352 mode_parse_apass(struct ParseState *state, int *flag_p)
2357 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2360 if (state->parc <= 0) { /* warn if not enough args */
2361 if (MyUser(state->sptr))
2362 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2367 t_str = state->parv[state->args_used++]; /* grab arg */
2371 /* If they're not an oper, they can't change modes */
2372 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2373 send_notoper(state);
2377 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2378 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2379 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2383 /* If they are not the channel manager, they are not allowed to change it */
2384 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2385 if (*state->chptr->mode.apass) {
2386 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2387 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2389 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2390 "Re-create the channel. The channel must be *empty* for",
2391 "at least a whole minute", "before it can be recreated.");
2396 if (state->done & DONE_APASS) /* allow apass to be set only once */
2398 state->done |= DONE_APASS;
2400 t_len = PASSLEN + 1;
2402 /* clean up the apass string */
2404 while (*++s > ' ' && *s != ':' && --t_len)
2408 if (!*t_str) { /* warn if empty */
2409 if (MyUser(state->sptr))
2410 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2418 if (!(state->flags & MODE_PARSE_FORCE)) {
2419 /* can't remove the apass while upass is still set */
2420 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2421 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2424 /* can't add an apass if one is set, nor can one remove the wrong apass */
2425 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2426 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2427 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2432 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2433 !ircd_strcmp(state->chptr->mode.apass, t_str))
2434 return; /* no apass change */
2436 if (state->flags & MODE_PARSE_BOUNCE) {
2437 if (*state->chptr->mode.apass) /* reset old apass */
2438 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2439 state->chptr->mode.apass, 0);
2440 else /* remove new bogus apass */
2441 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2442 } else /* send new apass */
2443 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2445 if (state->flags & MODE_PARSE_SET) {
2446 if (state->dir == MODE_ADD) { /* set the new apass */
2447 /* Make it VERY clear to the user that this is a one-time password */
2448 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2449 if (MyUser(state->sptr)) {
2450 send_reply(state->sptr, RPL_APASSWARN,
2451 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2452 "Are you SURE you want to use this as Admin password? ",
2453 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2454 send_reply(state->sptr, RPL_APASSWARN,
2455 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2456 "\" to remove the password and then immediately set a new one. "
2457 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2458 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2459 "Now set the channel user password (+u).");
2461 } else { /* remove the old apass */
2462 *state->chptr->mode.apass = '\0';
2463 if (MyUser(state->sptr))
2464 send_reply(state->sptr, RPL_APASSWARN,
2465 "WARNING: You removed the channel Admin password MODE (+A). ",
2466 "If you would disconnect or leave the channel without setting a new password then you will ",
2467 "not be able to set it again and lose ownership of this channel! ",
2468 "SET A NEW PASSWORD NOW!", "");
2474 * Helper function to convert bans
2477 mode_parse_ban(struct ParseState *state, int *flag_p)
2480 struct SLink *ban, *newban = 0;
2482 if (state->parc <= 0) { /* Not enough args, send ban list */
2483 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2484 send_ban_list(state->sptr, state->chptr);
2485 state->done |= DONE_BANLIST;
2491 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2494 t_str = state->parv[state->args_used++]; /* grab arg */
2498 /* If they're not an oper, they can't change modes */
2499 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2500 send_notoper(state);
2504 if ((s = strchr(t_str, ' ')))
2507 if (!*t_str || *t_str == ':') { /* warn if empty */
2508 if (MyUser(state->sptr))
2509 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2514 t_str = collapse(pretty_mask(t_str));
2516 /* remember the ban for the moment... */
2517 if (state->dir == MODE_ADD) {
2518 newban = state->banlist + (state->numbans++);
2521 DupString(newban->value.ban.banstr, t_str);
2522 newban->value.ban.who = cli_name(state->sptr);
2523 newban->value.ban.when = TStime();
2525 newban->flags = CHFL_BAN | MODE_ADD;
2527 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2528 newban->flags |= CHFL_BAN_IPMASK;
2531 if (!state->chptr->banlist) {
2532 state->chptr->banlist = newban; /* add our ban with its flags */
2533 state->done |= DONE_BANCLEAN;
2537 /* Go through all bans */
2538 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2539 /* first, clean the ban flags up a bit */
2540 if (!(state->done & DONE_BANCLEAN))
2541 /* Note: We're overloading *lots* of bits here; be careful! */
2542 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2546 * MODE_ADD - Ban was added; if we're bouncing modes,
2547 * then we'll remove it below; otherwise,
2548 * we'll have to allocate a real ban
2550 * MODE_DEL - Ban was marked for deletion; if we're
2551 * bouncing modes, we'll have to re-add it,
2552 * otherwise, we'll have to remove it
2554 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2555 * with a ban already set; if we're
2556 * bouncing modes, we'll have to bounce
2557 * this one; otherwise, we'll just ignore
2558 * it when we process added bans
2561 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2562 ban->flags |= MODE_DEL; /* delete one ban */
2564 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2566 } else if (state->dir == MODE_ADD) {
2567 /* if the ban already exists, don't worry about it */
2568 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2569 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2570 MyFree(newban->value.ban.banstr); /* stopper a leak */
2571 state->numbans--; /* deallocate last ban */
2572 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2574 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2575 if (!(ban->flags & MODE_DEL))
2576 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2577 } else if (!mmatch(t_str, ban->value.ban.banstr))
2578 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2580 if (!ban->next && (newban->flags & MODE_ADD))
2582 ban->next = newban; /* add our ban with its flags */
2583 break; /* get out of loop */
2587 state->done |= DONE_BANCLEAN;
2591 * This is the bottom half of the ban processor
2594 mode_process_bans(struct ParseState *state)
2596 struct SLink *ban, *newban, *prevban, *nextban;
2602 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2604 banlen = strlen(ban->value.ban.banstr);
2606 nextban = ban->next;
2608 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2610 prevban->next = 0; /* Break the list; ban isn't a real ban */
2612 state->chptr->banlist = 0;
2617 MyFree(ban->value.ban.banstr);
2620 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2621 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2622 ban->value.ban.banstr,
2623 state->flags & MODE_PARSE_SET);
2625 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2626 if (prevban) /* clip it out of the list... */
2627 prevban->next = ban->next;
2629 state->chptr->banlist = ban->next;
2634 MyFree(ban->value.ban.who);
2638 continue; /* next ban; keep prevban like it is */
2640 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2641 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2643 prevban->next = 0; /* Break the list; ban isn't a real ban */
2645 state->chptr->banlist = 0;
2647 /* If we're supposed to ignore it, do so. */
2648 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2649 !(state->flags & MODE_PARSE_BOUNCE)) {
2653 MyFree(ban->value.ban.banstr);
2655 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2656 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2657 count > feature_int(FEAT_MAXBANS))) {
2658 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2659 ban->value.ban.banstr);
2663 MyFree(ban->value.ban.banstr);
2665 /* add the ban to the buffer */
2666 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2667 ban->value.ban.banstr,
2668 !(state->flags & MODE_PARSE_SET));
2670 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2671 newban = make_link();
2672 newban->value.ban.banstr = ban->value.ban.banstr;
2673 DupString(newban->value.ban.who, ban->value.ban.who);
2674 newban->value.ban.when = ban->value.ban.when;
2675 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2677 newban->next = state->chptr->banlist; /* and link it in */
2678 state->chptr->banlist = newban;
2687 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2689 if (changed) /* if we changed the ban list, we must invalidate the bans */
2690 mode_ban_invalidate(state->chptr);
2694 * Helper function to process client changes
2697 mode_parse_client(struct ParseState *state, int *flag_p)
2700 struct Client *acptr;
2703 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2706 if (state->parc <= 0) /* return if not enough args */
2709 t_str = state->parv[state->args_used++]; /* grab arg */
2713 /* If they're not an oper, they can't change modes */
2714 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2715 send_notoper(state);
2719 if (MyUser(state->sptr)) /* find client we're manipulating */
2720 acptr = find_chasing(state->sptr, t_str, NULL);
2722 acptr = findNUser(t_str);
2725 return; /* find_chasing() already reported an error to the user */
2727 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2728 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2729 state->cli_change[i].flag & flag_p[0]))
2730 break; /* found a slot */
2732 /* Store what we're doing to them */
2733 state->cli_change[i].flag = state->dir | flag_p[0];
2734 state->cli_change[i].client = acptr;
2738 * Helper function to process the changed client list
2741 mode_process_clients(struct ParseState *state)
2744 struct Membership *member;
2746 for (i = 0; state->cli_change[i].flag; i++) {
2747 assert(0 != state->cli_change[i].client);
2749 /* look up member link */
2750 if (!(member = find_member_link(state->chptr,
2751 state->cli_change[i].client)) ||
2752 (MyUser(state->sptr) && IsZombie(member))) {
2753 if (MyUser(state->sptr))
2754 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2755 cli_name(state->cli_change[i].client),
2756 state->chptr->chname);
2760 if ((state->cli_change[i].flag & MODE_ADD &&
2761 (state->cli_change[i].flag & member->status)) ||
2762 (state->cli_change[i].flag & MODE_DEL &&
2763 !(state->cli_change[i].flag & member->status)))
2764 continue; /* no change made, don't do anything */
2766 /* see if the deop is allowed */
2767 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2768 (MODE_DEL | MODE_CHANOP)) {
2769 /* prevent +k users from being deopped */
2770 if (IsChannelService(state->cli_change[i].client)) {
2771 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2772 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2774 (IsServer(state->sptr) ? cli_name(state->sptr) :
2775 cli_name((cli_user(state->sptr))->server)));
2777 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2778 send_reply(state->sptr, ERR_ISCHANSERVICE,
2779 cli_name(state->cli_change[i].client),
2780 state->chptr->chname);
2785 /* check deop for local user */
2786 if (MyUser(state->sptr)) {
2788 /* don't allow local opers to be deopped on local channels */
2789 if (MyUser(state->sptr) &&
2790 state->cli_change[i].client != state->sptr &&
2791 IsLocalChannel(state->chptr->chname) &&
2792 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2793 send_reply(state->sptr, ERR_ISOPERLCHAN,
2794 cli_name(state->cli_change[i].client),
2795 state->chptr->chname);
2799 /* don't allow to deop members with an op level that is <= our own level */
2800 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2802 && OpLevel(member) <= OpLevel(state->member)) {
2803 int equal = (OpLevel(member) == OpLevel(state->member));
2804 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2805 cli_name(state->cli_change[i].client),
2806 state->chptr->chname,
2807 OpLevel(state->member), OpLevel(member),
2808 "deop", equal ? "the same" : "a higher");
2814 /* set op-level of member being opped */
2815 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2816 (MODE_ADD | MODE_CHANOP)) {
2817 /* If on a channel with upass set, someone with level x gives ops to someone else,
2818 then that person gets level x-1. On other channels, where upass is not set,
2819 the level stays the same. */
2820 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2821 /* Someone being opped by a server gets op-level 0 */
2822 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2823 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2826 /* accumulate the change */
2827 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2828 state->cli_change[i].client);
2830 /* actually effect the change */
2831 if (state->flags & MODE_PARSE_SET) {
2832 if (state->cli_change[i].flag & MODE_ADD) {
2833 member->status |= (state->cli_change[i].flag &
2834 (MODE_CHANOP | MODE_VOICE));
2835 if (state->cli_change[i].flag & MODE_CHANOP)
2836 ClearDeopped(member);
2838 member->status &= ~(state->cli_change[i].flag &
2839 (MODE_CHANOP | MODE_VOICE));
2841 } /* for (i = 0; state->cli_change[i].flags; i++) */
2845 * Helper function to process the simple modes
2848 mode_parse_mode(struct ParseState *state, int *flag_p)
2850 /* If they're not an oper, they can't change modes */
2851 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2852 send_notoper(state);
2859 if (state->dir == MODE_ADD) {
2860 state->add |= flag_p[0];
2861 state->del &= ~flag_p[0];
2863 if (flag_p[0] & MODE_SECRET) {
2864 state->add &= ~MODE_PRIVATE;
2865 state->del |= MODE_PRIVATE;
2866 } else if (flag_p[0] & MODE_PRIVATE) {
2867 state->add &= ~MODE_SECRET;
2868 state->del |= MODE_SECRET;
2871 state->add &= ~flag_p[0];
2872 state->del |= flag_p[0];
2875 assert(0 == (state->add & state->del));
2876 assert((MODE_SECRET | MODE_PRIVATE) !=
2877 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2881 * This routine is intended to parse MODE or OPMODE commands and effect the
2882 * changes (or just build the bounce buffer). We pass the starting offset
2886 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2887 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2888 struct Membership* member)
2890 static int chan_flags[] = {
2895 MODE_MODERATED, 'm',
2896 MODE_TOPICLIMIT, 't',
2897 MODE_INVITEONLY, 'i',
2898 MODE_NOPRIVMSGS, 'n',
2911 unsigned int t_mode;
2913 struct ParseState state;
2924 state.chptr = chptr;
2925 state.member = member;
2928 state.flags = flags;
2929 state.dir = MODE_ADD;
2933 state.args_used = 0;
2934 state.max_args = MAXMODEPARAMS;
2937 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2938 state.banlist[i].next = 0;
2939 state.banlist[i].value.ban.banstr = 0;
2940 state.banlist[i].value.ban.who = 0;
2941 state.banlist[i].value.ban.when = 0;
2942 state.banlist[i].flags = 0;
2943 state.cli_change[i].flag = 0;
2944 state.cli_change[i].client = 0;
2947 modestr = state.parv[state.args_used++];
2951 for (; *modestr; modestr++) {
2952 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2953 if (flag_p[1] == *modestr)
2956 if (!flag_p[0]) { /* didn't find it? complain and continue */
2957 if (MyUser(state.sptr))
2958 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2963 case '+': /* switch direction to MODE_ADD */
2964 case '-': /* switch direction to MODE_DEL */
2965 state.dir = flag_p[0];
2968 case 'l': /* deal with limits */
2969 mode_parse_limit(&state, flag_p);
2972 case 'k': /* deal with keys */
2973 mode_parse_key(&state, flag_p);
2976 case 'A': /* deal with Admin passes */
2977 mode_parse_apass(&state, flag_p);
2980 case 'u': /* deal with user passes */
2981 mode_parse_upass(&state, flag_p);
2984 case 'b': /* deal with bans */
2985 mode_parse_ban(&state, flag_p);
2988 case 'o': /* deal with ops/voice */
2990 mode_parse_client(&state, flag_p);
2993 default: /* deal with other modes */
2994 mode_parse_mode(&state, flag_p);
2996 } /* switch (*modestr) */
2997 } /* for (; *modestr; modestr++) */
2999 if (state.flags & MODE_PARSE_BURST)
3000 break; /* don't interpret any more arguments */
3002 if (state.parc > 0) { /* process next argument in string */
3003 modestr = state.parv[state.args_used++];
3007 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3010 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3011 break; /* we're then going to bounce the mode! */
3013 recv_ts = atoi(modestr);
3015 if (recv_ts && recv_ts < state.chptr->creationtime)
3016 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3018 break; /* break out of while loop */
3019 } else if (state.flags & MODE_PARSE_STRICT ||
3020 (MyUser(state.sptr) && state.max_args <= 0)) {
3021 state.parc++; /* we didn't actually gobble the argument */
3023 break; /* break out of while loop */
3026 } /* while (*modestr) */
3029 * the rest of the function finishes building resultant MODEs; if the
3030 * origin isn't a member or an oper, skip it.
3032 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3033 return state.args_used; /* tell our parent how many args we gobbled */
3035 t_mode = state.chptr->mode.mode;
3037 if (state.del & t_mode) { /* delete any modes to be deleted... */
3038 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3040 t_mode &= ~state.del;
3042 if (state.add & ~t_mode) { /* add any modes to be added... */
3043 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3045 t_mode |= state.add;
3048 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3049 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3050 !(t_mode & MODE_INVITEONLY))
3051 mode_invite_clear(state.chptr);
3053 state.chptr->mode.mode = t_mode;
3056 if (state.flags & MODE_PARSE_WIPEOUT) {
3057 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3058 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3059 state.chptr->mode.limit);
3060 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3061 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3062 state.chptr->mode.key, 0);
3063 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3064 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3065 state.chptr->mode.upass, 0);
3066 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3067 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3068 state.chptr->mode.apass, 0);
3071 if (state.done & DONE_BANCLEAN) /* process bans */
3072 mode_process_bans(&state);
3074 /* process client changes */
3075 if (state.cli_change[0].flag)
3076 mode_process_clients(&state);
3078 return state.args_used; /* tell our parent how many args we gobbled */
3082 * Initialize a join buffer
3085 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3086 struct Client *connect, unsigned int type, char *comment,
3092 assert(0 != source);
3093 assert(0 != connect);
3095 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3096 jbuf->jb_connect = connect;
3097 jbuf->jb_type = type;
3098 jbuf->jb_comment = comment;
3099 jbuf->jb_create = create;
3101 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3102 type == JOINBUF_TYPE_PART ||
3103 type == JOINBUF_TYPE_PARTALL) ?
3104 STARTJOINLEN : STARTCREATELEN) +
3105 (comment ? strlen(comment) + 2 : 0));
3107 for (i = 0; i < MAXJOINARGS; i++)
3108 jbuf->jb_channels[i] = 0;
3112 * Add a channel to the join buffer
3115 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3123 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3124 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3129 is_local = IsLocalChannel(chan->chname);
3131 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3132 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3133 /* Send notification to channel */
3134 if (!(flags & CHFL_ZOMBIE))
3135 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3136 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3137 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3138 else if (MyUser(jbuf->jb_source))
3139 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3140 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3141 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3142 /* XXX: Shouldn't we send a PART here anyway? */
3143 /* to users on the channel? Why? From their POV, the user isn't on
3144 * the channel anymore anyway. We don't send to servers until below,
3145 * when we gang all the channel parts together. Note that this is
3146 * exactly the same logic, albeit somewhat more concise, as was in
3147 * the original m_part.c */
3149 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3150 is_local) /* got to remove user here */
3151 remove_user_from_channel(jbuf->jb_source, chan);
3153 /* Add user to channel */
3154 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3156 /* send notification to all servers */
3157 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3158 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3159 "%H %Tu", chan, chan->creationtime);
3161 /* Send the notification to the channel */
3162 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3164 /* send an op, too, if needed */
3165 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3166 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3167 chan, jbuf->jb_source);
3170 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3171 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3172 return; /* don't send to remote */
3174 /* figure out if channel name will cause buffer to be overflowed */
3175 len = chan ? strlen(chan->chname) + 1 : 2;
3176 if (jbuf->jb_strlen + len > BUFSIZE)
3177 joinbuf_flush(jbuf);
3179 /* add channel to list of channels to send and update counts */
3180 jbuf->jb_channels[jbuf->jb_count++] = chan;
3181 jbuf->jb_strlen += len;
3183 /* if we've used up all slots, flush */
3184 if (jbuf->jb_count >= MAXJOINARGS)
3185 joinbuf_flush(jbuf);
3189 * Flush the channel list to remote servers
3192 joinbuf_flush(struct JoinBuf *jbuf)
3194 char chanlist[BUFSIZE];
3198 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3199 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3200 return 0; /* no joins to process */
3202 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3203 build_string(chanlist, &chanlist_i,
3204 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3205 i == 0 ? '\0' : ',');
3206 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3207 /* Remove user from channel */
3208 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3210 jbuf->jb_channels[i] = 0; /* mark slot empty */
3213 jbuf->jb_count = 0; /* reset base counters */
3214 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3215 STARTJOINLEN : STARTCREATELEN) +
3216 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3218 /* and send the appropriate command */
3219 switch (jbuf->jb_type) {
3220 case JOINBUF_TYPE_CREATE:
3221 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3222 "%s %Tu", chanlist, jbuf->jb_create);
3225 case JOINBUF_TYPE_PART:
3226 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3227 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3235 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3236 int IsInvited(struct Client* cptr, const void* chptr)
3240 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3241 if (lp->value.chptr == chptr)