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;
847 if (IsLocalChannel(chptr->chname))
850 member = chptr->members;
851 lp2 = chptr->banlist;
853 *modebuf = *parabuf = '\0';
854 channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
856 for (first = 1; full; first = 0) /* Loop for multiple messages */
858 full = 0; /* Assume by default we get it
859 all in one message */
861 /* (Continued) prefix: "<Y> B <channel> <TS>" */
862 /* is there any better way we can do this? */
863 mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
864 chptr->creationtime);
866 if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu)
869 /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
870 msgq_append(&me, mb, " %s", modebuf);
873 msgq_append(&me, mb, " %s", parabuf);
877 * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
879 * First find all opless members.
880 * Run 2 times over all members, to group the members with
881 * and without voice together.
882 * Then run 2 times over all opped members (which are ordered
883 * by op-level) to also group voice and non-voice together.
885 for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
889 if (flag_cnt < 2 && IsChanOp(member))
892 * The first loop (to find all non-voice/op), we count the ops.
893 * The second loop (to find all voiced non-ops), store the ops
894 * in a dynamic array.
899 opped_members[opped_members_index++] = member;
901 /* Only handle the members with the flags that we are interested in. */
902 if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
904 if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
905 /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
907 full = 1; /* Make sure we continue after
909 /* Ensure the new BURST line contains the current
910 * ":mode", except when there is no mode yet. */
911 new_mode = (flag_cnt > 0) ? 1 : 0;
912 break; /* Do not add this member to this message */
914 msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
915 first = 0; /* From now on, use commas to add new nicks */
918 * Do we have a nick with a new mode ?
919 * Or are we starting a new BURST line?
924 * This means we are at the _first_ member that has only
925 * voice, or the first member that has only ops, or the
926 * first member that has voice and ops (so we get here
927 * at most three times, plus once for every start of
928 * a continued BURST line where only these modes is current.
929 * In the two cases where the current mode includes ops,
930 * we need to add the _absolute_ value of the oplevel to the mode.
932 char tbuf[3 + MAXOPLEVELDIGITS] = ":";
935 if (HasVoice(member)) /* flag_cnt == 1 or 3 */
937 if (IsChanOp(member)) /* flag_cnt == 2 or 3 */
939 /* append the absolute value of the oplevel */
940 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
941 last_oplevel = member->oplevel;
944 msgq_append(&me, mb, tbuf);
947 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
950 * This can't be the first member of a (continued) BURST
951 * message because then either flag_cnt == 0 or new_mode == 1
952 * Now we need to append the incremental value of the oplevel.
954 char tbuf[2 + MAXOPLEVELDIGITS];
955 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
956 last_oplevel = member->oplevel;
957 msgq_append(&me, mb, tbuf);
960 /* Go to the next `member'. */
962 member = member->next_member;
964 member = opped_members[++opped_members_index];
969 /* Point `member' at the start of the list again. */
972 member = chptr->members;
973 /* Now, after one loop, we know the number of ops and can
974 * allocate the dynamic array with pointer to the ops. */
975 opped_members = (struct Membership**)
976 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
977 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
981 /* At the end of the second loop, sort the opped members with
982 * increasing op-level, so that we will output them in the
983 * correct order (and all op-level increments stay positive) */
985 qsort(opped_members, number_of_ops,
986 sizeof(struct Membership*), compare_member_oplevel);
987 /* The third and fourth loop run only over the opped members. */
988 member = opped_members[(opped_members_index = 0)];
991 } /* loop over 0,+v,+o,+ov */
995 /* Attach all bans, space seperated " :%ban ban ..." */
996 for (first = 2; lp2; lp2 = lp2->next)
998 len = strlen(lp2->value.ban.banstr);
999 if (msgq_bufleft(mb) < len + 1 + first)
1000 /* The +1 stands for the added ' '.
1001 * The +first stands for the added ":%".
1007 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1008 lp2->value.ban.banstr);
1013 send_buffer(cptr, mb, 0); /* Send this message */
1015 } /* Continue when there was something
1016 that didn't fit (full==1) */
1018 MyFree(opped_members);
1019 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1020 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1021 chptr->creationtime, chptr->topic_time, chptr->topic);
1027 * by Carlo Wood (Run), 05 Oct 1998.
1031 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1032 * When the user name or host name are too long (USERLEN and HOSTLEN
1033 * respectively) then they are cut off at the start with a '*'.
1035 * The following transformations are made:
1037 * 1) xxx -> nick!*@*
1038 * 2) xxx.xxx -> *!*@host
1039 * 3) xxx!yyy -> nick!user@*
1040 * 4) xxx@yyy -> *!user@host
1041 * 5) xxx!yyy@zzz -> nick!user@host
1043 char *pretty_mask(char *mask)
1045 static char star[2] = { '*', 0 };
1046 static char retmask[NUH_BUFSIZE];
1047 char *last_dot = NULL;
1050 /* Case 1: default */
1055 /* Do a _single_ pass through the characters of the mask: */
1056 for (ptr = mask; *ptr; ++ptr)
1060 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1064 else if (*ptr == '@')
1066 /* Case 4: Found last '@' (without finding a '!' yet) */
1071 else if (*ptr == '.')
1073 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1083 /* Case 4 or 5: Found last '@' */
1089 if (user == star && last_dot)
1099 char *nick_end = (user != star) ? user - 1 : ptr;
1100 if (nick_end - nick > NICKLEN)
1106 char *user_end = (host != star) ? host - 1 : ptr;
1107 if (user_end - user > USERLEN)
1109 user = user_end - USERLEN;
1114 if (host != star && ptr - host > HOSTLEN)
1116 host = ptr - HOSTLEN;
1119 return make_nick_user_host(retmask, nick, user, host);
1122 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1129 for (lp = chptr->banlist; lp; lp = lp->next)
1130 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1131 lp->value.ban.who, lp->value.ban.when);
1133 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1136 /* We are now treating the <key> part of /join <channel list> <key> as a key
1137 * ring; that is, we try one key against the actual channel key, and if that
1138 * doesn't work, we try the next one, and so on. -Kev -Texaco
1139 * Returns: 0 on match, 1 otherwise
1140 * This version contributed by SeKs <intru@info.polymtl.ca>
1142 static int compall(char *key, char *keyring)
1147 p1 = key; /* point to the key... */
1148 while (*p1 && *p1 == *keyring)
1149 { /* step through the key and ring until they
1155 if (!*p1 && (!*keyring || *keyring == ','))
1156 /* ok, if we're at the end of the and also at the end of one of the keys
1157 in the keyring, we have a match */
1160 if (!*keyring) /* if we're at the end of the key ring, there
1161 weren't any matches, so we return 1 */
1164 /* Not at the end of the key ring, so step
1165 through to the next key in the ring: */
1166 while (*keyring && *(keyring++) != ',');
1168 goto top; /* and check it against the key */
1171 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1173 int overrideJoin = 0;
1176 * Now a banned user CAN join if invited -- Nemesi
1177 * Now a user CAN escape channel limit if invited -- bfriendly
1178 * Now a user CAN escape anything if invited -- Isomer
1181 if (IsInvited(sptr, chptr))
1184 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1185 a HACK(4) notice will be sent if he would not have been supposed
1186 to join normally. */
1187 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1188 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1189 compall("OVERRIDE",key) == 0)
1190 overrideJoin = MAGIC_OPER_OVERRIDE;
1192 if (chptr->mode.mode & MODE_INVITEONLY)
1193 return overrideJoin + ERR_INVITEONLYCHAN;
1195 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1196 return overrideJoin + ERR_CHANNELISFULL;
1198 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1199 return overrideJoin + ERR_NEEDREGGEDNICK;
1201 if (is_banned(sptr, chptr, NULL))
1202 return overrideJoin + ERR_BANNEDFROMCHAN;
1205 * now using compall (above) to test against a whole key ring -Kev
1207 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1208 return overrideJoin + ERR_BADCHANNELKEY;
1211 return ERR_DONTCHEAT;
1217 * Remove bells and commas from channel name
1219 void clean_channelname(char *cn)
1223 for (i = 0; cn[i]; i++) {
1224 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1228 if (IsChannelLower(cn[i])) {
1229 cn[i] = ToLower(cn[i]);
1235 if ((unsigned char)(cn[i]) == 0xd0)
1236 cn[i] = (char) 0xf0;
1243 * Get Channel block for i (and allocate a new channel
1244 * block, if it didn't exists before).
1246 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1248 struct Channel *chptr;
1251 if (EmptyString(chname))
1254 len = strlen(chname);
1255 if (MyUser(cptr) && len > CHANNELLEN)
1258 *(chname + CHANNELLEN) = '\0';
1260 if ((chptr = FindChannel(chname)))
1262 if (flag == CGT_CREATE)
1264 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1266 ++UserStats.channels;
1267 memset(chptr, 0, sizeof(struct Channel));
1268 strcpy(chptr->chname, chname);
1269 if (GlobalChannelList)
1270 GlobalChannelList->prev = chptr;
1272 chptr->next = GlobalChannelList;
1273 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1274 GlobalChannelList = chptr;
1280 void add_invite(struct Client *cptr, struct Channel *chptr)
1282 struct SLink *inv, **tmp;
1284 del_invite(cptr, chptr);
1286 * Delete last link in chain if the list is max length
1288 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1289 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1290 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1292 * Add client to channel invite list
1295 inv->value.cptr = cptr;
1296 inv->next = chptr->invites;
1297 chptr->invites = inv;
1299 * Add channel to the end of the client invite list
1301 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1303 inv->value.chptr = chptr;
1306 (cli_user(cptr))->invites++;
1310 * Delete Invite block from channel invite list and client invite list
1312 void del_invite(struct Client *cptr, struct Channel *chptr)
1314 struct SLink **inv, *tmp;
1316 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1317 if (tmp->value.cptr == cptr)
1322 (cli_user(cptr))->invites--;
1326 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1327 if (tmp->value.chptr == chptr)
1336 /* List and skip all channels that are listen */
1337 void list_next_channels(struct Client *cptr, int nr)
1339 struct ListingArgs *args = cli_listing(cptr);
1340 struct Channel *chptr = args->chptr;
1341 chptr->mode.mode &= ~MODE_LISTED;
1342 while (is_listed(chptr) || --nr >= 0)
1344 for (; chptr; chptr = chptr->next)
1346 if (!cli_user(cptr))
1348 if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1349 SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1351 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1352 chptr->creationtime > args->min_time &&
1353 chptr->creationtime < args->max_time &&
1354 (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1355 chptr->topic_time > args->min_topic_time &&
1356 chptr->topic_time < args->max_topic_time)))
1358 if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1359 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1361 chptr = chptr->next;
1367 MyFree(cli_listing(cptr));
1368 cli_listing(cptr) = NULL;
1369 send_reply(cptr, RPL_LISTEND);
1375 (cli_listing(cptr))->chptr = chptr;
1376 chptr->mode.mode |= MODE_LISTED;
1389 * X --a--> A --b--> B --d--> D
1393 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1394 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1396 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1397 * Remove the user immediately when no users are left on the channel.
1398 * b) On server B : remove the user (who/lp) from the channel, send a
1399 * PART upstream (to A) and pass on the KICK.
1400 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1401 * channel, and pass on the KICK.
1402 * d) On server D : remove the user (who/lp) from the channel, and pass on
1406 * - Setting the ZOMBIE flag never hurts, we either remove the
1407 * client after that or we don't.
1408 * - The KICK message was already passed on, as should be in all cases.
1409 * - `who' is removed in all cases except case a) when users are left.
1410 * - A PART is only sent upstream in case b).
1416 * 1 --- 2 --- 3 --- 4 --- 5
1420 * We also need to turn 'who' into a zombie on servers 1 and 6,
1421 * because a KICK from 'who' (kicking someone else in that direction)
1422 * can arrive there afterwards - which should not be bounced itself.
1423 * Therefore case a) also applies for servers 1 and 6.
1427 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1428 struct Client* sptr, struct Channel* chptr)
1430 assert(0 != member);
1435 /* Default for case a): */
1438 /* Case b) or c) ?: */
1439 if (MyUser(who)) /* server 4 */
1441 if (IsServer(cptr)) /* Case b) ? */
1442 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1443 remove_user_from_channel(who, chptr);
1446 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1448 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1449 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1450 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1452 remove_user_from_channel(who, chptr);
1457 /* Case a) (servers 1, 2, 3 and 6) */
1458 if (channel_all_zombies(chptr))
1459 remove_user_from_channel(who, chptr);
1461 /* XXX Can't actually call Debug here; if the channel is all zombies,
1462 * chptr will no longer exist when we get here.
1463 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1467 int number_of_zombies(struct Channel *chptr)
1469 struct Membership* member;
1473 for (member = chptr->members; member; member = member->next_member) {
1474 if (IsZombie(member))
1481 * This helper function builds an argument string in strptr, consisting
1482 * of the original string, a space, and str1 and str2 concatenated (if,
1483 * of course, str2 is not NULL)
1486 build_string(char *strptr, int *strptr_i, const char *str1,
1487 const char *str2, char c)
1490 strptr[(*strptr_i)++] = c;
1493 strptr[(*strptr_i)++] = *(str1++);
1497 strptr[(*strptr_i)++] = *(str2++);
1499 strptr[(*strptr_i)] = '\0';
1503 * This is the workhorse of our ModeBuf suite; this actually generates the
1504 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1507 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1509 /* we only need the flags that don't take args right now */
1510 static int flags[] = {
1511 /* MODE_CHANOP, 'o', */
1512 /* MODE_VOICE, 'v', */
1515 MODE_MODERATED, 'm',
1516 MODE_TOPICLIMIT, 't',
1517 MODE_INVITEONLY, 'i',
1518 MODE_NOPRIVMSGS, 'n',
1521 MODE_WASDELJOINS, 'd',
1522 /* MODE_KEY, 'k', */
1523 /* MODE_BAN, 'b', */
1524 /* MODE_LIMIT, 'l', */
1525 /* MODE_APASS, 'A', */
1526 /* MODE_UPASS, 'u', */
1532 struct Client *app_source; /* where the MODE appears to come from */
1534 char addbuf[20]; /* accumulates +psmtin, etc. */
1536 char rembuf[20]; /* accumulates -psmtin, etc. */
1538 char *bufptr; /* we make use of indirection to simplify the code */
1541 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1543 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1545 char *strptr; /* more indirection to simplify the code */
1548 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1551 char limitbuf[20]; /* convert limits to strings */
1553 unsigned int limitdel = MODE_LIMIT;
1557 /* If the ModeBuf is empty, we have nothing to do */
1558 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1561 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1563 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1566 app_source = mbuf->mb_source;
1569 * Account for user we're bouncing; we have to get it in on the first
1570 * bounced MODE, or we could have problems
1572 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1573 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1575 /* Calculate the simple flags */
1576 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1577 if (*flag_p & mbuf->mb_add)
1578 addbuf[addbuf_i++] = flag_p[1];
1579 else if (*flag_p & mbuf->mb_rem)
1580 rembuf[rembuf_i++] = flag_p[1];
1583 /* Now go through the modes with arguments... */
1584 for (i = 0; i < mbuf->mb_count; i++) {
1585 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1587 bufptr_i = &addbuf_i;
1590 bufptr_i = &rembuf_i;
1593 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1594 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1596 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1597 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1599 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1600 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1602 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1603 tmp = strlen(MB_STRING(mbuf, i));
1605 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1606 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1609 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1621 bufptr[(*bufptr_i)++] = mode_char;
1622 totalbuflen -= tmp + 1;
1624 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1625 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1626 strlen(MB_STRING(mbuf, i)));
1628 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1629 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1631 bufptr[(*bufptr_i)++] = 'k';
1632 totalbuflen -= tmp + 1;
1634 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1635 /* if it's a limit, we also format the number */
1636 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1638 tmp = strlen(limitbuf);
1640 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1641 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1643 bufptr[(*bufptr_i)++] = 'l';
1644 totalbuflen -= tmp + 1;
1649 /* terminate the mode strings */
1650 addbuf[addbuf_i] = '\0';
1651 rembuf[rembuf_i] = '\0';
1653 /* If we're building a user visible MODE or HACK... */
1654 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1655 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1656 MODEBUF_DEST_LOG)) {
1657 /* Set up the parameter strings */
1663 for (i = 0; i < mbuf->mb_count; i++) {
1664 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1667 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1669 strptr_i = &addstr_i;
1672 strptr_i = &remstr_i;
1675 /* deal with clients... */
1676 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1677 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1679 /* deal with bans... */
1680 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1681 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1683 /* deal with keys... */
1684 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1685 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1686 "*" : MB_STRING(mbuf, i), 0, ' ');
1688 /* deal with invisible passwords */
1689 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1690 build_string(strptr, strptr_i, "*", 0, ' ');
1693 * deal with limit; note we cannot include the limit parameter if we're
1696 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1697 (MODE_ADD | MODE_LIMIT))
1698 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1701 /* send the messages off to their destination */
1702 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1703 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1705 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1706 mbuf->mb_source : app_source),
1707 mbuf->mb_channel->chname,
1708 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1709 addbuf, remstr, addstr,
1710 mbuf->mb_channel->creationtime);
1712 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1713 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1714 "%s%s%s%s%s%s [%Tu]",
1715 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1716 mbuf->mb_source : app_source),
1717 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1718 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1719 mbuf->mb_channel->creationtime);
1721 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1722 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1724 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1725 mbuf->mb_source : app_source),
1726 mbuf->mb_channel->chname,
1727 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1728 addbuf, remstr, addstr,
1729 mbuf->mb_channel->creationtime);
1731 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1732 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1733 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1734 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1735 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1737 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1738 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1739 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1740 rembuf_i ? "-" : "", rembuf,
1741 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1744 /* Now are we supposed to propagate to other servers? */
1745 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1746 /* set up parameter string */
1753 * limit is supressed if we're removing it; we have to figure out which
1754 * direction is the direction for it to be removed, though...
1756 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1758 for (i = 0; i < mbuf->mb_count; i++) {
1759 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1762 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1764 strptr_i = &addstr_i;
1767 strptr_i = &remstr_i;
1770 /* deal with modes that take clients */
1771 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1772 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1774 /* deal with modes that take strings */
1775 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1776 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1779 * deal with the limit. Logic here is complicated; if HACK2 is set,
1780 * we're bouncing the mode, so sense is reversed, and we have to
1781 * include the original limit if it looks like it's being removed
1783 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1784 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1787 /* we were told to deop the source */
1788 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1789 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1790 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1791 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1793 /* mark that we've done this, so we don't do it again */
1794 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1797 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1798 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1799 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1800 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1801 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1802 addbuf, remstr, addstr);
1803 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1805 * If HACK2 was set, we're bouncing; we send the MODE back to the
1806 * connection we got it from with the senses reversed and a TS of 0;
1809 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1810 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1811 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1812 mbuf->mb_channel->creationtime);
1815 * We're propagating a normal MODE command to the rest of the network;
1816 * we send the actual channel TS unless this is a HACK3 or a HACK4
1818 if (IsServer(mbuf->mb_source))
1819 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1820 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1821 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1822 addbuf, remstr, addstr,
1823 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1824 mbuf->mb_channel->creationtime);
1826 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1827 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1828 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1829 addbuf, remstr, addstr);
1833 /* We've drained the ModeBuf... */
1838 /* reinitialize the mode-with-arg slots */
1839 for (i = 0; i < MAXMODEPARAMS; i++) {
1840 /* If we saved any, pack them down */
1841 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1842 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1843 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1845 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1847 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1848 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1850 MB_TYPE(mbuf, i) = 0;
1851 MB_UINT(mbuf, i) = 0;
1854 /* If we're supposed to flush it all, do so--all hail tail recursion */
1855 if (all && mbuf->mb_count)
1856 return modebuf_flush_int(mbuf, 1);
1862 * This routine just initializes a ModeBuf structure with the information
1863 * needed and the options given.
1866 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1867 struct Client *connect, struct Channel *chan, unsigned int dest)
1872 assert(0 != source);
1876 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1880 mbuf->mb_source = source;
1881 mbuf->mb_connect = connect;
1882 mbuf->mb_channel = chan;
1883 mbuf->mb_dest = dest;
1886 /* clear each mode-with-parameter slot */
1887 for (i = 0; i < MAXMODEPARAMS; i++) {
1888 MB_TYPE(mbuf, i) = 0;
1889 MB_UINT(mbuf, i) = 0;
1894 * This routine simply adds modes to be added or deleted; do a binary OR
1895 * with either MODE_ADD or MODE_DEL
1898 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1901 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1903 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1904 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1905 MODE_DELJOINS | MODE_WASDELJOINS);
1907 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1910 if (mode & MODE_ADD) {
1911 mbuf->mb_rem &= ~mode;
1912 mbuf->mb_add |= mode;
1914 mbuf->mb_add &= ~mode;
1915 mbuf->mb_rem |= mode;
1920 * This routine adds a mode to be added or deleted that takes a unsigned
1921 * int parameter; mode may *only* be the relevant mode flag ORed with one
1922 * of MODE_ADD or MODE_DEL
1925 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1928 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1930 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1931 MB_UINT(mbuf, mbuf->mb_count) = uint;
1933 /* when we've reached the maximal count, flush the buffer */
1934 if (++mbuf->mb_count >=
1935 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1936 modebuf_flush_int(mbuf, 0);
1940 * This routine adds a mode to be added or deleted that takes a string
1941 * parameter; mode may *only* be the relevant mode flag ORed with one of
1942 * MODE_ADD or MODE_DEL
1945 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1949 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1951 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1952 MB_STRING(mbuf, mbuf->mb_count) = string;
1954 /* when we've reached the maximal count, flush the buffer */
1955 if (++mbuf->mb_count >=
1956 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1957 modebuf_flush_int(mbuf, 0);
1961 * This routine adds a mode to be added or deleted that takes a client
1962 * parameter; mode may *only* be the relevant mode flag ORed with one of
1963 * MODE_ADD or MODE_DEL
1966 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1967 struct Client *client)
1970 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1972 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1973 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1975 /* when we've reached the maximal count, flush the buffer */
1976 if (++mbuf->mb_count >=
1977 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1978 modebuf_flush_int(mbuf, 0);
1982 * This is the exported binding for modebuf_flush()
1985 modebuf_flush(struct ModeBuf *mbuf)
1987 struct Membership *memb;
1989 /* Check if MODE_WASDELJOINS should be set */
1990 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1991 && (mbuf->mb_rem & MODE_DELJOINS)) {
1992 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
1993 if (IsDelayedJoin(memb)) {
1994 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
1995 mbuf->mb_add |= MODE_WASDELJOINS;
1996 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2002 return modebuf_flush_int(mbuf, 1);
2006 * This extracts the simple modes contained in mbuf
2009 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2011 static int flags[] = {
2012 /* MODE_CHANOP, 'o', */
2013 /* MODE_VOICE, 'v', */
2016 MODE_MODERATED, 'm',
2017 MODE_TOPICLIMIT, 't',
2018 MODE_INVITEONLY, 'i',
2019 MODE_NOPRIVMSGS, 'n',
2023 /* MODE_BAN, 'b', */
2030 int i, bufpos = 0, len;
2032 char *key = 0, limitbuf[20];
2033 char *apass = 0, *upass = 0;
2042 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2043 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2044 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2046 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2047 key = MB_STRING(mbuf, i);
2048 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2049 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2050 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2051 upass = MB_STRING(mbuf, i);
2052 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2053 apass = MB_STRING(mbuf, i);
2060 buf[bufpos++] = '+'; /* start building buffer */
2062 for (flag_p = flags; flag_p[0]; flag_p += 2)
2064 buf[bufpos++] = flag_p[1];
2066 for (i = 0, len = bufpos; i < len; i++) {
2068 build_string(buf, &bufpos, key, 0, ' ');
2069 else if (buf[i] == 'l')
2070 build_string(buf, &bufpos, limitbuf, 0, ' ');
2071 else if (buf[i] == 'u')
2072 build_string(buf, &bufpos, upass, 0, ' ');
2073 else if (buf[i] == 'A')
2074 build_string(buf, &bufpos, apass, 0, ' ');
2083 * Simple function to invalidate bans
2086 mode_ban_invalidate(struct Channel *chan)
2088 struct Membership *member;
2090 for (member = chan->members; member; member = member->next_member)
2091 ClearBanValid(member);
2095 * Simple function to drop invite structures
2098 mode_invite_clear(struct Channel *chan)
2100 while (chan->invites)
2101 del_invite(chan->invites->value.cptr, chan);
2104 /* What we've done for mode_parse so far... */
2105 #define DONE_LIMIT 0x01 /* We've set the limit */
2106 #define DONE_KEY 0x02 /* We've set the key */
2107 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2108 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2109 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2110 #define DONE_UPASS 0x20 /* We've set user pass */
2111 #define DONE_APASS 0x40 /* We've set admin pass */
2114 struct ModeBuf *mbuf;
2115 struct Client *cptr;
2116 struct Client *sptr;
2117 struct Channel *chptr;
2118 struct Membership *member;
2129 struct SLink banlist[MAXPARA];
2132 struct Client *client;
2133 } cli_change[MAXPARA];
2137 * Here's a helper function to deal with sending along "Not oper" or
2138 * "Not member" messages
2141 send_notoper(struct ParseState *state)
2143 if (state->done & DONE_NOTOPER)
2146 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2147 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2149 state->done |= DONE_NOTOPER;
2153 * Helper function to convert limits
2156 mode_parse_limit(struct ParseState *state, int *flag_p)
2158 unsigned int t_limit;
2160 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2161 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2164 if (state->parc <= 0) { /* warn if not enough args */
2165 if (MyUser(state->sptr))
2166 need_more_params(state->sptr, "MODE +l");
2170 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2174 if ((int)t_limit<0) /* don't permit a negative limit */
2177 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2178 (!t_limit || t_limit == state->chptr->mode.limit))
2181 t_limit = state->chptr->mode.limit;
2183 /* If they're not an oper, they can't change modes */
2184 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2185 send_notoper(state);
2189 /* Can't remove a limit that's not there */
2190 if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2193 /* Skip if this is a burst and a lower limit than this is set already */
2194 if ((state->flags & MODE_PARSE_BURST) &&
2195 (state->chptr->mode.mode & flag_p[0]) &&
2196 (state->chptr->mode.limit < t_limit))
2199 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2201 state->done |= DONE_LIMIT;
2206 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2208 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2209 if (state->dir & MODE_ADD) {
2210 state->chptr->mode.mode |= flag_p[0];
2211 state->chptr->mode.limit = t_limit;
2213 state->chptr->mode.mode &= ~flag_p[0];
2214 state->chptr->mode.limit = 0;
2220 * Helper function to convert keys
2223 mode_parse_key(struct ParseState *state, int *flag_p)
2228 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2231 if (state->parc <= 0) { /* warn if not enough args */
2232 if (MyUser(state->sptr))
2233 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2238 t_str = state->parv[state->args_used++]; /* grab arg */
2242 /* If they're not an oper, they can't change modes */
2243 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2244 send_notoper(state);
2248 if (state->done & DONE_KEY) /* allow key to be set only once */
2250 state->done |= DONE_KEY;
2254 /* clean up the key string */
2256 while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2260 if (!*t_str) { /* warn if empty */
2261 if (MyUser(state->sptr))
2262 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2270 /* Skip if this is a burst, we have a key already and the new key is
2271 * after the old one alphabetically */
2272 if ((state->flags & MODE_PARSE_BURST) &&
2273 *(state->chptr->mode.key) &&
2274 ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2277 /* can't add a key if one is set, nor can one remove the wrong key */
2278 if (!(state->flags & MODE_PARSE_FORCE))
2279 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2280 (state->dir == MODE_DEL &&
2281 ircd_strcmp(state->chptr->mode.key, t_str))) {
2282 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2286 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2287 !ircd_strcmp(state->chptr->mode.key, t_str))
2288 return; /* no key change */
2290 if (state->flags & MODE_PARSE_BOUNCE) {
2291 if (*state->chptr->mode.key) /* reset old key */
2292 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2293 state->chptr->mode.key, 0);
2294 else /* remove new bogus key */
2295 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2296 } else /* send new key */
2297 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2299 if (state->flags & MODE_PARSE_SET) {
2300 if (state->dir == MODE_ADD) /* set the new key */
2301 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2302 else /* remove the old key */
2303 *state->chptr->mode.key = '\0';
2308 * Helper function to convert user passes
2311 mode_parse_upass(struct ParseState *state, int *flag_p)
2316 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2319 if (state->parc <= 0) { /* warn if not enough args */
2320 if (MyUser(state->sptr))
2321 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2326 t_str = state->parv[state->args_used++]; /* grab arg */
2330 /* If they're not an oper, they can't change modes */
2331 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2332 send_notoper(state);
2336 /* If they are not the channel manager, they are not allowed to change it */
2337 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2338 if (*state->chptr->mode.apass) {
2339 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2340 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2342 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2343 "Re-create the channel. The channel must be *empty* for",
2344 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2345 "before it can be recreated.");
2350 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2352 state->done |= DONE_UPASS;
2354 t_len = PASSLEN + 1;
2356 /* clean up the upass string */
2358 while (*++s > ' ' && *s != ':' && --t_len)
2362 if (!*t_str) { /* warn if empty */
2363 if (MyUser(state->sptr))
2364 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2372 if (!(state->flags & MODE_PARSE_FORCE))
2373 /* can't add the upass while apass is not set */
2374 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2375 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2378 /* can't add a upass if one is set, nor can one remove the wrong upass */
2379 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2380 (state->dir == MODE_DEL &&
2381 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2382 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2386 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2387 !ircd_strcmp(state->chptr->mode.upass, t_str))
2388 return; /* no upass change */
2390 if (state->flags & MODE_PARSE_BOUNCE) {
2391 if (*state->chptr->mode.upass) /* reset old upass */
2392 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2393 state->chptr->mode.upass, 0);
2394 else /* remove new bogus upass */
2395 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2396 } else /* send new upass */
2397 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2399 if (state->flags & MODE_PARSE_SET) {
2400 if (state->dir == MODE_ADD) /* set the new upass */
2401 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2402 else /* remove the old upass */
2403 *state->chptr->mode.upass = '\0';
2408 * Helper function to convert admin passes
2411 mode_parse_apass(struct ParseState *state, int *flag_p)
2416 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2419 if (state->parc <= 0) { /* warn if not enough args */
2420 if (MyUser(state->sptr))
2421 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2426 t_str = state->parv[state->args_used++]; /* grab arg */
2430 /* If they're not an oper, they can't change modes */
2431 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2432 send_notoper(state);
2436 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2437 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2438 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2442 /* If they are not the channel manager, they are not allowed to change it */
2443 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2444 if (*state->chptr->mode.apass) {
2445 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2446 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2448 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2449 "Re-create the channel. The channel must be *empty* for",
2450 "at least a whole minute", "before it can be recreated.");
2455 if (state->done & DONE_APASS) /* allow apass to be set only once */
2457 state->done |= DONE_APASS;
2459 t_len = PASSLEN + 1;
2461 /* clean up the apass string */
2463 while (*++s > ' ' && *s != ':' && --t_len)
2467 if (!*t_str) { /* warn if empty */
2468 if (MyUser(state->sptr))
2469 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2477 if (!(state->flags & MODE_PARSE_FORCE)) {
2478 /* can't remove the apass while upass is still set */
2479 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2480 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2483 /* can't add an apass if one is set, nor can one remove the wrong apass */
2484 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2485 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2486 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2491 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2492 !ircd_strcmp(state->chptr->mode.apass, t_str))
2493 return; /* no apass change */
2495 if (state->flags & MODE_PARSE_BOUNCE) {
2496 if (*state->chptr->mode.apass) /* reset old apass */
2497 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2498 state->chptr->mode.apass, 0);
2499 else /* remove new bogus apass */
2500 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2501 } else /* send new apass */
2502 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2504 if (state->flags & MODE_PARSE_SET) {
2505 if (state->dir == MODE_ADD) { /* set the new apass */
2506 /* Make it VERY clear to the user that this is a one-time password */
2507 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2508 if (MyUser(state->sptr)) {
2509 send_reply(state->sptr, RPL_APASSWARN,
2510 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2511 "Are you SURE you want to use this as Admin password? ",
2512 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2513 send_reply(state->sptr, RPL_APASSWARN,
2514 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2515 "\" to remove the password and then immediately set a new one. "
2516 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2517 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2518 "Now set the channel user password (+u).");
2520 } else { /* remove the old apass */
2521 *state->chptr->mode.apass = '\0';
2522 if (MyUser(state->sptr))
2523 send_reply(state->sptr, RPL_APASSWARN,
2524 "WARNING: You removed the channel Admin password MODE (+A). ",
2525 "If you would disconnect or leave the channel without setting a new password then you will ",
2526 "not be able to set it again and lose ownership of this channel! ",
2527 "SET A NEW PASSWORD NOW!", "");
2533 * Helper function to convert bans
2536 mode_parse_ban(struct ParseState *state, int *flag_p)
2539 struct SLink *ban, *newban = 0;
2541 if (state->parc <= 0) { /* Not enough args, send ban list */
2542 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2543 send_ban_list(state->sptr, state->chptr);
2544 state->done |= DONE_BANLIST;
2550 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2553 t_str = state->parv[state->args_used++]; /* grab arg */
2557 /* If they're not an oper, they can't change modes */
2558 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2559 send_notoper(state);
2563 if ((s = strchr(t_str, ' ')))
2566 if (!*t_str || *t_str == ':') { /* warn if empty */
2567 if (MyUser(state->sptr))
2568 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2573 t_str = collapse(pretty_mask(t_str));
2575 /* remember the ban for the moment... */
2576 if (state->dir == MODE_ADD) {
2577 newban = state->banlist + (state->numbans++);
2580 DupString(newban->value.ban.banstr, t_str);
2581 newban->value.ban.who = cli_name(state->sptr);
2582 newban->value.ban.when = TStime();
2584 newban->flags = CHFL_BAN | MODE_ADD;
2586 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2587 newban->flags |= CHFL_BAN_IPMASK;
2590 if (!state->chptr->banlist) {
2591 state->chptr->banlist = newban; /* add our ban with its flags */
2592 state->done |= DONE_BANCLEAN;
2596 /* Go through all bans */
2597 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2598 /* first, clean the ban flags up a bit */
2599 if (!(state->done & DONE_BANCLEAN))
2600 /* Note: We're overloading *lots* of bits here; be careful! */
2601 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2605 * MODE_ADD - Ban was added; if we're bouncing modes,
2606 * then we'll remove it below; otherwise,
2607 * we'll have to allocate a real ban
2609 * MODE_DEL - Ban was marked for deletion; if we're
2610 * bouncing modes, we'll have to re-add it,
2611 * otherwise, we'll have to remove it
2613 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2614 * with a ban already set; if we're
2615 * bouncing modes, we'll have to bounce
2616 * this one; otherwise, we'll just ignore
2617 * it when we process added bans
2620 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2621 ban->flags |= MODE_DEL; /* delete one ban */
2623 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2625 } else if (state->dir == MODE_ADD) {
2626 /* if the ban already exists, don't worry about it */
2627 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2628 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2629 MyFree(newban->value.ban.banstr); /* stopper a leak */
2630 state->numbans--; /* deallocate last ban */
2631 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2633 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2634 if (!(ban->flags & MODE_DEL))
2635 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2636 } else if (!mmatch(t_str, ban->value.ban.banstr))
2637 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2639 if (!ban->next && (newban->flags & MODE_ADD))
2641 ban->next = newban; /* add our ban with its flags */
2642 break; /* get out of loop */
2646 state->done |= DONE_BANCLEAN;
2650 * This is the bottom half of the ban processor
2653 mode_process_bans(struct ParseState *state)
2655 struct SLink *ban, *newban, *prevban, *nextban;
2661 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2663 banlen = strlen(ban->value.ban.banstr);
2665 nextban = ban->next;
2667 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2669 prevban->next = 0; /* Break the list; ban isn't a real ban */
2671 state->chptr->banlist = 0;
2676 MyFree(ban->value.ban.banstr);
2679 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2680 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2681 ban->value.ban.banstr,
2682 state->flags & MODE_PARSE_SET);
2684 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2685 if (prevban) /* clip it out of the list... */
2686 prevban->next = ban->next;
2688 state->chptr->banlist = ban->next;
2693 MyFree(ban->value.ban.who);
2697 continue; /* next ban; keep prevban like it is */
2699 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2700 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2702 prevban->next = 0; /* Break the list; ban isn't a real ban */
2704 state->chptr->banlist = 0;
2706 /* If we're supposed to ignore it, do so. */
2707 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2708 !(state->flags & MODE_PARSE_BOUNCE)) {
2712 MyFree(ban->value.ban.banstr);
2714 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2715 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2716 count > feature_int(FEAT_MAXBANS))) {
2717 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2718 ban->value.ban.banstr);
2722 MyFree(ban->value.ban.banstr);
2724 /* add the ban to the buffer */
2725 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2726 ban->value.ban.banstr,
2727 !(state->flags & MODE_PARSE_SET));
2729 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2730 newban = make_link();
2731 newban->value.ban.banstr = ban->value.ban.banstr;
2732 DupString(newban->value.ban.who, ban->value.ban.who);
2733 newban->value.ban.when = ban->value.ban.when;
2734 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2736 newban->next = state->chptr->banlist; /* and link it in */
2737 state->chptr->banlist = newban;
2746 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2748 if (changed) /* if we changed the ban list, we must invalidate the bans */
2749 mode_ban_invalidate(state->chptr);
2753 * Helper function to process client changes
2756 mode_parse_client(struct ParseState *state, int *flag_p)
2759 struct Client *acptr;
2762 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2765 if (state->parc <= 0) /* return if not enough args */
2768 t_str = state->parv[state->args_used++]; /* grab arg */
2772 /* If they're not an oper, they can't change modes */
2773 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2774 send_notoper(state);
2778 if (MyUser(state->sptr)) /* find client we're manipulating */
2779 acptr = find_chasing(state->sptr, t_str, NULL);
2781 acptr = findNUser(t_str);
2784 return; /* find_chasing() already reported an error to the user */
2786 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2787 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2788 state->cli_change[i].flag & flag_p[0]))
2789 break; /* found a slot */
2791 /* Store what we're doing to them */
2792 state->cli_change[i].flag = state->dir | flag_p[0];
2793 state->cli_change[i].client = acptr;
2797 * Helper function to process the changed client list
2800 mode_process_clients(struct ParseState *state)
2803 struct Membership *member;
2805 for (i = 0; state->cli_change[i].flag; i++) {
2806 assert(0 != state->cli_change[i].client);
2808 /* look up member link */
2809 if (!(member = find_member_link(state->chptr,
2810 state->cli_change[i].client)) ||
2811 (MyUser(state->sptr) && IsZombie(member))) {
2812 if (MyUser(state->sptr))
2813 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2814 cli_name(state->cli_change[i].client),
2815 state->chptr->chname);
2819 if ((state->cli_change[i].flag & MODE_ADD &&
2820 (state->cli_change[i].flag & member->status)) ||
2821 (state->cli_change[i].flag & MODE_DEL &&
2822 !(state->cli_change[i].flag & member->status)))
2823 continue; /* no change made, don't do anything */
2825 /* see if the deop is allowed */
2826 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2827 (MODE_DEL | MODE_CHANOP)) {
2828 /* prevent +k users from being deopped */
2829 if (IsChannelService(state->cli_change[i].client)) {
2830 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2831 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2833 (IsServer(state->sptr) ? cli_name(state->sptr) :
2834 cli_name((cli_user(state->sptr))->server)));
2836 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2837 send_reply(state->sptr, ERR_ISCHANSERVICE,
2838 cli_name(state->cli_change[i].client),
2839 state->chptr->chname);
2844 /* check deop for local user */
2845 if (MyUser(state->sptr)) {
2847 /* don't allow local opers to be deopped on local channels */
2848 if (state->cli_change[i].client != state->sptr &&
2849 IsLocalChannel(state->chptr->chname) &&
2850 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2851 send_reply(state->sptr, ERR_ISOPERLCHAN,
2852 cli_name(state->cli_change[i].client),
2853 state->chptr->chname);
2857 if (feature_bool(FEAT_OPLEVELS)) {
2858 /* don't allow to deop members with an op level that is <= our own level */
2859 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2861 && OpLevel(member) <= OpLevel(state->member)) {
2862 int equal = (OpLevel(member) == OpLevel(state->member));
2863 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2864 cli_name(state->cli_change[i].client),
2865 state->chptr->chname,
2866 OpLevel(state->member), OpLevel(member),
2867 "deop", equal ? "the same" : "a higher");
2874 /* set op-level of member being opped */
2875 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2876 (MODE_ADD | MODE_CHANOP)) {
2877 /* If on a channel with upass set, someone with level x gives ops to someone else,
2878 then that person gets level x-1. On other channels, where upass is not set,
2879 the level stays the same. */
2880 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2881 /* Someone being opped by a server gets op-level 0 */
2882 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2883 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2886 /* actually effect the change */
2887 if (state->flags & MODE_PARSE_SET) {
2888 if (state->cli_change[i].flag & MODE_ADD) {
2889 if (IsDelayedJoin(member))
2890 RevealDelayedJoin(member);
2891 member->status |= (state->cli_change[i].flag &
2892 (MODE_CHANOP | MODE_VOICE));
2893 if (state->cli_change[i].flag & MODE_CHANOP)
2894 ClearDeopped(member);
2896 member->status &= ~(state->cli_change[i].flag &
2897 (MODE_CHANOP | MODE_VOICE));
2900 /* accumulate the change */
2901 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2902 state->cli_change[i].client);
2903 } /* for (i = 0; state->cli_change[i].flags; i++) */
2907 * Helper function to process the simple modes
2910 mode_parse_mode(struct ParseState *state, int *flag_p)
2912 /* If they're not an oper, they can't change modes */
2913 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2914 send_notoper(state);
2921 if (state->dir == MODE_ADD) {
2922 state->add |= flag_p[0];
2923 state->del &= ~flag_p[0];
2925 if (flag_p[0] & MODE_SECRET) {
2926 state->add &= ~MODE_PRIVATE;
2927 state->del |= MODE_PRIVATE;
2928 } else if (flag_p[0] & MODE_PRIVATE) {
2929 state->add &= ~MODE_SECRET;
2930 state->del |= MODE_SECRET;
2932 if (flag_p[0] & MODE_DELJOINS) {
2933 state->add &= ~MODE_WASDELJOINS;
2934 state->del |= MODE_WASDELJOINS;
2937 state->add &= ~flag_p[0];
2938 state->del |= flag_p[0];
2941 assert(0 == (state->add & state->del));
2942 assert((MODE_SECRET | MODE_PRIVATE) !=
2943 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2947 * This routine is intended to parse MODE or OPMODE commands and effect the
2948 * changes (or just build the bounce buffer). We pass the starting offset
2952 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2953 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2954 struct Membership* member)
2956 static int chan_flags[] = {
2961 MODE_MODERATED, 'm',
2962 MODE_TOPICLIMIT, 't',
2963 MODE_INVITEONLY, 'i',
2964 MODE_NOPRIVMSGS, 'n',
2978 unsigned int t_mode;
2980 struct ParseState state;
2991 state.chptr = chptr;
2992 state.member = member;
2995 state.flags = flags;
2996 state.dir = MODE_ADD;
3000 state.args_used = 0;
3001 state.max_args = MAXMODEPARAMS;
3004 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3005 state.banlist[i].next = 0;
3006 state.banlist[i].value.ban.banstr = 0;
3007 state.banlist[i].value.ban.who = 0;
3008 state.banlist[i].value.ban.when = 0;
3009 state.banlist[i].flags = 0;
3010 state.cli_change[i].flag = 0;
3011 state.cli_change[i].client = 0;
3014 modestr = state.parv[state.args_used++];
3018 for (; *modestr; modestr++) {
3019 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3020 if (flag_p[1] == *modestr)
3023 if (!flag_p[0]) { /* didn't find it? complain and continue */
3024 if (MyUser(state.sptr))
3025 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3030 case '+': /* switch direction to MODE_ADD */
3031 case '-': /* switch direction to MODE_DEL */
3032 state.dir = flag_p[0];
3035 case 'l': /* deal with limits */
3036 mode_parse_limit(&state, flag_p);
3039 case 'k': /* deal with keys */
3040 mode_parse_key(&state, flag_p);
3043 case 'A': /* deal with Admin passes */
3044 if (feature_bool(FEAT_OPLEVELS))
3045 mode_parse_apass(&state, flag_p);
3048 case 'u': /* deal with user passes */
3049 if (feature_bool(FEAT_OPLEVELS))
3050 mode_parse_upass(&state, flag_p);
3053 case 'b': /* deal with bans */
3054 mode_parse_ban(&state, flag_p);
3057 case 'o': /* deal with ops/voice */
3059 mode_parse_client(&state, flag_p);
3062 default: /* deal with other modes */
3063 mode_parse_mode(&state, flag_p);
3065 } /* switch (*modestr) */
3066 } /* for (; *modestr; modestr++) */
3068 if (state.flags & MODE_PARSE_BURST)
3069 break; /* don't interpret any more arguments */
3071 if (state.parc > 0) { /* process next argument in string */
3072 modestr = state.parv[state.args_used++];
3076 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3079 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3080 break; /* we're then going to bounce the mode! */
3082 recv_ts = atoi(modestr);
3084 if (recv_ts && recv_ts < state.chptr->creationtime)
3085 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3087 break; /* break out of while loop */
3088 } else if (state.flags & MODE_PARSE_STRICT ||
3089 (MyUser(state.sptr) && state.max_args <= 0)) {
3090 state.parc++; /* we didn't actually gobble the argument */
3092 break; /* break out of while loop */
3095 } /* while (*modestr) */
3098 * the rest of the function finishes building resultant MODEs; if the
3099 * origin isn't a member or an oper, skip it.
3101 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3102 return state.args_used; /* tell our parent how many args we gobbled */
3104 t_mode = state.chptr->mode.mode;
3106 if (state.del & t_mode) { /* delete any modes to be deleted... */
3107 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3109 t_mode &= ~state.del;
3111 if (state.add & ~t_mode) { /* add any modes to be added... */
3112 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3114 t_mode |= state.add;
3117 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3118 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3119 !(t_mode & MODE_INVITEONLY))
3120 mode_invite_clear(state.chptr);
3122 state.chptr->mode.mode = t_mode;
3125 if (state.flags & MODE_PARSE_WIPEOUT) {
3126 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3127 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3128 state.chptr->mode.limit);
3129 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3130 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3131 state.chptr->mode.key, 0);
3132 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3133 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3134 state.chptr->mode.upass, 0);
3135 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3136 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3137 state.chptr->mode.apass, 0);
3140 if (state.done & DONE_BANCLEAN) /* process bans */
3141 mode_process_bans(&state);
3143 /* process client changes */
3144 if (state.cli_change[0].flag)
3145 mode_process_clients(&state);
3147 return state.args_used; /* tell our parent how many args we gobbled */
3151 * Initialize a join buffer
3154 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3155 struct Client *connect, unsigned int type, char *comment,
3161 assert(0 != source);
3162 assert(0 != connect);
3164 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3165 jbuf->jb_connect = connect;
3166 jbuf->jb_type = type;
3167 jbuf->jb_comment = comment;
3168 jbuf->jb_create = create;
3170 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3171 type == JOINBUF_TYPE_PART ||
3172 type == JOINBUF_TYPE_PARTALL) ?
3173 STARTJOINLEN : STARTCREATELEN) +
3174 (comment ? strlen(comment) + 2 : 0));
3176 for (i = 0; i < MAXJOINARGS; i++)
3177 jbuf->jb_channels[i] = 0;
3181 * Add a channel to the join buffer
3184 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3192 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3193 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3198 is_local = IsLocalChannel(chan->chname);
3200 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3201 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3202 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3203 if (IsUserParting(member))
3205 SetUserParting(member);
3207 /* Send notification to channel */
3208 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3209 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3210 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3211 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3212 else if (MyUser(jbuf->jb_source))
3213 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3214 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3215 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3216 /* XXX: Shouldn't we send a PART here anyway? */
3217 /* to users on the channel? Why? From their POV, the user isn't on
3218 * the channel anymore anyway. We don't send to servers until below,
3219 * when we gang all the channel parts together. Note that this is
3220 * exactly the same logic, albeit somewhat more concise, as was in
3221 * the original m_part.c */
3223 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3224 is_local) /* got to remove user here */
3225 remove_user_from_channel(jbuf->jb_source, chan);
3227 /* Add user to channel */
3228 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3229 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3231 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3233 /* send notification to all servers */
3234 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3235 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3236 "%H %Tu", chan, chan->creationtime);
3238 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3239 /* Send the notification to the channel */
3240 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3242 /* send an op, too, if needed */
3243 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3244 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3245 chan, jbuf->jb_source);
3246 } else if (MyUser(jbuf->jb_source))
3247 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3250 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3251 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3252 return; /* don't send to remote */
3254 /* figure out if channel name will cause buffer to be overflowed */
3255 len = chan ? strlen(chan->chname) + 1 : 2;
3256 if (jbuf->jb_strlen + len > BUFSIZE)
3257 joinbuf_flush(jbuf);
3259 /* add channel to list of channels to send and update counts */
3260 jbuf->jb_channels[jbuf->jb_count++] = chan;
3261 jbuf->jb_strlen += len;
3263 /* if we've used up all slots, flush */
3264 if (jbuf->jb_count >= MAXJOINARGS)
3265 joinbuf_flush(jbuf);
3269 * Flush the channel list to remote servers
3272 joinbuf_flush(struct JoinBuf *jbuf)
3274 char chanlist[BUFSIZE];
3278 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3279 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3280 return 0; /* no joins to process */
3282 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3283 build_string(chanlist, &chanlist_i,
3284 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3285 i == 0 ? '\0' : ',');
3286 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3287 /* Remove user from channel */
3288 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3290 jbuf->jb_channels[i] = 0; /* mark slot empty */
3293 jbuf->jb_count = 0; /* reset base counters */
3294 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3295 STARTJOINLEN : STARTCREATELEN) +
3296 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3298 /* and send the appropriate command */
3299 switch (jbuf->jb_type) {
3300 case JOINBUF_TYPE_CREATE:
3301 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3302 "%s %Tu", chanlist, jbuf->jb_create);
3305 case JOINBUF_TYPE_PART:
3306 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3307 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3315 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3316 int IsInvited(struct Client* cptr, const void* chptr)
3320 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3321 if (lp->value.chptr == chptr)
3326 /* RevealDelayedJoin: sends a join for a hidden user */
3328 void RevealDelayedJoin(struct Membership *member) {
3329 ClearDelayedJoin(member);
3330 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3332 CheckDelayedJoins(member->channel);
3335 /* CheckDelayedJoins: checks and clear +d if necessary */
3337 void CheckDelayedJoins(struct Channel *chan) {
3338 struct Membership *memb2;
3340 if (chan->mode.mode & MODE_WASDELJOINS) {
3341 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3342 if (IsDelayedJoin(memb2))
3347 chan->mode.mode &= ~MODE_WASDELJOINS;
3348 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,