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 + 16 + 3)
178 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
181 ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name,
182 ircd_ntoa((const char*) &ip));
187 * Subtract one user from channel i (and free channel
188 * block, if channel became empty).
189 * Returns: true (1) if channel still has members.
190 * false (0) if the channel is now empty.
192 int sub1_from_channel(struct Channel* chptr)
194 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
196 assert(0 != chptr->members);
204 * Also channels without Apass set need to be kept alive,
205 * otherwise Bad Guys(tm) would be able to takeover
206 * existing channels too easily, and then set an Apass!
207 * However, if a channel without Apass becomes empty
208 * then we try to be kind to them and remove possible
211 chptr->mode.mode &= ~MODE_INVITEONLY;
212 chptr->mode.limit = 0;
214 * We do NOT reset a possible key or bans because when
215 * the 'channel owners' can't get in because of a key
216 * or ban then apparently there was a fight/takeover
217 * on the channel and we want them to contact IRC opers
218 * who then will educate them on the use of Apass/upass.
221 if (feature_bool(FEAT_OPLEVELS)) {
222 if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */
223 schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */
225 schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */
227 destruct_channel(chptr);
232 int destruct_channel(struct Channel* chptr)
237 assert(0 == chptr->members);
239 /* Channel became (or was) empty: Remove channel */
240 if (is_listed(chptr))
243 for (i = 0; i <= HighestFd; i++)
245 struct Client *acptr = 0;
246 if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
247 (cli_listing(acptr))->chptr == chptr)
249 list_next_channels(acptr, 1);
250 break; /* Only one client can list a channel */
255 * Now, find all invite links from channel structure
257 while ((tmp = chptr->invites))
258 del_invite(tmp->value.cptr, chptr);
260 tmp = chptr->banlist;
265 MyFree(obtmp->value.ban.banstr);
266 MyFree(obtmp->value.ban.who);
270 chptr->prev->next = chptr->next;
272 GlobalChannelList = chptr->next;
274 chptr->next->prev = chptr->prev;
276 --UserStats.channels;
278 * make sure that channel actually got removed from hash table
280 assert(chptr->hnext == chptr);
288 * `cptr' must be the client adding the ban.
290 * If `change' is true then add `banid' to channel `chptr'.
291 * Returns 0 if the ban was added.
292 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
293 * Return -1 otherwise.
295 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
296 * when `change' is false, otherwise they will be removed from the banlist.
297 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
298 * respectively will return these bans until NULL is returned.
300 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
301 * is reset (unless a non-zero value is returned, in which case the
302 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
306 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
307 int change, int firsttime)
312 int removed_bans = 0;
313 int len = strlen(banid);
318 assert(0 == prev_ban);
319 assert(0 == removed_bans_list);
323 for (banp = &chptr->banlist; *banp;)
325 len += strlen((*banp)->value.ban.banstr);
327 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
329 if (!strcmp((*banp)->value.ban.banstr, banid))
331 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
335 else if (!mmatch((*banp)->value.ban.banstr, banid))
337 if (!mmatch(banid, (*banp)->value.ban.banstr))
339 struct SLink *tmp = *banp;
345 len -= strlen(tmp->value.ban.banstr);
348 /* These will be sent to the user later as -b */
349 tmp->next = removed_bans_list;
350 removed_bans_list = tmp;
353 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
355 tmp->flags |= CHFL_BAN_OVERLAPPED;
366 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
367 banp = &(*banp)->next;
370 if (MyUser(cptr) && !removed_bans &&
371 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
372 (cnt >= feature_int(FEAT_MAXBANS))))
374 send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
380 struct Membership* member;
382 ban->next = chptr->banlist;
384 ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
385 assert(0 != ban->value.ban.banstr);
386 strcpy(ban->value.ban.banstr, banid);
388 if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
389 DupString(ban->value.ban.who, cli_name(&me));
391 DupString(ban->value.ban.who, cli_name(cptr));
392 assert(0 != ban->value.ban.who);
394 ban->value.ban.when = TStime();
395 ban->flags = CHFL_BAN; /* This bit is never used I think... */
396 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
397 ban->flags |= CHFL_BAN_IPMASK;
398 chptr->banlist = ban;
401 * Erase ban-valid-bit
403 for (member = chptr->members; member; member = member->next_member)
404 ClearBanValid(member); /* `ban' == channel member ! */
409 struct SLink *next_removed_overlapped_ban(void)
411 struct SLink *tmp = removed_bans_list;
414 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
415 MyFree(prev_ban->value.ban.banstr);
416 MyFree(prev_ban->value.ban.who);
421 removed_bans_list = removed_bans_list->next;
427 * find_channel_member - returns Membership * if a person is joined and not a zombie
429 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
431 struct Membership* member;
434 member = find_member_link(chptr, cptr);
435 return (member && !IsZombie(member)) ? member : 0;
439 * is_banned - a non-zero value if banned else 0.
441 static int is_banned(struct Client *cptr, struct Channel *chptr,
442 struct Membership* member)
445 char tmphost[HOSTLEN + 1];
446 char nu_host[NUH_BUFSIZE];
447 char nu_realhost[NUH_BUFSIZE];
448 char nu_ip[NUI_BUFSIZE];
456 if (member && IsBanValid(member))
457 return IsBanned(member);
459 s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
460 (cli_user(cptr))->host);
463 if (HasHiddenHost(cptr))
465 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
466 (cli_user(cptr))->username,
467 cli_user(cptr)->realhost);
471 ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
472 cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
473 sr = make_nick_user_host(nu_realhost, cli_name(cptr),
474 cli_user(cptr)->username,
479 for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
480 if ((tmp->flags & CHFL_BAN_IPMASK)) {
482 ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
483 (cli_user(cptr))->username, cli_ip(cptr));
484 if (match(tmp->value.ban.banstr, ip_s) == 0)
487 else if (match(tmp->value.ban.banstr, s) == 0)
489 else if (sr && match(tmp->value.ban.banstr, sr) == 0)
505 return (tmp != NULL);
509 * adds a user to a channel by adding another link to the channels member
512 void add_user_to_channel(struct Channel* chptr, struct Client* who,
513 unsigned int flags, int oplevel)
520 struct Membership* member = membershipFreeList;
522 membershipFreeList = member->next_member;
524 member = (struct Membership*) MyMalloc(sizeof(struct Membership));
525 ++membershipAllocCount;
530 member->channel = chptr;
531 member->status = flags;
532 member->oplevel = oplevel;
534 member->next_member = chptr->members;
535 if (member->next_member)
536 member->next_member->prev_member = member;
537 member->prev_member = 0;
538 chptr->members = member;
540 member->next_channel = (cli_user(who))->channel;
541 if (member->next_channel)
542 member->next_channel->prev_channel = member;
543 member->prev_channel = 0;
544 (cli_user(who))->channel = member;
546 if (chptr->destruct_event)
547 remove_destruct_event(chptr);
549 ++((cli_user(who))->joined);
553 static int remove_member_from_channel(struct Membership* member)
555 struct Channel* chptr;
557 chptr = member->channel;
559 * unlink channel member list
561 if (member->next_member)
562 member->next_member->prev_member = member->prev_member;
563 if (member->prev_member)
564 member->prev_member->next_member = member->next_member;
566 member->channel->members = member->next_member;
569 * If this is the last delayed-join user, may have to clear WASDELJOINS.
571 if (IsDelayedJoin(member))
572 CheckDelayedJoins(chptr);
575 * unlink client channel list
577 if (member->next_channel)
578 member->next_channel->prev_channel = member->prev_channel;
579 if (member->prev_channel)
580 member->prev_channel->next_channel = member->next_channel;
582 (cli_user(member->user))->channel = member->next_channel;
584 --(cli_user(member->user))->joined;
586 member->next_member = membershipFreeList;
587 membershipFreeList = member;
589 return sub1_from_channel(chptr);
592 static int channel_all_zombies(struct Channel* chptr)
594 struct Membership* member;
596 for (member = chptr->members; member; member = member->next_member) {
597 if (!IsZombie(member))
604 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
607 struct Membership* member;
610 if ((member = find_member_link(chptr, cptr))) {
611 if (remove_member_from_channel(member)) {
612 if (channel_all_zombies(chptr)) {
614 * XXX - this looks dangerous but isn't if we got the referential
615 * integrity right for channels
617 while (remove_member_from_channel(chptr->members))
624 void remove_user_from_all_channels(struct Client* cptr)
626 struct Membership* chan;
628 assert(0 != cli_user(cptr));
630 while ((chan = (cli_user(cptr))->channel))
631 remove_user_from_channel(cptr, chan->channel);
634 int is_chan_op(struct Client *cptr, struct Channel *chptr)
636 struct Membership* member;
638 if ((member = find_member_link(chptr, cptr)))
639 return (!IsZombie(member) && IsChanOp(member));
644 int is_zombie(struct Client *cptr, struct Channel *chptr)
646 struct Membership* member;
650 if ((member = find_member_link(chptr, cptr)))
651 return IsZombie(member);
655 int has_voice(struct Client* cptr, struct Channel* chptr)
657 struct Membership* member;
660 if ((member = find_member_link(chptr, cptr)))
661 return (!IsZombie(member) && HasVoice(member));
666 int member_can_send_to_channel(struct Membership* member, int reveal)
670 /* Discourage using the Apass to get op. They should use the upass. */
671 if (IsChannelManager(member) && *member->channel->mode.upass)
674 if (IsVoicedOrOpped(member))
677 * If it's moderated, and you aren't a priviledged user, you can't
680 if (member->channel->mode.mode & MODE_MODERATED)
683 * If you're banned then you can't speak either.
684 * but because of the amount of CPU time that is_banned chews
685 * we only check it for our clients.
687 if (MyUser(member->user) && is_banned(member->user, member->channel, member))
690 if (IsDelayedJoin(member) && reveal)
691 RevealDelayedJoin(member);
696 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
698 struct Membership *member;
701 * Servers can always speak on channels.
706 member = find_channel_member(cptr, chptr);
709 * You can't speak if you're off channel, and it is +n (no external messages)
713 if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
714 ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
717 return !is_banned(cptr, chptr, NULL);
719 return member_can_send_to_channel(member, reveal);
723 * find_no_nickchange_channel
724 * if a member and not (opped or voiced) and (banned or moderated)
725 * return the name of the first channel banned on
727 const char* find_no_nickchange_channel(struct Client* cptr)
730 struct Membership* member;
731 for (member = (cli_user(cptr))->channel; member;
732 member = member->next_channel) {
733 if (!IsVoicedOrOpped(member) &&
734 (is_banned(cptr, member->channel, member) ||
735 (member->channel->mode.mode & MODE_MODERATED)))
736 return member->channel->chname;
744 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
745 * with the parameters in pbuf.
747 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
748 struct Channel *chptr, struct Membership *member)
750 int previous_parameter = 0;
757 if (chptr->mode.mode & MODE_SECRET)
759 else if (chptr->mode.mode & MODE_PRIVATE)
761 if (chptr->mode.mode & MODE_MODERATED)
763 if (chptr->mode.mode & MODE_TOPICLIMIT)
765 if (chptr->mode.mode & MODE_INVITEONLY)
767 if (chptr->mode.mode & MODE_NOPRIVMSGS)
769 if (chptr->mode.mode & MODE_REGONLY)
771 if (chptr->mode.mode & MODE_DELJOINS)
773 else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
775 if (chptr->mode.limit) {
777 ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
778 previous_parameter = 1;
781 if (*chptr->mode.key) {
783 if (previous_parameter)
785 if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
786 strcat(pbuf, chptr->mode.key);
789 previous_parameter = 1;
791 if (*chptr->mode.apass) {
793 if (previous_parameter)
795 if (IsServer(cptr)) {
796 strcat(pbuf, chptr->mode.apass);
799 previous_parameter = 1;
801 if (*chptr->mode.upass) {
803 if (previous_parameter)
805 if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
806 strcat(pbuf, chptr->mode.upass);
813 int compare_member_oplevel(const void *mp1, const void *mp2)
815 struct Membership const* member1 = *(struct Membership const**)mp1;
816 struct Membership const* member2 = *(struct Membership const**)mp2;
817 if (member1->oplevel == member2->oplevel)
819 return (member1->oplevel < member2->oplevel) ? -1 : 1;
823 * send "cptr" a full list of the modes for channel chptr.
825 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
827 /* The order in which modes are generated is now mandatory */
828 static unsigned int current_flags[4] =
829 { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
835 struct Membership* member;
837 char modebuf[MODEBUFLEN];
838 char parabuf[MODEBUFLEN];
840 int number_of_ops = 0;
841 int opped_members_index = 0;
842 struct Membership** opped_members = NULL;
843 int last_oplevel = 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?
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 */
941 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
942 last_oplevel = member->oplevel;
945 msgq_append(&me, mb, tbuf);
948 else if (flag_cnt > 1 && last_oplevel != member->oplevel)
951 * This can't be the first member of a (continued) BURST
952 * message because then either flag_cnt == 0 or new_mode == 1
953 * Now we need to append the incremental value of the oplevel.
955 char tbuf[2 + MAXOPLEVELDIGITS];
956 ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
957 last_oplevel = member->oplevel;
958 msgq_append(&me, mb, tbuf);
961 /* Go to the next `member'. */
963 member = member->next_member;
965 member = opped_members[++opped_members_index];
970 /* Point `member' at the start of the list again. */
973 member = chptr->members;
974 /* Now, after one loop, we know the number of ops and can
975 * allocate the dynamic array with pointer to the ops. */
976 opped_members = (struct Membership**)
977 MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
978 opped_members[number_of_ops] = NULL; /* Needed for loop termination */
982 /* At the end of the second loop, sort the opped members with
983 * increasing op-level, so that we will output them in the
984 * correct order (and all op-level increments stay positive) */
986 qsort(opped_members, number_of_ops,
987 sizeof(struct Membership*), compare_member_oplevel);
988 /* The third and fourth loop run only over the opped members. */
989 member = opped_members[(opped_members_index = 0)];
992 } /* loop over 0,+v,+o,+ov */
996 /* Attach all bans, space seperated " :%ban ban ..." */
997 for (first = 2; lp2; lp2 = lp2->next)
999 len = strlen(lp2->value.ban.banstr);
1000 if (msgq_bufleft(mb) < len + 1 + first)
1001 /* The +1 stands for the added ' '.
1002 * The +first stands for the added ":%".
1008 msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1009 lp2->value.ban.banstr);
1014 send_buffer(cptr, mb, 0); /* Send this message */
1016 } /* Continue when there was something
1017 that didn't fit (full==1) */
1019 MyFree(opped_members);
1025 * by Carlo Wood (Run), 05 Oct 1998.
1029 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1030 * When the user name or host name are too long (USERLEN and HOSTLEN
1031 * respectively) then they are cut off at the start with a '*'.
1033 * The following transformations are made:
1035 * 1) xxx -> nick!*@*
1036 * 2) xxx.xxx -> *!*@host
1037 * 3) xxx!yyy -> nick!user@*
1038 * 4) xxx@yyy -> *!user@host
1039 * 5) xxx!yyy@zzz -> nick!user@host
1041 char *pretty_mask(char *mask)
1043 static char star[2] = { '*', 0 };
1044 static char retmask[NUH_BUFSIZE];
1045 char *last_dot = NULL;
1048 /* Case 1: default */
1053 /* Do a _single_ pass through the characters of the mask: */
1054 for (ptr = mask; *ptr; ++ptr)
1058 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1062 else if (*ptr == '@')
1064 /* Case 4: Found last '@' (without finding a '!' yet) */
1069 else if (*ptr == '.')
1071 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1081 /* Case 4 or 5: Found last '@' */
1087 if (user == star && last_dot)
1097 char *nick_end = (user != star) ? user - 1 : ptr;
1098 if (nick_end - nick > NICKLEN)
1104 char *user_end = (host != star) ? host - 1 : ptr;
1105 if (user_end - user > USERLEN)
1107 user = user_end - USERLEN;
1112 if (host != star && ptr - host > HOSTLEN)
1114 host = ptr - HOSTLEN;
1117 return make_nick_user_host(retmask, nick, user, host);
1120 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1127 for (lp = chptr->banlist; lp; lp = lp->next)
1128 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1129 lp->value.ban.who, lp->value.ban.when);
1131 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1134 /* We are now treating the <key> part of /join <channel list> <key> as a key
1135 * ring; that is, we try one key against the actual channel key, and if that
1136 * doesn't work, we try the next one, and so on. -Kev -Texaco
1137 * Returns: 0 on match, 1 otherwise
1138 * This version contributed by SeKs <intru@info.polymtl.ca>
1140 static int compall(char *key, char *keyring)
1145 p1 = key; /* point to the key... */
1146 while (*p1 && *p1 == *keyring)
1147 { /* step through the key and ring until they
1153 if (!*p1 && (!*keyring || *keyring == ','))
1154 /* ok, if we're at the end of the and also at the end of one of the keys
1155 in the keyring, we have a match */
1158 if (!*keyring) /* if we're at the end of the key ring, there
1159 weren't any matches, so we return 1 */
1162 /* Not at the end of the key ring, so step
1163 through to the next key in the ring: */
1164 while (*keyring && *(keyring++) != ',');
1166 goto top; /* and check it against the key */
1169 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1172 int overrideJoin = 0;
1175 * Now a banned user CAN join if invited -- Nemesi
1176 * Now a user CAN escape channel limit if invited -- bfriendly
1177 * Now a user CAN escape anything if invited -- Isomer
1180 for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1181 if (lp->value.chptr == 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) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1347 SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1349 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1350 chptr->creationtime > args->min_time &&
1351 chptr->creationtime < args->max_time &&
1352 (!args->topic_limits || (*chptr->topic &&
1353 chptr->topic_time > args->min_topic_time &&
1354 chptr->topic_time < args->max_topic_time)))
1356 if (ShowChannel(cptr,chptr))
1357 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1359 chptr = chptr->next;
1365 MyFree(cli_listing(cptr));
1366 cli_listing(cptr) = NULL;
1367 send_reply(cptr, RPL_LISTEND);
1373 (cli_listing(cptr))->chptr = chptr;
1374 chptr->mode.mode |= MODE_LISTED;
1387 * X --a--> A --b--> B --d--> D
1391 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1392 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1394 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1395 * Remove the user immediately when no users are left on the channel.
1396 * b) On server B : remove the user (who/lp) from the channel, send a
1397 * PART upstream (to A) and pass on the KICK.
1398 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1399 * channel, and pass on the KICK.
1400 * d) On server D : remove the user (who/lp) from the channel, and pass on
1404 * - Setting the ZOMBIE flag never hurts, we either remove the
1405 * client after that or we don't.
1406 * - The KICK message was already passed on, as should be in all cases.
1407 * - `who' is removed in all cases except case a) when users are left.
1408 * - A PART is only sent upstream in case b).
1414 * 1 --- 2 --- 3 --- 4 --- 5
1418 * We also need to turn 'who' into a zombie on servers 1 and 6,
1419 * because a KICK from 'who' (kicking someone else in that direction)
1420 * can arrive there afterwards - which should not be bounced itself.
1421 * Therefore case a) also applies for servers 1 and 6.
1425 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1426 struct Client* sptr, struct Channel* chptr)
1428 assert(0 != member);
1433 /* Default for case a): */
1436 /* Case b) or c) ?: */
1437 if (MyUser(who)) /* server 4 */
1439 if (IsServer(cptr)) /* Case b) ? */
1440 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1441 remove_user_from_channel(who, chptr);
1444 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1446 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1447 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1448 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1450 remove_user_from_channel(who, chptr);
1455 /* Case a) (servers 1, 2, 3 and 6) */
1456 if (channel_all_zombies(chptr))
1457 remove_user_from_channel(who, chptr);
1459 /* XXX Can't actually call Debug here; if the channel is all zombies,
1460 * chptr will no longer exist when we get here.
1461 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1465 int number_of_zombies(struct Channel *chptr)
1467 struct Membership* member;
1471 for (member = chptr->members; member; member = member->next_member) {
1472 if (IsZombie(member))
1479 * This helper function builds an argument string in strptr, consisting
1480 * of the original string, a space, and str1 and str2 concatenated (if,
1481 * of course, str2 is not NULL)
1484 build_string(char *strptr, int *strptr_i, const char *str1,
1485 const char *str2, char c)
1488 strptr[(*strptr_i)++] = c;
1491 strptr[(*strptr_i)++] = *(str1++);
1495 strptr[(*strptr_i)++] = *(str2++);
1497 strptr[(*strptr_i)] = '\0';
1501 * This is the workhorse of our ModeBuf suite; this actually generates the
1502 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1505 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1507 /* we only need the flags that don't take args right now */
1508 static int flags[] = {
1509 /* MODE_CHANOP, 'o', */
1510 /* MODE_VOICE, 'v', */
1513 MODE_MODERATED, 'm',
1514 MODE_TOPICLIMIT, 't',
1515 MODE_INVITEONLY, 'i',
1516 MODE_NOPRIVMSGS, 'n',
1519 MODE_WASDELJOINS, 'd',
1520 /* MODE_KEY, 'k', */
1521 /* MODE_BAN, 'b', */
1522 /* MODE_LIMIT, 'l', */
1523 /* MODE_APASS, 'A', */
1524 /* MODE_UPASS, 'u', */
1530 struct Client *app_source; /* where the MODE appears to come from */
1532 char addbuf[20]; /* accumulates +psmtin, etc. */
1534 char rembuf[20]; /* accumulates -psmtin, etc. */
1536 char *bufptr; /* we make use of indirection to simplify the code */
1539 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1541 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1543 char *strptr; /* more indirection to simplify the code */
1546 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1549 char limitbuf[20]; /* convert limits to strings */
1551 unsigned int limitdel = MODE_LIMIT;
1555 /* If the ModeBuf is empty, we have nothing to do */
1556 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1559 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1561 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1564 app_source = mbuf->mb_source;
1567 * Account for user we're bouncing; we have to get it in on the first
1568 * bounced MODE, or we could have problems
1570 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1571 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1573 /* Calculate the simple flags */
1574 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1575 if (*flag_p & mbuf->mb_add)
1576 addbuf[addbuf_i++] = flag_p[1];
1577 else if (*flag_p & mbuf->mb_rem)
1578 rembuf[rembuf_i++] = flag_p[1];
1581 /* Now go through the modes with arguments... */
1582 for (i = 0; i < mbuf->mb_count; i++) {
1583 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1585 bufptr_i = &addbuf_i;
1588 bufptr_i = &rembuf_i;
1591 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1592 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1594 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1595 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1597 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1598 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1600 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1601 tmp = strlen(MB_STRING(mbuf, i));
1603 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1604 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1607 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1619 bufptr[(*bufptr_i)++] = mode_char;
1620 totalbuflen -= tmp + 1;
1622 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1623 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1624 strlen(MB_STRING(mbuf, i)));
1626 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1627 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1629 bufptr[(*bufptr_i)++] = 'k';
1630 totalbuflen -= tmp + 1;
1632 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1633 /* if it's a limit, we also format the number */
1634 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1636 tmp = strlen(limitbuf);
1638 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1639 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1641 bufptr[(*bufptr_i)++] = 'l';
1642 totalbuflen -= tmp + 1;
1647 /* terminate the mode strings */
1648 addbuf[addbuf_i] = '\0';
1649 rembuf[rembuf_i] = '\0';
1651 /* If we're building a user visible MODE or HACK... */
1652 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1653 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1654 MODEBUF_DEST_LOG)) {
1655 /* Set up the parameter strings */
1661 for (i = 0; i < mbuf->mb_count; i++) {
1662 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1665 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1667 strptr_i = &addstr_i;
1670 strptr_i = &remstr_i;
1673 /* deal with clients... */
1674 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1675 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1677 /* deal with bans... */
1678 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1679 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1681 /* deal with keys... */
1682 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1683 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1684 "*" : MB_STRING(mbuf, i), 0, ' ');
1686 /* deal with invisible passwords */
1687 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1688 build_string(strptr, strptr_i, "*", 0, ' ');
1691 * deal with limit; note we cannot include the limit parameter if we're
1694 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1695 (MODE_ADD | MODE_LIMIT))
1696 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1699 /* send the messages off to their destination */
1700 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1701 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1703 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1704 mbuf->mb_source : app_source),
1705 mbuf->mb_channel->chname,
1706 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1707 addbuf, remstr, addstr,
1708 mbuf->mb_channel->creationtime);
1710 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1711 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1712 "%s%s%s%s%s%s [%Tu]",
1713 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1714 mbuf->mb_source : app_source),
1715 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1716 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1717 mbuf->mb_channel->creationtime);
1719 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1720 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1722 #ifdef HEAD_IN_SAND_SNOTICES
1723 cli_name(mbuf->mb_source),
1725 cli_name(app_source),
1727 mbuf->mb_channel->chname,
1728 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1729 addbuf, remstr, addstr,
1730 mbuf->mb_channel->creationtime);
1732 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1733 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1734 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1735 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1736 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1738 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1739 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1740 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1741 rembuf_i ? "-" : "", rembuf,
1742 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1745 /* Now are we supposed to propagate to other servers? */
1746 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1747 /* set up parameter string */
1754 * limit is supressed if we're removing it; we have to figure out which
1755 * direction is the direction for it to be removed, though...
1757 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1759 for (i = 0; i < mbuf->mb_count; i++) {
1760 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1763 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1765 strptr_i = &addstr_i;
1768 strptr_i = &remstr_i;
1771 /* deal with modes that take clients */
1772 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1773 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1775 /* deal with modes that take strings */
1776 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1777 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1780 * deal with the limit. Logic here is complicated; if HACK2 is set,
1781 * we're bouncing the mode, so sense is reversed, and we have to
1782 * include the original limit if it looks like it's being removed
1784 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1785 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1788 /* we were told to deop the source */
1789 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1790 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1791 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1792 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1794 /* mark that we've done this, so we don't do it again */
1795 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1798 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1799 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1800 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1801 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1802 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1803 addbuf, remstr, addstr);
1804 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1806 * If HACK2 was set, we're bouncing; we send the MODE back to the
1807 * connection we got it from with the senses reversed and a TS of 0;
1810 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1811 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1812 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1813 mbuf->mb_channel->creationtime);
1816 * We're propagating a normal MODE command to the rest of the network;
1817 * we send the actual channel TS unless this is a HACK3 or a HACK4
1819 if (IsServer(mbuf->mb_source))
1820 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1821 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1822 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1823 addbuf, remstr, addstr,
1824 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1825 mbuf->mb_channel->creationtime);
1827 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1828 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1829 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1830 addbuf, remstr, addstr);
1834 /* We've drained the ModeBuf... */
1839 /* reinitialize the mode-with-arg slots */
1840 for (i = 0; i < MAXMODEPARAMS; i++) {
1841 /* If we saved any, pack them down */
1842 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1843 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1844 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1846 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1848 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1849 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1851 MB_TYPE(mbuf, i) = 0;
1852 MB_UINT(mbuf, i) = 0;
1855 /* If we're supposed to flush it all, do so--all hail tail recursion */
1856 if (all && mbuf->mb_count)
1857 return modebuf_flush_int(mbuf, 1);
1863 * This routine just initializes a ModeBuf structure with the information
1864 * needed and the options given.
1867 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1868 struct Client *connect, struct Channel *chan, unsigned int dest)
1873 assert(0 != source);
1877 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1881 mbuf->mb_source = source;
1882 mbuf->mb_connect = connect;
1883 mbuf->mb_channel = chan;
1884 mbuf->mb_dest = dest;
1887 /* clear each mode-with-parameter slot */
1888 for (i = 0; i < MAXMODEPARAMS; i++) {
1889 MB_TYPE(mbuf, i) = 0;
1890 MB_UINT(mbuf, i) = 0;
1895 * This routine simply adds modes to be added or deleted; do a binary OR
1896 * with either MODE_ADD or MODE_DEL
1899 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1902 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1904 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1905 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1906 MODE_DELJOINS | MODE_WASDELJOINS);
1908 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1911 if (mode & MODE_ADD) {
1912 mbuf->mb_rem &= ~mode;
1913 mbuf->mb_add |= mode;
1915 mbuf->mb_add &= ~mode;
1916 mbuf->mb_rem |= mode;
1921 * This routine adds a mode to be added or deleted that takes a unsigned
1922 * int parameter; mode may *only* be the relevant mode flag ORed with one
1923 * of MODE_ADD or MODE_DEL
1926 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1929 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1931 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1932 MB_UINT(mbuf, mbuf->mb_count) = uint;
1934 /* when we've reached the maximal count, flush the buffer */
1935 if (++mbuf->mb_count >=
1936 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1937 modebuf_flush_int(mbuf, 0);
1941 * This routine adds a mode to be added or deleted that takes a string
1942 * parameter; mode may *only* be the relevant mode flag ORed with one of
1943 * MODE_ADD or MODE_DEL
1946 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1950 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1952 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1953 MB_STRING(mbuf, mbuf->mb_count) = string;
1955 /* when we've reached the maximal count, flush the buffer */
1956 if (++mbuf->mb_count >=
1957 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1958 modebuf_flush_int(mbuf, 0);
1962 * This routine adds a mode to be added or deleted that takes a client
1963 * parameter; mode may *only* be the relevant mode flag ORed with one of
1964 * MODE_ADD or MODE_DEL
1967 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1968 struct Client *client)
1971 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1973 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1974 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1976 /* when we've reached the maximal count, flush the buffer */
1977 if (++mbuf->mb_count >=
1978 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1979 modebuf_flush_int(mbuf, 0);
1983 * This is the exported binding for modebuf_flush()
1986 modebuf_flush(struct ModeBuf *mbuf)
1988 struct Membership *memb;
1990 /* Check if MODE_WASDELJOINS should be set */
1991 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1992 && (mbuf->mb_rem & MODE_DELJOINS)) {
1993 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
1994 if (IsDelayedJoin(memb)) {
1995 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
1996 mbuf->mb_add |= MODE_WASDELJOINS;
1997 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2003 return modebuf_flush_int(mbuf, 1);
2007 * This extracts the simple modes contained in mbuf
2010 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2012 static int flags[] = {
2013 /* MODE_CHANOP, 'o', */
2014 /* MODE_VOICE, 'v', */
2017 MODE_MODERATED, 'm',
2018 MODE_TOPICLIMIT, 't',
2019 MODE_INVITEONLY, 'i',
2020 MODE_NOPRIVMSGS, 'n',
2024 /* MODE_BAN, 'b', */
2031 int i, bufpos = 0, len;
2033 char *key = 0, limitbuf[20];
2034 char *apass = 0, *upass = 0;
2043 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2044 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2045 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2047 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2048 key = MB_STRING(mbuf, i);
2049 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2050 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2051 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2052 upass = MB_STRING(mbuf, i);
2053 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2054 apass = MB_STRING(mbuf, i);
2061 buf[bufpos++] = '+'; /* start building buffer */
2063 for (flag_p = flags; flag_p[0]; flag_p += 2)
2065 buf[bufpos++] = flag_p[1];
2067 for (i = 0, len = bufpos; i < len; i++) {
2069 build_string(buf, &bufpos, key, 0, ' ');
2070 else if (buf[i] == 'l')
2071 build_string(buf, &bufpos, limitbuf, 0, ' ');
2072 else if (buf[i] == 'u')
2073 build_string(buf, &bufpos, upass, 0, ' ');
2074 else if (buf[i] == 'A')
2075 build_string(buf, &bufpos, apass, 0, ' ');
2084 * Simple function to invalidate bans
2087 mode_ban_invalidate(struct Channel *chan)
2089 struct Membership *member;
2091 for (member = chan->members; member; member = member->next_member)
2092 ClearBanValid(member);
2096 * Simple function to drop invite structures
2099 mode_invite_clear(struct Channel *chan)
2101 while (chan->invites)
2102 del_invite(chan->invites->value.cptr, chan);
2105 /* What we've done for mode_parse so far... */
2106 #define DONE_LIMIT 0x01 /* We've set the limit */
2107 #define DONE_KEY 0x02 /* We've set the key */
2108 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2109 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2110 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2111 #define DONE_UPASS 0x20 /* We've set user pass */
2112 #define DONE_APASS 0x40 /* We've set admin pass */
2115 struct ModeBuf *mbuf;
2116 struct Client *cptr;
2117 struct Client *sptr;
2118 struct Channel *chptr;
2119 struct Membership *member;
2130 struct SLink banlist[MAXPARA];
2133 struct Client *client;
2134 } cli_change[MAXPARA];
2138 * Here's a helper function to deal with sending along "Not oper" or
2139 * "Not member" messages
2142 send_notoper(struct ParseState *state)
2144 if (state->done & DONE_NOTOPER)
2147 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2148 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2150 state->done |= DONE_NOTOPER;
2154 * Helper function to convert limits
2157 mode_parse_limit(struct ParseState *state, int *flag_p)
2159 unsigned int t_limit;
2161 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2162 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2165 if (state->parc <= 0) { /* warn if not enough args */
2166 if (MyUser(state->sptr))
2167 need_more_params(state->sptr, "MODE +l");
2171 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2175 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2176 (!t_limit || t_limit == state->chptr->mode.limit))
2179 t_limit = state->chptr->mode.limit;
2181 /* If they're not an oper, they can't change modes */
2182 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2183 send_notoper(state);
2187 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2189 state->done |= DONE_LIMIT;
2194 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2196 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2197 if (state->dir & MODE_ADD) {
2198 state->chptr->mode.mode |= flag_p[0];
2199 state->chptr->mode.limit = t_limit;
2201 state->chptr->mode.mode &= ~flag_p[0];
2202 state->chptr->mode.limit = 0;
2208 * Helper function to convert keys
2211 mode_parse_key(struct ParseState *state, int *flag_p)
2216 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2219 if (state->parc <= 0) { /* warn if not enough args */
2220 if (MyUser(state->sptr))
2221 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2226 t_str = state->parv[state->args_used++]; /* grab arg */
2230 /* If they're not an oper, they can't change modes */
2231 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2232 send_notoper(state);
2236 if (state->done & DONE_KEY) /* allow key to be set only once */
2238 state->done |= DONE_KEY;
2242 /* clean up the key string */
2244 while (*++s > ' ' && *s != ':' && --t_len)
2248 if (!*t_str) { /* warn if empty */
2249 if (MyUser(state->sptr))
2250 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2258 /* can't add a key if one is set, nor can one remove the wrong key */
2259 if (!(state->flags & MODE_PARSE_FORCE))
2260 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2261 (state->dir == MODE_DEL &&
2262 ircd_strcmp(state->chptr->mode.key, t_str))) {
2263 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2267 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2268 !ircd_strcmp(state->chptr->mode.key, t_str))
2269 return; /* no key change */
2271 if (state->flags & MODE_PARSE_BOUNCE) {
2272 if (*state->chptr->mode.key) /* reset old key */
2273 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2274 state->chptr->mode.key, 0);
2275 else /* remove new bogus key */
2276 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2277 } else /* send new key */
2278 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2280 if (state->flags & MODE_PARSE_SET) {
2281 if (state->dir == MODE_ADD) /* set the new key */
2282 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2283 else /* remove the old key */
2284 *state->chptr->mode.key = '\0';
2289 * Helper function to convert user passes
2292 mode_parse_upass(struct ParseState *state, int *flag_p)
2297 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2300 if (state->parc <= 0) { /* warn if not enough args */
2301 if (MyUser(state->sptr))
2302 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2307 t_str = state->parv[state->args_used++]; /* grab arg */
2311 /* If they're not an oper, they can't change modes */
2312 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2313 send_notoper(state);
2317 /* If they are not the channel manager, they are not allowed to change it */
2318 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2319 if (*state->chptr->mode.apass) {
2320 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2321 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2323 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2324 "Re-create the channel. The channel must be *empty* for",
2325 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2326 "before it can be recreated.");
2331 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2333 state->done |= DONE_UPASS;
2335 t_len = PASSLEN + 1;
2337 /* clean up the upass string */
2339 while (*++s > ' ' && *s != ':' && --t_len)
2343 if (!*t_str) { /* warn if empty */
2344 if (MyUser(state->sptr))
2345 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2353 if (!(state->flags & MODE_PARSE_FORCE))
2354 /* can't add the upass while apass is not set */
2355 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2356 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2359 /* can't add a upass if one is set, nor can one remove the wrong upass */
2360 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2361 (state->dir == MODE_DEL &&
2362 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2363 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2367 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2368 !ircd_strcmp(state->chptr->mode.upass, t_str))
2369 return; /* no upass change */
2371 if (state->flags & MODE_PARSE_BOUNCE) {
2372 if (*state->chptr->mode.upass) /* reset old upass */
2373 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2374 state->chptr->mode.upass, 0);
2375 else /* remove new bogus upass */
2376 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2377 } else /* send new upass */
2378 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2380 if (state->flags & MODE_PARSE_SET) {
2381 if (state->dir == MODE_ADD) /* set the new upass */
2382 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2383 else /* remove the old upass */
2384 *state->chptr->mode.upass = '\0';
2389 * Helper function to convert admin passes
2392 mode_parse_apass(struct ParseState *state, int *flag_p)
2397 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2400 if (state->parc <= 0) { /* warn if not enough args */
2401 if (MyUser(state->sptr))
2402 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2407 t_str = state->parv[state->args_used++]; /* grab arg */
2411 /* If they're not an oper, they can't change modes */
2412 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2413 send_notoper(state);
2417 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2418 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2419 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2423 /* If they are not the channel manager, they are not allowed to change it */
2424 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2425 if (*state->chptr->mode.apass) {
2426 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2427 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2429 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2430 "Re-create the channel. The channel must be *empty* for",
2431 "at least a whole minute", "before it can be recreated.");
2436 if (state->done & DONE_APASS) /* allow apass to be set only once */
2438 state->done |= DONE_APASS;
2440 t_len = PASSLEN + 1;
2442 /* clean up the apass string */
2444 while (*++s > ' ' && *s != ':' && --t_len)
2448 if (!*t_str) { /* warn if empty */
2449 if (MyUser(state->sptr))
2450 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2458 if (!(state->flags & MODE_PARSE_FORCE)) {
2459 /* can't remove the apass while upass is still set */
2460 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2461 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2464 /* can't add an apass if one is set, nor can one remove the wrong apass */
2465 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2466 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2467 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2472 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2473 !ircd_strcmp(state->chptr->mode.apass, t_str))
2474 return; /* no apass change */
2476 if (state->flags & MODE_PARSE_BOUNCE) {
2477 if (*state->chptr->mode.apass) /* reset old apass */
2478 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2479 state->chptr->mode.apass, 0);
2480 else /* remove new bogus apass */
2481 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2482 } else /* send new apass */
2483 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2485 if (state->flags & MODE_PARSE_SET) {
2486 if (state->dir == MODE_ADD) { /* set the new apass */
2487 /* Make it VERY clear to the user that this is a one-time password */
2488 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2489 if (MyUser(state->sptr)) {
2490 send_reply(state->sptr, RPL_APASSWARN,
2491 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2492 "Are you SURE you want to use this as Admin password? ",
2493 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2494 send_reply(state->sptr, RPL_APASSWARN,
2495 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2496 "\" to remove the password and then immediately set a new one. "
2497 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2498 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2499 "Now set the channel user password (+u).");
2501 } else { /* remove the old apass */
2502 *state->chptr->mode.apass = '\0';
2503 if (MyUser(state->sptr))
2504 send_reply(state->sptr, RPL_APASSWARN,
2505 "WARNING: You removed the channel Admin password MODE (+A). ",
2506 "If you would disconnect or leave the channel without setting a new password then you will ",
2507 "not be able to set it again and lose ownership of this channel! ",
2508 "SET A NEW PASSWORD NOW!", "");
2514 * Helper function to convert bans
2517 mode_parse_ban(struct ParseState *state, int *flag_p)
2520 struct SLink *ban, *newban = 0;
2522 if (state->parc <= 0) { /* Not enough args, send ban list */
2523 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2524 send_ban_list(state->sptr, state->chptr);
2525 state->done |= DONE_BANLIST;
2531 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2534 t_str = state->parv[state->args_used++]; /* grab arg */
2538 /* If they're not an oper, they can't change modes */
2539 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2540 send_notoper(state);
2544 if ((s = strchr(t_str, ' ')))
2547 if (!*t_str || *t_str == ':') { /* warn if empty */
2548 if (MyUser(state->sptr))
2549 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2554 t_str = collapse(pretty_mask(t_str));
2556 /* remember the ban for the moment... */
2557 if (state->dir == MODE_ADD) {
2558 newban = state->banlist + (state->numbans++);
2561 DupString(newban->value.ban.banstr, t_str);
2562 newban->value.ban.who = cli_name(state->sptr);
2563 newban->value.ban.when = TStime();
2565 newban->flags = CHFL_BAN | MODE_ADD;
2567 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2568 newban->flags |= CHFL_BAN_IPMASK;
2571 if (!state->chptr->banlist) {
2572 state->chptr->banlist = newban; /* add our ban with its flags */
2573 state->done |= DONE_BANCLEAN;
2577 /* Go through all bans */
2578 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2579 /* first, clean the ban flags up a bit */
2580 if (!(state->done & DONE_BANCLEAN))
2581 /* Note: We're overloading *lots* of bits here; be careful! */
2582 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2586 * MODE_ADD - Ban was added; if we're bouncing modes,
2587 * then we'll remove it below; otherwise,
2588 * we'll have to allocate a real ban
2590 * MODE_DEL - Ban was marked for deletion; if we're
2591 * bouncing modes, we'll have to re-add it,
2592 * otherwise, we'll have to remove it
2594 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2595 * with a ban already set; if we're
2596 * bouncing modes, we'll have to bounce
2597 * this one; otherwise, we'll just ignore
2598 * it when we process added bans
2601 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2602 ban->flags |= MODE_DEL; /* delete one ban */
2604 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2606 } else if (state->dir == MODE_ADD) {
2607 /* if the ban already exists, don't worry about it */
2608 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2609 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2610 MyFree(newban->value.ban.banstr); /* stopper a leak */
2611 state->numbans--; /* deallocate last ban */
2612 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2614 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2615 if (!(ban->flags & MODE_DEL))
2616 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2617 } else if (!mmatch(t_str, ban->value.ban.banstr))
2618 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2620 if (!ban->next && (newban->flags & MODE_ADD))
2622 ban->next = newban; /* add our ban with its flags */
2623 break; /* get out of loop */
2627 state->done |= DONE_BANCLEAN;
2631 * This is the bottom half of the ban processor
2634 mode_process_bans(struct ParseState *state)
2636 struct SLink *ban, *newban, *prevban, *nextban;
2642 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2644 banlen = strlen(ban->value.ban.banstr);
2646 nextban = ban->next;
2648 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2650 prevban->next = 0; /* Break the list; ban isn't a real ban */
2652 state->chptr->banlist = 0;
2657 MyFree(ban->value.ban.banstr);
2660 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2661 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2662 ban->value.ban.banstr,
2663 state->flags & MODE_PARSE_SET);
2665 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2666 if (prevban) /* clip it out of the list... */
2667 prevban->next = ban->next;
2669 state->chptr->banlist = ban->next;
2674 MyFree(ban->value.ban.who);
2678 continue; /* next ban; keep prevban like it is */
2680 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2681 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2683 prevban->next = 0; /* Break the list; ban isn't a real ban */
2685 state->chptr->banlist = 0;
2687 /* If we're supposed to ignore it, do so. */
2688 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2689 !(state->flags & MODE_PARSE_BOUNCE)) {
2693 MyFree(ban->value.ban.banstr);
2695 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2696 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2697 count > feature_int(FEAT_MAXBANS))) {
2698 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2699 ban->value.ban.banstr);
2703 MyFree(ban->value.ban.banstr);
2705 /* add the ban to the buffer */
2706 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2707 ban->value.ban.banstr,
2708 !(state->flags & MODE_PARSE_SET));
2710 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2711 newban = make_link();
2712 newban->value.ban.banstr = ban->value.ban.banstr;
2713 DupString(newban->value.ban.who, ban->value.ban.who);
2714 newban->value.ban.when = ban->value.ban.when;
2715 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2717 newban->next = state->chptr->banlist; /* and link it in */
2718 state->chptr->banlist = newban;
2727 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2729 if (changed) /* if we changed the ban list, we must invalidate the bans */
2730 mode_ban_invalidate(state->chptr);
2734 * Helper function to process client changes
2737 mode_parse_client(struct ParseState *state, int *flag_p)
2740 struct Client *acptr;
2743 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2746 if (state->parc <= 0) /* return if not enough args */
2749 t_str = state->parv[state->args_used++]; /* grab arg */
2753 /* If they're not an oper, they can't change modes */
2754 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2755 send_notoper(state);
2759 if (MyUser(state->sptr)) /* find client we're manipulating */
2760 acptr = find_chasing(state->sptr, t_str, NULL);
2762 acptr = findNUser(t_str);
2765 return; /* find_chasing() already reported an error to the user */
2767 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2768 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2769 state->cli_change[i].flag & flag_p[0]))
2770 break; /* found a slot */
2772 /* Store what we're doing to them */
2773 state->cli_change[i].flag = state->dir | flag_p[0];
2774 state->cli_change[i].client = acptr;
2778 * Helper function to process the changed client list
2781 mode_process_clients(struct ParseState *state)
2784 struct Membership *member;
2786 for (i = 0; state->cli_change[i].flag; i++) {
2787 assert(0 != state->cli_change[i].client);
2789 /* look up member link */
2790 if (!(member = find_member_link(state->chptr,
2791 state->cli_change[i].client)) ||
2792 (MyUser(state->sptr) && IsZombie(member))) {
2793 if (MyUser(state->sptr))
2794 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2795 cli_name(state->cli_change[i].client),
2796 state->chptr->chname);
2800 if ((state->cli_change[i].flag & MODE_ADD &&
2801 (state->cli_change[i].flag & member->status)) ||
2802 (state->cli_change[i].flag & MODE_DEL &&
2803 !(state->cli_change[i].flag & member->status)))
2804 continue; /* no change made, don't do anything */
2806 /* see if the deop is allowed */
2807 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2808 (MODE_DEL | MODE_CHANOP)) {
2809 /* prevent +k users from being deopped */
2810 if (IsChannelService(state->cli_change[i].client)) {
2811 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2812 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2814 (IsServer(state->sptr) ? cli_name(state->sptr) :
2815 cli_name((cli_user(state->sptr))->server)));
2817 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2818 send_reply(state->sptr, ERR_ISCHANSERVICE,
2819 cli_name(state->cli_change[i].client),
2820 state->chptr->chname);
2825 /* check deop for local user */
2826 if (MyUser(state->sptr)) {
2828 /* don't allow local opers to be deopped on local channels */
2829 if (MyUser(state->sptr) &&
2830 state->cli_change[i].client != state->sptr &&
2831 IsLocalChannel(state->chptr->chname) &&
2832 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2833 send_reply(state->sptr, ERR_ISOPERLCHAN,
2834 cli_name(state->cli_change[i].client),
2835 state->chptr->chname);
2839 if (feature_bool(FEAT_OPLEVELS)) {
2840 /* don't allow to deop members with an op level that is <= our own level */
2841 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2843 && OpLevel(member) <= OpLevel(state->member)) {
2844 int equal = (OpLevel(member) == OpLevel(state->member));
2845 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2846 cli_name(state->cli_change[i].client),
2847 state->chptr->chname,
2848 OpLevel(state->member), OpLevel(member),
2849 "deop", equal ? "the same" : "a higher");
2856 /* set op-level of member being opped */
2857 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2858 (MODE_ADD | MODE_CHANOP)) {
2859 /* If on a channel with upass set, someone with level x gives ops to someone else,
2860 then that person gets level x-1. On other channels, where upass is not set,
2861 the level stays the same. */
2862 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2863 /* Someone being opped by a server gets op-level 0 */
2864 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2865 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2868 /* actually effect the change */
2869 if (state->flags & MODE_PARSE_SET) {
2870 if (state->cli_change[i].flag & MODE_ADD) {
2871 if (IsDelayedJoin(member))
2872 RevealDelayedJoin(member);
2873 member->status |= (state->cli_change[i].flag &
2874 (MODE_CHANOP | MODE_VOICE));
2875 if (state->cli_change[i].flag & MODE_CHANOP)
2876 ClearDeopped(member);
2878 member->status &= ~(state->cli_change[i].flag &
2879 (MODE_CHANOP | MODE_VOICE));
2882 /* accumulate the change */
2883 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2884 state->cli_change[i].client);
2885 } /* for (i = 0; state->cli_change[i].flags; i++) */
2889 * Helper function to process the simple modes
2892 mode_parse_mode(struct ParseState *state, int *flag_p)
2894 /* If they're not an oper, they can't change modes */
2895 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2896 send_notoper(state);
2903 if (state->dir == MODE_ADD) {
2904 state->add |= flag_p[0];
2905 state->del &= ~flag_p[0];
2907 if (flag_p[0] & MODE_SECRET) {
2908 state->add &= ~MODE_PRIVATE;
2909 state->del |= MODE_PRIVATE;
2910 } else if (flag_p[0] & MODE_PRIVATE) {
2911 state->add &= ~MODE_SECRET;
2912 state->del |= MODE_SECRET;
2914 if (flag_p[0] & MODE_DELJOINS) {
2915 state->add &= ~MODE_WASDELJOINS;
2916 state->del |= MODE_WASDELJOINS;
2919 state->add &= ~flag_p[0];
2920 state->del |= flag_p[0];
2923 assert(0 == (state->add & state->del));
2924 assert((MODE_SECRET | MODE_PRIVATE) !=
2925 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2929 * This routine is intended to parse MODE or OPMODE commands and effect the
2930 * changes (or just build the bounce buffer). We pass the starting offset
2934 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2935 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2936 struct Membership* member)
2938 static int chan_flags[] = {
2943 MODE_MODERATED, 'm',
2944 MODE_TOPICLIMIT, 't',
2945 MODE_INVITEONLY, 'i',
2946 MODE_NOPRIVMSGS, 'n',
2960 unsigned int t_mode;
2962 struct ParseState state;
2973 state.chptr = chptr;
2974 state.member = member;
2977 state.flags = flags;
2978 state.dir = MODE_ADD;
2982 state.args_used = 0;
2983 state.max_args = MAXMODEPARAMS;
2986 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2987 state.banlist[i].next = 0;
2988 state.banlist[i].value.ban.banstr = 0;
2989 state.banlist[i].value.ban.who = 0;
2990 state.banlist[i].value.ban.when = 0;
2991 state.banlist[i].flags = 0;
2992 state.cli_change[i].flag = 0;
2993 state.cli_change[i].client = 0;
2996 modestr = state.parv[state.args_used++];
3000 for (; *modestr; modestr++) {
3001 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3002 if (flag_p[1] == *modestr)
3005 if (!flag_p[0]) { /* didn't find it? complain and continue */
3006 if (MyUser(state.sptr))
3007 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3012 case '+': /* switch direction to MODE_ADD */
3013 case '-': /* switch direction to MODE_DEL */
3014 state.dir = flag_p[0];
3017 case 'l': /* deal with limits */
3018 mode_parse_limit(&state, flag_p);
3021 case 'k': /* deal with keys */
3022 mode_parse_key(&state, flag_p);
3025 case 'A': /* deal with Admin passes */
3026 if (feature_bool(FEAT_OPLEVELS))
3027 mode_parse_apass(&state, flag_p);
3030 case 'u': /* deal with user passes */
3031 if (feature_bool(FEAT_OPLEVELS))
3032 mode_parse_upass(&state, flag_p);
3035 case 'b': /* deal with bans */
3036 mode_parse_ban(&state, flag_p);
3039 case 'o': /* deal with ops/voice */
3041 mode_parse_client(&state, flag_p);
3044 default: /* deal with other modes */
3045 mode_parse_mode(&state, flag_p);
3047 } /* switch (*modestr) */
3048 } /* for (; *modestr; modestr++) */
3050 if (state.flags & MODE_PARSE_BURST)
3051 break; /* don't interpret any more arguments */
3053 if (state.parc > 0) { /* process next argument in string */
3054 modestr = state.parv[state.args_used++];
3058 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3061 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3062 break; /* we're then going to bounce the mode! */
3064 recv_ts = atoi(modestr);
3066 if (recv_ts && recv_ts < state.chptr->creationtime)
3067 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3069 break; /* break out of while loop */
3070 } else if (state.flags & MODE_PARSE_STRICT ||
3071 (MyUser(state.sptr) && state.max_args <= 0)) {
3072 state.parc++; /* we didn't actually gobble the argument */
3074 break; /* break out of while loop */
3077 } /* while (*modestr) */
3080 * the rest of the function finishes building resultant MODEs; if the
3081 * origin isn't a member or an oper, skip it.
3083 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3084 return state.args_used; /* tell our parent how many args we gobbled */
3086 t_mode = state.chptr->mode.mode;
3088 if (state.del & t_mode) { /* delete any modes to be deleted... */
3089 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3091 t_mode &= ~state.del;
3093 if (state.add & ~t_mode) { /* add any modes to be added... */
3094 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3096 t_mode |= state.add;
3099 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3100 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3101 !(t_mode & MODE_INVITEONLY))
3102 mode_invite_clear(state.chptr);
3104 state.chptr->mode.mode = t_mode;
3107 if (state.flags & MODE_PARSE_WIPEOUT) {
3108 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3109 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3110 state.chptr->mode.limit);
3111 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3112 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3113 state.chptr->mode.key, 0);
3114 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3115 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3116 state.chptr->mode.upass, 0);
3117 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3118 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3119 state.chptr->mode.apass, 0);
3122 if (state.done & DONE_BANCLEAN) /* process bans */
3123 mode_process_bans(&state);
3125 /* process client changes */
3126 if (state.cli_change[0].flag)
3127 mode_process_clients(&state);
3129 return state.args_used; /* tell our parent how many args we gobbled */
3133 * Initialize a join buffer
3136 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3137 struct Client *connect, unsigned int type, char *comment,
3143 assert(0 != source);
3144 assert(0 != connect);
3146 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3147 jbuf->jb_connect = connect;
3148 jbuf->jb_type = type;
3149 jbuf->jb_comment = comment;
3150 jbuf->jb_create = create;
3152 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3153 type == JOINBUF_TYPE_PART ||
3154 type == JOINBUF_TYPE_PARTALL) ?
3155 STARTJOINLEN : STARTCREATELEN) +
3156 (comment ? strlen(comment) + 2 : 0));
3158 for (i = 0; i < MAXJOINARGS; i++)
3159 jbuf->jb_channels[i] = 0;
3163 * Add a channel to the join buffer
3166 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3174 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3175 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3180 is_local = IsLocalChannel(chan->chname);
3182 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3183 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3184 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3185 if (IsUserParting(member))
3187 SetUserParting(member);
3189 /* Send notification to channel */
3190 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3191 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3192 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3193 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3194 else if (MyUser(jbuf->jb_source))
3195 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3196 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3197 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3198 /* XXX: Shouldn't we send a PART here anyway? */
3199 /* to users on the channel? Why? From their POV, the user isn't on
3200 * the channel anymore anyway. We don't send to servers until below,
3201 * when we gang all the channel parts together. Note that this is
3202 * exactly the same logic, albeit somewhat more concise, as was in
3203 * the original m_part.c */
3205 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3206 is_local) /* got to remove user here */
3207 remove_user_from_channel(jbuf->jb_source, chan);
3209 /* Add user to channel */
3210 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3211 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3213 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3215 /* send notification to all servers */
3216 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3217 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3218 "%H %Tu", chan, chan->creationtime);
3220 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3221 /* Send the notification to the channel */
3222 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, "%H", chan);
3224 /* send an op, too, if needed */
3225 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3226 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3227 chan, jbuf->jb_source);
3228 } else if (MyUser(jbuf->jb_source))
3229 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3232 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3233 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3234 return; /* don't send to remote */
3236 /* figure out if channel name will cause buffer to be overflowed */
3237 len = chan ? strlen(chan->chname) + 1 : 2;
3238 if (jbuf->jb_strlen + len > BUFSIZE)
3239 joinbuf_flush(jbuf);
3241 /* add channel to list of channels to send and update counts */
3242 jbuf->jb_channels[jbuf->jb_count++] = chan;
3243 jbuf->jb_strlen += len;
3245 /* if we've used up all slots, flush */
3246 if (jbuf->jb_count >= MAXJOINARGS)
3247 joinbuf_flush(jbuf);
3251 * Flush the channel list to remote servers
3254 joinbuf_flush(struct JoinBuf *jbuf)
3256 char chanlist[BUFSIZE];
3260 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3261 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3262 return 0; /* no joins to process */
3264 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3265 build_string(chanlist, &chanlist_i,
3266 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3267 i == 0 ? '\0' : ',');
3268 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3269 /* Remove user from channel */
3270 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3272 jbuf->jb_channels[i] = 0; /* mark slot empty */
3275 jbuf->jb_count = 0; /* reset base counters */
3276 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3277 STARTJOINLEN : STARTCREATELEN) +
3278 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3280 /* and send the appropriate command */
3281 switch (jbuf->jb_type) {
3282 case JOINBUF_TYPE_CREATE:
3283 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3284 "%s %Tu", chanlist, jbuf->jb_create);
3287 case JOINBUF_TYPE_PART:
3288 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3289 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3297 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3298 int IsInvited(struct Client* cptr, const void* chptr)
3302 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3303 if (lp->value.chptr == chptr)
3308 /* RevealDelayedJoin: sends a join for a hidden user */
3310 void RevealDelayedJoin(struct Membership *member) {
3311 ClearDelayedJoin(member);
3312 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, ":%H",
3314 CheckDelayedJoins(member->channel);
3317 /* CheckDelayedJoins: checks and clear +d if necessary */
3319 void CheckDelayedJoins(struct Channel *chan) {
3320 struct Membership *memb2;
3322 if (chan->mode.mode & MODE_WASDELJOINS) {
3323 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3324 if (IsDelayedJoin(memb2))
3329 chan->mode.mode &= ~MODE_WASDELJOINS;
3330 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL,