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 (!(chptr->mode.mode & MODE_APASS)) /* If no Apass, destroy now. */
263 destruct_channel(chptr);
264 else if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
265 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
267 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
272 /** Destroy an empty channel
273 * This function destroys an empty channel, removing it from hashtables,
274 * and removing any resources it may have consumed.
276 * @param chptr The channel to destroy
278 * @returns 0 (success)
280 * FIXME: Change to return void, this function never fails.
282 int destruct_channel(struct Channel* chptr)
284 struct Ban *ban, *next;
286 assert(0 == chptr->members);
289 * Now, find all invite links from channel structure
291 while (chptr->invites)
292 del_invite(chptr->invites->value.cptr, chptr);
294 for (ban = chptr->banlist; ban; ban = next)
300 chptr->prev->next = chptr->next;
302 GlobalChannelList = chptr->next;
304 chptr->next->prev = chptr->prev;
306 --UserStats.channels;
308 * make sure that channel actually got removed from hash table
310 assert(chptr->hnext == chptr);
315 /** returns Membership * if a person is joined and not a zombie
317 * @param chptr Channel
318 * @returns pointer to the client's struct Membership * on the channel if that
319 * user is a full member of the channel, or NULL otherwise.
321 * @see find_member_link()
323 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
325 struct Membership* member;
328 member = find_member_link(chptr, cptr);
329 return (member && !IsZombie(member)) ? member : 0;
332 /** Searches for a ban from a banlist that matches a user.
333 * @param[in] cptr The client to test.
334 * @param[in] banlist The list of bans to test.
335 * @return Pointer to a matching ban, or NULL if none exit.
337 struct Ban *find_ban(struct Client *cptr, struct Ban *banlist)
339 char nu[NICKLEN + USERLEN + 2];
340 char tmphost[HOSTLEN + 1];
344 /* Build nick!user and alternate host names. */
345 ircd_snprintf(0, nu, sizeof(nu), "%s!%s",
346 cli_name(cptr), cli_user(cptr)->username);
347 if (!IsAccount(cptr))
349 else if (HasHiddenHost(cptr))
350 sr = cli_user(cptr)->realhost;
353 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
354 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
358 /* Walk through ban list. */
359 for (found = NULL; banlist; banlist = banlist->next) {
361 /* If we have found a positive ban already, only consider exceptions. */
362 if (found && !(banlist->flags & BAN_EXCEPTION))
364 /* Compare nick!user portion of ban. */
365 banlist->banstr[banlist->nu_len] = '\0';
366 res = match(banlist->banstr, nu);
367 banlist->banstr[banlist->nu_len] = '@';
370 /* Compare host portion of ban. */
371 if (!((banlist->flags & BAN_IPMASK)
372 && ipmask_check(&cli_ip(cptr), &banlist->address, banlist->addrbits))
373 && match(banlist->banstr + banlist->nu_len + 1, cli_user(cptr)->host)
374 && !(sr && match(banlist->banstr + banlist->nu_len + 1, sr) == 0))
376 /* If an exception matches, no ban can match. */
377 if (banlist->flags & BAN_EXCEPTION)
379 /* Otherwise, remember this ban but keep searching for an exception. */
386 * This function returns true if the user is banned on the said channel.
387 * This function will check the ban cache if applicable, otherwise will
388 * do the comparisons and cache the result.
390 * @param[in] member The Membership to test for banned-ness.
391 * @return Non-zero if the member is banned, zero if not.
393 static int is_banned(struct Membership* member)
395 if (IsBanValid(member))
396 return IsBanned(member);
399 if (find_ban(member->user, member->channel->banlist)) {
408 /** add a user to a channel.
409 * adds a user to a channel by adding another link to the channels member
412 * @param chptr The channel to add to.
413 * @param who The user to add.
414 * @param flags The flags the user gets initially.
415 * @param oplevel The oplevel the user starts with.
417 void add_user_to_channel(struct Channel* chptr, struct Client* who,
418 unsigned int flags, int oplevel)
425 struct Membership* member = membershipFreeList;
427 membershipFreeList = member->next_member;
429 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
430 ++membershipAllocCount;
435 member->channel = chptr;
436 member->status = flags;
437 member->oplevel = oplevel;
439 member->next_member = chptr->members;
440 if (member->next_member)
441 member->next_member->prev_member = member;
442 member->prev_member = 0;
443 chptr->members = member;
445 member->next_channel = (cli_user(who))->channel;
446 if (member->next_channel)
447 member->next_channel->prev_channel = member;
448 member->prev_channel = 0;
449 (cli_user(who))->channel = member;
451 if (chptr->destruct_event)
452 remove_destruct_event(chptr);
454 ++((cli_user(who))->joined);
458 /** Remove a person from a channel, given their Membership*
460 * @param member A member of a channel.
462 * @returns true if there are more people in the channel.
464 static int remove_member_from_channel(struct Membership* member)
466 struct Channel* chptr;
468 chptr = member->channel;
470 * unlink channel member list
472 if (member->next_member)
473 member->next_member->prev_member = member->prev_member;
474 if (member->prev_member)
475 member->prev_member->next_member = member->next_member;
477 member->channel->members = member->next_member;
480 * If this is the last delayed-join user, may have to clear WASDELJOINS.
482 if (IsDelayedJoin(member))
483 CheckDelayedJoins(chptr);
486 * unlink client channel list
488 if (member->next_channel)
489 member->next_channel->prev_channel = member->prev_channel;
490 if (member->prev_channel)
491 member->prev_channel->next_channel = member->next_channel;
493 (cli_user(member->user))->channel = member->next_channel;
495 --(cli_user(member->user))->joined;
497 member->next_member = membershipFreeList;
498 membershipFreeList = member;
500 return sub1_from_channel(chptr);
503 /** Check if all the remaining members on the channel are zombies
505 * @returns False if the channel has any non zombie members, True otherwise.
508 static int channel_all_zombies(struct Channel* chptr)
510 struct Membership* member;
512 for (member = chptr->members; member; member = member->next_member) {
513 if (!IsZombie(member))
520 /** Remove a user from a channel
521 * This is the generic entry point for removing a user from a channel, this
522 * function will remove the client from the channel, and destory the channel
523 * if there are no more normal users left.
525 * @param cptr The client
526 * @param chptr The channel
528 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
531 struct Membership* member;
534 if ((member = find_member_link(chptr, cptr))) {
535 if (remove_member_from_channel(member)) {
536 if (channel_all_zombies(chptr)) {
538 * XXX - this looks dangerous but isn't if we got the referential
539 * integrity right for channels
541 while (remove_member_from_channel(chptr->members))
548 /** Remove a user from all channels they are on.
550 * This function removes a user from all channels they are on.
552 * @param cptr The client to remove.
554 void remove_user_from_all_channels(struct Client* cptr)
556 struct Membership* chan;
558 assert(0 != cli_user(cptr));
560 while ((chan = (cli_user(cptr))->channel))
561 remove_user_from_channel(cptr, chan->channel);
564 /** Check if this user is a legitimate chanop
566 * @param cptr Client to check
567 * @param chptr Channel to check
569 * @returns True if the user is a chanop (And not a zombie), False otherwise.
572 int is_chan_op(struct Client *cptr, struct Channel *chptr)
574 struct Membership* member;
576 if ((member = find_member_link(chptr, cptr)))
577 return (!IsZombie(member) && IsChanOp(member));
582 /** Check if a user is a Zombie on a specific channel.
584 * @param cptr The client to check.
585 * @param chptr The channel to check.
587 * @returns True if the client (cptr) is a zombie on the channel (chptr),
592 int is_zombie(struct Client *cptr, struct Channel *chptr)
594 struct Membership* member;
598 if ((member = find_member_link(chptr, cptr)))
599 return IsZombie(member);
603 /** Returns if a user has voice on a channel.
605 * @param cptr The client
606 * @param chptr The channel
608 * @returns True if the client (cptr) is voiced on (chptr) and is not a zombie.
611 int has_voice(struct Client* cptr, struct Channel* chptr)
613 struct Membership* member;
616 if ((member = find_member_link(chptr, cptr)))
617 return (!IsZombie(member) && HasVoice(member));
622 /** Can this member send to a channel
624 * A user can speak on a channel iff:
626 * <li> They didn't use the Apass to gain ops.
627 * <li> They are op'd or voice'd.
628 * <li> You aren't banned.
629 * <li> The channel isn't +m
630 * <li> The channel isn't +n or you are on the channel.
633 * This function will optionally reveal a user on a delayed join channel if
634 * they are allowed to send to the channel.
636 * @param member The membership of the user
637 * @param reveal If true, the user will be "revealed" on a delayed
640 * @returns True if the client can speak on the channel.
642 int member_can_send_to_channel(struct Membership* member, int reveal)
646 /* Discourage using the Apass to get op. They should use the upass. */
647 if (IsChannelManager(member) && *member->channel->mode.upass)
650 if (IsVoicedOrOpped(member))
653 * If it's moderated, and you aren't a priviledged user, you can't
656 if (member->channel->mode.mode & MODE_MODERATED)
659 * If you're banned then you can't speak either.
660 * but because of the amount of CPU time that is_banned chews
661 * we only check it for our clients.
663 if (MyUser(member->user) && is_banned(member))
666 if (IsDelayedJoin(member) && reveal)
667 RevealDelayedJoin(member);
672 /** Check if a client can send to a channel.
674 * Has the added check over member_can_send_to_channel() of servers can
677 * @param cptr The client to check
678 * @param chptr The channel to check
679 * @param reveal If the user should be revealed (see
680 * member_can_send_to_channel())
682 * @returns true if the client is allowed to speak on the channel, false
685 * @see member_can_send_to_channel()
687 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
689 struct Membership *member;
692 * Servers can always speak on channels.
697 member = find_channel_member(cptr, chptr);
700 * You can't speak if you're off channel, and it is +n (no external messages)
704 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
705 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
708 return !find_ban(cptr, chptr->banlist);
710 return member_can_send_to_channel(member, reveal);
713 /** Returns the name of a channel that prevents the user from changing nick.
714 * if a member and not (opped or voiced) and (banned or moderated), return
715 * the name of the first channel banned on.
717 * @param cptr The client
719 * @returns the name of the first channel banned on, or NULL if the user
722 const char* find_no_nickchange_channel(struct Client* cptr)
725 struct Membership* member;
726 for (member = (cli_user(cptr))->channel; member;
727 member = member->next_channel) {
728 if (!IsVoicedOrOpped(member) &&
729 (is_banned(member) ||
730 (member->channel->mode.mode & MODE_MODERATED)))
731 return member->channel->chname;
738 /** Fill mbuf/pbuf with modes from chptr
739 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
740 * with the parameters in pbuf as visible by cptr.
742 * This function will hide keys from non-op'd, non-server clients.
744 * @param cptr The client to generate the mode for.
745 * @param mbuf The buffer to write the modes into.
746 * @param pbuf The buffer to write the mode parameters into.
747 * @param buflen The length of the buffers.
748 * @param chptr The channel to get the modes from.
749 * @param member The membership of this client on this channel (or NULL
750 * if this client isn't on this channel)
753 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
754 struct Channel *chptr, struct Membership *member)
756 int previous_parameter = 0;
763 if (chptr->mode.mode & MODE_SECRET)
765 else if (chptr->mode.mode & MODE_PRIVATE)
767 if (chptr->mode.mode & MODE_MODERATED)
769 if (chptr->mode.mode & MODE_TOPICLIMIT)
771 if (chptr->mode.mode & MODE_INVITEONLY)
773 if (chptr->mode.mode & MODE_NOPRIVMSGS)
775 if (chptr->mode.mode & MODE_REGONLY)
777 if (chptr->mode.mode & MODE_DELJOINS)
779 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
781 if (chptr->mode.limit) {
783 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
784 previous_parameter = 1;
787 if (*chptr->mode.key) {
789 if (previous_parameter)
791 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
792 strcat(pbuf, chptr->mode.key);
795 previous_parameter = 1;
797 if (*chptr->mode.apass) {
799 if (previous_parameter)
801 if (IsServer(cptr)) {
802 strcat(pbuf, chptr->mode.apass);
805 previous_parameter = 1;
807 if (*chptr->mode.upass) {
809 if (previous_parameter)
811 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
812 strcat(pbuf, chptr->mode.upass);
819 /** Compare two members oplevel
821 * @param mp1 Pointer to a pointer to a membership
822 * @param mp2 Pointer to a pointer to a membership
824 * @returns 0 if equal, -1 if mp1 is lower, +1 otherwise.
828 int compare_member_oplevel(const void *mp1, const void *mp2)
830 struct Membership const* member1 = *(struct Membership const**)mp1;
831 struct Membership const* member2 = *(struct Membership const**)mp2;
832 if (member1->oplevel == member2->oplevel)
834 return (member1->oplevel < member2->oplevel) ? -1 : 1;
837 /* send "cptr" a full list of the modes for channel chptr.
839 * Sends a BURST line to cptr, bursting all the modes for the channel.
841 * @param cptr Client pointer
842 * @param chptr Channel pointer
844 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
846 /* The order in which modes are generated is now mandatory */
847 static unsigned int current_flags[4] =
848 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
854 struct Membership* member;
856 char modebuf[MODEBUFLEN];
857 char parabuf[MODEBUFLEN];
859 int number_of_ops = 0;
860 int opped_members_index = 0;
861 struct Membership** opped_members = NULL;
862 int last_oplevel = 0;
863 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
868 if (IsLocalChannel(chptr->chname))
871 member = chptr->members;
872 lp2 = chptr->banlist;
874 *modebuf = *parabuf = '\0';
875 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
877 for (first = 1; full; first = 0) /* Loop for multiple messages */
879 full = 0; /* Assume by default we get it
880 all in one message */
882 /* (Continued) prefix: "<Y> B <channel> <TS>" */
883 /* is there any better way we can do this? */
884 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
885 chptr->creationtime);
887 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
890 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
891 msgq_append(&me, mb, " %s", modebuf);
894 msgq_append(&me, mb, " %s", parabuf);
898 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
900 * First find all opless members.
901 * Run 2 times over all members, to group the members with
902 * and without voice together.
903 * Then run 2 times over all opped members (which are ordered
904 * by op-level) to also group voice and non-voice together.
906 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
910 if (flag_cnt < 2 && IsChanOp(member))
913 * The first loop (to find all non-voice/op), we count the ops.
914 * The second loop (to find all voiced non-ops), store the ops
915 * in a dynamic array.
920 opped_members[opped_members_index++] = member;
922 /* Only handle the members with the flags that we are interested in. */
923 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
925 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
926 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
928 full = 1; /* Make sure we continue after
930 /* Ensure the new BURST line contains the current
931 * ":mode", except when there is no mode yet. */
932 new_mode = (flag_cnt > 0) ? 1 : 0;
933 break; /* Do not add this member to this message */
935 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
936 first = 0; /* From now on, use commas to add new nicks */
939 * Do we have a nick with a new mode ?
940 * Or are we starting a new BURST line?
942 if (new_mode || !feat_oplevels)
945 * This means we are at the _first_ member that has only
946 * voice, or the first member that has only ops, or the
947 * first member that has voice and ops (so we get here
948 * at most three times, plus once for every start of
949 * a continued BURST line where only these modes is current.
950 * In the two cases where the current mode includes ops,
951 * we need to add the _absolute_ value of the oplevel to the mode.
953 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
956 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
958 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
960 /* append the absolute value of the oplevel */
962 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
967 msgq_append(&me, mb, tbuf);
970 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
973 * This can't be the first member of a (continued) BURST
974 * message because then either flag_cnt == 0 or new_mode == 1
975 * Now we need to append the incremental value of the oplevel.
977 char tbuf[2 + MAXOPLEVELDIGITS];
978 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
979 last_oplevel = member->oplevel;
980 msgq_append(&me, mb, tbuf);
983 /* Go to the next `member'. */
985 member = member->next_member;
987 member = opped_members[++opped_members_index];
992 /* Point `member' at the start of the list again. */
995 member = chptr->members;
996 /* Now, after one loop, we know the number of ops and can
997 * allocate the dynamic array with pointer to the ops. */
998 opped_members = (struct Membership**)
999 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
1000 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
1004 /* At the end of the second loop, sort the opped members with
1005 * increasing op-level, so that we will output them in the
1006 * correct order (and all op-level increments stay positive) */
1008 qsort(opped_members, number_of_ops,
1009 sizeof(struct Membership*), compare_member_oplevel);
1010 /* The third and fourth loop run only over the opped members. */
1011 member = opped_members[(opped_members_index = 0)];
1014 } /* loop over 0,+v,+o,+ov */
1018 /* Attach all bans, space seperated " :%ban ban ..." */
1019 for (first = 2; lp2; lp2 = lp2->next)
1021 len = strlen(lp2->banstr);
1022 if (msgq_bufleft(mb) < len + 1 + first)
1023 /* The +1 stands for the added ' '.
1024 * The +first stands for the added ":%".
1030 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1036 send_buffer(cptr, mb, 0); /* Send this message */
1038 } /* Continue when there was something
1039 that didn't fit (full==1) */
1041 MyFree(opped_members);
1042 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1043 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1044 chptr->creationtime, chptr->topic_time, chptr->topic);
1047 /** Canonify a mask.
1050 * @author Carlo Wood (Run),
1053 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1054 * When the user name or host name are too long (USERLEN and HOSTLEN
1055 * respectively) then they are cut off at the start with a '*'.
1057 * The following transformations are made:
1059 * 1) xxx -> nick!*@*
1060 * 2) xxx.xxx -> *!*\@host
1061 * 3) xxx\!yyy -> nick!user\@*
1062 * 4) xxx\@yyy -> *!user\@host
1063 * 5) xxx!yyy\@zzz -> nick!user\@host
1065 * @param mask The uncanonified mask.
1066 * @returns The updated mask in a static buffer.
1068 char *pretty_mask(char *mask)
1070 static char star[2] = { '*', 0 };
1071 static char retmask[NICKLEN + USERLEN + HOSTLEN + 3];
1072 char *last_dot = NULL;
1075 /* Case 1: default */
1080 /* Do a _single_ pass through the characters of the mask: */
1081 for (ptr = mask; *ptr; ++ptr)
1085 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1089 else if (*ptr == '@')
1091 /* Case 4: Found last '@' (without finding a '!' yet) */
1096 else if (*ptr == '.')
1098 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1108 /* Case 4 or 5: Found last '@' */
1114 if (user == star && last_dot)
1124 char *nick_end = (user != star) ? user - 1 : ptr;
1125 if (nick_end - nick > NICKLEN)
1131 char *user_end = (host != star) ? host - 1 : ptr;
1132 if (user_end - user > USERLEN)
1134 user = user_end - USERLEN;
1139 if (host != star && ptr - host > HOSTLEN)
1141 host = ptr - HOSTLEN;
1144 ircd_snprintf(0, retmask, sizeof(retmask), "%s!%s@%s", nick, user, host);
1148 /** send a banlist to a client for a channel
1150 * @param cptr Client to send the banlist to.
1151 * @param chptr Channel whose banlist to send.
1153 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1160 for (lp = chptr->banlist; lp; lp = lp->next)
1161 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->banstr,
1164 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1167 /** Check a key against a keyring.
1168 * We are now treating the key part of /join channellist key as a key
1169 * ring; that is, we try one key against the actual channel key, and if that
1170 * doesn't work, we try the next one, and so on. -Kev -Texaco
1171 * Returns: 0 on match, 1 otherwise
1172 * This version contributed by SeKs \<intru@info.polymtl.ca\>
1174 * @param key Key to check
1175 * @param keyring Comma seperated list of keys
1177 * @returns True if the key was found and matches, false otherwise.
1179 static int compall(char *key, char *keyring)
1184 p1 = key; /* point to the key... */
1185 while (*p1 && *p1 == *keyring)
1186 { /* step through the key and ring until they
1192 if (!*p1 && (!*keyring || *keyring == ','))
1193 /* ok, if we're at the end of the and also at the end of one of the keys
1194 in the keyring, we have a match */
1197 if (!*keyring) /* if we're at the end of the key ring, there
1198 weren't any matches, so we return 1 */
1201 /* Not at the end of the key ring, so step
1202 through to the next key in the ring: */
1203 while (*keyring && *(keyring++) != ',');
1205 goto top; /* and check it against the key */
1208 /** Returns if a user can join a channel with a specific key.
1210 * @param sptr The client trying to join
1211 * @param chptr The channel to join
1212 * @param key The key to use
1214 * @returns any error that occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1215 * if the oper used the magic key, 0 if no error occured.
1217 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1219 int overrideJoin = 0;
1222 * Now a banned user CAN join if invited -- Nemesi
1223 * Now a user CAN escape channel limit if invited -- bfriendly
1224 * Now a user CAN escape anything if invited -- Isomer
1227 if (IsInvited(sptr, chptr))
1230 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1231 a HACK(4) notice will be sent if he would not have been supposed
1232 to join normally. */
1233 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1234 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1235 compall("OVERRIDE",key) == 0)
1236 overrideJoin = MAGIC_OPER_OVERRIDE;
1238 if (chptr->mode.mode & MODE_INVITEONLY)
1239 return overrideJoin + ERR_INVITEONLYCHAN;
1241 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1242 return overrideJoin + ERR_CHANNELISFULL;
1244 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1245 return overrideJoin + ERR_NEEDREGGEDNICK;
1247 if (find_ban(sptr, chptr->banlist))
1248 return overrideJoin + ERR_BANNEDFROMCHAN;
1251 * now using compall (above) to test against a whole key ring -Kev
1253 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1254 return overrideJoin + ERR_BADCHANNELKEY;
1257 return ERR_DONTCHEAT;
1262 /** Remove bells and commas from channel name
1264 * @param cn Channel name to clean, modified in place.
1266 void clean_channelname(char *cn)
1270 for (i = 0; cn[i]; i++) {
1271 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1275 if (IsChannelLower(cn[i])) {
1276 cn[i] = ToLower(cn[i]);
1282 if ((unsigned char)(cn[i]) == 0xd0)
1283 cn[i] = (char) 0xf0;
1289 /** Get a channel block, creating if necessary.
1290 * Get Channel block for chname (and allocate a new channel
1291 * block, if it didn't exists before).
1293 * @param cptr Client joining the channel.
1294 * @param chname The name of the channel to join.
1295 * @param flag set to CGT_CREATE to create the channel if it doesn't
1298 * @returns NULL if the channel is invalid, doesn't exist and CGT_CREATE
1299 * wasn't specified or a pointer to the channel structure
1301 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1303 struct Channel *chptr;
1306 if (EmptyString(chname))
1309 len = strlen(chname);
1310 if (MyUser(cptr) && len > CHANNELLEN)
1313 *(chname + CHANNELLEN) = '\0';
1315 if ((chptr = FindChannel(chname)))
1317 if (flag == CGT_CREATE)
1319 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1321 ++UserStats.channels;
1322 memset(chptr, 0, sizeof(struct Channel));
1323 strcpy(chptr->chname, chname);
1324 if (GlobalChannelList)
1325 GlobalChannelList->prev = chptr;
1327 chptr->next = GlobalChannelList;
1328 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1329 GlobalChannelList = chptr;
1335 /** invite a user to a channel.
1337 * Adds an invite for a user to a channel. Limits the number of invites
1338 * to FEAT_MAXCHANNELSPERUSER. Does not sent notification to the user.
1340 * @param cptr The client to be invited.
1341 * @param chptr The channel to be invited to.
1343 void add_invite(struct Client *cptr, struct Channel *chptr)
1345 struct SLink *inv, **tmp;
1347 del_invite(cptr, chptr);
1349 * Delete last link in chain if the list is max length
1351 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1352 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1353 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1355 * Add client to channel invite list
1358 inv->value.cptr = cptr;
1359 inv->next = chptr->invites;
1360 chptr->invites = inv;
1362 * Add channel to the end of the client invite list
1364 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1366 inv->value.chptr = chptr;
1369 (cli_user(cptr))->invites++;
1372 /** Delete an invite
1373 * Delete Invite block from channel invite list and client invite list
1375 * @param cptr Client pointer
1376 * @param chptr Channel pointer
1378 void del_invite(struct Client *cptr, struct Channel *chptr)
1380 struct SLink **inv, *tmp;
1382 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1383 if (tmp->value.cptr == cptr)
1388 (cli_user(cptr))->invites--;
1392 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1393 if (tmp->value.chptr == chptr)
1402 /** @page zombie Explanation of Zombies
1406 * A channel member is turned into a zombie when he is kicked from a
1407 * channel but his server has not acknowledged the kick. Servers that
1408 * see the member as a zombie can accept actions he performed before
1409 * being kicked, without allowing chanop operations from outsiders or
1410 * desyncing the network.
1418 * X --a--> A --b--> B --d--> D
1423 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1424 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1426 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1427 * Remove the user immediately when no users are left on the channel.
1428 * b) On server B : remove the user (who/lp) from the channel, send a
1429 * PART upstream (to A) and pass on the KICK.
1430 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1431 * channel, and pass on the KICK.
1432 * d) On server D : remove the user (who/lp) from the channel, and pass on
1436 * - Setting the ZOMBIE flag never hurts, we either remove the
1437 * client after that or we don't.
1438 * - The KICK message was already passed on, as should be in all cases.
1439 * - `who' is removed in all cases except case a) when users are left.
1440 * - A PART is only sent upstream in case b).
1446 * 1 --- 2 --- 3 --- 4 --- 5
1451 * We also need to turn 'who' into a zombie on servers 1 and 6,
1452 * because a KICK from 'who' (kicking someone else in that direction)
1453 * can arrive there afterwards - which should not be bounced itself.
1454 * Therefore case a) also applies for servers 1 and 6.
1459 /** Turn a user on a channel into a zombie
1460 * This function turns a user into a zombie (see \ref zombie)
1462 * @param member The structure representing this user on this channel.
1463 * @param who The client that is being kicked.
1464 * @param cptr The connection the kick came from.
1465 * @param sptr The client that is doing the kicking.
1466 * @param chptr The channel the user is being kicked from.
1468 void make_zombie(struct Membership* member, struct Client* who,
1469 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1471 assert(0 != member);
1476 /* Default for case a): */
1479 /* Case b) or c) ?: */
1480 if (MyUser(who)) /* server 4 */
1482 if (IsServer(cptr)) /* Case b) ? */
1483 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1484 remove_user_from_channel(who, chptr);
1487 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1489 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1490 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1491 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1493 remove_user_from_channel(who, chptr);
1498 /* Case a) (servers 1, 2, 3 and 6) */
1499 if (channel_all_zombies(chptr))
1500 remove_user_from_channel(who, chptr);
1502 /* XXX Can't actually call Debug here; if the channel is all zombies,
1503 * chptr will no longer exist when we get here.
1504 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1508 /** returns the number of zombies on a channel
1509 * @param chptr Channel to count zombies in.
1511 * @returns The number of zombies on the channel.
1513 int number_of_zombies(struct Channel *chptr)
1515 struct Membership* member;
1519 for (member = chptr->members; member; member = member->next_member) {
1520 if (IsZombie(member))
1526 /** Concatenate some strings together.
1527 * This helper function builds an argument string in strptr, consisting
1528 * of the original string, a space, and str1 and str2 concatenated (if,
1529 * of course, str2 is not NULL)
1531 * @param strptr The buffer to concatenate into
1532 * @param strptr_i modified offset to the position to modify
1533 * @param str1 The string to contatenate from.
1534 * @param str2 The second string to contatenate from.
1535 * @param c Charactor to seperate the string from str1 and str2.
1538 build_string(char *strptr, int *strptr_i, const char *str1,
1539 const char *str2, char c)
1542 strptr[(*strptr_i)++] = c;
1545 strptr[(*strptr_i)++] = *(str1++);
1549 strptr[(*strptr_i)++] = *(str2++);
1551 strptr[(*strptr_i)] = '\0';
1554 /** Flush out the modes
1555 * This is the workhorse of our ModeBuf suite; this actually generates the
1556 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1558 * @param mbuf The mode buffer to flush
1559 * @param all If true, flush all modes, otherwise leave partial modes in the
1565 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1567 /* we only need the flags that don't take args right now */
1568 static int flags[] = {
1569 /* MODE_CHANOP, 'o', */
1570 /* MODE_VOICE, 'v', */
1573 MODE_MODERATED, 'm',
1574 MODE_TOPICLIMIT, 't',
1575 MODE_INVITEONLY, 'i',
1576 MODE_NOPRIVMSGS, 'n',
1579 MODE_WASDELJOINS, 'd',
1580 /* MODE_KEY, 'k', */
1581 /* MODE_BAN, 'b', */
1583 /* MODE_APASS, 'A', */
1584 /* MODE_UPASS, 'U', */
1590 struct Client *app_source; /* where the MODE appears to come from */
1592 char addbuf[20]; /* accumulates +psmtin, etc. */
1594 char rembuf[20]; /* accumulates -psmtin, etc. */
1596 char *bufptr; /* we make use of indirection to simplify the code */
1599 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1601 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1603 char *strptr; /* more indirection to simplify the code */
1606 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1609 char limitbuf[20]; /* convert limits to strings */
1611 unsigned int limitdel = MODE_LIMIT;
1615 /* If the ModeBuf is empty, we have nothing to do */
1616 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1619 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1621 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1624 app_source = mbuf->mb_source;
1627 * Account for user we're bouncing; we have to get it in on the first
1628 * bounced MODE, or we could have problems
1630 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1631 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1633 /* Calculate the simple flags */
1634 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1635 if (*flag_p & mbuf->mb_add)
1636 addbuf[addbuf_i++] = flag_p[1];
1637 else if (*flag_p & mbuf->mb_rem)
1638 rembuf[rembuf_i++] = flag_p[1];
1641 /* Now go through the modes with arguments... */
1642 for (i = 0; i < mbuf->mb_count; i++) {
1643 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1645 bufptr_i = &addbuf_i;
1648 bufptr_i = &rembuf_i;
1651 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1652 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1654 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1655 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1657 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1658 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1660 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1661 tmp = strlen(MB_STRING(mbuf, i));
1663 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1664 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1667 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1679 bufptr[(*bufptr_i)++] = mode_char;
1680 totalbuflen -= tmp + 1;
1682 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1683 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1684 strlen(MB_STRING(mbuf, i)));
1686 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1687 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1689 bufptr[(*bufptr_i)++] = 'k';
1690 totalbuflen -= tmp + 1;
1692 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1693 /* if it's a limit, we also format the number */
1694 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1696 tmp = strlen(limitbuf);
1698 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1699 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1701 bufptr[(*bufptr_i)++] = 'l';
1702 totalbuflen -= tmp + 1;
1707 /* terminate the mode strings */
1708 addbuf[addbuf_i] = '\0';
1709 rembuf[rembuf_i] = '\0';
1711 /* If we're building a user visible MODE or HACK... */
1712 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1713 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1714 MODEBUF_DEST_LOG)) {
1715 /* Set up the parameter strings */
1721 for (i = 0; i < mbuf->mb_count; i++) {
1722 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1725 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1727 strptr_i = &addstr_i;
1730 strptr_i = &remstr_i;
1733 /* deal with clients... */
1734 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1735 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1737 /* deal with bans... */
1738 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1739 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1741 /* deal with keys... */
1742 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1743 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1744 "*" : MB_STRING(mbuf, i), 0, ' ');
1746 /* deal with invisible passwords */
1747 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1748 build_string(strptr, strptr_i, "*", 0, ' ');
1751 * deal with limit; note we cannot include the limit parameter if we're
1754 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1755 (MODE_ADD | MODE_LIMIT))
1756 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1759 /* send the messages off to their destination */
1760 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1761 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1763 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1764 mbuf->mb_source : app_source),
1765 mbuf->mb_channel->chname,
1766 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1767 addbuf, remstr, addstr,
1768 mbuf->mb_channel->creationtime);
1770 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1771 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1772 "%s%s%s%s%s%s [%Tu]",
1773 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1774 mbuf->mb_source : app_source),
1775 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1776 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1777 mbuf->mb_channel->creationtime);
1779 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1780 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1782 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1783 mbuf->mb_source : app_source),
1784 mbuf->mb_channel->chname,
1785 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1786 addbuf, remstr, addstr,
1787 mbuf->mb_channel->creationtime);
1789 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1790 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1791 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1792 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1793 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1795 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1796 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1797 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1798 rembuf_i ? "-" : "", rembuf,
1799 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1802 /* Now are we supposed to propagate to other servers? */
1803 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1804 /* set up parameter string */
1811 * limit is supressed if we're removing it; we have to figure out which
1812 * direction is the direction for it to be removed, though...
1814 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1816 for (i = 0; i < mbuf->mb_count; i++) {
1817 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1820 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1822 strptr_i = &addstr_i;
1825 strptr_i = &remstr_i;
1828 /* deal with modes that take clients */
1829 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1830 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1832 /* deal with modes that take strings */
1833 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1834 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1837 * deal with the limit. Logic here is complicated; if HACK2 is set,
1838 * we're bouncing the mode, so sense is reversed, and we have to
1839 * include the original limit if it looks like it's being removed
1841 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1842 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1845 /* we were told to deop the source */
1846 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1847 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1848 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1849 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1851 /* mark that we've done this, so we don't do it again */
1852 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1855 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1856 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1857 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1858 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1859 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1860 addbuf, remstr, addstr);
1861 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1863 * If HACK2 was set, we're bouncing; we send the MODE back to the
1864 * connection we got it from with the senses reversed and a TS of 0;
1867 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1868 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1869 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1870 mbuf->mb_channel->creationtime);
1873 * We're propagating a normal MODE command to the rest of the network;
1874 * we send the actual channel TS unless this is a HACK3 or a HACK4
1876 if (IsServer(mbuf->mb_source))
1877 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1878 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1879 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1880 addbuf, remstr, addstr,
1881 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1882 mbuf->mb_channel->creationtime);
1884 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1885 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1886 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1887 addbuf, remstr, addstr);
1891 /* We've drained the ModeBuf... */
1896 /* reinitialize the mode-with-arg slots */
1897 for (i = 0; i < MAXMODEPARAMS; i++) {
1898 /* If we saved any, pack them down */
1899 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1900 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1901 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1903 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1905 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1906 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1908 MB_TYPE(mbuf, i) = 0;
1909 MB_UINT(mbuf, i) = 0;
1912 /* If we're supposed to flush it all, do so--all hail tail recursion */
1913 if (all && mbuf->mb_count)
1914 return modebuf_flush_int(mbuf, 1);
1919 /** Initialise a modebuf
1920 * This routine just initializes a ModeBuf structure with the information
1921 * needed and the options given.
1923 * @param mbuf The mode buffer to initialise.
1924 * @param source The client that is performing the mode.
1926 * @param chan The channel that the mode is being performed upon.
1930 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1931 struct Client *connect, struct Channel *chan, unsigned int dest)
1936 assert(0 != source);
1940 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1944 mbuf->mb_source = source;
1945 mbuf->mb_connect = connect;
1946 mbuf->mb_channel = chan;
1947 mbuf->mb_dest = dest;
1950 /* clear each mode-with-parameter slot */
1951 for (i = 0; i < MAXMODEPARAMS; i++) {
1952 MB_TYPE(mbuf, i) = 0;
1953 MB_UINT(mbuf, i) = 0;
1957 /** Append a new mode to a modebuf
1958 * This routine simply adds modes to be added or deleted; do a binary OR
1959 * with either MODE_ADD or MODE_DEL
1961 * @param mbuf Mode buffer
1962 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1965 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1968 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1970 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1971 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1972 MODE_DELJOINS | MODE_WASDELJOINS);
1974 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1977 if (mode & MODE_ADD) {
1978 mbuf->mb_rem &= ~mode;
1979 mbuf->mb_add |= mode;
1981 mbuf->mb_add &= ~mode;
1982 mbuf->mb_rem |= mode;
1986 /** Append a mode that takes an int argument to the modebuf
1988 * This routine adds a mode to be added or deleted that takes a unsigned
1989 * int parameter; mode may *only* be the relevant mode flag ORed with one
1990 * of MODE_ADD or MODE_DEL
1992 * @param mbuf The mode buffer to append to.
1993 * @param mode The mode to append.
1994 * @param uint The argument to the mode.
1997 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
2000 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2002 if (mode == (MODE_LIMIT | MODE_DEL)) {
2003 mbuf->mb_rem |= mode;
2006 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2007 MB_UINT(mbuf, mbuf->mb_count) = uint;
2009 /* when we've reached the maximal count, flush the buffer */
2010 if (++mbuf->mb_count >=
2011 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2012 modebuf_flush_int(mbuf, 0);
2015 /** append a string mode
2016 * This routine adds a mode to be added or deleted that takes a string
2017 * parameter; mode may *only* be the relevant mode flag ORed with one of
2018 * MODE_ADD or MODE_DEL
2020 * @param mbuf The mode buffer to append to.
2021 * @param mode The mode to append.
2022 * @param string The string parameter to append.
2023 * @param free If the string should be free'd later.
2026 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2030 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2032 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2033 MB_STRING(mbuf, mbuf->mb_count) = string;
2035 /* when we've reached the maximal count, flush the buffer */
2036 if (++mbuf->mb_count >=
2037 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2038 modebuf_flush_int(mbuf, 0);
2041 /** Append a mode on a client to a modebuf.
2042 * This routine adds a mode to be added or deleted that takes a client
2043 * parameter; mode may *only* be the relevant mode flag ORed with one of
2044 * MODE_ADD or MODE_DEL
2046 * @param mbuf The modebuf to append the mode to.
2047 * @param mode The mode to append.
2048 * @param client The client argument to append.
2051 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2052 struct Client *client)
2055 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2057 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2058 MB_CLIENT(mbuf, mbuf->mb_count) = client;
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 struct Client *client;
2230 } cli_change[MAXPARA];
2233 /** Helper function to send "Not oper" or "Not member" messages
2234 * Here's a helper function to deal with sending along "Not oper" or
2235 * "Not member" messages
2237 * @param state Parsing State object
2240 send_notoper(struct ParseState *state)
2242 if (state->done & DONE_NOTOPER)
2245 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2246 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2248 state->done |= DONE_NOTOPER;
2252 * Helper function to convert limits
2254 * @param state Parsing state object.
2258 mode_parse_limit(struct ParseState *state, int *flag_p)
2260 unsigned int t_limit;
2262 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2263 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2266 if (state->parc <= 0) { /* warn if not enough args */
2267 if (MyUser(state->sptr))
2268 need_more_params(state->sptr, "MODE +l");
2272 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2276 if ((int)t_limit<0) /* don't permit a negative limit */
2279 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2280 (!t_limit || t_limit == state->chptr->mode.limit))
2283 t_limit = state->chptr->mode.limit;
2285 /* If they're not an oper, they can't change modes */
2286 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2287 send_notoper(state);
2291 /* Can't remove a limit that's not there */
2292 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2295 /* Skip if this is a burst and a lower limit than this is set already */
2296 if ((state->flags & MODE_PARSE_BURST) &&
2297 (state->chptr->mode.mode & flag_p[0]) &&
2298 (state->chptr->mode.limit < t_limit))
2301 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2303 state->done |= DONE_LIMIT;
2308 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2310 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2311 if (state->dir & MODE_ADD) {
2312 state->chptr->mode.mode |= flag_p[0];
2313 state->chptr->mode.limit = t_limit;
2315 state->chptr->mode.mode &= ~flag_p[0];
2316 state->chptr->mode.limit = 0;
2322 * Helper function to convert keys
2325 mode_parse_key(struct ParseState *state, int *flag_p)
2330 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2333 if (state->parc <= 0) { /* warn if not enough args */
2334 if (MyUser(state->sptr))
2335 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2340 t_str = state->parv[state->args_used++]; /* grab arg */
2344 /* If they're not an oper, they can't change modes */
2345 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2346 send_notoper(state);
2350 if (state->done & DONE_KEY) /* allow key to be set only once */
2352 state->done |= DONE_KEY;
2356 /* clean up the key string */
2358 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2362 if (!*t_str) { /* warn if empty */
2363 if (MyUser(state->sptr))
2364 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2372 /* Skip if this is a burst, we have a key already and the new key is
2373 * after the old one alphabetically */
2374 if ((state->flags & MODE_PARSE_BURST) &&
2375 *(state->chptr->mode.key) &&
2376 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2379 /* can't add a key if one is set, nor can one remove the wrong key */
2380 if (!(state->flags & MODE_PARSE_FORCE))
2381 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2382 (state->dir == MODE_DEL &&
2383 ircd_strcmp(state->chptr->mode.key, t_str))) {
2384 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2388 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2389 !ircd_strcmp(state->chptr->mode.key, t_str))
2390 return; /* no key change */
2392 if (state->flags & MODE_PARSE_BOUNCE) {
2393 if (*state->chptr->mode.key) /* reset old key */
2394 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2395 state->chptr->mode.key, 0);
2396 else /* remove new bogus key */
2397 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2398 } else /* send new key */
2399 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2401 if (state->flags & MODE_PARSE_SET) {
2402 if (state->dir == MODE_ADD) /* set the new key */
2403 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2404 else /* remove the old key */
2405 *state->chptr->mode.key = '\0';
2410 * Helper function to convert user passes
2413 mode_parse_upass(struct ParseState *state, int *flag_p)
2418 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2421 if (state->parc <= 0) { /* warn if not enough args */
2422 if (MyUser(state->sptr))
2423 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2428 t_str = state->parv[state->args_used++]; /* grab arg */
2432 /* If they're not an oper, they can't change modes */
2433 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2434 send_notoper(state);
2438 /* If a non-service user is trying to force it, refuse. */
2439 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2440 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2441 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2445 /* If they are not the channel manager, they are not allowed to change it */
2446 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2447 if (*state->chptr->mode.apass) {
2448 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2449 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2451 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2452 "Re-create the channel. The channel must be *empty* for",
2453 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2454 "before it can be recreated.");
2459 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2461 state->done |= DONE_UPASS;
2463 t_len = PASSLEN + 1;
2465 /* clean up the upass string */
2467 while (*++s > ' ' && *s != ':' && --t_len)
2471 if (!*t_str) { /* warn if empty */
2472 if (MyUser(state->sptr))
2473 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2481 if (!(state->flags & MODE_PARSE_FORCE))
2482 /* can't add the upass while apass is not set */
2483 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2484 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2487 /* can't add a upass if one is set, nor can one remove the wrong upass */
2488 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2489 (state->dir == MODE_DEL &&
2490 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2491 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2495 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2496 !ircd_strcmp(state->chptr->mode.upass, t_str))
2497 return; /* no upass change */
2499 if (state->flags & MODE_PARSE_BOUNCE) {
2500 if (*state->chptr->mode.upass) /* reset old upass */
2501 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2502 state->chptr->mode.upass, 0);
2503 else /* remove new bogus upass */
2504 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2505 } else /* send new upass */
2506 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2508 if (state->flags & MODE_PARSE_SET) {
2509 if (state->dir == MODE_ADD) /* set the new upass */
2510 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2511 else /* remove the old upass */
2512 *state->chptr->mode.upass = '\0';
2517 * Helper function to convert admin passes
2520 mode_parse_apass(struct ParseState *state, int *flag_p)
2525 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2528 if (state->parc <= 0) { /* warn if not enough args */
2529 if (MyUser(state->sptr))
2530 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2535 t_str = state->parv[state->args_used++]; /* grab arg */
2539 /* If they're not an oper, they can't change modes */
2540 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2541 send_notoper(state);
2545 /* If a non-service user is trying to force it, refuse. */
2546 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2547 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2548 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2552 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2553 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2554 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2558 /* If they are not the channel manager, they are not allowed to change it */
2559 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2560 if (*state->chptr->mode.apass) {
2561 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2562 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2564 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2565 "Re-create the channel. The channel must be *empty* for",
2566 "at least a whole minute", "before it can be recreated.");
2571 if (state->done & DONE_APASS) /* allow apass to be set only once */
2573 state->done |= DONE_APASS;
2575 t_len = PASSLEN + 1;
2577 /* clean up the apass string */
2579 while (*++s > ' ' && *s != ':' && --t_len)
2583 if (!*t_str) { /* warn if empty */
2584 if (MyUser(state->sptr))
2585 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2593 if (!(state->flags & MODE_PARSE_FORCE)) {
2594 /* can't remove the apass while upass is still set */
2595 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2596 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2599 /* can't add an apass if one is set, nor can one remove the wrong apass */
2600 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2601 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2602 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2607 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2608 !ircd_strcmp(state->chptr->mode.apass, t_str))
2609 return; /* no apass change */
2611 if (state->flags & MODE_PARSE_BOUNCE) {
2612 if (*state->chptr->mode.apass) /* reset old apass */
2613 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2614 state->chptr->mode.apass, 0);
2615 else /* remove new bogus apass */
2616 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2617 } else /* send new apass */
2618 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2620 if (state->flags & MODE_PARSE_SET) {
2621 if (state->dir == MODE_ADD) { /* set the new apass */
2622 /* Make it VERY clear to the user that this is a one-time password */
2623 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2624 if (MyUser(state->sptr)) {
2625 send_reply(state->sptr, RPL_APASSWARN,
2626 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2627 "Are you SURE you want to use this as Admin password? ",
2628 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2629 send_reply(state->sptr, RPL_APASSWARN,
2630 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2631 "\" to remove the password and then immediately set a new one. "
2632 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2633 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2634 "Now set the channel user password (+U).");
2636 } else { /* remove the old apass */
2637 *state->chptr->mode.apass = '\0';
2638 if (MyUser(state->sptr))
2639 send_reply(state->sptr, RPL_APASSWARN,
2640 "WARNING: You removed the channel Admin password MODE (+A). ",
2641 "If you would disconnect or leave the channel without setting a new password then you will ",
2642 "not be able to set it again and lose ownership of this channel! ",
2643 "SET A NEW PASSWORD NOW!", "");
2648 /** Compare one ban's extent to another.
2649 * This works very similarly to mmatch() but it knows about CIDR masks
2650 * and ban exceptions. If both bans are CIDR-based, compare their
2651 * address bits; otherwise, use mmatch().
2652 * @param[in] old_ban One ban.
2653 * @param[in] new_ban Another ban.
2654 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2657 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2660 assert(old_ban != NULL);
2661 assert(new_ban != NULL);
2662 /* A ban is never treated as a superset of an exception. */
2663 if (!(old_ban->flags & BAN_EXCEPTION)
2664 && (new_ban->flags & BAN_EXCEPTION))
2666 /* If either is not an address mask, match the text masks. */
2667 if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2668 return mmatch(old_ban->banstr, new_ban->banstr);
2669 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2670 if (old_ban->addrbits > new_ban->addrbits)
2672 /* Compare the masks before the hostname part. */
2673 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2674 res = mmatch(old_ban->banstr, new_ban->banstr);
2675 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2678 /* Compare the addresses. */
2679 return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2682 /** Add a ban from a ban list and mark bans that should be removed
2683 * because they overlap.
2685 * There are three invariants for a ban list. First, no ban may be
2686 * more specific than another ban. Second, no exception may be more
2687 * specific than another exception. Finally, no ban may be more
2688 * specific than any exception.
2690 * @param[in,out] banlist Pointer to head of list.
2691 * @param[in] newban Ban (or exception) to add (or remove).
2692 * @return Zero if \a newban could be applied, non-zero if not.
2694 int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
2699 assert(newban->flags & (BAN_ADD|BAN_DEL));
2700 if (newban->flags & BAN_ADD) {
2702 /* If a less specific entry is found, fail. */
2703 for (ban = *banlist; ban; ban = ban->next) {
2704 if (!bmatch(ban, newban)) {
2709 if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2711 totlen += strlen(ban->banstr);
2714 /* Mark more specific entries and add this one to the end of the list. */
2715 while ((ban = *banlist) != NULL) {
2716 if (!bmatch(newban, ban)) {
2717 ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2719 banlist = &ban->next;
2723 } else if (newban->flags & BAN_DEL) {
2724 size_t remove_count = 0;
2725 /* Mark more specific entries. */
2726 for (ban = *banlist; ban; ban = ban->next) {
2727 if (!bmatch(newban, ban)) {
2728 ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2735 MyFree(newban->banstr);
2736 /* If no matches were found, fail. */
2737 return remove_count ? 0 : 3;
2745 * Helper function to convert bans
2748 mode_parse_ban(struct ParseState *state, int *flag_p)
2751 struct Ban *ban, *newban;
2753 if (state->parc <= 0) { /* Not enough args, send ban list */
2754 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2755 send_ban_list(state->sptr, state->chptr);
2756 state->done |= DONE_BANLIST;
2762 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2765 t_str = state->parv[state->args_used++]; /* grab arg */
2769 /* If they're not an oper, they can't change modes */
2770 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2771 send_notoper(state);
2775 if ((s = strchr(t_str, ' ')))
2778 if (!*t_str || *t_str == ':') { /* warn if empty */
2779 if (MyUser(state->sptr))
2780 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2785 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2786 if (!(state->done & DONE_BANCLEAN)) {
2787 for (ban = state->chptr->banlist; ban; ban = ban->next)
2788 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2789 state->done |= DONE_BANCLEAN;
2792 /* remember the ban for the moment... */
2793 newban = state->banlist + (state->numbans++);
2795 newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2796 | (*flag_p == 'b' ? 0 : BAN_EXCEPTION);
2797 newban->banstr = NULL;
2798 set_ban_mask(newban, collapse(pretty_mask(t_str)));
2799 newban->who = cli_name(state->sptr);
2800 newban->when = TStime();
2801 apply_ban(&state->chptr->banlist, newban, 0);
2805 * This is the bottom half of the ban processor
2808 mode_process_bans(struct ParseState *state)
2810 struct Ban *ban, *newban, *prevban, *nextban;
2816 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2818 banlen = strlen(ban->banstr);
2820 nextban = ban->next;
2822 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2824 prevban->next = 0; /* Break the list; ban isn't a real ban */
2826 state->chptr->banlist = 0;
2831 MyFree(ban->banstr);
2834 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2835 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2838 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2839 if (prevban) /* clip it out of the list... */
2840 prevban->next = ban->next;
2842 state->chptr->banlist = ban->next;
2847 ban->banstr = NULL; /* modebuf_mode_string() gave ownership of
2848 * the ban string to state->mbuf */
2852 continue; /* next ban; keep prevban like it is */
2854 ban->flags &= BAN_IPMASK; /* unset other flags */
2855 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2857 prevban->next = 0; /* Break the list; ban isn't a real ban */
2859 state->chptr->banlist = 0;
2861 /* If we're supposed to ignore it, do so. */
2862 if (ban->flags & BAN_OVERLAPPED &&
2863 !(state->flags & MODE_PARSE_BOUNCE)) {
2866 MyFree(ban->banstr);
2868 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2869 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2870 count > feature_int(FEAT_MAXBANS))) {
2871 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2875 MyFree(ban->banstr);
2877 /* add the ban to the buffer */
2878 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2881 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2882 newban = make_ban(ban->banstr);
2883 DupString(newban->who, ban->who);
2884 newban->when = ban->when;
2885 newban->flags = ban->flags & BAN_IPMASK;
2887 newban->next = state->chptr->banlist; /* and link it in */
2888 state->chptr->banlist = newban;
2897 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2899 if (changed) /* if we changed the ban list, we must invalidate the bans */
2900 mode_ban_invalidate(state->chptr);
2904 * Helper function to process client changes
2907 mode_parse_client(struct ParseState *state, int *flag_p)
2910 struct Client *acptr;
2913 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2916 if (state->parc <= 0) /* return if not enough args */
2919 t_str = state->parv[state->args_used++]; /* grab arg */
2923 /* If they're not an oper, they can't change modes */
2924 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2925 send_notoper(state);
2929 if (MyUser(state->sptr)) /* find client we're manipulating */
2930 acptr = find_chasing(state->sptr, t_str, NULL);
2932 acptr = findNUser(t_str);
2935 return; /* find_chasing() already reported an error to the user */
2937 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2938 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2939 state->cli_change[i].flag & flag_p[0]))
2940 break; /* found a slot */
2942 /* Store what we're doing to them */
2943 state->cli_change[i].flag = state->dir | flag_p[0];
2944 state->cli_change[i].client = acptr;
2948 * Helper function to process the changed client list
2951 mode_process_clients(struct ParseState *state)
2954 struct Membership *member;
2956 for (i = 0; state->cli_change[i].flag; i++) {
2957 assert(0 != state->cli_change[i].client);
2959 /* look up member link */
2960 if (!(member = find_member_link(state->chptr,
2961 state->cli_change[i].client)) ||
2962 (MyUser(state->sptr) && IsZombie(member))) {
2963 if (MyUser(state->sptr))
2964 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2965 cli_name(state->cli_change[i].client),
2966 state->chptr->chname);
2970 if ((state->cli_change[i].flag & MODE_ADD &&
2971 (state->cli_change[i].flag & member->status)) ||
2972 (state->cli_change[i].flag & MODE_DEL &&
2973 !(state->cli_change[i].flag & member->status)))
2974 continue; /* no change made, don't do anything */
2976 /* see if the deop is allowed */
2977 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2978 (MODE_DEL | MODE_CHANOP)) {
2979 /* prevent +k users from being deopped */
2980 if (IsChannelService(state->cli_change[i].client)) {
2981 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2982 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2984 (IsServer(state->sptr) ? cli_name(state->sptr) :
2985 cli_name((cli_user(state->sptr))->server)));
2987 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2988 send_reply(state->sptr, ERR_ISCHANSERVICE,
2989 cli_name(state->cli_change[i].client),
2990 state->chptr->chname);
2995 /* check deop for local user */
2996 if (MyUser(state->sptr)) {
2998 /* don't allow local opers to be deopped on local channels */
2999 if (state->cli_change[i].client != state->sptr &&
3000 IsLocalChannel(state->chptr->chname) &&
3001 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3002 send_reply(state->sptr, ERR_ISOPERLCHAN,
3003 cli_name(state->cli_change[i].client),
3004 state->chptr->chname);
3008 if (feature_bool(FEAT_OPLEVELS)) {
3009 /* don't allow to deop members with an op level that is <= our own level */
3010 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3012 && OpLevel(member) <= OpLevel(state->member)) {
3013 int equal = (OpLevel(member) == OpLevel(state->member));
3014 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3015 cli_name(state->cli_change[i].client),
3016 state->chptr->chname,
3017 OpLevel(state->member), OpLevel(member),
3018 "deop", equal ? "the same" : "a higher");
3025 /* set op-level of member being opped */
3026 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3027 (MODE_ADD | MODE_CHANOP)) {
3028 /* If on a channel with upass set, someone with level x gives ops to someone else,
3029 then that person gets level x-1. On other channels, where upass is not set,
3030 the level stays the same. */
3031 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3032 /* Someone being opped by a server gets op-level 0 */
3033 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3034 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3037 /* actually effect the change */
3038 if (state->flags & MODE_PARSE_SET) {
3039 if (state->cli_change[i].flag & MODE_ADD) {
3040 if (IsDelayedJoin(member))
3041 RevealDelayedJoin(member);
3042 member->status |= (state->cli_change[i].flag &
3043 (MODE_CHANOP | MODE_VOICE));
3044 if (state->cli_change[i].flag & MODE_CHANOP)
3045 ClearDeopped(member);
3047 member->status &= ~(state->cli_change[i].flag &
3048 (MODE_CHANOP | MODE_VOICE));
3051 /* accumulate the change */
3052 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3053 state->cli_change[i].client);
3054 } /* for (i = 0; state->cli_change[i].flags; i++) */
3058 * Helper function to process the simple modes
3061 mode_parse_mode(struct ParseState *state, int *flag_p)
3063 /* If they're not an oper, they can't change modes */
3064 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3065 send_notoper(state);
3072 if (state->dir == MODE_ADD) {
3073 state->add |= flag_p[0];
3074 state->del &= ~flag_p[0];
3076 if (flag_p[0] & MODE_SECRET) {
3077 state->add &= ~MODE_PRIVATE;
3078 state->del |= MODE_PRIVATE;
3079 } else if (flag_p[0] & MODE_PRIVATE) {
3080 state->add &= ~MODE_SECRET;
3081 state->del |= MODE_SECRET;
3083 if (flag_p[0] & MODE_DELJOINS) {
3084 state->add &= ~MODE_WASDELJOINS;
3085 state->del |= MODE_WASDELJOINS;
3088 state->add &= ~flag_p[0];
3089 state->del |= flag_p[0];
3092 assert(0 == (state->add & state->del));
3093 assert((MODE_SECRET | MODE_PRIVATE) !=
3094 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3098 * This routine is intended to parse MODE or OPMODE commands and effect the
3099 * changes (or just build the bounce buffer). We pass the starting offset
3103 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3104 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3105 struct Membership* member)
3107 static int chan_flags[] = {
3112 MODE_MODERATED, 'm',
3113 MODE_TOPICLIMIT, 't',
3114 MODE_INVITEONLY, 'i',
3115 MODE_NOPRIVMSGS, 'n',
3129 unsigned int t_mode;
3131 struct ParseState state;
3142 state.chptr = chptr;
3143 state.member = member;
3146 state.flags = flags;
3147 state.dir = MODE_ADD;
3151 state.args_used = 0;
3152 state.max_args = MAXMODEPARAMS;
3155 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3156 state.banlist[i].next = 0;
3157 state.banlist[i].who = 0;
3158 state.banlist[i].when = 0;
3159 state.banlist[i].flags = 0;
3160 state.cli_change[i].flag = 0;
3161 state.cli_change[i].client = 0;
3164 modestr = state.parv[state.args_used++];
3168 for (; *modestr; modestr++) {
3169 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3170 if (flag_p[1] == *modestr)
3173 if (!flag_p[0]) { /* didn't find it? complain and continue */
3174 if (MyUser(state.sptr))
3175 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3180 case '+': /* switch direction to MODE_ADD */
3181 case '-': /* switch direction to MODE_DEL */
3182 state.dir = flag_p[0];
3185 case 'l': /* deal with limits */
3186 mode_parse_limit(&state, flag_p);
3189 case 'k': /* deal with keys */
3190 mode_parse_key(&state, flag_p);
3193 case 'A': /* deal with Admin passes */
3194 if (feature_bool(FEAT_OPLEVELS))
3195 mode_parse_apass(&state, flag_p);
3198 case 'U': /* deal with user passes */
3199 if (feature_bool(FEAT_OPLEVELS))
3200 mode_parse_upass(&state, flag_p);
3203 case 'b': /* deal with bans */
3204 mode_parse_ban(&state, flag_p);
3207 case 'o': /* deal with ops/voice */
3209 mode_parse_client(&state, flag_p);
3212 default: /* deal with other modes */
3213 mode_parse_mode(&state, flag_p);
3215 } /* switch (*modestr) */
3216 } /* for (; *modestr; modestr++) */
3218 if (state.flags & MODE_PARSE_BURST)
3219 break; /* don't interpret any more arguments */
3221 if (state.parc > 0) { /* process next argument in string */
3222 modestr = state.parv[state.args_used++];
3226 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3229 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3230 break; /* we're then going to bounce the mode! */
3232 recv_ts = atoi(modestr);
3234 if (recv_ts && recv_ts < state.chptr->creationtime)
3235 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3237 break; /* break out of while loop */
3238 } else if (state.flags & MODE_PARSE_STRICT ||
3239 (MyUser(state.sptr) && state.max_args <= 0)) {
3240 state.parc++; /* we didn't actually gobble the argument */
3242 break; /* break out of while loop */
3245 } /* while (*modestr) */
3248 * the rest of the function finishes building resultant MODEs; if the
3249 * origin isn't a member or an oper, skip it.
3251 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3252 return state.args_used; /* tell our parent how many args we gobbled */
3254 t_mode = state.chptr->mode.mode;
3256 if (state.del & t_mode) { /* delete any modes to be deleted... */
3257 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3259 t_mode &= ~state.del;
3261 if (state.add & ~t_mode) { /* add any modes to be added... */
3262 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3264 t_mode |= state.add;
3267 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3268 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3269 !(t_mode & MODE_INVITEONLY))
3270 mode_invite_clear(state.chptr);
3272 state.chptr->mode.mode = t_mode;
3275 if (state.flags & MODE_PARSE_WIPEOUT) {
3276 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3277 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3278 state.chptr->mode.limit);
3279 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3280 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3281 state.chptr->mode.key, 0);
3282 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3283 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3284 state.chptr->mode.upass, 0);
3285 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3286 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3287 state.chptr->mode.apass, 0);
3290 if (state.done & DONE_BANCLEAN) /* process bans */
3291 mode_process_bans(&state);
3293 /* process client changes */
3294 if (state.cli_change[0].flag)
3295 mode_process_clients(&state);
3297 return state.args_used; /* tell our parent how many args we gobbled */
3301 * Initialize a join buffer
3304 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3305 struct Client *connect, unsigned int type, char *comment,
3311 assert(0 != source);
3312 assert(0 != connect);
3314 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3315 jbuf->jb_connect = connect;
3316 jbuf->jb_type = type;
3317 jbuf->jb_comment = comment;
3318 jbuf->jb_create = create;
3320 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3321 type == JOINBUF_TYPE_PART ||
3322 type == JOINBUF_TYPE_PARTALL) ?
3323 STARTJOINLEN : STARTCREATELEN) +
3324 (comment ? strlen(comment) + 2 : 0));
3326 for (i = 0; i < MAXJOINARGS; i++)
3327 jbuf->jb_channels[i] = 0;
3331 * Add a channel to the join buffer
3334 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3342 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3343 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3348 is_local = IsLocalChannel(chan->chname);
3350 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3351 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3352 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3353 if (IsUserParting(member))
3355 SetUserParting(member);
3357 /* Send notification to channel */
3358 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3359 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3360 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3361 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3362 else if (MyUser(jbuf->jb_source))
3363 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3364 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3365 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3366 /* XXX: Shouldn't we send a PART here anyway? */
3367 /* to users on the channel? Why? From their POV, the user isn't on
3368 * the channel anymore anyway. We don't send to servers until below,
3369 * when we gang all the channel parts together. Note that this is
3370 * exactly the same logic, albeit somewhat more concise, as was in
3371 * the original m_part.c */
3373 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3374 is_local) /* got to remove user here */
3375 remove_user_from_channel(jbuf->jb_source, chan);
3377 /* Add user to channel */
3378 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3379 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3381 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3383 /* send notification to all servers */
3384 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3385 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3386 "%H %Tu", chan, chan->creationtime);
3388 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3389 /* Send the notification to the channel */
3390 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3392 /* send an op, too, if needed */
3393 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3394 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3395 chan, jbuf->jb_source);
3396 } else if (MyUser(jbuf->jb_source))
3397 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3400 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3401 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3402 return; /* don't send to remote */
3404 /* figure out if channel name will cause buffer to be overflowed */
3405 len = chan ? strlen(chan->chname) + 1 : 2;
3406 if (jbuf->jb_strlen + len > BUFSIZE)
3407 joinbuf_flush(jbuf);
3409 /* add channel to list of channels to send and update counts */
3410 jbuf->jb_channels[jbuf->jb_count++] = chan;
3411 jbuf->jb_strlen += len;
3413 /* if we've used up all slots, flush */
3414 if (jbuf->jb_count >= MAXJOINARGS)
3415 joinbuf_flush(jbuf);
3419 * Flush the channel list to remote servers
3422 joinbuf_flush(struct JoinBuf *jbuf)
3424 char chanlist[BUFSIZE];
3428 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3429 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3430 return 0; /* no joins to process */
3432 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3433 build_string(chanlist, &chanlist_i,
3434 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3435 i == 0 ? '\0' : ',');
3436 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3437 /* Remove user from channel */
3438 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3440 jbuf->jb_channels[i] = 0; /* mark slot empty */
3443 jbuf->jb_count = 0; /* reset base counters */
3444 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3445 STARTJOINLEN : STARTCREATELEN) +
3446 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3448 /* and send the appropriate command */
3449 switch (jbuf->jb_type) {
3450 case JOINBUF_TYPE_CREATE:
3451 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3452 "%s %Tu", chanlist, jbuf->jb_create);
3455 case JOINBUF_TYPE_PART:
3456 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3457 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3465 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3466 int IsInvited(struct Client* cptr, const void* chptr)
3470 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3471 if (lp->value.chptr == chptr)
3476 /* RevealDelayedJoin: sends a join for a hidden user */
3478 void RevealDelayedJoin(struct Membership *member) {
3479 ClearDelayedJoin(member);
3480 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3482 CheckDelayedJoins(member->channel);
3485 /* CheckDelayedJoins: checks and clear +d if necessary */
3487 void CheckDelayedJoins(struct Channel *chan) {
3488 struct Membership *memb2;
3490 if (chan->mode.mode & MODE_WASDELJOINS) {
3491 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3492 if (IsDelayedJoin(memb2))
3497 chan->mode.mode &= ~MODE_WASDELJOINS;
3498 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,