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.apass[0]) /* 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.apass[0]) != '\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 && MyUser(state->sptr)
2440 && !HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
2441 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2442 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2446 /* If they are not the channel manager, they are not allowed to change it */
2447 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2448 if (*state->chptr->mode.apass) {
2449 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2450 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2452 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2453 "Re-create the channel. The channel must be *empty* for",
2454 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2455 "before it can be recreated.");
2460 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2462 state->done |= DONE_UPASS;
2464 t_len = PASSLEN + 1;
2466 /* clean up the upass string */
2468 while (*++s > ' ' && *s != ':' && --t_len)
2472 if (!*t_str) { /* warn if empty */
2473 if (MyUser(state->sptr))
2474 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2482 if (!(state->flags & MODE_PARSE_FORCE))
2483 /* can't add the upass while apass is not set */
2484 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2485 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2488 /* can't add a upass if one is set, nor can one remove the wrong upass */
2489 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2490 (state->dir == MODE_DEL &&
2491 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2492 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2496 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2497 !ircd_strcmp(state->chptr->mode.upass, t_str))
2498 return; /* no upass change */
2500 if (state->flags & MODE_PARSE_BOUNCE) {
2501 if (*state->chptr->mode.upass) /* reset old upass */
2502 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2503 state->chptr->mode.upass, 0);
2504 else /* remove new bogus upass */
2505 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2506 } else /* send new upass */
2507 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2509 if (state->flags & MODE_PARSE_SET) {
2510 if (state->dir == MODE_ADD) /* set the new upass */
2511 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2512 else /* remove the old upass */
2513 *state->chptr->mode.upass = '\0';
2518 * Helper function to convert admin passes
2521 mode_parse_apass(struct ParseState *state, int *flag_p)
2526 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2529 if (state->parc <= 0) { /* warn if not enough args */
2530 if (MyUser(state->sptr))
2531 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2536 t_str = state->parv[state->args_used++]; /* grab arg */
2540 /* If they're not an oper, they can't change modes */
2541 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2542 send_notoper(state);
2546 /* If a non-service user is trying to force it, refuse. */
2547 if (state->flags & MODE_PARSE_FORCE && MyUser(state->sptr)
2548 && !HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
2549 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2550 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2554 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2555 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2556 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2560 /* If they are not the channel manager, they are not allowed to change it */
2561 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2562 if (*state->chptr->mode.apass) {
2563 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2564 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2566 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2567 "Re-create the channel. The channel must be *empty* for",
2568 "at least a whole minute", "before it can be recreated.");
2573 if (state->done & DONE_APASS) /* allow apass to be set only once */
2575 state->done |= DONE_APASS;
2577 t_len = PASSLEN + 1;
2579 /* clean up the apass string */
2581 while (*++s > ' ' && *s != ':' && --t_len)
2585 if (!*t_str) { /* warn if empty */
2586 if (MyUser(state->sptr))
2587 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2595 if (!(state->flags & MODE_PARSE_FORCE)) {
2596 /* can't remove the apass while upass is still set */
2597 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2598 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2601 /* can't add an apass if one is set, nor can one remove the wrong apass */
2602 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2603 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2604 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2609 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2610 !ircd_strcmp(state->chptr->mode.apass, t_str))
2611 return; /* no apass change */
2613 if (state->flags & MODE_PARSE_BOUNCE) {
2614 if (*state->chptr->mode.apass) /* reset old apass */
2615 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2616 state->chptr->mode.apass, 0);
2617 else /* remove new bogus apass */
2618 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2619 } else /* send new apass */
2620 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2622 if (state->flags & MODE_PARSE_SET) {
2623 if (state->dir == MODE_ADD) { /* set the new apass */
2624 /* Make it VERY clear to the user that this is a one-time password */
2625 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2626 if (MyUser(state->sptr)) {
2627 send_reply(state->sptr, RPL_APASSWARN,
2628 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2629 "Are you SURE you want to use this as Admin password? ",
2630 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2631 send_reply(state->sptr, RPL_APASSWARN,
2632 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2633 "\" to remove the password and then immediately set a new one. "
2634 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2635 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2636 "Now set the channel user password (+U).");
2638 } else { /* remove the old apass */
2639 *state->chptr->mode.apass = '\0';
2640 if (MyUser(state->sptr))
2641 send_reply(state->sptr, RPL_APASSWARN,
2642 "WARNING: You removed the channel Admin password MODE (+A). ",
2643 "If you would disconnect or leave the channel without setting a new password then you will ",
2644 "not be able to set it again and lose ownership of this channel! ",
2645 "SET A NEW PASSWORD NOW!", "");
2650 /** Compare one ban's extent to another.
2651 * This works very similarly to mmatch() but it knows about CIDR masks
2652 * and ban exceptions. If both bans are CIDR-based, compare their
2653 * address bits; otherwise, use mmatch().
2654 * @param[in] old_ban One ban.
2655 * @param[in] new_ban Another ban.
2656 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2659 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2662 assert(old_ban != NULL);
2663 assert(new_ban != NULL);
2664 /* A ban is never treated as a superset of an exception. */
2665 if (!(old_ban->flags & BAN_EXCEPTION)
2666 && (new_ban->flags & BAN_EXCEPTION))
2668 /* If either is not an address mask, match the text masks. */
2669 if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2670 return mmatch(old_ban->banstr, new_ban->banstr);
2671 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2672 if (old_ban->addrbits > new_ban->addrbits)
2674 /* Compare the masks before the hostname part. */
2675 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2676 res = mmatch(old_ban->banstr, new_ban->banstr);
2677 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2680 /* Compare the addresses. */
2681 return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2684 /** Add a ban from a ban list and mark bans that should be removed
2685 * because they overlap.
2687 * There are three invariants for a ban list. First, no ban may be
2688 * more specific than another ban. Second, no exception may be more
2689 * specific than another exception. Finally, no ban may be more
2690 * specific than any exception.
2692 * @param[in,out] banlist Pointer to head of list.
2693 * @param[in] newban Ban (or exception) to add (or remove).
2694 * @return Zero if \a newban could be applied, non-zero if not.
2696 int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
2701 assert(newban->flags & (BAN_ADD|BAN_DEL));
2702 if (newban->flags & BAN_ADD) {
2704 /* If a less specific entry is found, fail. */
2705 for (ban = *banlist; ban; ban = ban->next) {
2706 if (!bmatch(ban, newban)) {
2711 if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2713 totlen += strlen(ban->banstr);
2716 /* Mark more specific entries and add this one to the end of the list. */
2717 while ((ban = *banlist) != NULL) {
2718 if (!bmatch(newban, ban)) {
2719 ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2721 banlist = &ban->next;
2725 } else if (newban->flags & BAN_DEL) {
2726 size_t remove_count = 0;
2727 /* Mark more specific entries. */
2728 for (ban = *banlist; ban; ban = ban->next) {
2729 if (!bmatch(newban, ban)) {
2730 ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2736 /* If no matches were found, fail. */
2740 MyFree(newban->banstr);
2749 * Helper function to convert bans
2752 mode_parse_ban(struct ParseState *state, int *flag_p)
2755 struct Ban *ban, *newban;
2757 if (state->parc <= 0) { /* Not enough args, send ban list */
2758 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2759 send_ban_list(state->sptr, state->chptr);
2760 state->done |= DONE_BANLIST;
2766 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2769 t_str = state->parv[state->args_used++]; /* grab arg */
2773 /* If they're not an oper, they can't change modes */
2774 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2775 send_notoper(state);
2779 if ((s = strchr(t_str, ' ')))
2782 if (!*t_str || *t_str == ':') { /* warn if empty */
2783 if (MyUser(state->sptr))
2784 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2789 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2790 if (!(state->done & DONE_BANCLEAN)) {
2791 for (ban = state->chptr->banlist; ban; ban = ban->next)
2792 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2793 state->done |= DONE_BANCLEAN;
2796 /* remember the ban for the moment... */
2797 newban = state->banlist + (state->numbans++);
2799 newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2800 | (*flag_p == 'b' ? 0 : BAN_EXCEPTION);
2801 newban->banstr = NULL;
2802 set_ban_mask(newban, collapse(pretty_mask(t_str)));
2803 newban->who = cli_name(state->sptr);
2804 newban->when = TStime();
2805 apply_ban(&state->chptr->banlist, newban, 0);
2809 * This is the bottom half of the ban processor
2812 mode_process_bans(struct ParseState *state)
2814 struct Ban *ban, *newban, *prevban, *nextban;
2820 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2822 banlen = strlen(ban->banstr);
2824 nextban = ban->next;
2826 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2828 prevban->next = 0; /* Break the list; ban isn't a real ban */
2830 state->chptr->banlist = 0;
2835 MyFree(ban->banstr);
2838 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2839 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2842 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2843 if (prevban) /* clip it out of the list... */
2844 prevban->next = ban->next;
2846 state->chptr->banlist = ban->next;
2851 ban->banstr = NULL; /* modebuf_mode_string() gave ownership of
2852 * the ban string to state->mbuf */
2856 continue; /* next ban; keep prevban like it is */
2858 ban->flags &= BAN_IPMASK; /* unset other flags */
2859 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2861 prevban->next = 0; /* Break the list; ban isn't a real ban */
2863 state->chptr->banlist = 0;
2865 /* If we're supposed to ignore it, do so. */
2866 if (ban->flags & BAN_OVERLAPPED &&
2867 !(state->flags & MODE_PARSE_BOUNCE)) {
2870 MyFree(ban->banstr);
2872 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2873 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2874 count > feature_int(FEAT_MAXBANS))) {
2875 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2879 MyFree(ban->banstr);
2881 /* add the ban to the buffer */
2882 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2885 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2886 newban = make_ban(ban->banstr);
2887 DupString(newban->who, ban->who);
2888 newban->when = ban->when;
2889 newban->flags = ban->flags & BAN_IPMASK;
2891 newban->next = state->chptr->banlist; /* and link it in */
2892 state->chptr->banlist = newban;
2901 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2903 if (changed) /* if we changed the ban list, we must invalidate the bans */
2904 mode_ban_invalidate(state->chptr);
2908 * Helper function to process client changes
2911 mode_parse_client(struct ParseState *state, int *flag_p)
2914 struct Client *acptr;
2917 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2920 if (state->parc <= 0) /* return if not enough args */
2923 t_str = state->parv[state->args_used++]; /* grab arg */
2927 /* If they're not an oper, they can't change modes */
2928 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2929 send_notoper(state);
2933 if (MyUser(state->sptr)) /* find client we're manipulating */
2934 acptr = find_chasing(state->sptr, t_str, NULL);
2936 acptr = findNUser(t_str);
2939 return; /* find_chasing() already reported an error to the user */
2941 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2942 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2943 state->cli_change[i].flag & flag_p[0]))
2944 break; /* found a slot */
2946 /* Store what we're doing to them */
2947 state->cli_change[i].flag = state->dir | flag_p[0];
2948 state->cli_change[i].client = acptr;
2952 * Helper function to process the changed client list
2955 mode_process_clients(struct ParseState *state)
2958 struct Membership *member;
2960 for (i = 0; state->cli_change[i].flag; i++) {
2961 assert(0 != state->cli_change[i].client);
2963 /* look up member link */
2964 if (!(member = find_member_link(state->chptr,
2965 state->cli_change[i].client)) ||
2966 (MyUser(state->sptr) && IsZombie(member))) {
2967 if (MyUser(state->sptr))
2968 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2969 cli_name(state->cli_change[i].client),
2970 state->chptr->chname);
2974 if ((state->cli_change[i].flag & MODE_ADD &&
2975 (state->cli_change[i].flag & member->status)) ||
2976 (state->cli_change[i].flag & MODE_DEL &&
2977 !(state->cli_change[i].flag & member->status)))
2978 continue; /* no change made, don't do anything */
2980 /* see if the deop is allowed */
2981 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2982 (MODE_DEL | MODE_CHANOP)) {
2983 /* prevent +k users from being deopped */
2984 if (IsChannelService(state->cli_change[i].client)) {
2985 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2986 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2988 (IsServer(state->sptr) ? cli_name(state->sptr) :
2989 cli_name((cli_user(state->sptr))->server)));
2991 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2992 send_reply(state->sptr, ERR_ISCHANSERVICE,
2993 cli_name(state->cli_change[i].client),
2994 state->chptr->chname);
2999 /* check deop for local user */
3000 if (MyUser(state->sptr)) {
3002 /* don't allow local opers to be deopped on local channels */
3003 if (state->cli_change[i].client != state->sptr &&
3004 IsLocalChannel(state->chptr->chname) &&
3005 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3006 send_reply(state->sptr, ERR_ISOPERLCHAN,
3007 cli_name(state->cli_change[i].client),
3008 state->chptr->chname);
3012 if (feature_bool(FEAT_OPLEVELS)) {
3013 /* don't allow to deop members with an op level that is <= our own level */
3014 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3016 && OpLevel(member) <= OpLevel(state->member)) {
3017 int equal = (OpLevel(member) == OpLevel(state->member));
3018 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3019 cli_name(state->cli_change[i].client),
3020 state->chptr->chname,
3021 OpLevel(state->member), OpLevel(member),
3022 "deop", equal ? "the same" : "a higher");
3029 /* set op-level of member being opped */
3030 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3031 (MODE_ADD | MODE_CHANOP)) {
3032 /* If on a channel with upass set, someone with level x gives ops to someone else,
3033 then that person gets level x-1. On other channels, where upass is not set,
3034 the level stays the same. */
3035 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3036 /* Someone being opped by a server gets op-level 0 */
3037 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3038 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3041 /* actually effect the change */
3042 if (state->flags & MODE_PARSE_SET) {
3043 if (state->cli_change[i].flag & MODE_ADD) {
3044 if (IsDelayedJoin(member))
3045 RevealDelayedJoin(member);
3046 member->status |= (state->cli_change[i].flag &
3047 (MODE_CHANOP | MODE_VOICE));
3048 if (state->cli_change[i].flag & MODE_CHANOP)
3049 ClearDeopped(member);
3051 member->status &= ~(state->cli_change[i].flag &
3052 (MODE_CHANOP | MODE_VOICE));
3055 /* accumulate the change */
3056 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3057 state->cli_change[i].client);
3058 } /* for (i = 0; state->cli_change[i].flags; i++) */
3062 * Helper function to process the simple modes
3065 mode_parse_mode(struct ParseState *state, int *flag_p)
3067 /* If they're not an oper, they can't change modes */
3068 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3069 send_notoper(state);
3076 if (state->dir == MODE_ADD) {
3077 state->add |= flag_p[0];
3078 state->del &= ~flag_p[0];
3080 if (flag_p[0] & MODE_SECRET) {
3081 state->add &= ~MODE_PRIVATE;
3082 state->del |= MODE_PRIVATE;
3083 } else if (flag_p[0] & MODE_PRIVATE) {
3084 state->add &= ~MODE_SECRET;
3085 state->del |= MODE_SECRET;
3087 if (flag_p[0] & MODE_DELJOINS) {
3088 state->add &= ~MODE_WASDELJOINS;
3089 state->del |= MODE_WASDELJOINS;
3092 state->add &= ~flag_p[0];
3093 state->del |= flag_p[0];
3096 assert(0 == (state->add & state->del));
3097 assert((MODE_SECRET | MODE_PRIVATE) !=
3098 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3102 * This routine is intended to parse MODE or OPMODE commands and effect the
3103 * changes (or just build the bounce buffer). We pass the starting offset
3107 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3108 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3109 struct Membership* member)
3111 static int chan_flags[] = {
3116 MODE_MODERATED, 'm',
3117 MODE_TOPICLIMIT, 't',
3118 MODE_INVITEONLY, 'i',
3119 MODE_NOPRIVMSGS, 'n',
3133 unsigned int t_mode;
3135 struct ParseState state;
3146 state.chptr = chptr;
3147 state.member = member;
3150 state.flags = flags;
3151 state.dir = MODE_ADD;
3155 state.args_used = 0;
3156 state.max_args = MAXMODEPARAMS;
3159 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3160 state.banlist[i].next = 0;
3161 state.banlist[i].who = 0;
3162 state.banlist[i].when = 0;
3163 state.banlist[i].flags = 0;
3164 state.cli_change[i].flag = 0;
3165 state.cli_change[i].client = 0;
3168 modestr = state.parv[state.args_used++];
3172 for (; *modestr; modestr++) {
3173 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3174 if (flag_p[1] == *modestr)
3177 if (!flag_p[0]) { /* didn't find it? complain and continue */
3178 if (MyUser(state.sptr))
3179 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3184 case '+': /* switch direction to MODE_ADD */
3185 case '-': /* switch direction to MODE_DEL */
3186 state.dir = flag_p[0];
3189 case 'l': /* deal with limits */
3190 mode_parse_limit(&state, flag_p);
3193 case 'k': /* deal with keys */
3194 mode_parse_key(&state, flag_p);
3197 case 'A': /* deal with Admin passes */
3198 if (feature_bool(FEAT_OPLEVELS))
3199 mode_parse_apass(&state, flag_p);
3202 case 'U': /* deal with user passes */
3203 if (feature_bool(FEAT_OPLEVELS))
3204 mode_parse_upass(&state, flag_p);
3207 case 'b': /* deal with bans */
3208 mode_parse_ban(&state, flag_p);
3211 case 'o': /* deal with ops/voice */
3213 mode_parse_client(&state, flag_p);
3216 default: /* deal with other modes */
3217 mode_parse_mode(&state, flag_p);
3219 } /* switch (*modestr) */
3220 } /* for (; *modestr; modestr++) */
3222 if (state.flags & MODE_PARSE_BURST)
3223 break; /* don't interpret any more arguments */
3225 if (state.parc > 0) { /* process next argument in string */
3226 modestr = state.parv[state.args_used++];
3230 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3233 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3234 break; /* we're then going to bounce the mode! */
3236 recv_ts = atoi(modestr);
3238 if (recv_ts && recv_ts < state.chptr->creationtime)
3239 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3241 break; /* break out of while loop */
3242 } else if (state.flags & MODE_PARSE_STRICT ||
3243 (MyUser(state.sptr) && state.max_args <= 0)) {
3244 state.parc++; /* we didn't actually gobble the argument */
3246 break; /* break out of while loop */
3249 } /* while (*modestr) */
3252 * the rest of the function finishes building resultant MODEs; if the
3253 * origin isn't a member or an oper, skip it.
3255 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3256 return state.args_used; /* tell our parent how many args we gobbled */
3258 t_mode = state.chptr->mode.mode;
3260 if (state.del & t_mode) { /* delete any modes to be deleted... */
3261 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3263 t_mode &= ~state.del;
3265 if (state.add & ~t_mode) { /* add any modes to be added... */
3266 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3268 t_mode |= state.add;
3271 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3272 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3273 !(t_mode & MODE_INVITEONLY))
3274 mode_invite_clear(state.chptr);
3276 state.chptr->mode.mode = t_mode;
3279 if (state.flags & MODE_PARSE_WIPEOUT) {
3280 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3281 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3282 state.chptr->mode.limit);
3283 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3284 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3285 state.chptr->mode.key, 0);
3286 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3287 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3288 state.chptr->mode.upass, 0);
3289 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3290 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3291 state.chptr->mode.apass, 0);
3294 if (state.done & DONE_BANCLEAN) /* process bans */
3295 mode_process_bans(&state);
3297 /* process client changes */
3298 if (state.cli_change[0].flag)
3299 mode_process_clients(&state);
3301 return state.args_used; /* tell our parent how many args we gobbled */
3305 * Initialize a join buffer
3308 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3309 struct Client *connect, unsigned int type, char *comment,
3315 assert(0 != source);
3316 assert(0 != connect);
3318 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3319 jbuf->jb_connect = connect;
3320 jbuf->jb_type = type;
3321 jbuf->jb_comment = comment;
3322 jbuf->jb_create = create;
3324 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3325 type == JOINBUF_TYPE_PART ||
3326 type == JOINBUF_TYPE_PARTALL) ?
3327 STARTJOINLEN : STARTCREATELEN) +
3328 (comment ? strlen(comment) + 2 : 0));
3330 for (i = 0; i < MAXJOINARGS; i++)
3331 jbuf->jb_channels[i] = 0;
3335 * Add a channel to the join buffer
3338 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3346 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3347 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3352 is_local = IsLocalChannel(chan->chname);
3354 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3355 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3356 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3357 if (IsUserParting(member))
3359 SetUserParting(member);
3361 /* Send notification to channel */
3362 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3363 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3364 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3365 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3366 else if (MyUser(jbuf->jb_source))
3367 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3368 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3369 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3370 /* XXX: Shouldn't we send a PART here anyway? */
3371 /* to users on the channel? Why? From their POV, the user isn't on
3372 * the channel anymore anyway. We don't send to servers until below,
3373 * when we gang all the channel parts together. Note that this is
3374 * exactly the same logic, albeit somewhat more concise, as was in
3375 * the original m_part.c */
3377 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3378 is_local) /* got to remove user here */
3379 remove_user_from_channel(jbuf->jb_source, chan);
3381 /* Add user to channel */
3382 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3383 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3385 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3387 /* send notification to all servers */
3388 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3389 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3390 "%H %Tu", chan, chan->creationtime);
3392 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3393 /* Send the notification to the channel */
3394 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3396 /* send an op, too, if needed */
3397 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3398 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3399 chan, jbuf->jb_source);
3400 } else if (MyUser(jbuf->jb_source))
3401 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3404 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3405 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3406 return; /* don't send to remote */
3408 /* figure out if channel name will cause buffer to be overflowed */
3409 len = chan ? strlen(chan->chname) + 1 : 2;
3410 if (jbuf->jb_strlen + len > BUFSIZE)
3411 joinbuf_flush(jbuf);
3413 /* add channel to list of channels to send and update counts */
3414 jbuf->jb_channels[jbuf->jb_count++] = chan;
3415 jbuf->jb_strlen += len;
3417 /* if we've used up all slots, flush */
3418 if (jbuf->jb_count >= MAXJOINARGS)
3419 joinbuf_flush(jbuf);
3423 * Flush the channel list to remote servers
3426 joinbuf_flush(struct JoinBuf *jbuf)
3428 char chanlist[BUFSIZE];
3432 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3433 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3434 return 0; /* no joins to process */
3436 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3437 build_string(chanlist, &chanlist_i,
3438 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3439 i == 0 ? '\0' : ',');
3440 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3441 /* Remove user from channel */
3442 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3444 jbuf->jb_channels[i] = 0; /* mark slot empty */
3447 jbuf->jb_count = 0; /* reset base counters */
3448 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3449 STARTJOINLEN : STARTCREATELEN) +
3450 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3452 /* and send the appropriate command */
3453 switch (jbuf->jb_type) {
3454 case JOINBUF_TYPE_CREATE:
3455 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3456 "%s %Tu", chanlist, jbuf->jb_create);
3459 case JOINBUF_TYPE_PART:
3460 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3461 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3469 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3470 int IsInvited(struct Client* cptr, const void* chptr)
3474 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3475 if (lp->value.chptr == chptr)
3480 /* RevealDelayedJoin: sends a join for a hidden user */
3482 void RevealDelayedJoin(struct Membership *member) {
3483 ClearDelayedJoin(member);
3484 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3486 CheckDelayedJoins(member->channel);
3489 /* CheckDelayedJoins: checks and clear +d if necessary */
3491 void CheckDelayedJoins(struct Channel *chan) {
3492 struct Membership *memb2;
3494 if (chan->mode.mode & MODE_WASDELJOINS) {
3495 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3496 if (IsDelayedJoin(memb2))
3501 chan->mode.mode &= ~MODE_WASDELJOINS;
3502 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,