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.
686 static int channel_all_zombies(struct Channel* chptr)
688 struct Membership* member;
690 for (member = chptr->members; member; member = member->next_member) {
691 if (!IsZombie(member))
698 /** Remove a user from a channel
699 * This is the generic entry point for removing a user from a channel, this
700 * function will remove the client from the channel, and destory the channel
701 * if there are no more normal users left.
703 * @param cptr The client
704 * @param channel The channel
706 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
709 struct Membership* member;
712 if ((member = find_member_link(chptr, cptr))) {
713 if (remove_member_from_channel(member)) {
714 if (channel_all_zombies(chptr)) {
716 * XXX - this looks dangerous but isn't if we got the referential
717 * integrity right for channels
719 while (remove_member_from_channel(chptr->members))
726 /** Remove a user from all channels they are on.
728 * This function removes a user from all channels they are on.
730 * @param cptr The client to remove.
732 void remove_user_from_all_channels(struct Client* cptr)
734 struct Membership* chan;
736 assert(0 != cli_user(cptr));
738 while ((chan = (cli_user(cptr))->channel))
739 remove_user_from_channel(cptr, chan->channel);
742 /** Check if this user is a legitimate chanop
744 * @param cptr Client to check
745 * @param chptr Channel to check
747 * @returns True if the user is a chanop (And not a zombie), False otherwise.
749 int is_chan_op(struct Client *cptr, struct Channel *chptr)
751 struct Membership* member;
753 if ((member = find_member_link(chptr, cptr)))
754 return (!IsZombie(member) && IsChanOp(member));
759 /** Check if a user is a Zombie on a specific channel.
761 * @param cptr The client to check.
762 * @param chptr The channel to check.
764 * @returns True if the client (cptr) is a zombie on the channel (chptr),
767 int is_zombie(struct Client *cptr, struct Channel *chptr)
769 struct Membership* member;
773 if ((member = find_member_link(chptr, cptr)))
774 return IsZombie(member);
778 /** Returns if a user has voice on a channel.
780 * @param cptr The client
781 * @param chptr The channel
783 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
785 int has_voice(struct Client* cptr, struct Channel* chptr)
787 struct Membership* member;
790 if ((member = find_member_link(chptr, cptr)))
791 return (!IsZombie(member) && HasVoice(member));
796 /** Can this member send to a channel
798 * A user can speak on a channel iff:
800 * <li> They didn't use the Apass to gain ops.
801 * <li> They are op'd or voice'd.
802 * <li> You aren't banned.
803 * <li> The channel isn't +m
804 * <li> The channel isn't +n or you are on the channel.
807 * This function will optionally reveal a user on a delayed join channel if
808 * they are allowed to send to the channel.
810 * @param member The membership of the user
811 * @param reveal If true, the user will be "revealed" on a delayed
814 * @returns True if the client can speak on the channel.
816 int member_can_send_to_channel(struct Membership* member, int reveal)
820 /* Discourage using the Apass to get op. They should use the upass. */
821 if (IsChannelManager(member) && *member->channel->mode.upass)
824 if (IsVoicedOrOpped(member))
827 * If it's moderated, and you aren't a priviledged user, you can't
830 if (member->channel->mode.mode & MODE_MODERATED)
833 * If you're banned then you can't speak either.
834 * but because of the amount of CPU time that is_banned chews
835 * we only check it for our clients.
837 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
840 if (IsDelayedJoin(member) && reveal)
841 RevealDelayedJoin(member);
846 /** Check if a client can send to a channel.
848 * Has the added check over member_can_send_to_channel() of servers can
851 * @param cptr The client to check
852 * @param chptr The channel to check
853 * @param reveal If the user should be revealed (see
854 * member_can_send_to_channel())
856 * @returns true if the client is allowed to speak on the channel, false
859 * @see member_can_send_to_channel()
861 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
863 struct Membership *member;
866 * Servers can always speak on channels.
871 member = find_channel_member(cptr, chptr);
874 * You can't speak if you're off channel, and it is +n (no external messages)
878 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
879 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
882 return !is_banned(cptr, chptr, NULL);
884 return member_can_send_to_channel(member, reveal);
887 /** Returns the name of a channel that prevents the user from changing nick.
888 * if a member and not (opped or voiced) and (banned or moderated), return
889 * the name of the first channel banned on.
891 * @param cptr The client
893 * @returns the name of the first channel banned on, or NULL if the user
896 const char* find_no_nickchange_channel(struct Client* cptr)
899 struct Membership* member;
900 for (member = (cli_user(cptr))->channel; member;
901 member = member->next_channel) {
902 if (!IsVoicedOrOpped(member) &&
903 (is_banned(cptr, member->channel, member) ||
904 (member->channel->mode.mode & MODE_MODERATED)))
905 return member->channel->chname;
912 /** Fill mbuf/pbuf with modes from chptr
913 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
914 * with the parameters in pbuf as visible by cptr.
916 * This function will hide keys from non-op'd, non-server clients.
918 * @param cptr The client to generate the mode for.
919 * @param mbuf The buffer to write the modes into.
920 * @param pbuf The buffer to write the mode parameters into.
921 * @param buflen The length of the buffers.
922 * @param chptr The channel to get the modes from.
923 * @param membership The membership of this client on this channel (or NULL
924 * if this client isn't on this channel)
927 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
928 struct Channel *chptr, struct Membership *member)
930 int previous_parameter = 0;
937 if (chptr->mode.mode & MODE_SECRET)
939 else if (chptr->mode.mode & MODE_PRIVATE)
941 if (chptr->mode.mode & MODE_MODERATED)
943 if (chptr->mode.mode & MODE_TOPICLIMIT)
945 if (chptr->mode.mode & MODE_INVITEONLY)
947 if (chptr->mode.mode & MODE_NOPRIVMSGS)
949 if (chptr->mode.mode & MODE_REGONLY)
951 if (chptr->mode.mode & MODE_DELJOINS)
953 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
955 if (chptr->mode.limit) {
957 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
958 previous_parameter = 1;
961 if (*chptr->mode.key) {
963 if (previous_parameter)
965 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
966 strcat(pbuf, chptr->mode.key);
969 previous_parameter = 1;
971 if (*chptr->mode.apass) {
973 if (previous_parameter)
975 if (IsServer(cptr)) {
976 strcat(pbuf, chptr->mode.apass);
979 previous_parameter = 1;
981 if (*chptr->mode.upass) {
983 if (previous_parameter)
985 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
986 strcat(pbuf, chptr->mode.upass);
993 /** Compare two members oplevel
995 * @param mp1 Pointer to a pointer to a membership
996 * @param mp2 Pointer to a pointer to a membership
998 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
1000 * Used for qsort(3).
1002 int compare_member_oplevel(const void *mp1, const void *mp2)
1004 struct Membership const* member1 = *(struct Membership const**)mp1;
1005 struct Membership const* member2 = *(struct Membership const**)mp2;
1006 if (member1->oplevel == member2->oplevel)
1008 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1011 /* send "cptr" a full list of the modes for channel chptr.
1013 * Sends a BURST line to cptr, bursting all the modes for the channel.
1015 * @param cptr Client pointer
1016 * @param chptr Channel pointer
1018 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1020 /* The order in which modes are generated is now mandatory */
1021 static unsigned int current_flags[4] =
1022 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1028 struct Membership* member;
1030 char modebuf[MODEBUFLEN];
1031 char parabuf[MODEBUFLEN];
1033 int number_of_ops = 0;
1034 int opped_members_index = 0;
1035 struct Membership** opped_members = NULL;
1036 int last_oplevel = 0;
1037 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1042 if (IsLocalChannel(chptr->chname))
1045 member = chptr->members;
1046 lp2 = chptr->banlist;
1048 *modebuf = *parabuf = '\0';
1049 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1051 for (first = 1; full; first = 0) /* Loop for multiple messages */
1053 full = 0; /* Assume by default we get it
1054 all in one message */
1056 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1057 /* is there any better way we can do this? */
1058 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1059 chptr->creationtime);
1061 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1064 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1065 msgq_append(&me, mb, " %s", modebuf);
1068 msgq_append(&me, mb, " %s", parabuf);
1072 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1074 * First find all opless members.
1075 * Run 2 times over all members, to group the members with
1076 * and without voice together.
1077 * Then run 2 times over all opped members (which are ordered
1078 * by op-level) to also group voice and non-voice together.
1080 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1084 if (flag_cnt < 2 && IsChanOp(member))
1087 * The first loop (to find all non-voice/op), we count the ops.
1088 * The second loop (to find all voiced non-ops), store the ops
1089 * in a dynamic array.
1094 opped_members[opped_members_index++] = member;
1096 /* Only handle the members with the flags that we are interested in. */
1097 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1099 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1100 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1102 full = 1; /* Make sure we continue after
1103 sending it so far */
1104 /* Ensure the new BURST line contains the current
1105 * ":mode", except when there is no mode yet. */
1106 new_mode = (flag_cnt > 0) ? 1 : 0;
1107 break; /* Do not add this member to this message */
1109 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1110 first = 0; /* From now on, use commas to add new nicks */
1113 * Do we have a nick with a new mode ?
1114 * Or are we starting a new BURST line?
1116 if (new_mode || !feat_oplevels)
1119 * This means we are at the _first_ member that has only
1120 * voice, or the first member that has only ops, or the
1121 * first member that has voice and ops (so we get here
1122 * at most three times, plus once for every start of
1123 * a continued BURST line where only these modes is current.
1124 * In the two cases where the current mode includes ops,
1125 * we need to add the _absolute_ value of the oplevel to the mode.
1127 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1130 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1132 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1134 /* append the absolute value of the oplevel */
1136 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1141 msgq_append(&me, mb, tbuf);
1144 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1147 * This can't be the first member of a (continued) BURST
1148 * message because then either flag_cnt == 0 or new_mode == 1
1149 * Now we need to append the incremental value of the oplevel.
1151 char tbuf[2 + MAXOPLEVELDIGITS];
1152 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1153 last_oplevel = member->oplevel;
1154 msgq_append(&me, mb, tbuf);
1157 /* Go to the next `member'. */
1159 member = member->next_member;
1161 member = opped_members[++opped_members_index];
1166 /* Point `member' at the start of the list again. */
1169 member = chptr->members;
1170 /* Now, after one loop, we know the number of ops and can
1171 * allocate the dynamic array with pointer to the ops. */
1172 opped_members = (struct Membership**)
1173 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1174 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1178 /* At the end of the second loop, sort the opped members with
1179 * increasing op-level, so that we will output them in the
1180 * correct order (and all op-level increments stay positive) */
1182 qsort(opped_members, number_of_ops,
1183 sizeof(struct Membership*), compare_member_oplevel);
1184 /* The third and fourth loop run only over the opped members. */
1185 member = opped_members[(opped_members_index = 0)];
1188 } /* loop over 0,+v,+o,+ov */
1192 /* Attach all bans, space seperated " :%ban ban ..." */
1193 for (first = 2; lp2; lp2 = lp2->next)
1195 len = strlen(lp2->value.ban.banstr);
1196 if (msgq_bufleft(mb) < len + 1 + first)
1197 /* The +1 stands for the added ' '.
1198 * The +first stands for the added ":%".
1204 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1205 lp2->value.ban.banstr);
1210 send_buffer(cptr, mb, 0); /* Send this message */
1212 } /* Continue when there was something
1213 that didn't fit (full==1) */
1215 MyFree(opped_members);
1216 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1217 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1218 chptr->creationtime, chptr->topic_time, chptr->topic);
1221 /** Canonify a mask.
1224 * @author Carlo Wood (Run),
1227 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1228 * When the user name or host name are too long (USERLEN and HOSTLEN
1229 * respectively) then they are cut off at the start with a '*'.
1231 * The following transformations are made:
1233 * 1) xxx -> nick!*@*
1234 * 2) xxx.xxx -> *!*@host
1235 * 3) xxx!yyy -> nick!user@*
1236 * 4) xxx@yyy -> *!user@host
1237 * 5) xxx!yyy@zzz -> nick!user@host
1239 * @param mask The uncanonified mask.
1240 * @returns The updated mask in a static buffer.
1242 char *pretty_mask(char *mask)
1244 static char star[2] = { '*', 0 };
1245 static char retmask[NUH_BUFSIZE];
1246 char *last_dot = NULL;
1249 /* Case 1: default */
1254 /* Do a _single_ pass through the characters of the mask: */
1255 for (ptr = mask; *ptr; ++ptr)
1259 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1263 else if (*ptr == '@')
1265 /* Case 4: Found last '@' (without finding a '!' yet) */
1270 else if (*ptr == '.')
1272 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1282 /* Case 4 or 5: Found last '@' */
1288 if (user == star && last_dot)
1298 char *nick_end = (user != star) ? user - 1 : ptr;
1299 if (nick_end - nick > NICKLEN)
1305 char *user_end = (host != star) ? host - 1 : ptr;
1306 if (user_end - user > USERLEN)
1308 user = user_end - USERLEN;
1313 if (host != star && ptr - host > HOSTLEN)
1315 host = ptr - HOSTLEN;
1318 return make_nick_user_host(retmask, nick, user, host);
1321 /** send a banlist to a client for a channel
1323 * @param cptr Client to send the banlist to.
1324 * @param chptr Channel whose banlist to send.
1326 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1333 for (lp = chptr->banlist; lp; lp = lp->next)
1334 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1335 lp->value.ban.who, lp->value.ban.when);
1337 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1340 /** Check a key against a keyring.
1341 * We are now treating the <key> part of /join <channel list> <key> as a key
1342 * ring; that is, we try one key against the actual channel key, and if that
1343 * doesn't work, we try the next one, and so on. -Kev -Texaco
1344 * Returns: 0 on match, 1 otherwise
1345 * This version contributed by SeKs <intru@info.polymtl.ca>
1347 * @param key Key to check
1348 * @param keyring Comma seperated list of keys
1350 * @returns True if the key was found and matches, false otherwise.
1352 static int compall(char *key, char *keyring)
1357 p1 = key; /* point to the key... */
1358 while (*p1 && *p1 == *keyring)
1359 { /* step through the key and ring until they
1365 if (!*p1 && (!*keyring || *keyring == ','))
1366 /* ok, if we're at the end of the and also at the end of one of the keys
1367 in the keyring, we have a match */
1370 if (!*keyring) /* if we're at the end of the key ring, there
1371 weren't any matches, so we return 1 */
1374 /* Not at the end of the key ring, so step
1375 through to the next key in the ring: */
1376 while (*keyring && *(keyring++) != ',');
1378 goto top; /* and check it against the key */
1381 /** Returns if a user can join a channel with a specific key.
1383 * @param sptr The client trying to join
1384 * @param chptr The channel to join
1385 * @param key The key to use
1387 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1388 * if the oper used the magic key, 0 if no error occured.
1390 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1392 int overrideJoin = 0;
1395 * Now a banned user CAN join if invited -- Nemesi
1396 * Now a user CAN escape channel limit if invited -- bfriendly
1397 * Now a user CAN escape anything if invited -- Isomer
1400 if (IsInvited(sptr, chptr))
1403 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1404 a HACK(4) notice will be sent if he would not have been supposed
1405 to join normally. */
1406 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1407 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1408 compall("OVERRIDE",key) == 0)
1409 overrideJoin = MAGIC_OPER_OVERRIDE;
1411 if (chptr->mode.mode & MODE_INVITEONLY)
1412 return overrideJoin + ERR_INVITEONLYCHAN;
1414 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1415 return overrideJoin + ERR_CHANNELISFULL;
1417 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1418 return overrideJoin + ERR_NEEDREGGEDNICK;
1420 if (is_banned(sptr, chptr, NULL))
1421 return overrideJoin + ERR_BANNEDFROMCHAN;
1424 * now using compall (above) to test against a whole key ring -Kev
1426 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1427 return overrideJoin + ERR_BADCHANNELKEY;
1430 return ERR_DONTCHEAT;
1435 /** Remove bells and commas from channel name
1437 * @param ch Channel name to clean, modified in place.
1439 void clean_channelname(char *cn)
1443 for (i = 0; cn[i]; i++) {
1444 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1448 if (IsChannelLower(cn[i])) {
1449 cn[i] = ToLower(cn[i]);
1455 if ((unsigned char)(cn[i]) == 0xd0)
1456 cn[i] = (char) 0xf0;
1462 /** Get a channel block, creating if necessary.
1463 * Get Channel block for chname (and allocate a new channel
1464 * block, if it didn't exists before).
1466 * @param cptr Client joining the channel.
1467 * @param chname The name of the channel to join.
1468 * @param flag set to CGT_CREATE to create the channel if it doesn't
1471 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1472 * wasn't specified or a pointer to the channel structure
1474 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1476 struct Channel *chptr;
1479 if (EmptyString(chname))
1482 len = strlen(chname);
1483 if (MyUser(cptr) && len > CHANNELLEN)
1486 *(chname + CHANNELLEN) = '\0';
1488 if ((chptr = FindChannel(chname)))
1490 if (flag == CGT_CREATE)
1492 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1494 ++UserStats.channels;
1495 memset(chptr, 0, sizeof(struct Channel));
1496 strcpy(chptr->chname, chname);
1497 if (GlobalChannelList)
1498 GlobalChannelList->prev = chptr;
1500 chptr->next = GlobalChannelList;
1501 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1502 GlobalChannelList = chptr;
1508 /** invite a user to a channel.
1510 * Adds an invite for a user to a channel. Limits the number of invites
1511 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1513 * @param cptr The client to be invited.
1514 * @param chptr The channel to be invited to.
1516 void add_invite(struct Client *cptr, struct Channel *chptr)
1518 struct SLink *inv, **tmp;
1520 del_invite(cptr, chptr);
1522 * Delete last link in chain if the list is max length
1524 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1525 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1526 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1528 * Add client to channel invite list
1531 inv->value.cptr = cptr;
1532 inv->next = chptr->invites;
1533 chptr->invites = inv;
1535 * Add channel to the end of the client invite list
1537 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1539 inv->value.chptr = chptr;
1542 (cli_user(cptr))->invites++;
1545 /** Delete an invite
1546 * Delete Invite block from channel invite list and client invite list
1548 * @param cptr Client pointer
1549 * @param chptr Channel pointer
1551 void del_invite(struct Client *cptr, struct Channel *chptr)
1553 struct SLink **inv, *tmp;
1555 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1556 if (tmp->value.cptr == cptr)
1561 (cli_user(cptr))->invites--;
1565 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1566 if (tmp->value.chptr == chptr)
1575 /** List a set of channels
1576 * Lists a series of channels that match a filter, skipping channels that
1577 * have been listed before.
1579 * @param cptr Client to send the list to.
1580 * @param nr Number of channels to send this update.
1582 void list_next_channels(struct Client *cptr, int nr)
1584 struct ListingArgs *args = cli_listing(cptr);
1585 struct Channel *chptr = args->chptr;
1586 chptr->mode.mode &= ~MODE_LISTED;
1587 while (is_listed(chptr) || --nr >= 0)
1589 for (; chptr; chptr = chptr->next)
1591 if (!cli_user(cptr))
1593 if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1594 SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1596 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1597 chptr->creationtime > args->min_time &&
1598 chptr->creationtime < args->max_time &&
1599 (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1600 chptr->topic_time > args->min_topic_time &&
1601 chptr->topic_time < args->max_topic_time)))
1603 if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1604 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1606 chptr = chptr->next;
1612 MyFree(cli_listing(cptr));
1613 cli_listing(cptr) = NULL;
1614 send_reply(cptr, RPL_LISTEND);
1620 (cli_listing(cptr))->chptr = chptr;
1621 chptr->mode.mode |= MODE_LISTED;
1634 * X --a--> A --b--> B --d--> D
1638 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1639 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1641 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1642 * Remove the user immediately when no users are left on the channel.
1643 * b) On server B : remove the user (who/lp) from the channel, send a
1644 * PART upstream (to A) and pass on the KICK.
1645 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1646 * channel, and pass on the KICK.
1647 * d) On server D : remove the user (who/lp) from the channel, and pass on
1651 * - Setting the ZOMBIE flag never hurts, we either remove the
1652 * client after that or we don't.
1653 * - The KICK message was already passed on, as should be in all cases.
1654 * - `who' is removed in all cases except case a) when users are left.
1655 * - A PART is only sent upstream in case b).
1661 * 1 --- 2 --- 3 --- 4 --- 5
1665 * We also need to turn 'who' into a zombie on servers 1 and 6,
1666 * because a KICK from 'who' (kicking someone else in that direction)
1667 * can arrive there afterwards - which should not be bounced itself.
1668 * Therefore case a) also applies for servers 1 and 6.
1672 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1673 struct Client* sptr, struct Channel* chptr)
1675 assert(0 != member);
1680 /* Default for case a): */
1683 /* Case b) or c) ?: */
1684 if (MyUser(who)) /* server 4 */
1686 if (IsServer(cptr)) /* Case b) ? */
1687 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1688 remove_user_from_channel(who, chptr);
1691 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1693 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1694 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1695 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1697 remove_user_from_channel(who, chptr);
1702 /* Case a) (servers 1, 2, 3 and 6) */
1703 if (channel_all_zombies(chptr))
1704 remove_user_from_channel(who, chptr);
1706 /* XXX Can't actually call Debug here; if the channel is all zombies,
1707 * chptr will no longer exist when we get here.
1708 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1712 int number_of_zombies(struct Channel *chptr)
1714 struct Membership* member;
1718 for (member = chptr->members; member; member = member->next_member) {
1719 if (IsZombie(member))
1726 * This helper function builds an argument string in strptr, consisting
1727 * of the original string, a space, and str1 and str2 concatenated (if,
1728 * of course, str2 is not NULL)
1731 build_string(char *strptr, int *strptr_i, const char *str1,
1732 const char *str2, char c)
1735 strptr[(*strptr_i)++] = c;
1738 strptr[(*strptr_i)++] = *(str1++);
1742 strptr[(*strptr_i)++] = *(str2++);
1744 strptr[(*strptr_i)] = '\0';
1748 * This is the workhorse of our ModeBuf suite; this actually generates the
1749 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1752 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1754 /* we only need the flags that don't take args right now */
1755 static int flags[] = {
1756 /* MODE_CHANOP, 'o', */
1757 /* MODE_VOICE, 'v', */
1760 MODE_MODERATED, 'm',
1761 MODE_TOPICLIMIT, 't',
1762 MODE_INVITEONLY, 'i',
1763 MODE_NOPRIVMSGS, 'n',
1766 MODE_WASDELJOINS, 'd',
1767 /* MODE_KEY, 'k', */
1768 /* MODE_BAN, 'b', */
1770 /* MODE_APASS, 'A', */
1771 /* MODE_UPASS, 'U', */
1777 struct Client *app_source; /* where the MODE appears to come from */
1779 char addbuf[20]; /* accumulates +psmtin, etc. */
1781 char rembuf[20]; /* accumulates -psmtin, etc. */
1783 char *bufptr; /* we make use of indirection to simplify the code */
1786 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1788 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1790 char *strptr; /* more indirection to simplify the code */
1793 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1796 char limitbuf[20]; /* convert limits to strings */
1798 unsigned int limitdel = MODE_LIMIT;
1802 /* If the ModeBuf is empty, we have nothing to do */
1803 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1806 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1808 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1811 app_source = mbuf->mb_source;
1814 * Account for user we're bouncing; we have to get it in on the first
1815 * bounced MODE, or we could have problems
1817 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1818 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1820 /* Calculate the simple flags */
1821 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1822 if (*flag_p & mbuf->mb_add)
1823 addbuf[addbuf_i++] = flag_p[1];
1824 else if (*flag_p & mbuf->mb_rem)
1825 rembuf[rembuf_i++] = flag_p[1];
1828 /* Now go through the modes with arguments... */
1829 for (i = 0; i < mbuf->mb_count; i++) {
1830 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1832 bufptr_i = &addbuf_i;
1835 bufptr_i = &rembuf_i;
1838 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1839 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1841 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1842 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1844 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1845 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1847 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1848 tmp = strlen(MB_STRING(mbuf, i));
1850 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1851 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1854 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1866 bufptr[(*bufptr_i)++] = mode_char;
1867 totalbuflen -= tmp + 1;
1869 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1870 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1871 strlen(MB_STRING(mbuf, i)));
1873 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1874 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1876 bufptr[(*bufptr_i)++] = 'k';
1877 totalbuflen -= tmp + 1;
1879 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1880 /* if it's a limit, we also format the number */
1881 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1883 tmp = strlen(limitbuf);
1885 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1886 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1888 bufptr[(*bufptr_i)++] = 'l';
1889 totalbuflen -= tmp + 1;
1894 /* terminate the mode strings */
1895 addbuf[addbuf_i] = '\0';
1896 rembuf[rembuf_i] = '\0';
1898 /* If we're building a user visible MODE or HACK... */
1899 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1900 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1901 MODEBUF_DEST_LOG)) {
1902 /* Set up the parameter strings */
1908 for (i = 0; i < mbuf->mb_count; i++) {
1909 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1912 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1914 strptr_i = &addstr_i;
1917 strptr_i = &remstr_i;
1920 /* deal with clients... */
1921 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1922 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1924 /* deal with bans... */
1925 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1926 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1928 /* deal with keys... */
1929 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1930 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1931 "*" : MB_STRING(mbuf, i), 0, ' ');
1933 /* deal with invisible passwords */
1934 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1935 build_string(strptr, strptr_i, "*", 0, ' ');
1938 * deal with limit; note we cannot include the limit parameter if we're
1941 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1942 (MODE_ADD | MODE_LIMIT))
1943 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1946 /* send the messages off to their destination */
1947 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1948 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1950 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1951 mbuf->mb_source : app_source),
1952 mbuf->mb_channel->chname,
1953 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1954 addbuf, remstr, addstr,
1955 mbuf->mb_channel->creationtime);
1957 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1958 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1959 "%s%s%s%s%s%s [%Tu]",
1960 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1961 mbuf->mb_source : app_source),
1962 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1963 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1964 mbuf->mb_channel->creationtime);
1966 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1967 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1969 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1970 mbuf->mb_source : app_source),
1971 mbuf->mb_channel->chname,
1972 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1973 addbuf, remstr, addstr,
1974 mbuf->mb_channel->creationtime);
1976 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1977 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1978 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1979 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1980 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1982 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1983 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1984 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1985 rembuf_i ? "-" : "", rembuf,
1986 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1989 /* Now are we supposed to propagate to other servers? */
1990 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1991 /* set up parameter string */
1998 * limit is supressed if we're removing it; we have to figure out which
1999 * direction is the direction for it to be removed, though...
2001 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
2003 for (i = 0; i < mbuf->mb_count; i++) {
2004 if (MB_TYPE(mbuf, i) & MODE_SAVE)
2007 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2009 strptr_i = &addstr_i;
2012 strptr_i = &remstr_i;
2015 /* deal with modes that take clients */
2016 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2017 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2019 /* deal with modes that take strings */
2020 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
2021 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2024 * deal with the limit. Logic here is complicated; if HACK2 is set,
2025 * we're bouncing the mode, so sense is reversed, and we have to
2026 * include the original limit if it looks like it's being removed
2028 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2029 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2032 /* we were told to deop the source */
2033 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2034 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2035 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2036 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2038 /* mark that we've done this, so we don't do it again */
2039 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2042 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2043 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2044 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2045 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2046 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2047 addbuf, remstr, addstr);
2048 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2050 * If HACK2 was set, we're bouncing; we send the MODE back to the
2051 * connection we got it from with the senses reversed and a TS of 0;
2054 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2055 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2056 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2057 mbuf->mb_channel->creationtime);
2060 * We're propagating a normal MODE command to the rest of the network;
2061 * we send the actual channel TS unless this is a HACK3 or a HACK4
2063 if (IsServer(mbuf->mb_source))
2064 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2065 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2066 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2067 addbuf, remstr, addstr,
2068 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2069 mbuf->mb_channel->creationtime);
2071 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2072 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2073 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2074 addbuf, remstr, addstr);
2078 /* We've drained the ModeBuf... */
2083 /* reinitialize the mode-with-arg slots */
2084 for (i = 0; i < MAXMODEPARAMS; i++) {
2085 /* If we saved any, pack them down */
2086 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2087 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2088 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2090 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2092 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2093 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2095 MB_TYPE(mbuf, i) = 0;
2096 MB_UINT(mbuf, i) = 0;
2099 /* If we're supposed to flush it all, do so--all hail tail recursion */
2100 if (all && mbuf->mb_count)
2101 return modebuf_flush_int(mbuf, 1);
2107 * This routine just initializes a ModeBuf structure with the information
2108 * needed and the options given.
2111 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2112 struct Client *connect, struct Channel *chan, unsigned int dest)
2117 assert(0 != source);
2121 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2125 mbuf->mb_source = source;
2126 mbuf->mb_connect = connect;
2127 mbuf->mb_channel = chan;
2128 mbuf->mb_dest = dest;
2131 /* clear each mode-with-parameter slot */
2132 for (i = 0; i < MAXMODEPARAMS; i++) {
2133 MB_TYPE(mbuf, i) = 0;
2134 MB_UINT(mbuf, i) = 0;
2139 * This routine simply adds modes to be added or deleted; do a binary OR
2140 * with either MODE_ADD or MODE_DEL
2143 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2146 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2148 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2149 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2150 MODE_DELJOINS | MODE_WASDELJOINS);
2152 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2155 if (mode & MODE_ADD) {
2156 mbuf->mb_rem &= ~mode;
2157 mbuf->mb_add |= mode;
2159 mbuf->mb_add &= ~mode;
2160 mbuf->mb_rem |= mode;
2165 * This routine adds a mode to be added or deleted that takes a unsigned
2166 * int parameter; mode may *only* be the relevant mode flag ORed with one
2167 * of MODE_ADD or MODE_DEL
2170 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2173 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2175 if (mode == (MODE_LIMIT | MODE_DEL)) {
2176 mbuf->mb_rem |= mode;
2179 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2180 MB_UINT(mbuf, mbuf->mb_count) = uint;
2182 /* when we've reached the maximal count, flush the buffer */
2183 if (++mbuf->mb_count >=
2184 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2185 modebuf_flush_int(mbuf, 0);
2189 * This routine adds a mode to be added or deleted that takes a string
2190 * parameter; mode may *only* be the relevant mode flag ORed with one of
2191 * MODE_ADD or MODE_DEL
2194 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2198 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2200 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2201 MB_STRING(mbuf, mbuf->mb_count) = string;
2203 /* when we've reached the maximal count, flush the buffer */
2204 if (++mbuf->mb_count >=
2205 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2206 modebuf_flush_int(mbuf, 0);
2210 * This routine adds a mode to be added or deleted that takes a client
2211 * parameter; mode may *only* be the relevant mode flag ORed with one of
2212 * MODE_ADD or MODE_DEL
2215 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2216 struct Client *client)
2219 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2221 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2222 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2224 /* when we've reached the maximal count, flush the buffer */
2225 if (++mbuf->mb_count >=
2226 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2227 modebuf_flush_int(mbuf, 0);
2231 * This is the exported binding for modebuf_flush()
2234 modebuf_flush(struct ModeBuf *mbuf)
2236 struct Membership *memb;
2238 /* Check if MODE_WASDELJOINS should be set */
2239 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2240 && (mbuf->mb_rem & MODE_DELJOINS)) {
2241 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2242 if (IsDelayedJoin(memb)) {
2243 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2244 mbuf->mb_add |= MODE_WASDELJOINS;
2245 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2251 return modebuf_flush_int(mbuf, 1);
2255 * This extracts the simple modes contained in mbuf
2258 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2260 static int flags[] = {
2261 /* MODE_CHANOP, 'o', */
2262 /* MODE_VOICE, 'v', */
2265 MODE_MODERATED, 'm',
2266 MODE_TOPICLIMIT, 't',
2267 MODE_INVITEONLY, 'i',
2268 MODE_NOPRIVMSGS, 'n',
2272 /* MODE_BAN, 'b', */
2279 int i, bufpos = 0, len;
2281 char *key = 0, limitbuf[20];
2282 char *apass = 0, *upass = 0;
2291 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2292 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2293 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2295 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2296 key = MB_STRING(mbuf, i);
2297 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2298 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2299 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2300 upass = MB_STRING(mbuf, i);
2301 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2302 apass = MB_STRING(mbuf, i);
2309 buf[bufpos++] = '+'; /* start building buffer */
2311 for (flag_p = flags; flag_p[0]; flag_p += 2)
2313 buf[bufpos++] = flag_p[1];
2315 for (i = 0, len = bufpos; i < len; i++) {
2317 build_string(buf, &bufpos, key, 0, ' ');
2318 else if (buf[i] == 'l')
2319 build_string(buf, &bufpos, limitbuf, 0, ' ');
2320 else if (buf[i] == 'U')
2321 build_string(buf, &bufpos, upass, 0, ' ');
2322 else if (buf[i] == 'A')
2323 build_string(buf, &bufpos, apass, 0, ' ');
2332 * Simple function to invalidate bans
2335 mode_ban_invalidate(struct Channel *chan)
2337 struct Membership *member;
2339 for (member = chan->members; member; member = member->next_member)
2340 ClearBanValid(member);
2344 * Simple function to drop invite structures
2347 mode_invite_clear(struct Channel *chan)
2349 while (chan->invites)
2350 del_invite(chan->invites->value.cptr, chan);
2353 /* What we've done for mode_parse so far... */
2354 #define DONE_LIMIT 0x01 /* We've set the limit */
2355 #define DONE_KEY 0x02 /* We've set the key */
2356 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2357 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2358 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2359 #define DONE_UPASS 0x20 /* We've set user pass */
2360 #define DONE_APASS 0x40 /* We've set admin pass */
2363 struct ModeBuf *mbuf;
2364 struct Client *cptr;
2365 struct Client *sptr;
2366 struct Channel *chptr;
2367 struct Membership *member;
2378 struct SLink banlist[MAXPARA];
2381 struct Client *client;
2382 } cli_change[MAXPARA];
2386 * Here's a helper function to deal with sending along "Not oper" or
2387 * "Not member" messages
2390 send_notoper(struct ParseState *state)
2392 if (state->done & DONE_NOTOPER)
2395 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2396 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2398 state->done |= DONE_NOTOPER;
2402 * Helper function to convert limits
2405 mode_parse_limit(struct ParseState *state, int *flag_p)
2407 unsigned int t_limit;
2409 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2410 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2413 if (state->parc <= 0) { /* warn if not enough args */
2414 if (MyUser(state->sptr))
2415 need_more_params(state->sptr, "MODE +l");
2419 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2423 if ((int)t_limit<0) /* don't permit a negative limit */
2426 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2427 (!t_limit || t_limit == state->chptr->mode.limit))
2430 t_limit = state->chptr->mode.limit;
2432 /* If they're not an oper, they can't change modes */
2433 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2434 send_notoper(state);
2438 /* Can't remove a limit that's not there */
2439 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2442 /* Skip if this is a burst and a lower limit than this is set already */
2443 if ((state->flags & MODE_PARSE_BURST) &&
2444 (state->chptr->mode.mode & flag_p[0]) &&
2445 (state->chptr->mode.limit < t_limit))
2448 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2450 state->done |= DONE_LIMIT;
2455 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2457 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2458 if (state->dir & MODE_ADD) {
2459 state->chptr->mode.mode |= flag_p[0];
2460 state->chptr->mode.limit = t_limit;
2462 state->chptr->mode.mode &= ~flag_p[0];
2463 state->chptr->mode.limit = 0;
2469 * Helper function to convert keys
2472 mode_parse_key(struct ParseState *state, int *flag_p)
2477 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2480 if (state->parc <= 0) { /* warn if not enough args */
2481 if (MyUser(state->sptr))
2482 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2487 t_str = state->parv[state->args_used++]; /* grab arg */
2491 /* If they're not an oper, they can't change modes */
2492 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2493 send_notoper(state);
2497 if (state->done & DONE_KEY) /* allow key to be set only once */
2499 state->done |= DONE_KEY;
2503 /* clean up the key string */
2505 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2509 if (!*t_str) { /* warn if empty */
2510 if (MyUser(state->sptr))
2511 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2519 /* Skip if this is a burst, we have a key already and the new key is
2520 * after the old one alphabetically */
2521 if ((state->flags & MODE_PARSE_BURST) &&
2522 *(state->chptr->mode.key) &&
2523 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2526 /* can't add a key if one is set, nor can one remove the wrong key */
2527 if (!(state->flags & MODE_PARSE_FORCE))
2528 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2529 (state->dir == MODE_DEL &&
2530 ircd_strcmp(state->chptr->mode.key, t_str))) {
2531 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2535 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2536 !ircd_strcmp(state->chptr->mode.key, t_str))
2537 return; /* no key change */
2539 if (state->flags & MODE_PARSE_BOUNCE) {
2540 if (*state->chptr->mode.key) /* reset old key */
2541 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2542 state->chptr->mode.key, 0);
2543 else /* remove new bogus key */
2544 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2545 } else /* send new key */
2546 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2548 if (state->flags & MODE_PARSE_SET) {
2549 if (state->dir == MODE_ADD) /* set the new key */
2550 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2551 else /* remove the old key */
2552 *state->chptr->mode.key = '\0';
2557 * Helper function to convert user passes
2560 mode_parse_upass(struct ParseState *state, int *flag_p)
2565 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2568 if (state->parc <= 0) { /* warn if not enough args */
2569 if (MyUser(state->sptr))
2570 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2575 t_str = state->parv[state->args_used++]; /* grab arg */
2579 /* If they're not an oper, they can't change modes */
2580 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2581 send_notoper(state);
2585 /* If a non-service user is trying to force it, refuse. */
2586 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2587 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2588 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2592 /* If they are not the channel manager, they are not allowed to change it */
2593 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2594 if (*state->chptr->mode.apass) {
2595 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2596 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2598 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2599 "Re-create the channel. The channel must be *empty* for",
2600 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2601 "before it can be recreated.");
2606 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2608 state->done |= DONE_UPASS;
2610 t_len = PASSLEN + 1;
2612 /* clean up the upass string */
2614 while (*++s > ' ' && *s != ':' && --t_len)
2618 if (!*t_str) { /* warn if empty */
2619 if (MyUser(state->sptr))
2620 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2628 if (!(state->flags & MODE_PARSE_FORCE))
2629 /* can't add the upass while apass is not set */
2630 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2631 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2634 /* can't add a upass if one is set, nor can one remove the wrong upass */
2635 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2636 (state->dir == MODE_DEL &&
2637 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2638 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2642 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2643 !ircd_strcmp(state->chptr->mode.upass, t_str))
2644 return; /* no upass change */
2646 if (state->flags & MODE_PARSE_BOUNCE) {
2647 if (*state->chptr->mode.upass) /* reset old upass */
2648 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2649 state->chptr->mode.upass, 0);
2650 else /* remove new bogus upass */
2651 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2652 } else /* send new upass */
2653 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2655 if (state->flags & MODE_PARSE_SET) {
2656 if (state->dir == MODE_ADD) /* set the new upass */
2657 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2658 else /* remove the old upass */
2659 *state->chptr->mode.upass = '\0';
2664 * Helper function to convert admin passes
2667 mode_parse_apass(struct ParseState *state, int *flag_p)
2672 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2675 if (state->parc <= 0) { /* warn if not enough args */
2676 if (MyUser(state->sptr))
2677 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2682 t_str = state->parv[state->args_used++]; /* grab arg */
2686 /* If they're not an oper, they can't change modes */
2687 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2688 send_notoper(state);
2692 /* If a non-service user is trying to force it, refuse. */
2693 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2694 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2695 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2699 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2700 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2701 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2705 /* If they are not the channel manager, they are not allowed to change it */
2706 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2707 if (*state->chptr->mode.apass) {
2708 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2709 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2711 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2712 "Re-create the channel. The channel must be *empty* for",
2713 "at least a whole minute", "before it can be recreated.");
2718 if (state->done & DONE_APASS) /* allow apass to be set only once */
2720 state->done |= DONE_APASS;
2722 t_len = PASSLEN + 1;
2724 /* clean up the apass string */
2726 while (*++s > ' ' && *s != ':' && --t_len)
2730 if (!*t_str) { /* warn if empty */
2731 if (MyUser(state->sptr))
2732 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2740 if (!(state->flags & MODE_PARSE_FORCE)) {
2741 /* can't remove the apass while upass is still set */
2742 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2743 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2746 /* can't add an apass if one is set, nor can one remove the wrong apass */
2747 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2748 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2749 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2754 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2755 !ircd_strcmp(state->chptr->mode.apass, t_str))
2756 return; /* no apass change */
2758 if (state->flags & MODE_PARSE_BOUNCE) {
2759 if (*state->chptr->mode.apass) /* reset old apass */
2760 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2761 state->chptr->mode.apass, 0);
2762 else /* remove new bogus apass */
2763 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2764 } else /* send new apass */
2765 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2767 if (state->flags & MODE_PARSE_SET) {
2768 if (state->dir == MODE_ADD) { /* set the new apass */
2769 /* Make it VERY clear to the user that this is a one-time password */
2770 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2771 if (MyUser(state->sptr)) {
2772 send_reply(state->sptr, RPL_APASSWARN,
2773 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2774 "Are you SURE you want to use this as Admin password? ",
2775 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2776 send_reply(state->sptr, RPL_APASSWARN,
2777 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2778 "\" to remove the password and then immediately set a new one. "
2779 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2780 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2781 "Now set the channel user password (+u).");
2783 } else { /* remove the old apass */
2784 *state->chptr->mode.apass = '\0';
2785 if (MyUser(state->sptr))
2786 send_reply(state->sptr, RPL_APASSWARN,
2787 "WARNING: You removed the channel Admin password MODE (+A). ",
2788 "If you would disconnect or leave the channel without setting a new password then you will ",
2789 "not be able to set it again and lose ownership of this channel! ",
2790 "SET A NEW PASSWORD NOW!", "");
2796 * Helper function to convert bans
2799 mode_parse_ban(struct ParseState *state, int *flag_p)
2802 struct SLink *ban, *newban = 0;
2804 if (state->parc <= 0) { /* Not enough args, send ban list */
2805 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2806 send_ban_list(state->sptr, state->chptr);
2807 state->done |= DONE_BANLIST;
2813 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2816 t_str = state->parv[state->args_used++]; /* grab arg */
2820 /* If they're not an oper, they can't change modes */
2821 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2822 send_notoper(state);
2826 if ((s = strchr(t_str, ' ')))
2829 if (!*t_str || *t_str == ':') { /* warn if empty */
2830 if (MyUser(state->sptr))
2831 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2836 t_str = collapse(pretty_mask(t_str));
2838 /* remember the ban for the moment... */
2839 if (state->dir == MODE_ADD) {
2840 newban = state->banlist + (state->numbans++);
2843 DupString(newban->value.ban.banstr, t_str);
2844 newban->value.ban.who = cli_name(state->sptr);
2845 newban->value.ban.when = TStime();
2847 newban->flags = CHFL_BAN | MODE_ADD;
2849 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2850 newban->flags |= CHFL_BAN_IPMASK;
2853 if (!state->chptr->banlist) {
2854 state->chptr->banlist = newban; /* add our ban with its flags */
2855 state->done |= DONE_BANCLEAN;
2859 /* Go through all bans */
2860 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2861 /* first, clean the ban flags up a bit */
2862 if (!(state->done & DONE_BANCLEAN))
2863 /* Note: We're overloading *lots* of bits here; be careful! */
2864 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2868 * MODE_ADD - Ban was added; if we're bouncing modes,
2869 * then we'll remove it below; otherwise,
2870 * we'll have to allocate a real ban
2872 * MODE_DEL - Ban was marked for deletion; if we're
2873 * bouncing modes, we'll have to re-add it,
2874 * otherwise, we'll have to remove it
2876 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2877 * with a ban already set; if we're
2878 * bouncing modes, we'll have to bounce
2879 * this one; otherwise, we'll just ignore
2880 * it when we process added bans
2883 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2884 ban->flags |= MODE_DEL; /* delete one ban */
2886 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2888 } else if (state->dir == MODE_ADD) {
2889 /* if the ban already exists, don't worry about it */
2890 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2891 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2892 MyFree(newban->value.ban.banstr); /* stopper a leak */
2893 state->numbans--; /* deallocate last ban */
2894 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2896 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2897 if (!(ban->flags & MODE_DEL))
2898 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2899 } else if (!mmatch(t_str, ban->value.ban.banstr))
2900 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2902 if (!ban->next && (newban->flags & MODE_ADD))
2904 ban->next = newban; /* add our ban with its flags */
2905 break; /* get out of loop */
2909 state->done |= DONE_BANCLEAN;
2913 * This is the bottom half of the ban processor
2916 mode_process_bans(struct ParseState *state)
2918 struct SLink *ban, *newban, *prevban, *nextban;
2924 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2926 banlen = strlen(ban->value.ban.banstr);
2928 nextban = ban->next;
2930 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2932 prevban->next = 0; /* Break the list; ban isn't a real ban */
2934 state->chptr->banlist = 0;
2939 MyFree(ban->value.ban.banstr);
2942 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2943 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2944 ban->value.ban.banstr,
2945 state->flags & MODE_PARSE_SET);
2947 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2948 if (prevban) /* clip it out of the list... */
2949 prevban->next = ban->next;
2951 state->chptr->banlist = ban->next;
2956 MyFree(ban->value.ban.who);
2960 continue; /* next ban; keep prevban like it is */
2962 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2963 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2965 prevban->next = 0; /* Break the list; ban isn't a real ban */
2967 state->chptr->banlist = 0;
2969 /* If we're supposed to ignore it, do so. */
2970 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2971 !(state->flags & MODE_PARSE_BOUNCE)) {
2975 MyFree(ban->value.ban.banstr);
2977 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2978 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2979 count > feature_int(FEAT_MAXBANS))) {
2980 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2981 ban->value.ban.banstr);
2985 MyFree(ban->value.ban.banstr);
2987 /* add the ban to the buffer */
2988 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2989 ban->value.ban.banstr,
2990 !(state->flags & MODE_PARSE_SET));
2992 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2993 newban = make_link();
2994 newban->value.ban.banstr = ban->value.ban.banstr;
2995 DupString(newban->value.ban.who, ban->value.ban.who);
2996 newban->value.ban.when = ban->value.ban.when;
2997 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2999 newban->next = state->chptr->banlist; /* and link it in */
3000 state->chptr->banlist = newban;
3009 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3011 if (changed) /* if we changed the ban list, we must invalidate the bans */
3012 mode_ban_invalidate(state->chptr);
3016 * Helper function to process client changes
3019 mode_parse_client(struct ParseState *state, int *flag_p)
3022 struct Client *acptr;
3025 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3028 if (state->parc <= 0) /* return if not enough args */
3031 t_str = state->parv[state->args_used++]; /* grab arg */
3035 /* If they're not an oper, they can't change modes */
3036 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3037 send_notoper(state);
3041 if (MyUser(state->sptr)) /* find client we're manipulating */
3042 acptr = find_chasing(state->sptr, t_str, NULL);
3044 acptr = findNUser(t_str);
3047 return; /* find_chasing() already reported an error to the user */
3049 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3050 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3051 state->cli_change[i].flag & flag_p[0]))
3052 break; /* found a slot */
3054 /* Store what we're doing to them */
3055 state->cli_change[i].flag = state->dir | flag_p[0];
3056 state->cli_change[i].client = acptr;
3060 * Helper function to process the changed client list
3063 mode_process_clients(struct ParseState *state)
3066 struct Membership *member;
3068 for (i = 0; state->cli_change[i].flag; i++) {
3069 assert(0 != state->cli_change[i].client);
3071 /* look up member link */
3072 if (!(member = find_member_link(state->chptr,
3073 state->cli_change[i].client)) ||
3074 (MyUser(state->sptr) && IsZombie(member))) {
3075 if (MyUser(state->sptr))
3076 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3077 cli_name(state->cli_change[i].client),
3078 state->chptr->chname);
3082 if ((state->cli_change[i].flag & MODE_ADD &&
3083 (state->cli_change[i].flag & member->status)) ||
3084 (state->cli_change[i].flag & MODE_DEL &&
3085 !(state->cli_change[i].flag & member->status)))
3086 continue; /* no change made, don't do anything */
3088 /* see if the deop is allowed */
3089 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3090 (MODE_DEL | MODE_CHANOP)) {
3091 /* prevent +k users from being deopped */
3092 if (IsChannelService(state->cli_change[i].client)) {
3093 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3094 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3096 (IsServer(state->sptr) ? cli_name(state->sptr) :
3097 cli_name((cli_user(state->sptr))->server)));
3099 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3100 send_reply(state->sptr, ERR_ISCHANSERVICE,
3101 cli_name(state->cli_change[i].client),
3102 state->chptr->chname);
3107 /* check deop for local user */
3108 if (MyUser(state->sptr)) {
3110 /* don't allow local opers to be deopped on local channels */
3111 if (state->cli_change[i].client != state->sptr &&
3112 IsLocalChannel(state->chptr->chname) &&
3113 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3114 send_reply(state->sptr, ERR_ISOPERLCHAN,
3115 cli_name(state->cli_change[i].client),
3116 state->chptr->chname);
3120 if (feature_bool(FEAT_OPLEVELS)) {
3121 /* don't allow to deop members with an op level that is <= our own level */
3122 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3124 && OpLevel(member) <= OpLevel(state->member)) {
3125 int equal = (OpLevel(member) == OpLevel(state->member));
3126 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3127 cli_name(state->cli_change[i].client),
3128 state->chptr->chname,
3129 OpLevel(state->member), OpLevel(member),
3130 "deop", equal ? "the same" : "a higher");
3137 /* set op-level of member being opped */
3138 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3139 (MODE_ADD | MODE_CHANOP)) {
3140 /* If on a channel with upass set, someone with level x gives ops to someone else,
3141 then that person gets level x-1. On other channels, where upass is not set,
3142 the level stays the same. */
3143 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3144 /* Someone being opped by a server gets op-level 0 */
3145 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3146 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3149 /* actually effect the change */
3150 if (state->flags & MODE_PARSE_SET) {
3151 if (state->cli_change[i].flag & MODE_ADD) {
3152 if (IsDelayedJoin(member))
3153 RevealDelayedJoin(member);
3154 member->status |= (state->cli_change[i].flag &
3155 (MODE_CHANOP | MODE_VOICE));
3156 if (state->cli_change[i].flag & MODE_CHANOP)
3157 ClearDeopped(member);
3159 member->status &= ~(state->cli_change[i].flag &
3160 (MODE_CHANOP | MODE_VOICE));
3163 /* accumulate the change */
3164 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3165 state->cli_change[i].client);
3166 } /* for (i = 0; state->cli_change[i].flags; i++) */
3170 * Helper function to process the simple modes
3173 mode_parse_mode(struct ParseState *state, int *flag_p)
3175 /* If they're not an oper, they can't change modes */
3176 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3177 send_notoper(state);
3184 if (state->dir == MODE_ADD) {
3185 state->add |= flag_p[0];
3186 state->del &= ~flag_p[0];
3188 if (flag_p[0] & MODE_SECRET) {
3189 state->add &= ~MODE_PRIVATE;
3190 state->del |= MODE_PRIVATE;
3191 } else if (flag_p[0] & MODE_PRIVATE) {
3192 state->add &= ~MODE_SECRET;
3193 state->del |= MODE_SECRET;
3195 if (flag_p[0] & MODE_DELJOINS) {
3196 state->add &= ~MODE_WASDELJOINS;
3197 state->del |= MODE_WASDELJOINS;
3200 state->add &= ~flag_p[0];
3201 state->del |= flag_p[0];
3204 assert(0 == (state->add & state->del));
3205 assert((MODE_SECRET | MODE_PRIVATE) !=
3206 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3210 * This routine is intended to parse MODE or OPMODE commands and effect the
3211 * changes (or just build the bounce buffer). We pass the starting offset
3215 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3216 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3217 struct Membership* member)
3219 static int chan_flags[] = {
3224 MODE_MODERATED, 'm',
3225 MODE_TOPICLIMIT, 't',
3226 MODE_INVITEONLY, 'i',
3227 MODE_NOPRIVMSGS, 'n',
3241 unsigned int t_mode;
3243 struct ParseState state;
3254 state.chptr = chptr;
3255 state.member = member;
3258 state.flags = flags;
3259 state.dir = MODE_ADD;
3263 state.args_used = 0;
3264 state.max_args = MAXMODEPARAMS;
3267 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3268 state.banlist[i].next = 0;
3269 state.banlist[i].value.ban.banstr = 0;
3270 state.banlist[i].value.ban.who = 0;
3271 state.banlist[i].value.ban.when = 0;
3272 state.banlist[i].flags = 0;
3273 state.cli_change[i].flag = 0;
3274 state.cli_change[i].client = 0;
3277 modestr = state.parv[state.args_used++];
3281 for (; *modestr; modestr++) {
3282 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3283 if (flag_p[1] == *modestr)
3286 if (!flag_p[0]) { /* didn't find it? complain and continue */
3287 if (MyUser(state.sptr))
3288 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3293 case '+': /* switch direction to MODE_ADD */
3294 case '-': /* switch direction to MODE_DEL */
3295 state.dir = flag_p[0];
3298 case 'l': /* deal with limits */
3299 mode_parse_limit(&state, flag_p);
3302 case 'k': /* deal with keys */
3303 mode_parse_key(&state, flag_p);
3306 case 'A': /* deal with Admin passes */
3307 if (feature_bool(FEAT_OPLEVELS))
3308 mode_parse_apass(&state, flag_p);
3311 case 'U': /* deal with user passes */
3312 if (feature_bool(FEAT_OPLEVELS))
3313 mode_parse_upass(&state, flag_p);
3316 case 'b': /* deal with bans */
3317 mode_parse_ban(&state, flag_p);
3320 case 'o': /* deal with ops/voice */
3322 mode_parse_client(&state, flag_p);
3325 default: /* deal with other modes */
3326 mode_parse_mode(&state, flag_p);
3328 } /* switch (*modestr) */
3329 } /* for (; *modestr; modestr++) */
3331 if (state.flags & MODE_PARSE_BURST)
3332 break; /* don't interpret any more arguments */
3334 if (state.parc > 0) { /* process next argument in string */
3335 modestr = state.parv[state.args_used++];
3339 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3342 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3343 break; /* we're then going to bounce the mode! */
3345 recv_ts = atoi(modestr);
3347 if (recv_ts && recv_ts < state.chptr->creationtime)
3348 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3350 break; /* break out of while loop */
3351 } else if (state.flags & MODE_PARSE_STRICT ||
3352 (MyUser(state.sptr) && state.max_args <= 0)) {
3353 state.parc++; /* we didn't actually gobble the argument */
3355 break; /* break out of while loop */
3358 } /* while (*modestr) */
3361 * the rest of the function finishes building resultant MODEs; if the
3362 * origin isn't a member or an oper, skip it.
3364 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3365 return state.args_used; /* tell our parent how many args we gobbled */
3367 t_mode = state.chptr->mode.mode;
3369 if (state.del & t_mode) { /* delete any modes to be deleted... */
3370 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3372 t_mode &= ~state.del;
3374 if (state.add & ~t_mode) { /* add any modes to be added... */
3375 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3377 t_mode |= state.add;
3380 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3381 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3382 !(t_mode & MODE_INVITEONLY))
3383 mode_invite_clear(state.chptr);
3385 state.chptr->mode.mode = t_mode;
3388 if (state.flags & MODE_PARSE_WIPEOUT) {
3389 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3390 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3391 state.chptr->mode.limit);
3392 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3393 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3394 state.chptr->mode.key, 0);
3395 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3396 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3397 state.chptr->mode.upass, 0);
3398 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3399 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3400 state.chptr->mode.apass, 0);
3403 if (state.done & DONE_BANCLEAN) /* process bans */
3404 mode_process_bans(&state);
3406 /* process client changes */
3407 if (state.cli_change[0].flag)
3408 mode_process_clients(&state);
3410 return state.args_used; /* tell our parent how many args we gobbled */
3414 * Initialize a join buffer
3417 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3418 struct Client *connect, unsigned int type, char *comment,
3424 assert(0 != source);
3425 assert(0 != connect);
3427 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3428 jbuf->jb_connect = connect;
3429 jbuf->jb_type = type;
3430 jbuf->jb_comment = comment;
3431 jbuf->jb_create = create;
3433 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3434 type == JOINBUF_TYPE_PART ||
3435 type == JOINBUF_TYPE_PARTALL) ?
3436 STARTJOINLEN : STARTCREATELEN) +
3437 (comment ? strlen(comment) + 2 : 0));
3439 for (i = 0; i < MAXJOINARGS; i++)
3440 jbuf->jb_channels[i] = 0;
3444 * Add a channel to the join buffer
3447 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3455 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3456 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3461 is_local = IsLocalChannel(chan->chname);
3463 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3464 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3465 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3466 if (IsUserParting(member))
3468 SetUserParting(member);
3470 /* Send notification to channel */
3471 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3472 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3473 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3474 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3475 else if (MyUser(jbuf->jb_source))
3476 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3477 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3478 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3479 /* XXX: Shouldn't we send a PART here anyway? */
3480 /* to users on the channel? Why? From their POV, the user isn't on
3481 * the channel anymore anyway. We don't send to servers until below,
3482 * when we gang all the channel parts together. Note that this is
3483 * exactly the same logic, albeit somewhat more concise, as was in
3484 * the original m_part.c */
3486 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3487 is_local) /* got to remove user here */
3488 remove_user_from_channel(jbuf->jb_source, chan);
3490 /* Add user to channel */
3491 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3492 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3494 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3496 /* send notification to all servers */
3497 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3498 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3499 "%H %Tu", chan, chan->creationtime);
3501 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3502 /* Send the notification to the channel */
3503 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3505 /* send an op, too, if needed */
3506 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3507 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3508 chan, jbuf->jb_source);
3509 } else if (MyUser(jbuf->jb_source))
3510 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3513 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3514 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3515 return; /* don't send to remote */
3517 /* figure out if channel name will cause buffer to be overflowed */
3518 len = chan ? strlen(chan->chname) + 1 : 2;
3519 if (jbuf->jb_strlen + len > BUFSIZE)
3520 joinbuf_flush(jbuf);
3522 /* add channel to list of channels to send and update counts */
3523 jbuf->jb_channels[jbuf->jb_count++] = chan;
3524 jbuf->jb_strlen += len;
3526 /* if we've used up all slots, flush */
3527 if (jbuf->jb_count >= MAXJOINARGS)
3528 joinbuf_flush(jbuf);
3532 * Flush the channel list to remote servers
3535 joinbuf_flush(struct JoinBuf *jbuf)
3537 char chanlist[BUFSIZE];
3541 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3542 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3543 return 0; /* no joins to process */
3545 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3546 build_string(chanlist, &chanlist_i,
3547 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3548 i == 0 ? '\0' : ',');
3549 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3550 /* Remove user from channel */
3551 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3553 jbuf->jb_channels[i] = 0; /* mark slot empty */
3556 jbuf->jb_count = 0; /* reset base counters */
3557 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3558 STARTJOINLEN : STARTCREATELEN) +
3559 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3561 /* and send the appropriate command */
3562 switch (jbuf->jb_type) {
3563 case JOINBUF_TYPE_CREATE:
3564 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3565 "%s %Tu", chanlist, jbuf->jb_create);
3568 case JOINBUF_TYPE_PART:
3569 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3570 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3578 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3579 int IsInvited(struct Client* cptr, const void* chptr)
3583 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3584 if (lp->value.chptr == chptr)
3589 /* RevealDelayedJoin: sends a join for a hidden user */
3591 void RevealDelayedJoin(struct Membership *member) {
3592 ClearDelayedJoin(member);
3593 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3595 CheckDelayedJoins(member->channel);
3598 /* CheckDelayedJoins: checks and clear +d if necessary */
3600 void CheckDelayedJoins(struct Channel *chan) {
3601 struct Membership *memb2;
3603 if (chan->mode.mode & MODE_WASDELJOINS) {
3604 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3605 if (IsDelayedJoin(memb2))
3610 chan->mode.mode &= ~MODE_WASDELJOINS;
3611 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,