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 SLink* next_ban;
78 static struct SLink* prev_ban;
79 static struct SLink* removed_bans_list;
82 * Use a global variable to remember if an oper set a mode on a local channel.
83 * Ugly, but the only way to do it without changing set_mode intensively.
85 int LocalChanOperMode = 0;
88 /** return the length (>=0) of a chain of links.
89 * @param lp pointer to the start of the linked list
90 * @return the number of items in the list
92 static int list_length(struct SLink *lp)
96 for (; lp; lp = lp->next)
102 /** return the struct Membership* that represents a client on a channel
103 * This function finds a struct Membership* which holds the state about
104 * a client on a specific channel. The code is smart enough to iterate
105 * over the channels a user is in, or the users in a channel to find the
106 * user depending on which is likely to be more efficient.
108 * @param chptr pointer to the channel struct
109 * @param cptr pointer to the client struct
111 * @returns pointer to the struct Membership representing this client on
112 * this channel. Returns NULL if the client is not on the channel.
113 * Returns NULL if the client is actually a server.
114 * @see find_channel_member()
116 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
118 struct Membership *m;
122 /* Servers don't have member links */
123 if (IsServer(cptr)||IsMe(cptr))
126 /* +k users are typically on a LOT of channels. So we iterate over who
127 * is in the channel. X/W are +k and are in about 5800 channels each.
128 * however there are typically no more than 1000 people in a channel
131 if (IsChannelService(cptr)) {
134 assert(m->channel == chptr);
140 /* Users on the other hand aren't allowed on more than 15 channels. 50%
141 * of users that are on channels are on 2 or less, 95% are on 7 or less,
142 * and 99% are on 10 or less.
145 m = (cli_user(cptr))->channel;
147 assert(m->user == cptr);
148 if (m->channel == chptr)
156 /** Find the client structure for a nick name (user)
157 * Find the client structure for a nick name (user)
158 * using history mechanism if necessary. If the client is not found, an error
159 * message (NO SUCH NICK) is generated. If the client was found
160 * through the history, chasing will be 1 and otherwise 0.
162 * This function was used extensively in the P09 days, and since we now have
163 * numeric nicks is no longer quite as important.
165 * @param sptr Pointer to the client that has requested the search
166 * @param user a string represeting the client to be found
167 * @param chasing a variable set to 0 if the user was found directly,
169 * @returns a pointer the client, or NULL if the client wasn't found.
171 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
173 struct Client* who = FindClient(user);
180 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
181 send_reply(sptr, ERR_NOSUCHNICK, user);
189 /** build up a hostmask
190 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
191 * as the parameters. If NULL, they become "*".
192 * @param namebuf the buffer to build the hostmask into. Must be at least
193 * NICKLEN+USERLEN+HOSTLEN+3 charactors long.
194 * @param nick The nickname
195 * @param name The ident
196 * @param host the hostname
198 * @see make_nick_user_ip()
200 static char *make_nick_user_host(char *namebuf, const char *nick,
201 const char *name, const char *host)
203 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
204 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
208 /** Create a hostmask using an IP address
209 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
210 * IP-number as the parameters. If NULL, they become "*".
212 * @param ipbuf Buffer at least NICKLEN+USERLEN+SOCKIPLEN+4 to hold the final
214 * @param nick The nickname (or NULL for *)
215 * @param name The ident (or NULL for *)
216 * @param ip The IP address
218 * @see make_nick_user_host()
220 #define NUI_BUFSIZE (NICKLEN + USERLEN + SOCKIPLEN + 4)
221 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
222 const struct irc_in_addr *ip)
224 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
228 /** Decrement the count of users, and free if empty.
229 * Subtract one user from channel i (and free channel * block, if channel
232 * @param chptr The channel to subtract one from.
234 * @returns true (1) if channel still has members.
235 * false (0) if the channel is now empty.
237 int sub1_from_channel(struct Channel* chptr)
239 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
241 assert(0 != chptr->members);
249 * Also channels without Apass set need to be kept alive,
250 * otherwise Bad Guys(tm) would be able to takeover
251 * existing channels too easily, and then set an Apass!
252 * However, if a channel without Apass becomes empty
253 * then we try to be kind to them and remove possible
256 chptr->mode.mode &= ~MODE_INVITEONLY;
257 chptr->mode.limit = 0;
259 * We do NOT reset a possible key or bans because when
260 * the 'channel owners' can't get in because of a key
261 * or ban then apparently there was a fight/takeover
262 * on the channel and we want them to contact IRC opers
263 * who then will educate them on the use of Apass/upass.
266 if (feature_bool(FEAT_OPLEVELS)) {
267 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
268 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
270 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
272 destruct_channel(chptr);
277 /** Destroy an empty channel
278 * This function destroys an empty channel, removing it from hashtables,
279 * and removing any resources it may have consumed.
281 * @param chptr The channel to destroy
283 * @returns 0 (success)
285 * FIXME: Change to return void, this function never fails.
287 int destruct_channel(struct Channel* chptr)
292 assert(0 == chptr->members);
295 * Now, find all invite links from channel structure
297 while ((tmp = chptr->invites))
298 del_invite(tmp->value.cptr, chptr);
300 tmp = chptr->banlist;
305 MyFree(obtmp->value.ban.banstr);
306 MyFree(obtmp->value.ban.who);
310 chptr->prev->next = chptr->next;
312 GlobalChannelList = chptr->next;
314 chptr->next->prev = chptr->prev;
316 --UserStats.channels;
318 * make sure that channel actually got removed from hash table
320 assert(chptr->hnext == chptr);
325 /** add a ban to a channel
327 * `cptr' must be the client adding the ban.
329 * If `change' is true then add `banid' to channel `chptr'.
330 * Returns 0 if the ban was added.
331 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
332 * Return -1 otherwise.
334 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
335 * when `change' is false, otherwise they will be removed from the banlist.
336 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
337 * respectively will return these bans until NULL is returned.
339 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
340 * is reset (unless a non-zero value is returned, in which case the
341 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
344 * @param cptr Client adding the ban
345 * @param chptr Channel to add the ban to
346 * @param banid The actual ban.
347 * @param change True if adding a ban, false if old bans should just be flagged
348 * @param firsttime Reset the next_overlapped_ban() iteration.
350 * 0 if the ban was added
351 * -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT
354 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
355 int change, int firsttime)
360 int removed_bans = 0;
361 int len = strlen(banid);
366 assert(0 == prev_ban);
367 assert(0 == removed_bans_list);
371 for (banp = &chptr->banlist; *banp;)
373 len += strlen((*banp)->value.ban.banstr);
375 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
377 if (!strcmp((*banp)->value.ban.banstr, banid))
379 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
383 else if (!mmatch((*banp)->value.ban.banstr, banid))
385 if (!mmatch(banid, (*banp)->value.ban.banstr))
387 struct SLink *tmp = *banp;
393 len -= strlen(tmp->value.ban.banstr);
396 /* These will be sent to the user later as -b */
397 tmp->next = removed_bans_list;
398 removed_bans_list = tmp;
401 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
403 tmp->flags |= CHFL_BAN_OVERLAPPED;
414 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
415 banp = &(*banp)->next;
418 if (MyUser(cptr) && !removed_bans &&
419 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
420 (cnt >= feature_int(FEAT_MAXBANS))))
422 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
428 struct Membership* member;
430 ban->next = chptr->banlist;
432 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
433 assert(0 != ban->value.ban.banstr);
434 strcpy(ban->value.ban.banstr, banid);
436 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
437 DupString(ban->value.ban.who, cli_name(&me));
439 DupString(ban->value.ban.who, cli_name(cptr));
440 assert(0 != ban->value.ban.who);
442 ban->value.ban.when = TStime();
443 ban->flags = CHFL_BAN; /* This bit is never used I think... */
444 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
445 ban->flags |= CHFL_BAN_IPMASK;
446 chptr->banlist = ban;
449 * Erase ban-valid-bit
451 for (member = chptr->members; member; member = member->next_member)
452 ClearBanValid(member); /* `ban' == channel member ! */
457 /** return the next ban that is removed
458 * @returns the next ban that is removed because of overlapping
460 struct SLink *next_removed_overlapped_ban(void)
462 struct SLink *tmp = removed_bans_list;
465 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
466 MyFree(prev_ban->value.ban.banstr);
467 MyFree(prev_ban->value.ban.who);
472 removed_bans_list = removed_bans_list->next;
477 /** returns Membership * if a person is joined and not a zombie
479 * @param chptr Channel
480 * @returns pointer to the client's struct Membership * on the channel if that
481 * user is a full member of the channel, or NULL otherwise.
483 * @see find_member_link()
485 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
487 struct Membership* member;
490 member = find_member_link(chptr, cptr);
491 return (member && !IsZombie(member)) ? member : 0;
494 /** return true if banned else false.
496 * This function returns true if the user is banned on the said channel.
497 * This function will check the ban cache if applicable, otherwise will
498 * do the comparisons and cache the result.
500 * @param cptr The client to test
501 * @param chptr The channel
502 * @param member The Membership * of this client on this channel
503 * (may be NULL if the member is not on the channel).
505 static int is_banned(struct Client *cptr, struct Channel *chptr,
506 struct Membership* member)
509 char tmphost[HOSTLEN + 1];
510 char nu_host[NUH_BUFSIZE];
511 char nu_realhost[NUH_BUFSIZE];
512 char nu_ip[NUI_BUFSIZE];
520 if (member && IsBanValid(member))
521 return IsBanned(member);
523 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
524 (cli_user(cptr))->host);
527 if (HasHiddenHost(cptr))
529 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
530 (cli_user(cptr))->username,
531 cli_user(cptr)->realhost);
535 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
536 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
537 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
538 cli_user(cptr)->username,
543 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
544 if ((tmp->flags & CHFL_BAN_IPMASK)) {
546 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
547 (cli_user(cptr))->username, &cli_ip(cptr));
548 if (match(tmp->value.ban.banstr, ip_s) == 0)
551 if (match(tmp->value.ban.banstr, s) == 0)
553 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
569 return (tmp != NULL);
572 /** add a user to a channel.
573 * adds a user to a channel by adding another link to the channels member
576 * @param chptr The channel to add to.
577 * @param who The user to add.
578 * @param flags The flags the user gets initially.
579 * @param oplevel The oplevel the user starts with.
581 void add_user_to_channel(struct Channel* chptr, struct Client* who,
582 unsigned int flags, int oplevel)
589 struct Membership* member = membershipFreeList;
591 membershipFreeList = member->next_member;
593 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
594 ++membershipAllocCount;
599 member->channel = chptr;
600 member->status = flags;
601 member->oplevel = oplevel;
603 member->next_member = chptr->members;
604 if (member->next_member)
605 member->next_member->prev_member = member;
606 member->prev_member = 0;
607 chptr->members = member;
609 member->next_channel = (cli_user(who))->channel;
610 if (member->next_channel)
611 member->next_channel->prev_channel = member;
612 member->prev_channel = 0;
613 (cli_user(who))->channel = member;
615 if (chptr->destruct_event)
616 remove_destruct_event(chptr);
618 ++((cli_user(who))->joined);
622 /** Remove a person from a channel, given their Membership*
624 * @param member A member of a channel.
626 * @returns true if there are more people in the channel.
628 static int remove_member_from_channel(struct Membership* member)
630 struct Channel* chptr;
632 chptr = member->channel;
634 * unlink channel member list
636 if (member->next_member)
637 member->next_member->prev_member = member->prev_member;
638 if (member->prev_member)
639 member->prev_member->next_member = member->next_member;
641 member->channel->members = member->next_member;
644 * If this is the last delayed-join user, may have to clear WASDELJOINS.
646 if (IsDelayedJoin(member))
647 CheckDelayedJoins(chptr);
650 * unlink client channel list
652 if (member->next_channel)
653 member->next_channel->prev_channel = member->prev_channel;
654 if (member->prev_channel)
655 member->prev_channel->next_channel = member->next_channel;
657 (cli_user(member->user))->channel = member->next_channel;
659 --(cli_user(member->user))->joined;
661 member->next_member = membershipFreeList;
662 membershipFreeList = member;
664 return sub1_from_channel(chptr);
667 /** Check if all the remaining members on the channel are zombies
669 * @returns False if the channel has any non zombie members, True otherwise.
672 static int channel_all_zombies(struct Channel* chptr)
674 struct Membership* member;
676 for (member = chptr->members; member; member = member->next_member) {
677 if (!IsZombie(member))
684 /** Remove a user from a channel
685 * This is the generic entry point for removing a user from a channel, this
686 * function will remove the client from the channel, and destory the channel
687 * if there are no more normal users left.
689 * @param cptr The client
690 * @param chptr The channel
692 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
695 struct Membership* member;
698 if ((member = find_member_link(chptr, cptr))) {
699 if (remove_member_from_channel(member)) {
700 if (channel_all_zombies(chptr)) {
702 * XXX - this looks dangerous but isn't if we got the referential
703 * integrity right for channels
705 while (remove_member_from_channel(chptr->members))
712 /** Remove a user from all channels they are on.
714 * This function removes a user from all channels they are on.
716 * @param cptr The client to remove.
718 void remove_user_from_all_channels(struct Client* cptr)
720 struct Membership* chan;
722 assert(0 != cli_user(cptr));
724 while ((chan = (cli_user(cptr))->channel))
725 remove_user_from_channel(cptr, chan->channel);
728 /** Check if this user is a legitimate chanop
730 * @param cptr Client to check
731 * @param chptr Channel to check
733 * @returns True if the user is a chanop (And not a zombie), False otherwise.
736 int is_chan_op(struct Client *cptr, struct Channel *chptr)
738 struct Membership* member;
740 if ((member = find_member_link(chptr, cptr)))
741 return (!IsZombie(member) && IsChanOp(member));
746 /** Check if a user is a Zombie on a specific channel.
748 * @param cptr The client to check.
749 * @param chptr The channel to check.
751 * @returns True if the client (cptr) is a zombie on the channel (chptr),
756 int is_zombie(struct Client *cptr, struct Channel *chptr)
758 struct Membership* member;
762 if ((member = find_member_link(chptr, cptr)))
763 return IsZombie(member);
767 /** Returns if a user has voice on a channel.
769 * @param cptr The client
770 * @param chptr The channel
772 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
775 int has_voice(struct Client* cptr, struct Channel* chptr)
777 struct Membership* member;
780 if ((member = find_member_link(chptr, cptr)))
781 return (!IsZombie(member) && HasVoice(member));
786 /** Can this member send to a channel
788 * A user can speak on a channel iff:
790 * <li> They didn't use the Apass to gain ops.
791 * <li> They are op'd or voice'd.
792 * <li> You aren't banned.
793 * <li> The channel isn't +m
794 * <li> The channel isn't +n or you are on the channel.
797 * This function will optionally reveal a user on a delayed join channel if
798 * they are allowed to send to the channel.
800 * @param member The membership of the user
801 * @param reveal If true, the user will be "revealed" on a delayed
804 * @returns True if the client can speak on the channel.
806 int member_can_send_to_channel(struct Membership* member, int reveal)
810 /* Discourage using the Apass to get op. They should use the upass. */
811 if (IsChannelManager(member) && *member->channel->mode.upass)
814 if (IsVoicedOrOpped(member))
817 * If it's moderated, and you aren't a priviledged user, you can't
820 if (member->channel->mode.mode & MODE_MODERATED)
823 * If you're banned then you can't speak either.
824 * but because of the amount of CPU time that is_banned chews
825 * we only check it for our clients.
827 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
830 if (IsDelayedJoin(member) && reveal)
831 RevealDelayedJoin(member);
836 /** Check if a client can send to a channel.
838 * Has the added check over member_can_send_to_channel() of servers can
841 * @param cptr The client to check
842 * @param chptr The channel to check
843 * @param reveal If the user should be revealed (see
844 * member_can_send_to_channel())
846 * @returns true if the client is allowed to speak on the channel, false
849 * @see member_can_send_to_channel()
851 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
853 struct Membership *member;
856 * Servers can always speak on channels.
861 member = find_channel_member(cptr, chptr);
864 * You can't speak if you're off channel, and it is +n (no external messages)
868 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
869 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
872 return !is_banned(cptr, chptr, NULL);
874 return member_can_send_to_channel(member, reveal);
877 /** Returns the name of a channel that prevents the user from changing nick.
878 * if a member and not (opped or voiced) and (banned or moderated), return
879 * the name of the first channel banned on.
881 * @param cptr The client
883 * @returns the name of the first channel banned on, or NULL if the user
886 const char* find_no_nickchange_channel(struct Client* cptr)
889 struct Membership* member;
890 for (member = (cli_user(cptr))->channel; member;
891 member = member->next_channel) {
892 if (!IsVoicedOrOpped(member) &&
893 (is_banned(cptr, member->channel, member) ||
894 (member->channel->mode.mode & MODE_MODERATED)))
895 return member->channel->chname;
902 /** Fill mbuf/pbuf with modes from chptr
903 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
904 * with the parameters in pbuf as visible by cptr.
906 * This function will hide keys from non-op'd, non-server clients.
908 * @param cptr The client to generate the mode for.
909 * @param mbuf The buffer to write the modes into.
910 * @param pbuf The buffer to write the mode parameters into.
911 * @param buflen The length of the buffers.
912 * @param chptr The channel to get the modes from.
913 * @param member The membership of this client on this channel (or NULL
914 * if this client isn't on this channel)
917 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
918 struct Channel *chptr, struct Membership *member)
920 int previous_parameter = 0;
927 if (chptr->mode.mode & MODE_SECRET)
929 else if (chptr->mode.mode & MODE_PRIVATE)
931 if (chptr->mode.mode & MODE_MODERATED)
933 if (chptr->mode.mode & MODE_TOPICLIMIT)
935 if (chptr->mode.mode & MODE_INVITEONLY)
937 if (chptr->mode.mode & MODE_NOPRIVMSGS)
939 if (chptr->mode.mode & MODE_REGONLY)
941 if (chptr->mode.mode & MODE_DELJOINS)
943 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
945 if (chptr->mode.limit) {
947 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
948 previous_parameter = 1;
951 if (*chptr->mode.key) {
953 if (previous_parameter)
955 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
956 strcat(pbuf, chptr->mode.key);
959 previous_parameter = 1;
961 if (*chptr->mode.apass) {
963 if (previous_parameter)
965 if (IsServer(cptr)) {
966 strcat(pbuf, chptr->mode.apass);
969 previous_parameter = 1;
971 if (*chptr->mode.upass) {
973 if (previous_parameter)
975 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
976 strcat(pbuf, chptr->mode.upass);
983 /** Compare two members oplevel
985 * @param mp1 Pointer to a pointer to a membership
986 * @param mp2 Pointer to a pointer to a membership
988 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
992 int compare_member_oplevel(const void *mp1, const void *mp2)
994 struct Membership const* member1 = *(struct Membership const**)mp1;
995 struct Membership const* member2 = *(struct Membership const**)mp2;
996 if (member1->oplevel == member2->oplevel)
998 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1001 /* send "cptr" a full list of the modes for channel chptr.
1003 * Sends a BURST line to cptr, bursting all the modes for the channel.
1005 * @param cptr Client pointer
1006 * @param chptr Channel pointer
1008 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1010 /* The order in which modes are generated is now mandatory */
1011 static unsigned int current_flags[4] =
1012 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1018 struct Membership* member;
1020 char modebuf[MODEBUFLEN];
1021 char parabuf[MODEBUFLEN];
1023 int number_of_ops = 0;
1024 int opped_members_index = 0;
1025 struct Membership** opped_members = NULL;
1026 int last_oplevel = 0;
1027 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1032 if (IsLocalChannel(chptr->chname))
1035 member = chptr->members;
1036 lp2 = chptr->banlist;
1038 *modebuf = *parabuf = '\0';
1039 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1041 for (first = 1; full; first = 0) /* Loop for multiple messages */
1043 full = 0; /* Assume by default we get it
1044 all in one message */
1046 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1047 /* is there any better way we can do this? */
1048 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1049 chptr->creationtime);
1051 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1054 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1055 msgq_append(&me, mb, " %s", modebuf);
1058 msgq_append(&me, mb, " %s", parabuf);
1062 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1064 * First find all opless members.
1065 * Run 2 times over all members, to group the members with
1066 * and without voice together.
1067 * Then run 2 times over all opped members (which are ordered
1068 * by op-level) to also group voice and non-voice together.
1070 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1074 if (flag_cnt < 2 && IsChanOp(member))
1077 * The first loop (to find all non-voice/op), we count the ops.
1078 * The second loop (to find all voiced non-ops), store the ops
1079 * in a dynamic array.
1084 opped_members[opped_members_index++] = member;
1086 /* Only handle the members with the flags that we are interested in. */
1087 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1089 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1090 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1092 full = 1; /* Make sure we continue after
1093 sending it so far */
1094 /* Ensure the new BURST line contains the current
1095 * ":mode", except when there is no mode yet. */
1096 new_mode = (flag_cnt > 0) ? 1 : 0;
1097 break; /* Do not add this member to this message */
1099 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1100 first = 0; /* From now on, use commas to add new nicks */
1103 * Do we have a nick with a new mode ?
1104 * Or are we starting a new BURST line?
1106 if (new_mode || !feat_oplevels)
1109 * This means we are at the _first_ member that has only
1110 * voice, or the first member that has only ops, or the
1111 * first member that has voice and ops (so we get here
1112 * at most three times, plus once for every start of
1113 * a continued BURST line where only these modes is current.
1114 * In the two cases where the current mode includes ops,
1115 * we need to add the _absolute_ value of the oplevel to the mode.
1117 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1120 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1122 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1124 /* append the absolute value of the oplevel */
1126 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1131 msgq_append(&me, mb, tbuf);
1134 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1137 * This can't be the first member of a (continued) BURST
1138 * message because then either flag_cnt == 0 or new_mode == 1
1139 * Now we need to append the incremental value of the oplevel.
1141 char tbuf[2 + MAXOPLEVELDIGITS];
1142 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1143 last_oplevel = member->oplevel;
1144 msgq_append(&me, mb, tbuf);
1147 /* Go to the next `member'. */
1149 member = member->next_member;
1151 member = opped_members[++opped_members_index];
1156 /* Point `member' at the start of the list again. */
1159 member = chptr->members;
1160 /* Now, after one loop, we know the number of ops and can
1161 * allocate the dynamic array with pointer to the ops. */
1162 opped_members = (struct Membership**)
1163 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1164 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1168 /* At the end of the second loop, sort the opped members with
1169 * increasing op-level, so that we will output them in the
1170 * correct order (and all op-level increments stay positive) */
1172 qsort(opped_members, number_of_ops,
1173 sizeof(struct Membership*), compare_member_oplevel);
1174 /* The third and fourth loop run only over the opped members. */
1175 member = opped_members[(opped_members_index = 0)];
1178 } /* loop over 0,+v,+o,+ov */
1182 /* Attach all bans, space seperated " :%ban ban ..." */
1183 for (first = 2; lp2; lp2 = lp2->next)
1185 len = strlen(lp2->value.ban.banstr);
1186 if (msgq_bufleft(mb) < len + 1 + first)
1187 /* The +1 stands for the added ' '.
1188 * The +first stands for the added ":%".
1194 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1195 lp2->value.ban.banstr);
1200 send_buffer(cptr, mb, 0); /* Send this message */
1202 } /* Continue when there was something
1203 that didn't fit (full==1) */
1205 MyFree(opped_members);
1206 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1207 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1208 chptr->creationtime, chptr->topic_time, chptr->topic);
1211 /** Canonify a mask.
1214 * @author Carlo Wood (Run),
1217 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1218 * When the user name or host name are too long (USERLEN and HOSTLEN
1219 * respectively) then they are cut off at the start with a '*'.
1221 * The following transformations are made:
1223 * 1) xxx -> nick!*@*
1224 * 2) xxx.xxx -> *!*\@host
1225 * 3) xxx\!yyy -> nick!user\@*
1226 * 4) xxx\@yyy -> *!user\@host
1227 * 5) xxx!yyy\@zzz -> nick!user\@host
1229 * @param mask The uncanonified mask.
1230 * @returns The updated mask in a static buffer.
1232 char *pretty_mask(char *mask)
1234 static char star[2] = { '*', 0 };
1235 static char retmask[NUH_BUFSIZE];
1236 char *last_dot = NULL;
1239 /* Case 1: default */
1244 /* Do a _single_ pass through the characters of the mask: */
1245 for (ptr = mask; *ptr; ++ptr)
1249 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1253 else if (*ptr == '@')
1255 /* Case 4: Found last '@' (without finding a '!' yet) */
1260 else if (*ptr == '.')
1262 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1272 /* Case 4 or 5: Found last '@' */
1278 if (user == star && last_dot)
1288 char *nick_end = (user != star) ? user - 1 : ptr;
1289 if (nick_end - nick > NICKLEN)
1295 char *user_end = (host != star) ? host - 1 : ptr;
1296 if (user_end - user > USERLEN)
1298 user = user_end - USERLEN;
1303 if (host != star && ptr - host > HOSTLEN)
1305 host = ptr - HOSTLEN;
1308 return make_nick_user_host(retmask, nick, user, host);
1311 /** send a banlist to a client for a channel
1313 * @param cptr Client to send the banlist to.
1314 * @param chptr Channel whose banlist to send.
1316 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1323 for (lp = chptr->banlist; lp; lp = lp->next)
1324 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1325 lp->value.ban.who, lp->value.ban.when);
1327 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1330 /** Check a key against a keyring.
1331 * We are now treating the key part of /join channellist key as a key
1332 * ring; that is, we try one key against the actual channel key, and if that
1333 * doesn't work, we try the next one, and so on. -Kev -Texaco
1334 * Returns: 0 on match, 1 otherwise
1335 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1337 * @param key Key to check
1338 * @param keyring Comma seperated list of keys
1340 * @returns True if the key was found and matches, false otherwise.
1342 static int compall(char *key, char *keyring)
1347 p1 = key; /* point to the key... */
1348 while (*p1 && *p1 == *keyring)
1349 { /* step through the key and ring until they
1355 if (!*p1 && (!*keyring || *keyring == ','))
1356 /* ok, if we're at the end of the and also at the end of one of the keys
1357 in the keyring, we have a match */
1360 if (!*keyring) /* if we're at the end of the key ring, there
1361 weren't any matches, so we return 1 */
1364 /* Not at the end of the key ring, so step
1365 through to the next key in the ring: */
1366 while (*keyring && *(keyring++) != ',');
1368 goto top; /* and check it against the key */
1371 /** Returns if a user can join a channel with a specific key.
1373 * @param sptr The client trying to join
1374 * @param chptr The channel to join
1375 * @param key The key to use
1377 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1378 * if the oper used the magic key, 0 if no error occured.
1380 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1382 int overrideJoin = 0;
1385 * Now a banned user CAN join if invited -- Nemesi
1386 * Now a user CAN escape channel limit if invited -- bfriendly
1387 * Now a user CAN escape anything if invited -- Isomer
1390 if (IsInvited(sptr, chptr))
1393 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1394 a HACK(4) notice will be sent if he would not have been supposed
1395 to join normally. */
1396 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1397 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1398 compall("OVERRIDE",key) == 0)
1399 overrideJoin = MAGIC_OPER_OVERRIDE;
1401 if (chptr->mode.mode & MODE_INVITEONLY)
1402 return overrideJoin + ERR_INVITEONLYCHAN;
1404 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1405 return overrideJoin + ERR_CHANNELISFULL;
1407 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1408 return overrideJoin + ERR_NEEDREGGEDNICK;
1410 if (is_banned(sptr, chptr, NULL))
1411 return overrideJoin + ERR_BANNEDFROMCHAN;
1414 * now using compall (above) to test against a whole key ring -Kev
1416 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1417 return overrideJoin + ERR_BADCHANNELKEY;
1420 return ERR_DONTCHEAT;
1425 /** Remove bells and commas from channel name
1427 * @param cn Channel name to clean, modified in place.
1429 void clean_channelname(char *cn)
1433 for (i = 0; cn[i]; i++) {
1434 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1438 if (IsChannelLower(cn[i])) {
1439 cn[i] = ToLower(cn[i]);
1445 if ((unsigned char)(cn[i]) == 0xd0)
1446 cn[i] = (char) 0xf0;
1452 /** Get a channel block, creating if necessary.
1453 * Get Channel block for chname (and allocate a new channel
1454 * block, if it didn't exists before).
1456 * @param cptr Client joining the channel.
1457 * @param chname The name of the channel to join.
1458 * @param flag set to CGT_CREATE to create the channel if it doesn't
1461 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1462 * wasn't specified or a pointer to the channel structure
1464 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1466 struct Channel *chptr;
1469 if (EmptyString(chname))
1472 len = strlen(chname);
1473 if (MyUser(cptr) && len > CHANNELLEN)
1476 *(chname + CHANNELLEN) = '\0';
1478 if ((chptr = FindChannel(chname)))
1480 if (flag == CGT_CREATE)
1482 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1484 ++UserStats.channels;
1485 memset(chptr, 0, sizeof(struct Channel));
1486 strcpy(chptr->chname, chname);
1487 if (GlobalChannelList)
1488 GlobalChannelList->prev = chptr;
1490 chptr->next = GlobalChannelList;
1491 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1492 GlobalChannelList = chptr;
1498 /** invite a user to a channel.
1500 * Adds an invite for a user to a channel. Limits the number of invites
1501 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1503 * @param cptr The client to be invited.
1504 * @param chptr The channel to be invited to.
1506 void add_invite(struct Client *cptr, struct Channel *chptr)
1508 struct SLink *inv, **tmp;
1510 del_invite(cptr, chptr);
1512 * Delete last link in chain if the list is max length
1514 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1515 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1516 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1518 * Add client to channel invite list
1521 inv->value.cptr = cptr;
1522 inv->next = chptr->invites;
1523 chptr->invites = inv;
1525 * Add channel to the end of the client invite list
1527 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1529 inv->value.chptr = chptr;
1532 (cli_user(cptr))->invites++;
1535 /** Delete an invite
1536 * Delete Invite block from channel invite list and client invite list
1538 * @param cptr Client pointer
1539 * @param chptr Channel pointer
1541 void del_invite(struct Client *cptr, struct Channel *chptr)
1543 struct SLink **inv, *tmp;
1545 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1546 if (tmp->value.cptr == cptr)
1551 (cli_user(cptr))->invites--;
1555 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1556 if (tmp->value.chptr == chptr)
1565 /** @page zombie Explaination of Zombies
1573 * X --a--> A --b--> B --d--> D
1578 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1579 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1581 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1582 * Remove the user immediately when no users are left on the channel.
1583 * b) On server B : remove the user (who/lp) from the channel, send a
1584 * PART upstream (to A) and pass on the KICK.
1585 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1586 * channel, and pass on the KICK.
1587 * d) On server D : remove the user (who/lp) from the channel, and pass on
1591 * - Setting the ZOMBIE flag never hurts, we either remove the
1592 * client after that or we don't.
1593 * - The KICK message was already passed on, as should be in all cases.
1594 * - `who' is removed in all cases except case a) when users are left.
1595 * - A PART is only sent upstream in case b).
1601 * 1 --- 2 --- 3 --- 4 --- 5
1606 * We also need to turn 'who' into a zombie on servers 1 and 6,
1607 * because a KICK from 'who' (kicking someone else in that direction)
1608 * can arrive there afterwards - which should not be bounced itself.
1609 * Therefore case a) also applies for servers 1 and 6.
1614 /** Turn a user on a channel into a zombie
1615 * This function turns a user into a zombie (see \ref zombie)
1617 * @param member The structure representing this user on this channel.
1618 * @param who The client that is being kicked.
1619 * @param cptr The connection the kick came from.
1620 * @param sptr The client that is doing the kicking.
1621 * @param chptr The channel the user is being kicked from.
1623 void make_zombie(struct Membership* member, struct Client* who,
1624 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1626 assert(0 != member);
1631 /* Default for case a): */
1634 /* Case b) or c) ?: */
1635 if (MyUser(who)) /* server 4 */
1637 if (IsServer(cptr)) /* Case b) ? */
1638 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1639 remove_user_from_channel(who, chptr);
1642 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1644 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1645 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1646 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1648 remove_user_from_channel(who, chptr);
1653 /* Case a) (servers 1, 2, 3 and 6) */
1654 if (channel_all_zombies(chptr))
1655 remove_user_from_channel(who, chptr);
1657 /* XXX Can't actually call Debug here; if the channel is all zombies,
1658 * chptr will no longer exist when we get here.
1659 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1663 /** returns the number of zombies on a channel
1664 * @param chptr Channel to count zombies in.
1666 * @returns The number of zombies on the channel.
1668 int number_of_zombies(struct Channel *chptr)
1670 struct Membership* member;
1674 for (member = chptr->members; member; member = member->next_member) {
1675 if (IsZombie(member))
1681 /** Concatenate some strings together.
1682 * This helper function builds an argument string in strptr, consisting
1683 * of the original string, a space, and str1 and str2 concatenated (if,
1684 * of course, str2 is not NULL)
1686 * @param strptr The buffer to concatenate into
1687 * @param strptr_i modified offset to the position to modify
1688 * @param str1 The string to contatenate from.
1689 * @param str2 The second string to contatenate from.
1690 * @param c Charactor to seperate the string from str1 and str2.
1693 build_string(char *strptr, int *strptr_i, const char *str1,
1694 const char *str2, char c)
1697 strptr[(*strptr_i)++] = c;
1700 strptr[(*strptr_i)++] = *(str1++);
1704 strptr[(*strptr_i)++] = *(str2++);
1706 strptr[(*strptr_i)] = '\0';
1709 /** Flush out the modes
1710 * This is the workhorse of our ModeBuf suite; this actually generates the
1711 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1713 * @param mbuf The mode buffer to flush
1714 * @param all If true, flush all modes, otherwise leave partial modes in the
1720 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1722 /* we only need the flags that don't take args right now */
1723 static int flags[] = {
1724 /* MODE_CHANOP, 'o', */
1725 /* MODE_VOICE, 'v', */
1728 MODE_MODERATED, 'm',
1729 MODE_TOPICLIMIT, 't',
1730 MODE_INVITEONLY, 'i',
1731 MODE_NOPRIVMSGS, 'n',
1734 MODE_WASDELJOINS, 'd',
1735 /* MODE_KEY, 'k', */
1736 /* MODE_BAN, 'b', */
1738 /* MODE_APASS, 'A', */
1739 /* MODE_UPASS, 'U', */
1745 struct Client *app_source; /* where the MODE appears to come from */
1747 char addbuf[20]; /* accumulates +psmtin, etc. */
1749 char rembuf[20]; /* accumulates -psmtin, etc. */
1751 char *bufptr; /* we make use of indirection to simplify the code */
1754 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1756 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1758 char *strptr; /* more indirection to simplify the code */
1761 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1764 char limitbuf[20]; /* convert limits to strings */
1766 unsigned int limitdel = MODE_LIMIT;
1770 /* If the ModeBuf is empty, we have nothing to do */
1771 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1774 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1776 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1779 app_source = mbuf->mb_source;
1782 * Account for user we're bouncing; we have to get it in on the first
1783 * bounced MODE, or we could have problems
1785 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1786 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1788 /* Calculate the simple flags */
1789 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1790 if (*flag_p & mbuf->mb_add)
1791 addbuf[addbuf_i++] = flag_p[1];
1792 else if (*flag_p & mbuf->mb_rem)
1793 rembuf[rembuf_i++] = flag_p[1];
1796 /* Now go through the modes with arguments... */
1797 for (i = 0; i < mbuf->mb_count; i++) {
1798 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1800 bufptr_i = &addbuf_i;
1803 bufptr_i = &rembuf_i;
1806 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1807 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1809 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1810 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1812 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1813 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1815 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1816 tmp = strlen(MB_STRING(mbuf, i));
1818 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1819 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1822 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1834 bufptr[(*bufptr_i)++] = mode_char;
1835 totalbuflen -= tmp + 1;
1837 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1838 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1839 strlen(MB_STRING(mbuf, i)));
1841 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1842 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1844 bufptr[(*bufptr_i)++] = 'k';
1845 totalbuflen -= tmp + 1;
1847 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1848 /* if it's a limit, we also format the number */
1849 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1851 tmp = strlen(limitbuf);
1853 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1854 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1856 bufptr[(*bufptr_i)++] = 'l';
1857 totalbuflen -= tmp + 1;
1862 /* terminate the mode strings */
1863 addbuf[addbuf_i] = '\0';
1864 rembuf[rembuf_i] = '\0';
1866 /* If we're building a user visible MODE or HACK... */
1867 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1868 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1869 MODEBUF_DEST_LOG)) {
1870 /* Set up the parameter strings */
1876 for (i = 0; i < mbuf->mb_count; i++) {
1877 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1880 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1882 strptr_i = &addstr_i;
1885 strptr_i = &remstr_i;
1888 /* deal with clients... */
1889 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1890 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1892 /* deal with bans... */
1893 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1894 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1896 /* deal with keys... */
1897 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1898 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1899 "*" : MB_STRING(mbuf, i), 0, ' ');
1901 /* deal with invisible passwords */
1902 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1903 build_string(strptr, strptr_i, "*", 0, ' ');
1906 * deal with limit; note we cannot include the limit parameter if we're
1909 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1910 (MODE_ADD | MODE_LIMIT))
1911 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1914 /* send the messages off to their destination */
1915 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1916 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1918 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1919 mbuf->mb_source : app_source),
1920 mbuf->mb_channel->chname,
1921 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1922 addbuf, remstr, addstr,
1923 mbuf->mb_channel->creationtime);
1925 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1926 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1927 "%s%s%s%s%s%s [%Tu]",
1928 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1929 mbuf->mb_source : app_source),
1930 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1931 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1932 mbuf->mb_channel->creationtime);
1934 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1935 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1937 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1938 mbuf->mb_source : app_source),
1939 mbuf->mb_channel->chname,
1940 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1941 addbuf, remstr, addstr,
1942 mbuf->mb_channel->creationtime);
1944 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1945 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1946 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1947 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1948 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1950 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1951 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1952 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1953 rembuf_i ? "-" : "", rembuf,
1954 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1957 /* Now are we supposed to propagate to other servers? */
1958 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1959 /* set up parameter string */
1966 * limit is supressed if we're removing it; we have to figure out which
1967 * direction is the direction for it to be removed, though...
1969 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1971 for (i = 0; i < mbuf->mb_count; i++) {
1972 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1975 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1977 strptr_i = &addstr_i;
1980 strptr_i = &remstr_i;
1983 /* deal with modes that take clients */
1984 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1985 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1987 /* deal with modes that take strings */
1988 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1989 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1992 * deal with the limit. Logic here is complicated; if HACK2 is set,
1993 * we're bouncing the mode, so sense is reversed, and we have to
1994 * include the original limit if it looks like it's being removed
1996 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1997 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2000 /* we were told to deop the source */
2001 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2002 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2003 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2004 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2006 /* mark that we've done this, so we don't do it again */
2007 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2010 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2011 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2012 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2013 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2014 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2015 addbuf, remstr, addstr);
2016 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2018 * If HACK2 was set, we're bouncing; we send the MODE back to the
2019 * connection we got it from with the senses reversed and a TS of 0;
2022 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2023 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2024 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2025 mbuf->mb_channel->creationtime);
2028 * We're propagating a normal MODE command to the rest of the network;
2029 * we send the actual channel TS unless this is a HACK3 or a HACK4
2031 if (IsServer(mbuf->mb_source))
2032 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2033 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2034 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2035 addbuf, remstr, addstr,
2036 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2037 mbuf->mb_channel->creationtime);
2039 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2040 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2041 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2042 addbuf, remstr, addstr);
2046 /* We've drained the ModeBuf... */
2051 /* reinitialize the mode-with-arg slots */
2052 for (i = 0; i < MAXMODEPARAMS; i++) {
2053 /* If we saved any, pack them down */
2054 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2055 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2056 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2058 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2060 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2061 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2063 MB_TYPE(mbuf, i) = 0;
2064 MB_UINT(mbuf, i) = 0;
2067 /* If we're supposed to flush it all, do so--all hail tail recursion */
2068 if (all && mbuf->mb_count)
2069 return modebuf_flush_int(mbuf, 1);
2074 /** Initialise a modebuf
2075 * This routine just initializes a ModeBuf structure with the information
2076 * needed and the options given.
2078 * @param mbuf The mode buffer to initialise.
2079 * @param source The client that is performing the mode.
2081 * @param chan The channel that the mode is being performed upon.
2085 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2086 struct Client *connect, struct Channel *chan, unsigned int dest)
2091 assert(0 != source);
2095 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2099 mbuf->mb_source = source;
2100 mbuf->mb_connect = connect;
2101 mbuf->mb_channel = chan;
2102 mbuf->mb_dest = dest;
2105 /* clear each mode-with-parameter slot */
2106 for (i = 0; i < MAXMODEPARAMS; i++) {
2107 MB_TYPE(mbuf, i) = 0;
2108 MB_UINT(mbuf, i) = 0;
2112 /** Append a new mode to a modebuf
2113 * This routine simply adds modes to be added or deleted; do a binary OR
2114 * with either MODE_ADD or MODE_DEL
2116 * @param mbuf Mode buffer
2117 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2120 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2123 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2125 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2126 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2127 MODE_DELJOINS | MODE_WASDELJOINS);
2129 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2132 if (mode & MODE_ADD) {
2133 mbuf->mb_rem &= ~mode;
2134 mbuf->mb_add |= mode;
2136 mbuf->mb_add &= ~mode;
2137 mbuf->mb_rem |= mode;
2141 /** Append a mode that takes an int argument to the modebuf
2143 * This routine adds a mode to be added or deleted that takes a unsigned
2144 * int parameter; mode may *only* be the relevant mode flag ORed with one
2145 * of MODE_ADD or MODE_DEL
2147 * @param mbuf The mode buffer to append to.
2148 * @param mode The mode to append.
2149 * @param uint The argument to the mode.
2152 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2155 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2157 if (mode == (MODE_LIMIT | MODE_DEL)) {
2158 mbuf->mb_rem |= mode;
2161 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2162 MB_UINT(mbuf, mbuf->mb_count) = uint;
2164 /* when we've reached the maximal count, flush the buffer */
2165 if (++mbuf->mb_count >=
2166 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2167 modebuf_flush_int(mbuf, 0);
2170 /** append a string mode
2171 * This routine adds a mode to be added or deleted that takes a string
2172 * parameter; mode may *only* be the relevant mode flag ORed with one of
2173 * MODE_ADD or MODE_DEL
2175 * @param mbuf The mode buffer to append to.
2176 * @param mode The mode to append.
2177 * @param string The string parameter to append.
2178 * @param free If the string should be free'd later.
2181 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2185 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2187 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2188 MB_STRING(mbuf, mbuf->mb_count) = string;
2190 /* when we've reached the maximal count, flush the buffer */
2191 if (++mbuf->mb_count >=
2192 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2193 modebuf_flush_int(mbuf, 0);
2196 /** Append a mode on a client to a modebuf.
2197 * This routine adds a mode to be added or deleted that takes a client
2198 * parameter; mode may *only* be the relevant mode flag ORed with one of
2199 * MODE_ADD or MODE_DEL
2201 * @param mbuf The modebuf to append the mode to.
2202 * @param mode The mode to append.
2203 * @param client The client argument to append.
2206 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2207 struct Client *client)
2210 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2212 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2213 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2215 /* when we've reached the maximal count, flush the buffer */
2216 if (++mbuf->mb_count >=
2217 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2218 modebuf_flush_int(mbuf, 0);
2221 /** The exported binding for modebuf_flush()
2223 * @param mbuf The mode buffer to flush.
2225 * @see modebuf_flush_int()
2228 modebuf_flush(struct ModeBuf *mbuf)
2230 struct Membership *memb;
2232 /* Check if MODE_WASDELJOINS should be set */
2233 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2234 && (mbuf->mb_rem & MODE_DELJOINS)) {
2235 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2236 if (IsDelayedJoin(memb)) {
2237 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2238 mbuf->mb_add |= MODE_WASDELJOINS;
2239 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2245 return modebuf_flush_int(mbuf, 1);
2248 /* This extracts the simple modes contained in mbuf
2250 * @param mbuf The mode buffer to extract the modes from.
2251 * @param buf The string buffer to write the modes into.
2254 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2256 static int flags[] = {
2257 /* MODE_CHANOP, 'o', */
2258 /* MODE_VOICE, 'v', */
2261 MODE_MODERATED, 'm',
2262 MODE_TOPICLIMIT, 't',
2263 MODE_INVITEONLY, 'i',
2264 MODE_NOPRIVMSGS, 'n',
2268 /* MODE_BAN, 'b', */
2275 int i, bufpos = 0, len;
2277 char *key = 0, limitbuf[20];
2278 char *apass = 0, *upass = 0;
2287 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2288 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2289 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2291 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2292 key = MB_STRING(mbuf, i);
2293 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2294 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2295 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2296 upass = MB_STRING(mbuf, i);
2297 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2298 apass = MB_STRING(mbuf, i);
2305 buf[bufpos++] = '+'; /* start building buffer */
2307 for (flag_p = flags; flag_p[0]; flag_p += 2)
2309 buf[bufpos++] = flag_p[1];
2311 for (i = 0, len = bufpos; i < len; i++) {
2313 build_string(buf, &bufpos, key, 0, ' ');
2314 else if (buf[i] == 'l')
2315 build_string(buf, &bufpos, limitbuf, 0, ' ');
2316 else if (buf[i] == 'U')
2317 build_string(buf, &bufpos, upass, 0, ' ');
2318 else if (buf[i] == 'A')
2319 build_string(buf, &bufpos, apass, 0, ' ');
2327 /** Simple function to invalidate bans
2329 * This function sets all bans as being valid.
2331 * @param chan The channel to operate on.
2334 mode_ban_invalidate(struct Channel *chan)
2336 struct Membership *member;
2338 for (member = chan->members; member; member = member->next_member)
2339 ClearBanValid(member);
2342 /** Simple function to drop invite structures
2344 * Remove all the invites on the channel.
2346 * @param chan Channel to remove invites from.
2350 mode_invite_clear(struct Channel *chan)
2352 while (chan->invites)
2353 del_invite(chan->invites->value.cptr, chan);
2356 /* What we've done for mode_parse so far... */
2357 #define DONE_LIMIT 0x01 /**< We've set the limit */
2358 #define DONE_KEY 0x02 /**< We've set the key */
2359 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2360 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2361 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2362 #define DONE_UPASS 0x20 /**< We've set user pass */
2363 #define DONE_APASS 0x40 /**< We've set admin pass */
2366 struct ModeBuf *mbuf;
2367 struct Client *cptr;
2368 struct Client *sptr;
2369 struct Channel *chptr;
2370 struct Membership *member;
2381 struct SLink banlist[MAXPARA];
2384 struct Client *client;
2385 } cli_change[MAXPARA];
2388 /** Helper function to send "Not oper" or "Not member" messages
2389 * Here's a helper function to deal with sending along "Not oper" or
2390 * "Not member" messages
2392 * @param state Parsing State object
2395 send_notoper(struct ParseState *state)
2397 if (state->done & DONE_NOTOPER)
2400 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2401 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2403 state->done |= DONE_NOTOPER;
2407 * Helper function to convert limits
2409 * @param state Parsing state object.
2413 mode_parse_limit(struct ParseState *state, int *flag_p)
2415 unsigned int t_limit;
2417 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2418 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2421 if (state->parc <= 0) { /* warn if not enough args */
2422 if (MyUser(state->sptr))
2423 need_more_params(state->sptr, "MODE +l");
2427 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2431 if ((int)t_limit<0) /* don't permit a negative limit */
2434 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2435 (!t_limit || t_limit == state->chptr->mode.limit))
2438 t_limit = state->chptr->mode.limit;
2440 /* If they're not an oper, they can't change modes */
2441 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2442 send_notoper(state);
2446 /* Can't remove a limit that's not there */
2447 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2450 /* Skip if this is a burst and a lower limit than this is set already */
2451 if ((state->flags & MODE_PARSE_BURST) &&
2452 (state->chptr->mode.mode & flag_p[0]) &&
2453 (state->chptr->mode.limit < t_limit))
2456 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2458 state->done |= DONE_LIMIT;
2463 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2465 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2466 if (state->dir & MODE_ADD) {
2467 state->chptr->mode.mode |= flag_p[0];
2468 state->chptr->mode.limit = t_limit;
2470 state->chptr->mode.mode &= ~flag_p[0];
2471 state->chptr->mode.limit = 0;
2477 * Helper function to convert keys
2480 mode_parse_key(struct ParseState *state, int *flag_p)
2485 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2488 if (state->parc <= 0) { /* warn if not enough args */
2489 if (MyUser(state->sptr))
2490 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2495 t_str = state->parv[state->args_used++]; /* grab arg */
2499 /* If they're not an oper, they can't change modes */
2500 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2501 send_notoper(state);
2505 if (state->done & DONE_KEY) /* allow key to be set only once */
2507 state->done |= DONE_KEY;
2511 /* clean up the key string */
2513 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2517 if (!*t_str) { /* warn if empty */
2518 if (MyUser(state->sptr))
2519 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2527 /* Skip if this is a burst, we have a key already and the new key is
2528 * after the old one alphabetically */
2529 if ((state->flags & MODE_PARSE_BURST) &&
2530 *(state->chptr->mode.key) &&
2531 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2534 /* can't add a key if one is set, nor can one remove the wrong key */
2535 if (!(state->flags & MODE_PARSE_FORCE))
2536 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2537 (state->dir == MODE_DEL &&
2538 ircd_strcmp(state->chptr->mode.key, t_str))) {
2539 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2543 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2544 !ircd_strcmp(state->chptr->mode.key, t_str))
2545 return; /* no key change */
2547 if (state->flags & MODE_PARSE_BOUNCE) {
2548 if (*state->chptr->mode.key) /* reset old key */
2549 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2550 state->chptr->mode.key, 0);
2551 else /* remove new bogus key */
2552 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2553 } else /* send new key */
2554 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2556 if (state->flags & MODE_PARSE_SET) {
2557 if (state->dir == MODE_ADD) /* set the new key */
2558 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2559 else /* remove the old key */
2560 *state->chptr->mode.key = '\0';
2565 * Helper function to convert user passes
2568 mode_parse_upass(struct ParseState *state, int *flag_p)
2573 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2576 if (state->parc <= 0) { /* warn if not enough args */
2577 if (MyUser(state->sptr))
2578 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2583 t_str = state->parv[state->args_used++]; /* grab arg */
2587 /* If they're not an oper, they can't change modes */
2588 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2589 send_notoper(state);
2593 /* If a non-service user is trying to force it, refuse. */
2594 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2595 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2596 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2600 /* If they are not the channel manager, they are not allowed to change it */
2601 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2602 if (*state->chptr->mode.apass) {
2603 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2604 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2606 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2607 "Re-create the channel. The channel must be *empty* for",
2608 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2609 "before it can be recreated.");
2614 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2616 state->done |= DONE_UPASS;
2618 t_len = PASSLEN + 1;
2620 /* clean up the upass string */
2622 while (*++s > ' ' && *s != ':' && --t_len)
2626 if (!*t_str) { /* warn if empty */
2627 if (MyUser(state->sptr))
2628 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2636 if (!(state->flags & MODE_PARSE_FORCE))
2637 /* can't add the upass while apass is not set */
2638 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2639 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2642 /* can't add a upass if one is set, nor can one remove the wrong upass */
2643 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2644 (state->dir == MODE_DEL &&
2645 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2646 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2650 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2651 !ircd_strcmp(state->chptr->mode.upass, t_str))
2652 return; /* no upass change */
2654 if (state->flags & MODE_PARSE_BOUNCE) {
2655 if (*state->chptr->mode.upass) /* reset old upass */
2656 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2657 state->chptr->mode.upass, 0);
2658 else /* remove new bogus upass */
2659 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2660 } else /* send new upass */
2661 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2663 if (state->flags & MODE_PARSE_SET) {
2664 if (state->dir == MODE_ADD) /* set the new upass */
2665 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2666 else /* remove the old upass */
2667 *state->chptr->mode.upass = '\0';
2672 * Helper function to convert admin passes
2675 mode_parse_apass(struct ParseState *state, int *flag_p)
2680 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2683 if (state->parc <= 0) { /* warn if not enough args */
2684 if (MyUser(state->sptr))
2685 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2690 t_str = state->parv[state->args_used++]; /* grab arg */
2694 /* If they're not an oper, they can't change modes */
2695 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2696 send_notoper(state);
2700 /* If a non-service user is trying to force it, refuse. */
2701 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2702 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2703 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2707 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2708 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2709 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2713 /* If they are not the channel manager, they are not allowed to change it */
2714 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2715 if (*state->chptr->mode.apass) {
2716 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2717 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2719 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2720 "Re-create the channel. The channel must be *empty* for",
2721 "at least a whole minute", "before it can be recreated.");
2726 if (state->done & DONE_APASS) /* allow apass to be set only once */
2728 state->done |= DONE_APASS;
2730 t_len = PASSLEN + 1;
2732 /* clean up the apass string */
2734 while (*++s > ' ' && *s != ':' && --t_len)
2738 if (!*t_str) { /* warn if empty */
2739 if (MyUser(state->sptr))
2740 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2748 if (!(state->flags & MODE_PARSE_FORCE)) {
2749 /* can't remove the apass while upass is still set */
2750 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2751 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2754 /* can't add an apass if one is set, nor can one remove the wrong apass */
2755 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2756 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2757 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2762 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2763 !ircd_strcmp(state->chptr->mode.apass, t_str))
2764 return; /* no apass change */
2766 if (state->flags & MODE_PARSE_BOUNCE) {
2767 if (*state->chptr->mode.apass) /* reset old apass */
2768 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2769 state->chptr->mode.apass, 0);
2770 else /* remove new bogus apass */
2771 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2772 } else /* send new apass */
2773 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2775 if (state->flags & MODE_PARSE_SET) {
2776 if (state->dir == MODE_ADD) { /* set the new apass */
2777 /* Make it VERY clear to the user that this is a one-time password */
2778 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2779 if (MyUser(state->sptr)) {
2780 send_reply(state->sptr, RPL_APASSWARN,
2781 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2782 "Are you SURE you want to use this as Admin password? ",
2783 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2784 send_reply(state->sptr, RPL_APASSWARN,
2785 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2786 "\" to remove the password and then immediately set a new one. "
2787 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2788 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2789 "Now set the channel user password (+u).");
2791 } else { /* remove the old apass */
2792 *state->chptr->mode.apass = '\0';
2793 if (MyUser(state->sptr))
2794 send_reply(state->sptr, RPL_APASSWARN,
2795 "WARNING: You removed the channel Admin password MODE (+A). ",
2796 "If you would disconnect or leave the channel without setting a new password then you will ",
2797 "not be able to set it again and lose ownership of this channel! ",
2798 "SET A NEW PASSWORD NOW!", "");
2804 * Helper function to convert bans
2807 mode_parse_ban(struct ParseState *state, int *flag_p)
2810 struct SLink *ban, *newban = 0;
2812 if (state->parc <= 0) { /* Not enough args, send ban list */
2813 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2814 send_ban_list(state->sptr, state->chptr);
2815 state->done |= DONE_BANLIST;
2821 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2824 t_str = state->parv[state->args_used++]; /* grab arg */
2828 /* If they're not an oper, they can't change modes */
2829 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2830 send_notoper(state);
2834 if ((s = strchr(t_str, ' ')))
2837 if (!*t_str || *t_str == ':') { /* warn if empty */
2838 if (MyUser(state->sptr))
2839 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2844 t_str = collapse(pretty_mask(t_str));
2846 /* remember the ban for the moment... */
2847 if (state->dir == MODE_ADD) {
2848 newban = state->banlist + (state->numbans++);
2851 DupString(newban->value.ban.banstr, t_str);
2852 newban->value.ban.who = cli_name(state->sptr);
2853 newban->value.ban.when = TStime();
2855 newban->flags = CHFL_BAN | MODE_ADD;
2857 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2858 newban->flags |= CHFL_BAN_IPMASK;
2861 if (!state->chptr->banlist) {
2862 state->chptr->banlist = newban; /* add our ban with its flags */
2863 state->done |= DONE_BANCLEAN;
2867 /* Go through all bans */
2868 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2869 /* first, clean the ban flags up a bit */
2870 if (!(state->done & DONE_BANCLEAN))
2871 /* Note: We're overloading *lots* of bits here; be careful! */
2872 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2876 * MODE_ADD - Ban was added; if we're bouncing modes,
2877 * then we'll remove it below; otherwise,
2878 * we'll have to allocate a real ban
2880 * MODE_DEL - Ban was marked for deletion; if we're
2881 * bouncing modes, we'll have to re-add it,
2882 * otherwise, we'll have to remove it
2884 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2885 * with a ban already set; if we're
2886 * bouncing modes, we'll have to bounce
2887 * this one; otherwise, we'll just ignore
2888 * it when we process added bans
2891 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2892 ban->flags |= MODE_DEL; /* delete one ban */
2894 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2896 } else if (state->dir == MODE_ADD) {
2897 /* if the ban already exists, don't worry about it */
2898 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2899 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2900 MyFree(newban->value.ban.banstr); /* stopper a leak */
2901 state->numbans--; /* deallocate last ban */
2902 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2904 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2905 if (!(ban->flags & MODE_DEL))
2906 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2907 } else if (!mmatch(t_str, ban->value.ban.banstr))
2908 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2910 if (!ban->next && (newban->flags & MODE_ADD))
2912 ban->next = newban; /* add our ban with its flags */
2913 break; /* get out of loop */
2917 state->done |= DONE_BANCLEAN;
2921 * This is the bottom half of the ban processor
2924 mode_process_bans(struct ParseState *state)
2926 struct SLink *ban, *newban, *prevban, *nextban;
2932 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2934 banlen = strlen(ban->value.ban.banstr);
2936 nextban = ban->next;
2938 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2940 prevban->next = 0; /* Break the list; ban isn't a real ban */
2942 state->chptr->banlist = 0;
2947 MyFree(ban->value.ban.banstr);
2950 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2951 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2952 ban->value.ban.banstr,
2953 state->flags & MODE_PARSE_SET);
2955 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2956 if (prevban) /* clip it out of the list... */
2957 prevban->next = ban->next;
2959 state->chptr->banlist = ban->next;
2964 MyFree(ban->value.ban.who);
2968 continue; /* next ban; keep prevban like it is */
2970 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2971 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2973 prevban->next = 0; /* Break the list; ban isn't a real ban */
2975 state->chptr->banlist = 0;
2977 /* If we're supposed to ignore it, do so. */
2978 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2979 !(state->flags & MODE_PARSE_BOUNCE)) {
2983 MyFree(ban->value.ban.banstr);
2985 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2986 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2987 count > feature_int(FEAT_MAXBANS))) {
2988 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2989 ban->value.ban.banstr);
2993 MyFree(ban->value.ban.banstr);
2995 /* add the ban to the buffer */
2996 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2997 ban->value.ban.banstr,
2998 !(state->flags & MODE_PARSE_SET));
3000 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3001 newban = make_link();
3002 newban->value.ban.banstr = ban->value.ban.banstr;
3003 DupString(newban->value.ban.who, ban->value.ban.who);
3004 newban->value.ban.when = ban->value.ban.when;
3005 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
3007 newban->next = state->chptr->banlist; /* and link it in */
3008 state->chptr->banlist = newban;
3017 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3019 if (changed) /* if we changed the ban list, we must invalidate the bans */
3020 mode_ban_invalidate(state->chptr);
3024 * Helper function to process client changes
3027 mode_parse_client(struct ParseState *state, int *flag_p)
3030 struct Client *acptr;
3033 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3036 if (state->parc <= 0) /* return if not enough args */
3039 t_str = state->parv[state->args_used++]; /* grab arg */
3043 /* If they're not an oper, they can't change modes */
3044 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3045 send_notoper(state);
3049 if (MyUser(state->sptr)) /* find client we're manipulating */
3050 acptr = find_chasing(state->sptr, t_str, NULL);
3052 acptr = findNUser(t_str);
3055 return; /* find_chasing() already reported an error to the user */
3057 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3058 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3059 state->cli_change[i].flag & flag_p[0]))
3060 break; /* found a slot */
3062 /* Store what we're doing to them */
3063 state->cli_change[i].flag = state->dir | flag_p[0];
3064 state->cli_change[i].client = acptr;
3068 * Helper function to process the changed client list
3071 mode_process_clients(struct ParseState *state)
3074 struct Membership *member;
3076 for (i = 0; state->cli_change[i].flag; i++) {
3077 assert(0 != state->cli_change[i].client);
3079 /* look up member link */
3080 if (!(member = find_member_link(state->chptr,
3081 state->cli_change[i].client)) ||
3082 (MyUser(state->sptr) && IsZombie(member))) {
3083 if (MyUser(state->sptr))
3084 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3085 cli_name(state->cli_change[i].client),
3086 state->chptr->chname);
3090 if ((state->cli_change[i].flag & MODE_ADD &&
3091 (state->cli_change[i].flag & member->status)) ||
3092 (state->cli_change[i].flag & MODE_DEL &&
3093 !(state->cli_change[i].flag & member->status)))
3094 continue; /* no change made, don't do anything */
3096 /* see if the deop is allowed */
3097 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3098 (MODE_DEL | MODE_CHANOP)) {
3099 /* prevent +k users from being deopped */
3100 if (IsChannelService(state->cli_change[i].client)) {
3101 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3102 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3104 (IsServer(state->sptr) ? cli_name(state->sptr) :
3105 cli_name((cli_user(state->sptr))->server)));
3107 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3108 send_reply(state->sptr, ERR_ISCHANSERVICE,
3109 cli_name(state->cli_change[i].client),
3110 state->chptr->chname);
3115 /* check deop for local user */
3116 if (MyUser(state->sptr)) {
3118 /* don't allow local opers to be deopped on local channels */
3119 if (state->cli_change[i].client != state->sptr &&
3120 IsLocalChannel(state->chptr->chname) &&
3121 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3122 send_reply(state->sptr, ERR_ISOPERLCHAN,
3123 cli_name(state->cli_change[i].client),
3124 state->chptr->chname);
3128 if (feature_bool(FEAT_OPLEVELS)) {
3129 /* don't allow to deop members with an op level that is <= our own level */
3130 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3132 && OpLevel(member) <= OpLevel(state->member)) {
3133 int equal = (OpLevel(member) == OpLevel(state->member));
3134 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3135 cli_name(state->cli_change[i].client),
3136 state->chptr->chname,
3137 OpLevel(state->member), OpLevel(member),
3138 "deop", equal ? "the same" : "a higher");
3145 /* set op-level of member being opped */
3146 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3147 (MODE_ADD | MODE_CHANOP)) {
3148 /* If on a channel with upass set, someone with level x gives ops to someone else,
3149 then that person gets level x-1. On other channels, where upass is not set,
3150 the level stays the same. */
3151 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3152 /* Someone being opped by a server gets op-level 0 */
3153 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3154 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3157 /* actually effect the change */
3158 if (state->flags & MODE_PARSE_SET) {
3159 if (state->cli_change[i].flag & MODE_ADD) {
3160 if (IsDelayedJoin(member))
3161 RevealDelayedJoin(member);
3162 member->status |= (state->cli_change[i].flag &
3163 (MODE_CHANOP | MODE_VOICE));
3164 if (state->cli_change[i].flag & MODE_CHANOP)
3165 ClearDeopped(member);
3167 member->status &= ~(state->cli_change[i].flag &
3168 (MODE_CHANOP | MODE_VOICE));
3171 /* accumulate the change */
3172 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3173 state->cli_change[i].client);
3174 } /* for (i = 0; state->cli_change[i].flags; i++) */
3178 * Helper function to process the simple modes
3181 mode_parse_mode(struct ParseState *state, int *flag_p)
3183 /* If they're not an oper, they can't change modes */
3184 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3185 send_notoper(state);
3192 if (state->dir == MODE_ADD) {
3193 state->add |= flag_p[0];
3194 state->del &= ~flag_p[0];
3196 if (flag_p[0] & MODE_SECRET) {
3197 state->add &= ~MODE_PRIVATE;
3198 state->del |= MODE_PRIVATE;
3199 } else if (flag_p[0] & MODE_PRIVATE) {
3200 state->add &= ~MODE_SECRET;
3201 state->del |= MODE_SECRET;
3203 if (flag_p[0] & MODE_DELJOINS) {
3204 state->add &= ~MODE_WASDELJOINS;
3205 state->del |= MODE_WASDELJOINS;
3208 state->add &= ~flag_p[0];
3209 state->del |= flag_p[0];
3212 assert(0 == (state->add & state->del));
3213 assert((MODE_SECRET | MODE_PRIVATE) !=
3214 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3218 * This routine is intended to parse MODE or OPMODE commands and effect the
3219 * changes (or just build the bounce buffer). We pass the starting offset
3223 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3224 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3225 struct Membership* member)
3227 static int chan_flags[] = {
3232 MODE_MODERATED, 'm',
3233 MODE_TOPICLIMIT, 't',
3234 MODE_INVITEONLY, 'i',
3235 MODE_NOPRIVMSGS, 'n',
3249 unsigned int t_mode;
3251 struct ParseState state;
3262 state.chptr = chptr;
3263 state.member = member;
3266 state.flags = flags;
3267 state.dir = MODE_ADD;
3271 state.args_used = 0;
3272 state.max_args = MAXMODEPARAMS;
3275 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3276 state.banlist[i].next = 0;
3277 state.banlist[i].value.ban.banstr = 0;
3278 state.banlist[i].value.ban.who = 0;
3279 state.banlist[i].value.ban.when = 0;
3280 state.banlist[i].flags = 0;
3281 state.cli_change[i].flag = 0;
3282 state.cli_change[i].client = 0;
3285 modestr = state.parv[state.args_used++];
3289 for (; *modestr; modestr++) {
3290 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3291 if (flag_p[1] == *modestr)
3294 if (!flag_p[0]) { /* didn't find it? complain and continue */
3295 if (MyUser(state.sptr))
3296 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3301 case '+': /* switch direction to MODE_ADD */
3302 case '-': /* switch direction to MODE_DEL */
3303 state.dir = flag_p[0];
3306 case 'l': /* deal with limits */
3307 mode_parse_limit(&state, flag_p);
3310 case 'k': /* deal with keys */
3311 mode_parse_key(&state, flag_p);
3314 case 'A': /* deal with Admin passes */
3315 if (feature_bool(FEAT_OPLEVELS))
3316 mode_parse_apass(&state, flag_p);
3319 case 'U': /* deal with user passes */
3320 if (feature_bool(FEAT_OPLEVELS))
3321 mode_parse_upass(&state, flag_p);
3324 case 'b': /* deal with bans */
3325 mode_parse_ban(&state, flag_p);
3328 case 'o': /* deal with ops/voice */
3330 mode_parse_client(&state, flag_p);
3333 default: /* deal with other modes */
3334 mode_parse_mode(&state, flag_p);
3336 } /* switch (*modestr) */
3337 } /* for (; *modestr; modestr++) */
3339 if (state.flags & MODE_PARSE_BURST)
3340 break; /* don't interpret any more arguments */
3342 if (state.parc > 0) { /* process next argument in string */
3343 modestr = state.parv[state.args_used++];
3347 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3350 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3351 break; /* we're then going to bounce the mode! */
3353 recv_ts = atoi(modestr);
3355 if (recv_ts && recv_ts < state.chptr->creationtime)
3356 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3358 break; /* break out of while loop */
3359 } else if (state.flags & MODE_PARSE_STRICT ||
3360 (MyUser(state.sptr) && state.max_args <= 0)) {
3361 state.parc++; /* we didn't actually gobble the argument */
3363 break; /* break out of while loop */
3366 } /* while (*modestr) */
3369 * the rest of the function finishes building resultant MODEs; if the
3370 * origin isn't a member or an oper, skip it.
3372 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3373 return state.args_used; /* tell our parent how many args we gobbled */
3375 t_mode = state.chptr->mode.mode;
3377 if (state.del & t_mode) { /* delete any modes to be deleted... */
3378 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3380 t_mode &= ~state.del;
3382 if (state.add & ~t_mode) { /* add any modes to be added... */
3383 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3385 t_mode |= state.add;
3388 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3389 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3390 !(t_mode & MODE_INVITEONLY))
3391 mode_invite_clear(state.chptr);
3393 state.chptr->mode.mode = t_mode;
3396 if (state.flags & MODE_PARSE_WIPEOUT) {
3397 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3398 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3399 state.chptr->mode.limit);
3400 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3401 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3402 state.chptr->mode.key, 0);
3403 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3404 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3405 state.chptr->mode.upass, 0);
3406 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3407 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3408 state.chptr->mode.apass, 0);
3411 if (state.done & DONE_BANCLEAN) /* process bans */
3412 mode_process_bans(&state);
3414 /* process client changes */
3415 if (state.cli_change[0].flag)
3416 mode_process_clients(&state);
3418 return state.args_used; /* tell our parent how many args we gobbled */
3422 * Initialize a join buffer
3425 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3426 struct Client *connect, unsigned int type, char *comment,
3432 assert(0 != source);
3433 assert(0 != connect);
3435 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3436 jbuf->jb_connect = connect;
3437 jbuf->jb_type = type;
3438 jbuf->jb_comment = comment;
3439 jbuf->jb_create = create;
3441 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3442 type == JOINBUF_TYPE_PART ||
3443 type == JOINBUF_TYPE_PARTALL) ?
3444 STARTJOINLEN : STARTCREATELEN) +
3445 (comment ? strlen(comment) + 2 : 0));
3447 for (i = 0; i < MAXJOINARGS; i++)
3448 jbuf->jb_channels[i] = 0;
3452 * Add a channel to the join buffer
3455 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3463 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3464 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3469 is_local = IsLocalChannel(chan->chname);
3471 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3472 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3473 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3474 if (IsUserParting(member))
3476 SetUserParting(member);
3478 /* Send notification to channel */
3479 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3480 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3481 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3482 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3483 else if (MyUser(jbuf->jb_source))
3484 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3485 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3486 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3487 /* XXX: Shouldn't we send a PART here anyway? */
3488 /* to users on the channel? Why? From their POV, the user isn't on
3489 * the channel anymore anyway. We don't send to servers until below,
3490 * when we gang all the channel parts together. Note that this is
3491 * exactly the same logic, albeit somewhat more concise, as was in
3492 * the original m_part.c */
3494 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3495 is_local) /* got to remove user here */
3496 remove_user_from_channel(jbuf->jb_source, chan);
3498 /* Add user to channel */
3499 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3500 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3502 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3504 /* send notification to all servers */
3505 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3506 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3507 "%H %Tu", chan, chan->creationtime);
3509 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3510 /* Send the notification to the channel */
3511 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3513 /* send an op, too, if needed */
3514 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3515 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3516 chan, jbuf->jb_source);
3517 } else if (MyUser(jbuf->jb_source))
3518 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3521 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3522 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3523 return; /* don't send to remote */
3525 /* figure out if channel name will cause buffer to be overflowed */
3526 len = chan ? strlen(chan->chname) + 1 : 2;
3527 if (jbuf->jb_strlen + len > BUFSIZE)
3528 joinbuf_flush(jbuf);
3530 /* add channel to list of channels to send and update counts */
3531 jbuf->jb_channels[jbuf->jb_count++] = chan;
3532 jbuf->jb_strlen += len;
3534 /* if we've used up all slots, flush */
3535 if (jbuf->jb_count >= MAXJOINARGS)
3536 joinbuf_flush(jbuf);
3540 * Flush the channel list to remote servers
3543 joinbuf_flush(struct JoinBuf *jbuf)
3545 char chanlist[BUFSIZE];
3549 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3550 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3551 return 0; /* no joins to process */
3553 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3554 build_string(chanlist, &chanlist_i,
3555 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3556 i == 0 ? '\0' : ',');
3557 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3558 /* Remove user from channel */
3559 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3561 jbuf->jb_channels[i] = 0; /* mark slot empty */
3564 jbuf->jb_count = 0; /* reset base counters */
3565 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3566 STARTJOINLEN : STARTCREATELEN) +
3567 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3569 /* and send the appropriate command */
3570 switch (jbuf->jb_type) {
3571 case JOINBUF_TYPE_CREATE:
3572 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3573 "%s %Tu", chanlist, jbuf->jb_create);
3576 case JOINBUF_TYPE_PART:
3577 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3578 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3586 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3587 int IsInvited(struct Client* cptr, const void* chptr)
3591 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3592 if (lp->value.chptr == chptr)
3597 /* RevealDelayedJoin: sends a join for a hidden user */
3599 void RevealDelayedJoin(struct Membership *member) {
3600 ClearDelayedJoin(member);
3601 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3603 CheckDelayedJoins(member->channel);
3606 /* CheckDelayedJoins: checks and clear +d if necessary */
3608 void CheckDelayedJoins(struct Channel *chan) {
3609 struct Membership *memb2;
3611 if (chan->mode.mode & MODE_WASDELJOINS) {
3612 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3613 if (IsDelayedJoin(memb2))
3618 chan->mode.mode &= ~MODE_WASDELJOINS;
3619 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,