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 maintenance
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"
56 /* #include <assert.h> -- Now using assert in ircd_log.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;
68 /** Freelist for struct Ban*'s */
69 static struct Ban* free_bans;
70 /** Number of ban structures allocated. */
71 static size_t bans_alloc;
72 /** Number of ban structures in use. */
73 static size_t bans_inuse;
76 /** return the length (>=0) of a chain of links.
77 * @param lp pointer to the start of the linked list
78 * @return the number of items in the list
80 static int list_length(struct SLink *lp)
84 for (; lp; lp = lp->next)
90 /** Set the mask for a ban, checking for IP masks.
91 * @param[in,out] ban Ban structure to modify.
92 * @param[in] banstr Mask to ban.
95 set_ban_mask(struct Ban *ban, const char *banstr)
98 assert(banstr != NULL);
99 ircd_strncpy(ban->banstr, banstr, sizeof(ban->banstr) - 1);
100 sep = strrchr(banstr, '@');
102 ban->nu_len = sep - banstr;
103 if (ipmask_parse(sep + 1, &ban->address, &ban->addrbits))
104 ban->flags |= BAN_IPMASK;
108 /** Allocate a new Ban structure.
109 * @param[in] banstr Ban mask to use.
110 * @return Newly allocated ban.
113 make_ban(const char *banstr)
118 free_bans = free_bans->next;
120 else if (!(ban = MyMalloc(sizeof(*ban))))
125 memset(ban, 0, sizeof(*ban));
126 set_ban_mask(ban, banstr);
130 /** Deallocate a ban structure.
131 * @param[in] ban Ban to deallocate.
134 free_ban(struct Ban *ban)
136 ban->next = free_bans;
141 /** Report ban usage to \a cptr.
142 * @param[in] cptr Client requesting information.
144 void bans_send_meminfo(struct Client *cptr)
148 for (num_free = 0, ban = free_bans; ban; ban = ban->next)
150 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Bans: inuse %zu(%zu) free %zu alloc %zu",
151 bans_inuse, bans_inuse * sizeof(*ban), num_free, bans_alloc);
154 /** return the struct Membership* that represents a client on a channel
155 * This function finds a struct Membership* which holds the state about
156 * a client on a specific channel. The code is smart enough to iterate
157 * over the channels a user is in, or the users in a channel to find the
158 * user depending on which is likely to be more efficient.
160 * @param chptr pointer to the channel struct
161 * @param cptr pointer to the client struct
163 * @returns pointer to the struct Membership representing this client on
164 * this channel. Returns NULL if the client is not on the channel.
165 * Returns NULL if the client is actually a server.
166 * @see find_channel_member()
168 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
170 struct Membership *m;
174 /* Servers don't have member links */
175 if (IsServer(cptr)||IsMe(cptr))
178 /* +k users are typically on a LOT of channels. So we iterate over who
179 * is in the channel. X/W are +k and are in about 5800 channels each.
180 * however there are typically no more than 1000 people in a channel
183 if (IsChannelService(cptr)) {
186 assert(m->channel == chptr);
192 /* Users on the other hand aren't allowed on more than 15 channels. 50%
193 * of users that are on channels are on 2 or less, 95% are on 7 or less,
194 * and 99% are on 10 or less.
197 m = (cli_user(cptr))->channel;
199 assert(m->user == cptr);
200 if (m->channel == chptr)
208 /** Find the client structure for a nick name (user)
209 * Find the client structure for a nick name (user)
210 * using history mechanism if necessary. If the client is not found, an error
211 * message (NO SUCH NICK) is generated. If the client was found
212 * through the history, chasing will be 1 and otherwise 0.
214 * This function was used extensively in the P09 days, and since we now have
215 * numeric nicks is no longer quite as important.
217 * @param sptr Pointer to the client that has requested the search
218 * @param user a string representing the client to be found
219 * @param chasing a variable set to 0 if the user was found directly,
221 * @returns a pointer the client, or NULL if the client wasn't found.
223 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
225 struct Client* who = FindClient(user);
232 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
233 send_reply(sptr, ERR_NOSUCHNICK, user);
241 /** Decrement the count of users, and free if empty.
242 * Subtract one user from channel i (and free channel * block, if channel
245 * @param chptr The channel to subtract one from.
247 * @returns true (1) if channel still has members.
248 * false (0) if the channel is now empty.
250 int sub1_from_channel(struct Channel* chptr)
252 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
254 assert(0 != chptr->members);
262 * Also channels without Apass set need to be kept alive,
263 * otherwise Bad Guys(tm) would be able to takeover
264 * existing channels too easily, and then set an Apass!
265 * However, if a channel without Apass becomes empty
266 * then we try to be kind to them and remove possible
269 chptr->mode.mode &= ~MODE_INVITEONLY;
270 chptr->mode.limit = 0;
272 * We do NOT reset a possible key or bans because when
273 * the 'channel owners' can't get in because of a key
274 * or ban then apparently there was a fight/takeover
275 * on the channel and we want them to contact IRC opers
276 * who then will educate them on the use of Apass/Upass.
278 if (!chptr->mode.apass[0]) /* If no Apass, reset all modes. */
280 struct Ban *link, *next;
281 chptr->mode.mode = 0;
282 *chptr->mode.key = '\0';
283 while (chptr->invites)
284 del_invite(chptr->invites->value.cptr, chptr);
285 for (link = chptr->banlist; link; link = next) {
289 chptr->banlist = NULL;
291 #if 1 /* Temporary code */
292 /* Immediately destruct empty -A channels if ZANNELS is FALSE.
293 When OPLEVELS is true, ZANNELS should be TRUE too. Test for
294 that error. This is done to avoid the DESTRUCT message to
295 occur, which is necessary on a network with mixed versions
296 of 2.10.12.x, with x < 04 *and* 2.10.11 servers. Because
297 servers prior to 2.10.12.04 can cause a BURST message outside
298 the normal net.burst as a result of a DESTRUCT message, and
299 2.10.11 SQUIT servers when they do that. */
300 if (!(feature_bool(FEAT_ZANNELS) || feature_bool(FEAT_OPLEVELS)))
302 destruct_channel(chptr);
307 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
308 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
310 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
315 /** Destroy an empty channel
316 * This function destroys an empty channel, removing it from hashtables,
317 * and removing any resources it may have consumed.
319 * @param chptr The channel to destroy
321 * @returns 0 (success)
323 * FIXME: Change to return void, this function never fails.
325 int destruct_channel(struct Channel* chptr)
327 struct Ban *ban, *next;
329 assert(0 == chptr->members);
332 * Now, find all invite links from channel structure
334 while (chptr->invites)
335 del_invite(chptr->invites->value.cptr, chptr);
337 for (ban = chptr->banlist; ban; ban = next)
343 chptr->prev->next = chptr->next;
345 GlobalChannelList = chptr->next;
347 chptr->next->prev = chptr->prev;
349 --UserStats.channels;
351 * make sure that channel actually got removed from hash table
353 assert(chptr->hnext == chptr);
358 /** returns Membership * if a person is joined and not a zombie
360 * @param chptr Channel
361 * @returns pointer to the client's struct Membership * on the channel if that
362 * user is a full member of the channel, or NULL otherwise.
364 * @see find_member_link()
366 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
368 struct Membership* member;
371 member = find_member_link(chptr, cptr);
372 return (member && !IsZombie(member)) ? member : 0;
375 /** Searches for a ban from a ban list that matches a user.
376 * @param[in] cptr The client to test.
377 * @param[in] banlist The list of bans to test.
378 * @return Pointer to a matching ban, or NULL if none exit.
380 struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
382 char nu[NICKLEN + USERLEN + 2];
383 char tmphost[HOSTLEN + 1];
384 char iphost[SOCKIPLEN + 1];
389 /* Build nick!user and alternate host names. */
390 ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
391 cli_name(cptr), cli_user(cptr)->username);
392 ircd_ntoa_r(iphost, &cli_ip(cptr));
393 if (!IsAccount(cptr))
395 else if (HasHiddenHost(cptr))
396 sr = cli_user(cptr)->realhost;
399 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
400 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
404 /* Walk through ban list. */
405 for (found = NULL; banlist; banlist = banlist->next) {
407 /* If we have found a positive ban already, only consider exceptions. */
408 if (found && !(banlist->flags & BAN_EXCEPTION))
410 /* Compare nick!user portion of ban. */
411 banlist->banstr[banlist->nu_len] = '\0';
412 res = match(banlist->banstr, nu);
413 banlist->banstr[banlist->nu_len] = '@';
416 /* Compare host portion of ban. */
417 hostmask = banlist->banstr + banlist->nu_len + 1;
418 if (!((banlist->flags & BAN_IPMASK)
419 && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
420 && match(hostmask, cli_user(cptr)->host)
421 && !(sr && !match(hostmask, sr)))
423 /* If an exception matches, no ban can match. */
424 if (banlist->flags & BAN_EXCEPTION)
426 /* Otherwise, remember this ban but keep searching for an exception. */
433 * This function returns true if the user is banned on the said channel.
434 * This function will check the ban cache if applicable, otherwise will
435 * do the comparisons and cache the result.
437 * @param[in] member The Membership to test for banned-ness.
438 * @return Non-zero if the member is banned, zero if not.
440 static int is_banned(struct Membership* member)
442 if (IsBanValid(member))
443 return IsBanned(member);
446 if (find_ban(member->user, member->channel->banlist)) {
455 /** add a user to a channel.
456 * adds a user to a channel by adding another link to the channels member
459 * @param chptr The channel to add to.
460 * @param who The user to add.
461 * @param flags The flags the user gets initially.
462 * @param oplevel The oplevel the user starts with.
464 void add_user_to_channel(struct Channel* chptr, struct Client* who,
465 unsigned int flags, int oplevel)
472 struct Membership* member = membershipFreeList;
474 membershipFreeList = member->next_member;
476 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
477 ++membershipAllocCount;
482 member->channel = chptr;
483 member->status = flags;
484 SetOpLevel(member, oplevel);
486 member->next_member = chptr->members;
487 if (member->next_member)
488 member->next_member->prev_member = member;
489 member->prev_member = 0;
490 chptr->members = member;
492 member->next_channel = (cli_user(who))->channel;
493 if (member->next_channel)
494 member->next_channel->prev_channel = member;
495 member->prev_channel = 0;
496 (cli_user(who))->channel = member;
498 if (chptr->destruct_event)
499 remove_destruct_event(chptr);
501 ++((cli_user(who))->joined);
505 /** Remove a person from a channel, given their Membership*
507 * @param member A member of a channel.
509 * @returns true if there are more people in the channel.
511 static int remove_member_from_channel(struct Membership* member)
513 struct Channel* chptr;
515 chptr = member->channel;
517 * unlink channel member list
519 if (member->next_member)
520 member->next_member->prev_member = member->prev_member;
521 if (member->prev_member)
522 member->prev_member->next_member = member->next_member;
524 member->channel->members = member->next_member;
527 * If this is the last delayed-join user, may have to clear WASDELJOINS.
529 if (IsDelayedJoin(member))
530 CheckDelayedJoins(chptr);
533 * unlink client channel list
535 if (member->next_channel)
536 member->next_channel->prev_channel = member->prev_channel;
537 if (member->prev_channel)
538 member->prev_channel->next_channel = member->next_channel;
540 (cli_user(member->user))->channel = member->next_channel;
542 --(cli_user(member->user))->joined;
544 member->next_member = membershipFreeList;
545 membershipFreeList = member;
547 return sub1_from_channel(chptr);
550 /** Check if all the remaining members on the channel are zombies
552 * @returns False if the channel has any non zombie members, True otherwise.
555 static int channel_all_zombies(struct Channel* chptr)
557 struct Membership* member;
559 for (member = chptr->members; member; member = member->next_member) {
560 if (!IsZombie(member))
567 /** Remove a user from a channel
568 * This is the generic entry point for removing a user from a channel, this
569 * function will remove the client from the channel, and destroy the channel
570 * if there are no more normal users left.
572 * @param cptr The client
573 * @param chptr The channel
575 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
578 struct Membership* member;
581 if ((member = find_member_link(chptr, cptr))) {
582 if (remove_member_from_channel(member)) {
583 if (channel_all_zombies(chptr)) {
585 * XXX - this looks dangerous but isn't if we got the referential
586 * integrity right for channels
588 while (remove_member_from_channel(chptr->members))
595 /** Remove a user from all channels they are on.
597 * This function removes a user from all channels they are on.
599 * @param cptr The client to remove.
601 void remove_user_from_all_channels(struct Client* cptr)
603 struct Membership* chan;
605 assert(0 != cli_user(cptr));
607 while ((chan = (cli_user(cptr))->channel))
608 remove_user_from_channel(cptr, chan->channel);
611 /** Check if this user is a legitimate chanop
613 * @param cptr Client to check
614 * @param chptr Channel to check
616 * @returns True if the user is a chanop (And not a zombie), False otherwise.
619 int is_chan_op(struct Client *cptr, struct Channel *chptr)
621 struct Membership* member;
623 if ((member = find_member_link(chptr, cptr)))
624 return (!IsZombie(member) && IsChanOp(member));
629 /** Check if a user is a Zombie on a specific channel.
631 * @param cptr The client to check.
632 * @param chptr The channel to check.
634 * @returns True if the client (cptr) is a zombie on the channel (chptr),
639 int is_zombie(struct Client *cptr, struct Channel *chptr)
641 struct Membership* member;
645 if ((member = find_member_link(chptr, cptr)))
646 return IsZombie(member);
650 /** Returns if a user has voice on a channel.
652 * @param cptr The client
653 * @param chptr The channel
655 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
658 int has_voice(struct Client* cptr, struct Channel* chptr)
660 struct Membership* member;
663 if ((member = find_member_link(chptr, cptr)))
664 return (!IsZombie(member) && HasVoice(member));
669 /** Can this member send to a channel
671 * A user can speak on a channel iff:
673 * <li> They didn't use the Apass to gain ops.
674 * <li> They are op'd or voice'd.
675 * <li> You aren't banned.
676 * <li> The channel isn't +m
677 * <li> The channel isn't +n or you are on the channel.
680 * This function will optionally reveal a user on a delayed join channel if
681 * they are allowed to send to the channel.
683 * @param member The membership of the user
684 * @param reveal If true, the user will be "revealed" on a delayed
687 * @returns True if the client can speak on the channel.
689 int member_can_send_to_channel(struct Membership* member, int reveal)
693 /* Do not check for users on other servers: This should be a
694 * temporary desynch, or maybe they are on an older server, but
695 * we do not want to send ERR_CANNOTSENDTOCHAN more than once.
697 if (!MyUser(member->user))
699 if (IsDelayedJoin(member) && reveal)
700 RevealDelayedJoin(member);
704 /* Discourage using the Apass to get op. They should use the Upass. */
705 if (IsChannelManager(member) && member->channel->mode.apass[0])
708 /* If you have voice or ops, you can speak. */
709 if (IsVoicedOrOpped(member))
713 * If it's moderated, and you aren't a privileged user, you can't
716 if (member->channel->mode.mode & MODE_MODERATED)
719 /* If only logged in users may join and you're not one, you can't speak. */
720 if (member->channel->mode.mode & MODE_REGONLY && !IsAccount(member->user))
723 /* If you're banned then you can't speak either. */
724 if (is_banned(member))
727 if (IsDelayedJoin(member) && reveal)
728 RevealDelayedJoin(member);
733 /** Check if a client can send to a channel.
735 * Has the added check over member_can_send_to_channel() of servers can
738 * @param cptr The client to check
739 * @param chptr The channel to check
740 * @param reveal If the user should be revealed (see
741 * member_can_send_to_channel())
743 * @returns true if the client is allowed to speak on the channel, false
746 * @see member_can_send_to_channel()
748 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
750 struct Membership *member;
753 * Servers can always speak on channels.
758 member = find_channel_member(cptr, chptr);
761 * You can't speak if you're off channel, and it is +n (no external messages)
765 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
766 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
769 return !find_ban(cptr, chptr->banlist);
771 return member_can_send_to_channel(member, reveal);
774 /** Returns the name of a channel that prevents the user from changing nick.
775 * if a member and not (opped or voiced) and (banned or moderated), return
776 * the name of the first channel banned on.
778 * @param cptr The client
780 * @returns the name of the first channel banned on, or NULL if the user
783 const char* find_no_nickchange_channel(struct Client* cptr)
786 struct Membership* member;
787 for (member = (cli_user(cptr))->channel; member;
788 member = member->next_channel) {
789 if (IsVoicedOrOpped(member))
791 if ((member->channel->mode.mode & MODE_MODERATED)
792 || (member->channel->mode.mode & MODE_REGONLY && !IsAccount(cptr))
793 || is_banned(member))
794 return member->channel->chname;
801 /** Fill mbuf/pbuf with modes from chptr
802 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
803 * with the parameters in pbuf as visible by cptr.
805 * This function will hide keys from non-op'd, non-server clients.
807 * @param cptr The client to generate the mode for.
808 * @param mbuf The buffer to write the modes into.
809 * @param pbuf The buffer to write the mode parameters into.
810 * @param buflen The length of the buffers.
811 * @param chptr The channel to get the modes from.
812 * @param member The membership of this client on this channel (or NULL
813 * if this client isn't on this channel)
816 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
817 struct Channel *chptr, struct Membership *member)
819 int previous_parameter = 0;
826 if (chptr->mode.mode & MODE_SECRET)
828 else if (chptr->mode.mode & MODE_PRIVATE)
830 if (chptr->mode.mode & MODE_MODERATED)
832 if (chptr->mode.mode & MODE_TOPICLIMIT)
834 if (chptr->mode.mode & MODE_INVITEONLY)
836 if (chptr->mode.mode & MODE_NOPRIVMSGS)
838 if (chptr->mode.mode & MODE_REGONLY)
840 if (chptr->mode.mode & MODE_DELJOINS)
842 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
844 if (chptr->mode.limit) {
846 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
847 previous_parameter = 1;
850 if (*chptr->mode.key) {
852 if (previous_parameter)
854 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
855 strcat(pbuf, chptr->mode.key);
858 previous_parameter = 1;
860 if (*chptr->mode.apass) {
862 if (previous_parameter)
864 if (IsServer(cptr)) {
865 strcat(pbuf, chptr->mode.apass);
868 previous_parameter = 1;
870 if (*chptr->mode.upass) {
872 if (previous_parameter)
874 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
875 strcat(pbuf, chptr->mode.upass);
882 /** Compare two members oplevel
884 * @param mp1 Pointer to a pointer to a membership
885 * @param mp2 Pointer to a pointer to a membership
887 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
891 int compare_member_oplevel(const void *mp1, const void *mp2)
893 struct Membership const* member1 = *(struct Membership const**)mp1;
894 struct Membership const* member2 = *(struct Membership const**)mp2;
895 if (member1->oplevel == member2->oplevel)
897 return (member1->oplevel < member2->oplevel) ? -1 : 1;
900 /* send "cptr" a full list of the modes for channel chptr.
902 * Sends a BURST line to cptr, bursting all the modes for the channel.
904 * @param cptr Client pointer
905 * @param chptr Channel pointer
907 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
909 /* The order in which modes are generated is now mandatory */
910 static unsigned int current_flags[4] =
911 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
917 struct Membership* member;
919 char modebuf[MODEBUFLEN];
920 char parabuf[MODEBUFLEN];
922 int number_of_ops = 0;
923 int opped_members_index = 0;
924 struct Membership** opped_members = NULL;
925 int last_oplevel = 0;
926 int feat_oplevels = (chptr->mode.apass[0]) != '\0';
931 if (IsLocalChannel(chptr->chname))
934 member = chptr->members;
935 lp2 = chptr->banlist;
937 *modebuf = *parabuf = '\0';
938 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
940 for (first = 1; full; first = 0) /* Loop for multiple messages */
942 full = 0; /* Assume by default we get it
943 all in one message */
945 /* (Continued) prefix: "<Y> B <channel> <TS>" */
946 /* is there any better way we can do this? */
947 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
948 chptr->creationtime);
950 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
953 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
954 msgq_append(&me, mb, " %s", modebuf);
957 msgq_append(&me, mb, " %s", parabuf);
961 * Attach nicks, comma separated " nick[:modes],nick[:modes],..."
963 * First find all opless members.
964 * Run 2 times over all members, to group the members with
965 * and without voice together.
966 * Then run 2 times over all opped members (which are ordered
967 * by op-level) to also group voice and non-voice together.
969 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
973 if (flag_cnt < 2 && IsChanOp(member))
976 * The first loop (to find all non-voice/op), we count the ops.
977 * The second loop (to find all voiced non-ops), store the ops
978 * in a dynamic array.
983 opped_members[opped_members_index++] = member;
985 /* Only handle the members with the flags that we are interested in. */
986 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
988 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
989 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
991 full = 1; /* Make sure we continue after
993 /* Ensure the new BURST line contains the current
994 * ":mode", except when there is no mode yet. */
995 new_mode = (flag_cnt > 0) ? 1 : 0;
996 break; /* Do not add this member to this message */
998 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
999 first = 0; /* From now on, use commas to add new nicks */
1002 * Do we have a nick with a new mode ?
1003 * Or are we starting a new BURST line?
1008 * This means we are at the _first_ member that has only
1009 * voice, or the first member that has only ops, or the
1010 * first member that has voice and ops (so we get here
1011 * at most three times, plus once for every start of
1012 * a continued BURST line where only these modes is current.
1013 * In the two cases where the current mode includes ops,
1014 * we need to add the _absolute_ value of the oplevel to the mode.
1016 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
1019 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
1021 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
1023 /* append the absolute value of the oplevel */
1025 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
1030 msgq_append(&me, mb, tbuf);
1033 else if (feat_oplevels && flag_cnt > 1 && last_oplevel != member->oplevel)
1036 * This can't be the first member of a (continued) BURST
1037 * message because then either flag_cnt == 0 or new_mode == 1
1038 * Now we need to append the incremental value of the oplevel.
1040 char tbuf[2 + MAXOPLEVELDIGITS];
1041 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
1042 last_oplevel = member->oplevel;
1043 msgq_append(&me, mb, tbuf);
1046 /* Go to the next `member'. */
1048 member = member->next_member;
1050 member = opped_members[++opped_members_index];
1055 /* Point `member' at the start of the list again. */
1058 member = chptr->members;
1059 /* Now, after one loop, we know the number of ops and can
1060 * allocate the dynamic array with pointer to the ops. */
1061 opped_members = (struct Membership**)
1062 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1063 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1067 /* At the end of the second loop, sort the opped members with
1068 * increasing op-level, so that we will output them in the
1069 * correct order (and all op-level increments stay positive) */
1071 qsort(opped_members, number_of_ops,
1072 sizeof(struct Membership*), compare_member_oplevel);
1073 /* The third and fourth loop run only over the opped members. */
1074 member = opped_members[(opped_members_index = 0)];
1077 } /* loop over 0,+v,+o,+ov */
1081 /* Attach all bans, space separated " :%ban ban ..." */
1082 for (first = 2; lp2; lp2 = lp2->next)
1084 len = strlen(lp2->banstr);
1085 if (msgq_bufleft(mb) < len + 1 + first)
1086 /* The +1 stands for the added ' '.
1087 * The +first stands for the added ":%".
1093 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1099 send_buffer(cptr, mb, 0); /* Send this message */
1101 } /* Continue when there was something
1102 that didn't fit (full==1) */
1104 MyFree(opped_members);
1105 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1106 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1107 chptr->creationtime, chptr->topic_time, chptr->topic);
1110 /** Canonify a mask.
1113 * @author Carlo Wood (Run),
1116 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1117 * When the user name or host name are too long (USERLEN and HOSTLEN
1118 * respectively) then they are cut off at the start with a '*'.
1120 * The following transformations are made:
1122 * 1) xxx -> nick!*@*
1123 * 2) xxx.xxx -> *!*\@host
1124 * 3) xxx\!yyy -> nick!user\@*
1125 * 4) xxx\@yyy -> *!user\@host
1126 * 5) xxx!yyy\@zzz -> nick!user\@host
1128 * @param mask The uncanonified mask.
1129 * @returns The updated mask in a static buffer.
1131 char *pretty_mask(char *mask)
1133 static char star[2] = { '*', 0 };
1134 static char retmask[NICKLEN + USERLEN + HOSTLEN + 3];
1135 char *last_dot = NULL;
1138 /* Case 1: default */
1143 /* Do a _single_ pass through the characters of the mask: */
1144 for (ptr = mask; *ptr; ++ptr)
1148 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1152 else if (*ptr == '@')
1154 /* Case 4: Found last '@' (without finding a '!' yet) */
1159 else if (*ptr == '.' || *ptr == ':')
1161 /* Case 2: Found character specific to IP or hostname (without
1162 * finding a '!' or '@' yet) */
1172 /* Case 4 or 5: Found last '@' */
1178 if (user == star && last_dot)
1188 char *nick_end = (user != star) ? user - 1 : ptr;
1189 if (nick_end - nick > NICKLEN)
1195 char *user_end = (host != star) ? host - 1 : ptr;
1196 if (user_end - user > USERLEN)
1198 user = user_end - USERLEN;
1203 if (host != star && ptr - host > HOSTLEN)
1205 host = ptr - HOSTLEN;
1208 ircd_snprintf(0, retmask, sizeof(retmask), "%s!%s@%s", nick, user, host);
1212 /** send a banlist to a client for a channel
1214 * @param cptr Client to send the banlist to.
1215 * @param chptr Channel whose banlist to send.
1217 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1224 for (lp = chptr->banlist; lp; lp = lp->next)
1225 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
1228 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1231 /** Remove bells and commas from channel name
1233 * @param cn Channel name to clean, modified in place.
1235 void clean_channelname(char *cn)
1239 for (i = 0; cn[i]; i++) {
1240 if (i >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))
1241 || !IsChannelChar(cn[i])) {
1245 if (IsChannelLower(cn[i])) {
1246 cn[i] = ToLower(cn[i]);
1252 if ((unsigned char)(cn[i]) == 0xd0)
1253 cn[i] = (char) 0xf0;
1259 /** Get a channel block, creating if necessary.
1260 * Get Channel block for chname (and allocate a new channel
1261 * block, if it didn't exists before).
1263 * @param cptr Client joining the channel.
1264 * @param chname The name of the channel to join.
1265 * @param flag set to CGT_CREATE to create the channel if it doesn't
1268 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1269 * wasn't specified or a pointer to the channel structure
1271 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1273 struct Channel *chptr;
1276 if (EmptyString(chname))
1279 len = strlen(chname);
1280 if (MyUser(cptr) && len > CHANNELLEN)
1283 *(chname + CHANNELLEN) = '\0';
1285 if ((chptr = FindChannel(chname)))
1287 if (flag == CGT_CREATE)
1289 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1291 ++UserStats.channels;
1292 memset(chptr, 0, sizeof(struct Channel));
1293 strcpy(chptr->chname, chname);
1294 if (GlobalChannelList)
1295 GlobalChannelList->prev = chptr;
1297 chptr->next = GlobalChannelList;
1298 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1299 GlobalChannelList = chptr;
1305 /** invite a user to a channel.
1307 * Adds an invite for a user to a channel. Limits the number of invites
1308 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1310 * @param cptr The client to be invited.
1311 * @param chptr The channel to be invited to.
1313 void add_invite(struct Client *cptr, struct Channel *chptr)
1315 struct SLink *inv, **tmp;
1317 del_invite(cptr, chptr);
1319 * Delete last link in chain if the list is max length
1321 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1322 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1323 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1325 * Add client to channel invite list
1328 inv->value.cptr = cptr;
1329 inv->next = chptr->invites;
1330 chptr->invites = inv;
1332 * Add channel to the end of the client invite list
1334 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1336 inv->value.chptr = chptr;
1339 (cli_user(cptr))->invites++;
1342 /** Delete an invite
1343 * Delete Invite block from channel invite list and client invite list
1345 * @param cptr Client pointer
1346 * @param chptr Channel pointer
1348 void del_invite(struct Client *cptr, struct Channel *chptr)
1350 struct SLink **inv, *tmp;
1352 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1353 if (tmp->value.cptr == cptr)
1358 (cli_user(cptr))->invites--;
1362 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1363 if (tmp->value.chptr == chptr)
1372 /** @page zombie Explanation of Zombies
1376 * A channel member is turned into a zombie when he is kicked from a
1377 * channel but his server has not acknowledged the kick. Servers that
1378 * see the member as a zombie can accept actions he performed before
1379 * being kicked, without allowing chanop operations from outsiders or
1380 * desyncing the network.
1388 * X --a--> A --b--> B --d--> D
1393 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1394 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1396 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1397 * Remove the user immediately when no users are left on the channel.
1398 * b) On server B : remove the user (who/lp) from the channel, send a
1399 * PART upstream (to A) and pass on the KICK.
1400 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1401 * channel, and pass on the KICK.
1402 * d) On server D : remove the user (who/lp) from the channel, and pass on
1406 * - Setting the ZOMBIE flag never hurts, we either remove the
1407 * client after that or we don't.
1408 * - The KICK message was already passed on, as should be in all cases.
1409 * - `who' is removed in all cases except case a) when users are left.
1410 * - A PART is only sent upstream in case b).
1416 * 1 --- 2 --- 3 --- 4 --- 5
1421 * We also need to turn 'who' into a zombie on servers 1 and 6,
1422 * because a KICK from 'who' (kicking someone else in that direction)
1423 * can arrive there afterward - which should not be bounced itself.
1424 * Therefore case a) also applies for servers 1 and 6.
1429 /** Turn a user on a channel into a zombie
1430 * This function turns a user into a zombie (see \ref zombie)
1432 * @param member The structure representing this user on this channel.
1433 * @param who The client that is being kicked.
1434 * @param cptr The connection the kick came from.
1435 * @param sptr The client that is doing the kicking.
1436 * @param chptr The channel the user is being kicked from.
1438 void make_zombie(struct Membership* member, struct Client* who,
1439 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1441 assert(0 != member);
1446 /* Default for case a): */
1449 /* Case b) or c) ?: */
1450 if (MyUser(who)) /* server 4 */
1452 if (IsServer(cptr)) /* Case b) ? */
1453 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1454 remove_user_from_channel(who, chptr);
1457 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1459 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1460 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1461 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1463 remove_user_from_channel(who, chptr);
1468 /* Case a) (servers 1, 2, 3 and 6) */
1469 if (channel_all_zombies(chptr))
1470 remove_user_from_channel(who, chptr);
1472 /* XXX Can't actually call Debug here; if the channel is all zombies,
1473 * chptr will no longer exist when we get here.
1474 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1478 /** returns the number of zombies on a channel
1479 * @param chptr Channel to count zombies in.
1481 * @returns The number of zombies on the channel.
1483 int number_of_zombies(struct Channel *chptr)
1485 struct Membership* member;
1489 for (member = chptr->members; member; member = member->next_member) {
1490 if (IsZombie(member))
1496 /** Concatenate some strings together.
1497 * This helper function builds an argument string in strptr, consisting
1498 * of the original string, a space, and str1 and str2 concatenated (if,
1499 * of course, str2 is not NULL)
1501 * @param strptr The buffer to concatenate into
1502 * @param strptr_i modified offset to the position to modify
1503 * @param str1 The string to concatenate from.
1504 * @param str2 The second string to contatenate from.
1505 * @param c Charactor to separate the string from str1 and str2.
1508 build_string(char *strptr, int *strptr_i, const char *str1,
1509 const char *str2, char c)
1512 strptr[(*strptr_i)++] = c;
1515 strptr[(*strptr_i)++] = *(str1++);
1519 strptr[(*strptr_i)++] = *(str2++);
1521 strptr[(*strptr_i)] = '\0';
1524 /** Flush out the modes
1525 * This is the workhorse of our ModeBuf suite; this actually generates the
1526 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1528 * @param mbuf The mode buffer to flush
1529 * @param all If true, flush all modes, otherwise leave partial modes in the
1535 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1537 /* we only need the flags that don't take args right now */
1538 static int flags[] = {
1539 /* MODE_CHANOP, 'o', */
1540 /* MODE_VOICE, 'v', */
1543 MODE_MODERATED, 'm',
1544 MODE_TOPICLIMIT, 't',
1545 MODE_INVITEONLY, 'i',
1546 MODE_NOPRIVMSGS, 'n',
1549 /* MODE_KEY, 'k', */
1550 /* MODE_BAN, 'b', */
1552 /* MODE_APASS, 'A', */
1553 /* MODE_UPASS, 'U', */
1556 static int local_flags[] = {
1557 MODE_WASDELJOINS, 'd',
1563 struct Client *app_source; /* where the MODE appears to come from */
1565 char addbuf[20], addbuf_local[20]; /* accumulates +psmtin, etc. */
1566 int addbuf_i = 0, addbuf_local_i = 0;
1567 char rembuf[20], rembuf_local[20]; /* accumulates -psmtin, etc. */
1568 int rembuf_i = 0, rembuf_local_i = 0;
1569 char *bufptr; /* we make use of indirection to simplify the code */
1572 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1574 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1576 char *strptr; /* more indirection to simplify the code */
1579 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1582 char limitbuf[20]; /* convert limits to strings */
1584 unsigned int limitdel = MODE_LIMIT;
1588 /* If the ModeBuf is empty, we have nothing to do */
1589 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1592 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1594 if (feature_bool(FEAT_HIS_MODEWHO) &&
1595 (mbuf->mb_dest & MODEBUF_DEST_OPMODE ||
1596 IsServer(mbuf->mb_source) ||
1597 IsMe(mbuf->mb_source)))
1600 app_source = mbuf->mb_source;
1603 * Account for user we're bouncing; we have to get it in on the first
1604 * bounced MODE, or we could have problems
1606 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1607 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1609 /* Calculate the simple flags */
1610 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1611 if (*flag_p & mbuf->mb_add)
1612 addbuf[addbuf_i++] = flag_p[1];
1613 else if (*flag_p & mbuf->mb_rem)
1614 rembuf[rembuf_i++] = flag_p[1];
1617 /* Some flags may be for local display only. */
1618 for (flag_p = local_flags; flag_p[0]; flag_p += 2) {
1619 if (*flag_p & mbuf->mb_add)
1620 addbuf_local[addbuf_local_i++] = flag_p[1];
1621 else if (*flag_p & mbuf->mb_rem)
1622 rembuf_local[rembuf_local_i++] = flag_p[1];
1625 /* Now go through the modes with arguments... */
1626 for (i = 0; i < mbuf->mb_count; i++) {
1627 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1629 bufptr_i = &addbuf_i;
1632 bufptr_i = &rembuf_i;
1635 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1636 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1638 if ((totalbuflen - IRCD_MAX(9, tmp)) <= 0) /* don't overflow buffer */
1639 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1641 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1642 totalbuflen -= IRCD_MAX(9, tmp) + 1;
1644 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1645 tmp = strlen(MB_STRING(mbuf, i));
1647 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1648 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1651 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1663 bufptr[(*bufptr_i)++] = mode_char;
1664 totalbuflen -= tmp + 1;
1666 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1667 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1668 strlen(MB_STRING(mbuf, i)));
1670 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1671 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1673 bufptr[(*bufptr_i)++] = 'k';
1674 totalbuflen -= tmp + 1;
1676 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1677 /* if it's a limit, we also format the number */
1678 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1680 tmp = strlen(limitbuf);
1682 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1683 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1685 bufptr[(*bufptr_i)++] = 'l';
1686 totalbuflen -= tmp + 1;
1691 /* terminate the mode strings */
1692 addbuf[addbuf_i] = '\0';
1693 rembuf[rembuf_i] = '\0';
1694 addbuf_local[addbuf_local_i] = '\0';
1695 rembuf_local[rembuf_local_i] = '\0';
1697 /* If we're building a user visible MODE or HACK... */
1698 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1699 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1700 MODEBUF_DEST_LOG)) {
1701 /* Set up the parameter strings */
1707 for (i = 0; i < mbuf->mb_count; i++) {
1708 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1711 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1713 strptr_i = &addstr_i;
1716 strptr_i = &remstr_i;
1719 /* deal with clients... */
1720 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1721 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1723 /* deal with bans... */
1724 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1725 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1727 /* deal with keys... */
1728 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1729 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1730 "*" : MB_STRING(mbuf, i), 0, ' ');
1732 /* deal with invisible passwords */
1733 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1734 build_string(strptr, strptr_i, "*", 0, ' ');
1737 * deal with limit; note we cannot include the limit parameter if we're
1740 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1741 (MODE_ADD | MODE_LIMIT))
1742 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1745 /* send the messages off to their destination */
1746 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1747 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1749 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1750 mbuf->mb_source : app_source),
1751 mbuf->mb_channel->chname,
1752 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1753 addbuf, remstr, addstr,
1754 mbuf->mb_channel->creationtime);
1756 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1757 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1758 "%s%s%s%s%s%s [%Tu]",
1759 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1760 mbuf->mb_source : app_source),
1761 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1762 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1763 mbuf->mb_channel->creationtime);
1765 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1766 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1768 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1769 mbuf->mb_source : app_source),
1770 mbuf->mb_channel->chname,
1771 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1772 addbuf, remstr, addstr,
1773 mbuf->mb_channel->creationtime);
1775 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1776 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1777 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1778 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1779 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1781 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1782 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1783 "%H %s%s%s%s%s%s%s%s", mbuf->mb_channel,
1784 rembuf_i || rembuf_local_i ? "-" : "",
1785 rembuf, rembuf_local,
1786 addbuf_i || addbuf_local_i ? "+" : "",
1787 addbuf, addbuf_local,
1791 /* Now are we supposed to propagate to other servers? */
1792 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1793 /* set up parameter string */
1800 * limit is supressed if we're removing it; we have to figure out which
1801 * direction is the direction for it to be removed, though...
1803 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_DEL : MODE_ADD;
1805 for (i = 0; i < mbuf->mb_count; i++) {
1806 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1809 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1811 strptr_i = &addstr_i;
1814 strptr_i = &remstr_i;
1817 /* if we're changing oplevels we know the oplevel, pass it on */
1818 if (mbuf->mb_channel->mode.apass[0]
1819 && (MB_TYPE(mbuf, i) & MODE_CHANOP)
1820 && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
1821 *strptr_i += ircd_snprintf(0, strptr + *strptr_i, BUFSIZE - *strptr_i,
1823 NumNick(MB_CLIENT(mbuf, i)),
1824 MB_OPLEVEL(mbuf, i));
1826 /* deal with other modes that take clients */
1827 else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1828 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1830 /* deal with modes that take strings */
1831 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1832 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1835 * deal with the limit. Logic here is complicated; if HACK2 is set,
1836 * we're bouncing the mode, so sense is reversed, and we have to
1837 * include the original limit if it looks like it's being removed
1839 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1840 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1843 /* we were told to deop the source */
1844 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1845 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1846 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1847 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1849 /* mark that we've done this, so we don't do it again */
1850 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1853 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1854 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1855 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1856 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1857 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1858 addbuf, remstr, addstr);
1859 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1861 * If HACK2 was set, we're bouncing; we send the MODE back to the
1862 * connection we got it from with the senses reversed and a TS of 0;
1865 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1866 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1867 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1868 mbuf->mb_channel->creationtime);
1871 * We're propagating a normal MODE command to the rest of the network;
1872 * we send the actual channel TS unless this is a HACK3 or a HACK4
1874 if (IsServer(mbuf->mb_source))
1875 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1876 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1877 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1878 addbuf, remstr, addstr,
1879 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1880 mbuf->mb_channel->creationtime);
1882 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1883 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1884 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1885 addbuf, remstr, addstr);
1889 /* We've drained the ModeBuf... */
1894 /* reinitialize the mode-with-arg slots */
1895 for (i = 0; i < MAXMODEPARAMS; i++) {
1896 /* If we saved any, pack them down */
1897 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1898 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1899 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1901 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1903 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1904 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1906 MB_TYPE(mbuf, i) = 0;
1907 MB_UINT(mbuf, i) = 0;
1910 /* If we're supposed to flush it all, do so--all hail tail recursion */
1911 if (all && mbuf->mb_count)
1912 return modebuf_flush_int(mbuf, 1);
1917 /** Initialise a modebuf
1918 * This routine just initializes a ModeBuf structure with the information
1919 * needed and the options given.
1921 * @param mbuf The mode buffer to initialise.
1922 * @param source The client that is performing the mode.
1924 * @param chan The channel that the mode is being performed upon.
1928 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1929 struct Client *connect, struct Channel *chan, unsigned int dest)
1934 assert(0 != source);
1938 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1942 mbuf->mb_source = source;
1943 mbuf->mb_connect = connect;
1944 mbuf->mb_channel = chan;
1945 mbuf->mb_dest = dest;
1948 /* clear each mode-with-parameter slot */
1949 for (i = 0; i < MAXMODEPARAMS; i++) {
1950 MB_TYPE(mbuf, i) = 0;
1951 MB_UINT(mbuf, i) = 0;
1955 /** Append a new mode to a modebuf
1956 * This routine simply adds modes to be added or deleted; do a binary OR
1957 * with either MODE_ADD or MODE_DEL
1959 * @param mbuf Mode buffer
1960 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1963 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1966 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1968 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1969 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1970 MODE_DELJOINS | MODE_WASDELJOINS);
1972 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1975 if (mode & MODE_ADD) {
1976 mbuf->mb_rem &= ~mode;
1977 mbuf->mb_add |= mode;
1979 mbuf->mb_add &= ~mode;
1980 mbuf->mb_rem |= mode;
1984 /** Append a mode that takes an int argument to the modebuf
1986 * This routine adds a mode to be added or deleted that takes a unsigned
1987 * int parameter; mode may *only* be the relevant mode flag ORed with one
1988 * of MODE_ADD or MODE_DEL
1990 * @param mbuf The mode buffer to append to.
1991 * @param mode The mode to append.
1992 * @param uint The argument to the mode.
1995 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1998 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2000 if (mode == (MODE_LIMIT | ((mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_ADD : MODE_DEL))) {
2001 mbuf->mb_rem |= mode;
2004 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2005 MB_UINT(mbuf, mbuf->mb_count) = uint;
2007 /* when we've reached the maximal count, flush the buffer */
2008 if (++mbuf->mb_count >=
2009 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2010 modebuf_flush_int(mbuf, 0);
2013 /** append a string mode
2014 * This routine adds a mode to be added or deleted that takes a string
2015 * parameter; mode may *only* be the relevant mode flag ORed with one of
2016 * MODE_ADD or MODE_DEL
2018 * @param mbuf The mode buffer to append to.
2019 * @param mode The mode to append.
2020 * @param string The string parameter to append.
2021 * @param free If the string should be free'd later.
2024 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2028 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2030 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2031 MB_STRING(mbuf, mbuf->mb_count) = string;
2033 /* when we've reached the maximal count, flush the buffer */
2034 if (++mbuf->mb_count >=
2035 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2036 modebuf_flush_int(mbuf, 0);
2039 /** Append a mode on a client to a modebuf.
2040 * This routine adds a mode to be added or deleted that takes a client
2041 * parameter; mode may *only* be the relevant mode flag ORed with one of
2042 * MODE_ADD or MODE_DEL
2044 * @param mbuf The modebuf to append the mode to.
2045 * @param mode The mode to append.
2046 * @param client The client argument to append.
2047 * @param oplevel The oplevel the user had or will have
2050 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2051 struct Client *client, int oplevel)
2054 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2056 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2057 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2058 MB_OPLEVEL(mbuf, mbuf->mb_count) = oplevel;
2060 /* when we've reached the maximal count, flush the buffer */
2061 if (++mbuf->mb_count >=
2062 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2063 modebuf_flush_int(mbuf, 0);
2066 /** The exported binding for modebuf_flush()
2068 * @param mbuf The mode buffer to flush.
2070 * @see modebuf_flush_int()
2073 modebuf_flush(struct ModeBuf *mbuf)
2075 struct Membership *memb;
2077 /* Check if MODE_WASDELJOINS should be set */
2078 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2079 && (mbuf->mb_rem & MODE_DELJOINS)) {
2080 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2081 if (IsDelayedJoin(memb)) {
2082 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2083 mbuf->mb_add |= MODE_WASDELJOINS;
2084 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2090 return modebuf_flush_int(mbuf, 1);
2093 /* This extracts the simple modes contained in mbuf
2095 * @param mbuf The mode buffer to extract the modes from.
2096 * @param buf The string buffer to write the modes into.
2099 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2101 static int flags[] = {
2102 /* MODE_CHANOP, 'o', */
2103 /* MODE_VOICE, 'v', */
2106 MODE_MODERATED, 'm',
2107 MODE_TOPICLIMIT, 't',
2108 MODE_INVITEONLY, 'i',
2109 MODE_NOPRIVMSGS, 'n',
2113 /* MODE_BAN, 'b', */
2120 int i, bufpos = 0, len;
2122 char *key = 0, limitbuf[20];
2123 char *apass = 0, *upass = 0;
2132 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2133 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2134 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2136 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2137 key = MB_STRING(mbuf, i);
2138 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2139 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2140 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2141 upass = MB_STRING(mbuf, i);
2142 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2143 apass = MB_STRING(mbuf, i);
2150 buf[bufpos++] = '+'; /* start building buffer */
2152 for (flag_p = flags; flag_p[0]; flag_p += 2)
2154 buf[bufpos++] = flag_p[1];
2156 for (i = 0, len = bufpos; i < len; i++) {
2158 build_string(buf, &bufpos, key, 0, ' ');
2159 else if (buf[i] == 'l')
2160 build_string(buf, &bufpos, limitbuf, 0, ' ');
2161 else if (buf[i] == 'U')
2162 build_string(buf, &bufpos, upass, 0, ' ');
2163 else if (buf[i] == 'A')
2164 build_string(buf, &bufpos, apass, 0, ' ');
2172 /** Simple function to invalidate bans
2174 * This function sets all bans as being valid.
2176 * @param chan The channel to operate on.
2179 mode_ban_invalidate(struct Channel *chan)
2181 struct Membership *member;
2183 for (member = chan->members; member; member = member->next_member)
2184 ClearBanValid(member);
2187 /** Simple function to drop invite structures
2189 * Remove all the invites on the channel.
2191 * @param chan Channel to remove invites from.
2195 mode_invite_clear(struct Channel *chan)
2197 while (chan->invites)
2198 del_invite(chan->invites->value.cptr, chan);
2201 /* What we've done for mode_parse so far... */
2202 #define DONE_LIMIT 0x01 /**< We've set the limit */
2203 #define DONE_KEY 0x02 /**< We've set the key */
2204 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2205 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2206 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2207 #define DONE_UPASS 0x20 /**< We've set user pass */
2208 #define DONE_APASS 0x40 /**< We've set admin pass */
2211 struct ModeBuf *mbuf;
2212 struct Client *cptr;
2213 struct Client *sptr;
2214 struct Channel *chptr;
2215 struct Membership *member;
2226 struct Ban banlist[MAXPARA];
2229 unsigned short oplevel;
2230 struct Client *client;
2231 } cli_change[MAXPARA];
2234 /** Helper function to send "Not oper" or "Not member" messages
2235 * Here's a helper function to deal with sending along "Not oper" or
2236 * "Not member" messages
2238 * @param state Parsing State object
2241 send_notoper(struct ParseState *state)
2243 if (state->done & DONE_NOTOPER)
2246 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2247 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2249 state->done |= DONE_NOTOPER;
2253 * Helper function to convert limits
2255 * @param state Parsing state object.
2259 mode_parse_limit(struct ParseState *state, int *flag_p)
2261 unsigned int t_limit;
2263 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2264 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2267 if (state->parc <= 0) { /* warn if not enough args */
2268 if (MyUser(state->sptr))
2269 need_more_params(state->sptr, "MODE +l");
2273 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2277 if ((int)t_limit<0) /* don't permit a negative limit */
2280 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2281 (!t_limit || t_limit == state->chptr->mode.limit))
2284 t_limit = state->chptr->mode.limit;
2286 /* If they're not an oper, they can't change modes */
2287 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2288 send_notoper(state);
2292 /* Can't remove a limit that's not there */
2293 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2296 /* Skip if this is a burst and a lower limit than this is set already */
2297 if ((state->flags & MODE_PARSE_BURST) &&
2298 (state->chptr->mode.mode & flag_p[0]) &&
2299 (state->chptr->mode.limit < t_limit))
2302 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2304 state->done |= DONE_LIMIT;
2309 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2311 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2312 if (state->dir & MODE_ADD) {
2313 state->chptr->mode.mode |= flag_p[0];
2314 state->chptr->mode.limit = t_limit;
2316 state->chptr->mode.mode &= ~flag_p[0];
2317 state->chptr->mode.limit = 0;
2322 /** Helper function to clean key-like parameters. */
2328 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2334 * Helper function to convert keys
2337 mode_parse_key(struct ParseState *state, int *flag_p)
2341 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2344 if (state->parc <= 0) { /* warn if not enough args */
2345 if (MyUser(state->sptr))
2346 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2351 t_str = state->parv[state->args_used++]; /* grab arg */
2355 /* If they're not an oper, they can't change modes */
2356 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2357 send_notoper(state);
2361 if (state->done & DONE_KEY) /* allow key to be set only once */
2363 state->done |= DONE_KEY;
2365 /* clean up the key string */
2367 if (!*t_str || *t_str == ':') { /* warn if empty */
2368 if (MyUser(state->sptr))
2369 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2377 /* Skip if this is a burst, we have a key already and the new key is
2378 * after the old one alphabetically */
2379 if ((state->flags & MODE_PARSE_BURST) &&
2380 *(state->chptr->mode.key) &&
2381 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2384 /* can't add a key if one is set, nor can one remove the wrong key */
2385 if (!(state->flags & MODE_PARSE_FORCE))
2386 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2387 (state->dir == MODE_DEL &&
2388 ircd_strcmp(state->chptr->mode.key, t_str))) {
2389 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2393 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2394 !ircd_strcmp(state->chptr->mode.key, t_str))
2395 return; /* no key change */
2397 if (state->flags & MODE_PARSE_BOUNCE) {
2398 if (*state->chptr->mode.key) /* reset old key */
2399 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2400 state->chptr->mode.key, 0);
2401 else /* remove new bogus key */
2402 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2403 } else /* send new key */
2404 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2406 if (state->flags & MODE_PARSE_SET) {
2407 if (state->dir == MODE_DEL) /* remove the old key */
2408 *state->chptr->mode.key = '\0';
2409 else if (!state->chptr->mode.key[0]
2410 || ircd_strcmp(t_str, state->chptr->mode.key) < 0)
2411 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2416 * Helper function to convert user passes
2419 mode_parse_upass(struct ParseState *state, int *flag_p)
2423 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2426 if (state->parc <= 0) { /* warn if not enough args */
2427 if (MyUser(state->sptr))
2428 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2433 t_str = state->parv[state->args_used++]; /* grab arg */
2437 /* If they're not an oper, they can't change modes */
2438 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2439 send_notoper(state);
2443 /* If a non-service user is trying to force it, refuse. */
2444 if (state->flags & MODE_PARSE_FORCE && MyUser(state->sptr)
2445 && !HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
2446 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2447 state->chptr->chname);
2451 /* If they are not the channel manager, they are not allowed to change it */
2452 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2453 if (*state->chptr->mode.apass) {
2454 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2455 state->chptr->chname);
2457 send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname,
2458 (TStime() - state->chptr->creationtime < 172800) ?
2459 "approximately 4-5 minutes" : "approximately 48 hours");
2464 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2466 state->done |= DONE_UPASS;
2468 /* clean up the upass string */
2470 if (!*t_str || *t_str == ':') { /* warn if empty */
2471 if (MyUser(state->sptr))
2472 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2480 if (!(state->flags & MODE_PARSE_FORCE)) {
2481 /* can't add the upass while apass is not set */
2482 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2483 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2486 /* cannot set a +U password that is the same as +A */
2487 if (state->dir == MODE_ADD && !ircd_strcmp(state->chptr->mode.apass, t_str)) {
2488 send_reply(state->sptr, ERR_UPASS_SAME_APASS, state->chptr->chname);
2491 /* can't add a upass if one is set, nor can one remove the wrong upass */
2492 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2493 (state->dir == MODE_DEL &&
2494 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2495 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2500 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2501 !ircd_strcmp(state->chptr->mode.upass, t_str))
2502 return; /* no upass change */
2504 if (state->flags & MODE_PARSE_BOUNCE) {
2505 if (*state->chptr->mode.upass) /* reset old upass */
2506 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2507 state->chptr->mode.upass, 0);
2508 else /* remove new bogus upass */
2509 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2510 } else /* send new upass */
2511 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2513 if (state->flags & MODE_PARSE_SET) {
2514 if (state->dir == MODE_DEL) /* remove the old upass */
2515 *state->chptr->mode.upass = '\0';
2516 else if (state->chptr->mode.upass[0] == '\0'
2517 || ircd_strcmp(t_str, state->chptr->mode.upass) < 0)
2518 ircd_strncpy(state->chptr->mode.upass, t_str, KEYLEN);
2523 * Helper function to convert admin passes
2526 mode_parse_apass(struct ParseState *state, int *flag_p)
2528 struct Membership *memb;
2531 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2534 if (state->parc <= 0) { /* warn if not enough args */
2535 if (MyUser(state->sptr))
2536 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2541 t_str = state->parv[state->args_used++]; /* grab arg */
2545 /* If they're not an oper, they can't change modes */
2546 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2547 send_notoper(state);
2551 if (MyUser(state->sptr)) {
2552 if (state->flags & MODE_PARSE_FORCE) {
2553 /* If an unprivileged oper is trying to force it, refuse. */
2554 if (!HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
2555 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2556 state->chptr->chname);
2560 /* If they are not the channel manager, they are not allowed to change it. */
2561 if (!IsChannelManager(state->member)) {
2562 if (*state->chptr->mode.apass) {
2563 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2564 state->chptr->chname);
2566 send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname,
2567 (TStime() - state->chptr->creationtime < 172800) ?
2568 "approximately 4-5 minutes" : "approximately 48 hours");
2572 /* Can't remove the Apass while Upass is still set. */
2573 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2574 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2577 /* Can't add an Apass if one is set, nor can one remove the wrong Apass. */
2578 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2579 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2580 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2585 /* Forbid removing the Apass if the channel is older than 48 hours
2586 * unless an oper is doing it. */
2587 if (TStime() - state->chptr->creationtime >= 172800
2588 && state->dir == MODE_DEL
2589 && !IsAnOper(state->sptr)) {
2590 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2595 if (state->done & DONE_APASS) /* allow apass to be set only once */
2597 state->done |= DONE_APASS;
2599 /* clean up the apass string */
2601 if (!*t_str || *t_str == ':') { /* warn if empty */
2602 if (MyUser(state->sptr))
2603 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2611 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2612 !ircd_strcmp(state->chptr->mode.apass, t_str))
2613 return; /* no apass change */
2615 if (state->flags & MODE_PARSE_BOUNCE) {
2616 if (*state->chptr->mode.apass) /* reset old apass */
2617 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2618 state->chptr->mode.apass, 0);
2619 else /* remove new bogus apass */
2620 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2621 } else /* send new apass */
2622 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2624 if (state->flags & MODE_PARSE_SET) {
2625 if (state->dir == MODE_ADD) { /* set the new apass */
2626 /* Only accept the new apass if there is no current apass
2627 * (e.g. when a user sets it) or the new one is "less" than the
2628 * old (for resolving conflicts during burst).
2630 if (state->chptr->mode.apass[0] == '\0'
2631 || ircd_strcmp(t_str, state->chptr->mode.apass) < 0)
2632 ircd_strncpy(state->chptr->mode.apass, t_str, KEYLEN);
2633 /* Make it VERY clear to the user that this is a one-time password */
2634 if (MyUser(state->sptr)) {
2635 send_reply(state->sptr, RPL_APASSWARN_SET, state->chptr->mode.apass);
2636 send_reply(state->sptr, RPL_APASSWARN_SECRET, state->chptr->chname,
2637 state->chptr->mode.apass);
2639 /* Give the channel manager level 0 ops.
2640 There should not be tested for IsChannelManager here because
2641 on the local server it is impossible to set the apass if one
2642 isn't a channel manager and remote servers might need to sync
2643 the oplevel here: when someone creates a channel (and becomes
2644 channel manager) during a net.break, and only sets the Apass
2645 after the net rejoined, they will have oplevel MAXOPLEVEL on
2646 all remote servers. */
2648 SetOpLevel(state->member, 0);
2649 } else { /* remove the old apass */
2650 *state->chptr->mode.apass = '\0';
2651 /* Clear Upass so that there is never a Upass set when a zannel is burst. */
2652 *state->chptr->mode.upass = '\0';
2653 if (MyUser(state->sptr))
2654 send_reply(state->sptr, RPL_APASSWARN_CLEAR);
2655 /* Revert everyone to MAXOPLEVEL. */
2656 for (memb = state->chptr->members; memb; memb = memb->next_member) {
2657 if (memb->status & MODE_CHANOP)
2658 SetOpLevel(memb, MAXOPLEVEL);
2664 /** Compare one ban's extent to another.
2665 * This works very similarly to mmatch() but it knows about CIDR masks
2666 * and ban exceptions. If both bans are CIDR-based, compare their
2667 * address bits; otherwise, use mmatch().
2668 * @param[in] old_ban One ban.
2669 * @param[in] new_ban Another ban.
2670 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2673 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2676 assert(old_ban != NULL);
2677 assert(new_ban != NULL);
2678 /* A ban is never treated as a superset of an exception. */
2679 if (!(old_ban->flags & BAN_EXCEPTION)
2680 && (new_ban->flags & BAN_EXCEPTION))
2682 /* If either is not an address mask, match the text masks. */
2683 if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2684 return mmatch(old_ban->banstr, new_ban->banstr);
2685 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2686 if (old_ban->addrbits > new_ban->addrbits)
2688 /* Compare the masks before the hostname part. */
2689 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2690 res = mmatch(old_ban->banstr, new_ban->banstr);
2691 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2694 /* Compare the addresses. */
2695 return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2698 /** Add a ban from a ban list and mark bans that should be removed
2699 * because they overlap.
2701 * There are three invariants for a ban list. First, no ban may be
2702 * more specific than another ban. Second, no exception may be more
2703 * specific than another exception. Finally, no ban may be more
2704 * specific than any exception.
2706 * @param[in,out] banlist Pointer to head of list.
2707 * @param[in] newban Ban (or exception) to add (or remove).
2708 * @param[in] do_free If non-zero, free \a newban on failure.
2709 * @return Zero if \a newban could be applied, non-zero if not.
2711 int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
2716 assert(newban->flags & (BAN_ADD|BAN_DEL));
2717 if (newban->flags & BAN_ADD) {
2719 /* If a less specific entry is found, fail. */
2720 for (ban = *banlist; ban; ban = ban->next) {
2721 if (!bmatch(ban, newban)) {
2726 if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2728 totlen += strlen(ban->banstr);
2731 /* Mark more specific entries and add this one to the end of the list. */
2732 while ((ban = *banlist) != NULL) {
2733 if (!bmatch(newban, ban)) {
2734 ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2736 banlist = &ban->next;
2740 } else if (newban->flags & BAN_DEL) {
2741 size_t remove_count = 0;
2742 /* Mark more specific entries. */
2743 for (ban = *banlist; ban; ban = ban->next) {
2744 if (!bmatch(newban, ban)) {
2745 ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2751 /* If no matches were found, fail. */
2762 * Helper function to convert bans
2765 mode_parse_ban(struct ParseState *state, int *flag_p)
2768 struct Ban *ban, *newban;
2770 if (state->parc <= 0) { /* Not enough args, send ban list */
2771 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2772 send_ban_list(state->sptr, state->chptr);
2773 state->done |= DONE_BANLIST;
2779 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2782 t_str = state->parv[state->args_used++]; /* grab arg */
2786 /* If they're not an oper, they can't change modes */
2787 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2788 send_notoper(state);
2792 if ((s = strchr(t_str, ' ')))
2795 if (!*t_str || *t_str == ':') { /* warn if empty */
2796 if (MyUser(state->sptr))
2797 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2802 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2803 if (!(state->done & DONE_BANCLEAN)) {
2804 for (ban = state->chptr->banlist; ban; ban = ban->next)
2805 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2806 state->done |= DONE_BANCLEAN;
2809 /* remember the ban for the moment... */
2810 newban = state->banlist + (state->numbans++);
2812 newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2813 | (*flag_p == MODE_BAN ? 0 : BAN_EXCEPTION);
2814 set_ban_mask(newban, collapse(pretty_mask(t_str)));
2815 ircd_strncpy(newban->who, IsUser(state->sptr) ? cli_name(state->sptr) : "*", NICKLEN);
2816 newban->when = TStime();
2817 apply_ban(&state->chptr->banlist, newban, 0);
2821 * This is the bottom half of the ban processor
2824 mode_process_bans(struct ParseState *state)
2826 struct Ban *ban, *newban, *prevban, *nextban;
2832 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2834 banlen = strlen(ban->banstr);
2836 nextban = ban->next;
2838 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2840 prevban->next = 0; /* Break the list; ban isn't a real ban */
2842 state->chptr->banlist = 0;
2848 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2850 DupString(bandup, ban->banstr);
2851 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2854 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2855 if (prevban) /* clip it out of the list... */
2856 prevban->next = ban->next;
2858 state->chptr->banlist = ban->next;
2865 continue; /* next ban; keep prevban like it is */
2867 ban->flags &= BAN_IPMASK; /* unset other flags */
2868 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2870 prevban->next = 0; /* Break the list; ban isn't a real ban */
2872 state->chptr->banlist = 0;
2874 /* If we're supposed to ignore it, do so. */
2875 if (ban->flags & BAN_OVERLAPPED &&
2876 !(state->flags & MODE_PARSE_BOUNCE)) {
2880 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2881 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2882 count > feature_int(FEAT_MAXBANS))) {
2883 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2889 /* add the ban to the buffer */
2890 DupString(bandup, ban->banstr);
2891 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2894 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2895 newban = make_ban(ban->banstr);
2896 strcpy(newban->who, ban->who);
2897 newban->when = ban->when;
2898 newban->flags = ban->flags & BAN_IPMASK;
2900 newban->next = state->chptr->banlist; /* and link it in */
2901 state->chptr->banlist = newban;
2910 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2912 if (changed) /* if we changed the ban list, we must invalidate the bans */
2913 mode_ban_invalidate(state->chptr);
2917 * Helper function to process client changes
2920 mode_parse_client(struct ParseState *state, int *flag_p)
2924 struct Client *acptr;
2925 struct Membership *member;
2926 int oplevel = MAXOPLEVEL + 1;
2930 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2933 if (state->parc <= 0) /* return if not enough args */
2936 t_str = state->parv[state->args_used++]; /* grab arg */
2940 /* If they're not an oper, they can't change modes */
2941 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2942 send_notoper(state);
2946 if (MyUser(state->sptr)) {
2947 colon = strchr(t_str, ':');
2948 if (colon != NULL) {
2950 req_oplevel = atoi(colon);
2951 if (!(state->flags & MODE_PARSE_FORCE)
2953 && (req_oplevel < OpLevel(state->member)
2954 || (req_oplevel == OpLevel(state->member)
2955 && OpLevel(state->member) < MAXOPLEVEL)
2956 || req_oplevel > MAXOPLEVEL))
2957 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2958 t_str, state->chptr->chname,
2959 OpLevel(state->member), req_oplevel, "op",
2960 OpLevel(state->member) == req_oplevel ? "the same" : "a higher");
2961 else if (req_oplevel <= MAXOPLEVEL)
2962 oplevel = req_oplevel;
2964 /* find client we're manipulating */
2965 acptr = find_chasing(state->sptr, t_str, NULL);
2967 if (t_str[5] == ':') {
2969 oplevel = atoi(t_str + 6);
2971 acptr = findNUser(t_str);
2975 return; /* find_chasing() already reported an error to the user */
2977 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2978 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2979 state->cli_change[i].flag & flag_p[0]))
2980 break; /* found a slot */
2982 /* If we are going to bounce this deop, mark the correct oplevel. */
2983 if (state->flags & MODE_PARSE_BOUNCE
2984 && state->dir == MODE_DEL
2985 && flag_p[0] == MODE_CHANOP
2986 && (member = find_member_link(state->chptr, acptr)))
2987 oplevel = OpLevel(member);
2989 /* Store what we're doing to them */
2990 state->cli_change[i].flag = state->dir | flag_p[0];
2991 state->cli_change[i].oplevel = oplevel;
2992 state->cli_change[i].client = acptr;
2996 * Helper function to process the changed client list
2999 mode_process_clients(struct ParseState *state)
3002 struct Membership *member;
3004 for (i = 0; state->cli_change[i].flag; i++) {
3005 assert(0 != state->cli_change[i].client);
3007 /* look up member link */
3008 if (!(member = find_member_link(state->chptr,
3009 state->cli_change[i].client)) ||
3010 (MyUser(state->sptr) && IsZombie(member))) {
3011 if (MyUser(state->sptr))
3012 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3013 cli_name(state->cli_change[i].client),
3014 state->chptr->chname);
3018 if ((state->cli_change[i].flag & MODE_ADD &&
3019 (state->cli_change[i].flag & member->status)) ||
3020 (state->cli_change[i].flag & MODE_DEL &&
3021 !(state->cli_change[i].flag & member->status)))
3022 continue; /* no change made, don't do anything */
3024 /* see if the deop is allowed */
3025 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3026 (MODE_DEL | MODE_CHANOP)) {
3027 /* prevent +k users from being deopped */
3028 if (IsChannelService(state->cli_change[i].client)) {
3029 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3030 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3032 (IsServer(state->sptr) ? cli_name(state->sptr) :
3033 cli_name((cli_user(state->sptr))->server)));
3035 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3036 send_reply(state->sptr, ERR_ISCHANSERVICE,
3037 cli_name(state->cli_change[i].client),
3038 state->chptr->chname);
3043 /* check deop for local user */
3044 if (MyUser(state->sptr)) {
3046 /* don't allow local opers to be deopped on local channels */
3047 if (state->cli_change[i].client != state->sptr &&
3048 IsLocalChannel(state->chptr->chname) &&
3049 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3050 send_reply(state->sptr, ERR_ISOPERLCHAN,
3051 cli_name(state->cli_change[i].client),
3052 state->chptr->chname);
3056 /* Forbid deopping other members with an oplevel less than
3057 * one's own level, and other members with an oplevel the same
3058 * as one's own unless both are at MAXOPLEVEL. */
3059 if (state->sptr != state->cli_change[i].client
3061 && ((OpLevel(member) < OpLevel(state->member))
3062 || (OpLevel(member) == OpLevel(state->member)
3063 && OpLevel(member) < MAXOPLEVEL))) {
3064 int equal = (OpLevel(member) == OpLevel(state->member));
3065 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3066 cli_name(state->cli_change[i].client),
3067 state->chptr->chname,
3068 OpLevel(state->member), OpLevel(member),
3069 "deop", equal ? "the same" : "a higher");
3075 /* set op-level of member being opped */
3076 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3077 (MODE_ADD | MODE_CHANOP)) {
3078 /* If a valid oplevel was specified, use it.
3079 * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
3080 * Otherwise, if not an apass channel, or state->member has
3081 * MAXOPLEVEL, get oplevel MAXOPLEVEL.
3082 * Otherwise, get state->member's oplevel+1.
3084 if (state->cli_change[i].oplevel <= MAXOPLEVEL)
3085 SetOpLevel(member, state->cli_change[i].oplevel);
3086 else if (!state->member)
3087 SetOpLevel(member, MAXOPLEVEL);
3088 else if (!state->chptr->mode.apass[0] || OpLevel(state->member) == MAXOPLEVEL)
3089 SetOpLevel(member, MAXOPLEVEL);
3091 SetOpLevel(member, OpLevel(state->member) + 1);
3094 /* actually effect the change */
3095 if (state->flags & MODE_PARSE_SET) {
3096 if (state->cli_change[i].flag & MODE_ADD) {
3097 if (IsDelayedJoin(member))
3098 RevealDelayedJoin(member);
3099 member->status |= (state->cli_change[i].flag &
3100 (MODE_CHANOP | MODE_VOICE));
3101 if (state->cli_change[i].flag & MODE_CHANOP)
3102 ClearDeopped(member);
3104 member->status &= ~(state->cli_change[i].flag &
3105 (MODE_CHANOP | MODE_VOICE));
3108 /* accumulate the change */
3109 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3110 state->cli_change[i].client,
3111 state->cli_change[i].oplevel);
3112 } /* for (i = 0; state->cli_change[i].flags; i++) */
3116 * Helper function to process the simple modes
3119 mode_parse_mode(struct ParseState *state, int *flag_p)
3121 /* If they're not an oper, they can't change modes */
3122 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3123 send_notoper(state);
3130 if (state->dir == MODE_ADD) {
3131 state->add |= flag_p[0];
3132 state->del &= ~flag_p[0];
3134 if (flag_p[0] & MODE_SECRET) {
3135 state->add &= ~MODE_PRIVATE;
3136 state->del |= MODE_PRIVATE;
3137 } else if (flag_p[0] & MODE_PRIVATE) {
3138 state->add &= ~MODE_SECRET;
3139 state->del |= MODE_SECRET;
3141 if (flag_p[0] & MODE_DELJOINS) {
3142 state->add &= ~MODE_WASDELJOINS;
3143 state->del |= MODE_WASDELJOINS;
3146 state->add &= ~flag_p[0];
3147 state->del |= flag_p[0];
3150 assert(0 == (state->add & state->del));
3151 assert((MODE_SECRET | MODE_PRIVATE) !=
3152 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3156 * This routine is intended to parse MODE or OPMODE commands and effect the
3157 * changes (or just build the bounce buffer). We pass the starting offset
3161 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3162 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3163 struct Membership* member)
3165 static int chan_flags[] = {
3170 MODE_MODERATED, 'm',
3171 MODE_TOPICLIMIT, 't',
3172 MODE_INVITEONLY, 'i',
3173 MODE_NOPRIVMSGS, 'n',
3187 unsigned int t_mode;
3189 struct ParseState state;
3200 state.chptr = chptr;
3201 state.member = member;
3204 state.flags = flags;
3205 state.dir = MODE_ADD;
3209 state.args_used = 0;
3210 state.max_args = MAXMODEPARAMS;
3213 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3214 state.banlist[i].next = 0;
3215 state.banlist[i].who[0] = '\0';
3216 state.banlist[i].when = 0;
3217 state.banlist[i].flags = 0;
3218 state.cli_change[i].flag = 0;
3219 state.cli_change[i].client = 0;
3222 modestr = state.parv[state.args_used++];
3226 for (; *modestr; modestr++) {
3227 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3228 if (flag_p[1] == *modestr)
3231 if (!flag_p[0]) { /* didn't find it? complain and continue */
3232 if (MyUser(state.sptr))
3233 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3238 case '+': /* switch direction to MODE_ADD */
3239 case '-': /* switch direction to MODE_DEL */
3240 state.dir = flag_p[0];
3243 case 'l': /* deal with limits */
3244 mode_parse_limit(&state, flag_p);
3247 case 'k': /* deal with keys */
3248 mode_parse_key(&state, flag_p);
3251 case 'A': /* deal with Admin passes */
3252 if (IsServer(cptr) || feature_bool(FEAT_OPLEVELS))
3253 mode_parse_apass(&state, flag_p);
3256 case 'U': /* deal with user passes */
3257 if (IsServer(cptr) || feature_bool(FEAT_OPLEVELS))
3258 mode_parse_upass(&state, flag_p);
3261 case 'b': /* deal with bans */
3262 mode_parse_ban(&state, flag_p);
3265 case 'o': /* deal with ops/voice */
3267 mode_parse_client(&state, flag_p);
3270 default: /* deal with other modes */
3271 mode_parse_mode(&state, flag_p);
3273 } /* switch (*modestr) */
3274 } /* for (; *modestr; modestr++) */
3276 if (state.flags & MODE_PARSE_BURST)
3277 break; /* don't interpret any more arguments */
3279 if (state.parc > 0) { /* process next argument in string */
3280 modestr = state.parv[state.args_used++];
3284 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3287 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3288 break; /* we're then going to bounce the mode! */
3290 recv_ts = atoi(modestr);
3292 if (recv_ts && recv_ts < state.chptr->creationtime)
3293 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3295 break; /* break out of while loop */
3296 } else if (state.flags & MODE_PARSE_STRICT ||
3297 (MyUser(state.sptr) && state.max_args <= 0)) {
3298 state.parc++; /* we didn't actually gobble the argument */
3300 break; /* break out of while loop */
3303 } /* while (*modestr) */
3306 * the rest of the function finishes building resultant MODEs; if the
3307 * origin isn't a member or an oper, skip it.
3309 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3310 return state.args_used; /* tell our parent how many args we gobbled */
3312 t_mode = state.chptr->mode.mode;
3314 if (state.del & t_mode) { /* delete any modes to be deleted... */
3315 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3317 t_mode &= ~state.del;
3319 if (state.add & ~t_mode) { /* add any modes to be added... */
3320 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3322 t_mode |= state.add;
3325 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3326 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3327 !(t_mode & MODE_INVITEONLY))
3328 mode_invite_clear(state.chptr);
3330 state.chptr->mode.mode = t_mode;
3333 if (state.flags & MODE_PARSE_WIPEOUT) {
3334 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3335 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3336 state.chptr->mode.limit);
3337 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3338 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3339 state.chptr->mode.key, 0);
3340 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3341 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3342 state.chptr->mode.upass, 0);
3343 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3344 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3345 state.chptr->mode.apass, 0);
3348 if (state.done & DONE_BANCLEAN) /* process bans */
3349 mode_process_bans(&state);
3351 /* process client changes */
3352 if (state.cli_change[0].flag)
3353 mode_process_clients(&state);
3355 return state.args_used; /* tell our parent how many args we gobbled */
3359 * Initialize a join buffer
3362 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3363 struct Client *connect, unsigned int type, char *comment,
3369 assert(0 != source);
3370 assert(0 != connect);
3372 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3373 jbuf->jb_connect = connect;
3374 jbuf->jb_type = type;
3375 jbuf->jb_comment = comment;
3376 jbuf->jb_create = create;
3378 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3379 type == JOINBUF_TYPE_PART ||
3380 type == JOINBUF_TYPE_PARTALL) ?
3381 STARTJOINLEN : STARTCREATELEN) +
3382 (comment ? strlen(comment) + 2 : 0));
3384 for (i = 0; i < MAXJOINARGS; i++)
3385 jbuf->jb_channels[i] = 0;
3389 * Add a channel to the join buffer
3392 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3400 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3404 is_local = IsLocalChannel(chan->chname);
3406 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3407 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3408 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3409 if (IsUserParting(member))
3411 SetUserParting(member);
3413 /* Send notification to channel */
3414 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3415 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3416 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3417 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3418 else if (MyUser(jbuf->jb_source))
3419 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3420 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3421 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3422 /* XXX: Shouldn't we send a PART here anyway? */
3423 /* to users on the channel? Why? From their POV, the user isn't on
3424 * the channel anymore anyway. We don't send to servers until below,
3425 * when we gang all the channel parts together. Note that this is
3426 * exactly the same logic, albeit somewhat more concise, as was in
3427 * the original m_part.c */
3429 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3430 is_local) /* got to remove user here */
3431 remove_user_from_channel(jbuf->jb_source, chan);
3433 int oplevel = !chan->mode.apass[0] ? MAXOPLEVEL
3434 : (flags & CHFL_CHANNEL_MANAGER) ? 0
3436 /* Add user to channel */
3437 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3438 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, oplevel);
3440 add_user_to_channel(chan, jbuf->jb_source, flags, oplevel);
3442 /* send JOIN notification to all servers (CREATE is sent later). */
3443 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3444 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3445 "%H %Tu", chan, chan->creationtime);
3447 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3448 /* Send the notification to the channel */
3449 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3451 /* send an op, too, if needed */
3452 if (flags & CHFL_CHANOP && (oplevel < MAXOPLEVEL || !MyUser(jbuf->jb_source)))
3453 sendcmdto_channel_butserv_butone((chan->mode.apass[0] ? &his : jbuf->jb_source),
3454 CMD_MODE, chan, NULL, 0, "%H +o %C",
3455 chan, jbuf->jb_source);
3456 } else if (MyUser(jbuf->jb_source))
3457 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3460 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3461 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3462 return; /* don't send to remote */
3464 /* figure out if channel name will cause buffer to be overflowed */
3465 len = chan ? strlen(chan->chname) + 1 : 2;
3466 if (jbuf->jb_strlen + len > BUFSIZE)
3467 joinbuf_flush(jbuf);
3469 /* add channel to list of channels to send and update counts */
3470 jbuf->jb_channels[jbuf->jb_count++] = chan;
3471 jbuf->jb_strlen += len;
3473 /* if we've used up all slots, flush */
3474 if (jbuf->jb_count >= MAXJOINARGS)
3475 joinbuf_flush(jbuf);
3479 * Flush the channel list to remote servers
3482 joinbuf_flush(struct JoinBuf *jbuf)
3484 char chanlist[BUFSIZE];
3488 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3489 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3490 return 0; /* no joins to process */
3492 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3493 build_string(chanlist, &chanlist_i,
3494 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3495 i == 0 ? '\0' : ',');
3496 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3497 /* Remove user from channel */
3498 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3500 jbuf->jb_channels[i] = 0; /* mark slot empty */
3503 jbuf->jb_count = 0; /* reset base counters */
3504 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3505 STARTJOINLEN : STARTCREATELEN) +
3506 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3508 /* and send the appropriate command */
3509 switch (jbuf->jb_type) {
3510 case JOINBUF_TYPE_CREATE:
3511 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3512 "%s %Tu", chanlist, jbuf->jb_create);
3515 case JOINBUF_TYPE_PART:
3516 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3517 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3525 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3526 int IsInvited(struct Client* cptr, const void* chptr)
3530 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3531 if (lp->value.chptr == chptr)
3536 /* RevealDelayedJoin: sends a join for a hidden user */
3538 void RevealDelayedJoin(struct Membership *member)
3540 ClearDelayedJoin(member);
3541 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3543 CheckDelayedJoins(member->channel);
3546 /* CheckDelayedJoins: checks and clear +d if necessary */
3548 void CheckDelayedJoins(struct Channel *chan)
3550 struct Membership *memb2;
3552 if (chan->mode.mode & MODE_WASDELJOINS) {
3553 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3554 if (IsDelayedJoin(memb2))
3559 chan->mode.mode &= ~MODE_WASDELJOINS;
3560 sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan, NULL, 0,