2 * IRC - Internet Relay Chat, ircd/channel.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Co Center
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * @brief Channel management and maintanance
28 #include "destruct_event.h"
31 #include "ircd_alloc.h"
32 #include "ircd_chattr.h"
33 #include "ircd_defs.h"
34 #include "ircd_features.h"
36 #include "ircd_reply.h"
37 #include "ircd_snprintf.h"
38 #include "ircd_string.h"
45 #include "querycmds.h"
61 /** Linked list containing the full list of all channels */
62 struct Channel* GlobalChannelList = 0;
64 /** Number of struct Membership*'s allocated */
65 static unsigned int membershipAllocCount;
66 /** Freelist for struct Membership*'s */
67 static struct Membership* membershipFreeList;
69 void del_invite(struct Client *, struct Channel *);
71 const char* const PartFmt1 = ":%s " MSG_PART " %s";
72 const char* const PartFmt2 = ":%s " MSG_PART " %s :%s";
73 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
74 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
77 static struct Ban* next_ban;
78 static struct Ban* prev_ban;
79 static struct Ban* removed_bans_list;
80 static struct Ban* free_bans;
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 /** Allocate a new Ban structure.
104 * @param[in] banstr Ban mask to use.
105 * @return Newly allocated ban.
108 make_ban(const char *banstr)
113 free_bans = free_bans->next;
115 else if (!(ban = MyMalloc(sizeof(*ban))))
117 memset(ban, 0, sizeof(*ban));
119 DupString(ban->banstr, banstr);
123 /** Deallocate a ban structure.
124 * @param[in] ban Ban to deallocate.
127 free_ban(struct Ban *ban)
131 ban->next = free_bans;
135 /** return the struct Membership* that represents a client on a channel
136 * This function finds a struct Membership* which holds the state about
137 * a client on a specific channel. The code is smart enough to iterate
138 * over the channels a user is in, or the users in a channel to find the
139 * user depending on which is likely to be more efficient.
141 * @param chptr pointer to the channel struct
142 * @param cptr pointer to the client struct
144 * @returns pointer to the struct Membership representing this client on
145 * this channel. Returns NULL if the client is not on the channel.
146 * Returns NULL if the client is actually a server.
147 * @see find_channel_member()
149 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
151 struct Membership *m;
155 /* Servers don't have member links */
156 if (IsServer(cptr)||IsMe(cptr))
159 /* +k users are typically on a LOT of channels. So we iterate over who
160 * is in the channel. X/W are +k and are in about 5800 channels each.
161 * however there are typically no more than 1000 people in a channel
164 if (IsChannelService(cptr)) {
167 assert(m->channel == chptr);
173 /* Users on the other hand aren't allowed on more than 15 channels. 50%
174 * of users that are on channels are on 2 or less, 95% are on 7 or less,
175 * and 99% are on 10 or less.
178 m = (cli_user(cptr))->channel;
180 assert(m->user == cptr);
181 if (m->channel == chptr)
189 /** Find the client structure for a nick name (user)
190 * Find the client structure for a nick name (user)
191 * using history mechanism if necessary. If the client is not found, an error
192 * message (NO SUCH NICK) is generated. If the client was found
193 * through the history, chasing will be 1 and otherwise 0.
195 * This function was used extensively in the P09 days, and since we now have
196 * numeric nicks is no longer quite as important.
198 * @param sptr Pointer to the client that has requested the search
199 * @param user a string represeting the client to be found
200 * @param chasing a variable set to 0 if the user was found directly,
202 * @returns a pointer the client, or NULL if the client wasn't found.
204 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
206 struct Client* who = FindClient(user);
213 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
214 send_reply(sptr, ERR_NOSUCHNICK, user);
222 /** build up a hostmask
223 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
224 * as the parameters. If NULL, they become "*".
225 * @param namebuf the buffer to build the hostmask into. Must be at least
226 * NICKLEN+USERLEN+HOSTLEN+3 charactors long.
227 * @param nick The nickname
228 * @param name The ident
229 * @param host the hostname
231 * @see make_nick_user_ip()
233 static char *make_nick_user_host(char *namebuf, const char *nick,
234 const char *name, const char *host)
236 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
237 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
241 /** Create a hostmask using an IP address
242 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
243 * IP-number as the parameters. If NULL, they become "*".
245 * @param ipbuf Buffer at least NICKLEN+USERLEN+SOCKIPLEN+4 to hold the final
247 * @param nick The nickname (or NULL for *)
248 * @param name The ident (or NULL for *)
249 * @param ip The IP address
251 * @see make_nick_user_host()
253 #define NUI_BUFSIZE (NICKLEN + USERLEN + SOCKIPLEN + 4)
254 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
255 const struct irc_in_addr *ip)
257 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
261 /** Decrement the count of users, and free if empty.
262 * Subtract one user from channel i (and free channel * block, if channel
265 * @param chptr The channel to subtract one from.
267 * @returns true (1) if channel still has members.
268 * false (0) if the channel is now empty.
270 int sub1_from_channel(struct Channel* chptr)
272 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
274 assert(0 != chptr->members);
282 * Also channels without Apass set need to be kept alive,
283 * otherwise Bad Guys(tm) would be able to takeover
284 * existing channels too easily, and then set an Apass!
285 * However, if a channel without Apass becomes empty
286 * then we try to be kind to them and remove possible
289 chptr->mode.mode &= ~MODE_INVITEONLY;
290 chptr->mode.limit = 0;
292 * We do NOT reset a possible key or bans because when
293 * the 'channel owners' can't get in because of a key
294 * or ban then apparently there was a fight/takeover
295 * on the channel and we want them to contact IRC opers
296 * who then will educate them on the use of Apass/upass.
299 if (feature_bool(FEAT_OPLEVELS)) {
300 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
301 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
303 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
305 destruct_channel(chptr);
310 /** Destroy an empty channel
311 * This function destroys an empty channel, removing it from hashtables,
312 * and removing any resources it may have consumed.
314 * @param chptr The channel to destroy
316 * @returns 0 (success)
318 * FIXME: Change to return void, this function never fails.
320 int destruct_channel(struct Channel* chptr)
322 struct Ban *ban, *next;
324 assert(0 == chptr->members);
327 * Now, find all invite links from channel structure
329 while (chptr->invites)
330 del_invite(chptr->invites->value.cptr, chptr);
332 for (ban = chptr->banlist; ban; ban = next)
338 chptr->prev->next = chptr->next;
340 GlobalChannelList = chptr->next;
342 chptr->next->prev = chptr->prev;
344 --UserStats.channels;
346 * make sure that channel actually got removed from hash table
348 assert(chptr->hnext == chptr);
353 /** add a ban to a channel
355 * `cptr' must be the client adding the ban.
357 * If `change' is true then add `banid' to channel `chptr'.
358 * Returns 0 if the ban was added.
359 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
360 * Return -1 otherwise.
362 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
363 * when `change' is false, otherwise they will be removed from the banlist.
364 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
365 * respectively will return these bans until NULL is returned.
367 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
368 * is reset (unless a non-zero value is returned, in which case the
369 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
372 * @param cptr Client adding the ban
373 * @param chptr Channel to add the ban to
374 * @param banid The actual ban.
375 * @param change True if adding a ban, false if old bans should just be flagged
376 * @param firsttime Reset the next_overlapped_ban() iteration.
378 * 0 if the ban was added
379 * -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT
382 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
383 int change, int firsttime)
388 int removed_bans = 0;
389 int len = strlen(banid);
394 assert(0 == prev_ban);
395 assert(0 == removed_bans_list);
399 for (banp = &chptr->banlist; *banp;)
401 len += strlen((*banp)->banstr);
403 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
405 if (!strcmp((*banp)->banstr, banid))
407 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
411 else if (!mmatch((*banp)->banstr, banid))
413 if (!mmatch(banid, (*banp)->banstr))
415 struct Ban *tmp = *banp;
421 len -= strlen(tmp->banstr);
424 /* These will be sent to the user later as -b */
425 tmp->next = removed_bans_list;
426 removed_bans_list = tmp;
429 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
431 tmp->flags |= CHFL_BAN_OVERLAPPED;
442 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
443 banp = &(*banp)->next;
446 if (MyUser(cptr) && !removed_bans &&
447 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
448 (cnt >= feature_int(FEAT_MAXBANS))))
450 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
456 struct Membership* member;
457 ban = make_ban(banid);
458 ban->next = chptr->banlist;
460 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
461 DupString(ban->who, cli_name(&me));
463 DupString(ban->who, cli_name(cptr));
464 assert(0 != ban->who);
466 ban->when = TStime();
467 ban->flags = CHFL_BAN; /* This bit is never used I think... */
468 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
469 ban->flags |= CHFL_BAN_IPMASK;
470 chptr->banlist = ban;
473 * Erase ban-valid-bit
475 for (member = chptr->members; member; member = member->next_member)
476 ClearBanValid(member); /* `ban' == channel member ! */
481 /** return the next ban that is removed
482 * @returns the next ban that is removed because of overlapping
484 struct Ban *next_removed_overlapped_ban(void)
491 if ((prev_ban = removed_bans_list))
492 removed_bans_list = removed_bans_list->next;
496 /** returns Membership * if a person is joined and not a zombie
498 * @param chptr Channel
499 * @returns pointer to the client's struct Membership * on the channel if that
500 * user is a full member of the channel, or NULL otherwise.
502 * @see find_member_link()
504 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
506 struct Membership* member;
509 member = find_member_link(chptr, cptr);
510 return (member && !IsZombie(member)) ? member : 0;
513 /** return true if banned else false.
515 * This function returns true if the user is banned on the said channel.
516 * This function will check the ban cache if applicable, otherwise will
517 * do the comparisons and cache the result.
519 * @param cptr The client to test
520 * @param chptr The channel
521 * @param member The Membership * of this client on this channel
522 * (may be NULL if the member is not on the channel).
524 static int is_banned(struct Client *cptr, struct Channel *chptr,
525 struct Membership* member)
528 char tmphost[HOSTLEN + 1];
529 char nu_host[NUH_BUFSIZE];
530 char nu_realhost[NUH_BUFSIZE];
531 char nu_ip[NUI_BUFSIZE];
539 if (member && IsBanValid(member))
540 return IsBanned(member);
542 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
543 (cli_user(cptr))->host);
546 if (HasHiddenHost(cptr))
548 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
549 (cli_user(cptr))->username,
550 cli_user(cptr)->realhost);
554 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
555 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
556 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
557 cli_user(cptr)->username,
562 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
563 if ((tmp->flags & CHFL_BAN_IPMASK)) {
565 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
566 (cli_user(cptr))->username, &cli_ip(cptr));
567 if (match(tmp->banstr, ip_s) == 0)
570 if (match(tmp->banstr, s) == 0)
572 else if (sr && match(tmp->banstr, sr) == 0)
588 return (tmp != NULL);
591 /** add a user to a channel.
592 * adds a user to a channel by adding another link to the channels member
595 * @param chptr The channel to add to.
596 * @param who The user to add.
597 * @param flags The flags the user gets initially.
598 * @param oplevel The oplevel the user starts with.
600 void add_user_to_channel(struct Channel* chptr, struct Client* who,
601 unsigned int flags, int oplevel)
608 struct Membership* member = membershipFreeList;
610 membershipFreeList = member->next_member;
612 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
613 ++membershipAllocCount;
618 member->channel = chptr;
619 member->status = flags;
620 member->oplevel = oplevel;
622 member->next_member = chptr->members;
623 if (member->next_member)
624 member->next_member->prev_member = member;
625 member->prev_member = 0;
626 chptr->members = member;
628 member->next_channel = (cli_user(who))->channel;
629 if (member->next_channel)
630 member->next_channel->prev_channel = member;
631 member->prev_channel = 0;
632 (cli_user(who))->channel = member;
634 if (chptr->destruct_event)
635 remove_destruct_event(chptr);
637 ++((cli_user(who))->joined);
641 /** Remove a person from a channel, given their Membership*
643 * @param member A member of a channel.
645 * @returns true if there are more people in the channel.
647 static int remove_member_from_channel(struct Membership* member)
649 struct Channel* chptr;
651 chptr = member->channel;
653 * unlink channel member list
655 if (member->next_member)
656 member->next_member->prev_member = member->prev_member;
657 if (member->prev_member)
658 member->prev_member->next_member = member->next_member;
660 member->channel->members = member->next_member;
663 * If this is the last delayed-join user, may have to clear WASDELJOINS.
665 if (IsDelayedJoin(member))
666 CheckDelayedJoins(chptr);
669 * unlink client channel list
671 if (member->next_channel)
672 member->next_channel->prev_channel = member->prev_channel;
673 if (member->prev_channel)
674 member->prev_channel->next_channel = member->next_channel;
676 (cli_user(member->user))->channel = member->next_channel;
678 --(cli_user(member->user))->joined;
680 member->next_member = membershipFreeList;
681 membershipFreeList = member;
683 return sub1_from_channel(chptr);
686 /** Check if all the remaining members on the channel are zombies
688 * @returns False if the channel has any non zombie members, True otherwise.
691 static int channel_all_zombies(struct Channel* chptr)
693 struct Membership* member;
695 for (member = chptr->members; member; member = member->next_member) {
696 if (!IsZombie(member))
703 /** Remove a user from a channel
704 * This is the generic entry point for removing a user from a channel, this
705 * function will remove the client from the channel, and destory the channel
706 * if there are no more normal users left.
708 * @param cptr The client
709 * @param chptr The channel
711 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
714 struct Membership* member;
717 if ((member = find_member_link(chptr, cptr))) {
718 if (remove_member_from_channel(member)) {
719 if (channel_all_zombies(chptr)) {
721 * XXX - this looks dangerous but isn't if we got the referential
722 * integrity right for channels
724 while (remove_member_from_channel(chptr->members))
731 /** Remove a user from all channels they are on.
733 * This function removes a user from all channels they are on.
735 * @param cptr The client to remove.
737 void remove_user_from_all_channels(struct Client* cptr)
739 struct Membership* chan;
741 assert(0 != cli_user(cptr));
743 while ((chan = (cli_user(cptr))->channel))
744 remove_user_from_channel(cptr, chan->channel);
747 /** Check if this user is a legitimate chanop
749 * @param cptr Client to check
750 * @param chptr Channel to check
752 * @returns True if the user is a chanop (And not a zombie), False otherwise.
755 int is_chan_op(struct Client *cptr, struct Channel *chptr)
757 struct Membership* member;
759 if ((member = find_member_link(chptr, cptr)))
760 return (!IsZombie(member) && IsChanOp(member));
765 /** Check if a user is a Zombie on a specific channel.
767 * @param cptr The client to check.
768 * @param chptr The channel to check.
770 * @returns True if the client (cptr) is a zombie on the channel (chptr),
775 int is_zombie(struct Client *cptr, struct Channel *chptr)
777 struct Membership* member;
781 if ((member = find_member_link(chptr, cptr)))
782 return IsZombie(member);
786 /** Returns if a user has voice on a channel.
788 * @param cptr The client
789 * @param chptr The channel
791 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
794 int has_voice(struct Client* cptr, struct Channel* chptr)
796 struct Membership* member;
799 if ((member = find_member_link(chptr, cptr)))
800 return (!IsZombie(member) && HasVoice(member));
805 /** Can this member send to a channel
807 * A user can speak on a channel iff:
809 * <li> They didn't use the Apass to gain ops.
810 * <li> They are op'd or voice'd.
811 * <li> You aren't banned.
812 * <li> The channel isn't +m
813 * <li> The channel isn't +n or you are on the channel.
816 * This function will optionally reveal a user on a delayed join channel if
817 * they are allowed to send to the channel.
819 * @param member The membership of the user
820 * @param reveal If true, the user will be "revealed" on a delayed
823 * @returns True if the client can speak on the channel.
825 int member_can_send_to_channel(struct Membership* member, int reveal)
829 /* Discourage using the Apass to get op. They should use the upass. */
830 if (IsChannelManager(member) && *member->channel->mode.upass)
833 if (IsVoicedOrOpped(member))
836 * If it's moderated, and you aren't a priviledged user, you can't
839 if (member->channel->mode.mode & MODE_MODERATED)
842 * If you're banned then you can't speak either.
843 * but because of the amount of CPU time that is_banned chews
844 * we only check it for our clients.
846 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
849 if (IsDelayedJoin(member) && reveal)
850 RevealDelayedJoin(member);
855 /** Check if a client can send to a channel.
857 * Has the added check over member_can_send_to_channel() of servers can
860 * @param cptr The client to check
861 * @param chptr The channel to check
862 * @param reveal If the user should be revealed (see
863 * member_can_send_to_channel())
865 * @returns true if the client is allowed to speak on the channel, false
868 * @see member_can_send_to_channel()
870 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
872 struct Membership *member;
875 * Servers can always speak on channels.
880 member = find_channel_member(cptr, chptr);
883 * You can't speak if you're off channel, and it is +n (no external messages)
887 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
888 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
891 return !is_banned(cptr, chptr, NULL);
893 return member_can_send_to_channel(member, reveal);
896 /** Returns the name of a channel that prevents the user from changing nick.
897 * if a member and not (opped or voiced) and (banned or moderated), return
898 * the name of the first channel banned on.
900 * @param cptr The client
902 * @returns the name of the first channel banned on, or NULL if the user
905 const char* find_no_nickchange_channel(struct Client* cptr)
908 struct Membership* member;
909 for (member = (cli_user(cptr))->channel; member;
910 member = member->next_channel) {
911 if (!IsVoicedOrOpped(member) &&
912 (is_banned(cptr, member->channel, member) ||
913 (member->channel->mode.mode & MODE_MODERATED)))
914 return member->channel->chname;
921 /** Fill mbuf/pbuf with modes from chptr
922 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
923 * with the parameters in pbuf as visible by cptr.
925 * This function will hide keys from non-op'd, non-server clients.
927 * @param cptr The client to generate the mode for.
928 * @param mbuf The buffer to write the modes into.
929 * @param pbuf The buffer to write the mode parameters into.
930 * @param buflen The length of the buffers.
931 * @param chptr The channel to get the modes from.
932 * @param member The membership of this client on this channel (or NULL
933 * if this client isn't on this channel)
936 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
937 struct Channel *chptr, struct Membership *member)
939 int previous_parameter = 0;
946 if (chptr->mode.mode & MODE_SECRET)
948 else if (chptr->mode.mode & MODE_PRIVATE)
950 if (chptr->mode.mode & MODE_MODERATED)
952 if (chptr->mode.mode & MODE_TOPICLIMIT)
954 if (chptr->mode.mode & MODE_INVITEONLY)
956 if (chptr->mode.mode & MODE_NOPRIVMSGS)
958 if (chptr->mode.mode & MODE_REGONLY)
960 if (chptr->mode.mode & MODE_DELJOINS)
962 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
964 if (chptr->mode.limit) {
966 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
967 previous_parameter = 1;
970 if (*chptr->mode.key) {
972 if (previous_parameter)
974 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
975 strcat(pbuf, chptr->mode.key);
978 previous_parameter = 1;
980 if (*chptr->mode.apass) {
982 if (previous_parameter)
984 if (IsServer(cptr)) {
985 strcat(pbuf, chptr->mode.apass);
988 previous_parameter = 1;
990 if (*chptr->mode.upass) {
992 if (previous_parameter)
994 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
995 strcat(pbuf, chptr->mode.upass);
1002 /** Compare two members oplevel
1004 * @param mp1 Pointer to a pointer to a membership
1005 * @param mp2 Pointer to a pointer to a membership
1007 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
1009 * Used for qsort(3).
1011 int compare_member_oplevel(const void *mp1, const void *mp2)
1013 struct Membership const* member1 = *(struct Membership const**)mp1;
1014 struct Membership const* member2 = *(struct Membership const**)mp2;
1015 if (member1->oplevel == member2->oplevel)
1017 return (member1->oplevel < member2->oplevel) ? -1 : 1;
1020 /* send "cptr" a full list of the modes for channel chptr.
1022 * Sends a BURST line to cptr, bursting all the modes for the channel.
1024 * @param cptr Client pointer
1025 * @param chptr Channel pointer
1027 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
1029 /* The order in which modes are generated is now mandatory */
1030 static unsigned int current_flags[4] =
1031 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
1037 struct Membership* member;
1039 char modebuf[MODEBUFLEN];
1040 char parabuf[MODEBUFLEN];
1042 int number_of_ops = 0;
1043 int opped_members_index = 0;
1044 struct Membership** opped_members = NULL;
1045 int last_oplevel = 0;
1046 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
1051 if (IsLocalChannel(chptr->chname))
1054 member = chptr->members;
1055 lp2 = chptr->banlist;
1057 *modebuf = *parabuf = '\0';
1058 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
1060 for (first = 1; full; first = 0) /* Loop for multiple messages */
1062 full = 0; /* Assume by default we get it
1063 all in one message */
1065 /* (Continued) prefix: "<Y> B <channel> <TS>" */
1066 /* is there any better way we can do this? */
1067 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
1068 chptr->creationtime);
1070 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
1073 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
1074 msgq_append(&me, mb, " %s", modebuf);
1077 msgq_append(&me, mb, " %s", parabuf);
1081 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
1083 * First find all opless members.
1084 * Run 2 times over all members, to group the members with
1085 * and without voice together.
1086 * Then run 2 times over all opped members (which are ordered
1087 * by op-level) to also group voice and non-voice together.
1089 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
1093 if (flag_cnt < 2 && IsChanOp(member))
1096 * The first loop (to find all non-voice/op), we count the ops.
1097 * The second loop (to find all voiced non-ops), store the ops
1098 * in a dynamic array.
1103 opped_members[opped_members_index++] = member;
1105 /* Only handle the members with the flags that we are interested in. */
1106 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
1108 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
1109 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
1111 full = 1; /* Make sure we continue after
1112 sending it so far */
1113 /* Ensure the new BURST line contains the current
1114 * ":mode", except when there is no mode yet. */
1115 new_mode = (flag_cnt > 0) ? 1 : 0;
1116 break; /* Do not add this member to this message */
1118 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
1119 first = 0; /* From now on, use commas to add new nicks */
1122 * Do we have a nick with a new mode ?
1123 * Or are we starting a new BURST line?
1125 if (new_mode || !feat_oplevels)
1128 * This means we are at the _first_ member that has only
1129 * voice, or the first member that has only ops, or the
1130 * first member that has voice and ops (so we get here
1131 * at most three times, plus once for every start of
1132 * a continued BURST line where only these modes is current.
1133 * In the two cases where the current mode includes ops,
1134 * we need to add the _absolute_ value of the oplevel to the mode.
1136 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1139 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1141 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1143 /* append the absolute value of the oplevel */
1145 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1150 msgq_append(&me, mb, tbuf);
1153 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
1156 * This can't be the first member of a (continued) BURST
1157 * message because then either flag_cnt == 0 or new_mode == 1
1158 * Now we need to append the incremental value of the oplevel.
1160 char tbuf[2 + MAXOPLEVELDIGITS];
1161 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1162 last_oplevel = member->oplevel;
1163 msgq_append(&me, mb, tbuf);
1166 /* Go to the next `member'. */
1168 member = member->next_member;
1170 member = opped_members[++opped_members_index];
1175 /* Point `member' at the start of the list again. */
1178 member = chptr->members;
1179 /* Now, after one loop, we know the number of ops and can
1180 * allocate the dynamic array with pointer to the ops. */
1181 opped_members = (struct Membership**)
1182 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1183 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1187 /* At the end of the second loop, sort the opped members with
1188 * increasing op-level, so that we will output them in the
1189 * correct order (and all op-level increments stay positive) */
1191 qsort(opped_members, number_of_ops,
1192 sizeof(struct Membership*), compare_member_oplevel);
1193 /* The third and fourth loop run only over the opped members. */
1194 member = opped_members[(opped_members_index = 0)];
1197 } /* loop over 0,+v,+o,+ov */
1201 /* Attach all bans, space seperated " :%ban ban ..." */
1202 for (first = 2; lp2; lp2 = lp2->next)
1204 len = strlen(lp2->banstr);
1205 if (msgq_bufleft(mb) < len + 1 + first)
1206 /* The +1 stands for the added ' '.
1207 * The +first stands for the added ":%".
1213 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1219 send_buffer(cptr, mb, 0); /* Send this message */
1221 } /* Continue when there was something
1222 that didn't fit (full==1) */
1224 MyFree(opped_members);
1225 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1226 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1227 chptr->creationtime, chptr->topic_time, chptr->topic);
1230 /** Canonify a mask.
1233 * @author Carlo Wood (Run),
1236 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1237 * When the user name or host name are too long (USERLEN and HOSTLEN
1238 * respectively) then they are cut off at the start with a '*'.
1240 * The following transformations are made:
1242 * 1) xxx -> nick!*@*
1243 * 2) xxx.xxx -> *!*\@host
1244 * 3) xxx\!yyy -> nick!user\@*
1245 * 4) xxx\@yyy -> *!user\@host
1246 * 5) xxx!yyy\@zzz -> nick!user\@host
1248 * @param mask The uncanonified mask.
1249 * @returns The updated mask in a static buffer.
1251 char *pretty_mask(char *mask)
1253 static char star[2] = { '*', 0 };
1254 static char retmask[NUH_BUFSIZE];
1255 char *last_dot = NULL;
1258 /* Case 1: default */
1263 /* Do a _single_ pass through the characters of the mask: */
1264 for (ptr = mask; *ptr; ++ptr)
1268 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1272 else if (*ptr == '@')
1274 /* Case 4: Found last '@' (without finding a '!' yet) */
1279 else if (*ptr == '.')
1281 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1291 /* Case 4 or 5: Found last '@' */
1297 if (user == star && last_dot)
1307 char *nick_end = (user != star) ? user - 1 : ptr;
1308 if (nick_end - nick > NICKLEN)
1314 char *user_end = (host != star) ? host - 1 : ptr;
1315 if (user_end - user > USERLEN)
1317 user = user_end - USERLEN;
1322 if (host != star && ptr - host > HOSTLEN)
1324 host = ptr - HOSTLEN;
1327 return make_nick_user_host(retmask, nick, user, host);
1330 /** send a banlist to a client for a channel
1332 * @param cptr Client to send the banlist to.
1333 * @param chptr Channel whose banlist to send.
1335 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1342 for (lp = chptr->banlist; lp; lp = lp->next)
1343 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
1346 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1349 /** Check a key against a keyring.
1350 * We are now treating the key part of /join channellist key as a key
1351 * ring; that is, we try one key against the actual channel key, and if that
1352 * doesn't work, we try the next one, and so on. -Kev -Texaco
1353 * Returns: 0 on match, 1 otherwise
1354 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1356 * @param key Key to check
1357 * @param keyring Comma seperated list of keys
1359 * @returns True if the key was found and matches, false otherwise.
1361 static int compall(char *key, char *keyring)
1366 p1 = key; /* point to the key... */
1367 while (*p1 && *p1 == *keyring)
1368 { /* step through the key and ring until they
1374 if (!*p1 && (!*keyring || *keyring == ','))
1375 /* ok, if we're at the end of the and also at the end of one of the keys
1376 in the keyring, we have a match */
1379 if (!*keyring) /* if we're at the end of the key ring, there
1380 weren't any matches, so we return 1 */
1383 /* Not at the end of the key ring, so step
1384 through to the next key in the ring: */
1385 while (*keyring && *(keyring++) != ',');
1387 goto top; /* and check it against the key */
1390 /** Returns if a user can join a channel with a specific key.
1392 * @param sptr The client trying to join
1393 * @param chptr The channel to join
1394 * @param key The key to use
1396 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1397 * if the oper used the magic key, 0 if no error occured.
1399 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1401 int overrideJoin = 0;
1404 * Now a banned user CAN join if invited -- Nemesi
1405 * Now a user CAN escape channel limit if invited -- bfriendly
1406 * Now a user CAN escape anything if invited -- Isomer
1409 if (IsInvited(sptr, chptr))
1412 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1413 a HACK(4) notice will be sent if he would not have been supposed
1414 to join normally. */
1415 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1416 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1417 compall("OVERRIDE",key) == 0)
1418 overrideJoin = MAGIC_OPER_OVERRIDE;
1420 if (chptr->mode.mode & MODE_INVITEONLY)
1421 return overrideJoin + ERR_INVITEONLYCHAN;
1423 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1424 return overrideJoin + ERR_CHANNELISFULL;
1426 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1427 return overrideJoin + ERR_NEEDREGGEDNICK;
1429 if (is_banned(sptr, chptr, NULL))
1430 return overrideJoin + ERR_BANNEDFROMCHAN;
1433 * now using compall (above) to test against a whole key ring -Kev
1435 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1436 return overrideJoin + ERR_BADCHANNELKEY;
1439 return ERR_DONTCHEAT;
1444 /** Remove bells and commas from channel name
1446 * @param cn Channel name to clean, modified in place.
1448 void clean_channelname(char *cn)
1452 for (i = 0; cn[i]; i++) {
1453 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1457 if (IsChannelLower(cn[i])) {
1458 cn[i] = ToLower(cn[i]);
1464 if ((unsigned char)(cn[i]) == 0xd0)
1465 cn[i] = (char) 0xf0;
1471 /** Get a channel block, creating if necessary.
1472 * Get Channel block for chname (and allocate a new channel
1473 * block, if it didn't exists before).
1475 * @param cptr Client joining the channel.
1476 * @param chname The name of the channel to join.
1477 * @param flag set to CGT_CREATE to create the channel if it doesn't
1480 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1481 * wasn't specified or a pointer to the channel structure
1483 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1485 struct Channel *chptr;
1488 if (EmptyString(chname))
1491 len = strlen(chname);
1492 if (MyUser(cptr) && len > CHANNELLEN)
1495 *(chname + CHANNELLEN) = '\0';
1497 if ((chptr = FindChannel(chname)))
1499 if (flag == CGT_CREATE)
1501 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1503 ++UserStats.channels;
1504 memset(chptr, 0, sizeof(struct Channel));
1505 strcpy(chptr->chname, chname);
1506 if (GlobalChannelList)
1507 GlobalChannelList->prev = chptr;
1509 chptr->next = GlobalChannelList;
1510 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1511 GlobalChannelList = chptr;
1517 /** invite a user to a channel.
1519 * Adds an invite for a user to a channel. Limits the number of invites
1520 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1522 * @param cptr The client to be invited.
1523 * @param chptr The channel to be invited to.
1525 void add_invite(struct Client *cptr, struct Channel *chptr)
1527 struct SLink *inv, **tmp;
1529 del_invite(cptr, chptr);
1531 * Delete last link in chain if the list is max length
1533 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1534 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1535 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1537 * Add client to channel invite list
1540 inv->value.cptr = cptr;
1541 inv->next = chptr->invites;
1542 chptr->invites = inv;
1544 * Add channel to the end of the client invite list
1546 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1548 inv->value.chptr = chptr;
1551 (cli_user(cptr))->invites++;
1554 /** Delete an invite
1555 * Delete Invite block from channel invite list and client invite list
1557 * @param cptr Client pointer
1558 * @param chptr Channel pointer
1560 void del_invite(struct Client *cptr, struct Channel *chptr)
1562 struct SLink **inv, *tmp;
1564 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1565 if (tmp->value.cptr == cptr)
1570 (cli_user(cptr))->invites--;
1574 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1575 if (tmp->value.chptr == chptr)
1584 /** @page zombie Explaination of Zombies
1592 * X --a--> A --b--> B --d--> D
1597 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1598 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1600 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1601 * Remove the user immediately when no users are left on the channel.
1602 * b) On server B : remove the user (who/lp) from the channel, send a
1603 * PART upstream (to A) and pass on the KICK.
1604 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1605 * channel, and pass on the KICK.
1606 * d) On server D : remove the user (who/lp) from the channel, and pass on
1610 * - Setting the ZOMBIE flag never hurts, we either remove the
1611 * client after that or we don't.
1612 * - The KICK message was already passed on, as should be in all cases.
1613 * - `who' is removed in all cases except case a) when users are left.
1614 * - A PART is only sent upstream in case b).
1620 * 1 --- 2 --- 3 --- 4 --- 5
1625 * We also need to turn 'who' into a zombie on servers 1 and 6,
1626 * because a KICK from 'who' (kicking someone else in that direction)
1627 * can arrive there afterwards - which should not be bounced itself.
1628 * Therefore case a) also applies for servers 1 and 6.
1633 /** Turn a user on a channel into a zombie
1634 * This function turns a user into a zombie (see \ref zombie)
1636 * @param member The structure representing this user on this channel.
1637 * @param who The client that is being kicked.
1638 * @param cptr The connection the kick came from.
1639 * @param sptr The client that is doing the kicking.
1640 * @param chptr The channel the user is being kicked from.
1642 void make_zombie(struct Membership* member, struct Client* who,
1643 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1645 assert(0 != member);
1650 /* Default for case a): */
1653 /* Case b) or c) ?: */
1654 if (MyUser(who)) /* server 4 */
1656 if (IsServer(cptr)) /* Case b) ? */
1657 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1658 remove_user_from_channel(who, chptr);
1661 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1663 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1664 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1665 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1667 remove_user_from_channel(who, chptr);
1672 /* Case a) (servers 1, 2, 3 and 6) */
1673 if (channel_all_zombies(chptr))
1674 remove_user_from_channel(who, chptr);
1676 /* XXX Can't actually call Debug here; if the channel is all zombies,
1677 * chptr will no longer exist when we get here.
1678 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1682 /** returns the number of zombies on a channel
1683 * @param chptr Channel to count zombies in.
1685 * @returns The number of zombies on the channel.
1687 int number_of_zombies(struct Channel *chptr)
1689 struct Membership* member;
1693 for (member = chptr->members; member; member = member->next_member) {
1694 if (IsZombie(member))
1700 /** Concatenate some strings together.
1701 * This helper function builds an argument string in strptr, consisting
1702 * of the original string, a space, and str1 and str2 concatenated (if,
1703 * of course, str2 is not NULL)
1705 * @param strptr The buffer to concatenate into
1706 * @param strptr_i modified offset to the position to modify
1707 * @param str1 The string to contatenate from.
1708 * @param str2 The second string to contatenate from.
1709 * @param c Charactor to seperate the string from str1 and str2.
1712 build_string(char *strptr, int *strptr_i, const char *str1,
1713 const char *str2, char c)
1716 strptr[(*strptr_i)++] = c;
1719 strptr[(*strptr_i)++] = *(str1++);
1723 strptr[(*strptr_i)++] = *(str2++);
1725 strptr[(*strptr_i)] = '\0';
1728 /** Flush out the modes
1729 * This is the workhorse of our ModeBuf suite; this actually generates the
1730 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1732 * @param mbuf The mode buffer to flush
1733 * @param all If true, flush all modes, otherwise leave partial modes in the
1739 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1741 /* we only need the flags that don't take args right now */
1742 static int flags[] = {
1743 /* MODE_CHANOP, 'o', */
1744 /* MODE_VOICE, 'v', */
1747 MODE_MODERATED, 'm',
1748 MODE_TOPICLIMIT, 't',
1749 MODE_INVITEONLY, 'i',
1750 MODE_NOPRIVMSGS, 'n',
1753 MODE_WASDELJOINS, 'd',
1754 /* MODE_KEY, 'k', */
1755 /* MODE_BAN, 'b', */
1757 /* MODE_APASS, 'A', */
1758 /* MODE_UPASS, 'U', */
1764 struct Client *app_source; /* where the MODE appears to come from */
1766 char addbuf[20]; /* accumulates +psmtin, etc. */
1768 char rembuf[20]; /* accumulates -psmtin, etc. */
1770 char *bufptr; /* we make use of indirection to simplify the code */
1773 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1775 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1777 char *strptr; /* more indirection to simplify the code */
1780 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1783 char limitbuf[20]; /* convert limits to strings */
1785 unsigned int limitdel = MODE_LIMIT;
1789 /* If the ModeBuf is empty, we have nothing to do */
1790 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1793 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1795 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1798 app_source = mbuf->mb_source;
1801 * Account for user we're bouncing; we have to get it in on the first
1802 * bounced MODE, or we could have problems
1804 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1805 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1807 /* Calculate the simple flags */
1808 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1809 if (*flag_p & mbuf->mb_add)
1810 addbuf[addbuf_i++] = flag_p[1];
1811 else if (*flag_p & mbuf->mb_rem)
1812 rembuf[rembuf_i++] = flag_p[1];
1815 /* Now go through the modes with arguments... */
1816 for (i = 0; i < mbuf->mb_count; i++) {
1817 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1819 bufptr_i = &addbuf_i;
1822 bufptr_i = &rembuf_i;
1825 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1826 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1828 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1829 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1831 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1832 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1834 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1835 tmp = strlen(MB_STRING(mbuf, i));
1837 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1838 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1841 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1853 bufptr[(*bufptr_i)++] = mode_char;
1854 totalbuflen -= tmp + 1;
1856 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1857 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1858 strlen(MB_STRING(mbuf, i)));
1860 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1861 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1863 bufptr[(*bufptr_i)++] = 'k';
1864 totalbuflen -= tmp + 1;
1866 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1867 /* if it's a limit, we also format the number */
1868 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1870 tmp = strlen(limitbuf);
1872 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1873 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1875 bufptr[(*bufptr_i)++] = 'l';
1876 totalbuflen -= tmp + 1;
1881 /* terminate the mode strings */
1882 addbuf[addbuf_i] = '\0';
1883 rembuf[rembuf_i] = '\0';
1885 /* If we're building a user visible MODE or HACK... */
1886 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1887 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1888 MODEBUF_DEST_LOG)) {
1889 /* Set up the parameter strings */
1895 for (i = 0; i < mbuf->mb_count; i++) {
1896 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1899 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1901 strptr_i = &addstr_i;
1904 strptr_i = &remstr_i;
1907 /* deal with clients... */
1908 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1909 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1911 /* deal with bans... */
1912 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1913 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1915 /* deal with keys... */
1916 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1917 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1918 "*" : MB_STRING(mbuf, i), 0, ' ');
1920 /* deal with invisible passwords */
1921 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1922 build_string(strptr, strptr_i, "*", 0, ' ');
1925 * deal with limit; note we cannot include the limit parameter if we're
1928 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1929 (MODE_ADD | MODE_LIMIT))
1930 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1933 /* send the messages off to their destination */
1934 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1935 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1937 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1938 mbuf->mb_source : app_source),
1939 mbuf->mb_channel->chname,
1940 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1941 addbuf, remstr, addstr,
1942 mbuf->mb_channel->creationtime);
1944 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1945 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1946 "%s%s%s%s%s%s [%Tu]",
1947 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1948 mbuf->mb_source : app_source),
1949 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1950 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1951 mbuf->mb_channel->creationtime);
1953 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1954 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1956 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1957 mbuf->mb_source : app_source),
1958 mbuf->mb_channel->chname,
1959 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1960 addbuf, remstr, addstr,
1961 mbuf->mb_channel->creationtime);
1963 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1964 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1965 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1966 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1967 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1969 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1970 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1971 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1972 rembuf_i ? "-" : "", rembuf,
1973 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1976 /* Now are we supposed to propagate to other servers? */
1977 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1978 /* set up parameter string */
1985 * limit is supressed if we're removing it; we have to figure out which
1986 * direction is the direction for it to be removed, though...
1988 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1990 for (i = 0; i < mbuf->mb_count; i++) {
1991 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1994 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1996 strptr_i = &addstr_i;
1999 strptr_i = &remstr_i;
2002 /* deal with modes that take clients */
2003 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2004 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2006 /* deal with modes that take strings */
2007 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
2008 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2011 * deal with the limit. Logic here is complicated; if HACK2 is set,
2012 * we're bouncing the mode, so sense is reversed, and we have to
2013 * include the original limit if it looks like it's being removed
2015 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2016 build_string(strptr, strptr_i, limitbuf, 0, ' ');
2019 /* we were told to deop the source */
2020 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2021 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2022 addbuf[addbuf_i] = '\0'; /* terminate the string... */
2023 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2025 /* mark that we've done this, so we don't do it again */
2026 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2029 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2030 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2031 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2032 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2033 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2034 addbuf, remstr, addstr);
2035 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2037 * If HACK2 was set, we're bouncing; we send the MODE back to the
2038 * connection we got it from with the senses reversed and a TS of 0;
2041 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2042 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2043 rembuf_i ? "+" : "", rembuf, addstr, remstr,
2044 mbuf->mb_channel->creationtime);
2047 * We're propagating a normal MODE command to the rest of the network;
2048 * we send the actual channel TS unless this is a HACK3 or a HACK4
2050 if (IsServer(mbuf->mb_source))
2051 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2052 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2053 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2054 addbuf, remstr, addstr,
2055 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2056 mbuf->mb_channel->creationtime);
2058 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2059 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2060 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2061 addbuf, remstr, addstr);
2065 /* We've drained the ModeBuf... */
2070 /* reinitialize the mode-with-arg slots */
2071 for (i = 0; i < MAXMODEPARAMS; i++) {
2072 /* If we saved any, pack them down */
2073 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2074 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2075 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2077 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2079 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2080 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2082 MB_TYPE(mbuf, i) = 0;
2083 MB_UINT(mbuf, i) = 0;
2086 /* If we're supposed to flush it all, do so--all hail tail recursion */
2087 if (all && mbuf->mb_count)
2088 return modebuf_flush_int(mbuf, 1);
2093 /** Initialise a modebuf
2094 * This routine just initializes a ModeBuf structure with the information
2095 * needed and the options given.
2097 * @param mbuf The mode buffer to initialise.
2098 * @param source The client that is performing the mode.
2100 * @param chan The channel that the mode is being performed upon.
2104 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2105 struct Client *connect, struct Channel *chan, unsigned int dest)
2110 assert(0 != source);
2114 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
2118 mbuf->mb_source = source;
2119 mbuf->mb_connect = connect;
2120 mbuf->mb_channel = chan;
2121 mbuf->mb_dest = dest;
2124 /* clear each mode-with-parameter slot */
2125 for (i = 0; i < MAXMODEPARAMS; i++) {
2126 MB_TYPE(mbuf, i) = 0;
2127 MB_UINT(mbuf, i) = 0;
2131 /** Append a new mode to a modebuf
2132 * This routine simply adds modes to be added or deleted; do a binary OR
2133 * with either MODE_ADD or MODE_DEL
2135 * @param mbuf Mode buffer
2136 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
2139 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2142 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2144 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
2145 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
2146 MODE_DELJOINS | MODE_WASDELJOINS);
2148 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
2151 if (mode & MODE_ADD) {
2152 mbuf->mb_rem &= ~mode;
2153 mbuf->mb_add |= mode;
2155 mbuf->mb_add &= ~mode;
2156 mbuf->mb_rem |= mode;
2160 /** Append a mode that takes an int argument to the modebuf
2162 * This routine adds a mode to be added or deleted that takes a unsigned
2163 * int parameter; mode may *only* be the relevant mode flag ORed with one
2164 * of MODE_ADD or MODE_DEL
2166 * @param mbuf The mode buffer to append to.
2167 * @param mode The mode to append.
2168 * @param uint The argument to the mode.
2171 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2174 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2176 if (mode == (MODE_LIMIT | MODE_DEL)) {
2177 mbuf->mb_rem |= mode;
2180 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2181 MB_UINT(mbuf, mbuf->mb_count) = uint;
2183 /* when we've reached the maximal count, flush the buffer */
2184 if (++mbuf->mb_count >=
2185 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2186 modebuf_flush_int(mbuf, 0);
2189 /** append a string mode
2190 * This routine adds a mode to be added or deleted that takes a string
2191 * parameter; mode may *only* be the relevant mode flag ORed with one of
2192 * MODE_ADD or MODE_DEL
2194 * @param mbuf The mode buffer to append to.
2195 * @param mode The mode to append.
2196 * @param string The string parameter to append.
2197 * @param free If the string should be free'd later.
2200 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2204 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2206 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2207 MB_STRING(mbuf, mbuf->mb_count) = string;
2209 /* when we've reached the maximal count, flush the buffer */
2210 if (++mbuf->mb_count >=
2211 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2212 modebuf_flush_int(mbuf, 0);
2215 /** Append a mode on a client to a modebuf.
2216 * This routine adds a mode to be added or deleted that takes a client
2217 * parameter; mode may *only* be the relevant mode flag ORed with one of
2218 * MODE_ADD or MODE_DEL
2220 * @param mbuf The modebuf to append the mode to.
2221 * @param mode The mode to append.
2222 * @param client The client argument to append.
2225 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2226 struct Client *client)
2229 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2231 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2232 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2234 /* when we've reached the maximal count, flush the buffer */
2235 if (++mbuf->mb_count >=
2236 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2237 modebuf_flush_int(mbuf, 0);
2240 /** The exported binding for modebuf_flush()
2242 * @param mbuf The mode buffer to flush.
2244 * @see modebuf_flush_int()
2247 modebuf_flush(struct ModeBuf *mbuf)
2249 struct Membership *memb;
2251 /* Check if MODE_WASDELJOINS should be set */
2252 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2253 && (mbuf->mb_rem & MODE_DELJOINS)) {
2254 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2255 if (IsDelayedJoin(memb)) {
2256 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2257 mbuf->mb_add |= MODE_WASDELJOINS;
2258 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2264 return modebuf_flush_int(mbuf, 1);
2267 /* This extracts the simple modes contained in mbuf
2269 * @param mbuf The mode buffer to extract the modes from.
2270 * @param buf The string buffer to write the modes into.
2273 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2275 static int flags[] = {
2276 /* MODE_CHANOP, 'o', */
2277 /* MODE_VOICE, 'v', */
2280 MODE_MODERATED, 'm',
2281 MODE_TOPICLIMIT, 't',
2282 MODE_INVITEONLY, 'i',
2283 MODE_NOPRIVMSGS, 'n',
2287 /* MODE_BAN, 'b', */
2294 int i, bufpos = 0, len;
2296 char *key = 0, limitbuf[20];
2297 char *apass = 0, *upass = 0;
2306 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2307 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2308 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2310 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2311 key = MB_STRING(mbuf, i);
2312 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2313 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2314 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2315 upass = MB_STRING(mbuf, i);
2316 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2317 apass = MB_STRING(mbuf, i);
2324 buf[bufpos++] = '+'; /* start building buffer */
2326 for (flag_p = flags; flag_p[0]; flag_p += 2)
2328 buf[bufpos++] = flag_p[1];
2330 for (i = 0, len = bufpos; i < len; i++) {
2332 build_string(buf, &bufpos, key, 0, ' ');
2333 else if (buf[i] == 'l')
2334 build_string(buf, &bufpos, limitbuf, 0, ' ');
2335 else if (buf[i] == 'U')
2336 build_string(buf, &bufpos, upass, 0, ' ');
2337 else if (buf[i] == 'A')
2338 build_string(buf, &bufpos, apass, 0, ' ');
2346 /** Simple function to invalidate bans
2348 * This function sets all bans as being valid.
2350 * @param chan The channel to operate on.
2353 mode_ban_invalidate(struct Channel *chan)
2355 struct Membership *member;
2357 for (member = chan->members; member; member = member->next_member)
2358 ClearBanValid(member);
2361 /** Simple function to drop invite structures
2363 * Remove all the invites on the channel.
2365 * @param chan Channel to remove invites from.
2369 mode_invite_clear(struct Channel *chan)
2371 while (chan->invites)
2372 del_invite(chan->invites->value.cptr, chan);
2375 /* What we've done for mode_parse so far... */
2376 #define DONE_LIMIT 0x01 /**< We've set the limit */
2377 #define DONE_KEY 0x02 /**< We've set the key */
2378 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2379 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2380 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2381 #define DONE_UPASS 0x20 /**< We've set user pass */
2382 #define DONE_APASS 0x40 /**< We've set admin pass */
2385 struct ModeBuf *mbuf;
2386 struct Client *cptr;
2387 struct Client *sptr;
2388 struct Channel *chptr;
2389 struct Membership *member;
2400 struct Ban banlist[MAXPARA];
2403 struct Client *client;
2404 } cli_change[MAXPARA];
2407 /** Helper function to send "Not oper" or "Not member" messages
2408 * Here's a helper function to deal with sending along "Not oper" or
2409 * "Not member" messages
2411 * @param state Parsing State object
2414 send_notoper(struct ParseState *state)
2416 if (state->done & DONE_NOTOPER)
2419 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2420 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2422 state->done |= DONE_NOTOPER;
2426 * Helper function to convert limits
2428 * @param state Parsing state object.
2432 mode_parse_limit(struct ParseState *state, int *flag_p)
2434 unsigned int t_limit;
2436 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2437 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2440 if (state->parc <= 0) { /* warn if not enough args */
2441 if (MyUser(state->sptr))
2442 need_more_params(state->sptr, "MODE +l");
2446 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2450 if ((int)t_limit<0) /* don't permit a negative limit */
2453 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2454 (!t_limit || t_limit == state->chptr->mode.limit))
2457 t_limit = state->chptr->mode.limit;
2459 /* If they're not an oper, they can't change modes */
2460 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2461 send_notoper(state);
2465 /* Can't remove a limit that's not there */
2466 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2469 /* Skip if this is a burst and a lower limit than this is set already */
2470 if ((state->flags & MODE_PARSE_BURST) &&
2471 (state->chptr->mode.mode & flag_p[0]) &&
2472 (state->chptr->mode.limit < t_limit))
2475 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2477 state->done |= DONE_LIMIT;
2482 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2484 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2485 if (state->dir & MODE_ADD) {
2486 state->chptr->mode.mode |= flag_p[0];
2487 state->chptr->mode.limit = t_limit;
2489 state->chptr->mode.mode &= ~flag_p[0];
2490 state->chptr->mode.limit = 0;
2496 * Helper function to convert keys
2499 mode_parse_key(struct ParseState *state, int *flag_p)
2504 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2507 if (state->parc <= 0) { /* warn if not enough args */
2508 if (MyUser(state->sptr))
2509 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2514 t_str = state->parv[state->args_used++]; /* grab arg */
2518 /* If they're not an oper, they can't change modes */
2519 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2520 send_notoper(state);
2524 if (state->done & DONE_KEY) /* allow key to be set only once */
2526 state->done |= DONE_KEY;
2530 /* clean up the key string */
2532 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2536 if (!*t_str) { /* warn if empty */
2537 if (MyUser(state->sptr))
2538 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2546 /* Skip if this is a burst, we have a key already and the new key is
2547 * after the old one alphabetically */
2548 if ((state->flags & MODE_PARSE_BURST) &&
2549 *(state->chptr->mode.key) &&
2550 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2553 /* can't add a key if one is set, nor can one remove the wrong key */
2554 if (!(state->flags & MODE_PARSE_FORCE))
2555 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2556 (state->dir == MODE_DEL &&
2557 ircd_strcmp(state->chptr->mode.key, t_str))) {
2558 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2562 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2563 !ircd_strcmp(state->chptr->mode.key, t_str))
2564 return; /* no key change */
2566 if (state->flags & MODE_PARSE_BOUNCE) {
2567 if (*state->chptr->mode.key) /* reset old key */
2568 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2569 state->chptr->mode.key, 0);
2570 else /* remove new bogus key */
2571 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2572 } else /* send new key */
2573 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2575 if (state->flags & MODE_PARSE_SET) {
2576 if (state->dir == MODE_ADD) /* set the new key */
2577 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2578 else /* remove the old key */
2579 *state->chptr->mode.key = '\0';
2584 * Helper function to convert user passes
2587 mode_parse_upass(struct ParseState *state, int *flag_p)
2592 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2595 if (state->parc <= 0) { /* warn if not enough args */
2596 if (MyUser(state->sptr))
2597 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2602 t_str = state->parv[state->args_used++]; /* grab arg */
2606 /* If they're not an oper, they can't change modes */
2607 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2608 send_notoper(state);
2612 /* If a non-service user is trying to force it, refuse. */
2613 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2614 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2615 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2619 /* If they are not the channel manager, they are not allowed to change it */
2620 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2621 if (*state->chptr->mode.apass) {
2622 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2623 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2625 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2626 "Re-create the channel. The channel must be *empty* for",
2627 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2628 "before it can be recreated.");
2633 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2635 state->done |= DONE_UPASS;
2637 t_len = PASSLEN + 1;
2639 /* clean up the upass string */
2641 while (*++s > ' ' && *s != ':' && --t_len)
2645 if (!*t_str) { /* warn if empty */
2646 if (MyUser(state->sptr))
2647 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2655 if (!(state->flags & MODE_PARSE_FORCE))
2656 /* can't add the upass while apass is not set */
2657 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2658 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2661 /* can't add a upass if one is set, nor can one remove the wrong upass */
2662 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2663 (state->dir == MODE_DEL &&
2664 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2665 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2669 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2670 !ircd_strcmp(state->chptr->mode.upass, t_str))
2671 return; /* no upass change */
2673 if (state->flags & MODE_PARSE_BOUNCE) {
2674 if (*state->chptr->mode.upass) /* reset old upass */
2675 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2676 state->chptr->mode.upass, 0);
2677 else /* remove new bogus upass */
2678 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2679 } else /* send new upass */
2680 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2682 if (state->flags & MODE_PARSE_SET) {
2683 if (state->dir == MODE_ADD) /* set the new upass */
2684 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2685 else /* remove the old upass */
2686 *state->chptr->mode.upass = '\0';
2691 * Helper function to convert admin passes
2694 mode_parse_apass(struct ParseState *state, int *flag_p)
2699 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2702 if (state->parc <= 0) { /* warn if not enough args */
2703 if (MyUser(state->sptr))
2704 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2709 t_str = state->parv[state->args_used++]; /* grab arg */
2713 /* If they're not an oper, they can't change modes */
2714 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2715 send_notoper(state);
2719 /* If a non-service user is trying to force it, refuse. */
2720 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2721 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2722 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2726 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2727 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2728 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2732 /* If they are not the channel manager, they are not allowed to change it */
2733 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2734 if (*state->chptr->mode.apass) {
2735 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2736 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2738 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2739 "Re-create the channel. The channel must be *empty* for",
2740 "at least a whole minute", "before it can be recreated.");
2745 if (state->done & DONE_APASS) /* allow apass to be set only once */
2747 state->done |= DONE_APASS;
2749 t_len = PASSLEN + 1;
2751 /* clean up the apass string */
2753 while (*++s > ' ' && *s != ':' && --t_len)
2757 if (!*t_str) { /* warn if empty */
2758 if (MyUser(state->sptr))
2759 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2767 if (!(state->flags & MODE_PARSE_FORCE)) {
2768 /* can't remove the apass while upass is still set */
2769 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2770 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2773 /* can't add an apass if one is set, nor can one remove the wrong apass */
2774 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2775 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2776 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2781 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2782 !ircd_strcmp(state->chptr->mode.apass, t_str))
2783 return; /* no apass change */
2785 if (state->flags & MODE_PARSE_BOUNCE) {
2786 if (*state->chptr->mode.apass) /* reset old apass */
2787 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2788 state->chptr->mode.apass, 0);
2789 else /* remove new bogus apass */
2790 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2791 } else /* send new apass */
2792 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2794 if (state->flags & MODE_PARSE_SET) {
2795 if (state->dir == MODE_ADD) { /* set the new apass */
2796 /* Make it VERY clear to the user that this is a one-time password */
2797 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2798 if (MyUser(state->sptr)) {
2799 send_reply(state->sptr, RPL_APASSWARN,
2800 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2801 "Are you SURE you want to use this as Admin password? ",
2802 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2803 send_reply(state->sptr, RPL_APASSWARN,
2804 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2805 "\" to remove the password and then immediately set a new one. "
2806 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2807 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2808 "Now set the channel user password (+u).");
2810 } else { /* remove the old apass */
2811 *state->chptr->mode.apass = '\0';
2812 if (MyUser(state->sptr))
2813 send_reply(state->sptr, RPL_APASSWARN,
2814 "WARNING: You removed the channel Admin password MODE (+A). ",
2815 "If you would disconnect or leave the channel without setting a new password then you will ",
2816 "not be able to set it again and lose ownership of this channel! ",
2817 "SET A NEW PASSWORD NOW!", "");
2823 * Helper function to convert bans
2826 mode_parse_ban(struct ParseState *state, int *flag_p)
2829 struct Ban *ban, *newban = 0;
2831 if (state->parc <= 0) { /* Not enough args, send ban list */
2832 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2833 send_ban_list(state->sptr, state->chptr);
2834 state->done |= DONE_BANLIST;
2840 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2843 t_str = state->parv[state->args_used++]; /* grab arg */
2847 /* If they're not an oper, they can't change modes */
2848 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2849 send_notoper(state);
2853 if ((s = strchr(t_str, ' ')))
2856 if (!*t_str || *t_str == ':') { /* warn if empty */
2857 if (MyUser(state->sptr))
2858 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2863 t_str = collapse(pretty_mask(t_str));
2865 /* remember the ban for the moment... */
2866 if (state->dir == MODE_ADD) {
2867 newban = state->banlist + (state->numbans++);
2870 DupString(newban->banstr, t_str);
2871 newban->who = cli_name(state->sptr);
2872 newban->when = TStime();
2874 newban->flags = CHFL_BAN | MODE_ADD;
2876 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2877 newban->flags |= CHFL_BAN_IPMASK;
2880 if (!state->chptr->banlist) {
2881 state->chptr->banlist = newban; /* add our ban with its flags */
2882 state->done |= DONE_BANCLEAN;
2886 /* Go through all bans */
2887 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2888 /* first, clean the ban flags up a bit */
2889 if (!(state->done & DONE_BANCLEAN))
2890 /* Note: We're overloading *lots* of bits here; be careful! */
2891 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2895 * MODE_ADD - Ban was added; if we're bouncing modes,
2896 * then we'll remove it below; otherwise,
2897 * we'll have to allocate a real ban
2899 * MODE_DEL - Ban was marked for deletion; if we're
2900 * bouncing modes, we'll have to re-add it,
2901 * otherwise, we'll have to remove it
2903 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2904 * with a ban already set; if we're
2905 * bouncing modes, we'll have to bounce
2906 * this one; otherwise, we'll just ignore
2907 * it when we process added bans
2910 if (state->dir == MODE_DEL && !ircd_strcmp(ban->banstr, t_str)) {
2911 ban->flags |= MODE_DEL; /* delete one ban */
2913 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2915 } else if (state->dir == MODE_ADD) {
2916 /* if the ban already exists, don't worry about it */
2917 if (!ircd_strcmp(ban->banstr, t_str)) {
2918 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2919 MyFree(newban->banstr); /* stopper a leak */
2920 state->numbans--; /* deallocate last ban */
2921 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2923 } else if (!mmatch(ban->banstr, t_str)) {
2924 if (!(ban->flags & MODE_DEL))
2925 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2926 } else if (!mmatch(t_str, ban->banstr))
2927 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2929 if (!ban->next && (newban->flags & MODE_ADD))
2931 ban->next = newban; /* add our ban with its flags */
2932 break; /* get out of loop */
2936 state->done |= DONE_BANCLEAN;
2940 * This is the bottom half of the ban processor
2943 mode_process_bans(struct ParseState *state)
2945 struct Ban *ban, *newban, *prevban, *nextban;
2951 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2953 banlen = strlen(ban->banstr);
2955 nextban = ban->next;
2957 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2959 prevban->next = 0; /* Break the list; ban isn't a real ban */
2961 state->chptr->banlist = 0;
2966 MyFree(ban->banstr);
2969 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2970 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2972 state->flags & MODE_PARSE_SET);
2974 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2975 if (prevban) /* clip it out of the list... */
2976 prevban->next = ban->next;
2978 state->chptr->banlist = ban->next;
2983 ban->banstr = NULL; /* do not free this string */
2987 continue; /* next ban; keep prevban like it is */
2989 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2990 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2992 prevban->next = 0; /* Break the list; ban isn't a real ban */
2994 state->chptr->banlist = 0;
2996 /* If we're supposed to ignore it, do so. */
2997 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2998 !(state->flags & MODE_PARSE_BOUNCE)) {
3001 MyFree(ban->banstr);
3003 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
3004 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
3005 count > feature_int(FEAT_MAXBANS))) {
3006 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
3010 MyFree(ban->banstr);
3012 /* add the ban to the buffer */
3013 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
3015 !(state->flags & MODE_PARSE_SET));
3017 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3018 newban = make_ban(ban->banstr);
3019 DupString(newban->who, ban->who);
3020 newban->when = ban->when;
3021 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
3023 newban->next = state->chptr->banlist; /* and link it in */
3024 state->chptr->banlist = newban;
3033 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3035 if (changed) /* if we changed the ban list, we must invalidate the bans */
3036 mode_ban_invalidate(state->chptr);
3040 * Helper function to process client changes
3043 mode_parse_client(struct ParseState *state, int *flag_p)
3046 struct Client *acptr;
3049 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3052 if (state->parc <= 0) /* return if not enough args */
3055 t_str = state->parv[state->args_used++]; /* grab arg */
3059 /* If they're not an oper, they can't change modes */
3060 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3061 send_notoper(state);
3065 if (MyUser(state->sptr)) /* find client we're manipulating */
3066 acptr = find_chasing(state->sptr, t_str, NULL);
3068 acptr = findNUser(t_str);
3071 return; /* find_chasing() already reported an error to the user */
3073 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3074 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3075 state->cli_change[i].flag & flag_p[0]))
3076 break; /* found a slot */
3078 /* Store what we're doing to them */
3079 state->cli_change[i].flag = state->dir | flag_p[0];
3080 state->cli_change[i].client = acptr;
3084 * Helper function to process the changed client list
3087 mode_process_clients(struct ParseState *state)
3090 struct Membership *member;
3092 for (i = 0; state->cli_change[i].flag; i++) {
3093 assert(0 != state->cli_change[i].client);
3095 /* look up member link */
3096 if (!(member = find_member_link(state->chptr,
3097 state->cli_change[i].client)) ||
3098 (MyUser(state->sptr) && IsZombie(member))) {
3099 if (MyUser(state->sptr))
3100 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3101 cli_name(state->cli_change[i].client),
3102 state->chptr->chname);
3106 if ((state->cli_change[i].flag & MODE_ADD &&
3107 (state->cli_change[i].flag & member->status)) ||
3108 (state->cli_change[i].flag & MODE_DEL &&
3109 !(state->cli_change[i].flag & member->status)))
3110 continue; /* no change made, don't do anything */
3112 /* see if the deop is allowed */
3113 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3114 (MODE_DEL | MODE_CHANOP)) {
3115 /* prevent +k users from being deopped */
3116 if (IsChannelService(state->cli_change[i].client)) {
3117 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3118 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3120 (IsServer(state->sptr) ? cli_name(state->sptr) :
3121 cli_name((cli_user(state->sptr))->server)));
3123 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3124 send_reply(state->sptr, ERR_ISCHANSERVICE,
3125 cli_name(state->cli_change[i].client),
3126 state->chptr->chname);
3131 /* check deop for local user */
3132 if (MyUser(state->sptr)) {
3134 /* don't allow local opers to be deopped on local channels */
3135 if (state->cli_change[i].client != state->sptr &&
3136 IsLocalChannel(state->chptr->chname) &&
3137 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3138 send_reply(state->sptr, ERR_ISOPERLCHAN,
3139 cli_name(state->cli_change[i].client),
3140 state->chptr->chname);
3144 if (feature_bool(FEAT_OPLEVELS)) {
3145 /* don't allow to deop members with an op level that is <= our own level */
3146 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3148 && OpLevel(member) <= OpLevel(state->member)) {
3149 int equal = (OpLevel(member) == OpLevel(state->member));
3150 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3151 cli_name(state->cli_change[i].client),
3152 state->chptr->chname,
3153 OpLevel(state->member), OpLevel(member),
3154 "deop", equal ? "the same" : "a higher");
3161 /* set op-level of member being opped */
3162 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3163 (MODE_ADD | MODE_CHANOP)) {
3164 /* If on a channel with upass set, someone with level x gives ops to someone else,
3165 then that person gets level x-1. On other channels, where upass is not set,
3166 the level stays the same. */
3167 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3168 /* Someone being opped by a server gets op-level 0 */
3169 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3170 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3173 /* actually effect the change */
3174 if (state->flags & MODE_PARSE_SET) {
3175 if (state->cli_change[i].flag & MODE_ADD) {
3176 if (IsDelayedJoin(member))
3177 RevealDelayedJoin(member);
3178 member->status |= (state->cli_change[i].flag &
3179 (MODE_CHANOP | MODE_VOICE));
3180 if (state->cli_change[i].flag & MODE_CHANOP)
3181 ClearDeopped(member);
3183 member->status &= ~(state->cli_change[i].flag &
3184 (MODE_CHANOP | MODE_VOICE));
3187 /* accumulate the change */
3188 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3189 state->cli_change[i].client);
3190 } /* for (i = 0; state->cli_change[i].flags; i++) */
3194 * Helper function to process the simple modes
3197 mode_parse_mode(struct ParseState *state, int *flag_p)
3199 /* If they're not an oper, they can't change modes */
3200 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3201 send_notoper(state);
3208 if (state->dir == MODE_ADD) {
3209 state->add |= flag_p[0];
3210 state->del &= ~flag_p[0];
3212 if (flag_p[0] & MODE_SECRET) {
3213 state->add &= ~MODE_PRIVATE;
3214 state->del |= MODE_PRIVATE;
3215 } else if (flag_p[0] & MODE_PRIVATE) {
3216 state->add &= ~MODE_SECRET;
3217 state->del |= MODE_SECRET;
3219 if (flag_p[0] & MODE_DELJOINS) {
3220 state->add &= ~MODE_WASDELJOINS;
3221 state->del |= MODE_WASDELJOINS;
3224 state->add &= ~flag_p[0];
3225 state->del |= flag_p[0];
3228 assert(0 == (state->add & state->del));
3229 assert((MODE_SECRET | MODE_PRIVATE) !=
3230 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3234 * This routine is intended to parse MODE or OPMODE commands and effect the
3235 * changes (or just build the bounce buffer). We pass the starting offset
3239 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3240 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3241 struct Membership* member)
3243 static int chan_flags[] = {
3248 MODE_MODERATED, 'm',
3249 MODE_TOPICLIMIT, 't',
3250 MODE_INVITEONLY, 'i',
3251 MODE_NOPRIVMSGS, 'n',
3265 unsigned int t_mode;
3267 struct ParseState state;
3278 state.chptr = chptr;
3279 state.member = member;
3282 state.flags = flags;
3283 state.dir = MODE_ADD;
3287 state.args_used = 0;
3288 state.max_args = MAXMODEPARAMS;
3291 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3292 state.banlist[i].next = 0;
3293 state.banlist[i].who = 0;
3294 state.banlist[i].when = 0;
3295 state.banlist[i].flags = 0;
3296 state.cli_change[i].flag = 0;
3297 state.cli_change[i].client = 0;
3300 modestr = state.parv[state.args_used++];
3304 for (; *modestr; modestr++) {
3305 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3306 if (flag_p[1] == *modestr)
3309 if (!flag_p[0]) { /* didn't find it? complain and continue */
3310 if (MyUser(state.sptr))
3311 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3316 case '+': /* switch direction to MODE_ADD */
3317 case '-': /* switch direction to MODE_DEL */
3318 state.dir = flag_p[0];
3321 case 'l': /* deal with limits */
3322 mode_parse_limit(&state, flag_p);
3325 case 'k': /* deal with keys */
3326 mode_parse_key(&state, flag_p);
3329 case 'A': /* deal with Admin passes */
3330 if (feature_bool(FEAT_OPLEVELS))
3331 mode_parse_apass(&state, flag_p);
3334 case 'U': /* deal with user passes */
3335 if (feature_bool(FEAT_OPLEVELS))
3336 mode_parse_upass(&state, flag_p);
3339 case 'b': /* deal with bans */
3340 mode_parse_ban(&state, flag_p);
3343 case 'o': /* deal with ops/voice */
3345 mode_parse_client(&state, flag_p);
3348 default: /* deal with other modes */
3349 mode_parse_mode(&state, flag_p);
3351 } /* switch (*modestr) */
3352 } /* for (; *modestr; modestr++) */
3354 if (state.flags & MODE_PARSE_BURST)
3355 break; /* don't interpret any more arguments */
3357 if (state.parc > 0) { /* process next argument in string */
3358 modestr = state.parv[state.args_used++];
3362 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3365 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3366 break; /* we're then going to bounce the mode! */
3368 recv_ts = atoi(modestr);
3370 if (recv_ts && recv_ts < state.chptr->creationtime)
3371 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3373 break; /* break out of while loop */
3374 } else if (state.flags & MODE_PARSE_STRICT ||
3375 (MyUser(state.sptr) && state.max_args <= 0)) {
3376 state.parc++; /* we didn't actually gobble the argument */
3378 break; /* break out of while loop */
3381 } /* while (*modestr) */
3384 * the rest of the function finishes building resultant MODEs; if the
3385 * origin isn't a member or an oper, skip it.
3387 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3388 return state.args_used; /* tell our parent how many args we gobbled */
3390 t_mode = state.chptr->mode.mode;
3392 if (state.del & t_mode) { /* delete any modes to be deleted... */
3393 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3395 t_mode &= ~state.del;
3397 if (state.add & ~t_mode) { /* add any modes to be added... */
3398 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3400 t_mode |= state.add;
3403 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3404 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3405 !(t_mode & MODE_INVITEONLY))
3406 mode_invite_clear(state.chptr);
3408 state.chptr->mode.mode = t_mode;
3411 if (state.flags & MODE_PARSE_WIPEOUT) {
3412 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3413 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3414 state.chptr->mode.limit);
3415 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3416 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3417 state.chptr->mode.key, 0);
3418 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3419 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3420 state.chptr->mode.upass, 0);
3421 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3422 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3423 state.chptr->mode.apass, 0);
3426 if (state.done & DONE_BANCLEAN) /* process bans */
3427 mode_process_bans(&state);
3429 /* process client changes */
3430 if (state.cli_change[0].flag)
3431 mode_process_clients(&state);
3433 return state.args_used; /* tell our parent how many args we gobbled */
3437 * Initialize a join buffer
3440 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3441 struct Client *connect, unsigned int type, char *comment,
3447 assert(0 != source);
3448 assert(0 != connect);
3450 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3451 jbuf->jb_connect = connect;
3452 jbuf->jb_type = type;
3453 jbuf->jb_comment = comment;
3454 jbuf->jb_create = create;
3456 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3457 type == JOINBUF_TYPE_PART ||
3458 type == JOINBUF_TYPE_PARTALL) ?
3459 STARTJOINLEN : STARTCREATELEN) +
3460 (comment ? strlen(comment) + 2 : 0));
3462 for (i = 0; i < MAXJOINARGS; i++)
3463 jbuf->jb_channels[i] = 0;
3467 * Add a channel to the join buffer
3470 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3478 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3479 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3484 is_local = IsLocalChannel(chan->chname);
3486 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3487 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3488 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3489 if (IsUserParting(member))
3491 SetUserParting(member);
3493 /* Send notification to channel */
3494 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3495 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3496 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3497 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3498 else if (MyUser(jbuf->jb_source))
3499 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3500 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3501 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3502 /* XXX: Shouldn't we send a PART here anyway? */
3503 /* to users on the channel? Why? From their POV, the user isn't on
3504 * the channel anymore anyway. We don't send to servers until below,
3505 * when we gang all the channel parts together. Note that this is
3506 * exactly the same logic, albeit somewhat more concise, as was in
3507 * the original m_part.c */
3509 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3510 is_local) /* got to remove user here */
3511 remove_user_from_channel(jbuf->jb_source, chan);
3513 /* Add user to channel */
3514 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3515 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3517 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3519 /* send notification to all servers */
3520 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3521 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3522 "%H %Tu", chan, chan->creationtime);
3524 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3525 /* Send the notification to the channel */
3526 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3528 /* send an op, too, if needed */
3529 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3530 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3531 chan, jbuf->jb_source);
3532 } else if (MyUser(jbuf->jb_source))
3533 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3536 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3537 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3538 return; /* don't send to remote */
3540 /* figure out if channel name will cause buffer to be overflowed */
3541 len = chan ? strlen(chan->chname) + 1 : 2;
3542 if (jbuf->jb_strlen + len > BUFSIZE)
3543 joinbuf_flush(jbuf);
3545 /* add channel to list of channels to send and update counts */
3546 jbuf->jb_channels[jbuf->jb_count++] = chan;
3547 jbuf->jb_strlen += len;
3549 /* if we've used up all slots, flush */
3550 if (jbuf->jb_count >= MAXJOINARGS)
3551 joinbuf_flush(jbuf);
3555 * Flush the channel list to remote servers
3558 joinbuf_flush(struct JoinBuf *jbuf)
3560 char chanlist[BUFSIZE];
3564 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3565 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3566 return 0; /* no joins to process */
3568 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3569 build_string(chanlist, &chanlist_i,
3570 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3571 i == 0 ? '\0' : ',');
3572 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3573 /* Remove user from channel */
3574 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3576 jbuf->jb_channels[i] = 0; /* mark slot empty */
3579 jbuf->jb_count = 0; /* reset base counters */
3580 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3581 STARTJOINLEN : STARTCREATELEN) +
3582 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3584 /* and send the appropriate command */
3585 switch (jbuf->jb_type) {
3586 case JOINBUF_TYPE_CREATE:
3587 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3588 "%s %Tu", chanlist, jbuf->jb_create);
3591 case JOINBUF_TYPE_PART:
3592 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3593 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3601 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3602 int IsInvited(struct Client* cptr, const void* chptr)
3606 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3607 if (lp->value.chptr == chptr)
3612 /* RevealDelayedJoin: sends a join for a hidden user */
3614 void RevealDelayedJoin(struct Membership *member) {
3615 ClearDelayedJoin(member);
3616 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3618 CheckDelayedJoins(member->channel);
3621 /* CheckDelayedJoins: checks and clear +d if necessary */
3623 void CheckDelayedJoins(struct Channel *chan) {
3624 struct Membership *memb2;
3626 if (chan->mode.mode & MODE_WASDELJOINS) {
3627 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3628 if (IsDelayedJoin(memb2))
3633 chan->mode.mode &= ~MODE_WASDELJOINS;
3634 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,