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.
21 * @brief Channel management and maintanance
28 #include "destruct_event.h"
31 #include "ircd_alloc.h"
32 #include "ircd_chattr.h"
33 #include "ircd_defs.h"
34 #include "ircd_features.h"
36 #include "ircd_reply.h"
37 #include "ircd_snprintf.h"
38 #include "ircd_string.h"
45 #include "querycmds.h"
61 /** Linked list containing the full list of all channels */
62 struct Channel* GlobalChannelList = 0;
64 /** Number of struct Membership*'s allocated */
65 static unsigned int membershipAllocCount;
66 /** Freelist for struct Membership*'s */
67 static struct Membership* membershipFreeList;
69 void del_invite(struct Client *, struct Channel *);
71 const char* const PartFmt1 = ":%s " MSG_PART " %s";
72 const char* const PartFmt2 = ":%s " MSG_PART " %s :%s";
73 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
74 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
77 static struct Ban* next_ban;
78 static struct Ban* prev_ban;
79 static struct Ban* removed_bans_list;
80 static struct Ban* free_bans;
83 * Use a global variable to remember if an oper set a mode on a local channel.
84 * Ugly, but the only way to do it without changing set_mode intensively.
86 int LocalChanOperMode = 0;
89 /** return the length (>=0) of a chain of links.
90 * @param lp pointer to the start of the linked list
91 * @return the number of items in the list
93 static int list_length(struct SLink *lp)
97 for (; lp; lp = lp->next)
103 /** Set the mask for a ban, checking for IP masks.
104 * @param[in,out] ban Ban structure to modify.
105 * @param[in] banstr Mask to ban.
108 set_ban_mask(struct Ban *ban, const char *banstr)
114 DupString(ban->banstr, banstr);
115 sep = strrchr(banstr, '@');
117 ban->nu_len = sep - banstr;
118 if (ipmask_parse(sep + 1, &ban->address, &ban->addrbits))
119 ban->flags |= BAN_IPMASK;
123 /** Allocate a new Ban structure.
124 * @param[in] banstr Ban mask to use.
125 * @return Newly allocated ban.
128 make_ban(const char *banstr)
133 free_bans = free_bans->next;
135 else if (!(ban = MyMalloc(sizeof(*ban))))
137 memset(ban, 0, sizeof(*ban));
138 set_ban_mask(ban, banstr);
142 /** Deallocate a ban structure.
143 * @param[in] ban Ban to deallocate.
146 free_ban(struct Ban *ban)
150 ban->next = free_bans;
154 /** return the struct Membership* that represents a client on a channel
155 * This function finds a struct Membership* which holds the state about
156 * a client on a specific channel. The code is smart enough to iterate
157 * over the channels a user is in, or the users in a channel to find the
158 * user depending on which is likely to be more efficient.
160 * @param chptr pointer to the channel struct
161 * @param cptr pointer to the client struct
163 * @returns pointer to the struct Membership representing this client on
164 * this channel. Returns NULL if the client is not on the channel.
165 * Returns NULL if the client is actually a server.
166 * @see find_channel_member()
168 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
170 struct Membership *m;
174 /* Servers don't have member links */
175 if (IsServer(cptr)||IsMe(cptr))
178 /* +k users are typically on a LOT of channels. So we iterate over who
179 * is in the channel. X/W are +k and are in about 5800 channels each.
180 * however there are typically no more than 1000 people in a channel
183 if (IsChannelService(cptr)) {
186 assert(m->channel == chptr);
192 /* Users on the other hand aren't allowed on more than 15 channels. 50%
193 * of users that are on channels are on 2 or less, 95% are on 7 or less,
194 * and 99% are on 10 or less.
197 m = (cli_user(cptr))->channel;
199 assert(m->user == cptr);
200 if (m->channel == chptr)
208 /** Find the client structure for a nick name (user)
209 * Find the client structure for a nick name (user)
210 * using history mechanism if necessary. If the client is not found, an error
211 * message (NO SUCH NICK) is generated. If the client was found
212 * through the history, chasing will be 1 and otherwise 0.
214 * This function was used extensively in the P09 days, and since we now have
215 * numeric nicks is no longer quite as important.
217 * @param sptr Pointer to the client that has requested the search
218 * @param user a string represeting the client to be found
219 * @param chasing a variable set to 0 if the user was found directly,
221 * @returns a pointer the client, or NULL if the client wasn't found.
223 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
225 struct Client* who = FindClient(user);
232 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
233 send_reply(sptr, ERR_NOSUCHNICK, user);
241 /** build up a hostmask
242 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
243 * as the parameters. If NULL, they become "*".
244 * @param namebuf the buffer to build the hostmask into. Must be at least
245 * NICKLEN+USERLEN+HOSTLEN+3 charactors long.
246 * @param nick The nickname
247 * @param name The ident
248 * @param host the hostname
251 static char *make_nick_user_host(char *namebuf, const char *nick,
252 const char *name, const char *host)
254 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
255 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
259 /** Decrement the count of users, and free if empty.
260 * Subtract one user from channel i (and free channel * block, if channel
263 * @param chptr The channel to subtract one from.
265 * @returns true (1) if channel still has members.
266 * false (0) if the channel is now empty.
268 int sub1_from_channel(struct Channel* chptr)
270 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
272 assert(0 != chptr->members);
280 * Also channels without Apass set need to be kept alive,
281 * otherwise Bad Guys(tm) would be able to takeover
282 * existing channels too easily, and then set an Apass!
283 * However, if a channel without Apass becomes empty
284 * then we try to be kind to them and remove possible
287 chptr->mode.mode &= ~MODE_INVITEONLY;
288 chptr->mode.limit = 0;
290 * We do NOT reset a possible key or bans because when
291 * the 'channel owners' can't get in because of a key
292 * or ban then apparently there was a fight/takeover
293 * on the channel and we want them to contact IRC opers
294 * who then will educate them on the use of Apass/upass.
297 if (feature_bool(FEAT_OPLEVELS)) {
298 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
299 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
301 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
303 destruct_channel(chptr);
308 /** Destroy an empty channel
309 * This function destroys an empty channel, removing it from hashtables,
310 * and removing any resources it may have consumed.
312 * @param chptr The channel to destroy
314 * @returns 0 (success)
316 * FIXME: Change to return void, this function never fails.
318 int destruct_channel(struct Channel* chptr)
320 struct Ban *ban, *next;
322 assert(0 == chptr->members);
325 * Now, find all invite links from channel structure
327 while (chptr->invites)
328 del_invite(chptr->invites->value.cptr, chptr);
330 for (ban = chptr->banlist; ban; ban = next)
336 chptr->prev->next = chptr->next;
338 GlobalChannelList = chptr->next;
340 chptr->next->prev = chptr->prev;
342 --UserStats.channels;
344 * make sure that channel actually got removed from hash table
346 assert(chptr->hnext == chptr);
351 /** add a ban to a channel
353 * `cptr' must be the client adding the ban.
355 * If `change' is true then add `banid' to channel `chptr'.
356 * Returns 0 if the ban was added.
357 * Returns -2 if the ban already existed and was marked BAN_BURST_WIPEOUT.
358 * Return -1 otherwise.
360 * Those bans that overlapped with `banid' are flagged with BAN_OVERLAPPED
361 * when `change' is false, otherwise they will be removed from the banlist.
362 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
363 * respectively will return these bans until NULL is returned.
365 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
366 * is reset (unless a non-zero value is returned, in which case the
367 * BAN_OVERLAPPED flag might not have been reset!).
370 * @param cptr Client adding the ban
371 * @param chptr Channel to add the ban to
372 * @param banid The actual ban.
373 * @param change True if adding a ban, false if old bans should just be flagged
374 * @param firsttime Reset the next_overlapped_ban() iteration.
376 * 0 if the ban was added
377 * -2 if the ban already existed and was marked BAN_BURST_WIPEOUT
380 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
381 int change, int firsttime)
386 int removed_bans = 0;
387 int len = strlen(banid);
392 assert(0 == prev_ban);
393 assert(0 == removed_bans_list);
397 for (banp = &chptr->banlist; *banp;)
399 len += strlen((*banp)->banstr);
401 if (((*banp)->flags & BAN_BURST_WIPEOUT))
403 if (!strcmp((*banp)->banstr, banid))
405 (*banp)->flags &= ~BAN_BURST_WIPEOUT;
409 else if (!mmatch((*banp)->banstr, banid))
411 if (!mmatch(banid, (*banp)->banstr))
413 struct Ban *tmp = *banp;
419 len -= strlen(tmp->banstr);
422 /* These will be sent to the user later as -b */
423 tmp->next = removed_bans_list;
424 removed_bans_list = tmp;
427 else if (!(tmp->flags & BAN_BURST_WIPEOUT))
429 tmp->flags |= BAN_OVERLAPPED;
440 (*banp)->flags &= ~BAN_OVERLAPPED;
441 banp = &(*banp)->next;
444 if (MyUser(cptr) && !removed_bans &&
445 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
446 (cnt >= feature_int(FEAT_MAXBANS))))
448 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
454 struct Membership* member;
455 ban = make_ban(banid);
456 ban->next = chptr->banlist;
458 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
459 DupString(ban->who, cli_name(&me));
461 DupString(ban->who, cli_name(cptr));
462 assert(0 != ban->who);
464 ban->when = TStime();
465 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
466 ban->flags |= BAN_IPMASK;
467 chptr->banlist = ban;
470 * Erase ban-valid-bit
472 for (member = chptr->members; member; member = member->next_member)
473 ClearBanValid(member); /* `ban' == channel member ! */
478 /** return the next ban that is removed
479 * @returns the next ban that is removed because of overlapping
481 struct Ban *next_removed_overlapped_ban(void)
488 if ((prev_ban = removed_bans_list))
489 removed_bans_list = removed_bans_list->next;
493 /** returns Membership * if a person is joined and not a zombie
495 * @param chptr Channel
496 * @returns pointer to the client's struct Membership * on the channel if that
497 * user is a full member of the channel, or NULL otherwise.
499 * @see find_member_link()
501 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
503 struct Membership* member;
506 member = find_member_link(chptr, cptr);
507 return (member && !IsZombie(member)) ? member : 0;
510 /** return true if banned else false.
512 * This function returns true if the user is banned on the said channel.
513 * This function will check the ban cache if applicable, otherwise will
514 * do the comparisons and cache the result.
516 * @param cptr The client to test
517 * @param chptr The channel
518 * @param member The Membership * of this client on this channel
519 * (may be NULL if the member is not on the channel).
521 static int is_banned(struct Client *cptr, struct Channel *chptr,
522 struct Membership* member)
525 char nu[NICKLEN + USERLEN + 2];
526 char tmphost[HOSTLEN + 1];
532 if (member && IsBanValid(member))
533 return IsBanned(member);
535 ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
536 cli_name(cptr), cli_user(cptr)->username);
539 if (HasHiddenHost(cptr))
541 sr = cli_user(cptr)->realhost;
545 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
546 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
551 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
553 tmp->banstr[tmp->nu_len] = '\0';
554 res = match(tmp->banstr, nu);
555 tmp->banstr[tmp->nu_len] = '@';
558 if (((tmp->flags & BAN_IPMASK)
559 && ipmask_check(&cli_ip(cptr), &tmp->address, tmp->addrbits))
560 || match(tmp->banstr + tmp->nu_len + 1, cli_user(cptr)->host) == 0
561 || (sr && match(tmp->banstr + tmp->nu_len + 1, sr) == 0))
577 return (tmp != NULL);
580 /** add a user to a channel.
581 * adds a user to a channel by adding another link to the channels member
584 * @param chptr The channel to add to.
585 * @param who The user to add.
586 * @param flags The flags the user gets initially.
587 * @param oplevel The oplevel the user starts with.
589 void add_user_to_channel(struct Channel* chptr, struct Client* who,
590 unsigned int flags, int oplevel)
597 struct Membership* member = membershipFreeList;
599 membershipFreeList = member->next_member;
601 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
602 ++membershipAllocCount;
607 member->channel = chptr;
608 member->status = flags;
609 member->oplevel = oplevel;
611 member->next_member = chptr->members;
612 if (member->next_member)
613 member->next_member->prev_member = member;
614 member->prev_member = 0;
615 chptr->members = member;
617 member->next_channel = (cli_user(who))->channel;
618 if (member->next_channel)
619 member->next_channel->prev_channel = member;
620 member->prev_channel = 0;
621 (cli_user(who))->channel = member;
623 if (chptr->destruct_event)
624 remove_destruct_event(chptr);
626 ++((cli_user(who))->joined);
630 /** Remove a person from a channel, given their Membership*
632 * @param member A member of a channel.
634 * @returns true if there are more people in the channel.
636 static int remove_member_from_channel(struct Membership* member)
638 struct Channel* chptr;
640 chptr = member->channel;
642 * unlink channel member list
644 if (member->next_member)
645 member->next_member->prev_member = member->prev_member;
646 if (member->prev_member)
647 member->prev_member->next_member = member->next_member;
649 member->channel->members = member->next_member;
652 * If this is the last delayed-join user, may have to clear WASDELJOINS.
654 if (IsDelayedJoin(member))
655 CheckDelayedJoins(chptr);
658 * unlink client channel list
660 if (member->next_channel)
661 member->next_channel->prev_channel = member->prev_channel;
662 if (member->prev_channel)
663 member->prev_channel->next_channel = member->next_channel;
665 (cli_user(member->user))->channel = member->next_channel;
667 --(cli_user(member->user))->joined;
669 member->next_member = membershipFreeList;
670 membershipFreeList = member;
672 return sub1_from_channel(chptr);
675 /** Check if all the remaining members on the channel are zombies
677 * @returns False if the channel has any non zombie members, True otherwise.
680 static int channel_all_zombies(struct Channel* chptr)
682 struct Membership* member;
684 for (member = chptr->members; member; member = member->next_member) {
685 if (!IsZombie(member))
692 /** Remove a user from a channel
693 * This is the generic entry point for removing a user from a channel, this
694 * function will remove the client from the channel, and destory the channel
695 * if there are no more normal users left.
697 * @param cptr The client
698 * @param chptr The channel
700 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
703 struct Membership* member;
706 if ((member = find_member_link(chptr, cptr))) {
707 if (remove_member_from_channel(member)) {
708 if (channel_all_zombies(chptr)) {
710 * XXX - this looks dangerous but isn't if we got the referential
711 * integrity right for channels
713 while (remove_member_from_channel(chptr->members))
720 /** Remove a user from all channels they are on.
722 * This function removes a user from all channels they are on.
724 * @param cptr The client to remove.
726 void remove_user_from_all_channels(struct Client* cptr)
728 struct Membership* chan;
730 assert(0 != cli_user(cptr));
732 while ((chan = (cli_user(cptr))->channel))
733 remove_user_from_channel(cptr, chan->channel);
736 /** Check if this user is a legitimate chanop
738 * @param cptr Client to check
739 * @param chptr Channel to check
741 * @returns True if the user is a chanop (And not a zombie), False otherwise.
744 int is_chan_op(struct Client *cptr, struct Channel *chptr)
746 struct Membership* member;
748 if ((member = find_member_link(chptr, cptr)))
749 return (!IsZombie(member) && IsChanOp(member));
754 /** Check if a user is a Zombie on a specific channel.
756 * @param cptr The client to check.
757 * @param chptr The channel to check.
759 * @returns True if the client (cptr) is a zombie on the channel (chptr),
764 int is_zombie(struct Client *cptr, struct Channel *chptr)
766 struct Membership* member;
770 if ((member = find_member_link(chptr, cptr)))
771 return IsZombie(member);
775 /** Returns if a user has voice on a channel.
777 * @param cptr The client
778 * @param chptr The channel
780 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
783 int has_voice(struct Client* cptr, struct Channel* chptr)
785 struct Membership* member;
788 if ((member = find_member_link(chptr, cptr)))
789 return (!IsZombie(member) && HasVoice(member));
794 /** Can this member send to a channel
796 * A user can speak on a channel iff:
798 * <li> They didn't use the Apass to gain ops.
799 * <li> They are op'd or voice'd.
800 * <li> You aren't banned.
801 * <li> The channel isn't +m
802 * <li> The channel isn't +n or you are on the channel.
805 * This function will optionally reveal a user on a delayed join channel if
806 * they are allowed to send to the channel.
808 * @param member The membership of the user
809 * @param reveal If true, the user will be "revealed" on a delayed
812 * @returns True if the client can speak on the channel.
814 int member_can_send_to_channel(struct Membership* member, int reveal)
818 /* Discourage using the Apass to get op. They should use the upass. */
819 if (IsChannelManager(member) && *member->channel->mode.upass)
822 if (IsVoicedOrOpped(member))
825 * If it's moderated, and you aren't a priviledged user, you can't
828 if (member->channel->mode.mode & MODE_MODERATED)
831 * If you're banned then you can't speak either.
832 * but because of the amount of CPU time that is_banned chews
833 * we only check it for our clients.
835 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
838 if (IsDelayedJoin(member) && reveal)
839 RevealDelayedJoin(member);
844 /** Check if a client can send to a channel.
846 * Has the added check over member_can_send_to_channel() of servers can
849 * @param cptr The client to check
850 * @param chptr The channel to check
851 * @param reveal If the user should be revealed (see
852 * member_can_send_to_channel())
854 * @returns true if the client is allowed to speak on the channel, false
857 * @see member_can_send_to_channel()
859 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
861 struct Membership *member;
864 * Servers can always speak on channels.
869 member = find_channel_member(cptr, chptr);
872 * You can't speak if you're off channel, and it is +n (no external messages)
876 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
877 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
880 return !is_banned(cptr, chptr, NULL);
882 return member_can_send_to_channel(member, reveal);
885 /** Returns the name of a channel that prevents the user from changing nick.
886 * if a member and not (opped or voiced) and (banned or moderated), return
887 * the name of the first channel banned on.
889 * @param cptr The client
891 * @returns the name of the first channel banned on, or NULL if the user
894 const char* find_no_nickchange_channel(struct Client* cptr)
897 struct Membership* member;
898 for (member = (cli_user(cptr))->channel; member;
899 member = member->next_channel) {
900 if (!IsVoicedOrOpped(member) &&
901 (is_banned(cptr, member->channel, member) ||
902 (member->channel->mode.mode & MODE_MODERATED)))
903 return member->channel->chname;
910 /** Fill mbuf/pbuf with modes from chptr
911 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
912 * with the parameters in pbuf as visible by cptr.
914 * This function will hide keys from non-op'd, non-server clients.
916 * @param cptr The client to generate the mode for.
917 * @param mbuf The buffer to write the modes into.
918 * @param pbuf The buffer to write the mode parameters into.
919 * @param buflen The length of the buffers.
920 * @param chptr The channel to get the modes from.
921 * @param member The membership of this client on this channel (or NULL
922 * if this client isn't on this channel)
925 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
926 struct Channel *chptr, struct Membership *member)
928 int previous_parameter = 0;
935 if (chptr->mode.mode & MODE_SECRET)
937 else if (chptr->mode.mode & MODE_PRIVATE)
939 if (chptr->mode.mode & MODE_MODERATED)
941 if (chptr->mode.mode & MODE_TOPICLIMIT)
943 if (chptr->mode.mode & MODE_INVITEONLY)
945 if (chptr->mode.mode & MODE_NOPRIVMSGS)
947 if (chptr->mode.mode & MODE_REGONLY)
949 if (chptr->mode.mode & MODE_DELJOINS)
951 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
953 if (chptr->mode.limit) {
955 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
956 previous_parameter = 1;
959 if (*chptr->mode.key) {
961 if (previous_parameter)
963 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
964 strcat(pbuf, chptr->mode.key);
967 previous_parameter = 1;
969 if (*chptr->mode.apass) {
971 if (previous_parameter)
973 if (IsServer(cptr)) {
974 strcat(pbuf, chptr->mode.apass);
977 previous_parameter = 1;
979 if (*chptr->mode.upass) {
981 if (previous_parameter)
983 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
984 strcat(pbuf, chptr->mode.upass);
991 /** Compare two members oplevel
993 * @param mp1 Pointer to a pointer to a membership
994 * @param mp2 Pointer to a pointer to a membership
996 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
1000 int compare_member_oplevel(const void *mp1, const void *mp2)
1002 struct Membership const* member1 = *(struct Membership const**)mp1;
1003 struct Membership const* member2 = *(struct Membership const**)mp2;
1004 if (member1->oplevel == member2->oplevel)
1006 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1009 /* send "cptr" a full list of the modes for channel chptr.
1011 * Sends a BURST line to cptr, bursting all the modes for the channel.
1013 * @param cptr Client pointer
1014 * @param chptr Channel pointer
1016 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1018 /* The order in which modes are generated is now mandatory */
1019 static unsigned int current_flags[4] =
1020 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1026 struct Membership* member;
1028 char modebuf[MODEBUFLEN];
1029 char parabuf[MODEBUFLEN];
1031 int number_of_ops = 0;
1032 int opped_members_index = 0;
1033 struct Membership** opped_members = NULL;
1034 int last_oplevel = 0;
1035 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1040 if (IsLocalChannel(chptr->chname))
1043 member = chptr->members;
1044 lp2 = chptr->banlist;
1046 *modebuf = *parabuf = '\0';
1047 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1049 for (first = 1; full; first = 0) /* Loop for multiple messages */
1051 full = 0; /* Assume by default we get it
1052 all in one message */
1054 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1055 /* is there any better way we can do this? */
1056 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1057 chptr->creationtime);
1059 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1062 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1063 msgq_append(&me, mb, " %s", modebuf);
1066 msgq_append(&me, mb, " %s", parabuf);
1070 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1072 * First find all opless members.
1073 * Run 2 times over all members, to group the members with
1074 * and without voice together.
1075 * Then run 2 times over all opped members (which are ordered
1076 * by op-level) to also group voice and non-voice together.
1078 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1082 if (flag_cnt < 2 && IsChanOp(member))
1085 * The first loop (to find all non-voice/op), we count the ops.
1086 * The second loop (to find all voiced non-ops), store the ops
1087 * in a dynamic array.
1092 opped_members[opped_members_index++] = member;
1094 /* Only handle the members with the flags that we are interested in. */
1095 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1097 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1098 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1100 full = 1; /* Make sure we continue after
1101 sending it so far */
1102 /* Ensure the new BURST line contains the current
1103 * ":mode", except when there is no mode yet. */
1104 new_mode = (flag_cnt > 0) ? 1 : 0;
1105 break; /* Do not add this member to this message */
1107 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1108 first = 0; /* From now on, use commas to add new nicks */
1111 * Do we have a nick with a new mode ?
1112 * Or are we starting a new BURST line?
1114 if (new_mode || !feat_oplevels)
1117 * This means we are at the _first_ member that has only
1118 * voice, or the first member that has only ops, or the
1119 * first member that has voice and ops (so we get here
1120 * at most three times, plus once for every start of
1121 * a continued BURST line where only these modes is current.
1122 * In the two cases where the current mode includes ops,
1123 * we need to add the _absolute_ value of the oplevel to the mode.
1125 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1128 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1130 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1132 /* append the absolute value of the oplevel */
1134 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1139 msgq_append(&me, mb, tbuf);
1142 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1145 * This can't be the first member of a (continued) BURST
1146 * message because then either flag_cnt == 0 or new_mode == 1
1147 * Now we need to append the incremental value of the oplevel.
1149 char tbuf[2 + MAXOPLEVELDIGITS];
1150 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1151 last_oplevel = member->oplevel;
1152 msgq_append(&me, mb, tbuf);
1155 /* Go to the next `member'. */
1157 member = member->next_member;
1159 member = opped_members[++opped_members_index];
1164 /* Point `member' at the start of the list again. */
1167 member = chptr->members;
1168 /* Now, after one loop, we know the number of ops and can
1169 * allocate the dynamic array with pointer to the ops. */
1170 opped_members = (struct Membership**)
1171 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1172 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1176 /* At the end of the second loop, sort the opped members with
1177 * increasing op-level, so that we will output them in the
1178 * correct order (and all op-level increments stay positive) */
1180 qsort(opped_members, number_of_ops,
1181 sizeof(struct Membership*), compare_member_oplevel);
1182 /* The third and fourth loop run only over the opped members. */
1183 member = opped_members[(opped_members_index = 0)];
1186 } /* loop over 0,+v,+o,+ov */
1190 /* Attach all bans, space seperated " :%ban ban ..." */
1191 for (first = 2; lp2; lp2 = lp2->next)
1193 len = strlen(lp2->banstr);
1194 if (msgq_bufleft(mb) < len + 1 + first)
1195 /* The +1 stands for the added ' '.
1196 * The +first stands for the added ":%".
1202 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1208 send_buffer(cptr, mb, 0); /* Send this message */
1210 } /* Continue when there was something
1211 that didn't fit (full==1) */
1213 MyFree(opped_members);
1214 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1215 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1216 chptr->creationtime, chptr->topic_time, chptr->topic);
1219 /** Canonify a mask.
1222 * @author Carlo Wood (Run),
1225 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1226 * When the user name or host name are too long (USERLEN and HOSTLEN
1227 * respectively) then they are cut off at the start with a '*'.
1229 * The following transformations are made:
1231 * 1) xxx -> nick!*@*
1232 * 2) xxx.xxx -> *!*\@host
1233 * 3) xxx\!yyy -> nick!user\@*
1234 * 4) xxx\@yyy -> *!user\@host
1235 * 5) xxx!yyy\@zzz -> nick!user\@host
1237 * @param mask The uncanonified mask.
1238 * @returns The updated mask in a static buffer.
1240 char *pretty_mask(char *mask)
1242 static char star[2] = { '*', 0 };
1243 static char retmask[NUH_BUFSIZE];
1244 char *last_dot = NULL;
1247 /* Case 1: default */
1252 /* Do a _single_ pass through the characters of the mask: */
1253 for (ptr = mask; *ptr; ++ptr)
1257 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1261 else if (*ptr == '@')
1263 /* Case 4: Found last '@' (without finding a '!' yet) */
1268 else if (*ptr == '.')
1270 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1280 /* Case 4 or 5: Found last '@' */
1286 if (user == star && last_dot)
1296 char *nick_end = (user != star) ? user - 1 : ptr;
1297 if (nick_end - nick > NICKLEN)
1303 char *user_end = (host != star) ? host - 1 : ptr;
1304 if (user_end - user > USERLEN)
1306 user = user_end - USERLEN;
1311 if (host != star && ptr - host > HOSTLEN)
1313 host = ptr - HOSTLEN;
1316 return make_nick_user_host(retmask, nick, user, host);
1319 /** send a banlist to a client for a channel
1321 * @param cptr Client to send the banlist to.
1322 * @param chptr Channel whose banlist to send.
1324 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1331 for (lp = chptr->banlist; lp; lp = lp->next)
1332 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
1335 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1338 /** Check a key against a keyring.
1339 * We are now treating the key part of /join channellist key as a key
1340 * ring; that is, we try one key against the actual channel key, and if that
1341 * doesn't work, we try the next one, and so on. -Kev -Texaco
1342 * Returns: 0 on match, 1 otherwise
1343 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1345 * @param key Key to check
1346 * @param keyring Comma seperated list of keys
1348 * @returns True if the key was found and matches, false otherwise.
1350 static int compall(char *key, char *keyring)
1355 p1 = key; /* point to the key... */
1356 while (*p1 && *p1 == *keyring)
1357 { /* step through the key and ring until they
1363 if (!*p1 && (!*keyring || *keyring == ','))
1364 /* ok, if we're at the end of the and also at the end of one of the keys
1365 in the keyring, we have a match */
1368 if (!*keyring) /* if we're at the end of the key ring, there
1369 weren't any matches, so we return 1 */
1372 /* Not at the end of the key ring, so step
1373 through to the next key in the ring: */
1374 while (*keyring && *(keyring++) != ',');
1376 goto top; /* and check it against the key */
1379 /** Returns if a user can join a channel with a specific key.
1381 * @param sptr The client trying to join
1382 * @param chptr The channel to join
1383 * @param key The key to use
1385 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1386 * if the oper used the magic key, 0 if no error occured.
1388 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1390 int overrideJoin = 0;
1393 * Now a banned user CAN join if invited -- Nemesi
1394 * Now a user CAN escape channel limit if invited -- bfriendly
1395 * Now a user CAN escape anything if invited -- Isomer
1398 if (IsInvited(sptr, chptr))
1401 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1402 a HACK(4) notice will be sent if he would not have been supposed
1403 to join normally. */
1404 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1405 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1406 compall("OVERRIDE",key) == 0)
1407 overrideJoin = MAGIC_OPER_OVERRIDE;
1409 if (chptr->mode.mode & MODE_INVITEONLY)
1410 return overrideJoin + ERR_INVITEONLYCHAN;
1412 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1413 return overrideJoin + ERR_CHANNELISFULL;
1415 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1416 return overrideJoin + ERR_NEEDREGGEDNICK;
1418 if (is_banned(sptr, chptr, NULL))
1419 return overrideJoin + ERR_BANNEDFROMCHAN;
1422 * now using compall (above) to test against a whole key ring -Kev
1424 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1425 return overrideJoin + ERR_BADCHANNELKEY;
1428 return ERR_DONTCHEAT;
1433 /** Remove bells and commas from channel name
1435 * @param cn Channel name to clean, modified in place.
1437 void clean_channelname(char *cn)
1441 for (i = 0; cn[i]; i++) {
1442 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1446 if (IsChannelLower(cn[i])) {
1447 cn[i] = ToLower(cn[i]);
1453 if ((unsigned char)(cn[i]) == 0xd0)
1454 cn[i] = (char) 0xf0;
1460 /** Get a channel block, creating if necessary.
1461 * Get Channel block for chname (and allocate a new channel
1462 * block, if it didn't exists before).
1464 * @param cptr Client joining the channel.
1465 * @param chname The name of the channel to join.
1466 * @param flag set to CGT_CREATE to create the channel if it doesn't
1469 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1470 * wasn't specified or a pointer to the channel structure
1472 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1474 struct Channel *chptr;
1477 if (EmptyString(chname))
1480 len = strlen(chname);
1481 if (MyUser(cptr) && len > CHANNELLEN)
1484 *(chname + CHANNELLEN) = '\0';
1486 if ((chptr = FindChannel(chname)))
1488 if (flag == CGT_CREATE)
1490 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1492 ++UserStats.channels;
1493 memset(chptr, 0, sizeof(struct Channel));
1494 strcpy(chptr->chname, chname);
1495 if (GlobalChannelList)
1496 GlobalChannelList->prev = chptr;
1498 chptr->next = GlobalChannelList;
1499 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1500 GlobalChannelList = chptr;
1506 /** invite a user to a channel.
1508 * Adds an invite for a user to a channel. Limits the number of invites
1509 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1511 * @param cptr The client to be invited.
1512 * @param chptr The channel to be invited to.
1514 void add_invite(struct Client *cptr, struct Channel *chptr)
1516 struct SLink *inv, **tmp;
1518 del_invite(cptr, chptr);
1520 * Delete last link in chain if the list is max length
1522 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1523 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1524 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1526 * Add client to channel invite list
1529 inv->value.cptr = cptr;
1530 inv->next = chptr->invites;
1531 chptr->invites = inv;
1533 * Add channel to the end of the client invite list
1535 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1537 inv->value.chptr = chptr;
1540 (cli_user(cptr))->invites++;
1543 /** Delete an invite
1544 * Delete Invite block from channel invite list and client invite list
1546 * @param cptr Client pointer
1547 * @param chptr Channel pointer
1549 void del_invite(struct Client *cptr, struct Channel *chptr)
1551 struct SLink **inv, *tmp;
1553 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1554 if (tmp->value.cptr == cptr)
1559 (cli_user(cptr))->invites--;
1563 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1564 if (tmp->value.chptr == chptr)
1573 /** @page zombie Explaination of Zombies
1581 * X --a--> A --b--> B --d--> D
1586 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1587 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1589 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1590 * Remove the user immediately when no users are left on the channel.
1591 * b) On server B : remove the user (who/lp) from the channel, send a
1592 * PART upstream (to A) and pass on the KICK.
1593 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1594 * channel, and pass on the KICK.
1595 * d) On server D : remove the user (who/lp) from the channel, and pass on
1599 * - Setting the ZOMBIE flag never hurts, we either remove the
1600 * client after that or we don't.
1601 * - The KICK message was already passed on, as should be in all cases.
1602 * - `who' is removed in all cases except case a) when users are left.
1603 * - A PART is only sent upstream in case b).
1609 * 1 --- 2 --- 3 --- 4 --- 5
1614 * We also need to turn 'who' into a zombie on servers 1 and 6,
1615 * because a KICK from 'who' (kicking someone else in that direction)
1616 * can arrive there afterwards - which should not be bounced itself.
1617 * Therefore case a) also applies for servers 1 and 6.
1622 /** Turn a user on a channel into a zombie
1623 * This function turns a user into a zombie (see \ref zombie)
1625 * @param member The structure representing this user on this channel.
1626 * @param who The client that is being kicked.
1627 * @param cptr The connection the kick came from.
1628 * @param sptr The client that is doing the kicking.
1629 * @param chptr The channel the user is being kicked from.
1631 void make_zombie(struct Membership* member, struct Client* who,
1632 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1634 assert(0 != member);
1639 /* Default for case a): */
1642 /* Case b) or c) ?: */
1643 if (MyUser(who)) /* server 4 */
1645 if (IsServer(cptr)) /* Case b) ? */
1646 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1647 remove_user_from_channel(who, chptr);
1650 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1652 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1653 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1654 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1656 remove_user_from_channel(who, chptr);
1661 /* Case a) (servers 1, 2, 3 and 6) */
1662 if (channel_all_zombies(chptr))
1663 remove_user_from_channel(who, chptr);
1665 /* XXX Can't actually call Debug here; if the channel is all zombies,
1666 * chptr will no longer exist when we get here.
1667 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1671 /** returns the number of zombies on a channel
1672 * @param chptr Channel to count zombies in.
1674 * @returns The number of zombies on the channel.
1676 int number_of_zombies(struct Channel *chptr)
1678 struct Membership* member;
1682 for (member = chptr->members; member; member = member->next_member) {
1683 if (IsZombie(member))
1689 /** Concatenate some strings together.
1690 * This helper function builds an argument string in strptr, consisting
1691 * of the original string, a space, and str1 and str2 concatenated (if,
1692 * of course, str2 is not NULL)
1694 * @param strptr The buffer to concatenate into
1695 * @param strptr_i modified offset to the position to modify
1696 * @param str1 The string to contatenate from.
1697 * @param str2 The second string to contatenate from.
1698 * @param c Charactor to seperate the string from str1 and str2.
1701 build_string(char *strptr, int *strptr_i, const char *str1,
1702 const char *str2, char c)
1705 strptr[(*strptr_i)++] = c;
1708 strptr[(*strptr_i)++] = *(str1++);
1712 strptr[(*strptr_i)++] = *(str2++);
1714 strptr[(*strptr_i)] = '\0';
1717 /** Flush out the modes
1718 * This is the workhorse of our ModeBuf suite; this actually generates the
1719 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1721 * @param mbuf The mode buffer to flush
1722 * @param all If true, flush all modes, otherwise leave partial modes in the
1728 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1730 /* we only need the flags that don't take args right now */
1731 static int flags[] = {
1732 /* MODE_CHANOP, 'o', */
1733 /* MODE_VOICE, 'v', */
1736 MODE_MODERATED, 'm',
1737 MODE_TOPICLIMIT, 't',
1738 MODE_INVITEONLY, 'i',
1739 MODE_NOPRIVMSGS, 'n',
1742 MODE_WASDELJOINS, 'd',
1743 /* MODE_KEY, 'k', */
1744 /* MODE_BAN, 'b', */
1746 /* MODE_APASS, 'A', */
1747 /* MODE_UPASS, 'U', */
1753 struct Client *app_source; /* where the MODE appears to come from */
1755 char addbuf[20]; /* accumulates +psmtin, etc. */
1757 char rembuf[20]; /* accumulates -psmtin, etc. */
1759 char *bufptr; /* we make use of indirection to simplify the code */
1762 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1764 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1766 char *strptr; /* more indirection to simplify the code */
1769 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1772 char limitbuf[20]; /* convert limits to strings */
1774 unsigned int limitdel = MODE_LIMIT;
1778 /* If the ModeBuf is empty, we have nothing to do */
1779 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1782 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1784 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1787 app_source = mbuf->mb_source;
1790 * Account for user we're bouncing; we have to get it in on the first
1791 * bounced MODE, or we could have problems
1793 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1794 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1796 /* Calculate the simple flags */
1797 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1798 if (*flag_p & mbuf->mb_add)
1799 addbuf[addbuf_i++] = flag_p[1];
1800 else if (*flag_p & mbuf->mb_rem)
1801 rembuf[rembuf_i++] = flag_p[1];
1804 /* Now go through the modes with arguments... */
1805 for (i = 0; i < mbuf->mb_count; i++) {
1806 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1808 bufptr_i = &addbuf_i;
1811 bufptr_i = &rembuf_i;
1814 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1815 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1817 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1818 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1820 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1821 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1823 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1824 tmp = strlen(MB_STRING(mbuf, i));
1826 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1827 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1830 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1842 bufptr[(*bufptr_i)++] = mode_char;
1843 totalbuflen -= tmp + 1;
1845 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1846 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1847 strlen(MB_STRING(mbuf, i)));
1849 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1850 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1852 bufptr[(*bufptr_i)++] = 'k';
1853 totalbuflen -= tmp + 1;
1855 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1856 /* if it's a limit, we also format the number */
1857 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1859 tmp = strlen(limitbuf);
1861 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1862 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1864 bufptr[(*bufptr_i)++] = 'l';
1865 totalbuflen -= tmp + 1;
1870 /* terminate the mode strings */
1871 addbuf[addbuf_i] = '\0';
1872 rembuf[rembuf_i] = '\0';
1874 /* If we're building a user visible MODE or HACK... */
1875 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1876 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1877 MODEBUF_DEST_LOG)) {
1878 /* Set up the parameter strings */
1884 for (i = 0; i < mbuf->mb_count; i++) {
1885 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1888 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1890 strptr_i = &addstr_i;
1893 strptr_i = &remstr_i;
1896 /* deal with clients... */
1897 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1898 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1900 /* deal with bans... */
1901 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1902 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1904 /* deal with keys... */
1905 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1906 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1907 "*" : MB_STRING(mbuf, i), 0, ' ');
1909 /* deal with invisible passwords */
1910 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1911 build_string(strptr, strptr_i, "*", 0, ' ');
1914 * deal with limit; note we cannot include the limit parameter if we're
1917 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1918 (MODE_ADD | MODE_LIMIT))
1919 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1922 /* send the messages off to their destination */
1923 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1924 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1926 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1927 mbuf->mb_source : app_source),
1928 mbuf->mb_channel->chname,
1929 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1930 addbuf, remstr, addstr,
1931 mbuf->mb_channel->creationtime);
1933 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1934 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1935 "%s%s%s%s%s%s [%Tu]",
1936 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1937 mbuf->mb_source : app_source),
1938 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1939 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1940 mbuf->mb_channel->creationtime);
1942 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1943 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1945 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1946 mbuf->mb_source : app_source),
1947 mbuf->mb_channel->chname,
1948 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1949 addbuf, remstr, addstr,
1950 mbuf->mb_channel->creationtime);
1952 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1953 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1954 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1955 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1956 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1958 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1959 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1960 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1961 rembuf_i ? "-" : "", rembuf,
1962 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1965 /* Now are we supposed to propagate to other servers? */
1966 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1967 /* set up parameter string */
1974 * limit is supressed if we're removing it; we have to figure out which
1975 * direction is the direction for it to be removed, though...
1977 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1979 for (i = 0; i < mbuf->mb_count; i++) {
1980 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1983 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1985 strptr_i = &addstr_i;
1988 strptr_i = &remstr_i;
1991 /* deal with modes that take clients */
1992 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1993 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1995 /* deal with modes that take strings */
1996 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1997 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2000 * deal with the limit. Logic here is complicated; if HACK2 is set,
2001 * we're bouncing the mode, so sense is reversed, and we have to
2002 * include the original limit if it looks like it's being removed
2004 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2005 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2008 /* we were told to deop the source */
2009 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2010 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2011 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2012 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2014 /* mark that we've done this, so we don't do it again */
2015 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2018 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2019 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2020 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2021 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2022 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2023 addbuf, remstr, addstr);
2024 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2026 * If HACK2 was set, we're bouncing; we send the MODE back to the
2027 * connection we got it from with the senses reversed and a TS of 0;
2030 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2031 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2032 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2033 mbuf->mb_channel->creationtime);
2036 * We're propagating a normal MODE command to the rest of the network;
2037 * we send the actual channel TS unless this is a HACK3 or a HACK4
2039 if (IsServer(mbuf->mb_source))
2040 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2041 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2042 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2043 addbuf, remstr, addstr,
2044 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2045 mbuf->mb_channel->creationtime);
2047 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2048 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2049 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2050 addbuf, remstr, addstr);
2054 /* We've drained the ModeBuf... */
2059 /* reinitialize the mode-with-arg slots */
2060 for (i = 0; i < MAXMODEPARAMS; i++) {
2061 /* If we saved any, pack them down */
2062 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2063 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2064 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2066 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2068 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2069 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2071 MB_TYPE(mbuf, i) = 0;
2072 MB_UINT(mbuf, i) = 0;
2075 /* If we're supposed to flush it all, do so--all hail tail recursion */
2076 if (all && mbuf->mb_count)
2077 return modebuf_flush_int(mbuf, 1);
2082 /** Initialise a modebuf
2083 * This routine just initializes a ModeBuf structure with the information
2084 * needed and the options given.
2086 * @param mbuf The mode buffer to initialise.
2087 * @param source The client that is performing the mode.
2089 * @param chan The channel that the mode is being performed upon.
2093 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2094 struct Client *connect, struct Channel *chan, unsigned int dest)
2099 assert(0 != source);
2103 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2107 mbuf->mb_source = source;
2108 mbuf->mb_connect = connect;
2109 mbuf->mb_channel = chan;
2110 mbuf->mb_dest = dest;
2113 /* clear each mode-with-parameter slot */
2114 for (i = 0; i < MAXMODEPARAMS; i++) {
2115 MB_TYPE(mbuf, i) = 0;
2116 MB_UINT(mbuf, i) = 0;
2120 /** Append a new mode to a modebuf
2121 * This routine simply adds modes to be added or deleted; do a binary OR
2122 * with either MODE_ADD or MODE_DEL
2124 * @param mbuf Mode buffer
2125 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2128 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2131 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2133 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2134 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2135 MODE_DELJOINS | MODE_WASDELJOINS);
2137 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2140 if (mode & MODE_ADD) {
2141 mbuf->mb_rem &= ~mode;
2142 mbuf->mb_add |= mode;
2144 mbuf->mb_add &= ~mode;
2145 mbuf->mb_rem |= mode;
2149 /** Append a mode that takes an int argument to the modebuf
2151 * This routine adds a mode to be added or deleted that takes a unsigned
2152 * int parameter; mode may *only* be the relevant mode flag ORed with one
2153 * of MODE_ADD or MODE_DEL
2155 * @param mbuf The mode buffer to append to.
2156 * @param mode The mode to append.
2157 * @param uint The argument to the mode.
2160 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2163 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2165 if (mode == (MODE_LIMIT | MODE_DEL)) {
2166 mbuf->mb_rem |= mode;
2169 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2170 MB_UINT(mbuf, mbuf->mb_count) = uint;
2172 /* when we've reached the maximal count, flush the buffer */
2173 if (++mbuf->mb_count >=
2174 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2175 modebuf_flush_int(mbuf, 0);
2178 /** append a string mode
2179 * This routine adds a mode to be added or deleted that takes a string
2180 * parameter; mode may *only* be the relevant mode flag ORed with one of
2181 * MODE_ADD or MODE_DEL
2183 * @param mbuf The mode buffer to append to.
2184 * @param mode The mode to append.
2185 * @param string The string parameter to append.
2186 * @param free If the string should be free'd later.
2189 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2193 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2195 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2196 MB_STRING(mbuf, mbuf->mb_count) = string;
2198 /* when we've reached the maximal count, flush the buffer */
2199 if (++mbuf->mb_count >=
2200 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2201 modebuf_flush_int(mbuf, 0);
2204 /** Append a mode on a client to a modebuf.
2205 * This routine adds a mode to be added or deleted that takes a client
2206 * parameter; mode may *only* be the relevant mode flag ORed with one of
2207 * MODE_ADD or MODE_DEL
2209 * @param mbuf The modebuf to append the mode to.
2210 * @param mode The mode to append.
2211 * @param client The client argument to append.
2214 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2215 struct Client *client)
2218 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2220 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2221 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2223 /* when we've reached the maximal count, flush the buffer */
2224 if (++mbuf->mb_count >=
2225 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2226 modebuf_flush_int(mbuf, 0);
2229 /** The exported binding for modebuf_flush()
2231 * @param mbuf The mode buffer to flush.
2233 * @see modebuf_flush_int()
2236 modebuf_flush(struct ModeBuf *mbuf)
2238 struct Membership *memb;
2240 /* Check if MODE_WASDELJOINS should be set */
2241 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2242 && (mbuf->mb_rem & MODE_DELJOINS)) {
2243 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2244 if (IsDelayedJoin(memb)) {
2245 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2246 mbuf->mb_add |= MODE_WASDELJOINS;
2247 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2253 return modebuf_flush_int(mbuf, 1);
2256 /* This extracts the simple modes contained in mbuf
2258 * @param mbuf The mode buffer to extract the modes from.
2259 * @param buf The string buffer to write the modes into.
2262 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2264 static int flags[] = {
2265 /* MODE_CHANOP, 'o', */
2266 /* MODE_VOICE, 'v', */
2269 MODE_MODERATED, 'm',
2270 MODE_TOPICLIMIT, 't',
2271 MODE_INVITEONLY, 'i',
2272 MODE_NOPRIVMSGS, 'n',
2276 /* MODE_BAN, 'b', */
2283 int i, bufpos = 0, len;
2285 char *key = 0, limitbuf[20];
2286 char *apass = 0, *upass = 0;
2295 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2296 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2297 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2299 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2300 key = MB_STRING(mbuf, i);
2301 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2302 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2303 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2304 upass = MB_STRING(mbuf, i);
2305 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2306 apass = MB_STRING(mbuf, i);
2313 buf[bufpos++] = '+'; /* start building buffer */
2315 for (flag_p = flags; flag_p[0]; flag_p += 2)
2317 buf[bufpos++] = flag_p[1];
2319 for (i = 0, len = bufpos; i < len; i++) {
2321 build_string(buf, &bufpos, key, 0, ' ');
2322 else if (buf[i] == 'l')
2323 build_string(buf, &bufpos, limitbuf, 0, ' ');
2324 else if (buf[i] == 'U')
2325 build_string(buf, &bufpos, upass, 0, ' ');
2326 else if (buf[i] == 'A')
2327 build_string(buf, &bufpos, apass, 0, ' ');
2335 /** Simple function to invalidate bans
2337 * This function sets all bans as being valid.
2339 * @param chan The channel to operate on.
2342 mode_ban_invalidate(struct Channel *chan)
2344 struct Membership *member;
2346 for (member = chan->members; member; member = member->next_member)
2347 ClearBanValid(member);
2350 /** Simple function to drop invite structures
2352 * Remove all the invites on the channel.
2354 * @param chan Channel to remove invites from.
2358 mode_invite_clear(struct Channel *chan)
2360 while (chan->invites)
2361 del_invite(chan->invites->value.cptr, chan);
2364 /* What we've done for mode_parse so far... */
2365 #define DONE_LIMIT 0x01 /**< We've set the limit */
2366 #define DONE_KEY 0x02 /**< We've set the key */
2367 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2368 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2369 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2370 #define DONE_UPASS 0x20 /**< We've set user pass */
2371 #define DONE_APASS 0x40 /**< We've set admin pass */
2374 struct ModeBuf *mbuf;
2375 struct Client *cptr;
2376 struct Client *sptr;
2377 struct Channel *chptr;
2378 struct Membership *member;
2389 struct Ban banlist[MAXPARA];
2392 struct Client *client;
2393 } cli_change[MAXPARA];
2396 /** Helper function to send "Not oper" or "Not member" messages
2397 * Here's a helper function to deal with sending along "Not oper" or
2398 * "Not member" messages
2400 * @param state Parsing State object
2403 send_notoper(struct ParseState *state)
2405 if (state->done & DONE_NOTOPER)
2408 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2409 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2411 state->done |= DONE_NOTOPER;
2415 * Helper function to convert limits
2417 * @param state Parsing state object.
2421 mode_parse_limit(struct ParseState *state, int *flag_p)
2423 unsigned int t_limit;
2425 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2426 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2429 if (state->parc <= 0) { /* warn if not enough args */
2430 if (MyUser(state->sptr))
2431 need_more_params(state->sptr, "MODE +l");
2435 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2439 if ((int)t_limit<0) /* don't permit a negative limit */
2442 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2443 (!t_limit || t_limit == state->chptr->mode.limit))
2446 t_limit = state->chptr->mode.limit;
2448 /* If they're not an oper, they can't change modes */
2449 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2450 send_notoper(state);
2454 /* Can't remove a limit that's not there */
2455 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2458 /* Skip if this is a burst and a lower limit than this is set already */
2459 if ((state->flags & MODE_PARSE_BURST) &&
2460 (state->chptr->mode.mode & flag_p[0]) &&
2461 (state->chptr->mode.limit < t_limit))
2464 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2466 state->done |= DONE_LIMIT;
2471 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2473 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2474 if (state->dir & MODE_ADD) {
2475 state->chptr->mode.mode |= flag_p[0];
2476 state->chptr->mode.limit = t_limit;
2478 state->chptr->mode.mode &= ~flag_p[0];
2479 state->chptr->mode.limit = 0;
2485 * Helper function to convert keys
2488 mode_parse_key(struct ParseState *state, int *flag_p)
2493 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2496 if (state->parc <= 0) { /* warn if not enough args */
2497 if (MyUser(state->sptr))
2498 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2503 t_str = state->parv[state->args_used++]; /* grab arg */
2507 /* If they're not an oper, they can't change modes */
2508 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2509 send_notoper(state);
2513 if (state->done & DONE_KEY) /* allow key to be set only once */
2515 state->done |= DONE_KEY;
2519 /* clean up the key string */
2521 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2525 if (!*t_str) { /* warn if empty */
2526 if (MyUser(state->sptr))
2527 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2535 /* Skip if this is a burst, we have a key already and the new key is
2536 * after the old one alphabetically */
2537 if ((state->flags & MODE_PARSE_BURST) &&
2538 *(state->chptr->mode.key) &&
2539 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2542 /* can't add a key if one is set, nor can one remove the wrong key */
2543 if (!(state->flags & MODE_PARSE_FORCE))
2544 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2545 (state->dir == MODE_DEL &&
2546 ircd_strcmp(state->chptr->mode.key, t_str))) {
2547 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2551 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2552 !ircd_strcmp(state->chptr->mode.key, t_str))
2553 return; /* no key change */
2555 if (state->flags & MODE_PARSE_BOUNCE) {
2556 if (*state->chptr->mode.key) /* reset old key */
2557 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2558 state->chptr->mode.key, 0);
2559 else /* remove new bogus key */
2560 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2561 } else /* send new key */
2562 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2564 if (state->flags & MODE_PARSE_SET) {
2565 if (state->dir == MODE_ADD) /* set the new key */
2566 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2567 else /* remove the old key */
2568 *state->chptr->mode.key = '\0';
2573 * Helper function to convert user passes
2576 mode_parse_upass(struct ParseState *state, int *flag_p)
2581 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2584 if (state->parc <= 0) { /* warn if not enough args */
2585 if (MyUser(state->sptr))
2586 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2591 t_str = state->parv[state->args_used++]; /* grab arg */
2595 /* If they're not an oper, they can't change modes */
2596 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2597 send_notoper(state);
2601 /* If a non-service user is trying to force it, refuse. */
2602 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2603 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2604 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2608 /* If they are not the channel manager, they are not allowed to change it */
2609 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2610 if (*state->chptr->mode.apass) {
2611 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2612 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2614 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2615 "Re-create the channel. The channel must be *empty* for",
2616 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2617 "before it can be recreated.");
2622 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2624 state->done |= DONE_UPASS;
2626 t_len = PASSLEN + 1;
2628 /* clean up the upass string */
2630 while (*++s > ' ' && *s != ':' && --t_len)
2634 if (!*t_str) { /* warn if empty */
2635 if (MyUser(state->sptr))
2636 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2644 if (!(state->flags & MODE_PARSE_FORCE))
2645 /* can't add the upass while apass is not set */
2646 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2647 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2650 /* can't add a upass if one is set, nor can one remove the wrong upass */
2651 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2652 (state->dir == MODE_DEL &&
2653 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2654 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2658 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2659 !ircd_strcmp(state->chptr->mode.upass, t_str))
2660 return; /* no upass change */
2662 if (state->flags & MODE_PARSE_BOUNCE) {
2663 if (*state->chptr->mode.upass) /* reset old upass */
2664 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2665 state->chptr->mode.upass, 0);
2666 else /* remove new bogus upass */
2667 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2668 } else /* send new upass */
2669 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2671 if (state->flags & MODE_PARSE_SET) {
2672 if (state->dir == MODE_ADD) /* set the new upass */
2673 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2674 else /* remove the old upass */
2675 *state->chptr->mode.upass = '\0';
2680 * Helper function to convert admin passes
2683 mode_parse_apass(struct ParseState *state, int *flag_p)
2688 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2691 if (state->parc <= 0) { /* warn if not enough args */
2692 if (MyUser(state->sptr))
2693 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2698 t_str = state->parv[state->args_used++]; /* grab arg */
2702 /* If they're not an oper, they can't change modes */
2703 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2704 send_notoper(state);
2708 /* If a non-service user is trying to force it, refuse. */
2709 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2710 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2711 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2715 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2716 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2717 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2721 /* If they are not the channel manager, they are not allowed to change it */
2722 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2723 if (*state->chptr->mode.apass) {
2724 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2725 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2727 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2728 "Re-create the channel. The channel must be *empty* for",
2729 "at least a whole minute", "before it can be recreated.");
2734 if (state->done & DONE_APASS) /* allow apass to be set only once */
2736 state->done |= DONE_APASS;
2738 t_len = PASSLEN + 1;
2740 /* clean up the apass string */
2742 while (*++s > ' ' && *s != ':' && --t_len)
2746 if (!*t_str) { /* warn if empty */
2747 if (MyUser(state->sptr))
2748 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2756 if (!(state->flags & MODE_PARSE_FORCE)) {
2757 /* can't remove the apass while upass is still set */
2758 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2759 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2762 /* can't add an apass if one is set, nor can one remove the wrong apass */
2763 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2764 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2765 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2770 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2771 !ircd_strcmp(state->chptr->mode.apass, t_str))
2772 return; /* no apass change */
2774 if (state->flags & MODE_PARSE_BOUNCE) {
2775 if (*state->chptr->mode.apass) /* reset old apass */
2776 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2777 state->chptr->mode.apass, 0);
2778 else /* remove new bogus apass */
2779 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2780 } else /* send new apass */
2781 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2783 if (state->flags & MODE_PARSE_SET) {
2784 if (state->dir == MODE_ADD) { /* set the new apass */
2785 /* Make it VERY clear to the user that this is a one-time password */
2786 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2787 if (MyUser(state->sptr)) {
2788 send_reply(state->sptr, RPL_APASSWARN,
2789 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2790 "Are you SURE you want to use this as Admin password? ",
2791 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2792 send_reply(state->sptr, RPL_APASSWARN,
2793 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2794 "\" to remove the password and then immediately set a new one. "
2795 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2796 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2797 "Now set the channel user password (+u).");
2799 } else { /* remove the old apass */
2800 *state->chptr->mode.apass = '\0';
2801 if (MyUser(state->sptr))
2802 send_reply(state->sptr, RPL_APASSWARN,
2803 "WARNING: You removed the channel Admin password MODE (+A). ",
2804 "If you would disconnect or leave the channel without setting a new password then you will ",
2805 "not be able to set it again and lose ownership of this channel! ",
2806 "SET A NEW PASSWORD NOW!", "");
2812 * Helper function to convert bans
2815 mode_parse_ban(struct ParseState *state, int *flag_p)
2818 struct Ban *ban, *newban = 0;
2820 if (state->parc <= 0) { /* Not enough args, send ban list */
2821 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2822 send_ban_list(state->sptr, state->chptr);
2823 state->done |= DONE_BANLIST;
2829 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2832 t_str = state->parv[state->args_used++]; /* grab arg */
2836 /* If they're not an oper, they can't change modes */
2837 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2838 send_notoper(state);
2842 if ((s = strchr(t_str, ' ')))
2845 if (!*t_str || *t_str == ':') { /* warn if empty */
2846 if (MyUser(state->sptr))
2847 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2852 t_str = collapse(pretty_mask(t_str));
2854 /* remember the ban for the moment... */
2855 if (state->dir == MODE_ADD) {
2856 newban = state->banlist + (state->numbans++);
2858 newban->flags = BAN_ADD;
2859 set_ban_mask(newban, t_str);
2860 newban->who = cli_name(state->sptr);
2861 newban->when = TStime();
2864 if (!state->chptr->banlist) {
2865 state->chptr->banlist = newban; /* add our ban with its flags */
2866 state->done |= DONE_BANCLEAN;
2870 /* Go through all bans */
2871 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2872 /* first, clean the ban flags up a bit */
2873 if (!(state->done & DONE_BANCLEAN))
2874 /* Note: We're overloading *lots* of bits here; be careful! */
2875 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2879 * BAN_ADD - Ban was added; if we're bouncing modes,
2880 * then we'll remove it below; otherwise,
2881 * we'll have to allocate a real ban
2883 * BAN_DEL - Ban was marked for deletion; if we're
2884 * bouncing modes, we'll have to re-add it,
2885 * otherwise, we'll have to remove it
2887 * BAN_OVERLAPPED - The ban we added turns out to overlap
2888 * with a ban already set; if we're
2889 * bouncing modes, we'll have to bounce
2890 * this one; otherwise, we'll just ignore
2891 * it when we process added bans
2894 if (state->dir == MODE_DEL && !ircd_strcmp(ban->banstr, t_str)) {
2895 ban->flags |= BAN_DEL; /* delete one ban */
2897 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2899 } else if (state->dir == MODE_ADD) {
2900 /* if the ban already exists, don't worry about it */
2901 if (!ircd_strcmp(ban->banstr, t_str)) {
2902 newban->flags &= ~BAN_ADD; /* don't add ban at all */
2903 MyFree(newban->banstr); /* stopper a leak */
2904 state->numbans--; /* deallocate last ban */
2905 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2907 } else if (!mmatch(ban->banstr, t_str)) {
2908 if (!(ban->flags & BAN_DEL))
2909 newban->flags |= BAN_OVERLAPPED; /* our ban overlaps */
2910 } else if (!mmatch(t_str, ban->banstr))
2911 ban->flags |= BAN_DEL; /* mark ban for deletion: overlapping */
2913 if (!ban->next && (newban->flags & BAN_ADD))
2915 ban->next = newban; /* add our ban with its flags */
2916 break; /* get out of loop */
2920 state->done |= DONE_BANCLEAN;
2924 * This is the bottom half of the ban processor
2927 mode_process_bans(struct ParseState *state)
2929 struct Ban *ban, *newban, *prevban, *nextban;
2935 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2937 banlen = strlen(ban->banstr);
2939 nextban = ban->next;
2941 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2943 prevban->next = 0; /* Break the list; ban isn't a real ban */
2945 state->chptr->banlist = 0;
2950 MyFree(ban->banstr);
2953 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2954 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2956 state->flags & MODE_PARSE_SET);
2958 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2959 if (prevban) /* clip it out of the list... */
2960 prevban->next = ban->next;
2962 state->chptr->banlist = ban->next;
2967 ban->banstr = NULL; /* do not free this string */
2971 continue; /* next ban; keep prevban like it is */
2973 ban->flags &= BAN_IPMASK; /* unset other flags */
2974 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2976 prevban->next = 0; /* Break the list; ban isn't a real ban */
2978 state->chptr->banlist = 0;
2980 /* If we're supposed to ignore it, do so. */
2981 if (ban->flags & BAN_OVERLAPPED &&
2982 !(state->flags & MODE_PARSE_BOUNCE)) {
2985 MyFree(ban->banstr);
2987 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2988 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2989 count > feature_int(FEAT_MAXBANS))) {
2990 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2994 MyFree(ban->banstr);
2996 /* add the ban to the buffer */
2997 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2999 !(state->flags & MODE_PARSE_SET));
3001 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3002 newban = make_ban(ban->banstr);
3003 DupString(newban->who, ban->who);
3004 newban->when = ban->when;
3005 newban->flags = ban->flags & BAN_IPMASK;
3007 newban->next = state->chptr->banlist; /* and link it in */
3008 state->chptr->banlist = newban;
3017 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3019 if (changed) /* if we changed the ban list, we must invalidate the bans */
3020 mode_ban_invalidate(state->chptr);
3024 * Helper function to process client changes
3027 mode_parse_client(struct ParseState *state, int *flag_p)
3030 struct Client *acptr;
3033 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3036 if (state->parc <= 0) /* return if not enough args */
3039 t_str = state->parv[state->args_used++]; /* grab arg */
3043 /* If they're not an oper, they can't change modes */
3044 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3045 send_notoper(state);
3049 if (MyUser(state->sptr)) /* find client we're manipulating */
3050 acptr = find_chasing(state->sptr, t_str, NULL);
3052 acptr = findNUser(t_str);
3055 return; /* find_chasing() already reported an error to the user */
3057 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3058 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3059 state->cli_change[i].flag & flag_p[0]))
3060 break; /* found a slot */
3062 /* Store what we're doing to them */
3063 state->cli_change[i].flag = state->dir | flag_p[0];
3064 state->cli_change[i].client = acptr;
3068 * Helper function to process the changed client list
3071 mode_process_clients(struct ParseState *state)
3074 struct Membership *member;
3076 for (i = 0; state->cli_change[i].flag; i++) {
3077 assert(0 != state->cli_change[i].client);
3079 /* look up member link */
3080 if (!(member = find_member_link(state->chptr,
3081 state->cli_change[i].client)) ||
3082 (MyUser(state->sptr) && IsZombie(member))) {
3083 if (MyUser(state->sptr))
3084 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3085 cli_name(state->cli_change[i].client),
3086 state->chptr->chname);
3090 if ((state->cli_change[i].flag & MODE_ADD &&
3091 (state->cli_change[i].flag & member->status)) ||
3092 (state->cli_change[i].flag & MODE_DEL &&
3093 !(state->cli_change[i].flag & member->status)))
3094 continue; /* no change made, don't do anything */
3096 /* see if the deop is allowed */
3097 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3098 (MODE_DEL | MODE_CHANOP)) {
3099 /* prevent +k users from being deopped */
3100 if (IsChannelService(state->cli_change[i].client)) {
3101 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3102 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3104 (IsServer(state->sptr) ? cli_name(state->sptr) :
3105 cli_name((cli_user(state->sptr))->server)));
3107 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3108 send_reply(state->sptr, ERR_ISCHANSERVICE,
3109 cli_name(state->cli_change[i].client),
3110 state->chptr->chname);
3115 /* check deop for local user */
3116 if (MyUser(state->sptr)) {
3118 /* don't allow local opers to be deopped on local channels */
3119 if (state->cli_change[i].client != state->sptr &&
3120 IsLocalChannel(state->chptr->chname) &&
3121 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3122 send_reply(state->sptr, ERR_ISOPERLCHAN,
3123 cli_name(state->cli_change[i].client),
3124 state->chptr->chname);
3128 if (feature_bool(FEAT_OPLEVELS)) {
3129 /* don't allow to deop members with an op level that is <= our own level */
3130 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3132 && OpLevel(member) <= OpLevel(state->member)) {
3133 int equal = (OpLevel(member) == OpLevel(state->member));
3134 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3135 cli_name(state->cli_change[i].client),
3136 state->chptr->chname,
3137 OpLevel(state->member), OpLevel(member),
3138 "deop", equal ? "the same" : "a higher");
3145 /* set op-level of member being opped */
3146 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3147 (MODE_ADD | MODE_CHANOP)) {
3148 /* If on a channel with upass set, someone with level x gives ops to someone else,
3149 then that person gets level x-1. On other channels, where upass is not set,
3150 the level stays the same. */
3151 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3152 /* Someone being opped by a server gets op-level 0 */
3153 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3154 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3157 /* actually effect the change */
3158 if (state->flags & MODE_PARSE_SET) {
3159 if (state->cli_change[i].flag & MODE_ADD) {
3160 if (IsDelayedJoin(member))
3161 RevealDelayedJoin(member);
3162 member->status |= (state->cli_change[i].flag &
3163 (MODE_CHANOP | MODE_VOICE));
3164 if (state->cli_change[i].flag & MODE_CHANOP)
3165 ClearDeopped(member);
3167 member->status &= ~(state->cli_change[i].flag &
3168 (MODE_CHANOP | MODE_VOICE));
3171 /* accumulate the change */
3172 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3173 state->cli_change[i].client);
3174 } /* for (i = 0; state->cli_change[i].flags; i++) */
3178 * Helper function to process the simple modes
3181 mode_parse_mode(struct ParseState *state, int *flag_p)
3183 /* If they're not an oper, they can't change modes */
3184 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3185 send_notoper(state);
3192 if (state->dir == MODE_ADD) {
3193 state->add |= flag_p[0];
3194 state->del &= ~flag_p[0];
3196 if (flag_p[0] & MODE_SECRET) {
3197 state->add &= ~MODE_PRIVATE;
3198 state->del |= MODE_PRIVATE;
3199 } else if (flag_p[0] & MODE_PRIVATE) {
3200 state->add &= ~MODE_SECRET;
3201 state->del |= MODE_SECRET;
3203 if (flag_p[0] & MODE_DELJOINS) {
3204 state->add &= ~MODE_WASDELJOINS;
3205 state->del |= MODE_WASDELJOINS;
3208 state->add &= ~flag_p[0];
3209 state->del |= flag_p[0];
3212 assert(0 == (state->add & state->del));
3213 assert((MODE_SECRET | MODE_PRIVATE) !=
3214 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3218 * This routine is intended to parse MODE or OPMODE commands and effect the
3219 * changes (or just build the bounce buffer). We pass the starting offset
3223 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3224 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3225 struct Membership* member)
3227 static int chan_flags[] = {
3232 MODE_MODERATED, 'm',
3233 MODE_TOPICLIMIT, 't',
3234 MODE_INVITEONLY, 'i',
3235 MODE_NOPRIVMSGS, 'n',
3249 unsigned int t_mode;
3251 struct ParseState state;
3262 state.chptr = chptr;
3263 state.member = member;
3266 state.flags = flags;
3267 state.dir = MODE_ADD;
3271 state.args_used = 0;
3272 state.max_args = MAXMODEPARAMS;
3275 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3276 state.banlist[i].next = 0;
3277 state.banlist[i].who = 0;
3278 state.banlist[i].when = 0;
3279 state.banlist[i].flags = 0;
3280 state.cli_change[i].flag = 0;
3281 state.cli_change[i].client = 0;
3284 modestr = state.parv[state.args_used++];
3288 for (; *modestr; modestr++) {
3289 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3290 if (flag_p[1] == *modestr)
3293 if (!flag_p[0]) { /* didn't find it? complain and continue */
3294 if (MyUser(state.sptr))
3295 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3300 case '+': /* switch direction to MODE_ADD */
3301 case '-': /* switch direction to MODE_DEL */
3302 state.dir = flag_p[0];
3305 case 'l': /* deal with limits */
3306 mode_parse_limit(&state, flag_p);
3309 case 'k': /* deal with keys */
3310 mode_parse_key(&state, flag_p);
3313 case 'A': /* deal with Admin passes */
3314 if (feature_bool(FEAT_OPLEVELS))
3315 mode_parse_apass(&state, flag_p);
3318 case 'U': /* deal with user passes */
3319 if (feature_bool(FEAT_OPLEVELS))
3320 mode_parse_upass(&state, flag_p);
3323 case 'b': /* deal with bans */
3324 mode_parse_ban(&state, flag_p);
3327 case 'o': /* deal with ops/voice */
3329 mode_parse_client(&state, flag_p);
3332 default: /* deal with other modes */
3333 mode_parse_mode(&state, flag_p);
3335 } /* switch (*modestr) */
3336 } /* for (; *modestr; modestr++) */
3338 if (state.flags & MODE_PARSE_BURST)
3339 break; /* don't interpret any more arguments */
3341 if (state.parc > 0) { /* process next argument in string */
3342 modestr = state.parv[state.args_used++];
3346 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3349 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3350 break; /* we're then going to bounce the mode! */
3352 recv_ts = atoi(modestr);
3354 if (recv_ts && recv_ts < state.chptr->creationtime)
3355 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3357 break; /* break out of while loop */
3358 } else if (state.flags & MODE_PARSE_STRICT ||
3359 (MyUser(state.sptr) && state.max_args <= 0)) {
3360 state.parc++; /* we didn't actually gobble the argument */
3362 break; /* break out of while loop */
3365 } /* while (*modestr) */
3368 * the rest of the function finishes building resultant MODEs; if the
3369 * origin isn't a member or an oper, skip it.
3371 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3372 return state.args_used; /* tell our parent how many args we gobbled */
3374 t_mode = state.chptr->mode.mode;
3376 if (state.del & t_mode) { /* delete any modes to be deleted... */
3377 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3379 t_mode &= ~state.del;
3381 if (state.add & ~t_mode) { /* add any modes to be added... */
3382 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3384 t_mode |= state.add;
3387 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3388 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3389 !(t_mode & MODE_INVITEONLY))
3390 mode_invite_clear(state.chptr);
3392 state.chptr->mode.mode = t_mode;
3395 if (state.flags & MODE_PARSE_WIPEOUT) {
3396 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3397 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3398 state.chptr->mode.limit);
3399 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3400 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3401 state.chptr->mode.key, 0);
3402 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3403 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3404 state.chptr->mode.upass, 0);
3405 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3406 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3407 state.chptr->mode.apass, 0);
3410 if (state.done & DONE_BANCLEAN) /* process bans */
3411 mode_process_bans(&state);
3413 /* process client changes */
3414 if (state.cli_change[0].flag)
3415 mode_process_clients(&state);
3417 return state.args_used; /* tell our parent how many args we gobbled */
3421 * Initialize a join buffer
3424 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3425 struct Client *connect, unsigned int type, char *comment,
3431 assert(0 != source);
3432 assert(0 != connect);
3434 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3435 jbuf->jb_connect = connect;
3436 jbuf->jb_type = type;
3437 jbuf->jb_comment = comment;
3438 jbuf->jb_create = create;
3440 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3441 type == JOINBUF_TYPE_PART ||
3442 type == JOINBUF_TYPE_PARTALL) ?
3443 STARTJOINLEN : STARTCREATELEN) +
3444 (comment ? strlen(comment) + 2 : 0));
3446 for (i = 0; i < MAXJOINARGS; i++)
3447 jbuf->jb_channels[i] = 0;
3451 * Add a channel to the join buffer
3454 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3462 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3463 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3468 is_local = IsLocalChannel(chan->chname);
3470 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3471 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3472 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3473 if (IsUserParting(member))
3475 SetUserParting(member);
3477 /* Send notification to channel */
3478 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3479 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3480 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3481 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3482 else if (MyUser(jbuf->jb_source))
3483 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3484 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3485 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3486 /* XXX: Shouldn't we send a PART here anyway? */
3487 /* to users on the channel? Why? From their POV, the user isn't on
3488 * the channel anymore anyway. We don't send to servers until below,
3489 * when we gang all the channel parts together. Note that this is
3490 * exactly the same logic, albeit somewhat more concise, as was in
3491 * the original m_part.c */
3493 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3494 is_local) /* got to remove user here */
3495 remove_user_from_channel(jbuf->jb_source, chan);
3497 /* Add user to channel */
3498 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3499 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3501 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3503 /* send notification to all servers */
3504 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3505 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3506 "%H %Tu", chan, chan->creationtime);
3508 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3509 /* Send the notification to the channel */
3510 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3512 /* send an op, too, if needed */
3513 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3514 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3515 chan, jbuf->jb_source);
3516 } else if (MyUser(jbuf->jb_source))
3517 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3520 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3521 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3522 return; /* don't send to remote */
3524 /* figure out if channel name will cause buffer to be overflowed */
3525 len = chan ? strlen(chan->chname) + 1 : 2;
3526 if (jbuf->jb_strlen + len > BUFSIZE)
3527 joinbuf_flush(jbuf);
3529 /* add channel to list of channels to send and update counts */
3530 jbuf->jb_channels[jbuf->jb_count++] = chan;
3531 jbuf->jb_strlen += len;
3533 /* if we've used up all slots, flush */
3534 if (jbuf->jb_count >= MAXJOINARGS)
3535 joinbuf_flush(jbuf);
3539 * Flush the channel list to remote servers
3542 joinbuf_flush(struct JoinBuf *jbuf)
3544 char chanlist[BUFSIZE];
3548 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3549 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3550 return 0; /* no joins to process */
3552 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3553 build_string(chanlist, &chanlist_i,
3554 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3555 i == 0 ? '\0' : ',');
3556 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3557 /* Remove user from channel */
3558 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3560 jbuf->jb_channels[i] = 0; /* mark slot empty */
3563 jbuf->jb_count = 0; /* reset base counters */
3564 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3565 STARTJOINLEN : STARTCREATELEN) +
3566 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3568 /* and send the appropriate command */
3569 switch (jbuf->jb_type) {
3570 case JOINBUF_TYPE_CREATE:
3571 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3572 "%s %Tu", chanlist, jbuf->jb_create);
3575 case JOINBUF_TYPE_PART:
3576 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3577 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3585 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3586 int IsInvited(struct Client* cptr, const void* chptr)
3590 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3591 if (lp->value.chptr == chptr)
3596 /* RevealDelayedJoin: sends a join for a hidden user */
3598 void RevealDelayedJoin(struct Membership *member) {
3599 ClearDelayedJoin(member);
3600 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3602 CheckDelayedJoins(member->channel);
3605 /* CheckDelayedJoins: checks and clear +d if necessary */
3607 void CheckDelayedJoins(struct Channel *chan) {
3608 struct Membership *memb2;
3610 if (chan->mode.mode & MODE_WASDELJOINS) {
3611 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3612 if (IsDelayedJoin(memb2))
3617 chan->mode.mode &= ~MODE_WASDELJOINS;
3618 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,