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 /** Allocate a new Ban structure.
104 * @param[in] banstr Ban mask to use.
105 * @return Newly allocated ban.
108 make_ban(const char *banstr)
113 free_bans = free_bans->next;
115 else if (!(ban = MyMalloc(sizeof(*ban))))
117 memset(ban, 0, sizeof(*ban));
119 DupString(ban->banstr, banstr);
123 /** Deallocate a ban structure.
124 * @param[in] ban Ban to deallocate.
127 free_ban(struct Ban *ban)
131 ban->next = free_bans;
135 /** return the struct Membership* that represents a client on a channel
136 * This function finds a struct Membership* which holds the state about
137 * a client on a specific channel. The code is smart enough to iterate
138 * over the channels a user is in, or the users in a channel to find the
139 * user depending on which is likely to be more efficient.
141 * @param chptr pointer to the channel struct
142 * @param cptr pointer to the client struct
144 * @returns pointer to the struct Membership representing this client on
145 * this channel. Returns NULL if the client is not on the channel.
146 * Returns NULL if the client is actually a server.
147 * @see find_channel_member()
149 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
151 struct Membership *m;
155 /* Servers don't have member links */
156 if (IsServer(cptr)||IsMe(cptr))
159 /* +k users are typically on a LOT of channels. So we iterate over who
160 * is in the channel. X/W are +k and are in about 5800 channels each.
161 * however there are typically no more than 1000 people in a channel
164 if (IsChannelService(cptr)) {
167 assert(m->channel == chptr);
173 /* Users on the other hand aren't allowed on more than 15 channels. 50%
174 * of users that are on channels are on 2 or less, 95% are on 7 or less,
175 * and 99% are on 10 or less.
178 m = (cli_user(cptr))->channel;
180 assert(m->user == cptr);
181 if (m->channel == chptr)
189 /** Find the client structure for a nick name (user)
190 * Find the client structure for a nick name (user)
191 * using history mechanism if necessary. If the client is not found, an error
192 * message (NO SUCH NICK) is generated. If the client was found
193 * through the history, chasing will be 1 and otherwise 0.
195 * This function was used extensively in the P09 days, and since we now have
196 * numeric nicks is no longer quite as important.
198 * @param sptr Pointer to the client that has requested the search
199 * @param user a string represeting the client to be found
200 * @param chasing a variable set to 0 if the user was found directly,
202 * @returns a pointer the client, or NULL if the client wasn't found.
204 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
206 struct Client* who = FindClient(user);
213 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
214 send_reply(sptr, ERR_NOSUCHNICK, user);
222 /** build up a hostmask
223 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
224 * as the parameters. If NULL, they become "*".
225 * @param namebuf the buffer to build the hostmask into. Must be at least
226 * NICKLEN+USERLEN+HOSTLEN+3 charactors long.
227 * @param nick The nickname
228 * @param name The ident
229 * @param host the hostname
231 * @see make_nick_user_ip()
233 static char *make_nick_user_host(char *namebuf, const char *nick,
234 const char *name, const char *host)
236 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
237 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
241 /** Create a hostmask using an IP address
242 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
243 * IP-number as the parameters. If NULL, they become "*".
245 * @param ipbuf Buffer at least NICKLEN+USERLEN+SOCKIPLEN+4 to hold the final
247 * @param nick The nickname (or NULL for *)
248 * @param name The ident (or NULL for *)
249 * @param ip The IP address
251 * @see make_nick_user_host()
253 #define NUI_BUFSIZE (NICKLEN + USERLEN + SOCKIPLEN + 4)
254 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
255 const struct irc_in_addr *ip)
257 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
261 /** Decrement the count of users, and free if empty.
262 * Subtract one user from channel i (and free channel * block, if channel
265 * @param chptr The channel to subtract one from.
267 * @returns true (1) if channel still has members.
268 * false (0) if the channel is now empty.
270 int sub1_from_channel(struct Channel* chptr)
272 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
274 assert(0 != chptr->members);
282 * Also channels without Apass set need to be kept alive,
283 * otherwise Bad Guys(tm) would be able to takeover
284 * existing channels too easily, and then set an Apass!
285 * However, if a channel without Apass becomes empty
286 * then we try to be kind to them and remove possible
289 chptr->mode.mode &= ~MODE_INVITEONLY;
290 chptr->mode.limit = 0;
292 * We do NOT reset a possible key or bans because when
293 * the 'channel owners' can't get in because of a key
294 * or ban then apparently there was a fight/takeover
295 * on the channel and we want them to contact IRC opers
296 * who then will educate them on the use of Apass/upass.
299 if (feature_bool(FEAT_OPLEVELS)) {
300 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
301 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
303 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
305 destruct_channel(chptr);
310 /** Destroy an empty channel
311 * This function destroys an empty channel, removing it from hashtables,
312 * and removing any resources it may have consumed.
314 * @param chptr The channel to destroy
316 * @returns 0 (success)
318 * FIXME: Change to return void, this function never fails.
320 int destruct_channel(struct Channel* chptr)
322 struct Ban *ban, *next;
324 assert(0 == chptr->members);
327 * Now, find all invite links from channel structure
329 while (chptr->invites)
330 del_invite(chptr->invites->value.cptr, chptr);
332 for (ban = chptr->banlist; ban; ban = next)
338 chptr->prev->next = chptr->next;
340 GlobalChannelList = chptr->next;
342 chptr->next->prev = chptr->prev;
344 --UserStats.channels;
346 * make sure that channel actually got removed from hash table
348 assert(chptr->hnext == chptr);
353 /** add a ban to a channel
355 * `cptr' must be the client adding the ban.
357 * If `change' is true then add `banid' to channel `chptr'.
358 * Returns 0 if the ban was added.
359 * Returns -2 if the ban already existed and was marked BAN_BURST_WIPEOUT.
360 * Return -1 otherwise.
362 * Those bans that overlapped with `banid' are flagged with BAN_OVERLAPPED
363 * when `change' is false, otherwise they will be removed from the banlist.
364 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
365 * respectively will return these bans until NULL is returned.
367 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
368 * is reset (unless a non-zero value is returned, in which case the
369 * BAN_OVERLAPPED flag might not have been reset!).
372 * @param cptr Client adding the ban
373 * @param chptr Channel to add the ban to
374 * @param banid The actual ban.
375 * @param change True if adding a ban, false if old bans should just be flagged
376 * @param firsttime Reset the next_overlapped_ban() iteration.
378 * 0 if the ban was added
379 * -2 if the ban already existed and was marked BAN_BURST_WIPEOUT
382 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
383 int change, int firsttime)
388 int removed_bans = 0;
389 int len = strlen(banid);
394 assert(0 == prev_ban);
395 assert(0 == removed_bans_list);
399 for (banp = &chptr->banlist; *banp;)
401 len += strlen((*banp)->banstr);
403 if (((*banp)->flags & BAN_BURST_WIPEOUT))
405 if (!strcmp((*banp)->banstr, banid))
407 (*banp)->flags &= ~BAN_BURST_WIPEOUT;
411 else if (!mmatch((*banp)->banstr, banid))
413 if (!mmatch(banid, (*banp)->banstr))
415 struct Ban *tmp = *banp;
421 len -= strlen(tmp->banstr);
424 /* These will be sent to the user later as -b */
425 tmp->next = removed_bans_list;
426 removed_bans_list = tmp;
429 else if (!(tmp->flags & BAN_BURST_WIPEOUT))
431 tmp->flags |= BAN_OVERLAPPED;
442 (*banp)->flags &= ~BAN_OVERLAPPED;
443 banp = &(*banp)->next;
446 if (MyUser(cptr) && !removed_bans &&
447 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
448 (cnt >= feature_int(FEAT_MAXBANS))))
450 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
456 struct Membership* member;
457 ban = make_ban(banid);
458 ban->next = chptr->banlist;
460 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
461 DupString(ban->who, cli_name(&me));
463 DupString(ban->who, cli_name(cptr));
464 assert(0 != ban->who);
466 ban->when = TStime();
467 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
468 ban->flags |= BAN_IPMASK;
469 chptr->banlist = ban;
472 * Erase ban-valid-bit
474 for (member = chptr->members; member; member = member->next_member)
475 ClearBanValid(member); /* `ban' == channel member ! */
480 /** return the next ban that is removed
481 * @returns the next ban that is removed because of overlapping
483 struct Ban *next_removed_overlapped_ban(void)
490 if ((prev_ban = removed_bans_list))
491 removed_bans_list = removed_bans_list->next;
495 /** returns Membership * if a person is joined and not a zombie
497 * @param chptr Channel
498 * @returns pointer to the client's struct Membership * on the channel if that
499 * user is a full member of the channel, or NULL otherwise.
501 * @see find_member_link()
503 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
505 struct Membership* member;
508 member = find_member_link(chptr, cptr);
509 return (member && !IsZombie(member)) ? member : 0;
512 /** return true if banned else false.
514 * This function returns true if the user is banned on the said channel.
515 * This function will check the ban cache if applicable, otherwise will
516 * do the comparisons and cache the result.
518 * @param cptr The client to test
519 * @param chptr The channel
520 * @param member The Membership * of this client on this channel
521 * (may be NULL if the member is not on the channel).
523 static int is_banned(struct Client *cptr, struct Channel *chptr,
524 struct Membership* member)
527 char tmphost[HOSTLEN + 1];
528 char nu_host[NUH_BUFSIZE];
529 char nu_realhost[NUH_BUFSIZE];
530 char nu_ip[NUI_BUFSIZE];
538 if (member && IsBanValid(member))
539 return IsBanned(member);
541 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
542 (cli_user(cptr))->host);
545 if (HasHiddenHost(cptr))
547 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
548 (cli_user(cptr))->username,
549 cli_user(cptr)->realhost);
553 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
554 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
555 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
556 cli_user(cptr)->username,
561 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
562 if ((tmp->flags & BAN_IPMASK)) {
564 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
565 (cli_user(cptr))->username, &cli_ip(cptr));
566 if (match(tmp->banstr, ip_s) == 0)
569 if (match(tmp->banstr, s) == 0)
571 else if (sr && match(tmp->banstr, sr) == 0)
587 return (tmp != NULL);
590 /** add a user to a channel.
591 * adds a user to a channel by adding another link to the channels member
594 * @param chptr The channel to add to.
595 * @param who The user to add.
596 * @param flags The flags the user gets initially.
597 * @param oplevel The oplevel the user starts with.
599 void add_user_to_channel(struct Channel* chptr, struct Client* who,
600 unsigned int flags, int oplevel)
607 struct Membership* member = membershipFreeList;
609 membershipFreeList = member->next_member;
611 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
612 ++membershipAllocCount;
617 member->channel = chptr;
618 member->status = flags;
619 member->oplevel = oplevel;
621 member->next_member = chptr->members;
622 if (member->next_member)
623 member->next_member->prev_member = member;
624 member->prev_member = 0;
625 chptr->members = member;
627 member->next_channel = (cli_user(who))->channel;
628 if (member->next_channel)
629 member->next_channel->prev_channel = member;
630 member->prev_channel = 0;
631 (cli_user(who))->channel = member;
633 if (chptr->destruct_event)
634 remove_destruct_event(chptr);
636 ++((cli_user(who))->joined);
640 /** Remove a person from a channel, given their Membership*
642 * @param member A member of a channel.
644 * @returns true if there are more people in the channel.
646 static int remove_member_from_channel(struct Membership* member)
648 struct Channel* chptr;
650 chptr = member->channel;
652 * unlink channel member list
654 if (member->next_member)
655 member->next_member->prev_member = member->prev_member;
656 if (member->prev_member)
657 member->prev_member->next_member = member->next_member;
659 member->channel->members = member->next_member;
662 * If this is the last delayed-join user, may have to clear WASDELJOINS.
664 if (IsDelayedJoin(member))
665 CheckDelayedJoins(chptr);
668 * unlink client channel list
670 if (member->next_channel)
671 member->next_channel->prev_channel = member->prev_channel;
672 if (member->prev_channel)
673 member->prev_channel->next_channel = member->next_channel;
675 (cli_user(member->user))->channel = member->next_channel;
677 --(cli_user(member->user))->joined;
679 member->next_member = membershipFreeList;
680 membershipFreeList = member;
682 return sub1_from_channel(chptr);
685 /** Check if all the remaining members on the channel are zombies
687 * @returns False if the channel has any non zombie members, True otherwise.
690 static int channel_all_zombies(struct Channel* chptr)
692 struct Membership* member;
694 for (member = chptr->members; member; member = member->next_member) {
695 if (!IsZombie(member))
702 /** Remove a user from a channel
703 * This is the generic entry point for removing a user from a channel, this
704 * function will remove the client from the channel, and destory the channel
705 * if there are no more normal users left.
707 * @param cptr The client
708 * @param chptr The channel
710 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
713 struct Membership* member;
716 if ((member = find_member_link(chptr, cptr))) {
717 if (remove_member_from_channel(member)) {
718 if (channel_all_zombies(chptr)) {
720 * XXX - this looks dangerous but isn't if we got the referential
721 * integrity right for channels
723 while (remove_member_from_channel(chptr->members))
730 /** Remove a user from all channels they are on.
732 * This function removes a user from all channels they are on.
734 * @param cptr The client to remove.
736 void remove_user_from_all_channels(struct Client* cptr)
738 struct Membership* chan;
740 assert(0 != cli_user(cptr));
742 while ((chan = (cli_user(cptr))->channel))
743 remove_user_from_channel(cptr, chan->channel);
746 /** Check if this user is a legitimate chanop
748 * @param cptr Client to check
749 * @param chptr Channel to check
751 * @returns True if the user is a chanop (And not a zombie), False otherwise.
754 int is_chan_op(struct Client *cptr, struct Channel *chptr)
756 struct Membership* member;
758 if ((member = find_member_link(chptr, cptr)))
759 return (!IsZombie(member) && IsChanOp(member));
764 /** Check if a user is a Zombie on a specific channel.
766 * @param cptr The client to check.
767 * @param chptr The channel to check.
769 * @returns True if the client (cptr) is a zombie on the channel (chptr),
774 int is_zombie(struct Client *cptr, struct Channel *chptr)
776 struct Membership* member;
780 if ((member = find_member_link(chptr, cptr)))
781 return IsZombie(member);
785 /** Returns if a user has voice on a channel.
787 * @param cptr The client
788 * @param chptr The channel
790 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
793 int has_voice(struct Client* cptr, struct Channel* chptr)
795 struct Membership* member;
798 if ((member = find_member_link(chptr, cptr)))
799 return (!IsZombie(member) && HasVoice(member));
804 /** Can this member send to a channel
806 * A user can speak on a channel iff:
808 * <li> They didn't use the Apass to gain ops.
809 * <li> They are op'd or voice'd.
810 * <li> You aren't banned.
811 * <li> The channel isn't +m
812 * <li> The channel isn't +n or you are on the channel.
815 * This function will optionally reveal a user on a delayed join channel if
816 * they are allowed to send to the channel.
818 * @param member The membership of the user
819 * @param reveal If true, the user will be "revealed" on a delayed
822 * @returns True if the client can speak on the channel.
824 int member_can_send_to_channel(struct Membership* member, int reveal)
828 /* Discourage using the Apass to get op. They should use the upass. */
829 if (IsChannelManager(member) && *member->channel->mode.upass)
832 if (IsVoicedOrOpped(member))
835 * If it's moderated, and you aren't a priviledged user, you can't
838 if (member->channel->mode.mode & MODE_MODERATED)
841 * If you're banned then you can't speak either.
842 * but because of the amount of CPU time that is_banned chews
843 * we only check it for our clients.
845 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
848 if (IsDelayedJoin(member) && reveal)
849 RevealDelayedJoin(member);
854 /** Check if a client can send to a channel.
856 * Has the added check over member_can_send_to_channel() of servers can
859 * @param cptr The client to check
860 * @param chptr The channel to check
861 * @param reveal If the user should be revealed (see
862 * member_can_send_to_channel())
864 * @returns true if the client is allowed to speak on the channel, false
867 * @see member_can_send_to_channel()
869 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
871 struct Membership *member;
874 * Servers can always speak on channels.
879 member = find_channel_member(cptr, chptr);
882 * You can't speak if you're off channel, and it is +n (no external messages)
886 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
887 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
890 return !is_banned(cptr, chptr, NULL);
892 return member_can_send_to_channel(member, reveal);
895 /** Returns the name of a channel that prevents the user from changing nick.
896 * if a member and not (opped or voiced) and (banned or moderated), return
897 * the name of the first channel banned on.
899 * @param cptr The client
901 * @returns the name of the first channel banned on, or NULL if the user
904 const char* find_no_nickchange_channel(struct Client* cptr)
907 struct Membership* member;
908 for (member = (cli_user(cptr))->channel; member;
909 member = member->next_channel) {
910 if (!IsVoicedOrOpped(member) &&
911 (is_banned(cptr, member->channel, member) ||
912 (member->channel->mode.mode & MODE_MODERATED)))
913 return member->channel->chname;
920 /** Fill mbuf/pbuf with modes from chptr
921 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
922 * with the parameters in pbuf as visible by cptr.
924 * This function will hide keys from non-op'd, non-server clients.
926 * @param cptr The client to generate the mode for.
927 * @param mbuf The buffer to write the modes into.
928 * @param pbuf The buffer to write the mode parameters into.
929 * @param buflen The length of the buffers.
930 * @param chptr The channel to get the modes from.
931 * @param member The membership of this client on this channel (or NULL
932 * if this client isn't on this channel)
935 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
936 struct Channel *chptr, struct Membership *member)
938 int previous_parameter = 0;
945 if (chptr->mode.mode & MODE_SECRET)
947 else if (chptr->mode.mode & MODE_PRIVATE)
949 if (chptr->mode.mode & MODE_MODERATED)
951 if (chptr->mode.mode & MODE_TOPICLIMIT)
953 if (chptr->mode.mode & MODE_INVITEONLY)
955 if (chptr->mode.mode & MODE_NOPRIVMSGS)
957 if (chptr->mode.mode & MODE_REGONLY)
959 if (chptr->mode.mode & MODE_DELJOINS)
961 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
963 if (chptr->mode.limit) {
965 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
966 previous_parameter = 1;
969 if (*chptr->mode.key) {
971 if (previous_parameter)
973 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
974 strcat(pbuf, chptr->mode.key);
977 previous_parameter = 1;
979 if (*chptr->mode.apass) {
981 if (previous_parameter)
983 if (IsServer(cptr)) {
984 strcat(pbuf, chptr->mode.apass);
987 previous_parameter = 1;
989 if (*chptr->mode.upass) {
991 if (previous_parameter)
993 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
994 strcat(pbuf, chptr->mode.upass);
1001 /** Compare two members oplevel
1003 * @param mp1 Pointer to a pointer to a membership
1004 * @param mp2 Pointer to a pointer to a membership
1006 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
1008 * Used for qsort(3).
1010 int compare_member_oplevel(const void *mp1, const void *mp2)
1012 struct Membership const* member1 = *(struct Membership const**)mp1;
1013 struct Membership const* member2 = *(struct Membership const**)mp2;
1014 if (member1->oplevel == member2->oplevel)
1016 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1019 /* send "cptr" a full list of the modes for channel chptr.
1021 * Sends a BURST line to cptr, bursting all the modes for the channel.
1023 * @param cptr Client pointer
1024 * @param chptr Channel pointer
1026 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1028 /* The order in which modes are generated is now mandatory */
1029 static unsigned int current_flags[4] =
1030 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1036 struct Membership* member;
1038 char modebuf[MODEBUFLEN];
1039 char parabuf[MODEBUFLEN];
1041 int number_of_ops = 0;
1042 int opped_members_index = 0;
1043 struct Membership** opped_members = NULL;
1044 int last_oplevel = 0;
1045 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1050 if (IsLocalChannel(chptr->chname))
1053 member = chptr->members;
1054 lp2 = chptr->banlist;
1056 *modebuf = *parabuf = '\0';
1057 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1059 for (first = 1; full; first = 0) /* Loop for multiple messages */
1061 full = 0; /* Assume by default we get it
1062 all in one message */
1064 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1065 /* is there any better way we can do this? */
1066 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1067 chptr->creationtime);
1069 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1072 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1073 msgq_append(&me, mb, " %s", modebuf);
1076 msgq_append(&me, mb, " %s", parabuf);
1080 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1082 * First find all opless members.
1083 * Run 2 times over all members, to group the members with
1084 * and without voice together.
1085 * Then run 2 times over all opped members (which are ordered
1086 * by op-level) to also group voice and non-voice together.
1088 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1092 if (flag_cnt < 2 && IsChanOp(member))
1095 * The first loop (to find all non-voice/op), we count the ops.
1096 * The second loop (to find all voiced non-ops), store the ops
1097 * in a dynamic array.
1102 opped_members[opped_members_index++] = member;
1104 /* Only handle the members with the flags that we are interested in. */
1105 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1107 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1108 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1110 full = 1; /* Make sure we continue after
1111 sending it so far */
1112 /* Ensure the new BURST line contains the current
1113 * ":mode", except when there is no mode yet. */
1114 new_mode = (flag_cnt > 0) ? 1 : 0;
1115 break; /* Do not add this member to this message */
1117 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1118 first = 0; /* From now on, use commas to add new nicks */
1121 * Do we have a nick with a new mode ?
1122 * Or are we starting a new BURST line?
1124 if (new_mode || !feat_oplevels)
1127 * This means we are at the _first_ member that has only
1128 * voice, or the first member that has only ops, or the
1129 * first member that has voice and ops (so we get here
1130 * at most three times, plus once for every start of
1131 * a continued BURST line where only these modes is current.
1132 * In the two cases where the current mode includes ops,
1133 * we need to add the _absolute_ value of the oplevel to the mode.
1135 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1138 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1140 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1142 /* append the absolute value of the oplevel */
1144 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1149 msgq_append(&me, mb, tbuf);
1152 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1155 * This can't be the first member of a (continued) BURST
1156 * message because then either flag_cnt == 0 or new_mode == 1
1157 * Now we need to append the incremental value of the oplevel.
1159 char tbuf[2 + MAXOPLEVELDIGITS];
1160 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1161 last_oplevel = member->oplevel;
1162 msgq_append(&me, mb, tbuf);
1165 /* Go to the next `member'. */
1167 member = member->next_member;
1169 member = opped_members[++opped_members_index];
1174 /* Point `member' at the start of the list again. */
1177 member = chptr->members;
1178 /* Now, after one loop, we know the number of ops and can
1179 * allocate the dynamic array with pointer to the ops. */
1180 opped_members = (struct Membership**)
1181 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1182 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1186 /* At the end of the second loop, sort the opped members with
1187 * increasing op-level, so that we will output them in the
1188 * correct order (and all op-level increments stay positive) */
1190 qsort(opped_members, number_of_ops,
1191 sizeof(struct Membership*), compare_member_oplevel);
1192 /* The third and fourth loop run only over the opped members. */
1193 member = opped_members[(opped_members_index = 0)];
1196 } /* loop over 0,+v,+o,+ov */
1200 /* Attach all bans, space seperated " :%ban ban ..." */
1201 for (first = 2; lp2; lp2 = lp2->next)
1203 len = strlen(lp2->banstr);
1204 if (msgq_bufleft(mb) < len + 1 + first)
1205 /* The +1 stands for the added ' '.
1206 * The +first stands for the added ":%".
1212 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1218 send_buffer(cptr, mb, 0); /* Send this message */
1220 } /* Continue when there was something
1221 that didn't fit (full==1) */
1223 MyFree(opped_members);
1224 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1225 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1226 chptr->creationtime, chptr->topic_time, chptr->topic);
1229 /** Canonify a mask.
1232 * @author Carlo Wood (Run),
1235 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1236 * When the user name or host name are too long (USERLEN and HOSTLEN
1237 * respectively) then they are cut off at the start with a '*'.
1239 * The following transformations are made:
1241 * 1) xxx -> nick!*@*
1242 * 2) xxx.xxx -> *!*\@host
1243 * 3) xxx\!yyy -> nick!user\@*
1244 * 4) xxx\@yyy -> *!user\@host
1245 * 5) xxx!yyy\@zzz -> nick!user\@host
1247 * @param mask The uncanonified mask.
1248 * @returns The updated mask in a static buffer.
1250 char *pretty_mask(char *mask)
1252 static char star[2] = { '*', 0 };
1253 static char retmask[NUH_BUFSIZE];
1254 char *last_dot = NULL;
1257 /* Case 1: default */
1262 /* Do a _single_ pass through the characters of the mask: */
1263 for (ptr = mask; *ptr; ++ptr)
1267 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1271 else if (*ptr == '@')
1273 /* Case 4: Found last '@' (without finding a '!' yet) */
1278 else if (*ptr == '.')
1280 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1290 /* Case 4 or 5: Found last '@' */
1296 if (user == star && last_dot)
1306 char *nick_end = (user != star) ? user - 1 : ptr;
1307 if (nick_end - nick > NICKLEN)
1313 char *user_end = (host != star) ? host - 1 : ptr;
1314 if (user_end - user > USERLEN)
1316 user = user_end - USERLEN;
1321 if (host != star && ptr - host > HOSTLEN)
1323 host = ptr - HOSTLEN;
1326 return make_nick_user_host(retmask, nick, user, host);
1329 /** send a banlist to a client for a channel
1331 * @param cptr Client to send the banlist to.
1332 * @param chptr Channel whose banlist to send.
1334 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1341 for (lp = chptr->banlist; lp; lp = lp->next)
1342 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
1345 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1348 /** Check a key against a keyring.
1349 * We are now treating the key part of /join channellist key as a key
1350 * ring; that is, we try one key against the actual channel key, and if that
1351 * doesn't work, we try the next one, and so on. -Kev -Texaco
1352 * Returns: 0 on match, 1 otherwise
1353 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1355 * @param key Key to check
1356 * @param keyring Comma seperated list of keys
1358 * @returns True if the key was found and matches, false otherwise.
1360 static int compall(char *key, char *keyring)
1365 p1 = key; /* point to the key... */
1366 while (*p1 && *p1 == *keyring)
1367 { /* step through the key and ring until they
1373 if (!*p1 && (!*keyring || *keyring == ','))
1374 /* ok, if we're at the end of the and also at the end of one of the keys
1375 in the keyring, we have a match */
1378 if (!*keyring) /* if we're at the end of the key ring, there
1379 weren't any matches, so we return 1 */
1382 /* Not at the end of the key ring, so step
1383 through to the next key in the ring: */
1384 while (*keyring && *(keyring++) != ',');
1386 goto top; /* and check it against the key */
1389 /** Returns if a user can join a channel with a specific key.
1391 * @param sptr The client trying to join
1392 * @param chptr The channel to join
1393 * @param key The key to use
1395 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1396 * if the oper used the magic key, 0 if no error occured.
1398 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1400 int overrideJoin = 0;
1403 * Now a banned user CAN join if invited -- Nemesi
1404 * Now a user CAN escape channel limit if invited -- bfriendly
1405 * Now a user CAN escape anything if invited -- Isomer
1408 if (IsInvited(sptr, chptr))
1411 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1412 a HACK(4) notice will be sent if he would not have been supposed
1413 to join normally. */
1414 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1415 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1416 compall("OVERRIDE",key) == 0)
1417 overrideJoin = MAGIC_OPER_OVERRIDE;
1419 if (chptr->mode.mode & MODE_INVITEONLY)
1420 return overrideJoin + ERR_INVITEONLYCHAN;
1422 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1423 return overrideJoin + ERR_CHANNELISFULL;
1425 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1426 return overrideJoin + ERR_NEEDREGGEDNICK;
1428 if (is_banned(sptr, chptr, NULL))
1429 return overrideJoin + ERR_BANNEDFROMCHAN;
1432 * now using compall (above) to test against a whole key ring -Kev
1434 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1435 return overrideJoin + ERR_BADCHANNELKEY;
1438 return ERR_DONTCHEAT;
1443 /** Remove bells and commas from channel name
1445 * @param cn Channel name to clean, modified in place.
1447 void clean_channelname(char *cn)
1451 for (i = 0; cn[i]; i++) {
1452 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1456 if (IsChannelLower(cn[i])) {
1457 cn[i] = ToLower(cn[i]);
1463 if ((unsigned char)(cn[i]) == 0xd0)
1464 cn[i] = (char) 0xf0;
1470 /** Get a channel block, creating if necessary.
1471 * Get Channel block for chname (and allocate a new channel
1472 * block, if it didn't exists before).
1474 * @param cptr Client joining the channel.
1475 * @param chname The name of the channel to join.
1476 * @param flag set to CGT_CREATE to create the channel if it doesn't
1479 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1480 * wasn't specified or a pointer to the channel structure
1482 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1484 struct Channel *chptr;
1487 if (EmptyString(chname))
1490 len = strlen(chname);
1491 if (MyUser(cptr) && len > CHANNELLEN)
1494 *(chname + CHANNELLEN) = '\0';
1496 if ((chptr = FindChannel(chname)))
1498 if (flag == CGT_CREATE)
1500 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1502 ++UserStats.channels;
1503 memset(chptr, 0, sizeof(struct Channel));
1504 strcpy(chptr->chname, chname);
1505 if (GlobalChannelList)
1506 GlobalChannelList->prev = chptr;
1508 chptr->next = GlobalChannelList;
1509 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1510 GlobalChannelList = chptr;
1516 /** invite a user to a channel.
1518 * Adds an invite for a user to a channel. Limits the number of invites
1519 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1521 * @param cptr The client to be invited.
1522 * @param chptr The channel to be invited to.
1524 void add_invite(struct Client *cptr, struct Channel *chptr)
1526 struct SLink *inv, **tmp;
1528 del_invite(cptr, chptr);
1530 * Delete last link in chain if the list is max length
1532 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1533 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1534 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1536 * Add client to channel invite list
1539 inv->value.cptr = cptr;
1540 inv->next = chptr->invites;
1541 chptr->invites = inv;
1543 * Add channel to the end of the client invite list
1545 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1547 inv->value.chptr = chptr;
1550 (cli_user(cptr))->invites++;
1553 /** Delete an invite
1554 * Delete Invite block from channel invite list and client invite list
1556 * @param cptr Client pointer
1557 * @param chptr Channel pointer
1559 void del_invite(struct Client *cptr, struct Channel *chptr)
1561 struct SLink **inv, *tmp;
1563 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1564 if (tmp->value.cptr == cptr)
1569 (cli_user(cptr))->invites--;
1573 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1574 if (tmp->value.chptr == chptr)
1583 /** @page zombie Explaination of Zombies
1591 * X --a--> A --b--> B --d--> D
1596 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1597 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1599 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1600 * Remove the user immediately when no users are left on the channel.
1601 * b) On server B : remove the user (who/lp) from the channel, send a
1602 * PART upstream (to A) and pass on the KICK.
1603 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1604 * channel, and pass on the KICK.
1605 * d) On server D : remove the user (who/lp) from the channel, and pass on
1609 * - Setting the ZOMBIE flag never hurts, we either remove the
1610 * client after that or we don't.
1611 * - The KICK message was already passed on, as should be in all cases.
1612 * - `who' is removed in all cases except case a) when users are left.
1613 * - A PART is only sent upstream in case b).
1619 * 1 --- 2 --- 3 --- 4 --- 5
1624 * We also need to turn 'who' into a zombie on servers 1 and 6,
1625 * because a KICK from 'who' (kicking someone else in that direction)
1626 * can arrive there afterwards - which should not be bounced itself.
1627 * Therefore case a) also applies for servers 1 and 6.
1632 /** Turn a user on a channel into a zombie
1633 * This function turns a user into a zombie (see \ref zombie)
1635 * @param member The structure representing this user on this channel.
1636 * @param who The client that is being kicked.
1637 * @param cptr The connection the kick came from.
1638 * @param sptr The client that is doing the kicking.
1639 * @param chptr The channel the user is being kicked from.
1641 void make_zombie(struct Membership* member, struct Client* who,
1642 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1644 assert(0 != member);
1649 /* Default for case a): */
1652 /* Case b) or c) ?: */
1653 if (MyUser(who)) /* server 4 */
1655 if (IsServer(cptr)) /* Case b) ? */
1656 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1657 remove_user_from_channel(who, chptr);
1660 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1662 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1663 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1664 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1666 remove_user_from_channel(who, chptr);
1671 /* Case a) (servers 1, 2, 3 and 6) */
1672 if (channel_all_zombies(chptr))
1673 remove_user_from_channel(who, chptr);
1675 /* XXX Can't actually call Debug here; if the channel is all zombies,
1676 * chptr will no longer exist when we get here.
1677 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1681 /** returns the number of zombies on a channel
1682 * @param chptr Channel to count zombies in.
1684 * @returns The number of zombies on the channel.
1686 int number_of_zombies(struct Channel *chptr)
1688 struct Membership* member;
1692 for (member = chptr->members; member; member = member->next_member) {
1693 if (IsZombie(member))
1699 /** Concatenate some strings together.
1700 * This helper function builds an argument string in strptr, consisting
1701 * of the original string, a space, and str1 and str2 concatenated (if,
1702 * of course, str2 is not NULL)
1704 * @param strptr The buffer to concatenate into
1705 * @param strptr_i modified offset to the position to modify
1706 * @param str1 The string to contatenate from.
1707 * @param str2 The second string to contatenate from.
1708 * @param c Charactor to seperate the string from str1 and str2.
1711 build_string(char *strptr, int *strptr_i, const char *str1,
1712 const char *str2, char c)
1715 strptr[(*strptr_i)++] = c;
1718 strptr[(*strptr_i)++] = *(str1++);
1722 strptr[(*strptr_i)++] = *(str2++);
1724 strptr[(*strptr_i)] = '\0';
1727 /** Flush out the modes
1728 * This is the workhorse of our ModeBuf suite; this actually generates the
1729 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1731 * @param mbuf The mode buffer to flush
1732 * @param all If true, flush all modes, otherwise leave partial modes in the
1738 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1740 /* we only need the flags that don't take args right now */
1741 static int flags[] = {
1742 /* MODE_CHANOP, 'o', */
1743 /* MODE_VOICE, 'v', */
1746 MODE_MODERATED, 'm',
1747 MODE_TOPICLIMIT, 't',
1748 MODE_INVITEONLY, 'i',
1749 MODE_NOPRIVMSGS, 'n',
1752 MODE_WASDELJOINS, 'd',
1753 /* MODE_KEY, 'k', */
1754 /* MODE_BAN, 'b', */
1756 /* MODE_APASS, 'A', */
1757 /* MODE_UPASS, 'U', */
1763 struct Client *app_source; /* where the MODE appears to come from */
1765 char addbuf[20]; /* accumulates +psmtin, etc. */
1767 char rembuf[20]; /* accumulates -psmtin, etc. */
1769 char *bufptr; /* we make use of indirection to simplify the code */
1772 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1774 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1776 char *strptr; /* more indirection to simplify the code */
1779 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1782 char limitbuf[20]; /* convert limits to strings */
1784 unsigned int limitdel = MODE_LIMIT;
1788 /* If the ModeBuf is empty, we have nothing to do */
1789 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1792 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1794 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1797 app_source = mbuf->mb_source;
1800 * Account for user we're bouncing; we have to get it in on the first
1801 * bounced MODE, or we could have problems
1803 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1804 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1806 /* Calculate the simple flags */
1807 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1808 if (*flag_p & mbuf->mb_add)
1809 addbuf[addbuf_i++] = flag_p[1];
1810 else if (*flag_p & mbuf->mb_rem)
1811 rembuf[rembuf_i++] = flag_p[1];
1814 /* Now go through the modes with arguments... */
1815 for (i = 0; i < mbuf->mb_count; i++) {
1816 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1818 bufptr_i = &addbuf_i;
1821 bufptr_i = &rembuf_i;
1824 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1825 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1827 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1828 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1830 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1831 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1833 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1834 tmp = strlen(MB_STRING(mbuf, i));
1836 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1837 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1840 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1852 bufptr[(*bufptr_i)++] = mode_char;
1853 totalbuflen -= tmp + 1;
1855 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1856 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1857 strlen(MB_STRING(mbuf, i)));
1859 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1860 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1862 bufptr[(*bufptr_i)++] = 'k';
1863 totalbuflen -= tmp + 1;
1865 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1866 /* if it's a limit, we also format the number */
1867 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1869 tmp = strlen(limitbuf);
1871 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1872 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1874 bufptr[(*bufptr_i)++] = 'l';
1875 totalbuflen -= tmp + 1;
1880 /* terminate the mode strings */
1881 addbuf[addbuf_i] = '\0';
1882 rembuf[rembuf_i] = '\0';
1884 /* If we're building a user visible MODE or HACK... */
1885 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1886 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1887 MODEBUF_DEST_LOG)) {
1888 /* Set up the parameter strings */
1894 for (i = 0; i < mbuf->mb_count; i++) {
1895 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1898 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1900 strptr_i = &addstr_i;
1903 strptr_i = &remstr_i;
1906 /* deal with clients... */
1907 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1908 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1910 /* deal with bans... */
1911 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1912 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1914 /* deal with keys... */
1915 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1916 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1917 "*" : MB_STRING(mbuf, i), 0, ' ');
1919 /* deal with invisible passwords */
1920 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1921 build_string(strptr, strptr_i, "*", 0, ' ');
1924 * deal with limit; note we cannot include the limit parameter if we're
1927 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1928 (MODE_ADD | MODE_LIMIT))
1929 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1932 /* send the messages off to their destination */
1933 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1934 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1936 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1937 mbuf->mb_source : app_source),
1938 mbuf->mb_channel->chname,
1939 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1940 addbuf, remstr, addstr,
1941 mbuf->mb_channel->creationtime);
1943 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1944 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1945 "%s%s%s%s%s%s [%Tu]",
1946 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1947 mbuf->mb_source : app_source),
1948 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1949 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1950 mbuf->mb_channel->creationtime);
1952 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1953 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1955 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1956 mbuf->mb_source : app_source),
1957 mbuf->mb_channel->chname,
1958 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1959 addbuf, remstr, addstr,
1960 mbuf->mb_channel->creationtime);
1962 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1963 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1964 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1965 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1966 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1968 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1969 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1970 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1971 rembuf_i ? "-" : "", rembuf,
1972 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1975 /* Now are we supposed to propagate to other servers? */
1976 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1977 /* set up parameter string */
1984 * limit is supressed if we're removing it; we have to figure out which
1985 * direction is the direction for it to be removed, though...
1987 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1989 for (i = 0; i < mbuf->mb_count; i++) {
1990 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1993 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1995 strptr_i = &addstr_i;
1998 strptr_i = &remstr_i;
2001 /* deal with modes that take clients */
2002 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2003 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2005 /* deal with modes that take strings */
2006 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
2007 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2010 * deal with the limit. Logic here is complicated; if HACK2 is set,
2011 * we're bouncing the mode, so sense is reversed, and we have to
2012 * include the original limit if it looks like it's being removed
2014 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2015 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2018 /* we were told to deop the source */
2019 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2020 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2021 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2022 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2024 /* mark that we've done this, so we don't do it again */
2025 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2028 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2029 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2030 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2031 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2032 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2033 addbuf, remstr, addstr);
2034 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2036 * If HACK2 was set, we're bouncing; we send the MODE back to the
2037 * connection we got it from with the senses reversed and a TS of 0;
2040 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2041 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2042 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2043 mbuf->mb_channel->creationtime);
2046 * We're propagating a normal MODE command to the rest of the network;
2047 * we send the actual channel TS unless this is a HACK3 or a HACK4
2049 if (IsServer(mbuf->mb_source))
2050 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2051 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2052 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2053 addbuf, remstr, addstr,
2054 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2055 mbuf->mb_channel->creationtime);
2057 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2058 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2059 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2060 addbuf, remstr, addstr);
2064 /* We've drained the ModeBuf... */
2069 /* reinitialize the mode-with-arg slots */
2070 for (i = 0; i < MAXMODEPARAMS; i++) {
2071 /* If we saved any, pack them down */
2072 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2073 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2074 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2076 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2078 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2079 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2081 MB_TYPE(mbuf, i) = 0;
2082 MB_UINT(mbuf, i) = 0;
2085 /* If we're supposed to flush it all, do so--all hail tail recursion */
2086 if (all && mbuf->mb_count)
2087 return modebuf_flush_int(mbuf, 1);
2092 /** Initialise a modebuf
2093 * This routine just initializes a ModeBuf structure with the information
2094 * needed and the options given.
2096 * @param mbuf The mode buffer to initialise.
2097 * @param source The client that is performing the mode.
2099 * @param chan The channel that the mode is being performed upon.
2103 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2104 struct Client *connect, struct Channel *chan, unsigned int dest)
2109 assert(0 != source);
2113 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2117 mbuf->mb_source = source;
2118 mbuf->mb_connect = connect;
2119 mbuf->mb_channel = chan;
2120 mbuf->mb_dest = dest;
2123 /* clear each mode-with-parameter slot */
2124 for (i = 0; i < MAXMODEPARAMS; i++) {
2125 MB_TYPE(mbuf, i) = 0;
2126 MB_UINT(mbuf, i) = 0;
2130 /** Append a new mode to a modebuf
2131 * This routine simply adds modes to be added or deleted; do a binary OR
2132 * with either MODE_ADD or MODE_DEL
2134 * @param mbuf Mode buffer
2135 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2138 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2141 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2143 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2144 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2145 MODE_DELJOINS | MODE_WASDELJOINS);
2147 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2150 if (mode & MODE_ADD) {
2151 mbuf->mb_rem &= ~mode;
2152 mbuf->mb_add |= mode;
2154 mbuf->mb_add &= ~mode;
2155 mbuf->mb_rem |= mode;
2159 /** Append a mode that takes an int argument to the modebuf
2161 * This routine adds a mode to be added or deleted that takes a unsigned
2162 * int parameter; mode may *only* be the relevant mode flag ORed with one
2163 * of MODE_ADD or MODE_DEL
2165 * @param mbuf The mode buffer to append to.
2166 * @param mode The mode to append.
2167 * @param uint The argument to the mode.
2170 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2173 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2175 if (mode == (MODE_LIMIT | MODE_DEL)) {
2176 mbuf->mb_rem |= mode;
2179 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2180 MB_UINT(mbuf, mbuf->mb_count) = uint;
2182 /* when we've reached the maximal count, flush the buffer */
2183 if (++mbuf->mb_count >=
2184 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2185 modebuf_flush_int(mbuf, 0);
2188 /** append a string mode
2189 * This routine adds a mode to be added or deleted that takes a string
2190 * parameter; mode may *only* be the relevant mode flag ORed with one of
2191 * MODE_ADD or MODE_DEL
2193 * @param mbuf The mode buffer to append to.
2194 * @param mode The mode to append.
2195 * @param string The string parameter to append.
2196 * @param free If the string should be free'd later.
2199 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2203 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2205 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2206 MB_STRING(mbuf, mbuf->mb_count) = string;
2208 /* when we've reached the maximal count, flush the buffer */
2209 if (++mbuf->mb_count >=
2210 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2211 modebuf_flush_int(mbuf, 0);
2214 /** Append a mode on a client to a modebuf.
2215 * This routine adds a mode to be added or deleted that takes a client
2216 * parameter; mode may *only* be the relevant mode flag ORed with one of
2217 * MODE_ADD or MODE_DEL
2219 * @param mbuf The modebuf to append the mode to.
2220 * @param mode The mode to append.
2221 * @param client The client argument to append.
2224 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2225 struct Client *client)
2228 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2230 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2231 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2233 /* when we've reached the maximal count, flush the buffer */
2234 if (++mbuf->mb_count >=
2235 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2236 modebuf_flush_int(mbuf, 0);
2239 /** The exported binding for modebuf_flush()
2241 * @param mbuf The mode buffer to flush.
2243 * @see modebuf_flush_int()
2246 modebuf_flush(struct ModeBuf *mbuf)
2248 struct Membership *memb;
2250 /* Check if MODE_WASDELJOINS should be set */
2251 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2252 && (mbuf->mb_rem & MODE_DELJOINS)) {
2253 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2254 if (IsDelayedJoin(memb)) {
2255 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2256 mbuf->mb_add |= MODE_WASDELJOINS;
2257 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2263 return modebuf_flush_int(mbuf, 1);
2266 /* This extracts the simple modes contained in mbuf
2268 * @param mbuf The mode buffer to extract the modes from.
2269 * @param buf The string buffer to write the modes into.
2272 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2274 static int flags[] = {
2275 /* MODE_CHANOP, 'o', */
2276 /* MODE_VOICE, 'v', */
2279 MODE_MODERATED, 'm',
2280 MODE_TOPICLIMIT, 't',
2281 MODE_INVITEONLY, 'i',
2282 MODE_NOPRIVMSGS, 'n',
2286 /* MODE_BAN, 'b', */
2293 int i, bufpos = 0, len;
2295 char *key = 0, limitbuf[20];
2296 char *apass = 0, *upass = 0;
2305 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2306 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2307 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2309 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2310 key = MB_STRING(mbuf, i);
2311 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2312 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2313 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2314 upass = MB_STRING(mbuf, i);
2315 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2316 apass = MB_STRING(mbuf, i);
2323 buf[bufpos++] = '+'; /* start building buffer */
2325 for (flag_p = flags; flag_p[0]; flag_p += 2)
2327 buf[bufpos++] = flag_p[1];
2329 for (i = 0, len = bufpos; i < len; i++) {
2331 build_string(buf, &bufpos, key, 0, ' ');
2332 else if (buf[i] == 'l')
2333 build_string(buf, &bufpos, limitbuf, 0, ' ');
2334 else if (buf[i] == 'U')
2335 build_string(buf, &bufpos, upass, 0, ' ');
2336 else if (buf[i] == 'A')
2337 build_string(buf, &bufpos, apass, 0, ' ');
2345 /** Simple function to invalidate bans
2347 * This function sets all bans as being valid.
2349 * @param chan The channel to operate on.
2352 mode_ban_invalidate(struct Channel *chan)
2354 struct Membership *member;
2356 for (member = chan->members; member; member = member->next_member)
2357 ClearBanValid(member);
2360 /** Simple function to drop invite structures
2362 * Remove all the invites on the channel.
2364 * @param chan Channel to remove invites from.
2368 mode_invite_clear(struct Channel *chan)
2370 while (chan->invites)
2371 del_invite(chan->invites->value.cptr, chan);
2374 /* What we've done for mode_parse so far... */
2375 #define DONE_LIMIT 0x01 /**< We've set the limit */
2376 #define DONE_KEY 0x02 /**< We've set the key */
2377 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2378 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2379 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2380 #define DONE_UPASS 0x20 /**< We've set user pass */
2381 #define DONE_APASS 0x40 /**< We've set admin pass */
2384 struct ModeBuf *mbuf;
2385 struct Client *cptr;
2386 struct Client *sptr;
2387 struct Channel *chptr;
2388 struct Membership *member;
2399 struct Ban banlist[MAXPARA];
2402 struct Client *client;
2403 } cli_change[MAXPARA];
2406 /** Helper function to send "Not oper" or "Not member" messages
2407 * Here's a helper function to deal with sending along "Not oper" or
2408 * "Not member" messages
2410 * @param state Parsing State object
2413 send_notoper(struct ParseState *state)
2415 if (state->done & DONE_NOTOPER)
2418 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2419 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2421 state->done |= DONE_NOTOPER;
2425 * Helper function to convert limits
2427 * @param state Parsing state object.
2431 mode_parse_limit(struct ParseState *state, int *flag_p)
2433 unsigned int t_limit;
2435 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2436 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2439 if (state->parc <= 0) { /* warn if not enough args */
2440 if (MyUser(state->sptr))
2441 need_more_params(state->sptr, "MODE +l");
2445 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2449 if ((int)t_limit<0) /* don't permit a negative limit */
2452 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2453 (!t_limit || t_limit == state->chptr->mode.limit))
2456 t_limit = state->chptr->mode.limit;
2458 /* If they're not an oper, they can't change modes */
2459 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2460 send_notoper(state);
2464 /* Can't remove a limit that's not there */
2465 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2468 /* Skip if this is a burst and a lower limit than this is set already */
2469 if ((state->flags & MODE_PARSE_BURST) &&
2470 (state->chptr->mode.mode & flag_p[0]) &&
2471 (state->chptr->mode.limit < t_limit))
2474 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2476 state->done |= DONE_LIMIT;
2481 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2483 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2484 if (state->dir & MODE_ADD) {
2485 state->chptr->mode.mode |= flag_p[0];
2486 state->chptr->mode.limit = t_limit;
2488 state->chptr->mode.mode &= ~flag_p[0];
2489 state->chptr->mode.limit = 0;
2495 * Helper function to convert keys
2498 mode_parse_key(struct ParseState *state, int *flag_p)
2503 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2506 if (state->parc <= 0) { /* warn if not enough args */
2507 if (MyUser(state->sptr))
2508 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2513 t_str = state->parv[state->args_used++]; /* grab arg */
2517 /* If they're not an oper, they can't change modes */
2518 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2519 send_notoper(state);
2523 if (state->done & DONE_KEY) /* allow key to be set only once */
2525 state->done |= DONE_KEY;
2529 /* clean up the key string */
2531 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2535 if (!*t_str) { /* warn if empty */
2536 if (MyUser(state->sptr))
2537 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2545 /* Skip if this is a burst, we have a key already and the new key is
2546 * after the old one alphabetically */
2547 if ((state->flags & MODE_PARSE_BURST) &&
2548 *(state->chptr->mode.key) &&
2549 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2552 /* can't add a key if one is set, nor can one remove the wrong key */
2553 if (!(state->flags & MODE_PARSE_FORCE))
2554 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2555 (state->dir == MODE_DEL &&
2556 ircd_strcmp(state->chptr->mode.key, t_str))) {
2557 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2561 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2562 !ircd_strcmp(state->chptr->mode.key, t_str))
2563 return; /* no key change */
2565 if (state->flags & MODE_PARSE_BOUNCE) {
2566 if (*state->chptr->mode.key) /* reset old key */
2567 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2568 state->chptr->mode.key, 0);
2569 else /* remove new bogus key */
2570 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2571 } else /* send new key */
2572 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2574 if (state->flags & MODE_PARSE_SET) {
2575 if (state->dir == MODE_ADD) /* set the new key */
2576 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2577 else /* remove the old key */
2578 *state->chptr->mode.key = '\0';
2583 * Helper function to convert user passes
2586 mode_parse_upass(struct ParseState *state, int *flag_p)
2591 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2594 if (state->parc <= 0) { /* warn if not enough args */
2595 if (MyUser(state->sptr))
2596 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2601 t_str = state->parv[state->args_used++]; /* grab arg */
2605 /* If they're not an oper, they can't change modes */
2606 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2607 send_notoper(state);
2611 /* If a non-service user is trying to force it, refuse. */
2612 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2613 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2614 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2618 /* If they are not the channel manager, they are not allowed to change it */
2619 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2620 if (*state->chptr->mode.apass) {
2621 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2622 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2624 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2625 "Re-create the channel. The channel must be *empty* for",
2626 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2627 "before it can be recreated.");
2632 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2634 state->done |= DONE_UPASS;
2636 t_len = PASSLEN + 1;
2638 /* clean up the upass string */
2640 while (*++s > ' ' && *s != ':' && --t_len)
2644 if (!*t_str) { /* warn if empty */
2645 if (MyUser(state->sptr))
2646 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2654 if (!(state->flags & MODE_PARSE_FORCE))
2655 /* can't add the upass while apass is not set */
2656 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2657 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2660 /* can't add a upass if one is set, nor can one remove the wrong upass */
2661 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2662 (state->dir == MODE_DEL &&
2663 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2664 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2668 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2669 !ircd_strcmp(state->chptr->mode.upass, t_str))
2670 return; /* no upass change */
2672 if (state->flags & MODE_PARSE_BOUNCE) {
2673 if (*state->chptr->mode.upass) /* reset old upass */
2674 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2675 state->chptr->mode.upass, 0);
2676 else /* remove new bogus upass */
2677 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2678 } else /* send new upass */
2679 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2681 if (state->flags & MODE_PARSE_SET) {
2682 if (state->dir == MODE_ADD) /* set the new upass */
2683 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2684 else /* remove the old upass */
2685 *state->chptr->mode.upass = '\0';
2690 * Helper function to convert admin passes
2693 mode_parse_apass(struct ParseState *state, int *flag_p)
2698 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2701 if (state->parc <= 0) { /* warn if not enough args */
2702 if (MyUser(state->sptr))
2703 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2708 t_str = state->parv[state->args_used++]; /* grab arg */
2712 /* If they're not an oper, they can't change modes */
2713 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2714 send_notoper(state);
2718 /* If a non-service user is trying to force it, refuse. */
2719 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2720 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2721 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2725 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2726 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2727 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2731 /* If they are not the channel manager, they are not allowed to change it */
2732 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2733 if (*state->chptr->mode.apass) {
2734 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2735 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2737 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2738 "Re-create the channel. The channel must be *empty* for",
2739 "at least a whole minute", "before it can be recreated.");
2744 if (state->done & DONE_APASS) /* allow apass to be set only once */
2746 state->done |= DONE_APASS;
2748 t_len = PASSLEN + 1;
2750 /* clean up the apass string */
2752 while (*++s > ' ' && *s != ':' && --t_len)
2756 if (!*t_str) { /* warn if empty */
2757 if (MyUser(state->sptr))
2758 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2766 if (!(state->flags & MODE_PARSE_FORCE)) {
2767 /* can't remove the apass while upass is still set */
2768 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2769 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2772 /* can't add an apass if one is set, nor can one remove the wrong apass */
2773 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2774 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2775 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2780 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2781 !ircd_strcmp(state->chptr->mode.apass, t_str))
2782 return; /* no apass change */
2784 if (state->flags & MODE_PARSE_BOUNCE) {
2785 if (*state->chptr->mode.apass) /* reset old apass */
2786 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2787 state->chptr->mode.apass, 0);
2788 else /* remove new bogus apass */
2789 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2790 } else /* send new apass */
2791 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2793 if (state->flags & MODE_PARSE_SET) {
2794 if (state->dir == MODE_ADD) { /* set the new apass */
2795 /* Make it VERY clear to the user that this is a one-time password */
2796 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2797 if (MyUser(state->sptr)) {
2798 send_reply(state->sptr, RPL_APASSWARN,
2799 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2800 "Are you SURE you want to use this as Admin password? ",
2801 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2802 send_reply(state->sptr, RPL_APASSWARN,
2803 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2804 "\" to remove the password and then immediately set a new one. "
2805 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2806 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2807 "Now set the channel user password (+u).");
2809 } else { /* remove the old apass */
2810 *state->chptr->mode.apass = '\0';
2811 if (MyUser(state->sptr))
2812 send_reply(state->sptr, RPL_APASSWARN,
2813 "WARNING: You removed the channel Admin password MODE (+A). ",
2814 "If you would disconnect or leave the channel without setting a new password then you will ",
2815 "not be able to set it again and lose ownership of this channel! ",
2816 "SET A NEW PASSWORD NOW!", "");
2822 * Helper function to convert bans
2825 mode_parse_ban(struct ParseState *state, int *flag_p)
2828 struct Ban *ban, *newban = 0;
2830 if (state->parc <= 0) { /* Not enough args, send ban list */
2831 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2832 send_ban_list(state->sptr, state->chptr);
2833 state->done |= DONE_BANLIST;
2839 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2842 t_str = state->parv[state->args_used++]; /* grab arg */
2846 /* If they're not an oper, they can't change modes */
2847 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2848 send_notoper(state);
2852 if ((s = strchr(t_str, ' ')))
2855 if (!*t_str || *t_str == ':') { /* warn if empty */
2856 if (MyUser(state->sptr))
2857 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2862 t_str = collapse(pretty_mask(t_str));
2864 /* remember the ban for the moment... */
2865 if (state->dir == MODE_ADD) {
2866 newban = state->banlist + (state->numbans++);
2869 DupString(newban->banstr, t_str);
2870 newban->who = cli_name(state->sptr);
2871 newban->when = TStime();
2873 newban->flags = BAN_ADD;
2875 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2876 newban->flags |= BAN_IPMASK;
2879 if (!state->chptr->banlist) {
2880 state->chptr->banlist = newban; /* add our ban with its flags */
2881 state->done |= DONE_BANCLEAN;
2885 /* Go through all bans */
2886 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2887 /* first, clean the ban flags up a bit */
2888 if (!(state->done & DONE_BANCLEAN))
2889 /* Note: We're overloading *lots* of bits here; be careful! */
2890 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2894 * BAN_ADD - Ban was added; if we're bouncing modes,
2895 * then we'll remove it below; otherwise,
2896 * we'll have to allocate a real ban
2898 * BAN_DEL - Ban was marked for deletion; if we're
2899 * bouncing modes, we'll have to re-add it,
2900 * otherwise, we'll have to remove it
2902 * BAN_OVERLAPPED - The ban we added turns out to overlap
2903 * with a ban already set; if we're
2904 * bouncing modes, we'll have to bounce
2905 * this one; otherwise, we'll just ignore
2906 * it when we process added bans
2909 if (state->dir == MODE_DEL && !ircd_strcmp(ban->banstr, t_str)) {
2910 ban->flags |= BAN_DEL; /* delete one ban */
2912 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2914 } else if (state->dir == MODE_ADD) {
2915 /* if the ban already exists, don't worry about it */
2916 if (!ircd_strcmp(ban->banstr, t_str)) {
2917 newban->flags &= ~BAN_ADD; /* don't add ban at all */
2918 MyFree(newban->banstr); /* stopper a leak */
2919 state->numbans--; /* deallocate last ban */
2920 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2922 } else if (!mmatch(ban->banstr, t_str)) {
2923 if (!(ban->flags & BAN_DEL))
2924 newban->flags |= BAN_OVERLAPPED; /* our ban overlaps */
2925 } else if (!mmatch(t_str, ban->banstr))
2926 ban->flags |= BAN_DEL; /* mark ban for deletion: overlapping */
2928 if (!ban->next && (newban->flags & BAN_ADD))
2930 ban->next = newban; /* add our ban with its flags */
2931 break; /* get out of loop */
2935 state->done |= DONE_BANCLEAN;
2939 * This is the bottom half of the ban processor
2942 mode_process_bans(struct ParseState *state)
2944 struct Ban *ban, *newban, *prevban, *nextban;
2950 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2952 banlen = strlen(ban->banstr);
2954 nextban = ban->next;
2956 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2958 prevban->next = 0; /* Break the list; ban isn't a real ban */
2960 state->chptr->banlist = 0;
2965 MyFree(ban->banstr);
2968 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2969 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2971 state->flags & MODE_PARSE_SET);
2973 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2974 if (prevban) /* clip it out of the list... */
2975 prevban->next = ban->next;
2977 state->chptr->banlist = ban->next;
2982 ban->banstr = NULL; /* do not free this string */
2986 continue; /* next ban; keep prevban like it is */
2988 ban->flags &= BAN_IPMASK; /* unset other flags */
2989 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2991 prevban->next = 0; /* Break the list; ban isn't a real ban */
2993 state->chptr->banlist = 0;
2995 /* If we're supposed to ignore it, do so. */
2996 if (ban->flags & BAN_OVERLAPPED &&
2997 !(state->flags & MODE_PARSE_BOUNCE)) {
3000 MyFree(ban->banstr);
3002 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
3003 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
3004 count > feature_int(FEAT_MAXBANS))) {
3005 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
3009 MyFree(ban->banstr);
3011 /* add the ban to the buffer */
3012 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
3014 !(state->flags & MODE_PARSE_SET));
3016 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3017 newban = make_ban(ban->banstr);
3018 DupString(newban->who, ban->who);
3019 newban->when = ban->when;
3020 newban->flags = ban->flags & BAN_IPMASK;
3022 newban->next = state->chptr->banlist; /* and link it in */
3023 state->chptr->banlist = newban;
3032 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3034 if (changed) /* if we changed the ban list, we must invalidate the bans */
3035 mode_ban_invalidate(state->chptr);
3039 * Helper function to process client changes
3042 mode_parse_client(struct ParseState *state, int *flag_p)
3045 struct Client *acptr;
3048 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3051 if (state->parc <= 0) /* return if not enough args */
3054 t_str = state->parv[state->args_used++]; /* grab arg */
3058 /* If they're not an oper, they can't change modes */
3059 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3060 send_notoper(state);
3064 if (MyUser(state->sptr)) /* find client we're manipulating */
3065 acptr = find_chasing(state->sptr, t_str, NULL);
3067 acptr = findNUser(t_str);
3070 return; /* find_chasing() already reported an error to the user */
3072 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3073 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3074 state->cli_change[i].flag & flag_p[0]))
3075 break; /* found a slot */
3077 /* Store what we're doing to them */
3078 state->cli_change[i].flag = state->dir | flag_p[0];
3079 state->cli_change[i].client = acptr;
3083 * Helper function to process the changed client list
3086 mode_process_clients(struct ParseState *state)
3089 struct Membership *member;
3091 for (i = 0; state->cli_change[i].flag; i++) {
3092 assert(0 != state->cli_change[i].client);
3094 /* look up member link */
3095 if (!(member = find_member_link(state->chptr,
3096 state->cli_change[i].client)) ||
3097 (MyUser(state->sptr) && IsZombie(member))) {
3098 if (MyUser(state->sptr))
3099 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3100 cli_name(state->cli_change[i].client),
3101 state->chptr->chname);
3105 if ((state->cli_change[i].flag & MODE_ADD &&
3106 (state->cli_change[i].flag & member->status)) ||
3107 (state->cli_change[i].flag & MODE_DEL &&
3108 !(state->cli_change[i].flag & member->status)))
3109 continue; /* no change made, don't do anything */
3111 /* see if the deop is allowed */
3112 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3113 (MODE_DEL | MODE_CHANOP)) {
3114 /* prevent +k users from being deopped */
3115 if (IsChannelService(state->cli_change[i].client)) {
3116 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3117 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3119 (IsServer(state->sptr) ? cli_name(state->sptr) :
3120 cli_name((cli_user(state->sptr))->server)));
3122 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3123 send_reply(state->sptr, ERR_ISCHANSERVICE,
3124 cli_name(state->cli_change[i].client),
3125 state->chptr->chname);
3130 /* check deop for local user */
3131 if (MyUser(state->sptr)) {
3133 /* don't allow local opers to be deopped on local channels */
3134 if (state->cli_change[i].client != state->sptr &&
3135 IsLocalChannel(state->chptr->chname) &&
3136 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3137 send_reply(state->sptr, ERR_ISOPERLCHAN,
3138 cli_name(state->cli_change[i].client),
3139 state->chptr->chname);
3143 if (feature_bool(FEAT_OPLEVELS)) {
3144 /* don't allow to deop members with an op level that is <= our own level */
3145 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3147 && OpLevel(member) <= OpLevel(state->member)) {
3148 int equal = (OpLevel(member) == OpLevel(state->member));
3149 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3150 cli_name(state->cli_change[i].client),
3151 state->chptr->chname,
3152 OpLevel(state->member), OpLevel(member),
3153 "deop", equal ? "the same" : "a higher");
3160 /* set op-level of member being opped */
3161 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3162 (MODE_ADD | MODE_CHANOP)) {
3163 /* If on a channel with upass set, someone with level x gives ops to someone else,
3164 then that person gets level x-1. On other channels, where upass is not set,
3165 the level stays the same. */
3166 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3167 /* Someone being opped by a server gets op-level 0 */
3168 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3169 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3172 /* actually effect the change */
3173 if (state->flags & MODE_PARSE_SET) {
3174 if (state->cli_change[i].flag & MODE_ADD) {
3175 if (IsDelayedJoin(member))
3176 RevealDelayedJoin(member);
3177 member->status |= (state->cli_change[i].flag &
3178 (MODE_CHANOP | MODE_VOICE));
3179 if (state->cli_change[i].flag & MODE_CHANOP)
3180 ClearDeopped(member);
3182 member->status &= ~(state->cli_change[i].flag &
3183 (MODE_CHANOP | MODE_VOICE));
3186 /* accumulate the change */
3187 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3188 state->cli_change[i].client);
3189 } /* for (i = 0; state->cli_change[i].flags; i++) */
3193 * Helper function to process the simple modes
3196 mode_parse_mode(struct ParseState *state, int *flag_p)
3198 /* If they're not an oper, they can't change modes */
3199 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3200 send_notoper(state);
3207 if (state->dir == MODE_ADD) {
3208 state->add |= flag_p[0];
3209 state->del &= ~flag_p[0];
3211 if (flag_p[0] & MODE_SECRET) {
3212 state->add &= ~MODE_PRIVATE;
3213 state->del |= MODE_PRIVATE;
3214 } else if (flag_p[0] & MODE_PRIVATE) {
3215 state->add &= ~MODE_SECRET;
3216 state->del |= MODE_SECRET;
3218 if (flag_p[0] & MODE_DELJOINS) {
3219 state->add &= ~MODE_WASDELJOINS;
3220 state->del |= MODE_WASDELJOINS;
3223 state->add &= ~flag_p[0];
3224 state->del |= flag_p[0];
3227 assert(0 == (state->add & state->del));
3228 assert((MODE_SECRET | MODE_PRIVATE) !=
3229 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3233 * This routine is intended to parse MODE or OPMODE commands and effect the
3234 * changes (or just build the bounce buffer). We pass the starting offset
3238 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3239 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3240 struct Membership* member)
3242 static int chan_flags[] = {
3247 MODE_MODERATED, 'm',
3248 MODE_TOPICLIMIT, 't',
3249 MODE_INVITEONLY, 'i',
3250 MODE_NOPRIVMSGS, 'n',
3264 unsigned int t_mode;
3266 struct ParseState state;
3277 state.chptr = chptr;
3278 state.member = member;
3281 state.flags = flags;
3282 state.dir = MODE_ADD;
3286 state.args_used = 0;
3287 state.max_args = MAXMODEPARAMS;
3290 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3291 state.banlist[i].next = 0;
3292 state.banlist[i].who = 0;
3293 state.banlist[i].when = 0;
3294 state.banlist[i].flags = 0;
3295 state.cli_change[i].flag = 0;
3296 state.cli_change[i].client = 0;
3299 modestr = state.parv[state.args_used++];
3303 for (; *modestr; modestr++) {
3304 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3305 if (flag_p[1] == *modestr)
3308 if (!flag_p[0]) { /* didn't find it? complain and continue */
3309 if (MyUser(state.sptr))
3310 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3315 case '+': /* switch direction to MODE_ADD */
3316 case '-': /* switch direction to MODE_DEL */
3317 state.dir = flag_p[0];
3320 case 'l': /* deal with limits */
3321 mode_parse_limit(&state, flag_p);
3324 case 'k': /* deal with keys */
3325 mode_parse_key(&state, flag_p);
3328 case 'A': /* deal with Admin passes */
3329 if (feature_bool(FEAT_OPLEVELS))
3330 mode_parse_apass(&state, flag_p);
3333 case 'U': /* deal with user passes */
3334 if (feature_bool(FEAT_OPLEVELS))
3335 mode_parse_upass(&state, flag_p);
3338 case 'b': /* deal with bans */
3339 mode_parse_ban(&state, flag_p);
3342 case 'o': /* deal with ops/voice */
3344 mode_parse_client(&state, flag_p);
3347 default: /* deal with other modes */
3348 mode_parse_mode(&state, flag_p);
3350 } /* switch (*modestr) */
3351 } /* for (; *modestr; modestr++) */
3353 if (state.flags & MODE_PARSE_BURST)
3354 break; /* don't interpret any more arguments */
3356 if (state.parc > 0) { /* process next argument in string */
3357 modestr = state.parv[state.args_used++];
3361 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3364 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3365 break; /* we're then going to bounce the mode! */
3367 recv_ts = atoi(modestr);
3369 if (recv_ts && recv_ts < state.chptr->creationtime)
3370 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3372 break; /* break out of while loop */
3373 } else if (state.flags & MODE_PARSE_STRICT ||
3374 (MyUser(state.sptr) && state.max_args <= 0)) {
3375 state.parc++; /* we didn't actually gobble the argument */
3377 break; /* break out of while loop */
3380 } /* while (*modestr) */
3383 * the rest of the function finishes building resultant MODEs; if the
3384 * origin isn't a member or an oper, skip it.
3386 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3387 return state.args_used; /* tell our parent how many args we gobbled */
3389 t_mode = state.chptr->mode.mode;
3391 if (state.del & t_mode) { /* delete any modes to be deleted... */
3392 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3394 t_mode &= ~state.del;
3396 if (state.add & ~t_mode) { /* add any modes to be added... */
3397 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3399 t_mode |= state.add;
3402 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3403 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3404 !(t_mode & MODE_INVITEONLY))
3405 mode_invite_clear(state.chptr);
3407 state.chptr->mode.mode = t_mode;
3410 if (state.flags & MODE_PARSE_WIPEOUT) {
3411 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3412 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3413 state.chptr->mode.limit);
3414 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3415 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3416 state.chptr->mode.key, 0);
3417 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3418 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3419 state.chptr->mode.upass, 0);
3420 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3421 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3422 state.chptr->mode.apass, 0);
3425 if (state.done & DONE_BANCLEAN) /* process bans */
3426 mode_process_bans(&state);
3428 /* process client changes */
3429 if (state.cli_change[0].flag)
3430 mode_process_clients(&state);
3432 return state.args_used; /* tell our parent how many args we gobbled */
3436 * Initialize a join buffer
3439 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3440 struct Client *connect, unsigned int type, char *comment,
3446 assert(0 != source);
3447 assert(0 != connect);
3449 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3450 jbuf->jb_connect = connect;
3451 jbuf->jb_type = type;
3452 jbuf->jb_comment = comment;
3453 jbuf->jb_create = create;
3455 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3456 type == JOINBUF_TYPE_PART ||
3457 type == JOINBUF_TYPE_PARTALL) ?
3458 STARTJOINLEN : STARTCREATELEN) +
3459 (comment ? strlen(comment) + 2 : 0));
3461 for (i = 0; i < MAXJOINARGS; i++)
3462 jbuf->jb_channels[i] = 0;
3466 * Add a channel to the join buffer
3469 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3477 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3478 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3483 is_local = IsLocalChannel(chan->chname);
3485 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3486 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3487 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3488 if (IsUserParting(member))
3490 SetUserParting(member);
3492 /* Send notification to channel */
3493 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3494 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3495 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3496 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3497 else if (MyUser(jbuf->jb_source))
3498 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3499 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3500 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3501 /* XXX: Shouldn't we send a PART here anyway? */
3502 /* to users on the channel? Why? From their POV, the user isn't on
3503 * the channel anymore anyway. We don't send to servers until below,
3504 * when we gang all the channel parts together. Note that this is
3505 * exactly the same logic, albeit somewhat more concise, as was in
3506 * the original m_part.c */
3508 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3509 is_local) /* got to remove user here */
3510 remove_user_from_channel(jbuf->jb_source, chan);
3512 /* Add user to channel */
3513 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3514 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3516 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3518 /* send notification to all servers */
3519 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3520 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3521 "%H %Tu", chan, chan->creationtime);
3523 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3524 /* Send the notification to the channel */
3525 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3527 /* send an op, too, if needed */
3528 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3529 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3530 chan, jbuf->jb_source);
3531 } else if (MyUser(jbuf->jb_source))
3532 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3535 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3536 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3537 return; /* don't send to remote */
3539 /* figure out if channel name will cause buffer to be overflowed */
3540 len = chan ? strlen(chan->chname) + 1 : 2;
3541 if (jbuf->jb_strlen + len > BUFSIZE)
3542 joinbuf_flush(jbuf);
3544 /* add channel to list of channels to send and update counts */
3545 jbuf->jb_channels[jbuf->jb_count++] = chan;
3546 jbuf->jb_strlen += len;
3548 /* if we've used up all slots, flush */
3549 if (jbuf->jb_count >= MAXJOINARGS)
3550 joinbuf_flush(jbuf);
3554 * Flush the channel list to remote servers
3557 joinbuf_flush(struct JoinBuf *jbuf)
3559 char chanlist[BUFSIZE];
3563 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3564 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3565 return 0; /* no joins to process */
3567 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3568 build_string(chanlist, &chanlist_i,
3569 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3570 i == 0 ? '\0' : ',');
3571 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3572 /* Remove user from channel */
3573 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3575 jbuf->jb_channels[i] = 0; /* mark slot empty */
3578 jbuf->jb_count = 0; /* reset base counters */
3579 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3580 STARTJOINLEN : STARTCREATELEN) +
3581 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3583 /* and send the appropriate command */
3584 switch (jbuf->jb_type) {
3585 case JOINBUF_TYPE_CREATE:
3586 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3587 "%s %Tu", chanlist, jbuf->jb_create);
3590 case JOINBUF_TYPE_PART:
3591 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3592 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3600 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3601 int IsInvited(struct Client* cptr, const void* chptr)
3605 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3606 if (lp->value.chptr == chptr)
3611 /* RevealDelayedJoin: sends a join for a hidden user */
3613 void RevealDelayedJoin(struct Membership *member) {
3614 ClearDelayedJoin(member);
3615 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3617 CheckDelayedJoins(member->channel);
3620 /* CheckDelayedJoins: checks and clear +d if necessary */
3622 void CheckDelayedJoins(struct Channel *chan) {
3623 struct Membership *memb2;
3625 if (chan->mode.mode & MODE_WASDELJOINS) {
3626 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3627 if (IsDelayedJoin(memb2))
3632 chan->mode.mode &= ~MODE_WASDELJOINS;
3633 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,