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 Explaination of Zombies
1410 * X --a--> A --b--> B --d--> D
1415 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1416 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1418 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1419 * Remove the user immediately when no users are left on the channel.
1420 * b) On server B : remove the user (who/lp) from the channel, send a
1421 * PART upstream (to A) and pass on the KICK.
1422 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1423 * channel, and pass on the KICK.
1424 * d) On server D : remove the user (who/lp) from the channel, and pass on
1428 * - Setting the ZOMBIE flag never hurts, we either remove the
1429 * client after that or we don't.
1430 * - The KICK message was already passed on, as should be in all cases.
1431 * - `who' is removed in all cases except case a) when users are left.
1432 * - A PART is only sent upstream in case b).
1438 * 1 --- 2 --- 3 --- 4 --- 5
1443 * We also need to turn 'who' into a zombie on servers 1 and 6,
1444 * because a KICK from 'who' (kicking someone else in that direction)
1445 * can arrive there afterwards - which should not be bounced itself.
1446 * Therefore case a) also applies for servers 1 and 6.
1451 /** Turn a user on a channel into a zombie
1452 * This function turns a user into a zombie (see \ref zombie)
1454 * @param member The structure representing this user on this channel.
1455 * @param who The client that is being kicked.
1456 * @param cptr The connection the kick came from.
1457 * @param sptr The client that is doing the kicking.
1458 * @param chptr The channel the user is being kicked from.
1460 void make_zombie(struct Membership* member, struct Client* who,
1461 struct Client* cptr, struct Client* sptr, struct Channel* chptr)
1463 assert(0 != member);
1468 /* Default for case a): */
1471 /* Case b) or c) ?: */
1472 if (MyUser(who)) /* server 4 */
1474 if (IsServer(cptr)) /* Case b) ? */
1475 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1476 remove_user_from_channel(who, chptr);
1479 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1481 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1482 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1483 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1485 remove_user_from_channel(who, chptr);
1490 /* Case a) (servers 1, 2, 3 and 6) */
1491 if (channel_all_zombies(chptr))
1492 remove_user_from_channel(who, chptr);
1494 /* XXX Can't actually call Debug here; if the channel is all zombies,
1495 * chptr will no longer exist when we get here.
1496 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1500 /** returns the number of zombies on a channel
1501 * @param chptr Channel to count zombies in.
1503 * @returns The number of zombies on the channel.
1505 int number_of_zombies(struct Channel *chptr)
1507 struct Membership* member;
1511 for (member = chptr->members; member; member = member->next_member) {
1512 if (IsZombie(member))
1518 /** Concatenate some strings together.
1519 * This helper function builds an argument string in strptr, consisting
1520 * of the original string, a space, and str1 and str2 concatenated (if,
1521 * of course, str2 is not NULL)
1523 * @param strptr The buffer to concatenate into
1524 * @param strptr_i modified offset to the position to modify
1525 * @param str1 The string to contatenate from.
1526 * @param str2 The second string to contatenate from.
1527 * @param c Charactor to seperate the string from str1 and str2.
1530 build_string(char *strptr, int *strptr_i, const char *str1,
1531 const char *str2, char c)
1534 strptr[(*strptr_i)++] = c;
1537 strptr[(*strptr_i)++] = *(str1++);
1541 strptr[(*strptr_i)++] = *(str2++);
1543 strptr[(*strptr_i)] = '\0';
1546 /** Flush out the modes
1547 * This is the workhorse of our ModeBuf suite; this actually generates the
1548 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1550 * @param mbuf The mode buffer to flush
1551 * @param all If true, flush all modes, otherwise leave partial modes in the
1557 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1559 /* we only need the flags that don't take args right now */
1560 static int flags[] = {
1561 /* MODE_CHANOP, 'o', */
1562 /* MODE_VOICE, 'v', */
1565 MODE_MODERATED, 'm',
1566 MODE_TOPICLIMIT, 't',
1567 MODE_INVITEONLY, 'i',
1568 MODE_NOPRIVMSGS, 'n',
1571 MODE_WASDELJOINS, 'd',
1572 /* MODE_KEY, 'k', */
1573 /* MODE_BAN, 'b', */
1575 /* MODE_APASS, 'A', */
1576 /* MODE_UPASS, 'U', */
1582 struct Client *app_source; /* where the MODE appears to come from */
1584 char addbuf[20]; /* accumulates +psmtin, etc. */
1586 char rembuf[20]; /* accumulates -psmtin, etc. */
1588 char *bufptr; /* we make use of indirection to simplify the code */
1591 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1593 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1595 char *strptr; /* more indirection to simplify the code */
1598 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1601 char limitbuf[20]; /* convert limits to strings */
1603 unsigned int limitdel = MODE_LIMIT;
1607 /* If the ModeBuf is empty, we have nothing to do */
1608 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1611 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1613 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1616 app_source = mbuf->mb_source;
1619 * Account for user we're bouncing; we have to get it in on the first
1620 * bounced MODE, or we could have problems
1622 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1623 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1625 /* Calculate the simple flags */
1626 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1627 if (*flag_p & mbuf->mb_add)
1628 addbuf[addbuf_i++] = flag_p[1];
1629 else if (*flag_p & mbuf->mb_rem)
1630 rembuf[rembuf_i++] = flag_p[1];
1633 /* Now go through the modes with arguments... */
1634 for (i = 0; i < mbuf->mb_count; i++) {
1635 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1637 bufptr_i = &addbuf_i;
1640 bufptr_i = &rembuf_i;
1643 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1644 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1646 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1647 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1649 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1650 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1652 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1653 tmp = strlen(MB_STRING(mbuf, i));
1655 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1656 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1659 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1671 bufptr[(*bufptr_i)++] = mode_char;
1672 totalbuflen -= tmp + 1;
1674 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1675 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1676 strlen(MB_STRING(mbuf, i)));
1678 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1679 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1681 bufptr[(*bufptr_i)++] = 'k';
1682 totalbuflen -= tmp + 1;
1684 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1685 /* if it's a limit, we also format the number */
1686 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1688 tmp = strlen(limitbuf);
1690 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1691 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1693 bufptr[(*bufptr_i)++] = 'l';
1694 totalbuflen -= tmp + 1;
1699 /* terminate the mode strings */
1700 addbuf[addbuf_i] = '\0';
1701 rembuf[rembuf_i] = '\0';
1703 /* If we're building a user visible MODE or HACK... */
1704 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1705 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1706 MODEBUF_DEST_LOG)) {
1707 /* Set up the parameter strings */
1713 for (i = 0; i < mbuf->mb_count; i++) {
1714 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1717 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1719 strptr_i = &addstr_i;
1722 strptr_i = &remstr_i;
1725 /* deal with clients... */
1726 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1727 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1729 /* deal with bans... */
1730 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1731 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1733 /* deal with keys... */
1734 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1735 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1736 "*" : MB_STRING(mbuf, i), 0, ' ');
1738 /* deal with invisible passwords */
1739 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1740 build_string(strptr, strptr_i, "*", 0, ' ');
1743 * deal with limit; note we cannot include the limit parameter if we're
1746 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1747 (MODE_ADD | MODE_LIMIT))
1748 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1751 /* send the messages off to their destination */
1752 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1753 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1755 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1756 mbuf->mb_source : app_source),
1757 mbuf->mb_channel->chname,
1758 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1759 addbuf, remstr, addstr,
1760 mbuf->mb_channel->creationtime);
1762 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1763 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1764 "%s%s%s%s%s%s [%Tu]",
1765 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1766 mbuf->mb_source : app_source),
1767 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1768 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1769 mbuf->mb_channel->creationtime);
1771 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1772 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1774 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1775 mbuf->mb_source : app_source),
1776 mbuf->mb_channel->chname,
1777 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1778 addbuf, remstr, addstr,
1779 mbuf->mb_channel->creationtime);
1781 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1782 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1783 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1784 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1785 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1787 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1788 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1789 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1790 rembuf_i ? "-" : "", rembuf,
1791 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1794 /* Now are we supposed to propagate to other servers? */
1795 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1796 /* set up parameter string */
1803 * limit is supressed if we're removing it; we have to figure out which
1804 * direction is the direction for it to be removed, though...
1806 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1808 for (i = 0; i < mbuf->mb_count; i++) {
1809 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1812 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1814 strptr_i = &addstr_i;
1817 strptr_i = &remstr_i;
1820 /* deal with modes that take clients */
1821 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1822 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1824 /* deal with modes that take strings */
1825 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1826 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1829 * deal with the limit. Logic here is complicated; if HACK2 is set,
1830 * we're bouncing the mode, so sense is reversed, and we have to
1831 * include the original limit if it looks like it's being removed
1833 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1834 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1837 /* we were told to deop the source */
1838 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1839 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1840 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1841 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1843 /* mark that we've done this, so we don't do it again */
1844 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1847 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1848 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1849 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1850 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1851 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1852 addbuf, remstr, addstr);
1853 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1855 * If HACK2 was set, we're bouncing; we send the MODE back to the
1856 * connection we got it from with the senses reversed and a TS of 0;
1859 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1860 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1861 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1862 mbuf->mb_channel->creationtime);
1865 * We're propagating a normal MODE command to the rest of the network;
1866 * we send the actual channel TS unless this is a HACK3 or a HACK4
1868 if (IsServer(mbuf->mb_source))
1869 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1870 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1871 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1872 addbuf, remstr, addstr,
1873 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1874 mbuf->mb_channel->creationtime);
1876 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1877 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1878 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1879 addbuf, remstr, addstr);
1883 /* We've drained the ModeBuf... */
1888 /* reinitialize the mode-with-arg slots */
1889 for (i = 0; i < MAXMODEPARAMS; i++) {
1890 /* If we saved any, pack them down */
1891 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1892 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1893 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1895 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1897 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1898 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1900 MB_TYPE(mbuf, i) = 0;
1901 MB_UINT(mbuf, i) = 0;
1904 /* If we're supposed to flush it all, do so--all hail tail recursion */
1905 if (all && mbuf->mb_count)
1906 return modebuf_flush_int(mbuf, 1);
1911 /** Initialise a modebuf
1912 * This routine just initializes a ModeBuf structure with the information
1913 * needed and the options given.
1915 * @param mbuf The mode buffer to initialise.
1916 * @param source The client that is performing the mode.
1918 * @param chan The channel that the mode is being performed upon.
1922 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1923 struct Client *connect, struct Channel *chan, unsigned int dest)
1928 assert(0 != source);
1932 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1936 mbuf->mb_source = source;
1937 mbuf->mb_connect = connect;
1938 mbuf->mb_channel = chan;
1939 mbuf->mb_dest = dest;
1942 /* clear each mode-with-parameter slot */
1943 for (i = 0; i < MAXMODEPARAMS; i++) {
1944 MB_TYPE(mbuf, i) = 0;
1945 MB_UINT(mbuf, i) = 0;
1949 /** Append a new mode to a modebuf
1950 * This routine simply adds modes to be added or deleted; do a binary OR
1951 * with either MODE_ADD or MODE_DEL
1953 * @param mbuf Mode buffer
1954 * @param mode MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1957 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1960 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1962 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1963 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1964 MODE_DELJOINS | MODE_WASDELJOINS);
1966 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1969 if (mode & MODE_ADD) {
1970 mbuf->mb_rem &= ~mode;
1971 mbuf->mb_add |= mode;
1973 mbuf->mb_add &= ~mode;
1974 mbuf->mb_rem |= mode;
1978 /** Append a mode that takes an int argument to the modebuf
1980 * This routine adds a mode to be added or deleted that takes a unsigned
1981 * int parameter; mode may *only* be the relevant mode flag ORed with one
1982 * of MODE_ADD or MODE_DEL
1984 * @param mbuf The mode buffer to append to.
1985 * @param mode The mode to append.
1986 * @param uint The argument to the mode.
1989 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1992 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1994 if (mode == (MODE_LIMIT | MODE_DEL)) {
1995 mbuf->mb_rem |= mode;
1998 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1999 MB_UINT(mbuf, mbuf->mb_count) = uint;
2001 /* when we've reached the maximal count, flush the buffer */
2002 if (++mbuf->mb_count >=
2003 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2004 modebuf_flush_int(mbuf, 0);
2007 /** append a string mode
2008 * This routine adds a mode to be added or deleted that takes a string
2009 * parameter; mode may *only* be the relevant mode flag ORed with one of
2010 * MODE_ADD or MODE_DEL
2012 * @param mbuf The mode buffer to append to.
2013 * @param mode The mode to append.
2014 * @param string The string parameter to append.
2015 * @param free If the string should be free'd later.
2018 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2022 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2024 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2025 MB_STRING(mbuf, mbuf->mb_count) = string;
2027 /* when we've reached the maximal count, flush the buffer */
2028 if (++mbuf->mb_count >=
2029 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2030 modebuf_flush_int(mbuf, 0);
2033 /** Append a mode on a client to a modebuf.
2034 * This routine adds a mode to be added or deleted that takes a client
2035 * parameter; mode may *only* be the relevant mode flag ORed with one of
2036 * MODE_ADD or MODE_DEL
2038 * @param mbuf The modebuf to append the mode to.
2039 * @param mode The mode to append.
2040 * @param client The client argument to append.
2043 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2044 struct Client *client)
2047 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2049 MB_TYPE(mbuf, mbuf->mb_count) = mode;
2050 MB_CLIENT(mbuf, mbuf->mb_count) = client;
2052 /* when we've reached the maximal count, flush the buffer */
2053 if (++mbuf->mb_count >=
2054 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2055 modebuf_flush_int(mbuf, 0);
2058 /** The exported binding for modebuf_flush()
2060 * @param mbuf The mode buffer to flush.
2062 * @see modebuf_flush_int()
2065 modebuf_flush(struct ModeBuf *mbuf)
2067 struct Membership *memb;
2069 /* Check if MODE_WASDELJOINS should be set */
2070 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2071 && (mbuf->mb_rem & MODE_DELJOINS)) {
2072 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2073 if (IsDelayedJoin(memb)) {
2074 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2075 mbuf->mb_add |= MODE_WASDELJOINS;
2076 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2082 return modebuf_flush_int(mbuf, 1);
2085 /* This extracts the simple modes contained in mbuf
2087 * @param mbuf The mode buffer to extract the modes from.
2088 * @param buf The string buffer to write the modes into.
2091 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2093 static int flags[] = {
2094 /* MODE_CHANOP, 'o', */
2095 /* MODE_VOICE, 'v', */
2098 MODE_MODERATED, 'm',
2099 MODE_TOPICLIMIT, 't',
2100 MODE_INVITEONLY, 'i',
2101 MODE_NOPRIVMSGS, 'n',
2105 /* MODE_BAN, 'b', */
2112 int i, bufpos = 0, len;
2114 char *key = 0, limitbuf[20];
2115 char *apass = 0, *upass = 0;
2124 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2125 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2126 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2128 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2129 key = MB_STRING(mbuf, i);
2130 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2131 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2132 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2133 upass = MB_STRING(mbuf, i);
2134 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2135 apass = MB_STRING(mbuf, i);
2142 buf[bufpos++] = '+'; /* start building buffer */
2144 for (flag_p = flags; flag_p[0]; flag_p += 2)
2146 buf[bufpos++] = flag_p[1];
2148 for (i = 0, len = bufpos; i < len; i++) {
2150 build_string(buf, &bufpos, key, 0, ' ');
2151 else if (buf[i] == 'l')
2152 build_string(buf, &bufpos, limitbuf, 0, ' ');
2153 else if (buf[i] == 'U')
2154 build_string(buf, &bufpos, upass, 0, ' ');
2155 else if (buf[i] == 'A')
2156 build_string(buf, &bufpos, apass, 0, ' ');
2164 /** Simple function to invalidate bans
2166 * This function sets all bans as being valid.
2168 * @param chan The channel to operate on.
2171 mode_ban_invalidate(struct Channel *chan)
2173 struct Membership *member;
2175 for (member = chan->members; member; member = member->next_member)
2176 ClearBanValid(member);
2179 /** Simple function to drop invite structures
2181 * Remove all the invites on the channel.
2183 * @param chan Channel to remove invites from.
2187 mode_invite_clear(struct Channel *chan)
2189 while (chan->invites)
2190 del_invite(chan->invites->value.cptr, chan);
2193 /* What we've done for mode_parse so far... */
2194 #define DONE_LIMIT 0x01 /**< We've set the limit */
2195 #define DONE_KEY 0x02 /**< We've set the key */
2196 #define DONE_BANLIST 0x04 /**< We've sent the ban list */
2197 #define DONE_NOTOPER 0x08 /**< We've sent a "Not oper" error */
2198 #define DONE_BANCLEAN 0x10 /**< We've cleaned bans... */
2199 #define DONE_UPASS 0x20 /**< We've set user pass */
2200 #define DONE_APASS 0x40 /**< We've set admin pass */
2203 struct ModeBuf *mbuf;
2204 struct Client *cptr;
2205 struct Client *sptr;
2206 struct Channel *chptr;
2207 struct Membership *member;
2218 struct Ban banlist[MAXPARA];
2221 struct Client *client;
2222 } cli_change[MAXPARA];
2225 /** Helper function to send "Not oper" or "Not member" messages
2226 * Here's a helper function to deal with sending along "Not oper" or
2227 * "Not member" messages
2229 * @param state Parsing State object
2232 send_notoper(struct ParseState *state)
2234 if (state->done & DONE_NOTOPER)
2237 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2238 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2240 state->done |= DONE_NOTOPER;
2244 * Helper function to convert limits
2246 * @param state Parsing state object.
2250 mode_parse_limit(struct ParseState *state, int *flag_p)
2252 unsigned int t_limit;
2254 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2255 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2258 if (state->parc <= 0) { /* warn if not enough args */
2259 if (MyUser(state->sptr))
2260 need_more_params(state->sptr, "MODE +l");
2264 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2268 if ((int)t_limit<0) /* don't permit a negative limit */
2271 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2272 (!t_limit || t_limit == state->chptr->mode.limit))
2275 t_limit = state->chptr->mode.limit;
2277 /* If they're not an oper, they can't change modes */
2278 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2279 send_notoper(state);
2283 /* Can't remove a limit that's not there */
2284 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2287 /* Skip if this is a burst and a lower limit than this is set already */
2288 if ((state->flags & MODE_PARSE_BURST) &&
2289 (state->chptr->mode.mode & flag_p[0]) &&
2290 (state->chptr->mode.limit < t_limit))
2293 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2295 state->done |= DONE_LIMIT;
2300 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2302 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2303 if (state->dir & MODE_ADD) {
2304 state->chptr->mode.mode |= flag_p[0];
2305 state->chptr->mode.limit = t_limit;
2307 state->chptr->mode.mode &= ~flag_p[0];
2308 state->chptr->mode.limit = 0;
2314 * Helper function to convert keys
2317 mode_parse_key(struct ParseState *state, int *flag_p)
2322 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2325 if (state->parc <= 0) { /* warn if not enough args */
2326 if (MyUser(state->sptr))
2327 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2332 t_str = state->parv[state->args_used++]; /* grab arg */
2336 /* If they're not an oper, they can't change modes */
2337 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2338 send_notoper(state);
2342 if (state->done & DONE_KEY) /* allow key to be set only once */
2344 state->done |= DONE_KEY;
2348 /* clean up the key string */
2350 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2354 if (!*t_str) { /* warn if empty */
2355 if (MyUser(state->sptr))
2356 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2364 /* Skip if this is a burst, we have a key already and the new key is
2365 * after the old one alphabetically */
2366 if ((state->flags & MODE_PARSE_BURST) &&
2367 *(state->chptr->mode.key) &&
2368 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2371 /* can't add a key if one is set, nor can one remove the wrong key */
2372 if (!(state->flags & MODE_PARSE_FORCE))
2373 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2374 (state->dir == MODE_DEL &&
2375 ircd_strcmp(state->chptr->mode.key, t_str))) {
2376 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2380 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2381 !ircd_strcmp(state->chptr->mode.key, t_str))
2382 return; /* no key change */
2384 if (state->flags & MODE_PARSE_BOUNCE) {
2385 if (*state->chptr->mode.key) /* reset old key */
2386 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2387 state->chptr->mode.key, 0);
2388 else /* remove new bogus key */
2389 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2390 } else /* send new key */
2391 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2393 if (state->flags & MODE_PARSE_SET) {
2394 if (state->dir == MODE_ADD) /* set the new key */
2395 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2396 else /* remove the old key */
2397 *state->chptr->mode.key = '\0';
2402 * Helper function to convert user passes
2405 mode_parse_upass(struct ParseState *state, int *flag_p)
2410 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2413 if (state->parc <= 0) { /* warn if not enough args */
2414 if (MyUser(state->sptr))
2415 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2420 t_str = state->parv[state->args_used++]; /* grab arg */
2424 /* If they're not an oper, they can't change modes */
2425 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2426 send_notoper(state);
2430 /* If a non-service user is trying to force it, refuse. */
2431 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2432 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2433 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2437 /* If they are not the channel manager, they are not allowed to change it */
2438 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2439 if (*state->chptr->mode.apass) {
2440 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2441 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2443 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2444 "Re-create the channel. The channel must be *empty* for",
2445 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2446 "before it can be recreated.");
2451 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2453 state->done |= DONE_UPASS;
2455 t_len = PASSLEN + 1;
2457 /* clean up the upass string */
2459 while (*++s > ' ' && *s != ':' && --t_len)
2463 if (!*t_str) { /* warn if empty */
2464 if (MyUser(state->sptr))
2465 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2473 if (!(state->flags & MODE_PARSE_FORCE))
2474 /* can't add the upass while apass is not set */
2475 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2476 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2479 /* can't add a upass if one is set, nor can one remove the wrong upass */
2480 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2481 (state->dir == MODE_DEL &&
2482 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2483 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2487 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2488 !ircd_strcmp(state->chptr->mode.upass, t_str))
2489 return; /* no upass change */
2491 if (state->flags & MODE_PARSE_BOUNCE) {
2492 if (*state->chptr->mode.upass) /* reset old upass */
2493 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2494 state->chptr->mode.upass, 0);
2495 else /* remove new bogus upass */
2496 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2497 } else /* send new upass */
2498 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2500 if (state->flags & MODE_PARSE_SET) {
2501 if (state->dir == MODE_ADD) /* set the new upass */
2502 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2503 else /* remove the old upass */
2504 *state->chptr->mode.upass = '\0';
2509 * Helper function to convert admin passes
2512 mode_parse_apass(struct ParseState *state, int *flag_p)
2517 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2520 if (state->parc <= 0) { /* warn if not enough args */
2521 if (MyUser(state->sptr))
2522 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2527 t_str = state->parv[state->args_used++]; /* grab arg */
2531 /* If they're not an oper, they can't change modes */
2532 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2533 send_notoper(state);
2537 /* If a non-service user is trying to force it, refuse. */
2538 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2539 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2540 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2544 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2545 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2546 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2550 /* If they are not the channel manager, they are not allowed to change it */
2551 if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2552 if (*state->chptr->mode.apass) {
2553 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2554 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2556 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2557 "Re-create the channel. The channel must be *empty* for",
2558 "at least a whole minute", "before it can be recreated.");
2563 if (state->done & DONE_APASS) /* allow apass to be set only once */
2565 state->done |= DONE_APASS;
2567 t_len = PASSLEN + 1;
2569 /* clean up the apass string */
2571 while (*++s > ' ' && *s != ':' && --t_len)
2575 if (!*t_str) { /* warn if empty */
2576 if (MyUser(state->sptr))
2577 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2585 if (!(state->flags & MODE_PARSE_FORCE)) {
2586 /* can't remove the apass while upass is still set */
2587 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2588 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2591 /* can't add an apass if one is set, nor can one remove the wrong apass */
2592 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2593 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2594 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2599 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2600 !ircd_strcmp(state->chptr->mode.apass, t_str))
2601 return; /* no apass change */
2603 if (state->flags & MODE_PARSE_BOUNCE) {
2604 if (*state->chptr->mode.apass) /* reset old apass */
2605 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2606 state->chptr->mode.apass, 0);
2607 else /* remove new bogus apass */
2608 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2609 } else /* send new apass */
2610 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2612 if (state->flags & MODE_PARSE_SET) {
2613 if (state->dir == MODE_ADD) { /* set the new apass */
2614 /* Make it VERY clear to the user that this is a one-time password */
2615 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2616 if (MyUser(state->sptr)) {
2617 send_reply(state->sptr, RPL_APASSWARN,
2618 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2619 "Are you SURE you want to use this as Admin password? ",
2620 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2621 send_reply(state->sptr, RPL_APASSWARN,
2622 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2623 "\" to remove the password and then immediately set a new one. "
2624 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2625 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2626 "Now set the channel user password (+u).");
2628 } else { /* remove the old apass */
2629 *state->chptr->mode.apass = '\0';
2630 if (MyUser(state->sptr))
2631 send_reply(state->sptr, RPL_APASSWARN,
2632 "WARNING: You removed the channel Admin password MODE (+A). ",
2633 "If you would disconnect or leave the channel without setting a new password then you will ",
2634 "not be able to set it again and lose ownership of this channel! ",
2635 "SET A NEW PASSWORD NOW!", "");
2640 /** Compare one ban's extent to another.
2641 * This works very similarly to mmatch() but it knows about CIDR masks
2642 * and ban exceptions. If both bans are CIDR-based, compare their
2643 * address bits; otherwise, use mmatch().
2644 * @param[in] old_ban One ban.
2645 * @param[in] new_ban Another ban.
2646 * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2649 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2652 assert(old_ban != NULL);
2653 assert(new_ban != NULL);
2654 /* A ban is never treated as a superset of an exception. */
2655 if (!(old_ban->flags & BAN_EXCEPTION)
2656 && (new_ban->flags & BAN_EXCEPTION))
2658 /* If either is not an address mask, match the text masks. */
2659 if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2660 return mmatch(old_ban->banstr, new_ban->banstr);
2661 /* If the old ban has a longer prefix than new, it cannot be a superset. */
2662 if (old_ban->addrbits > new_ban->addrbits)
2664 /* Compare the masks before the hostname part. */
2665 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2666 res = mmatch(old_ban->banstr, new_ban->banstr);
2667 old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2670 /* Compare the addresses. */
2671 return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2674 /** Add a ban from a ban list and mark bans that should be removed
2675 * because they overlap.
2677 * There are three invariants for a ban list. First, no ban may be
2678 * more specific than another ban. Second, no exception may be more
2679 * specific than another exception. Finally, no ban may be more
2680 * specific than any exception.
2682 * @param[in,out] banlist Pointer to head of list.
2683 * @param[in] newban Ban (or exception) to add (or remove).
2684 * @return Zero if \a newban could be applied, non-zero if not.
2686 int apply_ban(struct Ban **banlist, struct Ban *newban)
2691 assert(newban->flags & (BAN_ADD|BAN_DEL));
2692 if (newban->flags & BAN_ADD) {
2694 /* If a less specific entry is found, fail. */
2695 for (ban = *banlist; ban; ban = ban->next) {
2696 if (!bmatch(ban, newban)) {
2700 if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2702 totlen += strlen(ban->banstr);
2705 /* Mark more specific entries and add this one to the end of the list. */
2706 while ((ban = *banlist) != NULL) {
2707 if (!bmatch(newban, ban)) {
2708 ban->flags |= BAN_OVERLAPPED;
2710 banlist = &ban->next;
2714 } else if (newban->flags & BAN_DEL) {
2715 size_t remove_count = 0;
2716 /* Mark more specific entries. */
2717 for (ban = *banlist; ban; ban = ban->next) {
2718 if (!bmatch(newban, ban)) {
2719 ban->flags |= BAN_OVERLAPPED;
2723 /* If no matches were found, fail. */
2724 if (!remove_count) {
2735 * Helper function to convert bans
2738 mode_parse_ban(struct ParseState *state, int *flag_p)
2741 struct Ban *ban, *newban = 0;
2743 if (state->parc <= 0) { /* Not enough args, send ban list */
2744 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2745 send_ban_list(state->sptr, state->chptr);
2746 state->done |= DONE_BANLIST;
2752 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2755 t_str = state->parv[state->args_used++]; /* grab arg */
2759 /* If they're not an oper, they can't change modes */
2760 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2761 send_notoper(state);
2765 if ((s = strchr(t_str, ' ')))
2768 if (!*t_str || *t_str == ':') { /* warn if empty */
2769 if (MyUser(state->sptr))
2770 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2775 if (!state->chptr->banlist) {
2776 state->chptr->banlist = newban; /* add our ban with its flags */
2777 state->done |= DONE_BANCLEAN;
2781 /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2782 if (!(state->done & DONE_BANCLEAN)) {
2783 for (ban = state->chptr->banlist; ban; ban = ban->next)
2784 ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2785 state->done |= DONE_BANCLEAN;
2788 /* remember the ban for the moment... */
2789 newban = state->banlist + (state->numbans++);
2791 newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2792 | (*flag_p == 'b' ? 0 : BAN_EXCEPTION);
2793 newban->banstr = NULL;
2794 set_ban_mask(newban, collapse(pretty_mask(t_str)));
2795 newban->who = cli_name(state->sptr);
2796 newban->when = TStime();
2797 apply_ban(&state->chptr->banlist, newban);
2801 * This is the bottom half of the ban processor
2804 mode_process_bans(struct ParseState *state)
2806 struct Ban *ban, *newban, *prevban, *nextban;
2812 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2814 banlen = strlen(ban->banstr);
2816 nextban = ban->next;
2818 if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2820 prevban->next = 0; /* Break the list; ban isn't a real ban */
2822 state->chptr->banlist = 0;
2827 MyFree(ban->banstr);
2830 } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2831 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2833 state->flags & MODE_PARSE_SET);
2835 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2836 if (prevban) /* clip it out of the list... */
2837 prevban->next = ban->next;
2839 state->chptr->banlist = ban->next;
2844 ban->banstr = NULL; /* modebuf_mode_string() gave ownership of
2845 * the ban string to state->mbuf */
2849 continue; /* next ban; keep prevban like it is */
2851 ban->flags &= BAN_IPMASK; /* unset other flags */
2852 } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2854 prevban->next = 0; /* Break the list; ban isn't a real ban */
2856 state->chptr->banlist = 0;
2858 /* If we're supposed to ignore it, do so. */
2859 if (ban->flags & BAN_OVERLAPPED &&
2860 !(state->flags & MODE_PARSE_BOUNCE)) {
2863 MyFree(ban->banstr);
2865 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2866 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2867 count > feature_int(FEAT_MAXBANS))) {
2868 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2872 MyFree(ban->banstr);
2874 /* add the ban to the buffer */
2875 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2877 !(state->flags & MODE_PARSE_SET));
2879 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2880 newban = make_ban(ban->banstr);
2881 DupString(newban->who, ban->who);
2882 newban->when = ban->when;
2883 newban->flags = ban->flags & BAN_IPMASK;
2885 newban->next = state->chptr->banlist; /* and link it in */
2886 state->chptr->banlist = newban;
2895 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2897 if (changed) /* if we changed the ban list, we must invalidate the bans */
2898 mode_ban_invalidate(state->chptr);
2902 * Helper function to process client changes
2905 mode_parse_client(struct ParseState *state, int *flag_p)
2908 struct Client *acptr;
2911 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2914 if (state->parc <= 0) /* return if not enough args */
2917 t_str = state->parv[state->args_used++]; /* grab arg */
2921 /* If they're not an oper, they can't change modes */
2922 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2923 send_notoper(state);
2927 if (MyUser(state->sptr)) /* find client we're manipulating */
2928 acptr = find_chasing(state->sptr, t_str, NULL);
2930 acptr = findNUser(t_str);
2933 return; /* find_chasing() already reported an error to the user */
2935 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2936 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2937 state->cli_change[i].flag & flag_p[0]))
2938 break; /* found a slot */
2940 /* Store what we're doing to them */
2941 state->cli_change[i].flag = state->dir | flag_p[0];
2942 state->cli_change[i].client = acptr;
2946 * Helper function to process the changed client list
2949 mode_process_clients(struct ParseState *state)
2952 struct Membership *member;
2954 for (i = 0; state->cli_change[i].flag; i++) {
2955 assert(0 != state->cli_change[i].client);
2957 /* look up member link */
2958 if (!(member = find_member_link(state->chptr,
2959 state->cli_change[i].client)) ||
2960 (MyUser(state->sptr) && IsZombie(member))) {
2961 if (MyUser(state->sptr))
2962 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2963 cli_name(state->cli_change[i].client),
2964 state->chptr->chname);
2968 if ((state->cli_change[i].flag & MODE_ADD &&
2969 (state->cli_change[i].flag & member->status)) ||
2970 (state->cli_change[i].flag & MODE_DEL &&
2971 !(state->cli_change[i].flag & member->status)))
2972 continue; /* no change made, don't do anything */
2974 /* see if the deop is allowed */
2975 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2976 (MODE_DEL | MODE_CHANOP)) {
2977 /* prevent +k users from being deopped */
2978 if (IsChannelService(state->cli_change[i].client)) {
2979 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2980 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2982 (IsServer(state->sptr) ? cli_name(state->sptr) :
2983 cli_name((cli_user(state->sptr))->server)));
2985 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2986 send_reply(state->sptr, ERR_ISCHANSERVICE,
2987 cli_name(state->cli_change[i].client),
2988 state->chptr->chname);
2993 /* check deop for local user */
2994 if (MyUser(state->sptr)) {
2996 /* don't allow local opers to be deopped on local channels */
2997 if (state->cli_change[i].client != state->sptr &&
2998 IsLocalChannel(state->chptr->chname) &&
2999 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3000 send_reply(state->sptr, ERR_ISOPERLCHAN,
3001 cli_name(state->cli_change[i].client),
3002 state->chptr->chname);
3006 if (feature_bool(FEAT_OPLEVELS)) {
3007 /* don't allow to deop members with an op level that is <= our own level */
3008 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
3010 && OpLevel(member) <= OpLevel(state->member)) {
3011 int equal = (OpLevel(member) == OpLevel(state->member));
3012 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3013 cli_name(state->cli_change[i].client),
3014 state->chptr->chname,
3015 OpLevel(state->member), OpLevel(member),
3016 "deop", equal ? "the same" : "a higher");
3023 /* set op-level of member being opped */
3024 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3025 (MODE_ADD | MODE_CHANOP)) {
3026 /* If on a channel with upass set, someone with level x gives ops to someone else,
3027 then that person gets level x-1. On other channels, where upass is not set,
3028 the level stays the same. */
3029 int level_increment = *state->chptr->mode.upass ? 1 : 0;
3030 /* Someone being opped by a server gets op-level 0 */
3031 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3032 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3035 /* actually effect the change */
3036 if (state->flags & MODE_PARSE_SET) {
3037 if (state->cli_change[i].flag & MODE_ADD) {
3038 if (IsDelayedJoin(member))
3039 RevealDelayedJoin(member);
3040 member->status |= (state->cli_change[i].flag &
3041 (MODE_CHANOP | MODE_VOICE));
3042 if (state->cli_change[i].flag & MODE_CHANOP)
3043 ClearDeopped(member);
3045 member->status &= ~(state->cli_change[i].flag &
3046 (MODE_CHANOP | MODE_VOICE));
3049 /* accumulate the change */
3050 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3051 state->cli_change[i].client);
3052 } /* for (i = 0; state->cli_change[i].flags; i++) */
3056 * Helper function to process the simple modes
3059 mode_parse_mode(struct ParseState *state, int *flag_p)
3061 /* If they're not an oper, they can't change modes */
3062 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3063 send_notoper(state);
3070 if (state->dir == MODE_ADD) {
3071 state->add |= flag_p[0];
3072 state->del &= ~flag_p[0];
3074 if (flag_p[0] & MODE_SECRET) {
3075 state->add &= ~MODE_PRIVATE;
3076 state->del |= MODE_PRIVATE;
3077 } else if (flag_p[0] & MODE_PRIVATE) {
3078 state->add &= ~MODE_SECRET;
3079 state->del |= MODE_SECRET;
3081 if (flag_p[0] & MODE_DELJOINS) {
3082 state->add &= ~MODE_WASDELJOINS;
3083 state->del |= MODE_WASDELJOINS;
3086 state->add &= ~flag_p[0];
3087 state->del |= flag_p[0];
3090 assert(0 == (state->add & state->del));
3091 assert((MODE_SECRET | MODE_PRIVATE) !=
3092 (state->add & (MODE_SECRET | MODE_PRIVATE)));
3096 * This routine is intended to parse MODE or OPMODE commands and effect the
3097 * changes (or just build the bounce buffer). We pass the starting offset
3101 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3102 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3103 struct Membership* member)
3105 static int chan_flags[] = {
3110 MODE_MODERATED, 'm',
3111 MODE_TOPICLIMIT, 't',
3112 MODE_INVITEONLY, 'i',
3113 MODE_NOPRIVMSGS, 'n',
3127 unsigned int t_mode;
3129 struct ParseState state;
3140 state.chptr = chptr;
3141 state.member = member;
3144 state.flags = flags;
3145 state.dir = MODE_ADD;
3149 state.args_used = 0;
3150 state.max_args = MAXMODEPARAMS;
3153 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3154 state.banlist[i].next = 0;
3155 state.banlist[i].who = 0;
3156 state.banlist[i].when = 0;
3157 state.banlist[i].flags = 0;
3158 state.cli_change[i].flag = 0;
3159 state.cli_change[i].client = 0;
3162 modestr = state.parv[state.args_used++];
3166 for (; *modestr; modestr++) {
3167 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3168 if (flag_p[1] == *modestr)
3171 if (!flag_p[0]) { /* didn't find it? complain and continue */
3172 if (MyUser(state.sptr))
3173 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3178 case '+': /* switch direction to MODE_ADD */
3179 case '-': /* switch direction to MODE_DEL */
3180 state.dir = flag_p[0];
3183 case 'l': /* deal with limits */
3184 mode_parse_limit(&state, flag_p);
3187 case 'k': /* deal with keys */
3188 mode_parse_key(&state, flag_p);
3191 case 'A': /* deal with Admin passes */
3192 if (feature_bool(FEAT_OPLEVELS))
3193 mode_parse_apass(&state, flag_p);
3196 case 'U': /* deal with user passes */
3197 if (feature_bool(FEAT_OPLEVELS))
3198 mode_parse_upass(&state, flag_p);
3201 case 'b': /* deal with bans */
3202 mode_parse_ban(&state, flag_p);
3205 case 'o': /* deal with ops/voice */
3207 mode_parse_client(&state, flag_p);
3210 default: /* deal with other modes */
3211 mode_parse_mode(&state, flag_p);
3213 } /* switch (*modestr) */
3214 } /* for (; *modestr; modestr++) */
3216 if (state.flags & MODE_PARSE_BURST)
3217 break; /* don't interpret any more arguments */
3219 if (state.parc > 0) { /* process next argument in string */
3220 modestr = state.parv[state.args_used++];
3224 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3227 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3228 break; /* we're then going to bounce the mode! */
3230 recv_ts = atoi(modestr);
3232 if (recv_ts && recv_ts < state.chptr->creationtime)
3233 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3235 break; /* break out of while loop */
3236 } else if (state.flags & MODE_PARSE_STRICT ||
3237 (MyUser(state.sptr) && state.max_args <= 0)) {
3238 state.parc++; /* we didn't actually gobble the argument */
3240 break; /* break out of while loop */
3243 } /* while (*modestr) */
3246 * the rest of the function finishes building resultant MODEs; if the
3247 * origin isn't a member or an oper, skip it.
3249 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3250 return state.args_used; /* tell our parent how many args we gobbled */
3252 t_mode = state.chptr->mode.mode;
3254 if (state.del & t_mode) { /* delete any modes to be deleted... */
3255 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3257 t_mode &= ~state.del;
3259 if (state.add & ~t_mode) { /* add any modes to be added... */
3260 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3262 t_mode |= state.add;
3265 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3266 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3267 !(t_mode & MODE_INVITEONLY))
3268 mode_invite_clear(state.chptr);
3270 state.chptr->mode.mode = t_mode;
3273 if (state.flags & MODE_PARSE_WIPEOUT) {
3274 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3275 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3276 state.chptr->mode.limit);
3277 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3278 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3279 state.chptr->mode.key, 0);
3280 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3281 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3282 state.chptr->mode.upass, 0);
3283 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3284 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3285 state.chptr->mode.apass, 0);
3288 if (state.done & DONE_BANCLEAN) /* process bans */
3289 mode_process_bans(&state);
3291 /* process client changes */
3292 if (state.cli_change[0].flag)
3293 mode_process_clients(&state);
3295 return state.args_used; /* tell our parent how many args we gobbled */
3299 * Initialize a join buffer
3302 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3303 struct Client *connect, unsigned int type, char *comment,
3309 assert(0 != source);
3310 assert(0 != connect);
3312 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3313 jbuf->jb_connect = connect;
3314 jbuf->jb_type = type;
3315 jbuf->jb_comment = comment;
3316 jbuf->jb_create = create;
3318 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3319 type == JOINBUF_TYPE_PART ||
3320 type == JOINBUF_TYPE_PARTALL) ?
3321 STARTJOINLEN : STARTCREATELEN) +
3322 (comment ? strlen(comment) + 2 : 0));
3324 for (i = 0; i < MAXJOINARGS; i++)
3325 jbuf->jb_channels[i] = 0;
3329 * Add a channel to the join buffer
3332 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3340 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3341 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3346 is_local = IsLocalChannel(chan->chname);
3348 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3349 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3350 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3351 if (IsUserParting(member))
3353 SetUserParting(member);
3355 /* Send notification to channel */
3356 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3357 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3358 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3359 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3360 else if (MyUser(jbuf->jb_source))
3361 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3362 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3363 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3364 /* XXX: Shouldn't we send a PART here anyway? */
3365 /* to users on the channel? Why? From their POV, the user isn't on
3366 * the channel anymore anyway. We don't send to servers until below,
3367 * when we gang all the channel parts together. Note that this is
3368 * exactly the same logic, albeit somewhat more concise, as was in
3369 * the original m_part.c */
3371 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3372 is_local) /* got to remove user here */
3373 remove_user_from_channel(jbuf->jb_source, chan);
3375 /* Add user to channel */
3376 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3377 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3379 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3381 /* send notification to all servers */
3382 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3383 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3384 "%H %Tu", chan, chan->creationtime);
3386 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3387 /* Send the notification to the channel */
3388 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3390 /* send an op, too, if needed */
3391 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3392 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3393 chan, jbuf->jb_source);
3394 } else if (MyUser(jbuf->jb_source))
3395 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3398 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3399 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3400 return; /* don't send to remote */
3402 /* figure out if channel name will cause buffer to be overflowed */
3403 len = chan ? strlen(chan->chname) + 1 : 2;
3404 if (jbuf->jb_strlen + len > BUFSIZE)
3405 joinbuf_flush(jbuf);
3407 /* add channel to list of channels to send and update counts */
3408 jbuf->jb_channels[jbuf->jb_count++] = chan;
3409 jbuf->jb_strlen += len;
3411 /* if we've used up all slots, flush */
3412 if (jbuf->jb_count >= MAXJOINARGS)
3413 joinbuf_flush(jbuf);
3417 * Flush the channel list to remote servers
3420 joinbuf_flush(struct JoinBuf *jbuf)
3422 char chanlist[BUFSIZE];
3426 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3427 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3428 return 0; /* no joins to process */
3430 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3431 build_string(chanlist, &chanlist_i,
3432 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3433 i == 0 ? '\0' : ',');
3434 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3435 /* Remove user from channel */
3436 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3438 jbuf->jb_channels[i] = 0; /* mark slot empty */
3441 jbuf->jb_count = 0; /* reset base counters */
3442 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3443 STARTJOINLEN : STARTCREATELEN) +
3444 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3446 /* and send the appropriate command */
3447 switch (jbuf->jb_type) {
3448 case JOINBUF_TYPE_CREATE:
3449 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3450 "%s %Tu", chanlist, jbuf->jb_create);
3453 case JOINBUF_TYPE_PART:
3454 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3455 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3463 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3464 int IsInvited(struct Client* cptr, const void* chptr)
3468 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3469 if (lp->value.chptr == chptr)
3474 /* RevealDelayedJoin: sends a join for a hidden user */
3476 void RevealDelayedJoin(struct Membership *member) {
3477 ClearDelayedJoin(member);
3478 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3480 CheckDelayedJoins(member->channel);
3483 /* CheckDelayedJoins: checks and clear +d if necessary */
3485 void CheckDelayedJoins(struct Channel *chan) {
3486 struct Membership *memb2;
3488 if (chan->mode.mode & MODE_WASDELJOINS) {
3489 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3490 if (IsDelayedJoin(memb2))
3495 chan->mode.mode &= ~MODE_WASDELJOINS;
3496 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,