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.
26 #include "destruct_event.h"
29 #include "ircd_alloc.h"
30 #include "ircd_chattr.h"
31 #include "ircd_defs.h"
32 #include "ircd_features.h"
34 #include "ircd_reply.h"
35 #include "ircd_snprintf.h"
36 #include "ircd_string.h"
43 #include "querycmds.h"
60 struct Channel* GlobalChannelList = 0;
62 static unsigned int membershipAllocCount;
63 static struct Membership* membershipFreeList;
65 void del_invite(struct Client *, struct Channel *);
67 const char* const PartFmt1 = ":%s " MSG_PART " %s";
68 const char* const PartFmt2 = ":%s " MSG_PART " %s :%s";
69 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
70 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
73 static struct SLink* next_ban;
74 static struct SLink* prev_ban;
75 static struct SLink* removed_bans_list;
78 * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
79 * but the only way to do it without changing set_mode intensively.
81 int LocalChanOperMode = 0;
85 * return the length (>=0) of a chain of links.
87 static int list_length(struct SLink *lp)
91 for (; lp; lp = lp->next)
97 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
103 /* Servers don't have member links */
104 if (IsServer(cptr)||IsMe(cptr))
107 /* +k users are typically on a LOT of channels. So we iterate over who
108 * is in the channel. X/W are +k and are in about 5800 channels each.
109 * however there are typically no more than 1000 people in a channel
112 if (IsChannelService(cptr)) {
115 assert(m->channel == chptr);
121 /* Users on the other hand aren't allowed on more than 15 channels. 50%
122 * of users that are on channels are on 2 or less, 95% are on 7 or less,
123 * and 99% are on 10 or less.
126 m = (cli_user(cptr))->channel;
128 assert(m->user == cptr);
129 if (m->channel == chptr)
138 * find_chasing - Find the client structure for a nick name (user)
139 * using history mechanism if necessary. If the client is not found, an error
140 * message (NO SUCH NICK) is generated. If the client was found
141 * through the history, chasing will be 1 and otherwise 0.
143 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
145 struct Client* who = FindClient(user);
152 if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
153 send_reply(sptr, ERR_NOSUCHNICK, user);
162 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
163 * as the parameters. If NULL, they become "*".
165 #define NUH_BUFSIZE (NICKLEN + USERLEN + HOSTLEN + 3)
166 static char *make_nick_user_host(char *namebuf, const char *nick,
167 const char *name, const char *host)
169 ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
174 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
175 * IP-number as the parameters. If NULL, they become "*".
177 #define NUI_BUFSIZE (NICKLEN + USERLEN + SOCKIPLEN + 4)
178 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
179 const struct irc_in_addr *ip)
181 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
186 * Subtract one user from channel i (and free channel
187 * block, if channel became empty).
188 * Returns: true (1) if channel still has members.
189 * false (0) if the channel is now empty.
191 int sub1_from_channel(struct Channel* chptr)
193 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
195 assert(0 != chptr->members);
203 * Also channels without Apass set need to be kept alive,
204 * otherwise Bad Guys(tm) would be able to takeover
205 * existing channels too easily, and then set an Apass!
206 * However, if a channel without Apass becomes empty
207 * then we try to be kind to them and remove possible
210 chptr->mode.mode &= ~MODE_INVITEONLY;
211 chptr->mode.limit = 0;
213 * We do NOT reset a possible key or bans because when
214 * the 'channel owners' can't get in because of a key
215 * or ban then apparently there was a fight/takeover
216 * on the channel and we want them to contact IRC opers
217 * who then will educate them on the use of Apass/upass.
220 if (feature_bool(FEAT_OPLEVELS)) {
221 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
222 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
224 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
226 destruct_channel(chptr);
231 int destruct_channel(struct Channel* chptr)
236 assert(0 == chptr->members);
238 /* Channel became (or was) empty: Remove channel */
239 if (is_listed(chptr))
242 for (i = 0; i <= HighestFd; i++)
244 struct Client *acptr = 0;
245 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
246 (cli_listing(acptr))->chptr == chptr)
248 list_next_channels(acptr, 1);
249 break; /* Only one client can list a channel */
254 * Now, find all invite links from channel structure
256 while ((tmp = chptr->invites))
257 del_invite(tmp->value.cptr, chptr);
259 tmp = chptr->banlist;
264 MyFree(obtmp->value.ban.banstr);
265 MyFree(obtmp->value.ban.who);
269 chptr->prev->next = chptr->next;
271 GlobalChannelList = chptr->next;
273 chptr->next->prev = chptr->prev;
275 --UserStats.channels;
277 * make sure that channel actually got removed from hash table
279 assert(chptr->hnext == chptr);
287 * `cptr' must be the client adding the ban.
289 * If `change' is true then add `banid' to channel `chptr'.
290 * Returns 0 if the ban was added.
291 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
292 * Return -1 otherwise.
294 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
295 * when `change' is false, otherwise they will be removed from the banlist.
296 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
297 * respectively will return these bans until NULL is returned.
299 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
300 * is reset (unless a non-zero value is returned, in which case the
301 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
305 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
306 int change, int firsttime)
311 int removed_bans = 0;
312 int len = strlen(banid);
317 assert(0 == prev_ban);
318 assert(0 == removed_bans_list);
322 for (banp = &chptr->banlist; *banp;)
324 len += strlen((*banp)->value.ban.banstr);
326 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
328 if (!strcmp((*banp)->value.ban.banstr, banid))
330 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
334 else if (!mmatch((*banp)->value.ban.banstr, banid))
336 if (!mmatch(banid, (*banp)->value.ban.banstr))
338 struct SLink *tmp = *banp;
344 len -= strlen(tmp->value.ban.banstr);
347 /* These will be sent to the user later as -b */
348 tmp->next = removed_bans_list;
349 removed_bans_list = tmp;
352 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
354 tmp->flags |= CHFL_BAN_OVERLAPPED;
365 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
366 banp = &(*banp)->next;
369 if (MyUser(cptr) && !removed_bans &&
370 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
371 (cnt >= feature_int(FEAT_MAXBANS))))
373 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
379 struct Membership* member;
381 ban->next = chptr->banlist;
383 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
384 assert(0 != ban->value.ban.banstr);
385 strcpy(ban->value.ban.banstr, banid);
387 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
388 DupString(ban->value.ban.who, cli_name(&me));
390 DupString(ban->value.ban.who, cli_name(cptr));
391 assert(0 != ban->value.ban.who);
393 ban->value.ban.when = TStime();
394 ban->flags = CHFL_BAN; /* This bit is never used I think... */
395 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
396 ban->flags |= CHFL_BAN_IPMASK;
397 chptr->banlist = ban;
400 * Erase ban-valid-bit
402 for (member = chptr->members; member; member = member->next_member)
403 ClearBanValid(member); /* `ban' == channel member ! */
408 struct SLink *next_removed_overlapped_ban(void)
410 struct SLink *tmp = removed_bans_list;
413 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
414 MyFree(prev_ban->value.ban.banstr);
415 MyFree(prev_ban->value.ban.who);
420 removed_bans_list = removed_bans_list->next;
426 * find_channel_member - returns Membership * if a person is joined and not a zombie
428 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
430 struct Membership* member;
433 member = find_member_link(chptr, cptr);
434 return (member && !IsZombie(member)) ? member : 0;
438 * is_banned - a non-zero value if banned else 0.
440 static int is_banned(struct Client *cptr, struct Channel *chptr,
441 struct Membership* member)
444 char tmphost[HOSTLEN + 1];
445 char nu_host[NUH_BUFSIZE];
446 char nu_realhost[NUH_BUFSIZE];
447 char nu_ip[NUI_BUFSIZE];
455 if (member && IsBanValid(member))
456 return IsBanned(member);
458 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
459 (cli_user(cptr))->host);
462 if (HasHiddenHost(cptr))
464 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
465 (cli_user(cptr))->username,
466 cli_user(cptr)->realhost);
470 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
471 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
472 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
473 cli_user(cptr)->username,
478 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
479 if ((tmp->flags & CHFL_BAN_IPMASK)) {
481 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
482 (cli_user(cptr))->username, &cli_ip(cptr));
483 if (match(tmp->value.ban.banstr, ip_s) == 0)
486 if (match(tmp->value.ban.banstr, s) == 0)
488 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
504 return (tmp != NULL);
508 * adds a user to a channel by adding another link to the channels member
511 void add_user_to_channel(struct Channel* chptr, struct Client* who,
512 unsigned int flags, int oplevel)
519 struct Membership* member = membershipFreeList;
521 membershipFreeList = member->next_member;
523 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
524 ++membershipAllocCount;
529 member->channel = chptr;
530 member->status = flags;
531 member->oplevel = oplevel;
533 member->next_member = chptr->members;
534 if (member->next_member)
535 member->next_member->prev_member = member;
536 member->prev_member = 0;
537 chptr->members = member;
539 member->next_channel = (cli_user(who))->channel;
540 if (member->next_channel)
541 member->next_channel->prev_channel = member;
542 member->prev_channel = 0;
543 (cli_user(who))->channel = member;
545 if (chptr->destruct_event)
546 remove_destruct_event(chptr);
548 ++((cli_user(who))->joined);
552 static int remove_member_from_channel(struct Membership* member)
554 struct Channel* chptr;
556 chptr = member->channel;
558 * unlink channel member list
560 if (member->next_member)
561 member->next_member->prev_member = member->prev_member;
562 if (member->prev_member)
563 member->prev_member->next_member = member->next_member;
565 member->channel->members = member->next_member;
568 * If this is the last delayed-join user, may have to clear WASDELJOINS.
570 if (IsDelayedJoin(member))
571 CheckDelayedJoins(chptr);
574 * unlink client channel list
576 if (member->next_channel)
577 member->next_channel->prev_channel = member->prev_channel;
578 if (member->prev_channel)
579 member->prev_channel->next_channel = member->next_channel;
581 (cli_user(member->user))->channel = member->next_channel;
583 --(cli_user(member->user))->joined;
585 member->next_member = membershipFreeList;
586 membershipFreeList = member;
588 return sub1_from_channel(chptr);
591 static int channel_all_zombies(struct Channel* chptr)
593 struct Membership* member;
595 for (member = chptr->members; member; member = member->next_member) {
596 if (!IsZombie(member))
603 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
606 struct Membership* member;
609 if ((member = find_member_link(chptr, cptr))) {
610 if (remove_member_from_channel(member)) {
611 if (channel_all_zombies(chptr)) {
613 * XXX - this looks dangerous but isn't if we got the referential
614 * integrity right for channels
616 while (remove_member_from_channel(chptr->members))
623 void remove_user_from_all_channels(struct Client* cptr)
625 struct Membership* chan;
627 assert(0 != cli_user(cptr));
629 while ((chan = (cli_user(cptr))->channel))
630 remove_user_from_channel(cptr, chan->channel);
633 int is_chan_op(struct Client *cptr, struct Channel *chptr)
635 struct Membership* member;
637 if ((member = find_member_link(chptr, cptr)))
638 return (!IsZombie(member) && IsChanOp(member));
643 int is_zombie(struct Client *cptr, struct Channel *chptr)
645 struct Membership* member;
649 if ((member = find_member_link(chptr, cptr)))
650 return IsZombie(member);
654 int has_voice(struct Client* cptr, struct Channel* chptr)
656 struct Membership* member;
659 if ((member = find_member_link(chptr, cptr)))
660 return (!IsZombie(member) && HasVoice(member));
665 int member_can_send_to_channel(struct Membership* member, int reveal)
669 /* Discourage using the Apass to get op. They should use the upass. */
670 if (IsChannelManager(member) && *member->channel->mode.upass)
673 if (IsVoicedOrOpped(member))
676 * If it's moderated, and you aren't a priviledged user, you can't
679 if (member->channel->mode.mode & MODE_MODERATED)
682 * If you're banned then you can't speak either.
683 * but because of the amount of CPU time that is_banned chews
684 * we only check it for our clients.
686 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
689 if (IsDelayedJoin(member) && reveal)
690 RevealDelayedJoin(member);
695 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
697 struct Membership *member;
700 * Servers can always speak on channels.
705 member = find_channel_member(cptr, chptr);
708 * You can't speak if you're off channel, and it is +n (no external messages)
712 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
713 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
716 return !is_banned(cptr, chptr, NULL);
718 return member_can_send_to_channel(member, reveal);
722 * find_no_nickchange_channel
723 * if a member and not (opped or voiced) and (banned or moderated)
724 * return the name of the first channel banned on
726 const char* find_no_nickchange_channel(struct Client* cptr)
729 struct Membership* member;
730 for (member = (cli_user(cptr))->channel; member;
731 member = member->next_channel) {
732 if (!IsVoicedOrOpped(member) &&
733 (is_banned(cptr, member->channel, member) ||
734 (member->channel->mode.mode & MODE_MODERATED)))
735 return member->channel->chname;
743 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
744 * with the parameters in pbuf.
746 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
747 struct Channel *chptr, struct Membership *member)
749 int previous_parameter = 0;
756 if (chptr->mode.mode & MODE_SECRET)
758 else if (chptr->mode.mode & MODE_PRIVATE)
760 if (chptr->mode.mode & MODE_MODERATED)
762 if (chptr->mode.mode & MODE_TOPICLIMIT)
764 if (chptr->mode.mode & MODE_INVITEONLY)
766 if (chptr->mode.mode & MODE_NOPRIVMSGS)
768 if (chptr->mode.mode & MODE_REGONLY)
770 if (chptr->mode.mode & MODE_DELJOINS)
772 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
774 if (chptr->mode.limit) {
776 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
777 previous_parameter = 1;
780 if (*chptr->mode.key) {
782 if (previous_parameter)
784 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
785 strcat(pbuf, chptr->mode.key);
788 previous_parameter = 1;
790 if (*chptr->mode.apass) {
792 if (previous_parameter)
794 if (IsServer(cptr)) {
795 strcat(pbuf, chptr->mode.apass);
798 previous_parameter = 1;
800 if (*chptr->mode.upass) {
802 if (previous_parameter)
804 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
805 strcat(pbuf, chptr->mode.upass);
812 int compare_member_oplevel(const void *mp1, const void *mp2)
814 struct Membership const* member1 = *(struct Membership const**)mp1;
815 struct Membership const* member2 = *(struct Membership const**)mp2;
816 if (member1->oplevel == member2->oplevel)
818 return (member1->oplevel < member2->oplevel) ? -1 : 1;
822 * send "cptr" a full list of the modes for channel chptr.
824 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
826 /* The order in which modes are generated is now mandatory */
827 static unsigned int current_flags[4] =
828 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
834 struct Membership* member;
836 char modebuf[MODEBUFLEN];
837 char parabuf[MODEBUFLEN];
839 int number_of_ops = 0;
840 int opped_members_index = 0;
841 struct Membership** opped_members = NULL;
842 int last_oplevel = 0;
843 int feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
848 if (IsLocalChannel(chptr->chname))
851 member = chptr->members;
852 lp2 = chptr->banlist;
854 *modebuf = *parabuf = '\0';
855 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
857 for (first = 1; full; first = 0) /* Loop for multiple messages */
859 full = 0; /* Assume by default we get it
860 all in one message */
862 /* (Continued) prefix: "<Y> B <channel> <TS>" */
863 /* is there any better way we can do this? */
864 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
865 chptr->creationtime);
867 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
870 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
871 msgq_append(&me, mb, " %s", modebuf);
874 msgq_append(&me, mb, " %s", parabuf);
878 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
880 * First find all opless members.
881 * Run 2 times over all members, to group the members with
882 * and without voice together.
883 * Then run 2 times over all opped members (which are ordered
884 * by op-level) to also group voice and non-voice together.
886 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
890 if (flag_cnt < 2 && IsChanOp(member))
893 * The first loop (to find all non-voice/op), we count the ops.
894 * The second loop (to find all voiced non-ops), store the ops
895 * in a dynamic array.
900 opped_members[opped_members_index++] = member;
902 /* Only handle the members with the flags that we are interested in. */
903 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
905 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
906 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
908 full = 1; /* Make sure we continue after
910 /* Ensure the new BURST line contains the current
911 * ":mode", except when there is no mode yet. */
912 new_mode = (flag_cnt > 0) ? 1 : 0;
913 break; /* Do not add this member to this message */
915 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
916 first = 0; /* From now on, use commas to add new nicks */
919 * Do we have a nick with a new mode ?
920 * Or are we starting a new BURST line?
922 if (new_mode || !feat_oplevels)
925 * This means we are at the _first_ member that has only
926 * voice, or the first member that has only ops, or the
927 * first member that has voice and ops (so we get here
928 * at most three times, plus once for every start of
929 * a continued BURST line where only these modes is current.
930 * In the two cases where the current mode includes ops,
931 * we need to add the _absolute_ value of the oplevel to the mode.
933 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
936 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
938 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
940 /* append the absolute value of the oplevel */
942 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
947 msgq_append(&me, mb, tbuf);
950 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
953 * This can't be the first member of a (continued) BURST
954 * message because then either flag_cnt == 0 or new_mode == 1
955 * Now we need to append the incremental value of the oplevel.
957 char tbuf[2 + MAXOPLEVELDIGITS];
958 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
959 last_oplevel = member->oplevel;
960 msgq_append(&me, mb, tbuf);
963 /* Go to the next `member'. */
965 member = member->next_member;
967 member = opped_members[++opped_members_index];
972 /* Point `member' at the start of the list again. */
975 member = chptr->members;
976 /* Now, after one loop, we know the number of ops and can
977 * allocate the dynamic array with pointer to the ops. */
978 opped_members = (struct Membership**)
979 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
980 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
984 /* At the end of the second loop, sort the opped members with
985 * increasing op-level, so that we will output them in the
986 * correct order (and all op-level increments stay positive) */
988 qsort(opped_members, number_of_ops,
989 sizeof(struct Membership*), compare_member_oplevel);
990 /* The third and fourth loop run only over the opped members. */
991 member = opped_members[(opped_members_index = 0)];
994 } /* loop over 0,+v,+o,+ov */
998 /* Attach all bans, space seperated " :%ban ban ..." */
999 for (first = 2; lp2; lp2 = lp2->next)
1001 len = strlen(lp2->value.ban.banstr);
1002 if (msgq_bufleft(mb) < len + 1 + first)
1003 /* The +1 stands for the added ' '.
1004 * The +first stands for the added ":%".
1010 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1011 lp2->value.ban.banstr);
1016 send_buffer(cptr, mb, 0); /* Send this message */
1018 } /* Continue when there was something
1019 that didn't fit (full==1) */
1021 MyFree(opped_members);
1022 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1023 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1024 chptr->creationtime, chptr->topic_time, chptr->topic);
1030 * by Carlo Wood (Run), 05 Oct 1998.
1034 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1035 * When the user name or host name are too long (USERLEN and HOSTLEN
1036 * respectively) then they are cut off at the start with a '*'.
1038 * The following transformations are made:
1040 * 1) xxx -> nick!*@*
1041 * 2) xxx.xxx -> *!*@host
1042 * 3) xxx!yyy -> nick!user@*
1043 * 4) xxx@yyy -> *!user@host
1044 * 5) xxx!yyy@zzz -> nick!user@host
1046 char *pretty_mask(char *mask)
1048 static char star[2] = { '*', 0 };
1049 static char retmask[NUH_BUFSIZE];
1050 char *last_dot = NULL;
1053 /* Case 1: default */
1058 /* Do a _single_ pass through the characters of the mask: */
1059 for (ptr = mask; *ptr; ++ptr)
1063 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1067 else if (*ptr == '@')
1069 /* Case 4: Found last '@' (without finding a '!' yet) */
1074 else if (*ptr == '.')
1076 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1086 /* Case 4 or 5: Found last '@' */
1092 if (user == star && last_dot)
1102 char *nick_end = (user != star) ? user - 1 : ptr;
1103 if (nick_end - nick > NICKLEN)
1109 char *user_end = (host != star) ? host - 1 : ptr;
1110 if (user_end - user > USERLEN)
1112 user = user_end - USERLEN;
1117 if (host != star && ptr - host > HOSTLEN)
1119 host = ptr - HOSTLEN;
1122 return make_nick_user_host(retmask, nick, user, host);
1125 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1132 for (lp = chptr->banlist; lp; lp = lp->next)
1133 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1134 lp->value.ban.who, lp->value.ban.when);
1136 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1139 /* We are now treating the <key> part of /join <channel list> <key> as a key
1140 * ring; that is, we try one key against the actual channel key, and if that
1141 * doesn't work, we try the next one, and so on. -Kev -Texaco
1142 * Returns: 0 on match, 1 otherwise
1143 * This version contributed by SeKs <intru@info.polymtl.ca>
1145 static int compall(char *key, char *keyring)
1150 p1 = key; /* point to the key... */
1151 while (*p1 && *p1 == *keyring)
1152 { /* step through the key and ring until they
1158 if (!*p1 && (!*keyring || *keyring == ','))
1159 /* ok, if we're at the end of the and also at the end of one of the keys
1160 in the keyring, we have a match */
1163 if (!*keyring) /* if we're at the end of the key ring, there
1164 weren't any matches, so we return 1 */
1167 /* Not at the end of the key ring, so step
1168 through to the next key in the ring: */
1169 while (*keyring && *(keyring++) != ',');
1171 goto top; /* and check it against the key */
1174 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1176 int overrideJoin = 0;
1179 * Now a banned user CAN join if invited -- Nemesi
1180 * Now a user CAN escape channel limit if invited -- bfriendly
1181 * Now a user CAN escape anything if invited -- Isomer
1184 if (IsInvited(sptr, chptr))
1187 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1188 a HACK(4) notice will be sent if he would not have been supposed
1189 to join normally. */
1190 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1191 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1192 compall("OVERRIDE",key) == 0)
1193 overrideJoin = MAGIC_OPER_OVERRIDE;
1195 if (chptr->mode.mode & MODE_INVITEONLY)
1196 return overrideJoin + ERR_INVITEONLYCHAN;
1198 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1199 return overrideJoin + ERR_CHANNELISFULL;
1201 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1202 return overrideJoin + ERR_NEEDREGGEDNICK;
1204 if (is_banned(sptr, chptr, NULL))
1205 return overrideJoin + ERR_BANNEDFROMCHAN;
1208 * now using compall (above) to test against a whole key ring -Kev
1210 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1211 return overrideJoin + ERR_BADCHANNELKEY;
1214 return ERR_DONTCHEAT;
1220 * Remove bells and commas from channel name
1222 void clean_channelname(char *cn)
1226 for (i = 0; cn[i]; i++) {
1227 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1231 if (IsChannelLower(cn[i])) {
1232 cn[i] = ToLower(cn[i]);
1238 if ((unsigned char)(cn[i]) == 0xd0)
1239 cn[i] = (char) 0xf0;
1246 * Get Channel block for i (and allocate a new channel
1247 * block, if it didn't exists before).
1249 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1251 struct Channel *chptr;
1254 if (EmptyString(chname))
1257 len = strlen(chname);
1258 if (MyUser(cptr) && len > CHANNELLEN)
1261 *(chname + CHANNELLEN) = '\0';
1263 if ((chptr = FindChannel(chname)))
1265 if (flag == CGT_CREATE)
1267 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1269 ++UserStats.channels;
1270 memset(chptr, 0, sizeof(struct Channel));
1271 strcpy(chptr->chname, chname);
1272 if (GlobalChannelList)
1273 GlobalChannelList->prev = chptr;
1275 chptr->next = GlobalChannelList;
1276 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1277 GlobalChannelList = chptr;
1283 void add_invite(struct Client *cptr, struct Channel *chptr)
1285 struct SLink *inv, **tmp;
1287 del_invite(cptr, chptr);
1289 * Delete last link in chain if the list is max length
1291 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1292 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1293 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1295 * Add client to channel invite list
1298 inv->value.cptr = cptr;
1299 inv->next = chptr->invites;
1300 chptr->invites = inv;
1302 * Add channel to the end of the client invite list
1304 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1306 inv->value.chptr = chptr;
1309 (cli_user(cptr))->invites++;
1313 * Delete Invite block from channel invite list and client invite list
1315 void del_invite(struct Client *cptr, struct Channel *chptr)
1317 struct SLink **inv, *tmp;
1319 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1320 if (tmp->value.cptr == cptr)
1325 (cli_user(cptr))->invites--;
1329 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1330 if (tmp->value.chptr == chptr)
1339 /* List and skip all channels that are listen */
1340 void list_next_channels(struct Client *cptr, int nr)
1342 struct ListingArgs *args = cli_listing(cptr);
1343 struct Channel *chptr = args->chptr;
1344 chptr->mode.mode &= ~MODE_LISTED;
1345 while (is_listed(chptr) || --nr >= 0)
1347 for (; chptr; chptr = chptr->next)
1349 if (!cli_user(cptr))
1351 if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1352 SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1354 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1355 chptr->creationtime > args->min_time &&
1356 chptr->creationtime < args->max_time &&
1357 (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1358 chptr->topic_time > args->min_topic_time &&
1359 chptr->topic_time < args->max_topic_time)))
1361 if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1362 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1364 chptr = chptr->next;
1370 MyFree(cli_listing(cptr));
1371 cli_listing(cptr) = NULL;
1372 send_reply(cptr, RPL_LISTEND);
1378 (cli_listing(cptr))->chptr = chptr;
1379 chptr->mode.mode |= MODE_LISTED;
1392 * X --a--> A --b--> B --d--> D
1396 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1397 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1399 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1400 * Remove the user immediately when no users are left on the channel.
1401 * b) On server B : remove the user (who/lp) from the channel, send a
1402 * PART upstream (to A) and pass on the KICK.
1403 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1404 * channel, and pass on the KICK.
1405 * d) On server D : remove the user (who/lp) from the channel, and pass on
1409 * - Setting the ZOMBIE flag never hurts, we either remove the
1410 * client after that or we don't.
1411 * - The KICK message was already passed on, as should be in all cases.
1412 * - `who' is removed in all cases except case a) when users are left.
1413 * - A PART is only sent upstream in case b).
1419 * 1 --- 2 --- 3 --- 4 --- 5
1423 * We also need to turn 'who' into a zombie on servers 1 and 6,
1424 * because a KICK from 'who' (kicking someone else in that direction)
1425 * can arrive there afterwards - which should not be bounced itself.
1426 * Therefore case a) also applies for servers 1 and 6.
1430 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1431 struct Client* sptr, struct Channel* chptr)
1433 assert(0 != member);
1438 /* Default for case a): */
1441 /* Case b) or c) ?: */
1442 if (MyUser(who)) /* server 4 */
1444 if (IsServer(cptr)) /* Case b) ? */
1445 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1446 remove_user_from_channel(who, chptr);
1449 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1451 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1452 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1453 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1455 remove_user_from_channel(who, chptr);
1460 /* Case a) (servers 1, 2, 3 and 6) */
1461 if (channel_all_zombies(chptr))
1462 remove_user_from_channel(who, chptr);
1464 /* XXX Can't actually call Debug here; if the channel is all zombies,
1465 * chptr will no longer exist when we get here.
1466 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1470 int number_of_zombies(struct Channel *chptr)
1472 struct Membership* member;
1476 for (member = chptr->members; member; member = member->next_member) {
1477 if (IsZombie(member))
1484 * This helper function builds an argument string in strptr, consisting
1485 * of the original string, a space, and str1 and str2 concatenated (if,
1486 * of course, str2 is not NULL)
1489 build_string(char *strptr, int *strptr_i, const char *str1,
1490 const char *str2, char c)
1493 strptr[(*strptr_i)++] = c;
1496 strptr[(*strptr_i)++] = *(str1++);
1500 strptr[(*strptr_i)++] = *(str2++);
1502 strptr[(*strptr_i)] = '\0';
1506 * This is the workhorse of our ModeBuf suite; this actually generates the
1507 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1510 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1512 /* we only need the flags that don't take args right now */
1513 static int flags[] = {
1514 /* MODE_CHANOP, 'o', */
1515 /* MODE_VOICE, 'v', */
1518 MODE_MODERATED, 'm',
1519 MODE_TOPICLIMIT, 't',
1520 MODE_INVITEONLY, 'i',
1521 MODE_NOPRIVMSGS, 'n',
1524 MODE_WASDELJOINS, 'd',
1525 /* MODE_KEY, 'k', */
1526 /* MODE_BAN, 'b', */
1528 /* MODE_APASS, 'A', */
1529 /* MODE_UPASS, 'u', */
1535 struct Client *app_source; /* where the MODE appears to come from */
1537 char addbuf[20]; /* accumulates +psmtin, etc. */
1539 char rembuf[20]; /* accumulates -psmtin, etc. */
1541 char *bufptr; /* we make use of indirection to simplify the code */
1544 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1546 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1548 char *strptr; /* more indirection to simplify the code */
1551 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1554 char limitbuf[20]; /* convert limits to strings */
1556 unsigned int limitdel = MODE_LIMIT;
1560 /* If the ModeBuf is empty, we have nothing to do */
1561 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1564 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1566 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1569 app_source = mbuf->mb_source;
1572 * Account for user we're bouncing; we have to get it in on the first
1573 * bounced MODE, or we could have problems
1575 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1576 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1578 /* Calculate the simple flags */
1579 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1580 if (*flag_p & mbuf->mb_add)
1581 addbuf[addbuf_i++] = flag_p[1];
1582 else if (*flag_p & mbuf->mb_rem)
1583 rembuf[rembuf_i++] = flag_p[1];
1586 /* Now go through the modes with arguments... */
1587 for (i = 0; i < mbuf->mb_count; i++) {
1588 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1590 bufptr_i = &addbuf_i;
1593 bufptr_i = &rembuf_i;
1596 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1597 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1599 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1600 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1602 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1603 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1605 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1606 tmp = strlen(MB_STRING(mbuf, i));
1608 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1609 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1612 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1624 bufptr[(*bufptr_i)++] = mode_char;
1625 totalbuflen -= tmp + 1;
1627 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1628 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1629 strlen(MB_STRING(mbuf, i)));
1631 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1632 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1634 bufptr[(*bufptr_i)++] = 'k';
1635 totalbuflen -= tmp + 1;
1637 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1638 /* if it's a limit, we also format the number */
1639 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1641 tmp = strlen(limitbuf);
1643 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1644 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1646 bufptr[(*bufptr_i)++] = 'l';
1647 totalbuflen -= tmp + 1;
1652 /* terminate the mode strings */
1653 addbuf[addbuf_i] = '\0';
1654 rembuf[rembuf_i] = '\0';
1656 /* If we're building a user visible MODE or HACK... */
1657 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1658 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1659 MODEBUF_DEST_LOG)) {
1660 /* Set up the parameter strings */
1666 for (i = 0; i < mbuf->mb_count; i++) {
1667 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1670 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1672 strptr_i = &addstr_i;
1675 strptr_i = &remstr_i;
1678 /* deal with clients... */
1679 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1680 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1682 /* deal with bans... */
1683 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1684 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1686 /* deal with keys... */
1687 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1688 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1689 "*" : MB_STRING(mbuf, i), 0, ' ');
1691 /* deal with invisible passwords */
1692 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1693 build_string(strptr, strptr_i, "*", 0, ' ');
1696 * deal with limit; note we cannot include the limit parameter if we're
1699 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1700 (MODE_ADD | MODE_LIMIT))
1701 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1704 /* send the messages off to their destination */
1705 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1706 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1708 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1709 mbuf->mb_source : app_source),
1710 mbuf->mb_channel->chname,
1711 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1712 addbuf, remstr, addstr,
1713 mbuf->mb_channel->creationtime);
1715 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1716 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1717 "%s%s%s%s%s%s [%Tu]",
1718 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1719 mbuf->mb_source : app_source),
1720 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1721 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1722 mbuf->mb_channel->creationtime);
1724 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1725 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1727 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1728 mbuf->mb_source : app_source),
1729 mbuf->mb_channel->chname,
1730 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1731 addbuf, remstr, addstr,
1732 mbuf->mb_channel->creationtime);
1734 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1735 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1736 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1737 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1738 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1740 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1741 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1742 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1743 rembuf_i ? "-" : "", rembuf,
1744 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1747 /* Now are we supposed to propagate to other servers? */
1748 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1749 /* set up parameter string */
1756 * limit is supressed if we're removing it; we have to figure out which
1757 * direction is the direction for it to be removed, though...
1759 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1761 for (i = 0; i < mbuf->mb_count; i++) {
1762 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1765 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1767 strptr_i = &addstr_i;
1770 strptr_i = &remstr_i;
1773 /* deal with modes that take clients */
1774 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1775 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1777 /* deal with modes that take strings */
1778 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1779 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1782 * deal with the limit. Logic here is complicated; if HACK2 is set,
1783 * we're bouncing the mode, so sense is reversed, and we have to
1784 * include the original limit if it looks like it's being removed
1786 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1787 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1790 /* we were told to deop the source */
1791 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1792 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1793 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1794 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1796 /* mark that we've done this, so we don't do it again */
1797 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1800 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1801 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1802 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1803 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1804 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1805 addbuf, remstr, addstr);
1806 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1808 * If HACK2 was set, we're bouncing; we send the MODE back to the
1809 * connection we got it from with the senses reversed and a TS of 0;
1812 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1813 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1814 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1815 mbuf->mb_channel->creationtime);
1818 * We're propagating a normal MODE command to the rest of the network;
1819 * we send the actual channel TS unless this is a HACK3 or a HACK4
1821 if (IsServer(mbuf->mb_source))
1822 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1823 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1824 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1825 addbuf, remstr, addstr,
1826 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1827 mbuf->mb_channel->creationtime);
1829 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1830 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1831 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1832 addbuf, remstr, addstr);
1836 /* We've drained the ModeBuf... */
1841 /* reinitialize the mode-with-arg slots */
1842 for (i = 0; i < MAXMODEPARAMS; i++) {
1843 /* If we saved any, pack them down */
1844 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1845 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1846 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1848 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1850 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1851 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1853 MB_TYPE(mbuf, i) = 0;
1854 MB_UINT(mbuf, i) = 0;
1857 /* If we're supposed to flush it all, do so--all hail tail recursion */
1858 if (all && mbuf->mb_count)
1859 return modebuf_flush_int(mbuf, 1);
1865 * This routine just initializes a ModeBuf structure with the information
1866 * needed and the options given.
1869 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1870 struct Client *connect, struct Channel *chan, unsigned int dest)
1875 assert(0 != source);
1879 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1883 mbuf->mb_source = source;
1884 mbuf->mb_connect = connect;
1885 mbuf->mb_channel = chan;
1886 mbuf->mb_dest = dest;
1889 /* clear each mode-with-parameter slot */
1890 for (i = 0; i < MAXMODEPARAMS; i++) {
1891 MB_TYPE(mbuf, i) = 0;
1892 MB_UINT(mbuf, i) = 0;
1897 * This routine simply adds modes to be added or deleted; do a binary OR
1898 * with either MODE_ADD or MODE_DEL
1901 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1904 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1906 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1907 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1908 MODE_DELJOINS | MODE_WASDELJOINS);
1910 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1913 if (mode & MODE_ADD) {
1914 mbuf->mb_rem &= ~mode;
1915 mbuf->mb_add |= mode;
1917 mbuf->mb_add &= ~mode;
1918 mbuf->mb_rem |= mode;
1923 * This routine adds a mode to be added or deleted that takes a unsigned
1924 * int parameter; mode may *only* be the relevant mode flag ORed with one
1925 * of MODE_ADD or MODE_DEL
1928 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1931 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1933 if (mode == (MODE_LIMIT | MODE_DEL)) {
1934 mbuf->mb_rem |= mode;
1937 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1938 MB_UINT(mbuf, mbuf->mb_count) = uint;
1940 /* when we've reached the maximal count, flush the buffer */
1941 if (++mbuf->mb_count >=
1942 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1943 modebuf_flush_int(mbuf, 0);
1947 * This routine adds a mode to be added or deleted that takes a string
1948 * parameter; mode may *only* be the relevant mode flag ORed with one of
1949 * MODE_ADD or MODE_DEL
1952 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1956 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1958 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1959 MB_STRING(mbuf, mbuf->mb_count) = string;
1961 /* when we've reached the maximal count, flush the buffer */
1962 if (++mbuf->mb_count >=
1963 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1964 modebuf_flush_int(mbuf, 0);
1968 * This routine adds a mode to be added or deleted that takes a client
1969 * parameter; mode may *only* be the relevant mode flag ORed with one of
1970 * MODE_ADD or MODE_DEL
1973 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1974 struct Client *client)
1977 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1979 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1980 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1982 /* when we've reached the maximal count, flush the buffer */
1983 if (++mbuf->mb_count >=
1984 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1985 modebuf_flush_int(mbuf, 0);
1989 * This is the exported binding for modebuf_flush()
1992 modebuf_flush(struct ModeBuf *mbuf)
1994 struct Membership *memb;
1996 /* Check if MODE_WASDELJOINS should be set */
1997 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1998 && (mbuf->mb_rem & MODE_DELJOINS)) {
1999 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2000 if (IsDelayedJoin(memb)) {
2001 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2002 mbuf->mb_add |= MODE_WASDELJOINS;
2003 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2009 return modebuf_flush_int(mbuf, 1);
2013 * This extracts the simple modes contained in mbuf
2016 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2018 static int flags[] = {
2019 /* MODE_CHANOP, 'o', */
2020 /* MODE_VOICE, 'v', */
2023 MODE_MODERATED, 'm',
2024 MODE_TOPICLIMIT, 't',
2025 MODE_INVITEONLY, 'i',
2026 MODE_NOPRIVMSGS, 'n',
2030 /* MODE_BAN, 'b', */
2037 int i, bufpos = 0, len;
2039 char *key = 0, limitbuf[20];
2040 char *apass = 0, *upass = 0;
2049 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2050 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2051 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2053 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2054 key = MB_STRING(mbuf, i);
2055 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2056 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2057 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2058 upass = MB_STRING(mbuf, i);
2059 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2060 apass = MB_STRING(mbuf, i);
2067 buf[bufpos++] = '+'; /* start building buffer */
2069 for (flag_p = flags; flag_p[0]; flag_p += 2)
2071 buf[bufpos++] = flag_p[1];
2073 for (i = 0, len = bufpos; i < len; i++) {
2075 build_string(buf, &bufpos, key, 0, ' ');
2076 else if (buf[i] == 'l')
2077 build_string(buf, &bufpos, limitbuf, 0, ' ');
2078 else if (buf[i] == 'u')
2079 build_string(buf, &bufpos, upass, 0, ' ');
2080 else if (buf[i] == 'A')
2081 build_string(buf, &bufpos, apass, 0, ' ');
2090 * Simple function to invalidate bans
2093 mode_ban_invalidate(struct Channel *chan)
2095 struct Membership *member;
2097 for (member = chan->members; member; member = member->next_member)
2098 ClearBanValid(member);
2102 * Simple function to drop invite structures
2105 mode_invite_clear(struct Channel *chan)
2107 while (chan->invites)
2108 del_invite(chan->invites->value.cptr, chan);
2111 /* What we've done for mode_parse so far... */
2112 #define DONE_LIMIT 0x01 /* We've set the limit */
2113 #define DONE_KEY 0x02 /* We've set the key */
2114 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2115 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2116 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2117 #define DONE_UPASS 0x20 /* We've set user pass */
2118 #define DONE_APASS 0x40 /* We've set admin pass */
2121 struct ModeBuf *mbuf;
2122 struct Client *cptr;
2123 struct Client *sptr;
2124 struct Channel *chptr;
2125 struct Membership *member;
2136 struct SLink banlist[MAXPARA];
2139 struct Client *client;
2140 } cli_change[MAXPARA];
2144 * Here's a helper function to deal with sending along "Not oper" or
2145 * "Not member" messages
2148 send_notoper(struct ParseState *state)
2150 if (state->done & DONE_NOTOPER)
2153 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2154 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2156 state->done |= DONE_NOTOPER;
2160 * Helper function to convert limits
2163 mode_parse_limit(struct ParseState *state, int *flag_p)
2165 unsigned int t_limit;
2167 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2168 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2171 if (state->parc <= 0) { /* warn if not enough args */
2172 if (MyUser(state->sptr))
2173 need_more_params(state->sptr, "MODE +l");
2177 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2181 if ((int)t_limit<0) /* don't permit a negative limit */
2184 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2185 (!t_limit || t_limit == state->chptr->mode.limit))
2188 t_limit = state->chptr->mode.limit;
2190 /* If they're not an oper, they can't change modes */
2191 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2192 send_notoper(state);
2196 /* Can't remove a limit that's not there */
2197 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2200 /* Skip if this is a burst and a lower limit than this is set already */
2201 if ((state->flags & MODE_PARSE_BURST) &&
2202 (state->chptr->mode.mode & flag_p[0]) &&
2203 (state->chptr->mode.limit < t_limit))
2206 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2208 state->done |= DONE_LIMIT;
2213 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2215 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2216 if (state->dir & MODE_ADD) {
2217 state->chptr->mode.mode |= flag_p[0];
2218 state->chptr->mode.limit = t_limit;
2220 state->chptr->mode.mode &= ~flag_p[0];
2221 state->chptr->mode.limit = 0;
2227 * Helper function to convert keys
2230 mode_parse_key(struct ParseState *state, int *flag_p)
2235 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2238 if (state->parc <= 0) { /* warn if not enough args */
2239 if (MyUser(state->sptr))
2240 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2245 t_str = state->parv[state->args_used++]; /* grab arg */
2249 /* If they're not an oper, they can't change modes */
2250 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2251 send_notoper(state);
2255 if (state->done & DONE_KEY) /* allow key to be set only once */
2257 state->done |= DONE_KEY;
2261 /* clean up the key string */
2263 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2267 if (!*t_str) { /* warn if empty */
2268 if (MyUser(state->sptr))
2269 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2277 /* Skip if this is a burst, we have a key already and the new key is
2278 * after the old one alphabetically */
2279 if ((state->flags & MODE_PARSE_BURST) &&
2280 *(state->chptr->mode.key) &&
2281 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2284 /* can't add a key if one is set, nor can one remove the wrong key */
2285 if (!(state->flags & MODE_PARSE_FORCE))
2286 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2287 (state->dir == MODE_DEL &&
2288 ircd_strcmp(state->chptr->mode.key, t_str))) {
2289 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2293 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2294 !ircd_strcmp(state->chptr->mode.key, t_str))
2295 return; /* no key change */
2297 if (state->flags & MODE_PARSE_BOUNCE) {
2298 if (*state->chptr->mode.key) /* reset old key */
2299 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2300 state->chptr->mode.key, 0);
2301 else /* remove new bogus key */
2302 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2303 } else /* send new key */
2304 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2306 if (state->flags & MODE_PARSE_SET) {
2307 if (state->dir == MODE_ADD) /* set the new key */
2308 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2309 else /* remove the old key */
2310 *state->chptr->mode.key = '\0';
2315 * Helper function to convert user passes
2318 mode_parse_upass(struct ParseState *state, int *flag_p)
2323 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2326 if (state->parc <= 0) { /* warn if not enough args */
2327 if (MyUser(state->sptr))
2328 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2333 t_str = state->parv[state->args_used++]; /* grab arg */
2337 /* If they're not an oper, they can't change modes */
2338 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2339 send_notoper(state);
2343 /* If a non-service user is trying to force it, refuse. */
2344 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2345 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2346 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2350 /* If they are not the channel manager, they are not allowed to change it */
2351 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2352 if (*state->chptr->mode.apass) {
2353 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2354 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2356 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2357 "Re-create the channel. The channel must be *empty* for",
2358 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2359 "before it can be recreated.");
2364 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2366 state->done |= DONE_UPASS;
2368 t_len = PASSLEN + 1;
2370 /* clean up the upass string */
2372 while (*++s > ' ' && *s != ':' && --t_len)
2376 if (!*t_str) { /* warn if empty */
2377 if (MyUser(state->sptr))
2378 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2386 if (!(state->flags & MODE_PARSE_FORCE))
2387 /* can't add the upass while apass is not set */
2388 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2389 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2392 /* can't add a upass if one is set, nor can one remove the wrong upass */
2393 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2394 (state->dir == MODE_DEL &&
2395 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2396 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2400 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2401 !ircd_strcmp(state->chptr->mode.upass, t_str))
2402 return; /* no upass change */
2404 if (state->flags & MODE_PARSE_BOUNCE) {
2405 if (*state->chptr->mode.upass) /* reset old upass */
2406 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2407 state->chptr->mode.upass, 0);
2408 else /* remove new bogus upass */
2409 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2410 } else /* send new upass */
2411 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2413 if (state->flags & MODE_PARSE_SET) {
2414 if (state->dir == MODE_ADD) /* set the new upass */
2415 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2416 else /* remove the old upass */
2417 *state->chptr->mode.upass = '\0';
2422 * Helper function to convert admin passes
2425 mode_parse_apass(struct ParseState *state, int *flag_p)
2430 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2433 if (state->parc <= 0) { /* warn if not enough args */
2434 if (MyUser(state->sptr))
2435 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2440 t_str = state->parv[state->args_used++]; /* grab arg */
2444 /* If they're not an oper, they can't change modes */
2445 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2446 send_notoper(state);
2450 /* If a non-service user is trying to force it, refuse. */
2451 if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2452 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2453 "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2457 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2458 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2459 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2463 /* If they are not the channel manager, they are not allowed to change it */
2464 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2465 if (*state->chptr->mode.apass) {
2466 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2467 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2469 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2470 "Re-create the channel. The channel must be *empty* for",
2471 "at least a whole minute", "before it can be recreated.");
2476 if (state->done & DONE_APASS) /* allow apass to be set only once */
2478 state->done |= DONE_APASS;
2480 t_len = PASSLEN + 1;
2482 /* clean up the apass string */
2484 while (*++s > ' ' && *s != ':' && --t_len)
2488 if (!*t_str) { /* warn if empty */
2489 if (MyUser(state->sptr))
2490 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2498 if (!(state->flags & MODE_PARSE_FORCE)) {
2499 /* can't remove the apass while upass is still set */
2500 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2501 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2504 /* can't add an apass if one is set, nor can one remove the wrong apass */
2505 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2506 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2507 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2512 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2513 !ircd_strcmp(state->chptr->mode.apass, t_str))
2514 return; /* no apass change */
2516 if (state->flags & MODE_PARSE_BOUNCE) {
2517 if (*state->chptr->mode.apass) /* reset old apass */
2518 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2519 state->chptr->mode.apass, 0);
2520 else /* remove new bogus apass */
2521 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2522 } else /* send new apass */
2523 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2525 if (state->flags & MODE_PARSE_SET) {
2526 if (state->dir == MODE_ADD) { /* set the new apass */
2527 /* Make it VERY clear to the user that this is a one-time password */
2528 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2529 if (MyUser(state->sptr)) {
2530 send_reply(state->sptr, RPL_APASSWARN,
2531 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2532 "Are you SURE you want to use this as Admin password? ",
2533 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2534 send_reply(state->sptr, RPL_APASSWARN,
2535 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2536 "\" to remove the password and then immediately set a new one. "
2537 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2538 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2539 "Now set the channel user password (+u).");
2541 } else { /* remove the old apass */
2542 *state->chptr->mode.apass = '\0';
2543 if (MyUser(state->sptr))
2544 send_reply(state->sptr, RPL_APASSWARN,
2545 "WARNING: You removed the channel Admin password MODE (+A). ",
2546 "If you would disconnect or leave the channel without setting a new password then you will ",
2547 "not be able to set it again and lose ownership of this channel! ",
2548 "SET A NEW PASSWORD NOW!", "");
2554 * Helper function to convert bans
2557 mode_parse_ban(struct ParseState *state, int *flag_p)
2560 struct SLink *ban, *newban = 0;
2562 if (state->parc <= 0) { /* Not enough args, send ban list */
2563 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2564 send_ban_list(state->sptr, state->chptr);
2565 state->done |= DONE_BANLIST;
2571 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2574 t_str = state->parv[state->args_used++]; /* grab arg */
2578 /* If they're not an oper, they can't change modes */
2579 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2580 send_notoper(state);
2584 if ((s = strchr(t_str, ' ')))
2587 if (!*t_str || *t_str == ':') { /* warn if empty */
2588 if (MyUser(state->sptr))
2589 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2594 t_str = collapse(pretty_mask(t_str));
2596 /* remember the ban for the moment... */
2597 if (state->dir == MODE_ADD) {
2598 newban = state->banlist + (state->numbans++);
2601 DupString(newban->value.ban.banstr, t_str);
2602 newban->value.ban.who = cli_name(state->sptr);
2603 newban->value.ban.when = TStime();
2605 newban->flags = CHFL_BAN | MODE_ADD;
2607 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2608 newban->flags |= CHFL_BAN_IPMASK;
2611 if (!state->chptr->banlist) {
2612 state->chptr->banlist = newban; /* add our ban with its flags */
2613 state->done |= DONE_BANCLEAN;
2617 /* Go through all bans */
2618 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2619 /* first, clean the ban flags up a bit */
2620 if (!(state->done & DONE_BANCLEAN))
2621 /* Note: We're overloading *lots* of bits here; be careful! */
2622 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2626 * MODE_ADD - Ban was added; if we're bouncing modes,
2627 * then we'll remove it below; otherwise,
2628 * we'll have to allocate a real ban
2630 * MODE_DEL - Ban was marked for deletion; if we're
2631 * bouncing modes, we'll have to re-add it,
2632 * otherwise, we'll have to remove it
2634 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2635 * with a ban already set; if we're
2636 * bouncing modes, we'll have to bounce
2637 * this one; otherwise, we'll just ignore
2638 * it when we process added bans
2641 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2642 ban->flags |= MODE_DEL; /* delete one ban */
2644 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2646 } else if (state->dir == MODE_ADD) {
2647 /* if the ban already exists, don't worry about it */
2648 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2649 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2650 MyFree(newban->value.ban.banstr); /* stopper a leak */
2651 state->numbans--; /* deallocate last ban */
2652 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2654 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2655 if (!(ban->flags & MODE_DEL))
2656 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2657 } else if (!mmatch(t_str, ban->value.ban.banstr))
2658 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2660 if (!ban->next && (newban->flags & MODE_ADD))
2662 ban->next = newban; /* add our ban with its flags */
2663 break; /* get out of loop */
2667 state->done |= DONE_BANCLEAN;
2671 * This is the bottom half of the ban processor
2674 mode_process_bans(struct ParseState *state)
2676 struct SLink *ban, *newban, *prevban, *nextban;
2682 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2684 banlen = strlen(ban->value.ban.banstr);
2686 nextban = ban->next;
2688 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2690 prevban->next = 0; /* Break the list; ban isn't a real ban */
2692 state->chptr->banlist = 0;
2697 MyFree(ban->value.ban.banstr);
2700 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2701 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2702 ban->value.ban.banstr,
2703 state->flags & MODE_PARSE_SET);
2705 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2706 if (prevban) /* clip it out of the list... */
2707 prevban->next = ban->next;
2709 state->chptr->banlist = ban->next;
2714 MyFree(ban->value.ban.who);
2718 continue; /* next ban; keep prevban like it is */
2720 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2721 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2723 prevban->next = 0; /* Break the list; ban isn't a real ban */
2725 state->chptr->banlist = 0;
2727 /* If we're supposed to ignore it, do so. */
2728 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2729 !(state->flags & MODE_PARSE_BOUNCE)) {
2733 MyFree(ban->value.ban.banstr);
2735 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2736 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2737 count > feature_int(FEAT_MAXBANS))) {
2738 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2739 ban->value.ban.banstr);
2743 MyFree(ban->value.ban.banstr);
2745 /* add the ban to the buffer */
2746 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2747 ban->value.ban.banstr,
2748 !(state->flags & MODE_PARSE_SET));
2750 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2751 newban = make_link();
2752 newban->value.ban.banstr = ban->value.ban.banstr;
2753 DupString(newban->value.ban.who, ban->value.ban.who);
2754 newban->value.ban.when = ban->value.ban.when;
2755 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2757 newban->next = state->chptr->banlist; /* and link it in */
2758 state->chptr->banlist = newban;
2767 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2769 if (changed) /* if we changed the ban list, we must invalidate the bans */
2770 mode_ban_invalidate(state->chptr);
2774 * Helper function to process client changes
2777 mode_parse_client(struct ParseState *state, int *flag_p)
2780 struct Client *acptr;
2783 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2786 if (state->parc <= 0) /* return if not enough args */
2789 t_str = state->parv[state->args_used++]; /* grab arg */
2793 /* If they're not an oper, they can't change modes */
2794 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2795 send_notoper(state);
2799 if (MyUser(state->sptr)) /* find client we're manipulating */
2800 acptr = find_chasing(state->sptr, t_str, NULL);
2802 acptr = findNUser(t_str);
2805 return; /* find_chasing() already reported an error to the user */
2807 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2808 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2809 state->cli_change[i].flag & flag_p[0]))
2810 break; /* found a slot */
2812 /* Store what we're doing to them */
2813 state->cli_change[i].flag = state->dir | flag_p[0];
2814 state->cli_change[i].client = acptr;
2818 * Helper function to process the changed client list
2821 mode_process_clients(struct ParseState *state)
2824 struct Membership *member;
2826 for (i = 0; state->cli_change[i].flag; i++) {
2827 assert(0 != state->cli_change[i].client);
2829 /* look up member link */
2830 if (!(member = find_member_link(state->chptr,
2831 state->cli_change[i].client)) ||
2832 (MyUser(state->sptr) && IsZombie(member))) {
2833 if (MyUser(state->sptr))
2834 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2835 cli_name(state->cli_change[i].client),
2836 state->chptr->chname);
2840 if ((state->cli_change[i].flag & MODE_ADD &&
2841 (state->cli_change[i].flag & member->status)) ||
2842 (state->cli_change[i].flag & MODE_DEL &&
2843 !(state->cli_change[i].flag & member->status)))
2844 continue; /* no change made, don't do anything */
2846 /* see if the deop is allowed */
2847 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2848 (MODE_DEL | MODE_CHANOP)) {
2849 /* prevent +k users from being deopped */
2850 if (IsChannelService(state->cli_change[i].client)) {
2851 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2852 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2854 (IsServer(state->sptr) ? cli_name(state->sptr) :
2855 cli_name((cli_user(state->sptr))->server)));
2857 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2858 send_reply(state->sptr, ERR_ISCHANSERVICE,
2859 cli_name(state->cli_change[i].client),
2860 state->chptr->chname);
2865 /* check deop for local user */
2866 if (MyUser(state->sptr)) {
2868 /* don't allow local opers to be deopped on local channels */
2869 if (state->cli_change[i].client != state->sptr &&
2870 IsLocalChannel(state->chptr->chname) &&
2871 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2872 send_reply(state->sptr, ERR_ISOPERLCHAN,
2873 cli_name(state->cli_change[i].client),
2874 state->chptr->chname);
2878 if (feature_bool(FEAT_OPLEVELS)) {
2879 /* don't allow to deop members with an op level that is <= our own level */
2880 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2882 && OpLevel(member) <= OpLevel(state->member)) {
2883 int equal = (OpLevel(member) == OpLevel(state->member));
2884 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2885 cli_name(state->cli_change[i].client),
2886 state->chptr->chname,
2887 OpLevel(state->member), OpLevel(member),
2888 "deop", equal ? "the same" : "a higher");
2895 /* set op-level of member being opped */
2896 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2897 (MODE_ADD | MODE_CHANOP)) {
2898 /* If on a channel with upass set, someone with level x gives ops to someone else,
2899 then that person gets level x-1. On other channels, where upass is not set,
2900 the level stays the same. */
2901 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2902 /* Someone being opped by a server gets op-level 0 */
2903 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2904 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2907 /* actually effect the change */
2908 if (state->flags & MODE_PARSE_SET) {
2909 if (state->cli_change[i].flag & MODE_ADD) {
2910 if (IsDelayedJoin(member))
2911 RevealDelayedJoin(member);
2912 member->status |= (state->cli_change[i].flag &
2913 (MODE_CHANOP | MODE_VOICE));
2914 if (state->cli_change[i].flag & MODE_CHANOP)
2915 ClearDeopped(member);
2917 member->status &= ~(state->cli_change[i].flag &
2918 (MODE_CHANOP | MODE_VOICE));
2921 /* accumulate the change */
2922 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2923 state->cli_change[i].client);
2924 } /* for (i = 0; state->cli_change[i].flags; i++) */
2928 * Helper function to process the simple modes
2931 mode_parse_mode(struct ParseState *state, int *flag_p)
2933 /* If they're not an oper, they can't change modes */
2934 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2935 send_notoper(state);
2942 if (state->dir == MODE_ADD) {
2943 state->add |= flag_p[0];
2944 state->del &= ~flag_p[0];
2946 if (flag_p[0] & MODE_SECRET) {
2947 state->add &= ~MODE_PRIVATE;
2948 state->del |= MODE_PRIVATE;
2949 } else if (flag_p[0] & MODE_PRIVATE) {
2950 state->add &= ~MODE_SECRET;
2951 state->del |= MODE_SECRET;
2953 if (flag_p[0] & MODE_DELJOINS) {
2954 state->add &= ~MODE_WASDELJOINS;
2955 state->del |= MODE_WASDELJOINS;
2958 state->add &= ~flag_p[0];
2959 state->del |= flag_p[0];
2962 assert(0 == (state->add & state->del));
2963 assert((MODE_SECRET | MODE_PRIVATE) !=
2964 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2968 * This routine is intended to parse MODE or OPMODE commands and effect the
2969 * changes (or just build the bounce buffer). We pass the starting offset
2973 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2974 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2975 struct Membership* member)
2977 static int chan_flags[] = {
2982 MODE_MODERATED, 'm',
2983 MODE_TOPICLIMIT, 't',
2984 MODE_INVITEONLY, 'i',
2985 MODE_NOPRIVMSGS, 'n',
2999 unsigned int t_mode;
3001 struct ParseState state;
3012 state.chptr = chptr;
3013 state.member = member;
3016 state.flags = flags;
3017 state.dir = MODE_ADD;
3021 state.args_used = 0;
3022 state.max_args = MAXMODEPARAMS;
3025 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3026 state.banlist[i].next = 0;
3027 state.banlist[i].value.ban.banstr = 0;
3028 state.banlist[i].value.ban.who = 0;
3029 state.banlist[i].value.ban.when = 0;
3030 state.banlist[i].flags = 0;
3031 state.cli_change[i].flag = 0;
3032 state.cli_change[i].client = 0;
3035 modestr = state.parv[state.args_used++];
3039 for (; *modestr; modestr++) {
3040 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3041 if (flag_p[1] == *modestr)
3044 if (!flag_p[0]) { /* didn't find it? complain and continue */
3045 if (MyUser(state.sptr))
3046 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3051 case '+': /* switch direction to MODE_ADD */
3052 case '-': /* switch direction to MODE_DEL */
3053 state.dir = flag_p[0];
3056 case 'l': /* deal with limits */
3057 mode_parse_limit(&state, flag_p);
3060 case 'k': /* deal with keys */
3061 mode_parse_key(&state, flag_p);
3064 case 'A': /* deal with Admin passes */
3065 if (feature_bool(FEAT_OPLEVELS))
3066 mode_parse_apass(&state, flag_p);
3069 case 'u': /* deal with user passes */
3070 if (feature_bool(FEAT_OPLEVELS))
3071 mode_parse_upass(&state, flag_p);
3074 case 'b': /* deal with bans */
3075 mode_parse_ban(&state, flag_p);
3078 case 'o': /* deal with ops/voice */
3080 mode_parse_client(&state, flag_p);
3083 default: /* deal with other modes */
3084 mode_parse_mode(&state, flag_p);
3086 } /* switch (*modestr) */
3087 } /* for (; *modestr; modestr++) */
3089 if (state.flags & MODE_PARSE_BURST)
3090 break; /* don't interpret any more arguments */
3092 if (state.parc > 0) { /* process next argument in string */
3093 modestr = state.parv[state.args_used++];
3097 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3100 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3101 break; /* we're then going to bounce the mode! */
3103 recv_ts = atoi(modestr);
3105 if (recv_ts && recv_ts < state.chptr->creationtime)
3106 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3108 break; /* break out of while loop */
3109 } else if (state.flags & MODE_PARSE_STRICT ||
3110 (MyUser(state.sptr) && state.max_args <= 0)) {
3111 state.parc++; /* we didn't actually gobble the argument */
3113 break; /* break out of while loop */
3116 } /* while (*modestr) */
3119 * the rest of the function finishes building resultant MODEs; if the
3120 * origin isn't a member or an oper, skip it.
3122 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3123 return state.args_used; /* tell our parent how many args we gobbled */
3125 t_mode = state.chptr->mode.mode;
3127 if (state.del & t_mode) { /* delete any modes to be deleted... */
3128 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3130 t_mode &= ~state.del;
3132 if (state.add & ~t_mode) { /* add any modes to be added... */
3133 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3135 t_mode |= state.add;
3138 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3139 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3140 !(t_mode & MODE_INVITEONLY))
3141 mode_invite_clear(state.chptr);
3143 state.chptr->mode.mode = t_mode;
3146 if (state.flags & MODE_PARSE_WIPEOUT) {
3147 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3148 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3149 state.chptr->mode.limit);
3150 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3151 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3152 state.chptr->mode.key, 0);
3153 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3154 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3155 state.chptr->mode.upass, 0);
3156 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3157 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3158 state.chptr->mode.apass, 0);
3161 if (state.done & DONE_BANCLEAN) /* process bans */
3162 mode_process_bans(&state);
3164 /* process client changes */
3165 if (state.cli_change[0].flag)
3166 mode_process_clients(&state);
3168 return state.args_used; /* tell our parent how many args we gobbled */
3172 * Initialize a join buffer
3175 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3176 struct Client *connect, unsigned int type, char *comment,
3182 assert(0 != source);
3183 assert(0 != connect);
3185 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3186 jbuf->jb_connect = connect;
3187 jbuf->jb_type = type;
3188 jbuf->jb_comment = comment;
3189 jbuf->jb_create = create;
3191 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3192 type == JOINBUF_TYPE_PART ||
3193 type == JOINBUF_TYPE_PARTALL) ?
3194 STARTJOINLEN : STARTCREATELEN) +
3195 (comment ? strlen(comment) + 2 : 0));
3197 for (i = 0; i < MAXJOINARGS; i++)
3198 jbuf->jb_channels[i] = 0;
3202 * Add a channel to the join buffer
3205 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3213 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3214 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3219 is_local = IsLocalChannel(chan->chname);
3221 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3222 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3223 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3224 if (IsUserParting(member))
3226 SetUserParting(member);
3228 /* Send notification to channel */
3229 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3230 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3231 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3232 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3233 else if (MyUser(jbuf->jb_source))
3234 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3235 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3236 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3237 /* XXX: Shouldn't we send a PART here anyway? */
3238 /* to users on the channel? Why? From their POV, the user isn't on
3239 * the channel anymore anyway. We don't send to servers until below,
3240 * when we gang all the channel parts together. Note that this is
3241 * exactly the same logic, albeit somewhat more concise, as was in
3242 * the original m_part.c */
3244 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3245 is_local) /* got to remove user here */
3246 remove_user_from_channel(jbuf->jb_source, chan);
3248 /* Add user to channel */
3249 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3250 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3252 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3254 /* send notification to all servers */
3255 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3256 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3257 "%H %Tu", chan, chan->creationtime);
3259 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3260 /* Send the notification to the channel */
3261 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3263 /* send an op, too, if needed */
3264 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3265 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3266 chan, jbuf->jb_source);
3267 } else if (MyUser(jbuf->jb_source))
3268 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3271 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3272 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3273 return; /* don't send to remote */
3275 /* figure out if channel name will cause buffer to be overflowed */
3276 len = chan ? strlen(chan->chname) + 1 : 2;
3277 if (jbuf->jb_strlen + len > BUFSIZE)
3278 joinbuf_flush(jbuf);
3280 /* add channel to list of channels to send and update counts */
3281 jbuf->jb_channels[jbuf->jb_count++] = chan;
3282 jbuf->jb_strlen += len;
3284 /* if we've used up all slots, flush */
3285 if (jbuf->jb_count >= MAXJOINARGS)
3286 joinbuf_flush(jbuf);
3290 * Flush the channel list to remote servers
3293 joinbuf_flush(struct JoinBuf *jbuf)
3295 char chanlist[BUFSIZE];
3299 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3300 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3301 return 0; /* no joins to process */
3303 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3304 build_string(chanlist, &chanlist_i,
3305 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3306 i == 0 ? '\0' : ',');
3307 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3308 /* Remove user from channel */
3309 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3311 jbuf->jb_channels[i] = 0; /* mark slot empty */
3314 jbuf->jb_count = 0; /* reset base counters */
3315 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3316 STARTJOINLEN : STARTCREATELEN) +
3317 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3319 /* and send the appropriate command */
3320 switch (jbuf->jb_type) {
3321 case JOINBUF_TYPE_CREATE:
3322 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3323 "%s %Tu", chanlist, jbuf->jb_create);
3326 case JOINBUF_TYPE_PART:
3327 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3328 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3336 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3337 int IsInvited(struct Client* cptr, const void* chptr)
3341 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3342 if (lp->value.chptr == chptr)
3347 /* RevealDelayedJoin: sends a join for a hidden user */
3349 void RevealDelayedJoin(struct Membership *member) {
3350 ClearDelayedJoin(member);
3351 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3353 CheckDelayedJoins(member->channel);
3356 /* CheckDelayedJoins: checks and clear +d if necessary */
3358 void CheckDelayedJoins(struct Channel *chan) {
3359 struct Membership *memb2;
3361 if (chan->mode.mode & MODE_WASDELJOINS) {
3362 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3363 if (IsDelayedJoin(memb2))
3368 chan->mode.mode &= ~MODE_WASDELJOINS;
3369 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,