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 banid The actual ban.
363 * @param change True if adding a ban, false if old bans should just be flagged
364 * @param firsttime Reset the next_overlapped_ban() iteration.
366 * 0 if the ban was added
367 * -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT
370 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
371 int change, int firsttime)
376 int removed_bans = 0;
377 int len = strlen(banid);
382 assert(0 == prev_ban);
383 assert(0 == removed_bans_list);
387 for (banp = &chptr->banlist; *banp;)
389 len += strlen((*banp)->value.ban.banstr);
391 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
393 if (!strcmp((*banp)->value.ban.banstr, banid))
395 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
399 else if (!mmatch((*banp)->value.ban.banstr, banid))
401 if (!mmatch(banid, (*banp)->value.ban.banstr))
403 struct SLink *tmp = *banp;
409 len -= strlen(tmp->value.ban.banstr);
412 /* These will be sent to the user later as -b */
413 tmp->next = removed_bans_list;
414 removed_bans_list = tmp;
417 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
419 tmp->flags |= CHFL_BAN_OVERLAPPED;
430 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
431 banp = &(*banp)->next;
434 if (MyUser(cptr) && !removed_bans &&
435 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
436 (cnt >= feature_int(FEAT_MAXBANS))))
438 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
444 struct Membership* member;
446 ban->next = chptr->banlist;
448 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
449 assert(0 != ban->value.ban.banstr);
450 strcpy(ban->value.ban.banstr, banid);
452 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
453 DupString(ban->value.ban.who, cli_name(&me));
455 DupString(ban->value.ban.who, cli_name(cptr));
456 assert(0 != ban->value.ban.who);
458 ban->value.ban.when = TStime();
459 ban->flags = CHFL_BAN; /* This bit is never used I think... */
460 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
461 ban->flags |= CHFL_BAN_IPMASK;
462 chptr->banlist = ban;
465 * Erase ban-valid-bit
467 for (member = chptr->members; member; member = member->next_member)
468 ClearBanValid(member); /* `ban' == channel member ! */
473 /** return the next ban that is removed
474 * @returns the next ban that is removed because of overlapping
476 struct SLink *next_removed_overlapped_ban(void)
478 struct SLink *tmp = removed_bans_list;
481 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
482 MyFree(prev_ban->value.ban.banstr);
483 MyFree(prev_ban->value.ban.who);
488 removed_bans_list = removed_bans_list->next;
493 /** returns Membership * if a person is joined and not a zombie
495 * @param chptr Channel
496 * @returns pointer to the client's struct Membership * on the channel if that
497 * user is a full member of the channel, or NULL otherwise.
499 * @see find_member_link()
501 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
503 struct Membership* member;
506 member = find_member_link(chptr, cptr);
507 return (member && !IsZombie(member)) ? member : 0;
510 /** return true if banned else false.
512 * This function returns true if the user is banned on the said channel.
513 * This function will check the ban cache if applicable, otherwise will
514 * do the comparisons and cache the result.
516 * @param cptr The client to test
517 * @param chptr The channel
518 * @param member The Membership * of this client on this channel
519 * (may be NULL if the member is not on the channel).
521 static int is_banned(struct Client *cptr, struct Channel *chptr,
522 struct Membership* member)
525 char tmphost[HOSTLEN + 1];
526 char nu_host[NUH_BUFSIZE];
527 char nu_realhost[NUH_BUFSIZE];
528 char nu_ip[NUI_BUFSIZE];
536 if (member && IsBanValid(member))
537 return IsBanned(member);
539 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
540 (cli_user(cptr))->host);
543 if (HasHiddenHost(cptr))
545 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
546 (cli_user(cptr))->username,
547 cli_user(cptr)->realhost);
551 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
552 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
553 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
554 cli_user(cptr)->username,
559 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
560 if ((tmp->flags & CHFL_BAN_IPMASK)) {
562 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
563 (cli_user(cptr))->username, &cli_ip(cptr));
564 if (match(tmp->value.ban.banstr, ip_s) == 0)
567 if (match(tmp->value.ban.banstr, s) == 0)
569 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
585 return (tmp != NULL);
588 /** add a user to a channel.
589 * adds a user to a channel by adding another link to the channels member
592 * @param chptr The channel to add to.
593 * @param who The user to add.
594 * @param flags The flags the user gets initially.
595 * @param oplevel The oplevel the user starts with.
597 void add_user_to_channel(struct Channel* chptr, struct Client* who,
598 unsigned int flags, int oplevel)
605 struct Membership* member = membershipFreeList;
607 membershipFreeList = member->next_member;
609 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
610 ++membershipAllocCount;
615 member->channel = chptr;
616 member->status = flags;
617 member->oplevel = oplevel;
619 member->next_member = chptr->members;
620 if (member->next_member)
621 member->next_member->prev_member = member;
622 member->prev_member = 0;
623 chptr->members = member;
625 member->next_channel = (cli_user(who))->channel;
626 if (member->next_channel)
627 member->next_channel->prev_channel = member;
628 member->prev_channel = 0;
629 (cli_user(who))->channel = member;
631 if (chptr->destruct_event)
632 remove_destruct_event(chptr);
634 ++((cli_user(who))->joined);
638 /** Remove a person from a channel, given their Membership*
640 * @param member A member of a channel.
642 * @returns true if there are more people in the channel.
644 static int remove_member_from_channel(struct Membership* member)
646 struct Channel* chptr;
648 chptr = member->channel;
650 * unlink channel member list
652 if (member->next_member)
653 member->next_member->prev_member = member->prev_member;
654 if (member->prev_member)
655 member->prev_member->next_member = member->next_member;
657 member->channel->members = member->next_member;
660 * If this is the last delayed-join user, may have to clear WASDELJOINS.
662 if (IsDelayedJoin(member))
663 CheckDelayedJoins(chptr);
666 * unlink client channel list
668 if (member->next_channel)
669 member->next_channel->prev_channel = member->prev_channel;
670 if (member->prev_channel)
671 member->prev_channel->next_channel = member->next_channel;
673 (cli_user(member->user))->channel = member->next_channel;
675 --(cli_user(member->user))->joined;
677 member->next_member = membershipFreeList;
678 membershipFreeList = member;
680 return sub1_from_channel(chptr);
683 /** Check if all the remaining members on the channel are zombies
685 * @returns False if the channel has any non zombie members, True otherwise.
688 static int channel_all_zombies(struct Channel* chptr)
690 struct Membership* member;
692 for (member = chptr->members; member; member = member->next_member) {
693 if (!IsZombie(member))
700 /** Remove a user from a channel
701 * This is the generic entry point for removing a user from a channel, this
702 * function will remove the client from the channel, and destory the channel
703 * if there are no more normal users left.
705 * @param cptr The client
706 * @param chptr The channel
708 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
711 struct Membership* member;
714 if ((member = find_member_link(chptr, cptr))) {
715 if (remove_member_from_channel(member)) {
716 if (channel_all_zombies(chptr)) {
718 * XXX - this looks dangerous but isn't if we got the referential
719 * integrity right for channels
721 while (remove_member_from_channel(chptr->members))
728 /** Remove a user from all channels they are on.
730 * This function removes a user from all channels they are on.
732 * @param cptr The client to remove.
734 void remove_user_from_all_channels(struct Client* cptr)
736 struct Membership* chan;
738 assert(0 != cli_user(cptr));
740 while ((chan = (cli_user(cptr))->channel))
741 remove_user_from_channel(cptr, chan->channel);
744 /** Check if this user is a legitimate chanop
746 * @param cptr Client to check
747 * @param chptr Channel to check
749 * @returns True if the user is a chanop (And not a zombie), False otherwise.
752 int is_chan_op(struct Client *cptr, struct Channel *chptr)
754 struct Membership* member;
756 if ((member = find_member_link(chptr, cptr)))
757 return (!IsZombie(member) && IsChanOp(member));
762 /** Check if a user is a Zombie on a specific channel.
764 * @param cptr The client to check.
765 * @param chptr The channel to check.
767 * @returns True if the client (cptr) is a zombie on the channel (chptr),
772 int is_zombie(struct Client *cptr, struct Channel *chptr)
774 struct Membership* member;
778 if ((member = find_member_link(chptr, cptr)))
779 return IsZombie(member);
783 /** Returns if a user has voice on a channel.
785 * @param cptr The client
786 * @param chptr The channel
788 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
791 int has_voice(struct Client* cptr, struct Channel* chptr)
793 struct Membership* member;
796 if ((member = find_member_link(chptr, cptr)))
797 return (!IsZombie(member) && HasVoice(member));
802 /** Can this member send to a channel
804 * A user can speak on a channel iff:
806 * <li> They didn't use the Apass to gain ops.
807 * <li> They are op'd or voice'd.
808 * <li> You aren't banned.
809 * <li> The channel isn't +m
810 * <li> The channel isn't +n or you are on the channel.
813 * This function will optionally reveal a user on a delayed join channel if
814 * they are allowed to send to the channel.
816 * @param member The membership of the user
817 * @param reveal If true, the user will be "revealed" on a delayed
820 * @returns True if the client can speak on the channel.
822 int member_can_send_to_channel(struct Membership* member, int reveal)
826 /* Discourage using the Apass to get op. They should use the upass. */
827 if (IsChannelManager(member) && *member->channel->mode.upass)
830 if (IsVoicedOrOpped(member))
833 * If it's moderated, and you aren't a priviledged user, you can't
836 if (member->channel->mode.mode & MODE_MODERATED)
839 * If you're banned then you can't speak either.
840 * but because of the amount of CPU time that is_banned chews
841 * we only check it for our clients.
843 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
846 if (IsDelayedJoin(member) && reveal)
847 RevealDelayedJoin(member);
852 /** Check if a client can send to a channel.
854 * Has the added check over member_can_send_to_channel() of servers can
857 * @param cptr The client to check
858 * @param chptr The channel to check
859 * @param reveal If the user should be revealed (see
860 * member_can_send_to_channel())
862 * @returns true if the client is allowed to speak on the channel, false
865 * @see member_can_send_to_channel()
867 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
869 struct Membership *member;
872 * Servers can always speak on channels.
877 member = find_channel_member(cptr, chptr);
880 * You can't speak if you're off channel, and it is +n (no external messages)
884 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
885 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
888 return !is_banned(cptr, chptr, NULL);
890 return member_can_send_to_channel(member, reveal);
893 /** Returns the name of a channel that prevents the user from changing nick.
894 * if a member and not (opped or voiced) and (banned or moderated), return
895 * the name of the first channel banned on.
897 * @param cptr The client
899 * @returns the name of the first channel banned on, or NULL if the user
902 const char* find_no_nickchange_channel(struct Client* cptr)
905 struct Membership* member;
906 for (member = (cli_user(cptr))->channel; member;
907 member = member->next_channel) {
908 if (!IsVoicedOrOpped(member) &&
909 (is_banned(cptr, member->channel, member) ||
910 (member->channel->mode.mode & MODE_MODERATED)))
911 return member->channel->chname;
918 /** Fill mbuf/pbuf with modes from chptr
919 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
920 * with the parameters in pbuf as visible by cptr.
922 * This function will hide keys from non-op'd, non-server clients.
924 * @param cptr The client to generate the mode for.
925 * @param mbuf The buffer to write the modes into.
926 * @param pbuf The buffer to write the mode parameters into.
927 * @param buflen The length of the buffers.
928 * @param chptr The channel to get the modes from.
929 * @param member The membership of this client on this channel (or NULL
930 * if this client isn't on this channel)
933 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
934 struct Channel *chptr, struct Membership *member)
936 int previous_parameter = 0;
943 if (chptr->mode.mode & MODE_SECRET)
945 else if (chptr->mode.mode & MODE_PRIVATE)
947 if (chptr->mode.mode & MODE_MODERATED)
949 if (chptr->mode.mode & MODE_TOPICLIMIT)
951 if (chptr->mode.mode & MODE_INVITEONLY)
953 if (chptr->mode.mode & MODE_NOPRIVMSGS)
955 if (chptr->mode.mode & MODE_REGONLY)
957 if (chptr->mode.mode & MODE_DELJOINS)
959 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
961 if (chptr->mode.limit) {
963 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
964 previous_parameter = 1;
967 if (*chptr->mode.key) {
969 if (previous_parameter)
971 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
972 strcat(pbuf, chptr->mode.key);
975 previous_parameter = 1;
977 if (*chptr->mode.apass) {
979 if (previous_parameter)
981 if (IsServer(cptr)) {
982 strcat(pbuf, chptr->mode.apass);
985 previous_parameter = 1;
987 if (*chptr->mode.upass) {
989 if (previous_parameter)
991 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
992 strcat(pbuf, chptr->mode.upass);
999 /** Compare two members oplevel
1001 * @param mp1 Pointer to a pointer to a membership
1002 * @param mp2 Pointer to a pointer to a membership
1004 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
1006 * Used for qsort(3).
1008 int compare_member_oplevel(const void *mp1, const void *mp2)
1010 struct Membership const* member1 = *(struct Membership const**)mp1;
1011 struct Membership const* member2 = *(struct Membership const**)mp2;
1012 if (member1->oplevel == member2->oplevel)
1014 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1017 /* send "cptr" a full list of the modes for channel chptr.
1019 * Sends a BURST line to cptr, bursting all the modes for the channel.
1021 * @param cptr Client pointer
1022 * @param chptr Channel pointer
1024 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1026 /* The order in which modes are generated is now mandatory */
1027 static unsigned int current_flags[4] =
1028 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1034 struct Membership* member;
1036 char modebuf[MODEBUFLEN];
1037 char parabuf[MODEBUFLEN];
1039 int number_of_ops = 0;
1040 int opped_members_index = 0;
1041 struct Membership** opped_members = NULL;
1042 int last_oplevel = 0;
1043 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1048 if (IsLocalChannel(chptr->chname))
1051 member = chptr->members;
1052 lp2 = chptr->banlist;
1054 *modebuf = *parabuf = '\0';
1055 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1057 for (first = 1; full; first = 0) /* Loop for multiple messages */
1059 full = 0; /* Assume by default we get it
1060 all in one message */
1062 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1063 /* is there any better way we can do this? */
1064 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1065 chptr->creationtime);
1067 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1070 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1071 msgq_append(&me, mb, " %s", modebuf);
1074 msgq_append(&me, mb, " %s", parabuf);
1078 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1080 * First find all opless members.
1081 * Run 2 times over all members, to group the members with
1082 * and without voice together.
1083 * Then run 2 times over all opped members (which are ordered
1084 * by op-level) to also group voice and non-voice together.
1086 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1090 if (flag_cnt < 2 && IsChanOp(member))
1093 * The first loop (to find all non-voice/op), we count the ops.
1094 * The second loop (to find all voiced non-ops), store the ops
1095 * in a dynamic array.
1100 opped_members[opped_members_index++] = member;
1102 /* Only handle the members with the flags that we are interested in. */
1103 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1105 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1106 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1108 full = 1; /* Make sure we continue after
1109 sending it so far */
1110 /* Ensure the new BURST line contains the current
1111 * ":mode", except when there is no mode yet. */
1112 new_mode = (flag_cnt > 0) ? 1 : 0;
1113 break; /* Do not add this member to this message */
1115 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1116 first = 0; /* From now on, use commas to add new nicks */
1119 * Do we have a nick with a new mode ?
1120 * Or are we starting a new BURST line?
1122 if (new_mode || !feat_oplevels)
1125 * This means we are at the _first_ member that has only
1126 * voice, or the first member that has only ops, or the
1127 * first member that has voice and ops (so we get here
1128 * at most three times, plus once for every start of
1129 * a continued BURST line where only these modes is current.
1130 * In the two cases where the current mode includes ops,
1131 * we need to add the _absolute_ value of the oplevel to the mode.
1133 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1136 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1138 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1140 /* append the absolute value of the oplevel */
1142 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1147 msgq_append(&me, mb, tbuf);
1150 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1153 * This can't be the first member of a (continued) BURST
1154 * message because then either flag_cnt == 0 or new_mode == 1
1155 * Now we need to append the incremental value of the oplevel.
1157 char tbuf[2 + MAXOPLEVELDIGITS];
1158 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1159 last_oplevel = member->oplevel;
1160 msgq_append(&me, mb, tbuf);
1163 /* Go to the next `member'. */
1165 member = member->next_member;
1167 member = opped_members[++opped_members_index];
1172 /* Point `member' at the start of the list again. */
1175 member = chptr->members;
1176 /* Now, after one loop, we know the number of ops and can
1177 * allocate the dynamic array with pointer to the ops. */
1178 opped_members = (struct Membership**)
1179 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1180 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1184 /* At the end of the second loop, sort the opped members with
1185 * increasing op-level, so that we will output them in the
1186 * correct order (and all op-level increments stay positive) */
1188 qsort(opped_members, number_of_ops,
1189 sizeof(struct Membership*), compare_member_oplevel);
1190 /* The third and fourth loop run only over the opped members. */
1191 member = opped_members[(opped_members_index = 0)];
1194 } /* loop over 0,+v,+o,+ov */
1198 /* Attach all bans, space seperated " :%ban ban ..." */
1199 for (first = 2; lp2; lp2 = lp2->next)
1201 len = strlen(lp2->value.ban.banstr);
1202 if (msgq_bufleft(mb) < len + 1 + first)
1203 /* The +1 stands for the added ' '.
1204 * The +first stands for the added ":%".
1210 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1211 lp2->value.ban.banstr);
1216 send_buffer(cptr, mb, 0); /* Send this message */
1218 } /* Continue when there was something
1219 that didn't fit (full==1) */
1221 MyFree(opped_members);
1222 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1223 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1224 chptr->creationtime, chptr->topic_time, chptr->topic);
1227 /** Canonify a mask.
1230 * @author Carlo Wood (Run),
1233 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1234 * When the user name or host name are too long (USERLEN and HOSTLEN
1235 * respectively) then they are cut off at the start with a '*'.
1237 * The following transformations are made:
1239 * 1) xxx -> nick!*@*
1240 * 2) xxx.xxx -> *!*\@host
1241 * 3) xxx\!yyy -> nick!user\@*
1242 * 4) xxx\@yyy -> *!user\@host
1243 * 5) xxx!yyy\@zzz -> nick!user\@host
1245 * @param mask The uncanonified mask.
1246 * @returns The updated mask in a static buffer.
1248 char *pretty_mask(char *mask)
1250 static char star[2] = { '*', 0 };
1251 static char retmask[NUH_BUFSIZE];
1252 char *last_dot = NULL;
1255 /* Case 1: default */
1260 /* Do a _single_ pass through the characters of the mask: */
1261 for (ptr = mask; *ptr; ++ptr)
1265 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1269 else if (*ptr == '@')
1271 /* Case 4: Found last '@' (without finding a '!' yet) */
1276 else if (*ptr == '.')
1278 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1288 /* Case 4 or 5: Found last '@' */
1294 if (user == star && last_dot)
1304 char *nick_end = (user != star) ? user - 1 : ptr;
1305 if (nick_end - nick > NICKLEN)
1311 char *user_end = (host != star) ? host - 1 : ptr;
1312 if (user_end - user > USERLEN)
1314 user = user_end - USERLEN;
1319 if (host != star && ptr - host > HOSTLEN)
1321 host = ptr - HOSTLEN;
1324 return make_nick_user_host(retmask, nick, user, host);
1327 /** send a banlist to a client for a channel
1329 * @param cptr Client to send the banlist to.
1330 * @param chptr Channel whose banlist to send.
1332 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1339 for (lp = chptr->banlist; lp; lp = lp->next)
1340 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1341 lp->value.ban.who, lp->value.ban.when);
1343 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1346 /** Check a key against a keyring.
1347 * We are now treating the key part of /join channellist key as a key
1348 * ring; that is, we try one key against the actual channel key, and if that
1349 * doesn't work, we try the next one, and so on. -Kev -Texaco
1350 * Returns: 0 on match, 1 otherwise
1351 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1353 * @param key Key to check
1354 * @param keyring Comma seperated list of keys
1356 * @returns True if the key was found and matches, false otherwise.
1358 static int compall(char *key, char *keyring)
1363 p1 = key; /* point to the key... */
1364 while (*p1 && *p1 == *keyring)
1365 { /* step through the key and ring until they
1371 if (!*p1 && (!*keyring || *keyring == ','))
1372 /* ok, if we're at the end of the and also at the end of one of the keys
1373 in the keyring, we have a match */
1376 if (!*keyring) /* if we're at the end of the key ring, there
1377 weren't any matches, so we return 1 */
1380 /* Not at the end of the key ring, so step
1381 through to the next key in the ring: */
1382 while (*keyring && *(keyring++) != ',');
1384 goto top; /* and check it against the key */
1387 /** Returns if a user can join a channel with a specific key.
1389 * @param sptr The client trying to join
1390 * @param chptr The channel to join
1391 * @param key The key to use
1393 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1394 * if the oper used the magic key, 0 if no error occured.
1396 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1398 int overrideJoin = 0;
1401 * Now a banned user CAN join if invited -- Nemesi
1402 * Now a user CAN escape channel limit if invited -- bfriendly
1403 * Now a user CAN escape anything if invited -- Isomer
1406 if (IsInvited(sptr, chptr))
1409 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1410 a HACK(4) notice will be sent if he would not have been supposed
1411 to join normally. */
1412 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1413 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1414 compall("OVERRIDE",key) == 0)
1415 overrideJoin = MAGIC_OPER_OVERRIDE;
1417 if (chptr->mode.mode & MODE_INVITEONLY)
1418 return overrideJoin + ERR_INVITEONLYCHAN;
1420 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1421 return overrideJoin + ERR_CHANNELISFULL;
1423 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1424 return overrideJoin + ERR_NEEDREGGEDNICK;
1426 if (is_banned(sptr, chptr, NULL))
1427 return overrideJoin + ERR_BANNEDFROMCHAN;
1430 * now using compall (above) to test against a whole key ring -Kev
1432 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1433 return overrideJoin + ERR_BADCHANNELKEY;
1436 return ERR_DONTCHEAT;
1441 /** Remove bells and commas from channel name
1443 * @param cn Channel name to clean, modified in place.
1445 void clean_channelname(char *cn)
1449 for (i = 0; cn[i]; i++) {
1450 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1454 if (IsChannelLower(cn[i])) {
1455 cn[i] = ToLower(cn[i]);
1461 if ((unsigned char)(cn[i]) == 0xd0)
1462 cn[i] = (char) 0xf0;
1468 /** Get a channel block, creating if necessary.
1469 * Get Channel block for chname (and allocate a new channel
1470 * block, if it didn't exists before).
1472 * @param cptr Client joining the channel.
1473 * @param chname The name of the channel to join.
1474 * @param flag set to CGT_CREATE to create the channel if it doesn't
1477 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1478 * wasn't specified or a pointer to the channel structure
1480 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1482 struct Channel *chptr;
1485 if (EmptyString(chname))
1488 len = strlen(chname);
1489 if (MyUser(cptr) && len > CHANNELLEN)
1492 *(chname + CHANNELLEN) = '\0';
1494 if ((chptr = FindChannel(chname)))
1496 if (flag == CGT_CREATE)
1498 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1500 ++UserStats.channels;
1501 memset(chptr, 0, sizeof(struct Channel));
1502 strcpy(chptr->chname, chname);
1503 if (GlobalChannelList)
1504 GlobalChannelList->prev = chptr;
1506 chptr->next = GlobalChannelList;
1507 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1508 GlobalChannelList = chptr;
1514 /** invite a user to a channel.
1516 * Adds an invite for a user to a channel. Limits the number of invites
1517 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1519 * @param cptr The client to be invited.
1520 * @param chptr The channel to be invited to.
1522 void add_invite(struct Client *cptr, struct Channel *chptr)
1524 struct SLink *inv, **tmp;
1526 del_invite(cptr, chptr);
1528 * Delete last link in chain if the list is max length
1530 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1531 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1532 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1534 * Add client to channel invite list
1537 inv->value.cptr = cptr;
1538 inv->next = chptr->invites;
1539 chptr->invites = inv;
1541 * Add channel to the end of the client invite list
1543 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1545 inv->value.chptr = chptr;
1548 (cli_user(cptr))->invites++;
1551 /** Delete an invite
1552 * Delete Invite block from channel invite list and client invite list
1554 * @param cptr Client pointer
1555 * @param chptr Channel pointer
1557 void del_invite(struct Client *cptr, struct Channel *chptr)
1559 struct SLink **inv, *tmp;
1561 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1562 if (tmp->value.cptr == cptr)
1567 (cli_user(cptr))->invites--;
1571 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1572 if (tmp->value.chptr == chptr)
1581 /** List a set of channels
1582 * Lists a series of channels that match a filter, skipping channels that
1583 * have been listed before.
1585 * @param cptr Client to send the list to.
1586 * @param nr Number of channels to send this update.
1588 void list_next_channels(struct Client *cptr, int nr)
1590 struct ListingArgs *args = cli_listing(cptr);
1591 struct Channel *chptr = args->chptr;
1592 chptr->mode.mode &= ~MODE_LISTED;
1593 while (is_listed(chptr) || --nr >= 0)
1595 for (; chptr; chptr = chptr->next)
1597 if (!cli_user(cptr))
1599 if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1600 SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1602 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1603 chptr->creationtime > args->min_time &&
1604 chptr->creationtime < args->max_time &&
1605 (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1606 chptr->topic_time > args->min_topic_time &&
1607 chptr->topic_time < args->max_topic_time)))
1609 if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1610 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1612 chptr = chptr->next;
1618 MyFree(cli_listing(cptr));
1619 cli_listing(cptr) = NULL;
1620 send_reply(cptr, RPL_LISTEND);
1626 (cli_listing(cptr))->chptr = chptr;
1627 chptr->mode.mode |= MODE_LISTED;
1633 /** @page zombie Explaination of Zombies
1641 * X --a--> A --b--> B --d--> D
1646 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1647 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1649 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1650 * Remove the user immediately when no users are left on the channel.
1651 * b) On server B : remove the user (who/lp) from the channel, send a
1652 * PART upstream (to A) and pass on the KICK.
1653 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1654 * channel, and pass on the KICK.
1655 * d) On server D : remove the user (who/lp) from the channel, and pass on
1659 * - Setting the ZOMBIE flag never hurts, we either remove the
1660 * client after that or we don't.
1661 * - The KICK message was already passed on, as should be in all cases.
1662 * - `who' is removed in all cases except case a) when users are left.
1663 * - A PART is only sent upstream in case b).
1669 * 1 --- 2 --- 3 --- 4 --- 5
1674 * We also need to turn 'who' into a zombie on servers 1 and 6,
1675 * because a KICK from 'who' (kicking someone else in that direction)
1676 * can arrive there afterwards - which should not be bounced itself.
1677 * Therefore case a) also applies for servers 1 and 6.
1682 /** Turn a user on a channel into a zombie
1683 * This function turns a user into a zombie (see \ref zombie)
1685 * @param member The structure representing this user on this channel.
1686 * @param who The client that is being kicked.
1687 * @param cptr The connection the kick came from.
1688 * @param sptr The client that is doing the kicking.
1689 * @param chptr The channel the user is being kicked from.
1691 void make_zombie(struct Membership* member, struct Client* who,
1692 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1694 assert(0 != member);
1699 /* Default for case a): */
1702 /* Case b) or c) ?: */
1703 if (MyUser(who)) /* server 4 */
1705 if (IsServer(cptr)) /* Case b) ? */
1706 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1707 remove_user_from_channel(who, chptr);
1710 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1712 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1713 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1714 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1716 remove_user_from_channel(who, chptr);
1721 /* Case a) (servers 1, 2, 3 and 6) */
1722 if (channel_all_zombies(chptr))
1723 remove_user_from_channel(who, chptr);
1725 /* XXX Can't actually call Debug here; if the channel is all zombies,
1726 * chptr will no longer exist when we get here.
1727 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1731 /** returns the number of zombies on a channel
1732 * @param chptr Channel to count zombies in.
1734 * @returns The number of zombies on the channel.
1736 int number_of_zombies(struct Channel *chptr)
1738 struct Membership* member;
1742 for (member = chptr->members; member; member = member->next_member) {
1743 if (IsZombie(member))
1749 /** Concatenate some strings together.
1750 * This helper function builds an argument string in strptr, consisting
1751 * of the original string, a space, and str1 and str2 concatenated (if,
1752 * of course, str2 is not NULL)
1754 * @param strptr The buffer to concatenate into
1755 * @param strptr_i modified offset to the position to modify
1756 * @param str1 The string to contatenate from.
1757 * @param str2 The second string to contatenate from.
1758 * @param c Charactor to seperate the string from str1 and str2.
1761 build_string(char *strptr, int *strptr_i, const char *str1,
1762 const char *str2, char c)
1765 strptr[(*strptr_i)++] = c;
1768 strptr[(*strptr_i)++] = *(str1++);
1772 strptr[(*strptr_i)++] = *(str2++);
1774 strptr[(*strptr_i)] = '\0';
1777 /** Flush out the modes
1778 * This is the workhorse of our ModeBuf suite; this actually generates the
1779 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1781 * @param mbuf The mode buffer to flush
1782 * @param all If true, flush all modes, otherwise leave partial modes in the
1788 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1790 /* we only need the flags that don't take args right now */
1791 static int flags[] = {
1792 /* MODE_CHANOP, 'o', */
1793 /* MODE_VOICE, 'v', */
1796 MODE_MODERATED, 'm',
1797 MODE_TOPICLIMIT, 't',
1798 MODE_INVITEONLY, 'i',
1799 MODE_NOPRIVMSGS, 'n',
1802 MODE_WASDELJOINS, 'd',
1803 /* MODE_KEY, 'k', */
1804 /* MODE_BAN, 'b', */
1806 /* MODE_APASS, 'A', */
1807 /* MODE_UPASS, 'U', */
1813 struct Client *app_source; /* where the MODE appears to come from */
1815 char addbuf[20]; /* accumulates +psmtin, etc. */
1817 char rembuf[20]; /* accumulates -psmtin, etc. */
1819 char *bufptr; /* we make use of indirection to simplify the code */
1822 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1824 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1826 char *strptr; /* more indirection to simplify the code */
1829 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1832 char limitbuf[20]; /* convert limits to strings */
1834 unsigned int limitdel = MODE_LIMIT;
1838 /* If the ModeBuf is empty, we have nothing to do */
1839 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1842 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1844 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1847 app_source = mbuf->mb_source;
1850 * Account for user we're bouncing; we have to get it in on the first
1851 * bounced MODE, or we could have problems
1853 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1854 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1856 /* Calculate the simple flags */
1857 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1858 if (*flag_p & mbuf->mb_add)
1859 addbuf[addbuf_i++] = flag_p[1];
1860 else if (*flag_p & mbuf->mb_rem)
1861 rembuf[rembuf_i++] = flag_p[1];
1864 /* Now go through the modes with arguments... */
1865 for (i = 0; i < mbuf->mb_count; i++) {
1866 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1868 bufptr_i = &addbuf_i;
1871 bufptr_i = &rembuf_i;
1874 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1875 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1877 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1878 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1880 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1881 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1883 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1884 tmp = strlen(MB_STRING(mbuf, i));
1886 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1887 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1890 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1902 bufptr[(*bufptr_i)++] = mode_char;
1903 totalbuflen -= tmp + 1;
1905 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1906 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1907 strlen(MB_STRING(mbuf, i)));
1909 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1910 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1912 bufptr[(*bufptr_i)++] = 'k';
1913 totalbuflen -= tmp + 1;
1915 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1916 /* if it's a limit, we also format the number */
1917 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1919 tmp = strlen(limitbuf);
1921 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1922 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1924 bufptr[(*bufptr_i)++] = 'l';
1925 totalbuflen -= tmp + 1;
1930 /* terminate the mode strings */
1931 addbuf[addbuf_i] = '\0';
1932 rembuf[rembuf_i] = '\0';
1934 /* If we're building a user visible MODE or HACK... */
1935 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1936 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1937 MODEBUF_DEST_LOG)) {
1938 /* Set up the parameter strings */
1944 for (i = 0; i < mbuf->mb_count; i++) {
1945 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1948 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1950 strptr_i = &addstr_i;
1953 strptr_i = &remstr_i;
1956 /* deal with clients... */
1957 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1958 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1960 /* deal with bans... */
1961 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1962 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1964 /* deal with keys... */
1965 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1966 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1967 "*" : MB_STRING(mbuf, i), 0, ' ');
1969 /* deal with invisible passwords */
1970 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1971 build_string(strptr, strptr_i, "*", 0, ' ');
1974 * deal with limit; note we cannot include the limit parameter if we're
1977 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1978 (MODE_ADD | MODE_LIMIT))
1979 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1982 /* send the messages off to their destination */
1983 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1984 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1986 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1987 mbuf->mb_source : app_source),
1988 mbuf->mb_channel->chname,
1989 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1990 addbuf, remstr, addstr,
1991 mbuf->mb_channel->creationtime);
1993 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1994 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1995 "%s%s%s%s%s%s [%Tu]",
1996 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1997 mbuf->mb_source : app_source),
1998 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1999 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
2000 mbuf->mb_channel->creationtime);
2002 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
2003 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
2005 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
2006 mbuf->mb_source : app_source),
2007 mbuf->mb_channel->chname,
2008 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2009 addbuf, remstr, addstr,
2010 mbuf->mb_channel->creationtime);
2012 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
2013 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
2014 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
2015 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
2016 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2018 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
2019 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
2020 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2021 rembuf_i ? "-" : "", rembuf,
2022 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2025 /* Now are we supposed to propagate to other servers? */
2026 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
2027 /* set up parameter string */
2034 * limit is supressed if we're removing it; we have to figure out which
2035 * direction is the direction for it to be removed, though...
2037 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
2039 for (i = 0; i < mbuf->mb_count; i++) {
2040 if (MB_TYPE(mbuf, i) & MODE_SAVE)
2043 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2045 strptr_i = &addstr_i;
2048 strptr_i = &remstr_i;
2051 /* deal with modes that take clients */
2052 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2053 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2055 /* deal with modes that take strings */
2056 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
2057 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2060 * deal with the limit. Logic here is complicated; if HACK2 is set,
2061 * we're bouncing the mode, so sense is reversed, and we have to
2062 * include the original limit if it looks like it's being removed
2064 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2065 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2068 /* we were told to deop the source */
2069 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2070 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2071 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2072 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2074 /* mark that we've done this, so we don't do it again */
2075 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2078 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2079 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2080 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2081 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2082 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2083 addbuf, remstr, addstr);
2084 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2086 * If HACK2 was set, we're bouncing; we send the MODE back to the
2087 * connection we got it from with the senses reversed and a TS of 0;
2090 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2091 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2092 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2093 mbuf->mb_channel->creationtime);
2096 * We're propagating a normal MODE command to the rest of the network;
2097 * we send the actual channel TS unless this is a HACK3 or a HACK4
2099 if (IsServer(mbuf->mb_source))
2100 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2101 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2102 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2103 addbuf, remstr, addstr,
2104 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2105 mbuf->mb_channel->creationtime);
2107 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2108 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2109 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2110 addbuf, remstr, addstr);
2114 /* We've drained the ModeBuf... */
2119 /* reinitialize the mode-with-arg slots */
2120 for (i = 0; i < MAXMODEPARAMS; i++) {
2121 /* If we saved any, pack them down */
2122 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2123 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2124 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2126 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2128 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2129 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2131 MB_TYPE(mbuf, i) = 0;
2132 MB_UINT(mbuf, i) = 0;
2135 /* If we're supposed to flush it all, do so--all hail tail recursion */
2136 if (all && mbuf->mb_count)
2137 return modebuf_flush_int(mbuf, 1);
2142 /** Initialise a modebuf
2143 * This routine just initializes a ModeBuf structure with the information
2144 * needed and the options given.
2146 * @param mbuf The mode buffer to initialise.
2147 * @param source The client that is performing the mode.
2149 * @param chan The channel that the mode is being performed upon.
2153 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2154 struct Client *connect, struct Channel *chan, unsigned int dest)
2159 assert(0 != source);
2163 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2167 mbuf->mb_source = source;
2168 mbuf->mb_connect = connect;
2169 mbuf->mb_channel = chan;
2170 mbuf->mb_dest = dest;
2173 /* clear each mode-with-parameter slot */
2174 for (i = 0; i < MAXMODEPARAMS; i++) {
2175 MB_TYPE(mbuf, i) = 0;
2176 MB_UINT(mbuf, i) = 0;
2180 /** Append a new mode to a modebuf
2181 * This routine simply adds modes to be added or deleted; do a binary OR
2182 * with either MODE_ADD or MODE_DEL
2184 * @param mbuf Mode buffer
2185 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2188 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2191 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2193 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2194 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2195 MODE_DELJOINS | MODE_WASDELJOINS);
2197 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2200 if (mode & MODE_ADD) {
2201 mbuf->mb_rem &= ~mode;
2202 mbuf->mb_add |= mode;
2204 mbuf->mb_add &= ~mode;
2205 mbuf->mb_rem |= mode;
2209 /** Append a mode that takes an int argument to the modebuf
2211 * This routine adds a mode to be added or deleted that takes a unsigned
2212 * int parameter; mode may *only* be the relevant mode flag ORed with one
2213 * of MODE_ADD or MODE_DEL
2215 * @param mbuf The mode buffer to append to.
2216 * @param mode The mode to append.
2217 * @param uint The argument to the mode.
2220 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2223 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2225 if (mode == (MODE_LIMIT | MODE_DEL)) {
2226 mbuf->mb_rem |= mode;
2229 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2230 MB_UINT(mbuf, mbuf->mb_count) = uint;
2232 /* when we've reached the maximal count, flush the buffer */
2233 if (++mbuf->mb_count >=
2234 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2235 modebuf_flush_int(mbuf, 0);
2238 /** append a string mode
2239 * This routine adds a mode to be added or deleted that takes a string
2240 * parameter; mode may *only* be the relevant mode flag ORed with one of
2241 * MODE_ADD or MODE_DEL
2243 * @param mbuf The mode buffer to append to.
2244 * @param mode The mode to append.
2245 * @param string The string parameter to append.
2246 * @param free If the string should be free'd later.
2249 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2253 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2255 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2256 MB_STRING(mbuf, mbuf->mb_count) = string;
2258 /* when we've reached the maximal count, flush the buffer */
2259 if (++mbuf->mb_count >=
2260 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2261 modebuf_flush_int(mbuf, 0);
2264 /** Append a mode on a client to a modebuf.
2265 * This routine adds a mode to be added or deleted that takes a client
2266 * parameter; mode may *only* be the relevant mode flag ORed with one of
2267 * MODE_ADD or MODE_DEL
2269 * @param mbuf The modebuf to append the mode to.
2270 * @param mode The mode to append.
2271 * @param client The client argument to append.
2274 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2275 struct Client *client)
2278 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2280 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2281 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2283 /* when we've reached the maximal count, flush the buffer */
2284 if (++mbuf->mb_count >=
2285 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2286 modebuf_flush_int(mbuf, 0);
2289 /** The exported binding for modebuf_flush()
2291 * @param mbuf The mode buffer to flush.
2293 * @see modebuf_flush_int()
2296 modebuf_flush(struct ModeBuf *mbuf)
2298 struct Membership *memb;
2300 /* Check if MODE_WASDELJOINS should be set */
2301 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2302 && (mbuf->mb_rem & MODE_DELJOINS)) {
2303 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2304 if (IsDelayedJoin(memb)) {
2305 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2306 mbuf->mb_add |= MODE_WASDELJOINS;
2307 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2313 return modebuf_flush_int(mbuf, 1);
2316 /* This extracts the simple modes contained in mbuf
2318 * @param mbuf The mode buffer to extract the modes from.
2319 * @param buf The string buffer to write the modes into.
2322 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2324 static int flags[] = {
2325 /* MODE_CHANOP, 'o', */
2326 /* MODE_VOICE, 'v', */
2329 MODE_MODERATED, 'm',
2330 MODE_TOPICLIMIT, 't',
2331 MODE_INVITEONLY, 'i',
2332 MODE_NOPRIVMSGS, 'n',
2336 /* MODE_BAN, 'b', */
2343 int i, bufpos = 0, len;
2345 char *key = 0, limitbuf[20];
2346 char *apass = 0, *upass = 0;
2355 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2356 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2357 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2359 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2360 key = MB_STRING(mbuf, i);
2361 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2362 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2363 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2364 upass = MB_STRING(mbuf, i);
2365 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2366 apass = MB_STRING(mbuf, i);
2373 buf[bufpos++] = '+'; /* start building buffer */
2375 for (flag_p = flags; flag_p[0]; flag_p += 2)
2377 buf[bufpos++] = flag_p[1];
2379 for (i = 0, len = bufpos; i < len; i++) {
2381 build_string(buf, &bufpos, key, 0, ' ');
2382 else if (buf[i] == 'l')
2383 build_string(buf, &bufpos, limitbuf, 0, ' ');
2384 else if (buf[i] == 'U')
2385 build_string(buf, &bufpos, upass, 0, ' ');
2386 else if (buf[i] == 'A')
2387 build_string(buf, &bufpos, apass, 0, ' ');
2395 /** Simple function to invalidate bans
2397 * This function sets all bans as being valid.
2399 * @param chan The channel to operate on.
2402 mode_ban_invalidate(struct Channel *chan)
2404 struct Membership *member;
2406 for (member = chan->members; member; member = member->next_member)
2407 ClearBanValid(member);
2410 /** Simple function to drop invite structures
2412 * Remove all the invites on the channel.
2414 * @param chan Channel to remove invites from.
2418 mode_invite_clear(struct Channel *chan)
2420 while (chan->invites)
2421 del_invite(chan->invites->value.cptr, chan);
2424 /* What we've done for mode_parse so far... */
2425 #define DONE_LIMIT 0x01 /**< We've set the limit */
2426 #define DONE_KEY 0x02 /**< We've set the key */
2427 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2428 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2429 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2430 #define DONE_UPASS 0x20 /**< We've set user pass */
2431 #define DONE_APASS 0x40 /**< We've set admin pass */
2434 struct ModeBuf *mbuf;
2435 struct Client *cptr;
2436 struct Client *sptr;
2437 struct Channel *chptr;
2438 struct Membership *member;
2449 struct SLink banlist[MAXPARA];
2452 struct Client *client;
2453 } cli_change[MAXPARA];
2456 /** Helper function to send "Not oper" or "Not member" messages
2457 * Here's a helper function to deal with sending along "Not oper" or
2458 * "Not member" messages
2460 * @param state Parsing State object
2463 send_notoper(struct ParseState *state)
2465 if (state->done & DONE_NOTOPER)
2468 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2469 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2471 state->done |= DONE_NOTOPER;
2475 * Helper function to convert limits
2477 * @param state Parsing state object.
2481 mode_parse_limit(struct ParseState *state, int *flag_p)
2483 unsigned int t_limit;
2485 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2486 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2489 if (state->parc <= 0) { /* warn if not enough args */
2490 if (MyUser(state->sptr))
2491 need_more_params(state->sptr, "MODE +l");
2495 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2499 if ((int)t_limit<0) /* don't permit a negative limit */
2502 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2503 (!t_limit || t_limit == state->chptr->mode.limit))
2506 t_limit = state->chptr->mode.limit;
2508 /* If they're not an oper, they can't change modes */
2509 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2510 send_notoper(state);
2514 /* Can't remove a limit that's not there */
2515 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2518 /* Skip if this is a burst and a lower limit than this is set already */
2519 if ((state->flags & MODE_PARSE_BURST) &&
2520 (state->chptr->mode.mode & flag_p[0]) &&
2521 (state->chptr->mode.limit < t_limit))
2524 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2526 state->done |= DONE_LIMIT;
2531 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2533 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2534 if (state->dir & MODE_ADD) {
2535 state->chptr->mode.mode |= flag_p[0];
2536 state->chptr->mode.limit = t_limit;
2538 state->chptr->mode.mode &= ~flag_p[0];
2539 state->chptr->mode.limit = 0;
2545 * Helper function to convert keys
2548 mode_parse_key(struct ParseState *state, int *flag_p)
2553 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2556 if (state->parc <= 0) { /* warn if not enough args */
2557 if (MyUser(state->sptr))
2558 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2563 t_str = state->parv[state->args_used++]; /* grab arg */
2567 /* If they're not an oper, they can't change modes */
2568 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2569 send_notoper(state);
2573 if (state->done & DONE_KEY) /* allow key to be set only once */
2575 state->done |= DONE_KEY;
2579 /* clean up the key string */
2581 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2585 if (!*t_str) { /* warn if empty */
2586 if (MyUser(state->sptr))
2587 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2595 /* Skip if this is a burst, we have a key already and the new key is
2596 * after the old one alphabetically */
2597 if ((state->flags & MODE_PARSE_BURST) &&
2598 *(state->chptr->mode.key) &&
2599 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2602 /* can't add a key if one is set, nor can one remove the wrong key */
2603 if (!(state->flags & MODE_PARSE_FORCE))
2604 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2605 (state->dir == MODE_DEL &&
2606 ircd_strcmp(state->chptr->mode.key, t_str))) {
2607 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2611 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2612 !ircd_strcmp(state->chptr->mode.key, t_str))
2613 return; /* no key change */
2615 if (state->flags & MODE_PARSE_BOUNCE) {
2616 if (*state->chptr->mode.key) /* reset old key */
2617 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2618 state->chptr->mode.key, 0);
2619 else /* remove new bogus key */
2620 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2621 } else /* send new key */
2622 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2624 if (state->flags & MODE_PARSE_SET) {
2625 if (state->dir == MODE_ADD) /* set the new key */
2626 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2627 else /* remove the old key */
2628 *state->chptr->mode.key = '\0';
2633 * Helper function to convert user passes
2636 mode_parse_upass(struct ParseState *state, int *flag_p)
2641 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2644 if (state->parc <= 0) { /* warn if not enough args */
2645 if (MyUser(state->sptr))
2646 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2651 t_str = state->parv[state->args_used++]; /* grab arg */
2655 /* If they're not an oper, they can't change modes */
2656 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2657 send_notoper(state);
2661 /* If a non-service user is trying to force it, refuse. */
2662 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2663 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2664 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2668 /* If they are not the channel manager, they are not allowed to change it */
2669 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2670 if (*state->chptr->mode.apass) {
2671 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2672 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2674 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2675 "Re-create the channel. The channel must be *empty* for",
2676 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2677 "before it can be recreated.");
2682 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2684 state->done |= DONE_UPASS;
2686 t_len = PASSLEN + 1;
2688 /* clean up the upass string */
2690 while (*++s > ' ' && *s != ':' && --t_len)
2694 if (!*t_str) { /* warn if empty */
2695 if (MyUser(state->sptr))
2696 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2704 if (!(state->flags & MODE_PARSE_FORCE))
2705 /* can't add the upass while apass is not set */
2706 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2707 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2710 /* can't add a upass if one is set, nor can one remove the wrong upass */
2711 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2712 (state->dir == MODE_DEL &&
2713 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2714 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2718 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2719 !ircd_strcmp(state->chptr->mode.upass, t_str))
2720 return; /* no upass change */
2722 if (state->flags & MODE_PARSE_BOUNCE) {
2723 if (*state->chptr->mode.upass) /* reset old upass */
2724 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2725 state->chptr->mode.upass, 0);
2726 else /* remove new bogus upass */
2727 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2728 } else /* send new upass */
2729 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2731 if (state->flags & MODE_PARSE_SET) {
2732 if (state->dir == MODE_ADD) /* set the new upass */
2733 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2734 else /* remove the old upass */
2735 *state->chptr->mode.upass = '\0';
2740 * Helper function to convert admin passes
2743 mode_parse_apass(struct ParseState *state, int *flag_p)
2748 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2751 if (state->parc <= 0) { /* warn if not enough args */
2752 if (MyUser(state->sptr))
2753 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2758 t_str = state->parv[state->args_used++]; /* grab arg */
2762 /* If they're not an oper, they can't change modes */
2763 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2764 send_notoper(state);
2768 /* If a non-service user is trying to force it, refuse. */
2769 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2770 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2771 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2775 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2776 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2777 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2781 /* If they are not the channel manager, they are not allowed to change it */
2782 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2783 if (*state->chptr->mode.apass) {
2784 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2785 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2787 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2788 "Re-create the channel. The channel must be *empty* for",
2789 "at least a whole minute", "before it can be recreated.");
2794 if (state->done & DONE_APASS) /* allow apass to be set only once */
2796 state->done |= DONE_APASS;
2798 t_len = PASSLEN + 1;
2800 /* clean up the apass string */
2802 while (*++s > ' ' && *s != ':' && --t_len)
2806 if (!*t_str) { /* warn if empty */
2807 if (MyUser(state->sptr))
2808 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2816 if (!(state->flags & MODE_PARSE_FORCE)) {
2817 /* can't remove the apass while upass is still set */
2818 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2819 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2822 /* can't add an apass if one is set, nor can one remove the wrong apass */
2823 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2824 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2825 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2830 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2831 !ircd_strcmp(state->chptr->mode.apass, t_str))
2832 return; /* no apass change */
2834 if (state->flags & MODE_PARSE_BOUNCE) {
2835 if (*state->chptr->mode.apass) /* reset old apass */
2836 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2837 state->chptr->mode.apass, 0);
2838 else /* remove new bogus apass */
2839 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2840 } else /* send new apass */
2841 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2843 if (state->flags & MODE_PARSE_SET) {
2844 if (state->dir == MODE_ADD) { /* set the new apass */
2845 /* Make it VERY clear to the user that this is a one-time password */
2846 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2847 if (MyUser(state->sptr)) {
2848 send_reply(state->sptr, RPL_APASSWARN,
2849 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2850 "Are you SURE you want to use this as Admin password? ",
2851 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2852 send_reply(state->sptr, RPL_APASSWARN,
2853 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2854 "\" to remove the password and then immediately set a new one. "
2855 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2856 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2857 "Now set the channel user password (+u).");
2859 } else { /* remove the old apass */
2860 *state->chptr->mode.apass = '\0';
2861 if (MyUser(state->sptr))
2862 send_reply(state->sptr, RPL_APASSWARN,
2863 "WARNING: You removed the channel Admin password MODE (+A). ",
2864 "If you would disconnect or leave the channel without setting a new password then you will ",
2865 "not be able to set it again and lose ownership of this channel! ",
2866 "SET A NEW PASSWORD NOW!", "");
2872 * Helper function to convert bans
2875 mode_parse_ban(struct ParseState *state, int *flag_p)
2878 struct SLink *ban, *newban = 0;
2880 if (state->parc <= 0) { /* Not enough args, send ban list */
2881 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2882 send_ban_list(state->sptr, state->chptr);
2883 state->done |= DONE_BANLIST;
2889 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2892 t_str = state->parv[state->args_used++]; /* grab arg */
2896 /* If they're not an oper, they can't change modes */
2897 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2898 send_notoper(state);
2902 if ((s = strchr(t_str, ' ')))
2905 if (!*t_str || *t_str == ':') { /* warn if empty */
2906 if (MyUser(state->sptr))
2907 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2912 t_str = collapse(pretty_mask(t_str));
2914 /* remember the ban for the moment... */
2915 if (state->dir == MODE_ADD) {
2916 newban = state->banlist + (state->numbans++);
2919 DupString(newban->value.ban.banstr, t_str);
2920 newban->value.ban.who = cli_name(state->sptr);
2921 newban->value.ban.when = TStime();
2923 newban->flags = CHFL_BAN | MODE_ADD;
2925 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2926 newban->flags |= CHFL_BAN_IPMASK;
2929 if (!state->chptr->banlist) {
2930 state->chptr->banlist = newban; /* add our ban with its flags */
2931 state->done |= DONE_BANCLEAN;
2935 /* Go through all bans */
2936 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2937 /* first, clean the ban flags up a bit */
2938 if (!(state->done & DONE_BANCLEAN))
2939 /* Note: We're overloading *lots* of bits here; be careful! */
2940 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2944 * MODE_ADD - Ban was added; if we're bouncing modes,
2945 * then we'll remove it below; otherwise,
2946 * we'll have to allocate a real ban
2948 * MODE_DEL - Ban was marked for deletion; if we're
2949 * bouncing modes, we'll have to re-add it,
2950 * otherwise, we'll have to remove it
2952 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2953 * with a ban already set; if we're
2954 * bouncing modes, we'll have to bounce
2955 * this one; otherwise, we'll just ignore
2956 * it when we process added bans
2959 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2960 ban->flags |= MODE_DEL; /* delete one ban */
2962 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2964 } else if (state->dir == MODE_ADD) {
2965 /* if the ban already exists, don't worry about it */
2966 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2967 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2968 MyFree(newban->value.ban.banstr); /* stopper a leak */
2969 state->numbans--; /* deallocate last ban */
2970 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2972 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2973 if (!(ban->flags & MODE_DEL))
2974 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2975 } else if (!mmatch(t_str, ban->value.ban.banstr))
2976 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2978 if (!ban->next && (newban->flags & MODE_ADD))
2980 ban->next = newban; /* add our ban with its flags */
2981 break; /* get out of loop */
2985 state->done |= DONE_BANCLEAN;
2989 * This is the bottom half of the ban processor
2992 mode_process_bans(struct ParseState *state)
2994 struct SLink *ban, *newban, *prevban, *nextban;
3000 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
3002 banlen = strlen(ban->value.ban.banstr);
3004 nextban = ban->next;
3006 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
3008 prevban->next = 0; /* Break the list; ban isn't a real ban */
3010 state->chptr->banlist = 0;
3015 MyFree(ban->value.ban.banstr);
3018 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
3019 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
3020 ban->value.ban.banstr,
3021 state->flags & MODE_PARSE_SET);
3023 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
3024 if (prevban) /* clip it out of the list... */
3025 prevban->next = ban->next;
3027 state->chptr->banlist = ban->next;
3032 MyFree(ban->value.ban.who);
3036 continue; /* next ban; keep prevban like it is */
3038 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
3039 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
3041 prevban->next = 0; /* Break the list; ban isn't a real ban */
3043 state->chptr->banlist = 0;
3045 /* If we're supposed to ignore it, do so. */
3046 if (ban->flags & CHFL_BAN_OVERLAPPED &&
3047 !(state->flags & MODE_PARSE_BOUNCE)) {
3051 MyFree(ban->value.ban.banstr);
3053 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
3054 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
3055 count > feature_int(FEAT_MAXBANS))) {
3056 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
3057 ban->value.ban.banstr);
3061 MyFree(ban->value.ban.banstr);
3063 /* add the ban to the buffer */
3064 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
3065 ban->value.ban.banstr,
3066 !(state->flags & MODE_PARSE_SET));
3068 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3069 newban = make_link();
3070 newban->value.ban.banstr = ban->value.ban.banstr;
3071 DupString(newban->value.ban.who, ban->value.ban.who);
3072 newban->value.ban.when = ban->value.ban.when;
3073 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
3075 newban->next = state->chptr->banlist; /* and link it in */
3076 state->chptr->banlist = newban;
3085 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3087 if (changed) /* if we changed the ban list, we must invalidate the bans */
3088 mode_ban_invalidate(state->chptr);
3092 * Helper function to process client changes
3095 mode_parse_client(struct ParseState *state, int *flag_p)
3098 struct Client *acptr;
3101 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3104 if (state->parc <= 0) /* return if not enough args */
3107 t_str = state->parv[state->args_used++]; /* grab arg */
3111 /* If they're not an oper, they can't change modes */
3112 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3113 send_notoper(state);
3117 if (MyUser(state->sptr)) /* find client we're manipulating */
3118 acptr = find_chasing(state->sptr, t_str, NULL);
3120 acptr = findNUser(t_str);
3123 return; /* find_chasing() already reported an error to the user */
3125 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3126 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3127 state->cli_change[i].flag & flag_p[0]))
3128 break; /* found a slot */
3130 /* Store what we're doing to them */
3131 state->cli_change[i].flag = state->dir | flag_p[0];
3132 state->cli_change[i].client = acptr;
3136 * Helper function to process the changed client list
3139 mode_process_clients(struct ParseState *state)
3142 struct Membership *member;
3144 for (i = 0; state->cli_change[i].flag; i++) {
3145 assert(0 != state->cli_change[i].client);
3147 /* look up member link */
3148 if (!(member = find_member_link(state->chptr,
3149 state->cli_change[i].client)) ||
3150 (MyUser(state->sptr) && IsZombie(member))) {
3151 if (MyUser(state->sptr))
3152 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3153 cli_name(state->cli_change[i].client),
3154 state->chptr->chname);
3158 if ((state->cli_change[i].flag & MODE_ADD &&
3159 (state->cli_change[i].flag & member->status)) ||
3160 (state->cli_change[i].flag & MODE_DEL &&
3161 !(state->cli_change[i].flag & member->status)))
3162 continue; /* no change made, don't do anything */
3164 /* see if the deop is allowed */
3165 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3166 (MODE_DEL | MODE_CHANOP)) {
3167 /* prevent +k users from being deopped */
3168 if (IsChannelService(state->cli_change[i].client)) {
3169 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3170 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3172 (IsServer(state->sptr) ? cli_name(state->sptr) :
3173 cli_name((cli_user(state->sptr))->server)));
3175 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3176 send_reply(state->sptr, ERR_ISCHANSERVICE,
3177 cli_name(state->cli_change[i].client),
3178 state->chptr->chname);
3183 /* check deop for local user */
3184 if (MyUser(state->sptr)) {
3186 /* don't allow local opers to be deopped on local channels */
3187 if (state->cli_change[i].client != state->sptr &&
3188 IsLocalChannel(state->chptr->chname) &&
3189 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3190 send_reply(state->sptr, ERR_ISOPERLCHAN,
3191 cli_name(state->cli_change[i].client),
3192 state->chptr->chname);
3196 if (feature_bool(FEAT_OPLEVELS)) {
3197 /* don't allow to deop members with an op level that is <= our own level */
3198 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3200 && OpLevel(member) <= OpLevel(state->member)) {
3201 int equal = (OpLevel(member) == OpLevel(state->member));
3202 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3203 cli_name(state->cli_change[i].client),
3204 state->chptr->chname,
3205 OpLevel(state->member), OpLevel(member),
3206 "deop", equal ? "the same" : "a higher");
3213 /* set op-level of member being opped */
3214 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3215 (MODE_ADD | MODE_CHANOP)) {
3216 /* If on a channel with upass set, someone with level x gives ops to someone else,
3217 then that person gets level x-1. On other channels, where upass is not set,
3218 the level stays the same. */
3219 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3220 /* Someone being opped by a server gets op-level 0 */
3221 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3222 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3225 /* actually effect the change */
3226 if (state->flags & MODE_PARSE_SET) {
3227 if (state->cli_change[i].flag & MODE_ADD) {
3228 if (IsDelayedJoin(member))
3229 RevealDelayedJoin(member);
3230 member->status |= (state->cli_change[i].flag &
3231 (MODE_CHANOP | MODE_VOICE));
3232 if (state->cli_change[i].flag & MODE_CHANOP)
3233 ClearDeopped(member);
3235 member->status &= ~(state->cli_change[i].flag &
3236 (MODE_CHANOP | MODE_VOICE));
3239 /* accumulate the change */
3240 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3241 state->cli_change[i].client);
3242 } /* for (i = 0; state->cli_change[i].flags; i++) */
3246 * Helper function to process the simple modes
3249 mode_parse_mode(struct ParseState *state, int *flag_p)
3251 /* If they're not an oper, they can't change modes */
3252 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3253 send_notoper(state);
3260 if (state->dir == MODE_ADD) {
3261 state->add |= flag_p[0];
3262 state->del &= ~flag_p[0];
3264 if (flag_p[0] & MODE_SECRET) {
3265 state->add &= ~MODE_PRIVATE;
3266 state->del |= MODE_PRIVATE;
3267 } else if (flag_p[0] & MODE_PRIVATE) {
3268 state->add &= ~MODE_SECRET;
3269 state->del |= MODE_SECRET;
3271 if (flag_p[0] & MODE_DELJOINS) {
3272 state->add &= ~MODE_WASDELJOINS;
3273 state->del |= MODE_WASDELJOINS;
3276 state->add &= ~flag_p[0];
3277 state->del |= flag_p[0];
3280 assert(0 == (state->add & state->del));
3281 assert((MODE_SECRET | MODE_PRIVATE) !=
3282 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3286 * This routine is intended to parse MODE or OPMODE commands and effect the
3287 * changes (or just build the bounce buffer). We pass the starting offset
3291 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3292 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3293 struct Membership* member)
3295 static int chan_flags[] = {
3300 MODE_MODERATED, 'm',
3301 MODE_TOPICLIMIT, 't',
3302 MODE_INVITEONLY, 'i',
3303 MODE_NOPRIVMSGS, 'n',
3317 unsigned int t_mode;
3319 struct ParseState state;
3330 state.chptr = chptr;
3331 state.member = member;
3334 state.flags = flags;
3335 state.dir = MODE_ADD;
3339 state.args_used = 0;
3340 state.max_args = MAXMODEPARAMS;
3343 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3344 state.banlist[i].next = 0;
3345 state.banlist[i].value.ban.banstr = 0;
3346 state.banlist[i].value.ban.who = 0;
3347 state.banlist[i].value.ban.when = 0;
3348 state.banlist[i].flags = 0;
3349 state.cli_change[i].flag = 0;
3350 state.cli_change[i].client = 0;
3353 modestr = state.parv[state.args_used++];
3357 for (; *modestr; modestr++) {
3358 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3359 if (flag_p[1] == *modestr)
3362 if (!flag_p[0]) { /* didn't find it? complain and continue */
3363 if (MyUser(state.sptr))
3364 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3369 case '+': /* switch direction to MODE_ADD */
3370 case '-': /* switch direction to MODE_DEL */
3371 state.dir = flag_p[0];
3374 case 'l': /* deal with limits */
3375 mode_parse_limit(&state, flag_p);
3378 case 'k': /* deal with keys */
3379 mode_parse_key(&state, flag_p);
3382 case 'A': /* deal with Admin passes */
3383 if (feature_bool(FEAT_OPLEVELS))
3384 mode_parse_apass(&state, flag_p);
3387 case 'U': /* deal with user passes */
3388 if (feature_bool(FEAT_OPLEVELS))
3389 mode_parse_upass(&state, flag_p);
3392 case 'b': /* deal with bans */
3393 mode_parse_ban(&state, flag_p);
3396 case 'o': /* deal with ops/voice */
3398 mode_parse_client(&state, flag_p);
3401 default: /* deal with other modes */
3402 mode_parse_mode(&state, flag_p);
3404 } /* switch (*modestr) */
3405 } /* for (; *modestr; modestr++) */
3407 if (state.flags & MODE_PARSE_BURST)
3408 break; /* don't interpret any more arguments */
3410 if (state.parc > 0) { /* process next argument in string */
3411 modestr = state.parv[state.args_used++];
3415 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3418 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3419 break; /* we're then going to bounce the mode! */
3421 recv_ts = atoi(modestr);
3423 if (recv_ts && recv_ts < state.chptr->creationtime)
3424 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3426 break; /* break out of while loop */
3427 } else if (state.flags & MODE_PARSE_STRICT ||
3428 (MyUser(state.sptr) && state.max_args <= 0)) {
3429 state.parc++; /* we didn't actually gobble the argument */
3431 break; /* break out of while loop */
3434 } /* while (*modestr) */
3437 * the rest of the function finishes building resultant MODEs; if the
3438 * origin isn't a member or an oper, skip it.
3440 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3441 return state.args_used; /* tell our parent how many args we gobbled */
3443 t_mode = state.chptr->mode.mode;
3445 if (state.del & t_mode) { /* delete any modes to be deleted... */
3446 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3448 t_mode &= ~state.del;
3450 if (state.add & ~t_mode) { /* add any modes to be added... */
3451 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3453 t_mode |= state.add;
3456 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3457 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3458 !(t_mode & MODE_INVITEONLY))
3459 mode_invite_clear(state.chptr);
3461 state.chptr->mode.mode = t_mode;
3464 if (state.flags & MODE_PARSE_WIPEOUT) {
3465 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3466 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3467 state.chptr->mode.limit);
3468 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3469 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3470 state.chptr->mode.key, 0);
3471 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3472 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3473 state.chptr->mode.upass, 0);
3474 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3475 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3476 state.chptr->mode.apass, 0);
3479 if (state.done & DONE_BANCLEAN) /* process bans */
3480 mode_process_bans(&state);
3482 /* process client changes */
3483 if (state.cli_change[0].flag)
3484 mode_process_clients(&state);
3486 return state.args_used; /* tell our parent how many args we gobbled */
3490 * Initialize a join buffer
3493 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3494 struct Client *connect, unsigned int type, char *comment,
3500 assert(0 != source);
3501 assert(0 != connect);
3503 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3504 jbuf->jb_connect = connect;
3505 jbuf->jb_type = type;
3506 jbuf->jb_comment = comment;
3507 jbuf->jb_create = create;
3509 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3510 type == JOINBUF_TYPE_PART ||
3511 type == JOINBUF_TYPE_PARTALL) ?
3512 STARTJOINLEN : STARTCREATELEN) +
3513 (comment ? strlen(comment) + 2 : 0));
3515 for (i = 0; i < MAXJOINARGS; i++)
3516 jbuf->jb_channels[i] = 0;
3520 * Add a channel to the join buffer
3523 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3531 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3532 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3537 is_local = IsLocalChannel(chan->chname);
3539 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3540 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3541 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3542 if (IsUserParting(member))
3544 SetUserParting(member);
3546 /* Send notification to channel */
3547 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3548 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3549 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3550 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3551 else if (MyUser(jbuf->jb_source))
3552 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3553 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3554 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3555 /* XXX: Shouldn't we send a PART here anyway? */
3556 /* to users on the channel? Why? From their POV, the user isn't on
3557 * the channel anymore anyway. We don't send to servers until below,
3558 * when we gang all the channel parts together. Note that this is
3559 * exactly the same logic, albeit somewhat more concise, as was in
3560 * the original m_part.c */
3562 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3563 is_local) /* got to remove user here */
3564 remove_user_from_channel(jbuf->jb_source, chan);
3566 /* Add user to channel */
3567 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3568 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3570 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3572 /* send notification to all servers */
3573 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3574 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3575 "%H %Tu", chan, chan->creationtime);
3577 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3578 /* Send the notification to the channel */
3579 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3581 /* send an op, too, if needed */
3582 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3583 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3584 chan, jbuf->jb_source);
3585 } else if (MyUser(jbuf->jb_source))
3586 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3589 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3590 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3591 return; /* don't send to remote */
3593 /* figure out if channel name will cause buffer to be overflowed */
3594 len = chan ? strlen(chan->chname) + 1 : 2;
3595 if (jbuf->jb_strlen + len > BUFSIZE)
3596 joinbuf_flush(jbuf);
3598 /* add channel to list of channels to send and update counts */
3599 jbuf->jb_channels[jbuf->jb_count++] = chan;
3600 jbuf->jb_strlen += len;
3602 /* if we've used up all slots, flush */
3603 if (jbuf->jb_count >= MAXJOINARGS)
3604 joinbuf_flush(jbuf);
3608 * Flush the channel list to remote servers
3611 joinbuf_flush(struct JoinBuf *jbuf)
3613 char chanlist[BUFSIZE];
3617 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3618 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3619 return 0; /* no joins to process */
3621 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3622 build_string(chanlist, &chanlist_i,
3623 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3624 i == 0 ? '\0' : ',');
3625 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3626 /* Remove user from channel */
3627 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3629 jbuf->jb_channels[i] = 0; /* mark slot empty */
3632 jbuf->jb_count = 0; /* reset base counters */
3633 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3634 STARTJOINLEN : STARTCREATELEN) +
3635 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3637 /* and send the appropriate command */
3638 switch (jbuf->jb_type) {
3639 case JOINBUF_TYPE_CREATE:
3640 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3641 "%s %Tu", chanlist, jbuf->jb_create);
3644 case JOINBUF_TYPE_PART:
3645 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3646 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3654 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3655 int IsInvited(struct Client* cptr, const void* chptr)
3659 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3660 if (lp->value.chptr == chptr)
3665 /* RevealDelayedJoin: sends a join for a hidden user */
3667 void RevealDelayedJoin(struct Membership *member) {
3668 ClearDelayedJoin(member);
3669 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3671 CheckDelayedJoins(member->channel);
3674 /* CheckDelayedJoins: checks and clear +d if necessary */
3676 void CheckDelayedJoins(struct Channel *chan) {
3677 struct Membership *memb2;
3679 if (chan->mode.mode & MODE_WASDELJOINS) {
3680 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3681 if (IsDelayedJoin(memb2))
3686 chan->mode.mode &= ~MODE_WASDELJOINS;
3687 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,