2 * IRC - Internet Relay Chat, ircd/channel.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Co Center
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * @brief Channel management and maintanance
28 #include "destruct_event.h"
31 #include "ircd_alloc.h"
32 #include "ircd_chattr.h"
33 #include "ircd_defs.h"
34 #include "ircd_features.h"
36 #include "ircd_reply.h"
37 #include "ircd_snprintf.h"
38 #include "ircd_string.h"
45 #include "querycmds.h"
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;
72 /** return the length (>=0) of a chain of links.
73 * @param lp pointer to the start of the linked list
74 * @return the number of items in the list
76 static int list_length(struct SLink *lp)
80 for (; lp; lp = lp->next)
86 /** Set the mask for a ban, checking for IP masks.
87 * @param[in,out] ban Ban structure to modify.
88 * @param[in] banstr Mask to ban.
91 set_ban_mask(struct Ban *ban, const char *banstr)
97 DupString(ban->banstr, banstr);
98 sep = strrchr(banstr, '@');
100 ban->nu_len = sep - banstr;
101 if (ipmask_parse(sep + 1, &ban->address, &ban->addrbits))
102 ban->flags |= BAN_IPMASK;
106 /** Allocate a new Ban structure.
107 * @param[in] banstr Ban mask to use.
108 * @return Newly allocated ban.
111 make_ban(const char *banstr)
116 free_bans = free_bans->next;
118 else if (!(ban = MyMalloc(sizeof(*ban))))
120 memset(ban, 0, sizeof(*ban));
121 set_ban_mask(ban, banstr);
125 /** Deallocate a ban structure.
126 * @param[in] ban Ban to deallocate.
129 free_ban(struct Ban *ban)
133 ban->next = free_bans;
137 /** return the struct Membership* that represents a client on a channel
138 * This function finds a struct Membership* which holds the state about
139 * a client on a specific channel. The code is smart enough to iterate
140 * over the channels a user is in, or the users in a channel to find the
141 * user depending on which is likely to be more efficient.
143 * @param chptr pointer to the channel struct
144 * @param cptr pointer to the client struct
146 * @returns pointer to the struct Membership representing this client on
147 * this channel. Returns NULL if the client is not on the channel.
148 * Returns NULL if the client is actually a server.
149 * @see find_channel_member()
151 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
153 struct Membership *m;
157 /* Servers don't have member links */
158 if (IsServer(cptr)||IsMe(cptr))
161 /* +k users are typically on a LOT of channels. So we iterate over who
162 * is in the channel. X/W are +k and are in about 5800 channels each.
163 * however there are typically no more than 1000 people in a channel
166 if (IsChannelService(cptr)) {
169 assert(m->channel == chptr);
175 /* Users on the other hand aren't allowed on more than 15 channels. 50%
176 * of users that are on channels are on 2 or less, 95% are on 7 or less,
177 * and 99% are on 10 or less.
180 m = (cli_user(cptr))->channel;
182 assert(m->user == cptr);
183 if (m->channel == chptr)
191 /** Find the client structure for a nick name (user)
192 * Find the client structure for a nick name (user)
193 * using history mechanism if necessary. If the client is not found, an error
194 * message (NO SUCH NICK) is generated. If the client was found
195 * through the history, chasing will be 1 and otherwise 0.
197 * This function was used extensively in the P09 days, and since we now have
198 * numeric nicks is no longer quite as important.
200 * @param sptr Pointer to the client that has requested the search
201 * @param user a string represeting the client to be found
202 * @param chasing a variable set to 0 if the user was found directly,
204 * @returns a pointer the client, or NULL if the client wasn't found.
206 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
208 struct Client* who = FindClient(user);
215 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
216 send_reply(sptr, ERR_NOSUCHNICK, user);
224 /** Decrement the count of users, and free if empty.
225 * Subtract one user from channel i (and free channel * block, if channel
228 * @param chptr The channel to subtract one from.
230 * @returns true (1) if channel still has members.
231 * false (0) if the channel is now empty.
233 int sub1_from_channel(struct Channel* chptr)
235 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
237 assert(0 != chptr->members);
245 * Also channels without Apass set need to be kept alive,
246 * otherwise Bad Guys(tm) would be able to takeover
247 * existing channels too easily, and then set an Apass!
248 * However, if a channel without Apass becomes empty
249 * then we try to be kind to them and remove possible
252 chptr->mode.mode &= ~MODE_INVITEONLY;
253 chptr->mode.limit = 0;
255 * We do NOT reset a possible key or bans because when
256 * the 'channel owners' can't get in because of a key
257 * or ban then apparently there was a fight/takeover
258 * on the channel and we want them to contact IRC opers
259 * who then will educate them on the use of Apass/upass.
262 if (feature_bool(FEAT_OPLEVELS)) {
263 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
264 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
266 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
268 destruct_channel(chptr);
273 /** Destroy an empty channel
274 * This function destroys an empty channel, removing it from hashtables,
275 * and removing any resources it may have consumed.
277 * @param chptr The channel to destroy
279 * @returns 0 (success)
281 * FIXME: Change to return void, this function never fails.
283 int destruct_channel(struct Channel* chptr)
285 struct Ban *ban, *next;
287 assert(0 == chptr->members);
290 * Now, find all invite links from channel structure
292 while (chptr->invites)
293 del_invite(chptr->invites->value.cptr, chptr);
295 for (ban = chptr->banlist; ban; ban = next)
301 chptr->prev->next = chptr->next;
303 GlobalChannelList = chptr->next;
305 chptr->next->prev = chptr->prev;
307 --UserStats.channels;
309 * make sure that channel actually got removed from hash table
311 assert(chptr->hnext == chptr);
316 /** returns Membership * if a person is joined and not a zombie
318 * @param chptr Channel
319 * @returns pointer to the client's struct Membership * on the channel if that
320 * user is a full member of the channel, or NULL otherwise.
322 * @see find_member_link()
324 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
326 struct Membership* member;
329 member = find_member_link(chptr, cptr);
330 return (member && !IsZombie(member)) ? member : 0;
333 /** Searches for a ban from a banlist that matches a user.
334 * @param[in] cptr The client to test.
335 * @param[in] banlist The list of bans to test.
336 * @return Pointer to a matching ban, or NULL if none exit.
338 struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
340 char nu[NICKLEN + USERLEN + 2];
341 char tmphost[HOSTLEN + 1];
345 /* Build nick!user and alternate host names. */
346 ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
347 cli_name(cptr), cli_user(cptr)->username);
348 if (!IsAccount(cptr))
350 else if (HasHiddenHost(cptr))
351 sr = cli_user(cptr)->realhost;
354 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
355 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
359 /* Walk through ban list. */
360 for (found = NULL; banlist; banlist = banlist->next) {
362 /* If we have found a positive ban already, only consider exceptions. */
363 if (found && !(banlist->flags & BAN_EXCEPTION))
365 /* Compare nick!user portion of ban. */
366 banlist->banstr[banlist->nu_len] = '\0';
367 res = match(banlist->banstr, nu);
368 banlist->banstr[banlist->nu_len] = '@';
371 /* Compare host portion of ban. */
372 if (!((banlist->flags & BAN_IPMASK)
373 && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
374 && match(banlist->banstr + banlist->nu_len + 1, cli_user(cptr)->host)
375 && !(sr && match(banlist->banstr + banlist->nu_len + 1, sr) == 0))
377 /* If an exception matches, no ban can match. */
378 if (banlist->flags & BAN_EXCEPTION)
380 /* Otherwise, remember this ban but keep searching for an exception. */
387 * This function returns true if the user is banned on the said channel.
388 * This function will check the ban cache if applicable, otherwise will
389 * do the comparisons and cache the result.
391 * @param[in] member The Membership to test for banned-ness.
392 * @return Non-zero if the member is banned, zero if not.
394 static int is_banned(struct Membership* member)
396 if (IsBanValid(member))
397 return IsBanned(member);
400 if (find_ban(member->user, member->channel->banlist)) {
409 /** add a user to a channel.
410 * adds a user to a channel by adding another link to the channels member
413 * @param chptr The channel to add to.
414 * @param who The user to add.
415 * @param flags The flags the user gets initially.
416 * @param oplevel The oplevel the user starts with.
418 void add_user_to_channel(struct Channel* chptr, struct Client* who,
419 unsigned int flags, int oplevel)
426 struct Membership* member = membershipFreeList;
428 membershipFreeList = member->next_member;
430 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
431 ++membershipAllocCount;
436 member->channel = chptr;
437 member->status = flags;
438 member->oplevel = oplevel;
440 member->next_member = chptr->members;
441 if (member->next_member)
442 member->next_member->prev_member = member;
443 member->prev_member = 0;
444 chptr->members = member;
446 member->next_channel = (cli_user(who))->channel;
447 if (member->next_channel)
448 member->next_channel->prev_channel = member;
449 member->prev_channel = 0;
450 (cli_user(who))->channel = member;
452 if (chptr->destruct_event)
453 remove_destruct_event(chptr);
455 ++((cli_user(who))->joined);
459 /** Remove a person from a channel, given their Membership*
461 * @param member A member of a channel.
463 * @returns true if there are more people in the channel.
465 static int remove_member_from_channel(struct Membership* member)
467 struct Channel* chptr;
469 chptr = member->channel;
471 * unlink channel member list
473 if (member->next_member)
474 member->next_member->prev_member = member->prev_member;
475 if (member->prev_member)
476 member->prev_member->next_member = member->next_member;
478 member->channel->members = member->next_member;
481 * If this is the last delayed-join user, may have to clear WASDELJOINS.
483 if (IsDelayedJoin(member))
484 CheckDelayedJoins(chptr);
487 * unlink client channel list
489 if (member->next_channel)
490 member->next_channel->prev_channel = member->prev_channel;
491 if (member->prev_channel)
492 member->prev_channel->next_channel = member->next_channel;
494 (cli_user(member->user))->channel = member->next_channel;
496 --(cli_user(member->user))->joined;
498 member->next_member = membershipFreeList;
499 membershipFreeList = member;
501 return sub1_from_channel(chptr);
504 /** Check if all the remaining members on the channel are zombies
506 * @returns False if the channel has any non zombie members, True otherwise.
509 static int channel_all_zombies(struct Channel* chptr)
511 struct Membership* member;
513 for (member = chptr->members; member; member = member->next_member) {
514 if (!IsZombie(member))
521 /** Remove a user from a channel
522 * This is the generic entry point for removing a user from a channel, this
523 * function will remove the client from the channel, and destory the channel
524 * if there are no more normal users left.
526 * @param cptr The client
527 * @param chptr The channel
529 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
532 struct Membership* member;
535 if ((member = find_member_link(chptr, cptr))) {
536 if (remove_member_from_channel(member)) {
537 if (channel_all_zombies(chptr)) {
539 * XXX - this looks dangerous but isn't if we got the referential
540 * integrity right for channels
542 while (remove_member_from_channel(chptr->members))
549 /** Remove a user from all channels they are on.
551 * This function removes a user from all channels they are on.
553 * @param cptr The client to remove.
555 void remove_user_from_all_channels(struct Client* cptr)
557 struct Membership* chan;
559 assert(0 != cli_user(cptr));
561 while ((chan = (cli_user(cptr))->channel))
562 remove_user_from_channel(cptr, chan->channel);
565 /** Check if this user is a legitimate chanop
567 * @param cptr Client to check
568 * @param chptr Channel to check
570 * @returns True if the user is a chanop (And not a zombie), False otherwise.
573 int is_chan_op(struct Client *cptr, struct Channel *chptr)
575 struct Membership* member;
577 if ((member = find_member_link(chptr, cptr)))
578 return (!IsZombie(member) && IsChanOp(member));
583 /** Check if a user is a Zombie on a specific channel.
585 * @param cptr The client to check.
586 * @param chptr The channel to check.
588 * @returns True if the client (cptr) is a zombie on the channel (chptr),
593 int is_zombie(struct Client *cptr, struct Channel *chptr)
595 struct Membership* member;
599 if ((member = find_member_link(chptr, cptr)))
600 return IsZombie(member);
604 /** Returns if a user has voice on a channel.
606 * @param cptr The client
607 * @param chptr The channel
609 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
612 int has_voice(struct Client* cptr, struct Channel* chptr)
614 struct Membership* member;
617 if ((member = find_member_link(chptr, cptr)))
618 return (!IsZombie(member) && HasVoice(member));
623 /** Can this member send to a channel
625 * A user can speak on a channel iff:
627 * <li> They didn't use the Apass to gain ops.
628 * <li> They are op'd or voice'd.
629 * <li> You aren't banned.
630 * <li> The channel isn't +m
631 * <li> The channel isn't +n or you are on the channel.
634 * This function will optionally reveal a user on a delayed join channel if
635 * they are allowed to send to the channel.
637 * @param member The membership of the user
638 * @param reveal If true, the user will be "revealed" on a delayed
641 * @returns True if the client can speak on the channel.
643 int member_can_send_to_channel(struct Membership* member, int reveal)
647 /* Discourage using the Apass to get op. They should use the upass. */
648 if (IsChannelManager(member) && *member->channel->mode.upass)
651 if (IsVoicedOrOpped(member))
654 * If it's moderated, and you aren't a priviledged user, you can't
657 if (member->channel->mode.mode & MODE_MODERATED)
660 * If you're banned then you can't speak either.
661 * but because of the amount of CPU time that is_banned chews
662 * we only check it for our clients.
664 if (MyUser(member->user) && is_banned(member))
667 if (IsDelayedJoin(member) && reveal)
668 RevealDelayedJoin(member);
673 /** Check if a client can send to a channel.
675 * Has the added check over member_can_send_to_channel() of servers can
678 * @param cptr The client to check
679 * @param chptr The channel to check
680 * @param reveal If the user should be revealed (see
681 * member_can_send_to_channel())
683 * @returns true if the client is allowed to speak on the channel, false
686 * @see member_can_send_to_channel()
688 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
690 struct Membership *member;
693 * Servers can always speak on channels.
698 member = find_channel_member(cptr, chptr);
701 * You can't speak if you're off channel, and it is +n (no external messages)
705 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
706 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
709 return !find_ban(cptr, chptr->banlist);
711 return member_can_send_to_channel(member, reveal);
714 /** Returns the name of a channel that prevents the user from changing nick.
715 * if a member and not (opped or voiced) and (banned or moderated), return
716 * the name of the first channel banned on.
718 * @param cptr The client
720 * @returns the name of the first channel banned on, or NULL if the user
723 const char* find_no_nickchange_channel(struct Client* cptr)
726 struct Membership* member;
727 for (member = (cli_user(cptr))->channel; member;
728 member = member->next_channel) {
729 if (!IsVoicedOrOpped(member) &&
730 (is_banned(member) ||
731 (member->channel->mode.mode & MODE_MODERATED)))
732 return member->channel->chname;
739 /** Fill mbuf/pbuf with modes from chptr
740 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
741 * with the parameters in pbuf as visible by cptr.
743 * This function will hide keys from non-op'd, non-server clients.
745 * @param cptr The client to generate the mode for.
746 * @param mbuf The buffer to write the modes into.
747 * @param pbuf The buffer to write the mode parameters into.
748 * @param buflen The length of the buffers.
749 * @param chptr The channel to get the modes from.
750 * @param member The membership of this client on this channel (or NULL
751 * if this client isn't on this channel)
754 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
755 struct Channel *chptr, struct Membership *member)
757 int previous_parameter = 0;
764 if (chptr->mode.mode & MODE_SECRET)
766 else if (chptr->mode.mode & MODE_PRIVATE)
768 if (chptr->mode.mode & MODE_MODERATED)
770 if (chptr->mode.mode & MODE_TOPICLIMIT)
772 if (chptr->mode.mode & MODE_INVITEONLY)
774 if (chptr->mode.mode & MODE_NOPRIVMSGS)
776 if (chptr->mode.mode & MODE_REGONLY)
778 if (chptr->mode.mode & MODE_DELJOINS)
780 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
782 if (chptr->mode.limit) {
784 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
785 previous_parameter = 1;
788 if (*chptr->mode.key) {
790 if (previous_parameter)
792 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
793 strcat(pbuf, chptr->mode.key);
796 previous_parameter = 1;
798 if (*chptr->mode.apass) {
800 if (previous_parameter)
802 if (IsServer(cptr)) {
803 strcat(pbuf, chptr->mode.apass);
806 previous_parameter = 1;
808 if (*chptr->mode.upass) {
810 if (previous_parameter)
812 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
813 strcat(pbuf, chptr->mode.upass);
820 /** Compare two members oplevel
822 * @param mp1 Pointer to a pointer to a membership
823 * @param mp2 Pointer to a pointer to a membership
825 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
829 int compare_member_oplevel(const void *mp1, const void *mp2)
831 struct Membership const* member1 = *(struct Membership const**)mp1;
832 struct Membership const* member2 = *(struct Membership const**)mp2;
833 if (member1->oplevel == member2->oplevel)
835 return (member1->oplevel < member2->oplevel) ? -1 : 1;
838 /* send "cptr" a full list of the modes for channel chptr.
840 * Sends a BURST line to cptr, bursting all the modes for the channel.
842 * @param cptr Client pointer
843 * @param chptr Channel pointer
845 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
847 /* The order in which modes are generated is now mandatory */
848 static unsigned int current_flags[4] =
849 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
855 struct Membership* member;
857 char modebuf[MODEBUFLEN];
858 char parabuf[MODEBUFLEN];
860 int number_of_ops = 0;
861 int opped_members_index = 0;
862 struct Membership** opped_members = NULL;
863 int last_oplevel = 0;
864 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
869 if (IsLocalChannel(chptr->chname))
872 member = chptr->members;
873 lp2 = chptr->banlist;
875 *modebuf = *parabuf = '\0';
876 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
878 for (first = 1; full; first = 0) /* Loop for multiple messages */
880 full = 0; /* Assume by default we get it
881 all in one message */
883 /* (Continued) prefix: "<Y> B <channel> <TS>" */
884 /* is there any better way we can do this? */
885 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
886 chptr->creationtime);
888 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
891 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
892 msgq_append(&me, mb, " %s", modebuf);
895 msgq_append(&me, mb, " %s", parabuf);
899 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
901 * First find all opless members.
902 * Run 2 times over all members, to group the members with
903 * and without voice together.
904 * Then run 2 times over all opped members (which are ordered
905 * by op-level) to also group voice and non-voice together.
907 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
911 if (flag_cnt < 2 && IsChanOp(member))
914 * The first loop (to find all non-voice/op), we count the ops.
915 * The second loop (to find all voiced non-ops), store the ops
916 * in a dynamic array.
921 opped_members[opped_members_index++] = member;
923 /* Only handle the members with the flags that we are interested in. */
924 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
926 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
927 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
929 full = 1; /* Make sure we continue after
931 /* Ensure the new BURST line contains the current
932 * ":mode", except when there is no mode yet. */
933 new_mode = (flag_cnt > 0) ? 1 : 0;
934 break; /* Do not add this member to this message */
936 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
937 first = 0; /* From now on, use commas to add new nicks */
940 * Do we have a nick with a new mode ?
941 * Or are we starting a new BURST line?
943 if (new_mode || !feat_oplevels)
946 * This means we are at the _first_ member that has only
947 * voice, or the first member that has only ops, or the
948 * first member that has voice and ops (so we get here
949 * at most three times, plus once for every start of
950 * a continued BURST line where only these modes is current.
951 * In the two cases where the current mode includes ops,
952 * we need to add the _absolute_ value of the oplevel to the mode.
954 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
957 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
959 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
961 /* append the absolute value of the oplevel */
963 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
968 msgq_append(&me, mb, tbuf);
971 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
974 * This can't be the first member of a (continued) BURST
975 * message because then either flag_cnt == 0 or new_mode == 1
976 * Now we need to append the incremental value of the oplevel.
978 char tbuf[2 + MAXOPLEVELDIGITS];
979 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
980 last_oplevel = member->oplevel;
981 msgq_append(&me, mb, tbuf);
984 /* Go to the next `member'. */
986 member = member->next_member;
988 member = opped_members[++opped_members_index];
993 /* Point `member' at the start of the list again. */
996 member = chptr->members;
997 /* Now, after one loop, we know the number of ops and can
998 * allocate the dynamic array with pointer to the ops. */
999 opped_members = (struct Membership**)
1000 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1001 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1005 /* At the end of the second loop, sort the opped members with
1006 * increasing op-level, so that we will output them in the
1007 * correct order (and all op-level increments stay positive) */
1009 qsort(opped_members, number_of_ops,
1010 sizeof(struct Membership*), compare_member_oplevel);
1011 /* The third and fourth loop run only over the opped members. */
1012 member = opped_members[(opped_members_index = 0)];
1015 } /* loop over 0,+v,+o,+ov */
1019 /* Attach all bans, space seperated " :%ban ban ..." */
1020 for (first = 2; lp2; lp2 = lp2->next)
1022 len = strlen(lp2->banstr);
1023 if (msgq_bufleft(mb) < len + 1 + first)
1024 /* The +1 stands for the added ' '.
1025 * The +first stands for the added ":%".
1031 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1037 send_buffer(cptr, mb, 0); /* Send this message */
1039 } /* Continue when there was something
1040 that didn't fit (full==1) */
1042 MyFree(opped_members);
1043 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1044 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1045 chptr->creationtime, chptr->topic_time, chptr->topic);
1048 /** Canonify a mask.
1051 * @author Carlo Wood (Run),
1054 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1055 * When the user name or host name are too long (USERLEN and HOSTLEN
1056 * respectively) then they are cut off at the start with a '*'.
1058 * The following transformations are made:
1060 * 1) xxx -> nick!*@*
1061 * 2) xxx.xxx -> *!*\@host
1062 * 3) xxx\!yyy -> nick!user\@*
1063 * 4) xxx\@yyy -> *!user\@host
1064 * 5) xxx!yyy\@zzz -> nick!user\@host
1066 * @param mask The uncanonified mask.
1067 * @returns The updated mask in a static buffer.
1069 char *pretty_mask(char *mask)
1071 static char star[2] = { '*', 0 };
1072 static char retmask[NICKLEN + USERLEN + HOSTLEN + 3];
1073 char *last_dot = NULL;
1076 /* Case 1: default */
1081 /* Do a _single_ pass through the characters of the mask: */
1082 for (ptr = mask; *ptr; ++ptr)
1086 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1090 else if (*ptr == '@')
1092 /* Case 4: Found last '@' (without finding a '!' yet) */
1097 else if (*ptr == '.')
1099 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1109 /* Case 4 or 5: Found last '@' */
1115 if (user == star && last_dot)
1125 char *nick_end = (user != star) ? user - 1 : ptr;
1126 if (nick_end - nick > NICKLEN)
1132 char *user_end = (host != star) ? host - 1 : ptr;
1133 if (user_end - user > USERLEN)
1135 user = user_end - USERLEN;
1140 if (host != star && ptr - host > HOSTLEN)
1142 host = ptr - HOSTLEN;
1145 ircd_snprintf(0, retmask, sizeof(retmask), "%s!%s@%s", nick, user, host);
1149 /** send a banlist to a client for a channel
1151 * @param cptr Client to send the banlist to.
1152 * @param chptr Channel whose banlist to send.
1154 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1161 for (lp = chptr->banlist; lp; lp = lp->next)
1162 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
1165 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1168 /** Check a key against a keyring.
1169 * We are now treating the key part of /join channellist key as a key
1170 * ring; that is, we try one key against the actual channel key, and if that
1171 * doesn't work, we try the next one, and so on. -Kev -Texaco
1172 * Returns: 0 on match, 1 otherwise
1173 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1175 * @param key Key to check
1176 * @param keyring Comma seperated list of keys
1178 * @returns True if the key was found and matches, false otherwise.
1180 static int compall(char *key, char *keyring)
1185 p1 = key; /* point to the key... */
1186 while (*p1 && *p1 == *keyring)
1187 { /* step through the key and ring until they
1193 if (!*p1 && (!*keyring || *keyring == ','))
1194 /* ok, if we're at the end of the and also at the end of one of the keys
1195 in the keyring, we have a match */
1198 if (!*keyring) /* if we're at the end of the key ring, there
1199 weren't any matches, so we return 1 */
1202 /* Not at the end of the key ring, so step
1203 through to the next key in the ring: */
1204 while (*keyring && *(keyring++) != ',');
1206 goto top; /* and check it against the key */
1209 /** Returns if a user can join a channel with a specific key.
1211 * @param sptr The client trying to join
1212 * @param chptr The channel to join
1213 * @param key The key to use
1215 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1216 * if the oper used the magic key, 0 if no error occured.
1218 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1220 int overrideJoin = 0;
1223 * Now a banned user CAN join if invited -- Nemesi
1224 * Now a user CAN escape channel limit if invited -- bfriendly
1225 * Now a user CAN escape anything if invited -- Isomer
1228 if (IsInvited(sptr, chptr))
1231 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1232 a HACK(4) notice will be sent if he would not have been supposed
1233 to join normally. */
1234 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1235 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1236 compall("OVERRIDE",key) == 0)
1237 overrideJoin = MAGIC_OPER_OVERRIDE;
1239 if (chptr->mode.mode & MODE_INVITEONLY)
1240 return overrideJoin + ERR_INVITEONLYCHAN;
1242 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1243 return overrideJoin + ERR_CHANNELISFULL;
1245 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1246 return overrideJoin + ERR_NEEDREGGEDNICK;
1248 if (find_ban(sptr, chptr->banlist))
1249 return overrideJoin + ERR_BANNEDFROMCHAN;
1252 * now using compall (above) to test against a whole key ring -Kev
1254 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1255 return overrideJoin + ERR_BADCHANNELKEY;
1258 return ERR_DONTCHEAT;
1263 /** Remove bells and commas from channel name
1265 * @param cn Channel name to clean, modified in place.
1267 void clean_channelname(char *cn)
1271 for (i = 0; cn[i]; i++) {
1272 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1276 if (IsChannelLower(cn[i])) {
1277 cn[i] = ToLower(cn[i]);
1283 if ((unsigned char)(cn[i]) == 0xd0)
1284 cn[i] = (char) 0xf0;
1290 /** Get a channel block, creating if necessary.
1291 * Get Channel block for chname (and allocate a new channel
1292 * block, if it didn't exists before).
1294 * @param cptr Client joining the channel.
1295 * @param chname The name of the channel to join.
1296 * @param flag set to CGT_CREATE to create the channel if it doesn't
1299 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1300 * wasn't specified or a pointer to the channel structure
1302 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1304 struct Channel *chptr;
1307 if (EmptyString(chname))
1310 len = strlen(chname);
1311 if (MyUser(cptr) && len > CHANNELLEN)
1314 *(chname + CHANNELLEN) = '\0';
1316 if ((chptr = FindChannel(chname)))
1318 if (flag == CGT_CREATE)
1320 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1322 ++UserStats.channels;
1323 memset(chptr, 0, sizeof(struct Channel));
1324 strcpy(chptr->chname, chname);
1325 if (GlobalChannelList)
1326 GlobalChannelList->prev = chptr;
1328 chptr->next = GlobalChannelList;
1329 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1330 GlobalChannelList = chptr;
1336 /** invite a user to a channel.
1338 * Adds an invite for a user to a channel. Limits the number of invites
1339 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1341 * @param cptr The client to be invited.
1342 * @param chptr The channel to be invited to.
1344 void add_invite(struct Client *cptr, struct Channel *chptr)
1346 struct SLink *inv, **tmp;
1348 del_invite(cptr, chptr);
1350 * Delete last link in chain if the list is max length
1352 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1353 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1354 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1356 * Add client to channel invite list
1359 inv->value.cptr = cptr;
1360 inv->next = chptr->invites;
1361 chptr->invites = inv;
1363 * Add channel to the end of the client invite list
1365 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1367 inv->value.chptr = chptr;
1370 (cli_user(cptr))->invites++;
1373 /** Delete an invite
1374 * Delete Invite block from channel invite list and client invite list
1376 * @param cptr Client pointer
1377 * @param chptr Channel pointer
1379 void del_invite(struct Client *cptr, struct Channel *chptr)
1381 struct SLink **inv, *tmp;
1383 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1384 if (tmp->value.cptr == cptr)
1389 (cli_user(cptr))->invites--;
1393 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1394 if (tmp->value.chptr == chptr)
1403 /** @page zombie Explaination of Zombies
1411 * X --a--> A --b--> B --d--> D
1416 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1417 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1419 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1420 * Remove the user immediately when no users are left on the channel.
1421 * b) On server B : remove the user (who/lp) from the channel, send a
1422 * PART upstream (to A) and pass on the KICK.
1423 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1424 * channel, and pass on the KICK.
1425 * d) On server D : remove the user (who/lp) from the channel, and pass on
1429 * - Setting the ZOMBIE flag never hurts, we either remove the
1430 * client after that or we don't.
1431 * - The KICK message was already passed on, as should be in all cases.
1432 * - `who' is removed in all cases except case a) when users are left.
1433 * - A PART is only sent upstream in case b).
1439 * 1 --- 2 --- 3 --- 4 --- 5
1444 * We also need to turn 'who' into a zombie on servers 1 and 6,
1445 * because a KICK from 'who' (kicking someone else in that direction)
1446 * can arrive there afterwards - which should not be bounced itself.
1447 * Therefore case a) also applies for servers 1 and 6.
1452 /** Turn a user on a channel into a zombie
1453 * This function turns a user into a zombie (see \ref zombie)
1455 * @param member The structure representing this user on this channel.
1456 * @param who The client that is being kicked.
1457 * @param cptr The connection the kick came from.
1458 * @param sptr The client that is doing the kicking.
1459 * @param chptr The channel the user is being kicked from.
1461 void make_zombie(struct Membership* member, struct Client* who,
1462 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1464 assert(0 != member);
1469 /* Default for case a): */
1472 /* Case b) or c) ?: */
1473 if (MyUser(who)) /* server 4 */
1475 if (IsServer(cptr)) /* Case b) ? */
1476 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1477 remove_user_from_channel(who, chptr);
1480 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1482 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1483 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1484 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1486 remove_user_from_channel(who, chptr);
1491 /* Case a) (servers 1, 2, 3 and 6) */
1492 if (channel_all_zombies(chptr))
1493 remove_user_from_channel(who, chptr);
1495 /* XXX Can't actually call Debug here; if the channel is all zombies,
1496 * chptr will no longer exist when we get here.
1497 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1501 /** returns the number of zombies on a channel
1502 * @param chptr Channel to count zombies in.
1504 * @returns The number of zombies on the channel.
1506 int number_of_zombies(struct Channel *chptr)
1508 struct Membership* member;
1512 for (member = chptr->members; member; member = member->next_member) {
1513 if (IsZombie(member))
1519 /** Concatenate some strings together.
1520 * This helper function builds an argument string in strptr, consisting
1521 * of the original string, a space, and str1 and str2 concatenated (if,
1522 * of course, str2 is not NULL)
1524 * @param strptr The buffer to concatenate into
1525 * @param strptr_i modified offset to the position to modify
1526 * @param str1 The string to contatenate from.
1527 * @param str2 The second string to contatenate from.
1528 * @param c Charactor to seperate the string from str1 and str2.
1531 build_string(char *strptr, int *strptr_i, const char *str1,
1532 const char *str2, char c)
1535 strptr[(*strptr_i)++] = c;
1538 strptr[(*strptr_i)++] = *(str1++);
1542 strptr[(*strptr_i)++] = *(str2++);
1544 strptr[(*strptr_i)] = '\0';
1547 /** Flush out the modes
1548 * This is the workhorse of our ModeBuf suite; this actually generates the
1549 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1551 * @param mbuf The mode buffer to flush
1552 * @param all If true, flush all modes, otherwise leave partial modes in the
1558 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1560 /* we only need the flags that don't take args right now */
1561 static int flags[] = {
1562 /* MODE_CHANOP, 'o', */
1563 /* MODE_VOICE, 'v', */
1566 MODE_MODERATED, 'm',
1567 MODE_TOPICLIMIT, 't',
1568 MODE_INVITEONLY, 'i',
1569 MODE_NOPRIVMSGS, 'n',
1572 MODE_WASDELJOINS, 'd',
1573 /* MODE_KEY, 'k', */
1574 /* MODE_BAN, 'b', */
1576 /* MODE_APASS, 'A', */
1577 /* MODE_UPASS, 'U', */
1583 struct Client *app_source; /* where the MODE appears to come from */
1585 char addbuf[20]; /* accumulates +psmtin, etc. */
1587 char rembuf[20]; /* accumulates -psmtin, etc. */
1589 char *bufptr; /* we make use of indirection to simplify the code */
1592 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1594 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1596 char *strptr; /* more indirection to simplify the code */
1599 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1602 char limitbuf[20]; /* convert limits to strings */
1604 unsigned int limitdel = MODE_LIMIT;
1608 /* If the ModeBuf is empty, we have nothing to do */
1609 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1612 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1614 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1617 app_source = mbuf->mb_source;
1620 * Account for user we're bouncing; we have to get it in on the first
1621 * bounced MODE, or we could have problems
1623 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1624 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1626 /* Calculate the simple flags */
1627 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1628 if (*flag_p & mbuf->mb_add)
1629 addbuf[addbuf_i++] = flag_p[1];
1630 else if (*flag_p & mbuf->mb_rem)
1631 rembuf[rembuf_i++] = flag_p[1];
1634 /* Now go through the modes with arguments... */
1635 for (i = 0; i < mbuf->mb_count; i++) {
1636 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1638 bufptr_i = &addbuf_i;
1641 bufptr_i = &rembuf_i;
1644 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1645 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1647 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1648 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1650 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1651 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1653 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1654 tmp = strlen(MB_STRING(mbuf, i));
1656 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1657 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1660 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1672 bufptr[(*bufptr_i)++] = mode_char;
1673 totalbuflen -= tmp + 1;
1675 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1676 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1677 strlen(MB_STRING(mbuf, i)));
1679 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1680 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1682 bufptr[(*bufptr_i)++] = 'k';
1683 totalbuflen -= tmp + 1;
1685 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1686 /* if it's a limit, we also format the number */
1687 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1689 tmp = strlen(limitbuf);
1691 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1692 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1694 bufptr[(*bufptr_i)++] = 'l';
1695 totalbuflen -= tmp + 1;
1700 /* terminate the mode strings */
1701 addbuf[addbuf_i] = '\0';
1702 rembuf[rembuf_i] = '\0';
1704 /* If we're building a user visible MODE or HACK... */
1705 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1706 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1707 MODEBUF_DEST_LOG)) {
1708 /* Set up the parameter strings */
1714 for (i = 0; i < mbuf->mb_count; i++) {
1715 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1718 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1720 strptr_i = &addstr_i;
1723 strptr_i = &remstr_i;
1726 /* deal with clients... */
1727 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1728 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1730 /* deal with bans... */
1731 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1732 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1734 /* deal with keys... */
1735 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1736 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1737 "*" : MB_STRING(mbuf, i), 0, ' ');
1739 /* deal with invisible passwords */
1740 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1741 build_string(strptr, strptr_i, "*", 0, ' ');
1744 * deal with limit; note we cannot include the limit parameter if we're
1747 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1748 (MODE_ADD | MODE_LIMIT))
1749 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1752 /* send the messages off to their destination */
1753 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1754 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1756 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1757 mbuf->mb_source : app_source),
1758 mbuf->mb_channel->chname,
1759 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1760 addbuf, remstr, addstr,
1761 mbuf->mb_channel->creationtime);
1763 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1764 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1765 "%s%s%s%s%s%s [%Tu]",
1766 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1767 mbuf->mb_source : app_source),
1768 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1769 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1770 mbuf->mb_channel->creationtime);
1772 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1773 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1775 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1776 mbuf->mb_source : app_source),
1777 mbuf->mb_channel->chname,
1778 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1779 addbuf, remstr, addstr,
1780 mbuf->mb_channel->creationtime);
1782 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1783 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1784 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1785 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1786 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1788 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1789 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1790 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1791 rembuf_i ? "-" : "", rembuf,
1792 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1795 /* Now are we supposed to propagate to other servers? */
1796 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1797 /* set up parameter string */
1804 * limit is supressed if we're removing it; we have to figure out which
1805 * direction is the direction for it to be removed, though...
1807 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1809 for (i = 0; i < mbuf->mb_count; i++) {
1810 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1813 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1815 strptr_i = &addstr_i;
1818 strptr_i = &remstr_i;
1821 /* deal with modes that take clients */
1822 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1823 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1825 /* deal with modes that take strings */
1826 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1827 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1830 * deal with the limit. Logic here is complicated; if HACK2 is set,
1831 * we're bouncing the mode, so sense is reversed, and we have to
1832 * include the original limit if it looks like it's being removed
1834 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1835 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1838 /* we were told to deop the source */
1839 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1840 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1841 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1842 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1844 /* mark that we've done this, so we don't do it again */
1845 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1848 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1849 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1850 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1851 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1852 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1853 addbuf, remstr, addstr);
1854 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1856 * If HACK2 was set, we're bouncing; we send the MODE back to the
1857 * connection we got it from with the senses reversed and a TS of 0;
1860 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1861 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1862 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1863 mbuf->mb_channel->creationtime);
1866 * We're propagating a normal MODE command to the rest of the network;
1867 * we send the actual channel TS unless this is a HACK3 or a HACK4
1869 if (IsServer(mbuf->mb_source))
1870 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1871 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1872 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1873 addbuf, remstr, addstr,
1874 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1875 mbuf->mb_channel->creationtime);
1877 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1878 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1879 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1880 addbuf, remstr, addstr);
1884 /* We've drained the ModeBuf... */
1889 /* reinitialize the mode-with-arg slots */
1890 for (i = 0; i < MAXMODEPARAMS; i++) {
1891 /* If we saved any, pack them down */
1892 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1893 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1894 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1896 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1898 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1899 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1901 MB_TYPE(mbuf, i) = 0;
1902 MB_UINT(mbuf, i) = 0;
1905 /* If we're supposed to flush it all, do so--all hail tail recursion */
1906 if (all && mbuf->mb_count)
1907 return modebuf_flush_int(mbuf, 1);
1912 /** Initialise a modebuf
1913 * This routine just initializes a ModeBuf structure with the information
1914 * needed and the options given.
1916 * @param mbuf The mode buffer to initialise.
1917 * @param source The client that is performing the mode.
1919 * @param chan The channel that the mode is being performed upon.
1923 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1924 struct Client *connect, struct Channel *chan, unsigned int dest)
1929 assert(0 != source);
1933 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1937 mbuf->mb_source = source;
1938 mbuf->mb_connect = connect;
1939 mbuf->mb_channel = chan;
1940 mbuf->mb_dest = dest;
1943 /* clear each mode-with-parameter slot */
1944 for (i = 0; i < MAXMODEPARAMS; i++) {
1945 MB_TYPE(mbuf, i) = 0;
1946 MB_UINT(mbuf, i) = 0;
1950 /** Append a new mode to a modebuf
1951 * This routine simply adds modes to be added or deleted; do a binary OR
1952 * with either MODE_ADD or MODE_DEL
1954 * @param mbuf Mode buffer
1955 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1958 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1961 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1963 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1964 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1965 MODE_DELJOINS | MODE_WASDELJOINS);
1967 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1970 if (mode & MODE_ADD) {
1971 mbuf->mb_rem &= ~mode;
1972 mbuf->mb_add |= mode;
1974 mbuf->mb_add &= ~mode;
1975 mbuf->mb_rem |= mode;
1979 /** Append a mode that takes an int argument to the modebuf
1981 * This routine adds a mode to be added or deleted that takes a unsigned
1982 * int parameter; mode may *only* be the relevant mode flag ORed with one
1983 * of MODE_ADD or MODE_DEL
1985 * @param mbuf The mode buffer to append to.
1986 * @param mode The mode to append.
1987 * @param uint The argument to the mode.
1990 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1993 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1995 if (mode == (MODE_LIMIT | MODE_DEL)) {
1996 mbuf->mb_rem |= mode;
1999 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2000 MB_UINT(mbuf, mbuf->mb_count) = uint;
2002 /* when we've reached the maximal count, flush the buffer */
2003 if (++mbuf->mb_count >=
2004 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2005 modebuf_flush_int(mbuf, 0);
2008 /** append a string mode
2009 * This routine adds a mode to be added or deleted that takes a string
2010 * parameter; mode may *only* be the relevant mode flag ORed with one of
2011 * MODE_ADD or MODE_DEL
2013 * @param mbuf The mode buffer to append to.
2014 * @param mode The mode to append.
2015 * @param string The string parameter to append.
2016 * @param free If the string should be free'd later.
2019 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2023 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2025 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2026 MB_STRING(mbuf, mbuf->mb_count) = string;
2028 /* when we've reached the maximal count, flush the buffer */
2029 if (++mbuf->mb_count >=
2030 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2031 modebuf_flush_int(mbuf, 0);
2034 /** Append a mode on a client to a modebuf.
2035 * This routine adds a mode to be added or deleted that takes a client
2036 * parameter; mode may *only* be the relevant mode flag ORed with one of
2037 * MODE_ADD or MODE_DEL
2039 * @param mbuf The modebuf to append the mode to.
2040 * @param mode The mode to append.
2041 * @param client The client argument to append.
2044 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2045 struct Client *client)
2048 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2050 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2051 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2053 /* when we've reached the maximal count, flush the buffer */
2054 if (++mbuf->mb_count >=
2055 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2056 modebuf_flush_int(mbuf, 0);
2059 /** The exported binding for modebuf_flush()
2061 * @param mbuf The mode buffer to flush.
2063 * @see modebuf_flush_int()
2066 modebuf_flush(struct ModeBuf *mbuf)
2068 struct Membership *memb;
2070 /* Check if MODE_WASDELJOINS should be set */
2071 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2072 && (mbuf->mb_rem & MODE_DELJOINS)) {
2073 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2074 if (IsDelayedJoin(memb)) {
2075 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2076 mbuf->mb_add |= MODE_WASDELJOINS;
2077 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2083 return modebuf_flush_int(mbuf, 1);
2086 /* This extracts the simple modes contained in mbuf
2088 * @param mbuf The mode buffer to extract the modes from.
2089 * @param buf The string buffer to write the modes into.
2092 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2094 static int flags[] = {
2095 /* MODE_CHANOP, 'o', */
2096 /* MODE_VOICE, 'v', */
2099 MODE_MODERATED, 'm',
2100 MODE_TOPICLIMIT, 't',
2101 MODE_INVITEONLY, 'i',
2102 MODE_NOPRIVMSGS, 'n',
2106 /* MODE_BAN, 'b', */
2113 int i, bufpos = 0, len;
2115 char *key = 0, limitbuf[20];
2116 char *apass = 0, *upass = 0;
2125 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2126 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2127 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2129 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2130 key = MB_STRING(mbuf, i);
2131 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2132 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2133 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2134 upass = MB_STRING(mbuf, i);
2135 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2136 apass = MB_STRING(mbuf, i);
2143 buf[bufpos++] = '+'; /* start building buffer */
2145 for (flag_p = flags; flag_p[0]; flag_p += 2)
2147 buf[bufpos++] = flag_p[1];
2149 for (i = 0, len = bufpos; i < len; i++) {
2151 build_string(buf, &bufpos, key, 0, ' ');
2152 else if (buf[i] == 'l')
2153 build_string(buf, &bufpos, limitbuf, 0, ' ');
2154 else if (buf[i] == 'U')
2155 build_string(buf, &bufpos, upass, 0, ' ');
2156 else if (buf[i] == 'A')
2157 build_string(buf, &bufpos, apass, 0, ' ');
2165 /** Simple function to invalidate bans
2167 * This function sets all bans as being valid.
2169 * @param chan The channel to operate on.
2172 mode_ban_invalidate(struct Channel *chan)
2174 struct Membership *member;
2176 for (member = chan->members; member; member = member->next_member)
2177 ClearBanValid(member);
2180 /** Simple function to drop invite structures
2182 * Remove all the invites on the channel.
2184 * @param chan Channel to remove invites from.
2188 mode_invite_clear(struct Channel *chan)
2190 while (chan->invites)
2191 del_invite(chan->invites->value.cptr, chan);
2194 /* What we've done for mode_parse so far... */
2195 #define DONE_LIMIT 0x01 /**< We've set the limit */
2196 #define DONE_KEY 0x02 /**< We've set the key */
2197 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2198 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2199 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2200 #define DONE_UPASS 0x20 /**< We've set user pass */
2201 #define DONE_APASS 0x40 /**< We've set admin pass */
2204 struct ModeBuf *mbuf;
2205 struct Client *cptr;
2206 struct Client *sptr;
2207 struct Channel *chptr;
2208 struct Membership *member;
2219 struct Ban banlist[MAXPARA];
2222 struct Client *client;
2223 } cli_change[MAXPARA];
2226 /** Helper function to send "Not oper" or "Not member" messages
2227 * Here's a helper function to deal with sending along "Not oper" or
2228 * "Not member" messages
2230 * @param state Parsing State object
2233 send_notoper(struct ParseState *state)
2235 if (state->done & DONE_NOTOPER)
2238 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2239 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2241 state->done |= DONE_NOTOPER;
2245 * Helper function to convert limits
2247 * @param state Parsing state object.
2251 mode_parse_limit(struct ParseState *state, int *flag_p)
2253 unsigned int t_limit;
2255 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2256 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2259 if (state->parc <= 0) { /* warn if not enough args */
2260 if (MyUser(state->sptr))
2261 need_more_params(state->sptr, "MODE +l");
2265 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2269 if ((int)t_limit<0) /* don't permit a negative limit */
2272 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2273 (!t_limit || t_limit == state->chptr->mode.limit))
2276 t_limit = state->chptr->mode.limit;
2278 /* If they're not an oper, they can't change modes */
2279 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2280 send_notoper(state);
2284 /* Can't remove a limit that's not there */
2285 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2288 /* Skip if this is a burst and a lower limit than this is set already */
2289 if ((state->flags & MODE_PARSE_BURST) &&
2290 (state->chptr->mode.mode & flag_p[0]) &&
2291 (state->chptr->mode.limit < t_limit))
2294 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2296 state->done |= DONE_LIMIT;
2301 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2303 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2304 if (state->dir & MODE_ADD) {
2305 state->chptr->mode.mode |= flag_p[0];
2306 state->chptr->mode.limit = t_limit;
2308 state->chptr->mode.mode &= ~flag_p[0];
2309 state->chptr->mode.limit = 0;
2315 * Helper function to convert keys
2318 mode_parse_key(struct ParseState *state, int *flag_p)
2323 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2326 if (state->parc <= 0) { /* warn if not enough args */
2327 if (MyUser(state->sptr))
2328 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2333 t_str = state->parv[state->args_used++]; /* grab arg */
2337 /* If they're not an oper, they can't change modes */
2338 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2339 send_notoper(state);
2343 if (state->done & DONE_KEY) /* allow key to be set only once */
2345 state->done |= DONE_KEY;
2349 /* clean up the key string */
2351 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2355 if (!*t_str) { /* warn if empty */
2356 if (MyUser(state->sptr))
2357 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2365 /* Skip if this is a burst, we have a key already and the new key is
2366 * after the old one alphabetically */
2367 if ((state->flags & MODE_PARSE_BURST) &&
2368 *(state->chptr->mode.key) &&
2369 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2372 /* can't add a key if one is set, nor can one remove the wrong key */
2373 if (!(state->flags & MODE_PARSE_FORCE))
2374 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2375 (state->dir == MODE_DEL &&
2376 ircd_strcmp(state->chptr->mode.key, t_str))) {
2377 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2381 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2382 !ircd_strcmp(state->chptr->mode.key, t_str))
2383 return; /* no key change */
2385 if (state->flags & MODE_PARSE_BOUNCE) {
2386 if (*state->chptr->mode.key) /* reset old key */
2387 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2388 state->chptr->mode.key, 0);
2389 else /* remove new bogus key */
2390 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2391 } else /* send new key */
2392 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2394 if (state->flags & MODE_PARSE_SET) {
2395 if (state->dir == MODE_ADD) /* set the new key */
2396 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2397 else /* remove the old key */
2398 *state->chptr->mode.key = '\0';
2403 * Helper function to convert user passes
2406 mode_parse_upass(struct ParseState *state, int *flag_p)
2411 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2414 if (state->parc <= 0) { /* warn if not enough args */
2415 if (MyUser(state->sptr))
2416 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2421 t_str = state->parv[state->args_used++]; /* grab arg */
2425 /* If they're not an oper, they can't change modes */
2426 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2427 send_notoper(state);
2431 /* If a non-service user is trying to force it, refuse. */
2432 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2433 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2434 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2438 /* If they are not the channel manager, they are not allowed to change it */
2439 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2440 if (*state->chptr->mode.apass) {
2441 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2442 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2444 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2445 "Re-create the channel. The channel must be *empty* for",
2446 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2447 "before it can be recreated.");
2452 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2454 state->done |= DONE_UPASS;
2456 t_len = PASSLEN + 1;
2458 /* clean up the upass string */
2460 while (*++s > ' ' && *s != ':' && --t_len)
2464 if (!*t_str) { /* warn if empty */
2465 if (MyUser(state->sptr))
2466 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2474 if (!(state->flags & MODE_PARSE_FORCE))
2475 /* can't add the upass while apass is not set */
2476 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2477 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2480 /* can't add a upass if one is set, nor can one remove the wrong upass */
2481 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2482 (state->dir == MODE_DEL &&
2483 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2484 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2488 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2489 !ircd_strcmp(state->chptr->mode.upass, t_str))
2490 return; /* no upass change */
2492 if (state->flags & MODE_PARSE_BOUNCE) {
2493 if (*state->chptr->mode.upass) /* reset old upass */
2494 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2495 state->chptr->mode.upass, 0);
2496 else /* remove new bogus upass */
2497 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2498 } else /* send new upass */
2499 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2501 if (state->flags & MODE_PARSE_SET) {
2502 if (state->dir == MODE_ADD) /* set the new upass */
2503 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2504 else /* remove the old upass */
2505 *state->chptr->mode.upass = '\0';
2510 * Helper function to convert admin passes
2513 mode_parse_apass(struct ParseState *state, int *flag_p)
2518 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2521 if (state->parc <= 0) { /* warn if not enough args */
2522 if (MyUser(state->sptr))
2523 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2528 t_str = state->parv[state->args_used++]; /* grab arg */
2532 /* If they're not an oper, they can't change modes */
2533 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2534 send_notoper(state);
2538 /* If a non-service user is trying to force it, refuse. */
2539 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2540 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2541 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2545 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2546 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2547 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2551 /* If they are not the channel manager, they are not allowed to change it */
2552 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2553 if (*state->chptr->mode.apass) {
2554 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2555 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2557 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2558 "Re-create the channel. The channel must be *empty* for",
2559 "at least a whole minute", "before it can be recreated.");
2564 if (state->done & DONE_APASS) /* allow apass to be set only once */
2566 state->done |= DONE_APASS;
2568 t_len = PASSLEN + 1;
2570 /* clean up the apass string */
2572 while (*++s > ' ' && *s != ':' && --t_len)
2576 if (!*t_str) { /* warn if empty */
2577 if (MyUser(state->sptr))
2578 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2586 if (!(state->flags & MODE_PARSE_FORCE)) {
2587 /* can't remove the apass while upass is still set */
2588 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2589 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2592 /* can't add an apass if one is set, nor can one remove the wrong apass */
2593 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2594 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2595 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2600 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2601 !ircd_strcmp(state->chptr->mode.apass, t_str))
2602 return; /* no apass change */
2604 if (state->flags & MODE_PARSE_BOUNCE) {
2605 if (*state->chptr->mode.apass) /* reset old apass */
2606 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2607 state->chptr->mode.apass, 0);
2608 else /* remove new bogus apass */
2609 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2610 } else /* send new apass */
2611 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2613 if (state->flags & MODE_PARSE_SET) {
2614 if (state->dir == MODE_ADD) { /* set the new apass */
2615 /* Make it VERY clear to the user that this is a one-time password */
2616 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2617 if (MyUser(state->sptr)) {
2618 send_reply(state->sptr, RPL_APASSWARN,
2619 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2620 "Are you SURE you want to use this as Admin password? ",
2621 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2622 send_reply(state->sptr, RPL_APASSWARN,
2623 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2624 "\" to remove the password and then immediately set a new one. "
2625 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2626 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2627 "Now set the channel user password (+u).");
2629 } else { /* remove the old apass */
2630 *state->chptr->mode.apass = '\0';
2631 if (MyUser(state->sptr))
2632 send_reply(state->sptr, RPL_APASSWARN,
2633 "WARNING: You removed the channel Admin password MODE (+A). ",
2634 "If you would disconnect or leave the channel without setting a new password then you will ",
2635 "not be able to set it again and lose ownership of this channel! ",
2636 "SET A NEW PASSWORD NOW!", "");
2641 /** Compare one ban's extent to another.
2642 * This works very similarly to mmatch() but it knows about CIDR masks
2643 * and ban exceptions. If both bans are CIDR-based, compare their
2644 * address bits; otherwise, use mmatch().
2645 * @param[in] old_ban One ban.
2646 * @param[in] new_ban Another ban.
2647 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2650 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2653 assert(old_ban != NULL);
2654 assert(new_ban != NULL);
2655 /* A ban is never treated as a superset of an exception. */
2656 if (!(old_ban->flags & BAN_EXCEPTION)
2657 && (new_ban->flags & BAN_EXCEPTION))
2659 /* If either is not an address mask, match the text masks. */
2660 if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2661 return mmatch(old_ban->banstr, new_ban->banstr);
2662 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2663 if (old_ban->addrbits > new_ban->addrbits)
2665 /* Compare the masks before the hostname part. */
2666 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2667 res = mmatch(old_ban->banstr, new_ban->banstr);
2668 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2671 /* Compare the addresses. */
2672 return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2675 /** Add a ban from a ban list and mark bans that should be removed
2676 * because they overlap.
2678 * There are three invariants for a ban list. First, no ban may be
2679 * more specific than another ban. Second, no exception may be more
2680 * specific than another exception. Finally, no ban may be more
2681 * specific than any exception.
2683 * @param[in,out] banlist Pointer to head of list.
2684 * @param[in] newban Ban (or exception) to add (or remove).
2685 * @return Zero if \a newban could be applied, non-zero if not.
2687 int apply_ban(struct Ban **banlist, struct Ban *newban)
2692 assert(newban->flags & (BAN_ADD|BAN_DEL));
2693 if (newban->flags & BAN_ADD) {
2695 /* If a less specific entry is found, fail. */
2696 for (ban = *banlist; ban; ban = ban->next) {
2697 if (!bmatch(ban, newban)) {
2701 if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2703 totlen += strlen(ban->banstr);
2706 /* Mark more specific entries and add this one to the end of the list. */
2707 while ((ban = *banlist) != NULL) {
2708 if (!bmatch(newban, ban)) {
2709 ban->flags |= BAN_OVERLAPPED;
2711 banlist = &ban->next;
2715 } else if (newban->flags & BAN_DEL) {
2716 size_t remove_count = 0;
2717 /* Mark more specific entries. */
2718 for (ban = *banlist; ban; ban = ban->next) {
2719 if (!bmatch(newban, ban)) {
2720 ban->flags |= BAN_OVERLAPPED;
2724 /* If no matches were found, fail. */
2725 if (!remove_count) {
2736 * Helper function to convert bans
2739 mode_parse_ban(struct ParseState *state, int *flag_p)
2742 struct Ban *ban, *newban = 0;
2744 if (state->parc <= 0) { /* Not enough args, send ban list */
2745 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2746 send_ban_list(state->sptr, state->chptr);
2747 state->done |= DONE_BANLIST;
2753 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2756 t_str = state->parv[state->args_used++]; /* grab arg */
2760 /* If they're not an oper, they can't change modes */
2761 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2762 send_notoper(state);
2766 if ((s = strchr(t_str, ' ')))
2769 if (!*t_str || *t_str == ':') { /* warn if empty */
2770 if (MyUser(state->sptr))
2771 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2776 if (!state->chptr->banlist) {
2777 state->chptr->banlist = newban; /* add our ban with its flags */
2778 state->done |= DONE_BANCLEAN;
2782 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2783 if (!(state->done & DONE_BANCLEAN)) {
2784 for (ban = state->chptr->banlist; ban; ban = ban->next)
2785 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2786 state->done |= DONE_BANCLEAN;
2789 /* remember the ban for the moment... */
2790 newban = state->banlist + (state->numbans++);
2792 newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2793 | (*flag_p == 'b' ? 0 : BAN_EXCEPTION);
2794 set_ban_mask(newban, collapse(pretty_mask(t_str)));
2795 newban->who = cli_name(state->sptr);
2796 newban->when = TStime();
2797 apply_ban(&state->chptr->banlist, newban);
2801 * This is the bottom half of the ban processor
2804 mode_process_bans(struct ParseState *state)
2806 struct Ban *ban, *newban, *prevban, *nextban;
2812 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2814 banlen = strlen(ban->banstr);
2816 nextban = ban->next;
2818 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2820 prevban->next = 0; /* Break the list; ban isn't a real ban */
2822 state->chptr->banlist = 0;
2827 MyFree(ban->banstr);
2830 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2831 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2833 state->flags & MODE_PARSE_SET);
2835 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2836 if (prevban) /* clip it out of the list... */
2837 prevban->next = ban->next;
2839 state->chptr->banlist = ban->next;
2844 ban->banstr = NULL; /* modebuf_mode_string() gave ownership of
2845 * the ban string to state->mbuf */
2849 continue; /* next ban; keep prevban like it is */
2851 ban->flags &= BAN_IPMASK; /* unset other flags */
2852 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2854 prevban->next = 0; /* Break the list; ban isn't a real ban */
2856 state->chptr->banlist = 0;
2858 /* If we're supposed to ignore it, do so. */
2859 if (ban->flags & BAN_OVERLAPPED &&
2860 !(state->flags & MODE_PARSE_BOUNCE)) {
2863 MyFree(ban->banstr);
2865 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2866 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2867 count > feature_int(FEAT_MAXBANS))) {
2868 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2872 MyFree(ban->banstr);
2874 /* add the ban to the buffer */
2875 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2877 !(state->flags & MODE_PARSE_SET));
2879 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2880 newban = make_ban(ban->banstr);
2881 DupString(newban->who, ban->who);
2882 newban->when = ban->when;
2883 newban->flags = ban->flags & BAN_IPMASK;
2885 newban->next = state->chptr->banlist; /* and link it in */
2886 state->chptr->banlist = newban;
2895 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2897 if (changed) /* if we changed the ban list, we must invalidate the bans */
2898 mode_ban_invalidate(state->chptr);
2902 * Helper function to process client changes
2905 mode_parse_client(struct ParseState *state, int *flag_p)
2908 struct Client *acptr;
2911 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2914 if (state->parc <= 0) /* return if not enough args */
2917 t_str = state->parv[state->args_used++]; /* grab arg */
2921 /* If they're not an oper, they can't change modes */
2922 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2923 send_notoper(state);
2927 if (MyUser(state->sptr)) /* find client we're manipulating */
2928 acptr = find_chasing(state->sptr, t_str, NULL);
2930 acptr = findNUser(t_str);
2933 return; /* find_chasing() already reported an error to the user */
2935 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2936 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2937 state->cli_change[i].flag & flag_p[0]))
2938 break; /* found a slot */
2940 /* Store what we're doing to them */
2941 state->cli_change[i].flag = state->dir | flag_p[0];
2942 state->cli_change[i].client = acptr;
2946 * Helper function to process the changed client list
2949 mode_process_clients(struct ParseState *state)
2952 struct Membership *member;
2954 for (i = 0; state->cli_change[i].flag; i++) {
2955 assert(0 != state->cli_change[i].client);
2957 /* look up member link */
2958 if (!(member = find_member_link(state->chptr,
2959 state->cli_change[i].client)) ||
2960 (MyUser(state->sptr) && IsZombie(member))) {
2961 if (MyUser(state->sptr))
2962 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2963 cli_name(state->cli_change[i].client),
2964 state->chptr->chname);
2968 if ((state->cli_change[i].flag & MODE_ADD &&
2969 (state->cli_change[i].flag & member->status)) ||
2970 (state->cli_change[i].flag & MODE_DEL &&
2971 !(state->cli_change[i].flag & member->status)))
2972 continue; /* no change made, don't do anything */
2974 /* see if the deop is allowed */
2975 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2976 (MODE_DEL | MODE_CHANOP)) {
2977 /* prevent +k users from being deopped */
2978 if (IsChannelService(state->cli_change[i].client)) {
2979 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2980 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2982 (IsServer(state->sptr) ? cli_name(state->sptr) :
2983 cli_name((cli_user(state->sptr))->server)));
2985 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2986 send_reply(state->sptr, ERR_ISCHANSERVICE,
2987 cli_name(state->cli_change[i].client),
2988 state->chptr->chname);
2993 /* check deop for local user */
2994 if (MyUser(state->sptr)) {
2996 /* don't allow local opers to be deopped on local channels */
2997 if (state->cli_change[i].client != state->sptr &&
2998 IsLocalChannel(state->chptr->chname) &&
2999 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3000 send_reply(state->sptr, ERR_ISOPERLCHAN,
3001 cli_name(state->cli_change[i].client),
3002 state->chptr->chname);
3006 if (feature_bool(FEAT_OPLEVELS)) {
3007 /* don't allow to deop members with an op level that is <= our own level */
3008 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3010 && OpLevel(member) <= OpLevel(state->member)) {
3011 int equal = (OpLevel(member) == OpLevel(state->member));
3012 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3013 cli_name(state->cli_change[i].client),
3014 state->chptr->chname,
3015 OpLevel(state->member), OpLevel(member),
3016 "deop", equal ? "the same" : "a higher");
3023 /* set op-level of member being opped */
3024 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3025 (MODE_ADD | MODE_CHANOP)) {
3026 /* If on a channel with upass set, someone with level x gives ops to someone else,
3027 then that person gets level x-1. On other channels, where upass is not set,
3028 the level stays the same. */
3029 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3030 /* Someone being opped by a server gets op-level 0 */
3031 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3032 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3035 /* actually effect the change */
3036 if (state->flags & MODE_PARSE_SET) {
3037 if (state->cli_change[i].flag & MODE_ADD) {
3038 if (IsDelayedJoin(member))
3039 RevealDelayedJoin(member);
3040 member->status |= (state->cli_change[i].flag &
3041 (MODE_CHANOP | MODE_VOICE));
3042 if (state->cli_change[i].flag & MODE_CHANOP)
3043 ClearDeopped(member);
3045 member->status &= ~(state->cli_change[i].flag &
3046 (MODE_CHANOP | MODE_VOICE));
3049 /* accumulate the change */
3050 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3051 state->cli_change[i].client);
3052 } /* for (i = 0; state->cli_change[i].flags; i++) */
3056 * Helper function to process the simple modes
3059 mode_parse_mode(struct ParseState *state, int *flag_p)
3061 /* If they're not an oper, they can't change modes */
3062 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3063 send_notoper(state);
3070 if (state->dir == MODE_ADD) {
3071 state->add |= flag_p[0];
3072 state->del &= ~flag_p[0];
3074 if (flag_p[0] & MODE_SECRET) {
3075 state->add &= ~MODE_PRIVATE;
3076 state->del |= MODE_PRIVATE;
3077 } else if (flag_p[0] & MODE_PRIVATE) {
3078 state->add &= ~MODE_SECRET;
3079 state->del |= MODE_SECRET;
3081 if (flag_p[0] & MODE_DELJOINS) {
3082 state->add &= ~MODE_WASDELJOINS;
3083 state->del |= MODE_WASDELJOINS;
3086 state->add &= ~flag_p[0];
3087 state->del |= flag_p[0];
3090 assert(0 == (state->add & state->del));
3091 assert((MODE_SECRET | MODE_PRIVATE) !=
3092 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3096 * This routine is intended to parse MODE or OPMODE commands and effect the
3097 * changes (or just build the bounce buffer). We pass the starting offset
3101 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3102 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3103 struct Membership* member)
3105 static int chan_flags[] = {
3110 MODE_MODERATED, 'm',
3111 MODE_TOPICLIMIT, 't',
3112 MODE_INVITEONLY, 'i',
3113 MODE_NOPRIVMSGS, 'n',
3127 unsigned int t_mode;
3129 struct ParseState state;
3140 state.chptr = chptr;
3141 state.member = member;
3144 state.flags = flags;
3145 state.dir = MODE_ADD;
3149 state.args_used = 0;
3150 state.max_args = MAXMODEPARAMS;
3153 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3154 state.banlist[i].next = 0;
3155 state.banlist[i].who = 0;
3156 state.banlist[i].when = 0;
3157 state.banlist[i].flags = 0;
3158 state.cli_change[i].flag = 0;
3159 state.cli_change[i].client = 0;
3162 modestr = state.parv[state.args_used++];
3166 for (; *modestr; modestr++) {
3167 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3168 if (flag_p[1] == *modestr)
3171 if (!flag_p[0]) { /* didn't find it? complain and continue */
3172 if (MyUser(state.sptr))
3173 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3178 case '+': /* switch direction to MODE_ADD */
3179 case '-': /* switch direction to MODE_DEL */
3180 state.dir = flag_p[0];
3183 case 'l': /* deal with limits */
3184 mode_parse_limit(&state, flag_p);
3187 case 'k': /* deal with keys */
3188 mode_parse_key(&state, flag_p);
3191 case 'A': /* deal with Admin passes */
3192 if (feature_bool(FEAT_OPLEVELS))
3193 mode_parse_apass(&state, flag_p);
3196 case 'U': /* deal with user passes */
3197 if (feature_bool(FEAT_OPLEVELS))
3198 mode_parse_upass(&state, flag_p);
3201 case 'b': /* deal with bans */
3202 mode_parse_ban(&state, flag_p);
3205 case 'o': /* deal with ops/voice */
3207 mode_parse_client(&state, flag_p);
3210 default: /* deal with other modes */
3211 mode_parse_mode(&state, flag_p);
3213 } /* switch (*modestr) */
3214 } /* for (; *modestr; modestr++) */
3216 if (state.flags & MODE_PARSE_BURST)
3217 break; /* don't interpret any more arguments */
3219 if (state.parc > 0) { /* process next argument in string */
3220 modestr = state.parv[state.args_used++];
3224 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3227 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3228 break; /* we're then going to bounce the mode! */
3230 recv_ts = atoi(modestr);
3232 if (recv_ts && recv_ts < state.chptr->creationtime)
3233 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3235 break; /* break out of while loop */
3236 } else if (state.flags & MODE_PARSE_STRICT ||
3237 (MyUser(state.sptr) && state.max_args <= 0)) {
3238 state.parc++; /* we didn't actually gobble the argument */
3240 break; /* break out of while loop */
3243 } /* while (*modestr) */
3246 * the rest of the function finishes building resultant MODEs; if the
3247 * origin isn't a member or an oper, skip it.
3249 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3250 return state.args_used; /* tell our parent how many args we gobbled */
3252 t_mode = state.chptr->mode.mode;
3254 if (state.del & t_mode) { /* delete any modes to be deleted... */
3255 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3257 t_mode &= ~state.del;
3259 if (state.add & ~t_mode) { /* add any modes to be added... */
3260 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3262 t_mode |= state.add;
3265 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3266 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3267 !(t_mode & MODE_INVITEONLY))
3268 mode_invite_clear(state.chptr);
3270 state.chptr->mode.mode = t_mode;
3273 if (state.flags & MODE_PARSE_WIPEOUT) {
3274 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3275 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3276 state.chptr->mode.limit);
3277 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3278 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3279 state.chptr->mode.key, 0);
3280 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3281 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3282 state.chptr->mode.upass, 0);
3283 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3284 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3285 state.chptr->mode.apass, 0);
3288 if (state.done & DONE_BANCLEAN) /* process bans */
3289 mode_process_bans(&state);
3291 /* process client changes */
3292 if (state.cli_change[0].flag)
3293 mode_process_clients(&state);
3295 return state.args_used; /* tell our parent how many args we gobbled */
3299 * Initialize a join buffer
3302 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3303 struct Client *connect, unsigned int type, char *comment,
3309 assert(0 != source);
3310 assert(0 != connect);
3312 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3313 jbuf->jb_connect = connect;
3314 jbuf->jb_type = type;
3315 jbuf->jb_comment = comment;
3316 jbuf->jb_create = create;
3318 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3319 type == JOINBUF_TYPE_PART ||
3320 type == JOINBUF_TYPE_PARTALL) ?
3321 STARTJOINLEN : STARTCREATELEN) +
3322 (comment ? strlen(comment) + 2 : 0));
3324 for (i = 0; i < MAXJOINARGS; i++)
3325 jbuf->jb_channels[i] = 0;
3329 * Add a channel to the join buffer
3332 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3340 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3341 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3346 is_local = IsLocalChannel(chan->chname);
3348 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3349 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3350 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3351 if (IsUserParting(member))
3353 SetUserParting(member);
3355 /* Send notification to channel */
3356 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3357 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3358 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3359 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3360 else if (MyUser(jbuf->jb_source))
3361 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3362 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3363 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3364 /* XXX: Shouldn't we send a PART here anyway? */
3365 /* to users on the channel? Why? From their POV, the user isn't on
3366 * the channel anymore anyway. We don't send to servers until below,
3367 * when we gang all the channel parts together. Note that this is
3368 * exactly the same logic, albeit somewhat more concise, as was in
3369 * the original m_part.c */
3371 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3372 is_local) /* got to remove user here */
3373 remove_user_from_channel(jbuf->jb_source, chan);
3375 /* Add user to channel */
3376 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3377 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3379 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3381 /* send notification to all servers */
3382 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3383 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3384 "%H %Tu", chan, chan->creationtime);
3386 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3387 /* Send the notification to the channel */
3388 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3390 /* send an op, too, if needed */
3391 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3392 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3393 chan, jbuf->jb_source);
3394 } else if (MyUser(jbuf->jb_source))
3395 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3398 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3399 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3400 return; /* don't send to remote */
3402 /* figure out if channel name will cause buffer to be overflowed */
3403 len = chan ? strlen(chan->chname) + 1 : 2;
3404 if (jbuf->jb_strlen + len > BUFSIZE)
3405 joinbuf_flush(jbuf);
3407 /* add channel to list of channels to send and update counts */
3408 jbuf->jb_channels[jbuf->jb_count++] = chan;
3409 jbuf->jb_strlen += len;
3411 /* if we've used up all slots, flush */
3412 if (jbuf->jb_count >= MAXJOINARGS)
3413 joinbuf_flush(jbuf);
3417 * Flush the channel list to remote servers
3420 joinbuf_flush(struct JoinBuf *jbuf)
3422 char chanlist[BUFSIZE];
3426 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3427 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3428 return 0; /* no joins to process */
3430 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3431 build_string(chanlist, &chanlist_i,
3432 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3433 i == 0 ? '\0' : ',');
3434 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3435 /* Remove user from channel */
3436 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3438 jbuf->jb_channels[i] = 0; /* mark slot empty */
3441 jbuf->jb_count = 0; /* reset base counters */
3442 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3443 STARTJOINLEN : STARTCREATELEN) +
3444 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3446 /* and send the appropriate command */
3447 switch (jbuf->jb_type) {
3448 case JOINBUF_TYPE_CREATE:
3449 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3450 "%s %Tu", chanlist, jbuf->jb_create);
3453 case JOINBUF_TYPE_PART:
3454 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3455 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3463 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3464 int IsInvited(struct Client* cptr, const void* chptr)
3468 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3469 if (lp->value.chptr == chptr)
3474 /* RevealDelayedJoin: sends a join for a hidden user */
3476 void RevealDelayedJoin(struct Membership *member) {
3477 ClearDelayedJoin(member);
3478 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3480 CheckDelayedJoins(member->channel);
3483 /* CheckDelayedJoins: checks and clear +d if necessary */
3485 void CheckDelayedJoins(struct Channel *chan) {
3486 struct Membership *memb2;
3488 if (chan->mode.mode & MODE_WASDELJOINS) {
3489 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3490 if (IsDelayedJoin(memb2))
3495 chan->mode.mode &= ~MODE_WASDELJOINS;
3496 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,