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);
294 /* Channel became (or was) empty: Remove channel */
295 if (is_listed(chptr))
298 for (i = 0; i <= HighestFd; i++)
300 struct Client *acptr = 0;
301 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
302 (cli_listing(acptr))->chptr == chptr)
304 list_next_channels(acptr, 1);
305 break; /* Only one client can list a channel */
310 * Now, find all invite links from channel structure
312 while ((tmp = chptr->invites))
313 del_invite(tmp->value.cptr, chptr);
315 tmp = chptr->banlist;
320 MyFree(obtmp->value.ban.banstr);
321 MyFree(obtmp->value.ban.who);
325 chptr->prev->next = chptr->next;
327 GlobalChannelList = chptr->next;
329 chptr->next->prev = chptr->prev;
331 --UserStats.channels;
333 * make sure that channel actually got removed from hash table
335 assert(chptr->hnext == chptr);
340 /** add a ban to a channel
342 * `cptr' must be the client adding the ban.
344 * If `change' is true then add `banid' to channel `chptr'.
345 * Returns 0 if the ban was added.
346 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
347 * Return -1 otherwise.
349 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
350 * when `change' is false, otherwise they will be removed from the banlist.
351 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
352 * respectively will return these bans until NULL is returned.
354 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
355 * is reset (unless a non-zero value is returned, in which case the
356 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
359 * @param cptr Client adding the ban
360 * @param chptr Channel to add the ban to
361 * @param banid The actual ban.
362 * @param change True if adding a ban, false if old bans should just be flagged
363 * @param firsttime Reset the next_overlapped_ban() iteration.
365 * 0 if the ban was added
366 * -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT
369 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
370 int change, int firsttime)
375 int removed_bans = 0;
376 int len = strlen(banid);
381 assert(0 == prev_ban);
382 assert(0 == removed_bans_list);
386 for (banp = &chptr->banlist; *banp;)
388 len += strlen((*banp)->value.ban.banstr);
390 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
392 if (!strcmp((*banp)->value.ban.banstr, banid))
394 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
398 else if (!mmatch((*banp)->value.ban.banstr, banid))
400 if (!mmatch(banid, (*banp)->value.ban.banstr))
402 struct SLink *tmp = *banp;
408 len -= strlen(tmp->value.ban.banstr);
411 /* These will be sent to the user later as -b */
412 tmp->next = removed_bans_list;
413 removed_bans_list = tmp;
416 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
418 tmp->flags |= CHFL_BAN_OVERLAPPED;
429 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
430 banp = &(*banp)->next;
433 if (MyUser(cptr) && !removed_bans &&
434 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
435 (cnt >= feature_int(FEAT_MAXBANS))))
437 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
443 struct Membership* member;
445 ban->next = chptr->banlist;
447 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
448 assert(0 != ban->value.ban.banstr);
449 strcpy(ban->value.ban.banstr, banid);
451 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
452 DupString(ban->value.ban.who, cli_name(&me));
454 DupString(ban->value.ban.who, cli_name(cptr));
455 assert(0 != ban->value.ban.who);
457 ban->value.ban.when = TStime();
458 ban->flags = CHFL_BAN; /* This bit is never used I think... */
459 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
460 ban->flags |= CHFL_BAN_IPMASK;
461 chptr->banlist = ban;
464 * Erase ban-valid-bit
466 for (member = chptr->members; member; member = member->next_member)
467 ClearBanValid(member); /* `ban' == channel member ! */
472 /** return the next ban that is removed
473 * @returns the next ban that is removed because of overlapping
475 struct SLink *next_removed_overlapped_ban(void)
477 struct SLink *tmp = removed_bans_list;
480 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
481 MyFree(prev_ban->value.ban.banstr);
482 MyFree(prev_ban->value.ban.who);
487 removed_bans_list = removed_bans_list->next;
492 /** returns Membership * if a person is joined and not a zombie
494 * @param chptr Channel
495 * @returns pointer to the client's struct Membership * on the channel if that
496 * user is a full member of the channel, or NULL otherwise.
498 * @see find_member_link()
500 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
502 struct Membership* member;
505 member = find_member_link(chptr, cptr);
506 return (member && !IsZombie(member)) ? member : 0;
509 /** return true if banned else false.
511 * This function returns true if the user is banned on the said channel.
512 * This function will check the ban cache if applicable, otherwise will
513 * do the comparisons and cache the result.
515 * @param cptr The client to test
516 * @param chptr The channel
517 * @param member The Membership * of this client on this channel
518 * (may be NULL if the member is not on the channel).
520 static int is_banned(struct Client *cptr, struct Channel *chptr,
521 struct Membership* member)
524 char tmphost[HOSTLEN + 1];
525 char nu_host[NUH_BUFSIZE];
526 char nu_realhost[NUH_BUFSIZE];
527 char nu_ip[NUI_BUFSIZE];
535 if (member && IsBanValid(member))
536 return IsBanned(member);
538 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
539 (cli_user(cptr))->host);
542 if (HasHiddenHost(cptr))
544 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
545 (cli_user(cptr))->username,
546 cli_user(cptr)->realhost);
550 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
551 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
552 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
553 cli_user(cptr)->username,
558 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
559 if ((tmp->flags & CHFL_BAN_IPMASK)) {
561 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
562 (cli_user(cptr))->username, &cli_ip(cptr));
563 if (match(tmp->value.ban.banstr, ip_s) == 0)
566 if (match(tmp->value.ban.banstr, s) == 0)
568 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
584 return (tmp != NULL);
587 /** add a user to a channel.
588 * adds a user to a channel by adding another link to the channels member
591 * @param chptr The channel to add to.
592 * @param who The user to add.
593 * @param flags The flags the user gets initially.
594 * @param oplevel The oplevel the user starts with.
596 void add_user_to_channel(struct Channel* chptr, struct Client* who,
597 unsigned int flags, int oplevel)
604 struct Membership* member = membershipFreeList;
606 membershipFreeList = member->next_member;
608 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
609 ++membershipAllocCount;
614 member->channel = chptr;
615 member->status = flags;
616 member->oplevel = oplevel;
618 member->next_member = chptr->members;
619 if (member->next_member)
620 member->next_member->prev_member = member;
621 member->prev_member = 0;
622 chptr->members = member;
624 member->next_channel = (cli_user(who))->channel;
625 if (member->next_channel)
626 member->next_channel->prev_channel = member;
627 member->prev_channel = 0;
628 (cli_user(who))->channel = member;
630 if (chptr->destruct_event)
631 remove_destruct_event(chptr);
633 ++((cli_user(who))->joined);
637 /** Remove a person from a channel, given their Membership*
639 * @param member A member of a channel.
641 * @returns true if there are more people in the channel.
643 static int remove_member_from_channel(struct Membership* member)
645 struct Channel* chptr;
647 chptr = member->channel;
649 * unlink channel member list
651 if (member->next_member)
652 member->next_member->prev_member = member->prev_member;
653 if (member->prev_member)
654 member->prev_member->next_member = member->next_member;
656 member->channel->members = member->next_member;
659 * If this is the last delayed-join user, may have to clear WASDELJOINS.
661 if (IsDelayedJoin(member))
662 CheckDelayedJoins(chptr);
665 * unlink client channel list
667 if (member->next_channel)
668 member->next_channel->prev_channel = member->prev_channel;
669 if (member->prev_channel)
670 member->prev_channel->next_channel = member->next_channel;
672 (cli_user(member->user))->channel = member->next_channel;
674 --(cli_user(member->user))->joined;
676 member->next_member = membershipFreeList;
677 membershipFreeList = member;
679 return sub1_from_channel(chptr);
682 /** Check if all the remaining members on the channel are zombies
684 * @returns False if the channel has any non zombie members, True otherwise.
687 static int channel_all_zombies(struct Channel* chptr)
689 struct Membership* member;
691 for (member = chptr->members; member; member = member->next_member) {
692 if (!IsZombie(member))
699 /** Remove a user from a channel
700 * This is the generic entry point for removing a user from a channel, this
701 * function will remove the client from the channel, and destory the channel
702 * if there are no more normal users left.
704 * @param cptr The client
705 * @param chptr The channel
707 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
710 struct Membership* member;
713 if ((member = find_member_link(chptr, cptr))) {
714 if (remove_member_from_channel(member)) {
715 if (channel_all_zombies(chptr)) {
717 * XXX - this looks dangerous but isn't if we got the referential
718 * integrity right for channels
720 while (remove_member_from_channel(chptr->members))
727 /** Remove a user from all channels they are on.
729 * This function removes a user from all channels they are on.
731 * @param cptr The client to remove.
733 void remove_user_from_all_channels(struct Client* cptr)
735 struct Membership* chan;
737 assert(0 != cli_user(cptr));
739 while ((chan = (cli_user(cptr))->channel))
740 remove_user_from_channel(cptr, chan->channel);
743 /** Check if this user is a legitimate chanop
745 * @param cptr Client to check
746 * @param chptr Channel to check
748 * @returns True if the user is a chanop (And not a zombie), False otherwise.
751 int is_chan_op(struct Client *cptr, struct Channel *chptr)
753 struct Membership* member;
755 if ((member = find_member_link(chptr, cptr)))
756 return (!IsZombie(member) && IsChanOp(member));
761 /** Check if a user is a Zombie on a specific channel.
763 * @param cptr The client to check.
764 * @param chptr The channel to check.
766 * @returns True if the client (cptr) is a zombie on the channel (chptr),
771 int is_zombie(struct Client *cptr, struct Channel *chptr)
773 struct Membership* member;
777 if ((member = find_member_link(chptr, cptr)))
778 return IsZombie(member);
782 /** Returns if a user has voice on a channel.
784 * @param cptr The client
785 * @param chptr The channel
787 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
790 int has_voice(struct Client* cptr, struct Channel* chptr)
792 struct Membership* member;
795 if ((member = find_member_link(chptr, cptr)))
796 return (!IsZombie(member) && HasVoice(member));
801 /** Can this member send to a channel
803 * A user can speak on a channel iff:
805 * <li> They didn't use the Apass to gain ops.
806 * <li> They are op'd or voice'd.
807 * <li> You aren't banned.
808 * <li> The channel isn't +m
809 * <li> The channel isn't +n or you are on the channel.
812 * This function will optionally reveal a user on a delayed join channel if
813 * they are allowed to send to the channel.
815 * @param member The membership of the user
816 * @param reveal If true, the user will be "revealed" on a delayed
819 * @returns True if the client can speak on the channel.
821 int member_can_send_to_channel(struct Membership* member, int reveal)
825 /* Discourage using the Apass to get op. They should use the upass. */
826 if (IsChannelManager(member) && *member->channel->mode.upass)
829 if (IsVoicedOrOpped(member))
832 * If it's moderated, and you aren't a priviledged user, you can't
835 if (member->channel->mode.mode & MODE_MODERATED)
838 * If you're banned then you can't speak either.
839 * but because of the amount of CPU time that is_banned chews
840 * we only check it for our clients.
842 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
845 if (IsDelayedJoin(member) && reveal)
846 RevealDelayedJoin(member);
851 /** Check if a client can send to a channel.
853 * Has the added check over member_can_send_to_channel() of servers can
856 * @param cptr The client to check
857 * @param chptr The channel to check
858 * @param reveal If the user should be revealed (see
859 * member_can_send_to_channel())
861 * @returns true if the client is allowed to speak on the channel, false
864 * @see member_can_send_to_channel()
866 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
868 struct Membership *member;
871 * Servers can always speak on channels.
876 member = find_channel_member(cptr, chptr);
879 * You can't speak if you're off channel, and it is +n (no external messages)
883 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
884 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
887 return !is_banned(cptr, chptr, NULL);
889 return member_can_send_to_channel(member, reveal);
892 /** Returns the name of a channel that prevents the user from changing nick.
893 * if a member and not (opped or voiced) and (banned or moderated), return
894 * the name of the first channel banned on.
896 * @param cptr The client
898 * @returns the name of the first channel banned on, or NULL if the user
901 const char* find_no_nickchange_channel(struct Client* cptr)
904 struct Membership* member;
905 for (member = (cli_user(cptr))->channel; member;
906 member = member->next_channel) {
907 if (!IsVoicedOrOpped(member) &&
908 (is_banned(cptr, member->channel, member) ||
909 (member->channel->mode.mode & MODE_MODERATED)))
910 return member->channel->chname;
917 /** Fill mbuf/pbuf with modes from chptr
918 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
919 * with the parameters in pbuf as visible by cptr.
921 * This function will hide keys from non-op'd, non-server clients.
923 * @param cptr The client to generate the mode for.
924 * @param mbuf The buffer to write the modes into.
925 * @param pbuf The buffer to write the mode parameters into.
926 * @param buflen The length of the buffers.
927 * @param chptr The channel to get the modes from.
928 * @param member The membership of this client on this channel (or NULL
929 * if this client isn't on this channel)
932 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
933 struct Channel *chptr, struct Membership *member)
935 int previous_parameter = 0;
942 if (chptr->mode.mode & MODE_SECRET)
944 else if (chptr->mode.mode & MODE_PRIVATE)
946 if (chptr->mode.mode & MODE_MODERATED)
948 if (chptr->mode.mode & MODE_TOPICLIMIT)
950 if (chptr->mode.mode & MODE_INVITEONLY)
952 if (chptr->mode.mode & MODE_NOPRIVMSGS)
954 if (chptr->mode.mode & MODE_REGONLY)
956 if (chptr->mode.mode & MODE_DELJOINS)
958 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
960 if (chptr->mode.limit) {
962 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
963 previous_parameter = 1;
966 if (*chptr->mode.key) {
968 if (previous_parameter)
970 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
971 strcat(pbuf, chptr->mode.key);
974 previous_parameter = 1;
976 if (*chptr->mode.apass) {
978 if (previous_parameter)
980 if (IsServer(cptr)) {
981 strcat(pbuf, chptr->mode.apass);
984 previous_parameter = 1;
986 if (*chptr->mode.upass) {
988 if (previous_parameter)
990 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
991 strcat(pbuf, chptr->mode.upass);
998 /** Compare two members oplevel
1000 * @param mp1 Pointer to a pointer to a membership
1001 * @param mp2 Pointer to a pointer to a membership
1003 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
1005 * Used for qsort(3).
1007 int compare_member_oplevel(const void *mp1, const void *mp2)
1009 struct Membership const* member1 = *(struct Membership const**)mp1;
1010 struct Membership const* member2 = *(struct Membership const**)mp2;
1011 if (member1->oplevel == member2->oplevel)
1013 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1016 /* send "cptr" a full list of the modes for channel chptr.
1018 * Sends a BURST line to cptr, bursting all the modes for the channel.
1020 * @param cptr Client pointer
1021 * @param chptr Channel pointer
1023 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1025 /* The order in which modes are generated is now mandatory */
1026 static unsigned int current_flags[4] =
1027 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1033 struct Membership* member;
1035 char modebuf[MODEBUFLEN];
1036 char parabuf[MODEBUFLEN];
1038 int number_of_ops = 0;
1039 int opped_members_index = 0;
1040 struct Membership** opped_members = NULL;
1041 int last_oplevel = 0;
1042 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1047 if (IsLocalChannel(chptr->chname))
1050 member = chptr->members;
1051 lp2 = chptr->banlist;
1053 *modebuf = *parabuf = '\0';
1054 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1056 for (first = 1; full; first = 0) /* Loop for multiple messages */
1058 full = 0; /* Assume by default we get it
1059 all in one message */
1061 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1062 /* is there any better way we can do this? */
1063 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1064 chptr->creationtime);
1066 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1069 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1070 msgq_append(&me, mb, " %s", modebuf);
1073 msgq_append(&me, mb, " %s", parabuf);
1077 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1079 * First find all opless members.
1080 * Run 2 times over all members, to group the members with
1081 * and without voice together.
1082 * Then run 2 times over all opped members (which are ordered
1083 * by op-level) to also group voice and non-voice together.
1085 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1089 if (flag_cnt < 2 && IsChanOp(member))
1092 * The first loop (to find all non-voice/op), we count the ops.
1093 * The second loop (to find all voiced non-ops), store the ops
1094 * in a dynamic array.
1099 opped_members[opped_members_index++] = member;
1101 /* Only handle the members with the flags that we are interested in. */
1102 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1104 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1105 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1107 full = 1; /* Make sure we continue after
1108 sending it so far */
1109 /* Ensure the new BURST line contains the current
1110 * ":mode", except when there is no mode yet. */
1111 new_mode = (flag_cnt > 0) ? 1 : 0;
1112 break; /* Do not add this member to this message */
1114 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1115 first = 0; /* From now on, use commas to add new nicks */
1118 * Do we have a nick with a new mode ?
1119 * Or are we starting a new BURST line?
1121 if (new_mode || !feat_oplevels)
1124 * This means we are at the _first_ member that has only
1125 * voice, or the first member that has only ops, or the
1126 * first member that has voice and ops (so we get here
1127 * at most three times, plus once for every start of
1128 * a continued BURST line where only these modes is current.
1129 * In the two cases where the current mode includes ops,
1130 * we need to add the _absolute_ value of the oplevel to the mode.
1132 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1135 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1137 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1139 /* append the absolute value of the oplevel */
1141 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1146 msgq_append(&me, mb, tbuf);
1149 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1152 * This can't be the first member of a (continued) BURST
1153 * message because then either flag_cnt == 0 or new_mode == 1
1154 * Now we need to append the incremental value of the oplevel.
1156 char tbuf[2 + MAXOPLEVELDIGITS];
1157 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1158 last_oplevel = member->oplevel;
1159 msgq_append(&me, mb, tbuf);
1162 /* Go to the next `member'. */
1164 member = member->next_member;
1166 member = opped_members[++opped_members_index];
1171 /* Point `member' at the start of the list again. */
1174 member = chptr->members;
1175 /* Now, after one loop, we know the number of ops and can
1176 * allocate the dynamic array with pointer to the ops. */
1177 opped_members = (struct Membership**)
1178 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1179 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1183 /* At the end of the second loop, sort the opped members with
1184 * increasing op-level, so that we will output them in the
1185 * correct order (and all op-level increments stay positive) */
1187 qsort(opped_members, number_of_ops,
1188 sizeof(struct Membership*), compare_member_oplevel);
1189 /* The third and fourth loop run only over the opped members. */
1190 member = opped_members[(opped_members_index = 0)];
1193 } /* loop over 0,+v,+o,+ov */
1197 /* Attach all bans, space seperated " :%ban ban ..." */
1198 for (first = 2; lp2; lp2 = lp2->next)
1200 len = strlen(lp2->value.ban.banstr);
1201 if (msgq_bufleft(mb) < len + 1 + first)
1202 /* The +1 stands for the added ' '.
1203 * The +first stands for the added ":%".
1209 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1210 lp2->value.ban.banstr);
1215 send_buffer(cptr, mb, 0); /* Send this message */
1217 } /* Continue when there was something
1218 that didn't fit (full==1) */
1220 MyFree(opped_members);
1221 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1222 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1223 chptr->creationtime, chptr->topic_time, chptr->topic);
1226 /** Canonify a mask.
1229 * @author Carlo Wood (Run),
1232 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1233 * When the user name or host name are too long (USERLEN and HOSTLEN
1234 * respectively) then they are cut off at the start with a '*'.
1236 * The following transformations are made:
1238 * 1) xxx -> nick!*@*
1239 * 2) xxx.xxx -> *!*\@host
1240 * 3) xxx\!yyy -> nick!user\@*
1241 * 4) xxx\@yyy -> *!user\@host
1242 * 5) xxx!yyy\@zzz -> nick!user\@host
1244 * @param mask The uncanonified mask.
1245 * @returns The updated mask in a static buffer.
1247 char *pretty_mask(char *mask)
1249 static char star[2] = { '*', 0 };
1250 static char retmask[NUH_BUFSIZE];
1251 char *last_dot = NULL;
1254 /* Case 1: default */
1259 /* Do a _single_ pass through the characters of the mask: */
1260 for (ptr = mask; *ptr; ++ptr)
1264 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1268 else if (*ptr == '@')
1270 /* Case 4: Found last '@' (without finding a '!' yet) */
1275 else if (*ptr == '.')
1277 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1287 /* Case 4 or 5: Found last '@' */
1293 if (user == star && last_dot)
1303 char *nick_end = (user != star) ? user - 1 : ptr;
1304 if (nick_end - nick > NICKLEN)
1310 char *user_end = (host != star) ? host - 1 : ptr;
1311 if (user_end - user > USERLEN)
1313 user = user_end - USERLEN;
1318 if (host != star && ptr - host > HOSTLEN)
1320 host = ptr - HOSTLEN;
1323 return make_nick_user_host(retmask, nick, user, host);
1326 /** send a banlist to a client for a channel
1328 * @param cptr Client to send the banlist to.
1329 * @param chptr Channel whose banlist to send.
1331 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1338 for (lp = chptr->banlist; lp; lp = lp->next)
1339 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1340 lp->value.ban.who, lp->value.ban.when);
1342 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1345 /** Check a key against a keyring.
1346 * We are now treating the key part of /join channellist key as a key
1347 * ring; that is, we try one key against the actual channel key, and if that
1348 * doesn't work, we try the next one, and so on. -Kev -Texaco
1349 * Returns: 0 on match, 1 otherwise
1350 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1352 * @param key Key to check
1353 * @param keyring Comma seperated list of keys
1355 * @returns True if the key was found and matches, false otherwise.
1357 static int compall(char *key, char *keyring)
1362 p1 = key; /* point to the key... */
1363 while (*p1 && *p1 == *keyring)
1364 { /* step through the key and ring until they
1370 if (!*p1 && (!*keyring || *keyring == ','))
1371 /* ok, if we're at the end of the and also at the end of one of the keys
1372 in the keyring, we have a match */
1375 if (!*keyring) /* if we're at the end of the key ring, there
1376 weren't any matches, so we return 1 */
1379 /* Not at the end of the key ring, so step
1380 through to the next key in the ring: */
1381 while (*keyring && *(keyring++) != ',');
1383 goto top; /* and check it against the key */
1386 /** Returns if a user can join a channel with a specific key.
1388 * @param sptr The client trying to join
1389 * @param chptr The channel to join
1390 * @param key The key to use
1392 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1393 * if the oper used the magic key, 0 if no error occured.
1395 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1397 int overrideJoin = 0;
1400 * Now a banned user CAN join if invited -- Nemesi
1401 * Now a user CAN escape channel limit if invited -- bfriendly
1402 * Now a user CAN escape anything if invited -- Isomer
1405 if (IsInvited(sptr, chptr))
1408 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1409 a HACK(4) notice will be sent if he would not have been supposed
1410 to join normally. */
1411 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1412 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1413 compall("OVERRIDE",key) == 0)
1414 overrideJoin = MAGIC_OPER_OVERRIDE;
1416 if (chptr->mode.mode & MODE_INVITEONLY)
1417 return overrideJoin + ERR_INVITEONLYCHAN;
1419 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1420 return overrideJoin + ERR_CHANNELISFULL;
1422 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1423 return overrideJoin + ERR_NEEDREGGEDNICK;
1425 if (is_banned(sptr, chptr, NULL))
1426 return overrideJoin + ERR_BANNEDFROMCHAN;
1429 * now using compall (above) to test against a whole key ring -Kev
1431 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1432 return overrideJoin + ERR_BADCHANNELKEY;
1435 return ERR_DONTCHEAT;
1440 /** Remove bells and commas from channel name
1442 * @param cn Channel name to clean, modified in place.
1444 void clean_channelname(char *cn)
1448 for (i = 0; cn[i]; i++) {
1449 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1453 if (IsChannelLower(cn[i])) {
1454 cn[i] = ToLower(cn[i]);
1460 if ((unsigned char)(cn[i]) == 0xd0)
1461 cn[i] = (char) 0xf0;
1467 /** Get a channel block, creating if necessary.
1468 * Get Channel block for chname (and allocate a new channel
1469 * block, if it didn't exists before).
1471 * @param cptr Client joining the channel.
1472 * @param chname The name of the channel to join.
1473 * @param flag set to CGT_CREATE to create the channel if it doesn't
1476 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1477 * wasn't specified or a pointer to the channel structure
1479 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1481 struct Channel *chptr;
1484 if (EmptyString(chname))
1487 len = strlen(chname);
1488 if (MyUser(cptr) && len > CHANNELLEN)
1491 *(chname + CHANNELLEN) = '\0';
1493 if ((chptr = FindChannel(chname)))
1495 if (flag == CGT_CREATE)
1497 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1499 ++UserStats.channels;
1500 memset(chptr, 0, sizeof(struct Channel));
1501 strcpy(chptr->chname, chname);
1502 if (GlobalChannelList)
1503 GlobalChannelList->prev = chptr;
1505 chptr->next = GlobalChannelList;
1506 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1507 GlobalChannelList = chptr;
1513 /** invite a user to a channel.
1515 * Adds an invite for a user to a channel. Limits the number of invites
1516 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1518 * @param cptr The client to be invited.
1519 * @param chptr The channel to be invited to.
1521 void add_invite(struct Client *cptr, struct Channel *chptr)
1523 struct SLink *inv, **tmp;
1525 del_invite(cptr, chptr);
1527 * Delete last link in chain if the list is max length
1529 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1530 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1531 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1533 * Add client to channel invite list
1536 inv->value.cptr = cptr;
1537 inv->next = chptr->invites;
1538 chptr->invites = inv;
1540 * Add channel to the end of the client invite list
1542 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1544 inv->value.chptr = chptr;
1547 (cli_user(cptr))->invites++;
1550 /** Delete an invite
1551 * Delete Invite block from channel invite list and client invite list
1553 * @param cptr Client pointer
1554 * @param chptr Channel pointer
1556 void del_invite(struct Client *cptr, struct Channel *chptr)
1558 struct SLink **inv, *tmp;
1560 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1561 if (tmp->value.cptr == cptr)
1566 (cli_user(cptr))->invites--;
1570 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1571 if (tmp->value.chptr == chptr)
1580 /** List a set of channels
1581 * Lists a series of channels that match a filter, skipping channels that
1582 * have been listed before.
1584 * @param cptr Client to send the list to.
1585 * @param nr Number of channels to send this update.
1587 void list_next_channels(struct Client *cptr, int nr)
1589 struct ListingArgs *args = cli_listing(cptr);
1590 struct Channel *chptr = args->chptr;
1591 chptr->mode.mode &= ~MODE_LISTED;
1592 while (is_listed(chptr) || --nr >= 0)
1594 for (; chptr; chptr = chptr->next)
1596 if (!cli_user(cptr))
1598 if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1599 SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1601 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1602 chptr->creationtime > args->min_time &&
1603 chptr->creationtime < args->max_time &&
1604 (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1605 chptr->topic_time > args->min_topic_time &&
1606 chptr->topic_time < args->max_topic_time)))
1608 if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1609 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1611 chptr = chptr->next;
1617 MyFree(cli_listing(cptr));
1618 cli_listing(cptr) = NULL;
1619 send_reply(cptr, RPL_LISTEND);
1625 (cli_listing(cptr))->chptr = chptr;
1626 chptr->mode.mode |= MODE_LISTED;
1632 /** @page zombie Explaination of Zombies
1640 * X --a--> A --b--> B --d--> D
1645 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1646 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1648 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1649 * Remove the user immediately when no users are left on the channel.
1650 * b) On server B : remove the user (who/lp) from the channel, send a
1651 * PART upstream (to A) and pass on the KICK.
1652 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1653 * channel, and pass on the KICK.
1654 * d) On server D : remove the user (who/lp) from the channel, and pass on
1658 * - Setting the ZOMBIE flag never hurts, we either remove the
1659 * client after that or we don't.
1660 * - The KICK message was already passed on, as should be in all cases.
1661 * - `who' is removed in all cases except case a) when users are left.
1662 * - A PART is only sent upstream in case b).
1668 * 1 --- 2 --- 3 --- 4 --- 5
1673 * We also need to turn 'who' into a zombie on servers 1 and 6,
1674 * because a KICK from 'who' (kicking someone else in that direction)
1675 * can arrive there afterwards - which should not be bounced itself.
1676 * Therefore case a) also applies for servers 1 and 6.
1681 /** Turn a user on a channel into a zombie
1682 * This function turns a user into a zombie (see \ref zombie)
1684 * @param member The structure representing this user on this channel.
1685 * @param who The client that is being kicked.
1686 * @param cptr The connection the kick came from.
1687 * @param sptr The client that is doing the kicking.
1688 * @param chptr The channel the user is being kicked from.
1690 void make_zombie(struct Membership* member, struct Client* who,
1691 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1693 assert(0 != member);
1698 /* Default for case a): */
1701 /* Case b) or c) ?: */
1702 if (MyUser(who)) /* server 4 */
1704 if (IsServer(cptr)) /* Case b) ? */
1705 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1706 remove_user_from_channel(who, chptr);
1709 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1711 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1712 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1713 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1715 remove_user_from_channel(who, chptr);
1720 /* Case a) (servers 1, 2, 3 and 6) */
1721 if (channel_all_zombies(chptr))
1722 remove_user_from_channel(who, chptr);
1724 /* XXX Can't actually call Debug here; if the channel is all zombies,
1725 * chptr will no longer exist when we get here.
1726 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1730 /** returns the number of zombies on a channel
1731 * @param chptr Channel to count zombies in.
1733 * @returns The number of zombies on the channel.
1735 int number_of_zombies(struct Channel *chptr)
1737 struct Membership* member;
1741 for (member = chptr->members; member; member = member->next_member) {
1742 if (IsZombie(member))
1748 /** Concatenate some strings together.
1749 * This helper function builds an argument string in strptr, consisting
1750 * of the original string, a space, and str1 and str2 concatenated (if,
1751 * of course, str2 is not NULL)
1753 * @param strptr The buffer to concatenate into
1754 * @param strptr_i modified offset to the position to modify
1755 * @param str1 The string to contatenate from.
1756 * @param str2 The second string to contatenate from.
1757 * @param c Charactor to seperate the string from str1 and str2.
1760 build_string(char *strptr, int *strptr_i, const char *str1,
1761 const char *str2, char c)
1764 strptr[(*strptr_i)++] = c;
1767 strptr[(*strptr_i)++] = *(str1++);
1771 strptr[(*strptr_i)++] = *(str2++);
1773 strptr[(*strptr_i)] = '\0';
1776 /** Flush out the modes
1777 * This is the workhorse of our ModeBuf suite; this actually generates the
1778 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1780 * @param mbuf The mode buffer to flush
1781 * @param all If true, flush all modes, otherwise leave partial modes in the
1787 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1789 /* we only need the flags that don't take args right now */
1790 static int flags[] = {
1791 /* MODE_CHANOP, 'o', */
1792 /* MODE_VOICE, 'v', */
1795 MODE_MODERATED, 'm',
1796 MODE_TOPICLIMIT, 't',
1797 MODE_INVITEONLY, 'i',
1798 MODE_NOPRIVMSGS, 'n',
1801 MODE_WASDELJOINS, 'd',
1802 /* MODE_KEY, 'k', */
1803 /* MODE_BAN, 'b', */
1805 /* MODE_APASS, 'A', */
1806 /* MODE_UPASS, 'U', */
1812 struct Client *app_source; /* where the MODE appears to come from */
1814 char addbuf[20]; /* accumulates +psmtin, etc. */
1816 char rembuf[20]; /* accumulates -psmtin, etc. */
1818 char *bufptr; /* we make use of indirection to simplify the code */
1821 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1823 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1825 char *strptr; /* more indirection to simplify the code */
1828 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1831 char limitbuf[20]; /* convert limits to strings */
1833 unsigned int limitdel = MODE_LIMIT;
1837 /* If the ModeBuf is empty, we have nothing to do */
1838 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1841 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1843 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1846 app_source = mbuf->mb_source;
1849 * Account for user we're bouncing; we have to get it in on the first
1850 * bounced MODE, or we could have problems
1852 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1853 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1855 /* Calculate the simple flags */
1856 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1857 if (*flag_p & mbuf->mb_add)
1858 addbuf[addbuf_i++] = flag_p[1];
1859 else if (*flag_p & mbuf->mb_rem)
1860 rembuf[rembuf_i++] = flag_p[1];
1863 /* Now go through the modes with arguments... */
1864 for (i = 0; i < mbuf->mb_count; i++) {
1865 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1867 bufptr_i = &addbuf_i;
1870 bufptr_i = &rembuf_i;
1873 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1874 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1876 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1877 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1879 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1880 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1882 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1883 tmp = strlen(MB_STRING(mbuf, i));
1885 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1886 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1889 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1901 bufptr[(*bufptr_i)++] = mode_char;
1902 totalbuflen -= tmp + 1;
1904 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1905 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1906 strlen(MB_STRING(mbuf, i)));
1908 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1909 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1911 bufptr[(*bufptr_i)++] = 'k';
1912 totalbuflen -= tmp + 1;
1914 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1915 /* if it's a limit, we also format the number */
1916 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1918 tmp = strlen(limitbuf);
1920 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1921 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1923 bufptr[(*bufptr_i)++] = 'l';
1924 totalbuflen -= tmp + 1;
1929 /* terminate the mode strings */
1930 addbuf[addbuf_i] = '\0';
1931 rembuf[rembuf_i] = '\0';
1933 /* If we're building a user visible MODE or HACK... */
1934 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1935 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1936 MODEBUF_DEST_LOG)) {
1937 /* Set up the parameter strings */
1943 for (i = 0; i < mbuf->mb_count; i++) {
1944 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1947 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1949 strptr_i = &addstr_i;
1952 strptr_i = &remstr_i;
1955 /* deal with clients... */
1956 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1957 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1959 /* deal with bans... */
1960 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1961 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1963 /* deal with keys... */
1964 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1965 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1966 "*" : MB_STRING(mbuf, i), 0, ' ');
1968 /* deal with invisible passwords */
1969 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1970 build_string(strptr, strptr_i, "*", 0, ' ');
1973 * deal with limit; note we cannot include the limit parameter if we're
1976 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1977 (MODE_ADD | MODE_LIMIT))
1978 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1981 /* send the messages off to their destination */
1982 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1983 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1985 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1986 mbuf->mb_source : app_source),
1987 mbuf->mb_channel->chname,
1988 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1989 addbuf, remstr, addstr,
1990 mbuf->mb_channel->creationtime);
1992 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1993 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1994 "%s%s%s%s%s%s [%Tu]",
1995 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1996 mbuf->mb_source : app_source),
1997 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1998 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1999 mbuf->mb_channel->creationtime);
2001 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
2002 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
2004 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
2005 mbuf->mb_source : app_source),
2006 mbuf->mb_channel->chname,
2007 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2008 addbuf, remstr, addstr,
2009 mbuf->mb_channel->creationtime);
2011 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
2012 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
2013 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
2014 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
2015 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2017 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
2018 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
2019 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2020 rembuf_i ? "-" : "", rembuf,
2021 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2024 /* Now are we supposed to propagate to other servers? */
2025 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
2026 /* set up parameter string */
2033 * limit is supressed if we're removing it; we have to figure out which
2034 * direction is the direction for it to be removed, though...
2036 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
2038 for (i = 0; i < mbuf->mb_count; i++) {
2039 if (MB_TYPE(mbuf, i) & MODE_SAVE)
2042 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2044 strptr_i = &addstr_i;
2047 strptr_i = &remstr_i;
2050 /* deal with modes that take clients */
2051 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2052 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2054 /* deal with modes that take strings */
2055 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
2056 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2059 * deal with the limit. Logic here is complicated; if HACK2 is set,
2060 * we're bouncing the mode, so sense is reversed, and we have to
2061 * include the original limit if it looks like it's being removed
2063 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2064 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2067 /* we were told to deop the source */
2068 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2069 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2070 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2071 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2073 /* mark that we've done this, so we don't do it again */
2074 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2077 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2078 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2079 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2080 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2081 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2082 addbuf, remstr, addstr);
2083 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2085 * If HACK2 was set, we're bouncing; we send the MODE back to the
2086 * connection we got it from with the senses reversed and a TS of 0;
2089 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2090 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2091 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2092 mbuf->mb_channel->creationtime);
2095 * We're propagating a normal MODE command to the rest of the network;
2096 * we send the actual channel TS unless this is a HACK3 or a HACK4
2098 if (IsServer(mbuf->mb_source))
2099 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2100 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2101 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2102 addbuf, remstr, addstr,
2103 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2104 mbuf->mb_channel->creationtime);
2106 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2107 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2108 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2109 addbuf, remstr, addstr);
2113 /* We've drained the ModeBuf... */
2118 /* reinitialize the mode-with-arg slots */
2119 for (i = 0; i < MAXMODEPARAMS; i++) {
2120 /* If we saved any, pack them down */
2121 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2122 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2123 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2125 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2127 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2128 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2130 MB_TYPE(mbuf, i) = 0;
2131 MB_UINT(mbuf, i) = 0;
2134 /* If we're supposed to flush it all, do so--all hail tail recursion */
2135 if (all && mbuf->mb_count)
2136 return modebuf_flush_int(mbuf, 1);
2141 /** Initialise a modebuf
2142 * This routine just initializes a ModeBuf structure with the information
2143 * needed and the options given.
2145 * @param mbuf The mode buffer to initialise.
2146 * @param source The client that is performing the mode.
2148 * @param chan The channel that the mode is being performed upon.
2152 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2153 struct Client *connect, struct Channel *chan, unsigned int dest)
2158 assert(0 != source);
2162 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2166 mbuf->mb_source = source;
2167 mbuf->mb_connect = connect;
2168 mbuf->mb_channel = chan;
2169 mbuf->mb_dest = dest;
2172 /* clear each mode-with-parameter slot */
2173 for (i = 0; i < MAXMODEPARAMS; i++) {
2174 MB_TYPE(mbuf, i) = 0;
2175 MB_UINT(mbuf, i) = 0;
2179 /** Append a new mode to a modebuf
2180 * This routine simply adds modes to be added or deleted; do a binary OR
2181 * with either MODE_ADD or MODE_DEL
2183 * @param mbuf Mode buffer
2184 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2187 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2190 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2192 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2193 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2194 MODE_DELJOINS | MODE_WASDELJOINS);
2196 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2199 if (mode & MODE_ADD) {
2200 mbuf->mb_rem &= ~mode;
2201 mbuf->mb_add |= mode;
2203 mbuf->mb_add &= ~mode;
2204 mbuf->mb_rem |= mode;
2208 /** Append a mode that takes an int argument to the modebuf
2210 * This routine adds a mode to be added or deleted that takes a unsigned
2211 * int parameter; mode may *only* be the relevant mode flag ORed with one
2212 * of MODE_ADD or MODE_DEL
2214 * @param mbuf The mode buffer to append to.
2215 * @param mode The mode to append.
2216 * @param uint The argument to the mode.
2219 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2222 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2224 if (mode == (MODE_LIMIT | MODE_DEL)) {
2225 mbuf->mb_rem |= mode;
2228 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2229 MB_UINT(mbuf, mbuf->mb_count) = uint;
2231 /* when we've reached the maximal count, flush the buffer */
2232 if (++mbuf->mb_count >=
2233 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2234 modebuf_flush_int(mbuf, 0);
2237 /** append a string mode
2238 * This routine adds a mode to be added or deleted that takes a string
2239 * parameter; mode may *only* be the relevant mode flag ORed with one of
2240 * MODE_ADD or MODE_DEL
2242 * @param mbuf The mode buffer to append to.
2243 * @param mode The mode to append.
2244 * @param string The string parameter to append.
2245 * @param free If the string should be free'd later.
2248 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2252 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2254 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2255 MB_STRING(mbuf, mbuf->mb_count) = string;
2257 /* when we've reached the maximal count, flush the buffer */
2258 if (++mbuf->mb_count >=
2259 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2260 modebuf_flush_int(mbuf, 0);
2263 /** Append a mode on a client to a modebuf.
2264 * This routine adds a mode to be added or deleted that takes a client
2265 * parameter; mode may *only* be the relevant mode flag ORed with one of
2266 * MODE_ADD or MODE_DEL
2268 * @param mbuf The modebuf to append the mode to.
2269 * @param mode The mode to append.
2270 * @param client The client argument to append.
2273 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2274 struct Client *client)
2277 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2279 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2280 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2282 /* when we've reached the maximal count, flush the buffer */
2283 if (++mbuf->mb_count >=
2284 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2285 modebuf_flush_int(mbuf, 0);
2288 /** The exported binding for modebuf_flush()
2290 * @param mbuf The mode buffer to flush.
2292 * @see modebuf_flush_int()
2295 modebuf_flush(struct ModeBuf *mbuf)
2297 struct Membership *memb;
2299 /* Check if MODE_WASDELJOINS should be set */
2300 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2301 && (mbuf->mb_rem & MODE_DELJOINS)) {
2302 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2303 if (IsDelayedJoin(memb)) {
2304 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2305 mbuf->mb_add |= MODE_WASDELJOINS;
2306 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2312 return modebuf_flush_int(mbuf, 1);
2315 /* This extracts the simple modes contained in mbuf
2317 * @param mbuf The mode buffer to extract the modes from.
2318 * @param buf The string buffer to write the modes into.
2321 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2323 static int flags[] = {
2324 /* MODE_CHANOP, 'o', */
2325 /* MODE_VOICE, 'v', */
2328 MODE_MODERATED, 'm',
2329 MODE_TOPICLIMIT, 't',
2330 MODE_INVITEONLY, 'i',
2331 MODE_NOPRIVMSGS, 'n',
2335 /* MODE_BAN, 'b', */
2342 int i, bufpos = 0, len;
2344 char *key = 0, limitbuf[20];
2345 char *apass = 0, *upass = 0;
2354 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2355 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2356 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2358 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2359 key = MB_STRING(mbuf, i);
2360 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2361 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2362 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2363 upass = MB_STRING(mbuf, i);
2364 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2365 apass = MB_STRING(mbuf, i);
2372 buf[bufpos++] = '+'; /* start building buffer */
2374 for (flag_p = flags; flag_p[0]; flag_p += 2)
2376 buf[bufpos++] = flag_p[1];
2378 for (i = 0, len = bufpos; i < len; i++) {
2380 build_string(buf, &bufpos, key, 0, ' ');
2381 else if (buf[i] == 'l')
2382 build_string(buf, &bufpos, limitbuf, 0, ' ');
2383 else if (buf[i] == 'U')
2384 build_string(buf, &bufpos, upass, 0, ' ');
2385 else if (buf[i] == 'A')
2386 build_string(buf, &bufpos, apass, 0, ' ');
2394 /** Simple function to invalidate bans
2396 * This function sets all bans as being valid.
2398 * @param chan The channel to operate on.
2401 mode_ban_invalidate(struct Channel *chan)
2403 struct Membership *member;
2405 for (member = chan->members; member; member = member->next_member)
2406 ClearBanValid(member);
2409 /** Simple function to drop invite structures
2411 * Remove all the invites on the channel.
2413 * @param chan Channel to remove invites from.
2417 mode_invite_clear(struct Channel *chan)
2419 while (chan->invites)
2420 del_invite(chan->invites->value.cptr, chan);
2423 /* What we've done for mode_parse so far... */
2424 #define DONE_LIMIT 0x01 /**< We've set the limit */
2425 #define DONE_KEY 0x02 /**< We've set the key */
2426 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2427 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2428 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2429 #define DONE_UPASS 0x20 /**< We've set user pass */
2430 #define DONE_APASS 0x40 /**< We've set admin pass */
2433 struct ModeBuf *mbuf;
2434 struct Client *cptr;
2435 struct Client *sptr;
2436 struct Channel *chptr;
2437 struct Membership *member;
2448 struct SLink banlist[MAXPARA];
2451 struct Client *client;
2452 } cli_change[MAXPARA];
2455 /** Helper function to send "Not oper" or "Not member" messages
2456 * Here's a helper function to deal with sending along "Not oper" or
2457 * "Not member" messages
2459 * @param state Parsing State object
2462 send_notoper(struct ParseState *state)
2464 if (state->done & DONE_NOTOPER)
2467 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2468 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2470 state->done |= DONE_NOTOPER;
2474 * Helper function to convert limits
2476 * @param state Parsing state object.
2480 mode_parse_limit(struct ParseState *state, int *flag_p)
2482 unsigned int t_limit;
2484 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2485 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2488 if (state->parc <= 0) { /* warn if not enough args */
2489 if (MyUser(state->sptr))
2490 need_more_params(state->sptr, "MODE +l");
2494 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2498 if ((int)t_limit<0) /* don't permit a negative limit */
2501 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2502 (!t_limit || t_limit == state->chptr->mode.limit))
2505 t_limit = state->chptr->mode.limit;
2507 /* If they're not an oper, they can't change modes */
2508 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2509 send_notoper(state);
2513 /* Can't remove a limit that's not there */
2514 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2517 /* Skip if this is a burst and a lower limit than this is set already */
2518 if ((state->flags & MODE_PARSE_BURST) &&
2519 (state->chptr->mode.mode & flag_p[0]) &&
2520 (state->chptr->mode.limit < t_limit))
2523 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2525 state->done |= DONE_LIMIT;
2530 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2532 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2533 if (state->dir & MODE_ADD) {
2534 state->chptr->mode.mode |= flag_p[0];
2535 state->chptr->mode.limit = t_limit;
2537 state->chptr->mode.mode &= ~flag_p[0];
2538 state->chptr->mode.limit = 0;
2544 * Helper function to convert keys
2547 mode_parse_key(struct ParseState *state, int *flag_p)
2552 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2555 if (state->parc <= 0) { /* warn if not enough args */
2556 if (MyUser(state->sptr))
2557 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2562 t_str = state->parv[state->args_used++]; /* grab arg */
2566 /* If they're not an oper, they can't change modes */
2567 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2568 send_notoper(state);
2572 if (state->done & DONE_KEY) /* allow key to be set only once */
2574 state->done |= DONE_KEY;
2578 /* clean up the key string */
2580 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2584 if (!*t_str) { /* warn if empty */
2585 if (MyUser(state->sptr))
2586 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2594 /* Skip if this is a burst, we have a key already and the new key is
2595 * after the old one alphabetically */
2596 if ((state->flags & MODE_PARSE_BURST) &&
2597 *(state->chptr->mode.key) &&
2598 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2601 /* can't add a key if one is set, nor can one remove the wrong key */
2602 if (!(state->flags & MODE_PARSE_FORCE))
2603 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2604 (state->dir == MODE_DEL &&
2605 ircd_strcmp(state->chptr->mode.key, t_str))) {
2606 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2610 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2611 !ircd_strcmp(state->chptr->mode.key, t_str))
2612 return; /* no key change */
2614 if (state->flags & MODE_PARSE_BOUNCE) {
2615 if (*state->chptr->mode.key) /* reset old key */
2616 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2617 state->chptr->mode.key, 0);
2618 else /* remove new bogus key */
2619 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2620 } else /* send new key */
2621 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2623 if (state->flags & MODE_PARSE_SET) {
2624 if (state->dir == MODE_ADD) /* set the new key */
2625 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2626 else /* remove the old key */
2627 *state->chptr->mode.key = '\0';
2632 * Helper function to convert user passes
2635 mode_parse_upass(struct ParseState *state, int *flag_p)
2640 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2643 if (state->parc <= 0) { /* warn if not enough args */
2644 if (MyUser(state->sptr))
2645 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2650 t_str = state->parv[state->args_used++]; /* grab arg */
2654 /* If they're not an oper, they can't change modes */
2655 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2656 send_notoper(state);
2660 /* If a non-service user is trying to force it, refuse. */
2661 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2662 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2663 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2667 /* If they are not the channel manager, they are not allowed to change it */
2668 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2669 if (*state->chptr->mode.apass) {
2670 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2671 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2673 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2674 "Re-create the channel. The channel must be *empty* for",
2675 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2676 "before it can be recreated.");
2681 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2683 state->done |= DONE_UPASS;
2685 t_len = PASSLEN + 1;
2687 /* clean up the upass string */
2689 while (*++s > ' ' && *s != ':' && --t_len)
2693 if (!*t_str) { /* warn if empty */
2694 if (MyUser(state->sptr))
2695 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2703 if (!(state->flags & MODE_PARSE_FORCE))
2704 /* can't add the upass while apass is not set */
2705 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2706 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2709 /* can't add a upass if one is set, nor can one remove the wrong upass */
2710 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2711 (state->dir == MODE_DEL &&
2712 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2713 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2717 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2718 !ircd_strcmp(state->chptr->mode.upass, t_str))
2719 return; /* no upass change */
2721 if (state->flags & MODE_PARSE_BOUNCE) {
2722 if (*state->chptr->mode.upass) /* reset old upass */
2723 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2724 state->chptr->mode.upass, 0);
2725 else /* remove new bogus upass */
2726 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2727 } else /* send new upass */
2728 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2730 if (state->flags & MODE_PARSE_SET) {
2731 if (state->dir == MODE_ADD) /* set the new upass */
2732 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2733 else /* remove the old upass */
2734 *state->chptr->mode.upass = '\0';
2739 * Helper function to convert admin passes
2742 mode_parse_apass(struct ParseState *state, int *flag_p)
2747 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2750 if (state->parc <= 0) { /* warn if not enough args */
2751 if (MyUser(state->sptr))
2752 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2757 t_str = state->parv[state->args_used++]; /* grab arg */
2761 /* If they're not an oper, they can't change modes */
2762 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2763 send_notoper(state);
2767 /* If a non-service user is trying to force it, refuse. */
2768 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2769 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2770 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2774 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2775 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2776 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2780 /* If they are not the channel manager, they are not allowed to change it */
2781 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2782 if (*state->chptr->mode.apass) {
2783 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2784 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2786 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2787 "Re-create the channel. The channel must be *empty* for",
2788 "at least a whole minute", "before it can be recreated.");
2793 if (state->done & DONE_APASS) /* allow apass to be set only once */
2795 state->done |= DONE_APASS;
2797 t_len = PASSLEN + 1;
2799 /* clean up the apass string */
2801 while (*++s > ' ' && *s != ':' && --t_len)
2805 if (!*t_str) { /* warn if empty */
2806 if (MyUser(state->sptr))
2807 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2815 if (!(state->flags & MODE_PARSE_FORCE)) {
2816 /* can't remove the apass while upass is still set */
2817 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2818 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2821 /* can't add an apass if one is set, nor can one remove the wrong apass */
2822 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2823 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2824 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2829 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2830 !ircd_strcmp(state->chptr->mode.apass, t_str))
2831 return; /* no apass change */
2833 if (state->flags & MODE_PARSE_BOUNCE) {
2834 if (*state->chptr->mode.apass) /* reset old apass */
2835 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2836 state->chptr->mode.apass, 0);
2837 else /* remove new bogus apass */
2838 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2839 } else /* send new apass */
2840 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2842 if (state->flags & MODE_PARSE_SET) {
2843 if (state->dir == MODE_ADD) { /* set the new apass */
2844 /* Make it VERY clear to the user that this is a one-time password */
2845 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2846 if (MyUser(state->sptr)) {
2847 send_reply(state->sptr, RPL_APASSWARN,
2848 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2849 "Are you SURE you want to use this as Admin password? ",
2850 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2851 send_reply(state->sptr, RPL_APASSWARN,
2852 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2853 "\" to remove the password and then immediately set a new one. "
2854 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2855 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2856 "Now set the channel user password (+u).");
2858 } else { /* remove the old apass */
2859 *state->chptr->mode.apass = '\0';
2860 if (MyUser(state->sptr))
2861 send_reply(state->sptr, RPL_APASSWARN,
2862 "WARNING: You removed the channel Admin password MODE (+A). ",
2863 "If you would disconnect or leave the channel without setting a new password then you will ",
2864 "not be able to set it again and lose ownership of this channel! ",
2865 "SET A NEW PASSWORD NOW!", "");
2871 * Helper function to convert bans
2874 mode_parse_ban(struct ParseState *state, int *flag_p)
2877 struct SLink *ban, *newban = 0;
2879 if (state->parc <= 0) { /* Not enough args, send ban list */
2880 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2881 send_ban_list(state->sptr, state->chptr);
2882 state->done |= DONE_BANLIST;
2888 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2891 t_str = state->parv[state->args_used++]; /* grab arg */
2895 /* If they're not an oper, they can't change modes */
2896 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2897 send_notoper(state);
2901 if ((s = strchr(t_str, ' ')))
2904 if (!*t_str || *t_str == ':') { /* warn if empty */
2905 if (MyUser(state->sptr))
2906 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2911 t_str = collapse(pretty_mask(t_str));
2913 /* remember the ban for the moment... */
2914 if (state->dir == MODE_ADD) {
2915 newban = state->banlist + (state->numbans++);
2918 DupString(newban->value.ban.banstr, t_str);
2919 newban->value.ban.who = cli_name(state->sptr);
2920 newban->value.ban.when = TStime();
2922 newban->flags = CHFL_BAN | MODE_ADD;
2924 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2925 newban->flags |= CHFL_BAN_IPMASK;
2928 if (!state->chptr->banlist) {
2929 state->chptr->banlist = newban; /* add our ban with its flags */
2930 state->done |= DONE_BANCLEAN;
2934 /* Go through all bans */
2935 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2936 /* first, clean the ban flags up a bit */
2937 if (!(state->done & DONE_BANCLEAN))
2938 /* Note: We're overloading *lots* of bits here; be careful! */
2939 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2943 * MODE_ADD - Ban was added; if we're bouncing modes,
2944 * then we'll remove it below; otherwise,
2945 * we'll have to allocate a real ban
2947 * MODE_DEL - Ban was marked for deletion; if we're
2948 * bouncing modes, we'll have to re-add it,
2949 * otherwise, we'll have to remove it
2951 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2952 * with a ban already set; if we're
2953 * bouncing modes, we'll have to bounce
2954 * this one; otherwise, we'll just ignore
2955 * it when we process added bans
2958 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2959 ban->flags |= MODE_DEL; /* delete one ban */
2961 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2963 } else if (state->dir == MODE_ADD) {
2964 /* if the ban already exists, don't worry about it */
2965 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2966 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2967 MyFree(newban->value.ban.banstr); /* stopper a leak */
2968 state->numbans--; /* deallocate last ban */
2969 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2971 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2972 if (!(ban->flags & MODE_DEL))
2973 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2974 } else if (!mmatch(t_str, ban->value.ban.banstr))
2975 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2977 if (!ban->next && (newban->flags & MODE_ADD))
2979 ban->next = newban; /* add our ban with its flags */
2980 break; /* get out of loop */
2984 state->done |= DONE_BANCLEAN;
2988 * This is the bottom half of the ban processor
2991 mode_process_bans(struct ParseState *state)
2993 struct SLink *ban, *newban, *prevban, *nextban;
2999 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
3001 banlen = strlen(ban->value.ban.banstr);
3003 nextban = ban->next;
3005 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
3007 prevban->next = 0; /* Break the list; ban isn't a real ban */
3009 state->chptr->banlist = 0;
3014 MyFree(ban->value.ban.banstr);
3017 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
3018 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
3019 ban->value.ban.banstr,
3020 state->flags & MODE_PARSE_SET);
3022 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
3023 if (prevban) /* clip it out of the list... */
3024 prevban->next = ban->next;
3026 state->chptr->banlist = ban->next;
3031 MyFree(ban->value.ban.who);
3035 continue; /* next ban; keep prevban like it is */
3037 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
3038 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
3040 prevban->next = 0; /* Break the list; ban isn't a real ban */
3042 state->chptr->banlist = 0;
3044 /* If we're supposed to ignore it, do so. */
3045 if (ban->flags & CHFL_BAN_OVERLAPPED &&
3046 !(state->flags & MODE_PARSE_BOUNCE)) {
3050 MyFree(ban->value.ban.banstr);
3052 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
3053 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
3054 count > feature_int(FEAT_MAXBANS))) {
3055 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
3056 ban->value.ban.banstr);
3060 MyFree(ban->value.ban.banstr);
3062 /* add the ban to the buffer */
3063 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
3064 ban->value.ban.banstr,
3065 !(state->flags & MODE_PARSE_SET));
3067 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3068 newban = make_link();
3069 newban->value.ban.banstr = ban->value.ban.banstr;
3070 DupString(newban->value.ban.who, ban->value.ban.who);
3071 newban->value.ban.when = ban->value.ban.when;
3072 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
3074 newban->next = state->chptr->banlist; /* and link it in */
3075 state->chptr->banlist = newban;
3084 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3086 if (changed) /* if we changed the ban list, we must invalidate the bans */
3087 mode_ban_invalidate(state->chptr);
3091 * Helper function to process client changes
3094 mode_parse_client(struct ParseState *state, int *flag_p)
3097 struct Client *acptr;
3100 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3103 if (state->parc <= 0) /* return if not enough args */
3106 t_str = state->parv[state->args_used++]; /* grab arg */
3110 /* If they're not an oper, they can't change modes */
3111 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3112 send_notoper(state);
3116 if (MyUser(state->sptr)) /* find client we're manipulating */
3117 acptr = find_chasing(state->sptr, t_str, NULL);
3119 acptr = findNUser(t_str);
3122 return; /* find_chasing() already reported an error to the user */
3124 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3125 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3126 state->cli_change[i].flag & flag_p[0]))
3127 break; /* found a slot */
3129 /* Store what we're doing to them */
3130 state->cli_change[i].flag = state->dir | flag_p[0];
3131 state->cli_change[i].client = acptr;
3135 * Helper function to process the changed client list
3138 mode_process_clients(struct ParseState *state)
3141 struct Membership *member;
3143 for (i = 0; state->cli_change[i].flag; i++) {
3144 assert(0 != state->cli_change[i].client);
3146 /* look up member link */
3147 if (!(member = find_member_link(state->chptr,
3148 state->cli_change[i].client)) ||
3149 (MyUser(state->sptr) && IsZombie(member))) {
3150 if (MyUser(state->sptr))
3151 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3152 cli_name(state->cli_change[i].client),
3153 state->chptr->chname);
3157 if ((state->cli_change[i].flag & MODE_ADD &&
3158 (state->cli_change[i].flag & member->status)) ||
3159 (state->cli_change[i].flag & MODE_DEL &&
3160 !(state->cli_change[i].flag & member->status)))
3161 continue; /* no change made, don't do anything */
3163 /* see if the deop is allowed */
3164 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3165 (MODE_DEL | MODE_CHANOP)) {
3166 /* prevent +k users from being deopped */
3167 if (IsChannelService(state->cli_change[i].client)) {
3168 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3169 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3171 (IsServer(state->sptr) ? cli_name(state->sptr) :
3172 cli_name((cli_user(state->sptr))->server)));
3174 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3175 send_reply(state->sptr, ERR_ISCHANSERVICE,
3176 cli_name(state->cli_change[i].client),
3177 state->chptr->chname);
3182 /* check deop for local user */
3183 if (MyUser(state->sptr)) {
3185 /* don't allow local opers to be deopped on local channels */
3186 if (state->cli_change[i].client != state->sptr &&
3187 IsLocalChannel(state->chptr->chname) &&
3188 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3189 send_reply(state->sptr, ERR_ISOPERLCHAN,
3190 cli_name(state->cli_change[i].client),
3191 state->chptr->chname);
3195 if (feature_bool(FEAT_OPLEVELS)) {
3196 /* don't allow to deop members with an op level that is <= our own level */
3197 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3199 && OpLevel(member) <= OpLevel(state->member)) {
3200 int equal = (OpLevel(member) == OpLevel(state->member));
3201 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3202 cli_name(state->cli_change[i].client),
3203 state->chptr->chname,
3204 OpLevel(state->member), OpLevel(member),
3205 "deop", equal ? "the same" : "a higher");
3212 /* set op-level of member being opped */
3213 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3214 (MODE_ADD | MODE_CHANOP)) {
3215 /* If on a channel with upass set, someone with level x gives ops to someone else,
3216 then that person gets level x-1. On other channels, where upass is not set,
3217 the level stays the same. */
3218 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3219 /* Someone being opped by a server gets op-level 0 */
3220 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3221 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3224 /* actually effect the change */
3225 if (state->flags & MODE_PARSE_SET) {
3226 if (state->cli_change[i].flag & MODE_ADD) {
3227 if (IsDelayedJoin(member))
3228 RevealDelayedJoin(member);
3229 member->status |= (state->cli_change[i].flag &
3230 (MODE_CHANOP | MODE_VOICE));
3231 if (state->cli_change[i].flag & MODE_CHANOP)
3232 ClearDeopped(member);
3234 member->status &= ~(state->cli_change[i].flag &
3235 (MODE_CHANOP | MODE_VOICE));
3238 /* accumulate the change */
3239 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3240 state->cli_change[i].client);
3241 } /* for (i = 0; state->cli_change[i].flags; i++) */
3245 * Helper function to process the simple modes
3248 mode_parse_mode(struct ParseState *state, int *flag_p)
3250 /* If they're not an oper, they can't change modes */
3251 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3252 send_notoper(state);
3259 if (state->dir == MODE_ADD) {
3260 state->add |= flag_p[0];
3261 state->del &= ~flag_p[0];
3263 if (flag_p[0] & MODE_SECRET) {
3264 state->add &= ~MODE_PRIVATE;
3265 state->del |= MODE_PRIVATE;
3266 } else if (flag_p[0] & MODE_PRIVATE) {
3267 state->add &= ~MODE_SECRET;
3268 state->del |= MODE_SECRET;
3270 if (flag_p[0] & MODE_DELJOINS) {
3271 state->add &= ~MODE_WASDELJOINS;
3272 state->del |= MODE_WASDELJOINS;
3275 state->add &= ~flag_p[0];
3276 state->del |= flag_p[0];
3279 assert(0 == (state->add & state->del));
3280 assert((MODE_SECRET | MODE_PRIVATE) !=
3281 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3285 * This routine is intended to parse MODE or OPMODE commands and effect the
3286 * changes (or just build the bounce buffer). We pass the starting offset
3290 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3291 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3292 struct Membership* member)
3294 static int chan_flags[] = {
3299 MODE_MODERATED, 'm',
3300 MODE_TOPICLIMIT, 't',
3301 MODE_INVITEONLY, 'i',
3302 MODE_NOPRIVMSGS, 'n',
3316 unsigned int t_mode;
3318 struct ParseState state;
3329 state.chptr = chptr;
3330 state.member = member;
3333 state.flags = flags;
3334 state.dir = MODE_ADD;
3338 state.args_used = 0;
3339 state.max_args = MAXMODEPARAMS;
3342 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3343 state.banlist[i].next = 0;
3344 state.banlist[i].value.ban.banstr = 0;
3345 state.banlist[i].value.ban.who = 0;
3346 state.banlist[i].value.ban.when = 0;
3347 state.banlist[i].flags = 0;
3348 state.cli_change[i].flag = 0;
3349 state.cli_change[i].client = 0;
3352 modestr = state.parv[state.args_used++];
3356 for (; *modestr; modestr++) {
3357 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3358 if (flag_p[1] == *modestr)
3361 if (!flag_p[0]) { /* didn't find it? complain and continue */
3362 if (MyUser(state.sptr))
3363 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3368 case '+': /* switch direction to MODE_ADD */
3369 case '-': /* switch direction to MODE_DEL */
3370 state.dir = flag_p[0];
3373 case 'l': /* deal with limits */
3374 mode_parse_limit(&state, flag_p);
3377 case 'k': /* deal with keys */
3378 mode_parse_key(&state, flag_p);
3381 case 'A': /* deal with Admin passes */
3382 if (feature_bool(FEAT_OPLEVELS))
3383 mode_parse_apass(&state, flag_p);
3386 case 'U': /* deal with user passes */
3387 if (feature_bool(FEAT_OPLEVELS))
3388 mode_parse_upass(&state, flag_p);
3391 case 'b': /* deal with bans */
3392 mode_parse_ban(&state, flag_p);
3395 case 'o': /* deal with ops/voice */
3397 mode_parse_client(&state, flag_p);
3400 default: /* deal with other modes */
3401 mode_parse_mode(&state, flag_p);
3403 } /* switch (*modestr) */
3404 } /* for (; *modestr; modestr++) */
3406 if (state.flags & MODE_PARSE_BURST)
3407 break; /* don't interpret any more arguments */
3409 if (state.parc > 0) { /* process next argument in string */
3410 modestr = state.parv[state.args_used++];
3414 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3417 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3418 break; /* we're then going to bounce the mode! */
3420 recv_ts = atoi(modestr);
3422 if (recv_ts && recv_ts < state.chptr->creationtime)
3423 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3425 break; /* break out of while loop */
3426 } else if (state.flags & MODE_PARSE_STRICT ||
3427 (MyUser(state.sptr) && state.max_args <= 0)) {
3428 state.parc++; /* we didn't actually gobble the argument */
3430 break; /* break out of while loop */
3433 } /* while (*modestr) */
3436 * the rest of the function finishes building resultant MODEs; if the
3437 * origin isn't a member or an oper, skip it.
3439 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3440 return state.args_used; /* tell our parent how many args we gobbled */
3442 t_mode = state.chptr->mode.mode;
3444 if (state.del & t_mode) { /* delete any modes to be deleted... */
3445 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3447 t_mode &= ~state.del;
3449 if (state.add & ~t_mode) { /* add any modes to be added... */
3450 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3452 t_mode |= state.add;
3455 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3456 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3457 !(t_mode & MODE_INVITEONLY))
3458 mode_invite_clear(state.chptr);
3460 state.chptr->mode.mode = t_mode;
3463 if (state.flags & MODE_PARSE_WIPEOUT) {
3464 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3465 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3466 state.chptr->mode.limit);
3467 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3468 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3469 state.chptr->mode.key, 0);
3470 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3471 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3472 state.chptr->mode.upass, 0);
3473 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3474 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3475 state.chptr->mode.apass, 0);
3478 if (state.done & DONE_BANCLEAN) /* process bans */
3479 mode_process_bans(&state);
3481 /* process client changes */
3482 if (state.cli_change[0].flag)
3483 mode_process_clients(&state);
3485 return state.args_used; /* tell our parent how many args we gobbled */
3489 * Initialize a join buffer
3492 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3493 struct Client *connect, unsigned int type, char *comment,
3499 assert(0 != source);
3500 assert(0 != connect);
3502 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3503 jbuf->jb_connect = connect;
3504 jbuf->jb_type = type;
3505 jbuf->jb_comment = comment;
3506 jbuf->jb_create = create;
3508 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3509 type == JOINBUF_TYPE_PART ||
3510 type == JOINBUF_TYPE_PARTALL) ?
3511 STARTJOINLEN : STARTCREATELEN) +
3512 (comment ? strlen(comment) + 2 : 0));
3514 for (i = 0; i < MAXJOINARGS; i++)
3515 jbuf->jb_channels[i] = 0;
3519 * Add a channel to the join buffer
3522 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3530 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3531 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3536 is_local = IsLocalChannel(chan->chname);
3538 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3539 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3540 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3541 if (IsUserParting(member))
3543 SetUserParting(member);
3545 /* Send notification to channel */
3546 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3547 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3548 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3549 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3550 else if (MyUser(jbuf->jb_source))
3551 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3552 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3553 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3554 /* XXX: Shouldn't we send a PART here anyway? */
3555 /* to users on the channel? Why? From their POV, the user isn't on
3556 * the channel anymore anyway. We don't send to servers until below,
3557 * when we gang all the channel parts together. Note that this is
3558 * exactly the same logic, albeit somewhat more concise, as was in
3559 * the original m_part.c */
3561 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3562 is_local) /* got to remove user here */
3563 remove_user_from_channel(jbuf->jb_source, chan);
3565 /* Add user to channel */
3566 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3567 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3569 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3571 /* send notification to all servers */
3572 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3573 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3574 "%H %Tu", chan, chan->creationtime);
3576 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3577 /* Send the notification to the channel */
3578 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3580 /* send an op, too, if needed */
3581 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3582 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3583 chan, jbuf->jb_source);
3584 } else if (MyUser(jbuf->jb_source))
3585 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3588 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3589 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3590 return; /* don't send to remote */
3592 /* figure out if channel name will cause buffer to be overflowed */
3593 len = chan ? strlen(chan->chname) + 1 : 2;
3594 if (jbuf->jb_strlen + len > BUFSIZE)
3595 joinbuf_flush(jbuf);
3597 /* add channel to list of channels to send and update counts */
3598 jbuf->jb_channels[jbuf->jb_count++] = chan;
3599 jbuf->jb_strlen += len;
3601 /* if we've used up all slots, flush */
3602 if (jbuf->jb_count >= MAXJOINARGS)
3603 joinbuf_flush(jbuf);
3607 * Flush the channel list to remote servers
3610 joinbuf_flush(struct JoinBuf *jbuf)
3612 char chanlist[BUFSIZE];
3616 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3617 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3618 return 0; /* no joins to process */
3620 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3621 build_string(chanlist, &chanlist_i,
3622 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3623 i == 0 ? '\0' : ',');
3624 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3625 /* Remove user from channel */
3626 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3628 jbuf->jb_channels[i] = 0; /* mark slot empty */
3631 jbuf->jb_count = 0; /* reset base counters */
3632 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3633 STARTJOINLEN : STARTCREATELEN) +
3634 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3636 /* and send the appropriate command */
3637 switch (jbuf->jb_type) {
3638 case JOINBUF_TYPE_CREATE:
3639 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3640 "%s %Tu", chanlist, jbuf->jb_create);
3643 case JOINBUF_TYPE_PART:
3644 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3645 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3653 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3654 int IsInvited(struct Client* cptr, const void* chptr)
3658 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3659 if (lp->value.chptr == chptr)
3664 /* RevealDelayedJoin: sends a join for a hidden user */
3666 void RevealDelayedJoin(struct Membership *member) {
3667 ClearDelayedJoin(member);
3668 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3670 CheckDelayedJoins(member->channel);
3673 /* CheckDelayedJoins: checks and clear +d if necessary */
3675 void CheckDelayedJoins(struct Channel *chan) {
3676 struct Membership *memb2;
3678 if (chan->mode.mode & MODE_WASDELJOINS) {
3679 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3680 if (IsDelayedJoin(memb2))
3685 chan->mode.mode &= ~MODE_WASDELJOINS;
3686 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,