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"
62 /** Linked list containing the full list of all channels */
63 struct Channel* GlobalChannelList = 0;
65 /** Number of struct Membership*'s allocated */
66 static unsigned int membershipAllocCount;
67 /** Freelist for struct Membership*'s */
68 static struct Membership* membershipFreeList;
70 void del_invite(struct Client *, struct Channel *);
72 const char* const PartFmt1 = ":%s " MSG_PART " %s";
73 const char* const PartFmt2 = ":%s " MSG_PART " %s :%s";
74 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
75 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
78 static struct SLink* next_ban;
79 static struct SLink* prev_ban;
80 static struct SLink* removed_bans_list;
83 * Use a global variable to remember if an oper set a mode on a local channel.
84 * Ugly, but the only way to do it without changing set_mode intensively.
86 int LocalChanOperMode = 0;
89 /** return the length (>=0) of a chain of links.
90 * @param lp pointer to the start of the linked list
91 * @return the number of items in the list
93 static int list_length(struct SLink *lp)
97 for (; lp; lp = lp->next)
103 /** return the struct Membership* that represents a client on a channel
104 * This function finds a struct Membership* which holds the state about
105 * a client on a specific channel. The code is smart enough to iterate
106 * over the channels a user is in, or the users in a channel to find the
107 * user depending on which is likely to be more efficient.
109 * @param chptr pointer to the channel struct
110 * @param cptr pointer to the client struct
112 * @returns pointer to the struct Membership representing this client on
113 * this channel. Returns NULL if the client is not on the channel.
114 * Returns NULL if the client is actually a server.
115 * @see find_channel_member()
117 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
119 struct Membership *m;
123 /* Servers don't have member links */
124 if (IsServer(cptr)||IsMe(cptr))
127 /* +k users are typically on a LOT of channels. So we iterate over who
128 * is in the channel. X/W are +k and are in about 5800 channels each.
129 * however there are typically no more than 1000 people in a channel
132 if (IsChannelService(cptr)) {
135 assert(m->channel == chptr);
141 /* Users on the other hand aren't allowed on more than 15 channels. 50%
142 * of users that are on channels are on 2 or less, 95% are on 7 or less,
143 * and 99% are on 10 or less.
146 m = (cli_user(cptr))->channel;
148 assert(m->user == cptr);
149 if (m->channel == chptr)
157 /** Find the client structure for a nick name (user)
158 * Find the client structure for a nick name (user)
159 * using history mechanism if necessary. If the client is not found, an error
160 * message (NO SUCH NICK) is generated. If the client was found
161 * through the history, chasing will be 1 and otherwise 0.
163 * This function was used extensively in the P09 days, and since we now have
164 * numeric nicks is no longer quite as important.
166 * @param sptr Pointer to the client that has requested the search
167 * @param user a string represeting the client to be found
168 * @param chasing a variable set to 0 if the user was found directly,
170 * @returns a pointer the client, or NULL if the client wasn't found.
172 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
174 struct Client* who = FindClient(user);
181 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
182 send_reply(sptr, ERR_NOSUCHNICK, user);
190 /** build up a hostmask
191 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
192 * as the parameters. If NULL, they become "*".
193 * @param namebuf the buffer to build the hostmask into. Must be at least
194 * NICKLEN+USERLEN+HOSTLEN+3 charactors long.
195 * @param nick The nickname
196 * @param name The ident
197 * @param host the hostname
199 * @see make_nick_user_ip()
201 static char *make_nick_user_host(char *namebuf, const char *nick,
202 const char *name, const char *host)
204 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
205 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
209 /** Create a hostmask using an IP address
210 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
211 * IP-number as the parameters. If NULL, they become "*".
213 * @param ipbuf Buffer at least NICKLEN+USERLEN+SOCKIPLEN+4 to hold the final
215 * @param nick The nickname (or NULL for *)
216 * @param name The ident (or NULL for *)
217 * @param ip The IP address
219 * @see make_nick_user_host()
221 #define NUI_BUFSIZE (NICKLEN + USERLEN + SOCKIPLEN + 4)
222 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
223 const struct irc_in_addr *ip)
225 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
229 /** Decrement the count of users, and free if empty.
230 * Subtract one user from channel i (and free channel * block, if channel
233 * @param chptr The channel to subtract one from.
235 * @returns true (1) if channel still has members.
236 * false (0) if the channel is now empty.
238 int sub1_from_channel(struct Channel* chptr)
240 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
242 assert(0 != chptr->members);
250 * Also channels without Apass set need to be kept alive,
251 * otherwise Bad Guys(tm) would be able to takeover
252 * existing channels too easily, and then set an Apass!
253 * However, if a channel without Apass becomes empty
254 * then we try to be kind to them and remove possible
257 chptr->mode.mode &= ~MODE_INVITEONLY;
258 chptr->mode.limit = 0;
260 * We do NOT reset a possible key or bans because when
261 * the 'channel owners' can't get in because of a key
262 * or ban then apparently there was a fight/takeover
263 * on the channel and we want them to contact IRC opers
264 * who then will educate them on the use of Apass/upass.
267 if (feature_bool(FEAT_OPLEVELS)) {
268 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
269 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
271 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
273 destruct_channel(chptr);
278 /** Destroy an empty channel
279 * This function destroys an empty channel, removing it from hashtables,
280 * and removing any resources it may have consumed.
282 * @param chptr The channel to destroy
284 * @returns 0 (success)
286 * FIXME: Change to return void, this function never fails.
288 int destruct_channel(struct Channel* chptr)
293 assert(0 == chptr->members);
295 /* Channel became (or was) empty: Remove channel */
296 if (is_listed(chptr))
299 for (i = 0; i <= HighestFd; i++)
301 struct Client *acptr = 0;
302 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
303 (cli_listing(acptr))->chptr == chptr)
305 list_next_channels(acptr, 1);
306 break; /* Only one client can list a channel */
311 * Now, find all invite links from channel structure
313 while ((tmp = chptr->invites))
314 del_invite(tmp->value.cptr, chptr);
316 tmp = chptr->banlist;
321 MyFree(obtmp->value.ban.banstr);
322 MyFree(obtmp->value.ban.who);
326 chptr->prev->next = chptr->next;
328 GlobalChannelList = chptr->next;
330 chptr->next->prev = chptr->prev;
332 --UserStats.channels;
334 * make sure that channel actually got removed from hash table
336 assert(chptr->hnext == chptr);
341 /** add a ban to a channel
343 * `cptr' must be the client adding the ban.
345 * If `change' is true then add `banid' to channel `chptr'.
346 * Returns 0 if the ban was added.
347 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
348 * Return -1 otherwise.
350 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
351 * when `change' is false, otherwise they will be removed from the banlist.
352 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
353 * respectively will return these bans until NULL is returned.
355 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
356 * is reset (unless a non-zero value is returned, in which case the
357 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
360 * @param cptr Client adding the ban
361 * @param chptr Channel to add the ban to
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 channel 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 membership 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 <channel list> <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 ch 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
1644 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1645 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1647 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1648 * Remove the user immediately when no users are left on the channel.
1649 * b) On server B : remove the user (who/lp) from the channel, send a
1650 * PART upstream (to A) and pass on the KICK.
1651 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1652 * channel, and pass on the KICK.
1653 * d) On server D : remove the user (who/lp) from the channel, and pass on
1657 * - Setting the ZOMBIE flag never hurts, we either remove the
1658 * client after that or we don't.
1659 * - The KICK message was already passed on, as should be in all cases.
1660 * - `who' is removed in all cases except case a) when users are left.
1661 * - A PART is only sent upstream in case b).
1667 * 1 --- 2 --- 3 --- 4 --- 5
1671 * We also need to turn 'who' into a zombie on servers 1 and 6,
1672 * because a KICK from 'who' (kicking someone else in that direction)
1673 * can arrive there afterwards - which should not be bounced itself.
1674 * Therefore case a) also applies for servers 1 and 6.
1679 /** Turn a user on a channel into a zombie
1680 * This function turns a user into a zombie (see \ref zombie)
1682 * @param member The structure representing this user on this channel.
1683 * @param who The client that is being kicked.
1684 * @param cptr The connection the kick came from.
1685 * @param sptr The client that is doing the kicking.
1686 * @param chptr The channel the user is being kicked from.
1688 void make_zombie(struct Membership* member, struct Client* who,
1689 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1691 assert(0 != member);
1696 /* Default for case a): */
1699 /* Case b) or c) ?: */
1700 if (MyUser(who)) /* server 4 */
1702 if (IsServer(cptr)) /* Case b) ? */
1703 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1704 remove_user_from_channel(who, chptr);
1707 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1709 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1710 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1711 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1713 remove_user_from_channel(who, chptr);
1718 /* Case a) (servers 1, 2, 3 and 6) */
1719 if (channel_all_zombies(chptr))
1720 remove_user_from_channel(who, chptr);
1722 /* XXX Can't actually call Debug here; if the channel is all zombies,
1723 * chptr will no longer exist when we get here.
1724 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1728 /** returns the number of zombies on a channel
1729 * @param chptr Channel to count zombies in.
1731 * @returns The number of zombies on the channel.
1733 int number_of_zombies(struct Channel *chptr)
1735 struct Membership* member;
1739 for (member = chptr->members; member; member = member->next_member) {
1740 if (IsZombie(member))
1746 /** Concatenate some strings together.
1747 * This helper function builds an argument string in strptr, consisting
1748 * of the original string, a space, and str1 and str2 concatenated (if,
1749 * of course, str2 is not NULL)
1751 * @param strptr The buffer to concatenate into
1752 * @param strptr_i modified offset to the position to modify
1753 * @param str1 The string to contatenate from.
1754 * @param str2 The second string to contatenate from.
1755 * @param c Charactor to seperate the string from str1 and str2.
1758 build_string(char *strptr, int *strptr_i, const char *str1,
1759 const char *str2, char c)
1762 strptr[(*strptr_i)++] = c;
1765 strptr[(*strptr_i)++] = *(str1++);
1769 strptr[(*strptr_i)++] = *(str2++);
1771 strptr[(*strptr_i)] = '\0';
1774 /** Flush out the modes
1775 * This is the workhorse of our ModeBuf suite; this actually generates the
1776 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1778 * @param mbuf The mode buffer to flush
1779 * @param all If true, flush all modes, otherwise leave partial modes in the
1785 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1787 /* we only need the flags that don't take args right now */
1788 static int flags[] = {
1789 /* MODE_CHANOP, 'o', */
1790 /* MODE_VOICE, 'v', */
1793 MODE_MODERATED, 'm',
1794 MODE_TOPICLIMIT, 't',
1795 MODE_INVITEONLY, 'i',
1796 MODE_NOPRIVMSGS, 'n',
1799 MODE_WASDELJOINS, 'd',
1800 /* MODE_KEY, 'k', */
1801 /* MODE_BAN, 'b', */
1803 /* MODE_APASS, 'A', */
1804 /* MODE_UPASS, 'U', */
1810 struct Client *app_source; /* where the MODE appears to come from */
1812 char addbuf[20]; /* accumulates +psmtin, etc. */
1814 char rembuf[20]; /* accumulates -psmtin, etc. */
1816 char *bufptr; /* we make use of indirection to simplify the code */
1819 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1821 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1823 char *strptr; /* more indirection to simplify the code */
1826 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1829 char limitbuf[20]; /* convert limits to strings */
1831 unsigned int limitdel = MODE_LIMIT;
1835 /* If the ModeBuf is empty, we have nothing to do */
1836 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1839 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1841 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1844 app_source = mbuf->mb_source;
1847 * Account for user we're bouncing; we have to get it in on the first
1848 * bounced MODE, or we could have problems
1850 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1851 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1853 /* Calculate the simple flags */
1854 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1855 if (*flag_p & mbuf->mb_add)
1856 addbuf[addbuf_i++] = flag_p[1];
1857 else if (*flag_p & mbuf->mb_rem)
1858 rembuf[rembuf_i++] = flag_p[1];
1861 /* Now go through the modes with arguments... */
1862 for (i = 0; i < mbuf->mb_count; i++) {
1863 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1865 bufptr_i = &addbuf_i;
1868 bufptr_i = &rembuf_i;
1871 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1872 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1874 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1875 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1877 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1878 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1880 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1881 tmp = strlen(MB_STRING(mbuf, i));
1883 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1884 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1887 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1899 bufptr[(*bufptr_i)++] = mode_char;
1900 totalbuflen -= tmp + 1;
1902 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1903 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1904 strlen(MB_STRING(mbuf, i)));
1906 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1907 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1909 bufptr[(*bufptr_i)++] = 'k';
1910 totalbuflen -= tmp + 1;
1912 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1913 /* if it's a limit, we also format the number */
1914 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1916 tmp = strlen(limitbuf);
1918 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1919 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1921 bufptr[(*bufptr_i)++] = 'l';
1922 totalbuflen -= tmp + 1;
1927 /* terminate the mode strings */
1928 addbuf[addbuf_i] = '\0';
1929 rembuf[rembuf_i] = '\0';
1931 /* If we're building a user visible MODE or HACK... */
1932 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1933 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1934 MODEBUF_DEST_LOG)) {
1935 /* Set up the parameter strings */
1941 for (i = 0; i < mbuf->mb_count; i++) {
1942 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1945 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1947 strptr_i = &addstr_i;
1950 strptr_i = &remstr_i;
1953 /* deal with clients... */
1954 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1955 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1957 /* deal with bans... */
1958 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1959 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1961 /* deal with keys... */
1962 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1963 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1964 "*" : MB_STRING(mbuf, i), 0, ' ');
1966 /* deal with invisible passwords */
1967 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1968 build_string(strptr, strptr_i, "*", 0, ' ');
1971 * deal with limit; note we cannot include the limit parameter if we're
1974 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1975 (MODE_ADD | MODE_LIMIT))
1976 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1979 /* send the messages off to their destination */
1980 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1981 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1983 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1984 mbuf->mb_source : app_source),
1985 mbuf->mb_channel->chname,
1986 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1987 addbuf, remstr, addstr,
1988 mbuf->mb_channel->creationtime);
1990 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1991 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1992 "%s%s%s%s%s%s [%Tu]",
1993 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1994 mbuf->mb_source : app_source),
1995 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1996 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1997 mbuf->mb_channel->creationtime);
1999 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
2000 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
2002 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
2003 mbuf->mb_source : app_source),
2004 mbuf->mb_channel->chname,
2005 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2006 addbuf, remstr, addstr,
2007 mbuf->mb_channel->creationtime);
2009 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
2010 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
2011 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
2012 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
2013 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2015 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
2016 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
2017 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2018 rembuf_i ? "-" : "", rembuf,
2019 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2022 /* Now are we supposed to propagate to other servers? */
2023 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
2024 /* set up parameter string */
2031 * limit is supressed if we're removing it; we have to figure out which
2032 * direction is the direction for it to be removed, though...
2034 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
2036 for (i = 0; i < mbuf->mb_count; i++) {
2037 if (MB_TYPE(mbuf, i) & MODE_SAVE)
2040 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2042 strptr_i = &addstr_i;
2045 strptr_i = &remstr_i;
2048 /* deal with modes that take clients */
2049 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2050 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2052 /* deal with modes that take strings */
2053 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
2054 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2057 * deal with the limit. Logic here is complicated; if HACK2 is set,
2058 * we're bouncing the mode, so sense is reversed, and we have to
2059 * include the original limit if it looks like it's being removed
2061 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2062 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2065 /* we were told to deop the source */
2066 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2067 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2068 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2069 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2071 /* mark that we've done this, so we don't do it again */
2072 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2075 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2076 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2077 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2078 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2079 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2080 addbuf, remstr, addstr);
2081 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2083 * If HACK2 was set, we're bouncing; we send the MODE back to the
2084 * connection we got it from with the senses reversed and a TS of 0;
2087 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2088 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2089 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2090 mbuf->mb_channel->creationtime);
2093 * We're propagating a normal MODE command to the rest of the network;
2094 * we send the actual channel TS unless this is a HACK3 or a HACK4
2096 if (IsServer(mbuf->mb_source))
2097 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2098 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2099 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2100 addbuf, remstr, addstr,
2101 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2102 mbuf->mb_channel->creationtime);
2104 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2105 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2106 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2107 addbuf, remstr, addstr);
2111 /* We've drained the ModeBuf... */
2116 /* reinitialize the mode-with-arg slots */
2117 for (i = 0; i < MAXMODEPARAMS; i++) {
2118 /* If we saved any, pack them down */
2119 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2120 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2121 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2123 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2125 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2126 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2128 MB_TYPE(mbuf, i) = 0;
2129 MB_UINT(mbuf, i) = 0;
2132 /* If we're supposed to flush it all, do so--all hail tail recursion */
2133 if (all && mbuf->mb_count)
2134 return modebuf_flush_int(mbuf, 1);
2139 /** Initialise a modebuf
2140 * This routine just initializes a ModeBuf structure with the information
2141 * needed and the options given.
2143 * @param mbuf The mode buffer to initialise.
2144 * @param source The client that is performing the mode.
2146 * @param chan The channel that the mode is being performed upon.
2150 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2151 struct Client *connect, struct Channel *chan, unsigned int dest)
2156 assert(0 != source);
2160 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2164 mbuf->mb_source = source;
2165 mbuf->mb_connect = connect;
2166 mbuf->mb_channel = chan;
2167 mbuf->mb_dest = dest;
2170 /* clear each mode-with-parameter slot */
2171 for (i = 0; i < MAXMODEPARAMS; i++) {
2172 MB_TYPE(mbuf, i) = 0;
2173 MB_UINT(mbuf, i) = 0;
2177 /** Append a new mode to a modebuf
2178 * This routine simply adds modes to be added or deleted; do a binary OR
2179 * with either MODE_ADD or MODE_DEL
2181 * @param mbuf Mode buffer
2182 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2185 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2188 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2190 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2191 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2192 MODE_DELJOINS | MODE_WASDELJOINS);
2194 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2197 if (mode & MODE_ADD) {
2198 mbuf->mb_rem &= ~mode;
2199 mbuf->mb_add |= mode;
2201 mbuf->mb_add &= ~mode;
2202 mbuf->mb_rem |= mode;
2206 /** Append a mode that takes an int argument to the modebuf
2208 * This routine adds a mode to be added or deleted that takes a unsigned
2209 * int parameter; mode may *only* be the relevant mode flag ORed with one
2210 * of MODE_ADD or MODE_DEL
2212 * @param mbuf The mode buffer to append to.
2213 * @param mode The mode to append.
2214 * @param uint The argument to the mode.
2217 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2220 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2222 if (mode == (MODE_LIMIT | MODE_DEL)) {
2223 mbuf->mb_rem |= mode;
2226 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2227 MB_UINT(mbuf, mbuf->mb_count) = uint;
2229 /* when we've reached the maximal count, flush the buffer */
2230 if (++mbuf->mb_count >=
2231 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2232 modebuf_flush_int(mbuf, 0);
2235 /** append a string mode
2236 * This routine adds a mode to be added or deleted that takes a string
2237 * parameter; mode may *only* be the relevant mode flag ORed with one of
2238 * MODE_ADD or MODE_DEL
2240 * @param mbuf The mode buffer to append to.
2241 * @param mode The mode to append.
2242 * @param string The string parameter to append.
2243 * @param free If the string should be free'd later.
2246 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2250 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2252 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2253 MB_STRING(mbuf, mbuf->mb_count) = string;
2255 /* when we've reached the maximal count, flush the buffer */
2256 if (++mbuf->mb_count >=
2257 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2258 modebuf_flush_int(mbuf, 0);
2261 /** Append a mode on a client to a modebuf.
2262 * This routine adds a mode to be added or deleted that takes a client
2263 * parameter; mode may *only* be the relevant mode flag ORed with one of
2264 * MODE_ADD or MODE_DEL
2266 * @param mbuf The modebuf to append the mode to.
2267 * @param mode The mode to append.
2268 * @param client The client argument to append.
2271 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2272 struct Client *client)
2275 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2277 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2278 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2280 /* when we've reached the maximal count, flush the buffer */
2281 if (++mbuf->mb_count >=
2282 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2283 modebuf_flush_int(mbuf, 0);
2286 /** The exported binding for modebuf_flush()
2288 * @param mbuf The mode buffer to flush.
2290 * @see modebuf_flush_int()
2293 modebuf_flush(struct ModeBuf *mbuf)
2295 struct Membership *memb;
2297 /* Check if MODE_WASDELJOINS should be set */
2298 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2299 && (mbuf->mb_rem & MODE_DELJOINS)) {
2300 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2301 if (IsDelayedJoin(memb)) {
2302 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2303 mbuf->mb_add |= MODE_WASDELJOINS;
2304 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2310 return modebuf_flush_int(mbuf, 1);
2313 /* This extracts the simple modes contained in mbuf
2315 * @param mbuf The mode buffer to extract the modes from.
2316 * @param buf The string buffer to write the modes into.
2319 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2321 static int flags[] = {
2322 /* MODE_CHANOP, 'o', */
2323 /* MODE_VOICE, 'v', */
2326 MODE_MODERATED, 'm',
2327 MODE_TOPICLIMIT, 't',
2328 MODE_INVITEONLY, 'i',
2329 MODE_NOPRIVMSGS, 'n',
2333 /* MODE_BAN, 'b', */
2340 int i, bufpos = 0, len;
2342 char *key = 0, limitbuf[20];
2343 char *apass = 0, *upass = 0;
2352 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2353 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2354 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2356 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2357 key = MB_STRING(mbuf, i);
2358 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2359 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2360 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2361 upass = MB_STRING(mbuf, i);
2362 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2363 apass = MB_STRING(mbuf, i);
2370 buf[bufpos++] = '+'; /* start building buffer */
2372 for (flag_p = flags; flag_p[0]; flag_p += 2)
2374 buf[bufpos++] = flag_p[1];
2376 for (i = 0, len = bufpos; i < len; i++) {
2378 build_string(buf, &bufpos, key, 0, ' ');
2379 else if (buf[i] == 'l')
2380 build_string(buf, &bufpos, limitbuf, 0, ' ');
2381 else if (buf[i] == 'U')
2382 build_string(buf, &bufpos, upass, 0, ' ');
2383 else if (buf[i] == 'A')
2384 build_string(buf, &bufpos, apass, 0, ' ');
2392 /** Simple function to invalidate bans
2394 * This function sets all bans as being valid.
2396 * @param chan The channel to operate on.
2399 mode_ban_invalidate(struct Channel *chan)
2401 struct Membership *member;
2403 for (member = chan->members; member; member = member->next_member)
2404 ClearBanValid(member);
2407 /** Simple function to drop invite structures
2409 * Remove all the invites on the channel.
2411 * @param chan Channel to remove invites from.
2415 mode_invite_clear(struct Channel *chan)
2417 while (chan->invites)
2418 del_invite(chan->invites->value.cptr, chan);
2421 /* What we've done for mode_parse so far... */
2422 #define DONE_LIMIT 0x01 /**< We've set the limit */
2423 #define DONE_KEY 0x02 /**< We've set the key */
2424 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2425 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2426 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2427 #define DONE_UPASS 0x20 /**< We've set user pass */
2428 #define DONE_APASS 0x40 /**< We've set admin pass */
2431 struct ModeBuf *mbuf;
2432 struct Client *cptr;
2433 struct Client *sptr;
2434 struct Channel *chptr;
2435 struct Membership *member;
2446 struct SLink banlist[MAXPARA];
2449 struct Client *client;
2450 } cli_change[MAXPARA];
2453 /** Helper function to send "Not oper" or "Not member" messages
2454 * Here's a helper function to deal with sending along "Not oper" or
2455 * "Not member" messages
2457 * @param state Parsing State object
2460 send_notoper(struct ParseState *state)
2462 if (state->done & DONE_NOTOPER)
2465 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2466 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2468 state->done |= DONE_NOTOPER;
2472 * Helper function to convert limits
2474 * @param state Parsing state object.
2478 mode_parse_limit(struct ParseState *state, int *flag_p)
2480 unsigned int t_limit;
2482 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2483 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2486 if (state->parc <= 0) { /* warn if not enough args */
2487 if (MyUser(state->sptr))
2488 need_more_params(state->sptr, "MODE +l");
2492 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2496 if ((int)t_limit<0) /* don't permit a negative limit */
2499 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2500 (!t_limit || t_limit == state->chptr->mode.limit))
2503 t_limit = state->chptr->mode.limit;
2505 /* If they're not an oper, they can't change modes */
2506 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2507 send_notoper(state);
2511 /* Can't remove a limit that's not there */
2512 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2515 /* Skip if this is a burst and a lower limit than this is set already */
2516 if ((state->flags & MODE_PARSE_BURST) &&
2517 (state->chptr->mode.mode & flag_p[0]) &&
2518 (state->chptr->mode.limit < t_limit))
2521 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2523 state->done |= DONE_LIMIT;
2528 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2530 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2531 if (state->dir & MODE_ADD) {
2532 state->chptr->mode.mode |= flag_p[0];
2533 state->chptr->mode.limit = t_limit;
2535 state->chptr->mode.mode &= ~flag_p[0];
2536 state->chptr->mode.limit = 0;
2542 * Helper function to convert keys
2545 mode_parse_key(struct ParseState *state, int *flag_p)
2550 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2553 if (state->parc <= 0) { /* warn if not enough args */
2554 if (MyUser(state->sptr))
2555 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2560 t_str = state->parv[state->args_used++]; /* grab arg */
2564 /* If they're not an oper, they can't change modes */
2565 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2566 send_notoper(state);
2570 if (state->done & DONE_KEY) /* allow key to be set only once */
2572 state->done |= DONE_KEY;
2576 /* clean up the key string */
2578 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2582 if (!*t_str) { /* warn if empty */
2583 if (MyUser(state->sptr))
2584 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2592 /* Skip if this is a burst, we have a key already and the new key is
2593 * after the old one alphabetically */
2594 if ((state->flags & MODE_PARSE_BURST) &&
2595 *(state->chptr->mode.key) &&
2596 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2599 /* can't add a key if one is set, nor can one remove the wrong key */
2600 if (!(state->flags & MODE_PARSE_FORCE))
2601 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2602 (state->dir == MODE_DEL &&
2603 ircd_strcmp(state->chptr->mode.key, t_str))) {
2604 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2608 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2609 !ircd_strcmp(state->chptr->mode.key, t_str))
2610 return; /* no key change */
2612 if (state->flags & MODE_PARSE_BOUNCE) {
2613 if (*state->chptr->mode.key) /* reset old key */
2614 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2615 state->chptr->mode.key, 0);
2616 else /* remove new bogus key */
2617 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2618 } else /* send new key */
2619 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2621 if (state->flags & MODE_PARSE_SET) {
2622 if (state->dir == MODE_ADD) /* set the new key */
2623 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2624 else /* remove the old key */
2625 *state->chptr->mode.key = '\0';
2630 * Helper function to convert user passes
2633 mode_parse_upass(struct ParseState *state, int *flag_p)
2638 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2641 if (state->parc <= 0) { /* warn if not enough args */
2642 if (MyUser(state->sptr))
2643 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2648 t_str = state->parv[state->args_used++]; /* grab arg */
2652 /* If they're not an oper, they can't change modes */
2653 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2654 send_notoper(state);
2658 /* If a non-service user is trying to force it, refuse. */
2659 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2660 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2661 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2665 /* If they are not the channel manager, they are not allowed to change it */
2666 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2667 if (*state->chptr->mode.apass) {
2668 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2669 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2671 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2672 "Re-create the channel. The channel must be *empty* for",
2673 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2674 "before it can be recreated.");
2679 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2681 state->done |= DONE_UPASS;
2683 t_len = PASSLEN + 1;
2685 /* clean up the upass string */
2687 while (*++s > ' ' && *s != ':' && --t_len)
2691 if (!*t_str) { /* warn if empty */
2692 if (MyUser(state->sptr))
2693 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2701 if (!(state->flags & MODE_PARSE_FORCE))
2702 /* can't add the upass while apass is not set */
2703 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2704 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2707 /* can't add a upass if one is set, nor can one remove the wrong upass */
2708 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2709 (state->dir == MODE_DEL &&
2710 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2711 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2715 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2716 !ircd_strcmp(state->chptr->mode.upass, t_str))
2717 return; /* no upass change */
2719 if (state->flags & MODE_PARSE_BOUNCE) {
2720 if (*state->chptr->mode.upass) /* reset old upass */
2721 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2722 state->chptr->mode.upass, 0);
2723 else /* remove new bogus upass */
2724 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2725 } else /* send new upass */
2726 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2728 if (state->flags & MODE_PARSE_SET) {
2729 if (state->dir == MODE_ADD) /* set the new upass */
2730 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2731 else /* remove the old upass */
2732 *state->chptr->mode.upass = '\0';
2737 * Helper function to convert admin passes
2740 mode_parse_apass(struct ParseState *state, int *flag_p)
2745 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2748 if (state->parc <= 0) { /* warn if not enough args */
2749 if (MyUser(state->sptr))
2750 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2755 t_str = state->parv[state->args_used++]; /* grab arg */
2759 /* If they're not an oper, they can't change modes */
2760 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2761 send_notoper(state);
2765 /* If a non-service user is trying to force it, refuse. */
2766 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2767 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2768 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2772 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2773 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2774 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2778 /* If they are not the channel manager, they are not allowed to change it */
2779 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2780 if (*state->chptr->mode.apass) {
2781 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2782 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2784 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2785 "Re-create the channel. The channel must be *empty* for",
2786 "at least a whole minute", "before it can be recreated.");
2791 if (state->done & DONE_APASS) /* allow apass to be set only once */
2793 state->done |= DONE_APASS;
2795 t_len = PASSLEN + 1;
2797 /* clean up the apass string */
2799 while (*++s > ' ' && *s != ':' && --t_len)
2803 if (!*t_str) { /* warn if empty */
2804 if (MyUser(state->sptr))
2805 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2813 if (!(state->flags & MODE_PARSE_FORCE)) {
2814 /* can't remove the apass while upass is still set */
2815 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2816 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2819 /* can't add an apass if one is set, nor can one remove the wrong apass */
2820 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2821 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2822 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2827 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2828 !ircd_strcmp(state->chptr->mode.apass, t_str))
2829 return; /* no apass change */
2831 if (state->flags & MODE_PARSE_BOUNCE) {
2832 if (*state->chptr->mode.apass) /* reset old apass */
2833 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2834 state->chptr->mode.apass, 0);
2835 else /* remove new bogus apass */
2836 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2837 } else /* send new apass */
2838 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2840 if (state->flags & MODE_PARSE_SET) {
2841 if (state->dir == MODE_ADD) { /* set the new apass */
2842 /* Make it VERY clear to the user that this is a one-time password */
2843 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2844 if (MyUser(state->sptr)) {
2845 send_reply(state->sptr, RPL_APASSWARN,
2846 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2847 "Are you SURE you want to use this as Admin password? ",
2848 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2849 send_reply(state->sptr, RPL_APASSWARN,
2850 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2851 "\" to remove the password and then immediately set a new one. "
2852 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2853 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2854 "Now set the channel user password (+u).");
2856 } else { /* remove the old apass */
2857 *state->chptr->mode.apass = '\0';
2858 if (MyUser(state->sptr))
2859 send_reply(state->sptr, RPL_APASSWARN,
2860 "WARNING: You removed the channel Admin password MODE (+A). ",
2861 "If you would disconnect or leave the channel without setting a new password then you will ",
2862 "not be able to set it again and lose ownership of this channel! ",
2863 "SET A NEW PASSWORD NOW!", "");
2869 * Helper function to convert bans
2872 mode_parse_ban(struct ParseState *state, int *flag_p)
2875 struct SLink *ban, *newban = 0;
2877 if (state->parc <= 0) { /* Not enough args, send ban list */
2878 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2879 send_ban_list(state->sptr, state->chptr);
2880 state->done |= DONE_BANLIST;
2886 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2889 t_str = state->parv[state->args_used++]; /* grab arg */
2893 /* If they're not an oper, they can't change modes */
2894 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2895 send_notoper(state);
2899 if ((s = strchr(t_str, ' ')))
2902 if (!*t_str || *t_str == ':') { /* warn if empty */
2903 if (MyUser(state->sptr))
2904 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2909 t_str = collapse(pretty_mask(t_str));
2911 /* remember the ban for the moment... */
2912 if (state->dir == MODE_ADD) {
2913 newban = state->banlist + (state->numbans++);
2916 DupString(newban->value.ban.banstr, t_str);
2917 newban->value.ban.who = cli_name(state->sptr);
2918 newban->value.ban.when = TStime();
2920 newban->flags = CHFL_BAN | MODE_ADD;
2922 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2923 newban->flags |= CHFL_BAN_IPMASK;
2926 if (!state->chptr->banlist) {
2927 state->chptr->banlist = newban; /* add our ban with its flags */
2928 state->done |= DONE_BANCLEAN;
2932 /* Go through all bans */
2933 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2934 /* first, clean the ban flags up a bit */
2935 if (!(state->done & DONE_BANCLEAN))
2936 /* Note: We're overloading *lots* of bits here; be careful! */
2937 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2941 * MODE_ADD - Ban was added; if we're bouncing modes,
2942 * then we'll remove it below; otherwise,
2943 * we'll have to allocate a real ban
2945 * MODE_DEL - Ban was marked for deletion; if we're
2946 * bouncing modes, we'll have to re-add it,
2947 * otherwise, we'll have to remove it
2949 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2950 * with a ban already set; if we're
2951 * bouncing modes, we'll have to bounce
2952 * this one; otherwise, we'll just ignore
2953 * it when we process added bans
2956 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2957 ban->flags |= MODE_DEL; /* delete one ban */
2959 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2961 } else if (state->dir == MODE_ADD) {
2962 /* if the ban already exists, don't worry about it */
2963 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2964 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2965 MyFree(newban->value.ban.banstr); /* stopper a leak */
2966 state->numbans--; /* deallocate last ban */
2967 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2969 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2970 if (!(ban->flags & MODE_DEL))
2971 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2972 } else if (!mmatch(t_str, ban->value.ban.banstr))
2973 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2975 if (!ban->next && (newban->flags & MODE_ADD))
2977 ban->next = newban; /* add our ban with its flags */
2978 break; /* get out of loop */
2982 state->done |= DONE_BANCLEAN;
2986 * This is the bottom half of the ban processor
2989 mode_process_bans(struct ParseState *state)
2991 struct SLink *ban, *newban, *prevban, *nextban;
2997 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2999 banlen = strlen(ban->value.ban.banstr);
3001 nextban = ban->next;
3003 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
3005 prevban->next = 0; /* Break the list; ban isn't a real ban */
3007 state->chptr->banlist = 0;
3012 MyFree(ban->value.ban.banstr);
3015 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
3016 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
3017 ban->value.ban.banstr,
3018 state->flags & MODE_PARSE_SET);
3020 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
3021 if (prevban) /* clip it out of the list... */
3022 prevban->next = ban->next;
3024 state->chptr->banlist = ban->next;
3029 MyFree(ban->value.ban.who);
3033 continue; /* next ban; keep prevban like it is */
3035 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
3036 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
3038 prevban->next = 0; /* Break the list; ban isn't a real ban */
3040 state->chptr->banlist = 0;
3042 /* If we're supposed to ignore it, do so. */
3043 if (ban->flags & CHFL_BAN_OVERLAPPED &&
3044 !(state->flags & MODE_PARSE_BOUNCE)) {
3048 MyFree(ban->value.ban.banstr);
3050 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
3051 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
3052 count > feature_int(FEAT_MAXBANS))) {
3053 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
3054 ban->value.ban.banstr);
3058 MyFree(ban->value.ban.banstr);
3060 /* add the ban to the buffer */
3061 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
3062 ban->value.ban.banstr,
3063 !(state->flags & MODE_PARSE_SET));
3065 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3066 newban = make_link();
3067 newban->value.ban.banstr = ban->value.ban.banstr;
3068 DupString(newban->value.ban.who, ban->value.ban.who);
3069 newban->value.ban.when = ban->value.ban.when;
3070 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
3072 newban->next = state->chptr->banlist; /* and link it in */
3073 state->chptr->banlist = newban;
3082 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3084 if (changed) /* if we changed the ban list, we must invalidate the bans */
3085 mode_ban_invalidate(state->chptr);
3089 * Helper function to process client changes
3092 mode_parse_client(struct ParseState *state, int *flag_p)
3095 struct Client *acptr;
3098 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3101 if (state->parc <= 0) /* return if not enough args */
3104 t_str = state->parv[state->args_used++]; /* grab arg */
3108 /* If they're not an oper, they can't change modes */
3109 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3110 send_notoper(state);
3114 if (MyUser(state->sptr)) /* find client we're manipulating */
3115 acptr = find_chasing(state->sptr, t_str, NULL);
3117 acptr = findNUser(t_str);
3120 return; /* find_chasing() already reported an error to the user */
3122 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3123 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3124 state->cli_change[i].flag & flag_p[0]))
3125 break; /* found a slot */
3127 /* Store what we're doing to them */
3128 state->cli_change[i].flag = state->dir | flag_p[0];
3129 state->cli_change[i].client = acptr;
3133 * Helper function to process the changed client list
3136 mode_process_clients(struct ParseState *state)
3139 struct Membership *member;
3141 for (i = 0; state->cli_change[i].flag; i++) {
3142 assert(0 != state->cli_change[i].client);
3144 /* look up member link */
3145 if (!(member = find_member_link(state->chptr,
3146 state->cli_change[i].client)) ||
3147 (MyUser(state->sptr) && IsZombie(member))) {
3148 if (MyUser(state->sptr))
3149 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3150 cli_name(state->cli_change[i].client),
3151 state->chptr->chname);
3155 if ((state->cli_change[i].flag & MODE_ADD &&
3156 (state->cli_change[i].flag & member->status)) ||
3157 (state->cli_change[i].flag & MODE_DEL &&
3158 !(state->cli_change[i].flag & member->status)))
3159 continue; /* no change made, don't do anything */
3161 /* see if the deop is allowed */
3162 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3163 (MODE_DEL | MODE_CHANOP)) {
3164 /* prevent +k users from being deopped */
3165 if (IsChannelService(state->cli_change[i].client)) {
3166 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3167 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3169 (IsServer(state->sptr) ? cli_name(state->sptr) :
3170 cli_name((cli_user(state->sptr))->server)));
3172 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3173 send_reply(state->sptr, ERR_ISCHANSERVICE,
3174 cli_name(state->cli_change[i].client),
3175 state->chptr->chname);
3180 /* check deop for local user */
3181 if (MyUser(state->sptr)) {
3183 /* don't allow local opers to be deopped on local channels */
3184 if (state->cli_change[i].client != state->sptr &&
3185 IsLocalChannel(state->chptr->chname) &&
3186 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3187 send_reply(state->sptr, ERR_ISOPERLCHAN,
3188 cli_name(state->cli_change[i].client),
3189 state->chptr->chname);
3193 if (feature_bool(FEAT_OPLEVELS)) {
3194 /* don't allow to deop members with an op level that is <= our own level */
3195 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3197 && OpLevel(member) <= OpLevel(state->member)) {
3198 int equal = (OpLevel(member) == OpLevel(state->member));
3199 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3200 cli_name(state->cli_change[i].client),
3201 state->chptr->chname,
3202 OpLevel(state->member), OpLevel(member),
3203 "deop", equal ? "the same" : "a higher");
3210 /* set op-level of member being opped */
3211 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3212 (MODE_ADD | MODE_CHANOP)) {
3213 /* If on a channel with upass set, someone with level x gives ops to someone else,
3214 then that person gets level x-1. On other channels, where upass is not set,
3215 the level stays the same. */
3216 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3217 /* Someone being opped by a server gets op-level 0 */
3218 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3219 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3222 /* actually effect the change */
3223 if (state->flags & MODE_PARSE_SET) {
3224 if (state->cli_change[i].flag & MODE_ADD) {
3225 if (IsDelayedJoin(member))
3226 RevealDelayedJoin(member);
3227 member->status |= (state->cli_change[i].flag &
3228 (MODE_CHANOP | MODE_VOICE));
3229 if (state->cli_change[i].flag & MODE_CHANOP)
3230 ClearDeopped(member);
3232 member->status &= ~(state->cli_change[i].flag &
3233 (MODE_CHANOP | MODE_VOICE));
3236 /* accumulate the change */
3237 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3238 state->cli_change[i].client);
3239 } /* for (i = 0; state->cli_change[i].flags; i++) */
3243 * Helper function to process the simple modes
3246 mode_parse_mode(struct ParseState *state, int *flag_p)
3248 /* If they're not an oper, they can't change modes */
3249 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3250 send_notoper(state);
3257 if (state->dir == MODE_ADD) {
3258 state->add |= flag_p[0];
3259 state->del &= ~flag_p[0];
3261 if (flag_p[0] & MODE_SECRET) {
3262 state->add &= ~MODE_PRIVATE;
3263 state->del |= MODE_PRIVATE;
3264 } else if (flag_p[0] & MODE_PRIVATE) {
3265 state->add &= ~MODE_SECRET;
3266 state->del |= MODE_SECRET;
3268 if (flag_p[0] & MODE_DELJOINS) {
3269 state->add &= ~MODE_WASDELJOINS;
3270 state->del |= MODE_WASDELJOINS;
3273 state->add &= ~flag_p[0];
3274 state->del |= flag_p[0];
3277 assert(0 == (state->add & state->del));
3278 assert((MODE_SECRET | MODE_PRIVATE) !=
3279 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3283 * This routine is intended to parse MODE or OPMODE commands and effect the
3284 * changes (or just build the bounce buffer). We pass the starting offset
3288 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3289 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3290 struct Membership* member)
3292 static int chan_flags[] = {
3297 MODE_MODERATED, 'm',
3298 MODE_TOPICLIMIT, 't',
3299 MODE_INVITEONLY, 'i',
3300 MODE_NOPRIVMSGS, 'n',
3314 unsigned int t_mode;
3316 struct ParseState state;
3327 state.chptr = chptr;
3328 state.member = member;
3331 state.flags = flags;
3332 state.dir = MODE_ADD;
3336 state.args_used = 0;
3337 state.max_args = MAXMODEPARAMS;
3340 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3341 state.banlist[i].next = 0;
3342 state.banlist[i].value.ban.banstr = 0;
3343 state.banlist[i].value.ban.who = 0;
3344 state.banlist[i].value.ban.when = 0;
3345 state.banlist[i].flags = 0;
3346 state.cli_change[i].flag = 0;
3347 state.cli_change[i].client = 0;
3350 modestr = state.parv[state.args_used++];
3354 for (; *modestr; modestr++) {
3355 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3356 if (flag_p[1] == *modestr)
3359 if (!flag_p[0]) { /* didn't find it? complain and continue */
3360 if (MyUser(state.sptr))
3361 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3366 case '+': /* switch direction to MODE_ADD */
3367 case '-': /* switch direction to MODE_DEL */
3368 state.dir = flag_p[0];
3371 case 'l': /* deal with limits */
3372 mode_parse_limit(&state, flag_p);
3375 case 'k': /* deal with keys */
3376 mode_parse_key(&state, flag_p);
3379 case 'A': /* deal with Admin passes */
3380 if (feature_bool(FEAT_OPLEVELS))
3381 mode_parse_apass(&state, flag_p);
3384 case 'U': /* deal with user passes */
3385 if (feature_bool(FEAT_OPLEVELS))
3386 mode_parse_upass(&state, flag_p);
3389 case 'b': /* deal with bans */
3390 mode_parse_ban(&state, flag_p);
3393 case 'o': /* deal with ops/voice */
3395 mode_parse_client(&state, flag_p);
3398 default: /* deal with other modes */
3399 mode_parse_mode(&state, flag_p);
3401 } /* switch (*modestr) */
3402 } /* for (; *modestr; modestr++) */
3404 if (state.flags & MODE_PARSE_BURST)
3405 break; /* don't interpret any more arguments */
3407 if (state.parc > 0) { /* process next argument in string */
3408 modestr = state.parv[state.args_used++];
3412 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3415 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3416 break; /* we're then going to bounce the mode! */
3418 recv_ts = atoi(modestr);
3420 if (recv_ts && recv_ts < state.chptr->creationtime)
3421 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3423 break; /* break out of while loop */
3424 } else if (state.flags & MODE_PARSE_STRICT ||
3425 (MyUser(state.sptr) && state.max_args <= 0)) {
3426 state.parc++; /* we didn't actually gobble the argument */
3428 break; /* break out of while loop */
3431 } /* while (*modestr) */
3434 * the rest of the function finishes building resultant MODEs; if the
3435 * origin isn't a member or an oper, skip it.
3437 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3438 return state.args_used; /* tell our parent how many args we gobbled */
3440 t_mode = state.chptr->mode.mode;
3442 if (state.del & t_mode) { /* delete any modes to be deleted... */
3443 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3445 t_mode &= ~state.del;
3447 if (state.add & ~t_mode) { /* add any modes to be added... */
3448 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3450 t_mode |= state.add;
3453 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3454 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3455 !(t_mode & MODE_INVITEONLY))
3456 mode_invite_clear(state.chptr);
3458 state.chptr->mode.mode = t_mode;
3461 if (state.flags & MODE_PARSE_WIPEOUT) {
3462 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3463 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3464 state.chptr->mode.limit);
3465 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3466 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3467 state.chptr->mode.key, 0);
3468 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3469 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3470 state.chptr->mode.upass, 0);
3471 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3472 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3473 state.chptr->mode.apass, 0);
3476 if (state.done & DONE_BANCLEAN) /* process bans */
3477 mode_process_bans(&state);
3479 /* process client changes */
3480 if (state.cli_change[0].flag)
3481 mode_process_clients(&state);
3483 return state.args_used; /* tell our parent how many args we gobbled */
3487 * Initialize a join buffer
3490 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3491 struct Client *connect, unsigned int type, char *comment,
3497 assert(0 != source);
3498 assert(0 != connect);
3500 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3501 jbuf->jb_connect = connect;
3502 jbuf->jb_type = type;
3503 jbuf->jb_comment = comment;
3504 jbuf->jb_create = create;
3506 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3507 type == JOINBUF_TYPE_PART ||
3508 type == JOINBUF_TYPE_PARTALL) ?
3509 STARTJOINLEN : STARTCREATELEN) +
3510 (comment ? strlen(comment) + 2 : 0));
3512 for (i = 0; i < MAXJOINARGS; i++)
3513 jbuf->jb_channels[i] = 0;
3517 * Add a channel to the join buffer
3520 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3528 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3529 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3534 is_local = IsLocalChannel(chan->chname);
3536 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3537 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3538 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3539 if (IsUserParting(member))
3541 SetUserParting(member);
3543 /* Send notification to channel */
3544 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3545 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3546 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3547 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3548 else if (MyUser(jbuf->jb_source))
3549 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3550 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3551 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3552 /* XXX: Shouldn't we send a PART here anyway? */
3553 /* to users on the channel? Why? From their POV, the user isn't on
3554 * the channel anymore anyway. We don't send to servers until below,
3555 * when we gang all the channel parts together. Note that this is
3556 * exactly the same logic, albeit somewhat more concise, as was in
3557 * the original m_part.c */
3559 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3560 is_local) /* got to remove user here */
3561 remove_user_from_channel(jbuf->jb_source, chan);
3563 /* Add user to channel */
3564 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3565 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3567 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3569 /* send notification to all servers */
3570 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3571 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3572 "%H %Tu", chan, chan->creationtime);
3574 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3575 /* Send the notification to the channel */
3576 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3578 /* send an op, too, if needed */
3579 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3580 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3581 chan, jbuf->jb_source);
3582 } else if (MyUser(jbuf->jb_source))
3583 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3586 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3587 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3588 return; /* don't send to remote */
3590 /* figure out if channel name will cause buffer to be overflowed */
3591 len = chan ? strlen(chan->chname) + 1 : 2;
3592 if (jbuf->jb_strlen + len > BUFSIZE)
3593 joinbuf_flush(jbuf);
3595 /* add channel to list of channels to send and update counts */
3596 jbuf->jb_channels[jbuf->jb_count++] = chan;
3597 jbuf->jb_strlen += len;
3599 /* if we've used up all slots, flush */
3600 if (jbuf->jb_count >= MAXJOINARGS)
3601 joinbuf_flush(jbuf);
3605 * Flush the channel list to remote servers
3608 joinbuf_flush(struct JoinBuf *jbuf)
3610 char chanlist[BUFSIZE];
3614 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3615 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3616 return 0; /* no joins to process */
3618 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3619 build_string(chanlist, &chanlist_i,
3620 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3621 i == 0 ? '\0' : ',');
3622 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3623 /* Remove user from channel */
3624 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3626 jbuf->jb_channels[i] = 0; /* mark slot empty */
3629 jbuf->jb_count = 0; /* reset base counters */
3630 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3631 STARTJOINLEN : STARTCREATELEN) +
3632 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3634 /* and send the appropriate command */
3635 switch (jbuf->jb_type) {
3636 case JOINBUF_TYPE_CREATE:
3637 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3638 "%s %Tu", chanlist, jbuf->jb_create);
3641 case JOINBUF_TYPE_PART:
3642 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3643 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3651 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3652 int IsInvited(struct Client* cptr, const void* chptr)
3656 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3657 if (lp->value.chptr == chptr)
3662 /* RevealDelayedJoin: sends a join for a hidden user */
3664 void RevealDelayedJoin(struct Membership *member) {
3665 ClearDelayedJoin(member);
3666 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3668 CheckDelayedJoins(member->channel);
3671 /* CheckDelayedJoins: checks and clear +d if necessary */
3673 void CheckDelayedJoins(struct Channel *chan) {
3674 struct Membership *memb2;
3676 if (chan->mode.mode & MODE_WASDELJOINS) {
3677 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3678 if (IsDelayedJoin(memb2))
3683 chan->mode.mode &= ~MODE_WASDELJOINS;
3684 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,