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);
1020 if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1021 sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1022 chptr->creationtime, chptr->topic_time, chptr->topic);
1028 * by Carlo Wood (Run), 05 Oct 1998.
1032 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1033 * When the user name or host name are too long (USERLEN and HOSTLEN
1034 * respectively) then they are cut off at the start with a '*'.
1036 * The following transformations are made:
1038 * 1) xxx -> nick!*@*
1039 * 2) xxx.xxx -> *!*@host
1040 * 3) xxx!yyy -> nick!user@*
1041 * 4) xxx@yyy -> *!user@host
1042 * 5) xxx!yyy@zzz -> nick!user@host
1044 char *pretty_mask(char *mask)
1046 static char star[2] = { '*', 0 };
1047 static char retmask[NUH_BUFSIZE];
1048 char *last_dot = NULL;
1051 /* Case 1: default */
1056 /* Do a _single_ pass through the characters of the mask: */
1057 for (ptr = mask; *ptr; ++ptr)
1061 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1065 else if (*ptr == '@')
1067 /* Case 4: Found last '@' (without finding a '!' yet) */
1072 else if (*ptr == '.')
1074 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1084 /* Case 4 or 5: Found last '@' */
1090 if (user == star && last_dot)
1100 char *nick_end = (user != star) ? user - 1 : ptr;
1101 if (nick_end - nick > NICKLEN)
1107 char *user_end = (host != star) ? host - 1 : ptr;
1108 if (user_end - user > USERLEN)
1110 user = user_end - USERLEN;
1115 if (host != star && ptr - host > HOSTLEN)
1117 host = ptr - HOSTLEN;
1120 return make_nick_user_host(retmask, nick, user, host);
1123 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1130 for (lp = chptr->banlist; lp; lp = lp->next)
1131 send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1132 lp->value.ban.who, lp->value.ban.when);
1134 send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1137 /* We are now treating the <key> part of /join <channel list> <key> as a key
1138 * ring; that is, we try one key against the actual channel key, and if that
1139 * doesn't work, we try the next one, and so on. -Kev -Texaco
1140 * Returns: 0 on match, 1 otherwise
1141 * This version contributed by SeKs <intru@info.polymtl.ca>
1143 static int compall(char *key, char *keyring)
1148 p1 = key; /* point to the key... */
1149 while (*p1 && *p1 == *keyring)
1150 { /* step through the key and ring until they
1156 if (!*p1 && (!*keyring || *keyring == ','))
1157 /* ok, if we're at the end of the and also at the end of one of the keys
1158 in the keyring, we have a match */
1161 if (!*keyring) /* if we're at the end of the key ring, there
1162 weren't any matches, so we return 1 */
1165 /* Not at the end of the key ring, so step
1166 through to the next key in the ring: */
1167 while (*keyring && *(keyring++) != ',');
1169 goto top; /* and check it against the key */
1172 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1175 int overrideJoin = 0;
1178 * Now a banned user CAN join if invited -- Nemesi
1179 * Now a user CAN escape channel limit if invited -- bfriendly
1180 * Now a user CAN escape anything if invited -- Isomer
1183 for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1184 if (lp->value.chptr == chptr)
1187 /* An oper can force a join on a local channel using "OVERRIDE" as the key.
1188 a HACK(4) notice will be sent if he would not have been supposed
1189 to join normally. */
1190 if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1191 !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1192 compall("OVERRIDE",key) == 0)
1193 overrideJoin = MAGIC_OPER_OVERRIDE;
1195 if (chptr->mode.mode & MODE_INVITEONLY)
1196 return overrideJoin + ERR_INVITEONLYCHAN;
1198 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1199 return overrideJoin + ERR_CHANNELISFULL;
1201 if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1202 return overrideJoin + ERR_NEEDREGGEDNICK;
1204 if (is_banned(sptr, chptr, NULL))
1205 return overrideJoin + ERR_BANNEDFROMCHAN;
1208 * now using compall (above) to test against a whole key ring -Kev
1210 if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1211 return overrideJoin + ERR_BADCHANNELKEY;
1214 return ERR_DONTCHEAT;
1220 * Remove bells and commas from channel name
1222 void clean_channelname(char *cn)
1226 for (i = 0; cn[i]; i++) {
1227 if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1231 if (IsChannelLower(cn[i])) {
1232 cn[i] = ToLower(cn[i]);
1238 if ((unsigned char)(cn[i]) == 0xd0)
1239 cn[i] = (char) 0xf0;
1246 * Get Channel block for i (and allocate a new channel
1247 * block, if it didn't exists before).
1249 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1251 struct Channel *chptr;
1254 if (EmptyString(chname))
1257 len = strlen(chname);
1258 if (MyUser(cptr) && len > CHANNELLEN)
1261 *(chname + CHANNELLEN) = '\0';
1263 if ((chptr = FindChannel(chname)))
1265 if (flag == CGT_CREATE)
1267 chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1269 ++UserStats.channels;
1270 memset(chptr, 0, sizeof(struct Channel));
1271 strcpy(chptr->chname, chname);
1272 if (GlobalChannelList)
1273 GlobalChannelList->prev = chptr;
1275 chptr->next = GlobalChannelList;
1276 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1277 GlobalChannelList = chptr;
1283 void add_invite(struct Client *cptr, struct Channel *chptr)
1285 struct SLink *inv, **tmp;
1287 del_invite(cptr, chptr);
1289 * Delete last link in chain if the list is max length
1291 assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1292 if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1293 del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1295 * Add client to channel invite list
1298 inv->value.cptr = cptr;
1299 inv->next = chptr->invites;
1300 chptr->invites = inv;
1302 * Add channel to the end of the client invite list
1304 for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1306 inv->value.chptr = chptr;
1309 (cli_user(cptr))->invites++;
1313 * Delete Invite block from channel invite list and client invite list
1315 void del_invite(struct Client *cptr, struct Channel *chptr)
1317 struct SLink **inv, *tmp;
1319 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1320 if (tmp->value.cptr == cptr)
1325 (cli_user(cptr))->invites--;
1329 for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1330 if (tmp->value.chptr == chptr)
1339 /* List and skip all channels that are listen */
1340 void list_next_channels(struct Client *cptr, int nr)
1342 struct ListingArgs *args = cli_listing(cptr);
1343 struct Channel *chptr = args->chptr;
1344 chptr->mode.mode &= ~MODE_LISTED;
1345 while (is_listed(chptr) || --nr >= 0)
1347 for (; chptr; chptr = chptr->next)
1349 if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) &&
1350 SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1352 if (chptr->users > args->min_users && chptr->users < args->max_users &&
1353 chptr->creationtime > args->min_time &&
1354 chptr->creationtime < args->max_time &&
1355 (!args->topic_limits || (*chptr->topic &&
1356 chptr->topic_time > args->min_topic_time &&
1357 chptr->topic_time < args->max_topic_time)))
1359 if (ShowChannel(cptr,chptr))
1360 send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1362 chptr = chptr->next;
1368 MyFree(cli_listing(cptr));
1369 cli_listing(cptr) = NULL;
1370 send_reply(cptr, RPL_LISTEND);
1376 (cli_listing(cptr))->chptr = chptr;
1377 chptr->mode.mode |= MODE_LISTED;
1390 * X --a--> A --b--> B --d--> D
1394 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1395 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1397 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1398 * Remove the user immediately when no users are left on the channel.
1399 * b) On server B : remove the user (who/lp) from the channel, send a
1400 * PART upstream (to A) and pass on the KICK.
1401 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1402 * channel, and pass on the KICK.
1403 * d) On server D : remove the user (who/lp) from the channel, and pass on
1407 * - Setting the ZOMBIE flag never hurts, we either remove the
1408 * client after that or we don't.
1409 * - The KICK message was already passed on, as should be in all cases.
1410 * - `who' is removed in all cases except case a) when users are left.
1411 * - A PART is only sent upstream in case b).
1417 * 1 --- 2 --- 3 --- 4 --- 5
1421 * We also need to turn 'who' into a zombie on servers 1 and 6,
1422 * because a KICK from 'who' (kicking someone else in that direction)
1423 * can arrive there afterwards - which should not be bounced itself.
1424 * Therefore case a) also applies for servers 1 and 6.
1428 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1429 struct Client* sptr, struct Channel* chptr)
1431 assert(0 != member);
1436 /* Default for case a): */
1439 /* Case b) or c) ?: */
1440 if (MyUser(who)) /* server 4 */
1442 if (IsServer(cptr)) /* Case b) ? */
1443 sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1444 remove_user_from_channel(who, chptr);
1447 if (cli_from(who) == cptr) /* True on servers 1, 5 and 6 */
1449 struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1450 for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1451 if (acptr == (cli_user(who))->server) /* Case d) (server 5) */
1453 remove_user_from_channel(who, chptr);
1458 /* Case a) (servers 1, 2, 3 and 6) */
1459 if (channel_all_zombies(chptr))
1460 remove_user_from_channel(who, chptr);
1462 /* XXX Can't actually call Debug here; if the channel is all zombies,
1463 * chptr will no longer exist when we get here.
1464 Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1468 int number_of_zombies(struct Channel *chptr)
1470 struct Membership* member;
1474 for (member = chptr->members; member; member = member->next_member) {
1475 if (IsZombie(member))
1482 * This helper function builds an argument string in strptr, consisting
1483 * of the original string, a space, and str1 and str2 concatenated (if,
1484 * of course, str2 is not NULL)
1487 build_string(char *strptr, int *strptr_i, const char *str1,
1488 const char *str2, char c)
1491 strptr[(*strptr_i)++] = c;
1494 strptr[(*strptr_i)++] = *(str1++);
1498 strptr[(*strptr_i)++] = *(str2++);
1500 strptr[(*strptr_i)] = '\0';
1504 * This is the workhorse of our ModeBuf suite; this actually generates the
1505 * output MODE commands, HACK notices, or whatever. It's pretty complicated.
1508 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1510 /* we only need the flags that don't take args right now */
1511 static int flags[] = {
1512 /* MODE_CHANOP, 'o', */
1513 /* MODE_VOICE, 'v', */
1516 MODE_MODERATED, 'm',
1517 MODE_TOPICLIMIT, 't',
1518 MODE_INVITEONLY, 'i',
1519 MODE_NOPRIVMSGS, 'n',
1522 MODE_WASDELJOINS, 'd',
1523 /* MODE_KEY, 'k', */
1524 /* MODE_BAN, 'b', */
1525 /* MODE_LIMIT, 'l', */
1526 /* MODE_APASS, 'A', */
1527 /* MODE_UPASS, 'u', */
1533 struct Client *app_source; /* where the MODE appears to come from */
1535 char addbuf[20]; /* accumulates +psmtin, etc. */
1537 char rembuf[20]; /* accumulates -psmtin, etc. */
1539 char *bufptr; /* we make use of indirection to simplify the code */
1542 char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1544 char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1546 char *strptr; /* more indirection to simplify the code */
1549 int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1552 char limitbuf[20]; /* convert limits to strings */
1554 unsigned int limitdel = MODE_LIMIT;
1558 /* If the ModeBuf is empty, we have nothing to do */
1559 if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1562 /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1564 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1567 app_source = mbuf->mb_source;
1570 * Account for user we're bouncing; we have to get it in on the first
1571 * bounced MODE, or we could have problems
1573 if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1574 totalbuflen -= 6; /* numeric nick == 5, plus one space */
1576 /* Calculate the simple flags */
1577 for (flag_p = flags; flag_p[0]; flag_p += 2) {
1578 if (*flag_p & mbuf->mb_add)
1579 addbuf[addbuf_i++] = flag_p[1];
1580 else if (*flag_p & mbuf->mb_rem)
1581 rembuf[rembuf_i++] = flag_p[1];
1584 /* Now go through the modes with arguments... */
1585 for (i = 0; i < mbuf->mb_count; i++) {
1586 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1588 bufptr_i = &addbuf_i;
1591 bufptr_i = &rembuf_i;
1594 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1595 tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1597 if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1598 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1600 bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1601 totalbuflen -= IRCD_MAX(5, tmp) + 1;
1603 } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1604 tmp = strlen(MB_STRING(mbuf, i));
1606 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1607 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1610 switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1622 bufptr[(*bufptr_i)++] = mode_char;
1623 totalbuflen -= tmp + 1;
1625 } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1626 tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1627 strlen(MB_STRING(mbuf, i)));
1629 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1630 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1632 bufptr[(*bufptr_i)++] = 'k';
1633 totalbuflen -= tmp + 1;
1635 } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1636 /* if it's a limit, we also format the number */
1637 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1639 tmp = strlen(limitbuf);
1641 if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1642 MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1644 bufptr[(*bufptr_i)++] = 'l';
1645 totalbuflen -= tmp + 1;
1650 /* terminate the mode strings */
1651 addbuf[addbuf_i] = '\0';
1652 rembuf[rembuf_i] = '\0';
1654 /* If we're building a user visible MODE or HACK... */
1655 if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1656 MODEBUF_DEST_HACK3 | MODEBUF_DEST_HACK4 |
1657 MODEBUF_DEST_LOG)) {
1658 /* Set up the parameter strings */
1664 for (i = 0; i < mbuf->mb_count; i++) {
1665 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1668 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1670 strptr_i = &addstr_i;
1673 strptr_i = &remstr_i;
1676 /* deal with clients... */
1677 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1678 build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1680 /* deal with bans... */
1681 else if (MB_TYPE(mbuf, i) & MODE_BAN)
1682 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1684 /* deal with keys... */
1685 else if (MB_TYPE(mbuf, i) & MODE_KEY)
1686 build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1687 "*" : MB_STRING(mbuf, i), 0, ' ');
1689 /* deal with invisible passwords */
1690 else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1691 build_string(strptr, strptr_i, "*", 0, ' ');
1694 * deal with limit; note we cannot include the limit parameter if we're
1697 else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1698 (MODE_ADD | MODE_LIMIT))
1699 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1702 /* send the messages off to their destination */
1703 if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1704 sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1706 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1707 mbuf->mb_source : app_source),
1708 mbuf->mb_channel->chname,
1709 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1710 addbuf, remstr, addstr,
1711 mbuf->mb_channel->creationtime);
1713 if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1714 sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1715 "%s%s%s%s%s%s [%Tu]",
1716 cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1717 mbuf->mb_source : app_source),
1718 mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1719 rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1720 mbuf->mb_channel->creationtime);
1722 if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1723 sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1725 #ifdef HEAD_IN_SAND_SNOTICES
1726 cli_name(mbuf->mb_source),
1728 cli_name(app_source),
1730 mbuf->mb_channel->chname,
1731 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1732 addbuf, remstr, addstr,
1733 mbuf->mb_channel->creationtime);
1735 if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1736 log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1737 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1738 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1739 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1741 if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1742 sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1743 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1744 rembuf_i ? "-" : "", rembuf,
1745 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1748 /* Now are we supposed to propagate to other servers? */
1749 if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1750 /* set up parameter string */
1757 * limit is supressed if we're removing it; we have to figure out which
1758 * direction is the direction for it to be removed, though...
1760 limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1762 for (i = 0; i < mbuf->mb_count; i++) {
1763 if (MB_TYPE(mbuf, i) & MODE_SAVE)
1766 if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1768 strptr_i = &addstr_i;
1771 strptr_i = &remstr_i;
1774 /* deal with modes that take clients */
1775 if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1776 build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1778 /* deal with modes that take strings */
1779 else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1780 build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1783 * deal with the limit. Logic here is complicated; if HACK2 is set,
1784 * we're bouncing the mode, so sense is reversed, and we have to
1785 * include the original limit if it looks like it's being removed
1787 else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1788 build_string(strptr, strptr_i, limitbuf, 0, ' ');
1791 /* we were told to deop the source */
1792 if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1793 addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1794 addbuf[addbuf_i] = '\0'; /* terminate the string... */
1795 build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1797 /* mark that we've done this, so we don't do it again */
1798 mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1801 if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1802 /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1803 sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1804 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1805 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1806 addbuf, remstr, addstr);
1807 } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1809 * If HACK2 was set, we're bouncing; we send the MODE back to the
1810 * connection we got it from with the senses reversed and a TS of 0;
1813 sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1814 mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1815 rembuf_i ? "+" : "", rembuf, addstr, remstr,
1816 mbuf->mb_channel->creationtime);
1819 * We're propagating a normal MODE command to the rest of the network;
1820 * we send the actual channel TS unless this is a HACK3 or a HACK4
1822 if (IsServer(mbuf->mb_source))
1823 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1824 "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1825 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1826 addbuf, remstr, addstr,
1827 (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1828 mbuf->mb_channel->creationtime);
1830 sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1831 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1832 rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1833 addbuf, remstr, addstr);
1837 /* We've drained the ModeBuf... */
1842 /* reinitialize the mode-with-arg slots */
1843 for (i = 0; i < MAXMODEPARAMS; i++) {
1844 /* If we saved any, pack them down */
1845 if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1846 mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1847 MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1849 if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1851 } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1852 MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1854 MB_TYPE(mbuf, i) = 0;
1855 MB_UINT(mbuf, i) = 0;
1858 /* If we're supposed to flush it all, do so--all hail tail recursion */
1859 if (all && mbuf->mb_count)
1860 return modebuf_flush_int(mbuf, 1);
1866 * This routine just initializes a ModeBuf structure with the information
1867 * needed and the options given.
1870 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1871 struct Client *connect, struct Channel *chan, unsigned int dest)
1876 assert(0 != source);
1880 if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1884 mbuf->mb_source = source;
1885 mbuf->mb_connect = connect;
1886 mbuf->mb_channel = chan;
1887 mbuf->mb_dest = dest;
1890 /* clear each mode-with-parameter slot */
1891 for (i = 0; i < MAXMODEPARAMS; i++) {
1892 MB_TYPE(mbuf, i) = 0;
1893 MB_UINT(mbuf, i) = 0;
1898 * This routine simply adds modes to be added or deleted; do a binary OR
1899 * with either MODE_ADD or MODE_DEL
1902 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1905 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1907 mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1908 MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1909 MODE_DELJOINS | MODE_WASDELJOINS);
1911 if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1914 if (mode & MODE_ADD) {
1915 mbuf->mb_rem &= ~mode;
1916 mbuf->mb_add |= mode;
1918 mbuf->mb_add &= ~mode;
1919 mbuf->mb_rem |= mode;
1924 * This routine adds a mode to be added or deleted that takes a unsigned
1925 * int parameter; mode may *only* be the relevant mode flag ORed with one
1926 * of MODE_ADD or MODE_DEL
1929 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1932 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1934 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1935 MB_UINT(mbuf, mbuf->mb_count) = uint;
1937 /* when we've reached the maximal count, flush the buffer */
1938 if (++mbuf->mb_count >=
1939 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1940 modebuf_flush_int(mbuf, 0);
1944 * This routine adds a mode to be added or deleted that takes a string
1945 * parameter; mode may *only* be the relevant mode flag ORed with one of
1946 * MODE_ADD or MODE_DEL
1949 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1953 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1955 MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1956 MB_STRING(mbuf, mbuf->mb_count) = string;
1958 /* when we've reached the maximal count, flush the buffer */
1959 if (++mbuf->mb_count >=
1960 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1961 modebuf_flush_int(mbuf, 0);
1965 * This routine adds a mode to be added or deleted that takes a client
1966 * parameter; mode may *only* be the relevant mode flag ORed with one of
1967 * MODE_ADD or MODE_DEL
1970 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1971 struct Client *client)
1974 assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1976 MB_TYPE(mbuf, mbuf->mb_count) = mode;
1977 MB_CLIENT(mbuf, mbuf->mb_count) = client;
1979 /* when we've reached the maximal count, flush the buffer */
1980 if (++mbuf->mb_count >=
1981 (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1982 modebuf_flush_int(mbuf, 0);
1986 * This is the exported binding for modebuf_flush()
1989 modebuf_flush(struct ModeBuf *mbuf)
1991 struct Membership *memb;
1993 /* Check if MODE_WASDELJOINS should be set */
1994 if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1995 && (mbuf->mb_rem & MODE_DELJOINS)) {
1996 for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
1997 if (IsDelayedJoin(memb)) {
1998 mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
1999 mbuf->mb_add |= MODE_WASDELJOINS;
2000 mbuf->mb_rem &= ~MODE_WASDELJOINS;
2006 return modebuf_flush_int(mbuf, 1);
2010 * This extracts the simple modes contained in mbuf
2013 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2015 static int flags[] = {
2016 /* MODE_CHANOP, 'o', */
2017 /* MODE_VOICE, 'v', */
2020 MODE_MODERATED, 'm',
2021 MODE_TOPICLIMIT, 't',
2022 MODE_INVITEONLY, 'i',
2023 MODE_NOPRIVMSGS, 'n',
2027 /* MODE_BAN, 'b', */
2034 int i, bufpos = 0, len;
2036 char *key = 0, limitbuf[20];
2037 char *apass = 0, *upass = 0;
2046 for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2047 if (MB_TYPE(mbuf, i) & MODE_ADD) {
2048 add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2050 if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2051 key = MB_STRING(mbuf, i);
2052 else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2053 ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2054 else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2055 upass = MB_STRING(mbuf, i);
2056 else if (MB_TYPE(mbuf, i) & MODE_APASS)
2057 apass = MB_STRING(mbuf, i);
2064 buf[bufpos++] = '+'; /* start building buffer */
2066 for (flag_p = flags; flag_p[0]; flag_p += 2)
2068 buf[bufpos++] = flag_p[1];
2070 for (i = 0, len = bufpos; i < len; i++) {
2072 build_string(buf, &bufpos, key, 0, ' ');
2073 else if (buf[i] == 'l')
2074 build_string(buf, &bufpos, limitbuf, 0, ' ');
2075 else if (buf[i] == 'u')
2076 build_string(buf, &bufpos, upass, 0, ' ');
2077 else if (buf[i] == 'A')
2078 build_string(buf, &bufpos, apass, 0, ' ');
2087 * Simple function to invalidate bans
2090 mode_ban_invalidate(struct Channel *chan)
2092 struct Membership *member;
2094 for (member = chan->members; member; member = member->next_member)
2095 ClearBanValid(member);
2099 * Simple function to drop invite structures
2102 mode_invite_clear(struct Channel *chan)
2104 while (chan->invites)
2105 del_invite(chan->invites->value.cptr, chan);
2108 /* What we've done for mode_parse so far... */
2109 #define DONE_LIMIT 0x01 /* We've set the limit */
2110 #define DONE_KEY 0x02 /* We've set the key */
2111 #define DONE_BANLIST 0x04 /* We've sent the ban list */
2112 #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */
2113 #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */
2114 #define DONE_UPASS 0x20 /* We've set user pass */
2115 #define DONE_APASS 0x40 /* We've set admin pass */
2118 struct ModeBuf *mbuf;
2119 struct Client *cptr;
2120 struct Client *sptr;
2121 struct Channel *chptr;
2122 struct Membership *member;
2133 struct SLink banlist[MAXPARA];
2136 struct Client *client;
2137 } cli_change[MAXPARA];
2141 * Here's a helper function to deal with sending along "Not oper" or
2142 * "Not member" messages
2145 send_notoper(struct ParseState *state)
2147 if (state->done & DONE_NOTOPER)
2150 send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2151 ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2153 state->done |= DONE_NOTOPER;
2157 * Helper function to convert limits
2160 mode_parse_limit(struct ParseState *state, int *flag_p)
2162 unsigned int t_limit;
2164 if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2165 if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2168 if (state->parc <= 0) { /* warn if not enough args */
2169 if (MyUser(state->sptr))
2170 need_more_params(state->sptr, "MODE +l");
2174 t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2178 if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2179 (!t_limit || t_limit == state->chptr->mode.limit))
2182 t_limit = state->chptr->mode.limit;
2184 /* If they're not an oper, they can't change modes */
2185 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2186 send_notoper(state);
2190 if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2192 state->done |= DONE_LIMIT;
2197 modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2199 if (state->flags & MODE_PARSE_SET) { /* set the limit */
2200 if (state->dir & MODE_ADD) {
2201 state->chptr->mode.mode |= flag_p[0];
2202 state->chptr->mode.limit = t_limit;
2204 state->chptr->mode.mode &= ~flag_p[0];
2205 state->chptr->mode.limit = 0;
2211 * Helper function to convert keys
2214 mode_parse_key(struct ParseState *state, int *flag_p)
2219 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2222 if (state->parc <= 0) { /* warn if not enough args */
2223 if (MyUser(state->sptr))
2224 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2229 t_str = state->parv[state->args_used++]; /* grab arg */
2233 /* If they're not an oper, they can't change modes */
2234 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2235 send_notoper(state);
2239 if (state->done & DONE_KEY) /* allow key to be set only once */
2241 state->done |= DONE_KEY;
2245 /* clean up the key string */
2247 while (*++s > ' ' && *s != ':' && --t_len)
2251 if (!*t_str) { /* warn if empty */
2252 if (MyUser(state->sptr))
2253 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2261 /* can't add a key if one is set, nor can one remove the wrong key */
2262 if (!(state->flags & MODE_PARSE_FORCE))
2263 if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2264 (state->dir == MODE_DEL &&
2265 ircd_strcmp(state->chptr->mode.key, t_str))) {
2266 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2270 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2271 !ircd_strcmp(state->chptr->mode.key, t_str))
2272 return; /* no key change */
2274 if (state->flags & MODE_PARSE_BOUNCE) {
2275 if (*state->chptr->mode.key) /* reset old key */
2276 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2277 state->chptr->mode.key, 0);
2278 else /* remove new bogus key */
2279 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2280 } else /* send new key */
2281 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2283 if (state->flags & MODE_PARSE_SET) {
2284 if (state->dir == MODE_ADD) /* set the new key */
2285 ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2286 else /* remove the old key */
2287 *state->chptr->mode.key = '\0';
2292 * Helper function to convert user passes
2295 mode_parse_upass(struct ParseState *state, int *flag_p)
2300 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2303 if (state->parc <= 0) { /* warn if not enough args */
2304 if (MyUser(state->sptr))
2305 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2310 t_str = state->parv[state->args_used++]; /* grab arg */
2314 /* If they're not an oper, they can't change modes */
2315 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2316 send_notoper(state);
2320 /* If they are not the channel manager, they are not allowed to change it */
2321 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2322 if (*state->chptr->mode.apass) {
2323 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2324 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2326 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2327 "Re-create the channel. The channel must be *empty* for",
2328 TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2329 "before it can be recreated.");
2334 if (state->done & DONE_UPASS) /* allow upass to be set only once */
2336 state->done |= DONE_UPASS;
2338 t_len = PASSLEN + 1;
2340 /* clean up the upass string */
2342 while (*++s > ' ' && *s != ':' && --t_len)
2346 if (!*t_str) { /* warn if empty */
2347 if (MyUser(state->sptr))
2348 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2356 if (!(state->flags & MODE_PARSE_FORCE))
2357 /* can't add the upass while apass is not set */
2358 if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2359 send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2362 /* can't add a upass if one is set, nor can one remove the wrong upass */
2363 if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2364 (state->dir == MODE_DEL &&
2365 ircd_strcmp(state->chptr->mode.upass, t_str))) {
2366 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2370 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2371 !ircd_strcmp(state->chptr->mode.upass, t_str))
2372 return; /* no upass change */
2374 if (state->flags & MODE_PARSE_BOUNCE) {
2375 if (*state->chptr->mode.upass) /* reset old upass */
2376 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2377 state->chptr->mode.upass, 0);
2378 else /* remove new bogus upass */
2379 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2380 } else /* send new upass */
2381 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2383 if (state->flags & MODE_PARSE_SET) {
2384 if (state->dir == MODE_ADD) /* set the new upass */
2385 ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2386 else /* remove the old upass */
2387 *state->chptr->mode.upass = '\0';
2392 * Helper function to convert admin passes
2395 mode_parse_apass(struct ParseState *state, int *flag_p)
2400 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2403 if (state->parc <= 0) { /* warn if not enough args */
2404 if (MyUser(state->sptr))
2405 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2410 t_str = state->parv[state->args_used++]; /* grab arg */
2414 /* If they're not an oper, they can't change modes */
2415 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2416 send_notoper(state);
2420 /* Don't allow to change the Apass if the channel is older than 48 hours. */
2421 if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2422 send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2426 /* If they are not the channel manager, they are not allowed to change it */
2427 if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2428 if (*state->chptr->mode.apass) {
2429 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2430 "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2432 send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2433 "Re-create the channel. The channel must be *empty* for",
2434 "at least a whole minute", "before it can be recreated.");
2439 if (state->done & DONE_APASS) /* allow apass to be set only once */
2441 state->done |= DONE_APASS;
2443 t_len = PASSLEN + 1;
2445 /* clean up the apass string */
2447 while (*++s > ' ' && *s != ':' && --t_len)
2451 if (!*t_str) { /* warn if empty */
2452 if (MyUser(state->sptr))
2453 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2461 if (!(state->flags & MODE_PARSE_FORCE)) {
2462 /* can't remove the apass while upass is still set */
2463 if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2464 send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2467 /* can't add an apass if one is set, nor can one remove the wrong apass */
2468 if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2469 (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2470 send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2475 if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2476 !ircd_strcmp(state->chptr->mode.apass, t_str))
2477 return; /* no apass change */
2479 if (state->flags & MODE_PARSE_BOUNCE) {
2480 if (*state->chptr->mode.apass) /* reset old apass */
2481 modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2482 state->chptr->mode.apass, 0);
2483 else /* remove new bogus apass */
2484 modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2485 } else /* send new apass */
2486 modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2488 if (state->flags & MODE_PARSE_SET) {
2489 if (state->dir == MODE_ADD) { /* set the new apass */
2490 /* Make it VERY clear to the user that this is a one-time password */
2491 ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2492 if (MyUser(state->sptr)) {
2493 send_reply(state->sptr, RPL_APASSWARN,
2494 "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2495 "Are you SURE you want to use this as Admin password? ",
2496 "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2497 send_reply(state->sptr, RPL_APASSWARN,
2498 "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2499 "\" to remove the password and then immediately set a new one. "
2500 "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2501 "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2502 "Now set the channel user password (+u).");
2504 } else { /* remove the old apass */
2505 *state->chptr->mode.apass = '\0';
2506 if (MyUser(state->sptr))
2507 send_reply(state->sptr, RPL_APASSWARN,
2508 "WARNING: You removed the channel Admin password MODE (+A). ",
2509 "If you would disconnect or leave the channel without setting a new password then you will ",
2510 "not be able to set it again and lose ownership of this channel! ",
2511 "SET A NEW PASSWORD NOW!", "");
2517 * Helper function to convert bans
2520 mode_parse_ban(struct ParseState *state, int *flag_p)
2523 struct SLink *ban, *newban = 0;
2525 if (state->parc <= 0) { /* Not enough args, send ban list */
2526 if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2527 send_ban_list(state->sptr, state->chptr);
2528 state->done |= DONE_BANLIST;
2534 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2537 t_str = state->parv[state->args_used++]; /* grab arg */
2541 /* If they're not an oper, they can't change modes */
2542 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2543 send_notoper(state);
2547 if ((s = strchr(t_str, ' ')))
2550 if (!*t_str || *t_str == ':') { /* warn if empty */
2551 if (MyUser(state->sptr))
2552 need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2557 t_str = collapse(pretty_mask(t_str));
2559 /* remember the ban for the moment... */
2560 if (state->dir == MODE_ADD) {
2561 newban = state->banlist + (state->numbans++);
2564 DupString(newban->value.ban.banstr, t_str);
2565 newban->value.ban.who = cli_name(state->sptr);
2566 newban->value.ban.when = TStime();
2568 newban->flags = CHFL_BAN | MODE_ADD;
2570 if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2571 newban->flags |= CHFL_BAN_IPMASK;
2574 if (!state->chptr->banlist) {
2575 state->chptr->banlist = newban; /* add our ban with its flags */
2576 state->done |= DONE_BANCLEAN;
2580 /* Go through all bans */
2581 for (ban = state->chptr->banlist; ban; ban = ban->next) {
2582 /* first, clean the ban flags up a bit */
2583 if (!(state->done & DONE_BANCLEAN))
2584 /* Note: We're overloading *lots* of bits here; be careful! */
2585 ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2589 * MODE_ADD - Ban was added; if we're bouncing modes,
2590 * then we'll remove it below; otherwise,
2591 * we'll have to allocate a real ban
2593 * MODE_DEL - Ban was marked for deletion; if we're
2594 * bouncing modes, we'll have to re-add it,
2595 * otherwise, we'll have to remove it
2597 * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2598 * with a ban already set; if we're
2599 * bouncing modes, we'll have to bounce
2600 * this one; otherwise, we'll just ignore
2601 * it when we process added bans
2604 if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2605 ban->flags |= MODE_DEL; /* delete one ban */
2607 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2609 } else if (state->dir == MODE_ADD) {
2610 /* if the ban already exists, don't worry about it */
2611 if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2612 newban->flags &= ~MODE_ADD; /* don't add ban at all */
2613 MyFree(newban->value.ban.banstr); /* stopper a leak */
2614 state->numbans--; /* deallocate last ban */
2615 if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2617 } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2618 if (!(ban->flags & MODE_DEL))
2619 newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2620 } else if (!mmatch(t_str, ban->value.ban.banstr))
2621 ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2623 if (!ban->next && (newban->flags & MODE_ADD))
2625 ban->next = newban; /* add our ban with its flags */
2626 break; /* get out of loop */
2630 state->done |= DONE_BANCLEAN;
2634 * This is the bottom half of the ban processor
2637 mode_process_bans(struct ParseState *state)
2639 struct SLink *ban, *newban, *prevban, *nextban;
2645 for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2647 banlen = strlen(ban->value.ban.banstr);
2649 nextban = ban->next;
2651 if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2653 prevban->next = 0; /* Break the list; ban isn't a real ban */
2655 state->chptr->banlist = 0;
2660 MyFree(ban->value.ban.banstr);
2663 } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2664 modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2665 ban->value.ban.banstr,
2666 state->flags & MODE_PARSE_SET);
2668 if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2669 if (prevban) /* clip it out of the list... */
2670 prevban->next = ban->next;
2672 state->chptr->banlist = ban->next;
2677 MyFree(ban->value.ban.who);
2681 continue; /* next ban; keep prevban like it is */
2683 ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2684 } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2686 prevban->next = 0; /* Break the list; ban isn't a real ban */
2688 state->chptr->banlist = 0;
2690 /* If we're supposed to ignore it, do so. */
2691 if (ban->flags & CHFL_BAN_OVERLAPPED &&
2692 !(state->flags & MODE_PARSE_BOUNCE)) {
2696 MyFree(ban->value.ban.banstr);
2698 if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2699 (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2700 count > feature_int(FEAT_MAXBANS))) {
2701 send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2702 ban->value.ban.banstr);
2706 MyFree(ban->value.ban.banstr);
2708 /* add the ban to the buffer */
2709 modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2710 ban->value.ban.banstr,
2711 !(state->flags & MODE_PARSE_SET));
2713 if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2714 newban = make_link();
2715 newban->value.ban.banstr = ban->value.ban.banstr;
2716 DupString(newban->value.ban.who, ban->value.ban.who);
2717 newban->value.ban.when = ban->value.ban.when;
2718 newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2720 newban->next = state->chptr->banlist; /* and link it in */
2721 state->chptr->banlist = newban;
2730 } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2732 if (changed) /* if we changed the ban list, we must invalidate the bans */
2733 mode_ban_invalidate(state->chptr);
2737 * Helper function to process client changes
2740 mode_parse_client(struct ParseState *state, int *flag_p)
2743 struct Client *acptr;
2746 if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2749 if (state->parc <= 0) /* return if not enough args */
2752 t_str = state->parv[state->args_used++]; /* grab arg */
2756 /* If they're not an oper, they can't change modes */
2757 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2758 send_notoper(state);
2762 if (MyUser(state->sptr)) /* find client we're manipulating */
2763 acptr = find_chasing(state->sptr, t_str, NULL);
2765 acptr = findNUser(t_str);
2768 return; /* find_chasing() already reported an error to the user */
2770 for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2771 if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2772 state->cli_change[i].flag & flag_p[0]))
2773 break; /* found a slot */
2775 /* Store what we're doing to them */
2776 state->cli_change[i].flag = state->dir | flag_p[0];
2777 state->cli_change[i].client = acptr;
2781 * Helper function to process the changed client list
2784 mode_process_clients(struct ParseState *state)
2787 struct Membership *member;
2789 for (i = 0; state->cli_change[i].flag; i++) {
2790 assert(0 != state->cli_change[i].client);
2792 /* look up member link */
2793 if (!(member = find_member_link(state->chptr,
2794 state->cli_change[i].client)) ||
2795 (MyUser(state->sptr) && IsZombie(member))) {
2796 if (MyUser(state->sptr))
2797 send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2798 cli_name(state->cli_change[i].client),
2799 state->chptr->chname);
2803 if ((state->cli_change[i].flag & MODE_ADD &&
2804 (state->cli_change[i].flag & member->status)) ||
2805 (state->cli_change[i].flag & MODE_DEL &&
2806 !(state->cli_change[i].flag & member->status)))
2807 continue; /* no change made, don't do anything */
2809 /* see if the deop is allowed */
2810 if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2811 (MODE_DEL | MODE_CHANOP)) {
2812 /* prevent +k users from being deopped */
2813 if (IsChannelService(state->cli_change[i].client)) {
2814 if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2815 sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2817 (IsServer(state->sptr) ? cli_name(state->sptr) :
2818 cli_name((cli_user(state->sptr))->server)));
2820 else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2821 send_reply(state->sptr, ERR_ISCHANSERVICE,
2822 cli_name(state->cli_change[i].client),
2823 state->chptr->chname);
2828 /* check deop for local user */
2829 if (MyUser(state->sptr)) {
2831 /* don't allow local opers to be deopped on local channels */
2832 if (MyUser(state->sptr) &&
2833 state->cli_change[i].client != state->sptr &&
2834 IsLocalChannel(state->chptr->chname) &&
2835 HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2836 send_reply(state->sptr, ERR_ISOPERLCHAN,
2837 cli_name(state->cli_change[i].client),
2838 state->chptr->chname);
2842 if (feature_bool(FEAT_OPLEVELS)) {
2843 /* don't allow to deop members with an op level that is <= our own level */
2844 if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */
2846 && OpLevel(member) <= OpLevel(state->member)) {
2847 int equal = (OpLevel(member) == OpLevel(state->member));
2848 send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2849 cli_name(state->cli_change[i].client),
2850 state->chptr->chname,
2851 OpLevel(state->member), OpLevel(member),
2852 "deop", equal ? "the same" : "a higher");
2859 /* set op-level of member being opped */
2860 if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2861 (MODE_ADD | MODE_CHANOP)) {
2862 /* If on a channel with upass set, someone with level x gives ops to someone else,
2863 then that person gets level x-1. On other channels, where upass is not set,
2864 the level stays the same. */
2865 int level_increment = *state->chptr->mode.upass ? 1 : 0;
2866 /* Someone being opped by a server gets op-level 0 */
2867 int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2868 SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2871 /* actually effect the change */
2872 if (state->flags & MODE_PARSE_SET) {
2873 if (state->cli_change[i].flag & MODE_ADD) {
2874 if (IsDelayedJoin(member))
2875 RevealDelayedJoin(member);
2876 member->status |= (state->cli_change[i].flag &
2877 (MODE_CHANOP | MODE_VOICE));
2878 if (state->cli_change[i].flag & MODE_CHANOP)
2879 ClearDeopped(member);
2881 member->status &= ~(state->cli_change[i].flag &
2882 (MODE_CHANOP | MODE_VOICE));
2885 /* accumulate the change */
2886 modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2887 state->cli_change[i].client);
2888 } /* for (i = 0; state->cli_change[i].flags; i++) */
2892 * Helper function to process the simple modes
2895 mode_parse_mode(struct ParseState *state, int *flag_p)
2897 /* If they're not an oper, they can't change modes */
2898 if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2899 send_notoper(state);
2906 if (state->dir == MODE_ADD) {
2907 state->add |= flag_p[0];
2908 state->del &= ~flag_p[0];
2910 if (flag_p[0] & MODE_SECRET) {
2911 state->add &= ~MODE_PRIVATE;
2912 state->del |= MODE_PRIVATE;
2913 } else if (flag_p[0] & MODE_PRIVATE) {
2914 state->add &= ~MODE_SECRET;
2915 state->del |= MODE_SECRET;
2917 if (flag_p[0] & MODE_DELJOINS) {
2918 state->add &= ~MODE_WASDELJOINS;
2919 state->del |= MODE_WASDELJOINS;
2922 state->add &= ~flag_p[0];
2923 state->del |= flag_p[0];
2926 assert(0 == (state->add & state->del));
2927 assert((MODE_SECRET | MODE_PRIVATE) !=
2928 (state->add & (MODE_SECRET | MODE_PRIVATE)));
2932 * This routine is intended to parse MODE or OPMODE commands and effect the
2933 * changes (or just build the bounce buffer). We pass the starting offset
2937 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2938 struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2939 struct Membership* member)
2941 static int chan_flags[] = {
2946 MODE_MODERATED, 'm',
2947 MODE_TOPICLIMIT, 't',
2948 MODE_INVITEONLY, 'i',
2949 MODE_NOPRIVMSGS, 'n',
2963 unsigned int t_mode;
2965 struct ParseState state;
2976 state.chptr = chptr;
2977 state.member = member;
2980 state.flags = flags;
2981 state.dir = MODE_ADD;
2985 state.args_used = 0;
2986 state.max_args = MAXMODEPARAMS;
2989 for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2990 state.banlist[i].next = 0;
2991 state.banlist[i].value.ban.banstr = 0;
2992 state.banlist[i].value.ban.who = 0;
2993 state.banlist[i].value.ban.when = 0;
2994 state.banlist[i].flags = 0;
2995 state.cli_change[i].flag = 0;
2996 state.cli_change[i].client = 0;
2999 modestr = state.parv[state.args_used++];
3003 for (; *modestr; modestr++) {
3004 for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3005 if (flag_p[1] == *modestr)
3008 if (!flag_p[0]) { /* didn't find it? complain and continue */
3009 if (MyUser(state.sptr))
3010 send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3015 case '+': /* switch direction to MODE_ADD */
3016 case '-': /* switch direction to MODE_DEL */
3017 state.dir = flag_p[0];
3020 case 'l': /* deal with limits */
3021 mode_parse_limit(&state, flag_p);
3024 case 'k': /* deal with keys */
3025 mode_parse_key(&state, flag_p);
3028 case 'A': /* deal with Admin passes */
3029 if (feature_bool(FEAT_OPLEVELS))
3030 mode_parse_apass(&state, flag_p);
3033 case 'u': /* deal with user passes */
3034 if (feature_bool(FEAT_OPLEVELS))
3035 mode_parse_upass(&state, flag_p);
3038 case 'b': /* deal with bans */
3039 mode_parse_ban(&state, flag_p);
3042 case 'o': /* deal with ops/voice */
3044 mode_parse_client(&state, flag_p);
3047 default: /* deal with other modes */
3048 mode_parse_mode(&state, flag_p);
3050 } /* switch (*modestr) */
3051 } /* for (; *modestr; modestr++) */
3053 if (state.flags & MODE_PARSE_BURST)
3054 break; /* don't interpret any more arguments */
3056 if (state.parc > 0) { /* process next argument in string */
3057 modestr = state.parv[state.args_used++];
3061 if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3064 if (!(state.flags & MODE_PARSE_SET)) /* don't set earlier TS if */
3065 break; /* we're then going to bounce the mode! */
3067 recv_ts = atoi(modestr);
3069 if (recv_ts && recv_ts < state.chptr->creationtime)
3070 state.chptr->creationtime = recv_ts; /* respect earlier TS */
3072 break; /* break out of while loop */
3073 } else if (state.flags & MODE_PARSE_STRICT ||
3074 (MyUser(state.sptr) && state.max_args <= 0)) {
3075 state.parc++; /* we didn't actually gobble the argument */
3077 break; /* break out of while loop */
3080 } /* while (*modestr) */
3083 * the rest of the function finishes building resultant MODEs; if the
3084 * origin isn't a member or an oper, skip it.
3086 if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3087 return state.args_used; /* tell our parent how many args we gobbled */
3089 t_mode = state.chptr->mode.mode;
3091 if (state.del & t_mode) { /* delete any modes to be deleted... */
3092 modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3094 t_mode &= ~state.del;
3096 if (state.add & ~t_mode) { /* add any modes to be added... */
3097 modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3099 t_mode |= state.add;
3102 if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3103 if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3104 !(t_mode & MODE_INVITEONLY))
3105 mode_invite_clear(state.chptr);
3107 state.chptr->mode.mode = t_mode;
3110 if (state.flags & MODE_PARSE_WIPEOUT) {
3111 if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3112 modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3113 state.chptr->mode.limit);
3114 if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3115 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3116 state.chptr->mode.key, 0);
3117 if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3118 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3119 state.chptr->mode.upass, 0);
3120 if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3121 modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3122 state.chptr->mode.apass, 0);
3125 if (state.done & DONE_BANCLEAN) /* process bans */
3126 mode_process_bans(&state);
3128 /* process client changes */
3129 if (state.cli_change[0].flag)
3130 mode_process_clients(&state);
3132 return state.args_used; /* tell our parent how many args we gobbled */
3136 * Initialize a join buffer
3139 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3140 struct Client *connect, unsigned int type, char *comment,
3146 assert(0 != source);
3147 assert(0 != connect);
3149 jbuf->jb_source = source; /* just initialize struct JoinBuf */
3150 jbuf->jb_connect = connect;
3151 jbuf->jb_type = type;
3152 jbuf->jb_comment = comment;
3153 jbuf->jb_create = create;
3155 jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3156 type == JOINBUF_TYPE_PART ||
3157 type == JOINBUF_TYPE_PARTALL) ?
3158 STARTJOINLEN : STARTCREATELEN) +
3159 (comment ? strlen(comment) + 2 : 0));
3161 for (i = 0; i < MAXJOINARGS; i++)
3162 jbuf->jb_channels[i] = 0;
3166 * Add a channel to the join buffer
3169 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3177 if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3178 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3183 is_local = IsLocalChannel(chan->chname);
3185 if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3186 jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3187 struct Membership *member = find_member_link(chan, jbuf->jb_source);
3188 if (IsUserParting(member))
3190 SetUserParting(member);
3192 /* Send notification to channel */
3193 if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3194 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3195 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3196 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3197 else if (MyUser(jbuf->jb_source))
3198 sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3199 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3200 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3201 /* XXX: Shouldn't we send a PART here anyway? */
3202 /* to users on the channel? Why? From their POV, the user isn't on
3203 * the channel anymore anyway. We don't send to servers until below,
3204 * when we gang all the channel parts together. Note that this is
3205 * exactly the same logic, albeit somewhat more concise, as was in
3206 * the original m_part.c */
3208 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3209 is_local) /* got to remove user here */
3210 remove_user_from_channel(jbuf->jb_source, chan);
3212 /* Add user to channel */
3213 if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3214 add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3216 add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3218 /* send notification to all servers */
3219 if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3220 sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3221 "%H %Tu", chan, chan->creationtime);
3223 if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3224 /* Send the notification to the channel */
3225 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, "%H", chan);
3227 /* send an op, too, if needed */
3228 if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3229 sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3230 chan, jbuf->jb_source);
3231 } else if (MyUser(jbuf->jb_source))
3232 sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3235 if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3236 jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3237 return; /* don't send to remote */
3239 /* figure out if channel name will cause buffer to be overflowed */
3240 len = chan ? strlen(chan->chname) + 1 : 2;
3241 if (jbuf->jb_strlen + len > BUFSIZE)
3242 joinbuf_flush(jbuf);
3244 /* add channel to list of channels to send and update counts */
3245 jbuf->jb_channels[jbuf->jb_count++] = chan;
3246 jbuf->jb_strlen += len;
3248 /* if we've used up all slots, flush */
3249 if (jbuf->jb_count >= MAXJOINARGS)
3250 joinbuf_flush(jbuf);
3254 * Flush the channel list to remote servers
3257 joinbuf_flush(struct JoinBuf *jbuf)
3259 char chanlist[BUFSIZE];
3263 if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3264 jbuf->jb_type == JOINBUF_TYPE_JOIN)
3265 return 0; /* no joins to process */
3267 for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3268 build_string(chanlist, &chanlist_i,
3269 jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3270 i == 0 ? '\0' : ',');
3271 if (JOINBUF_TYPE_PART == jbuf->jb_type)
3272 /* Remove user from channel */
3273 remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3275 jbuf->jb_channels[i] = 0; /* mark slot empty */
3278 jbuf->jb_count = 0; /* reset base counters */
3279 jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3280 STARTJOINLEN : STARTCREATELEN) +
3281 (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3283 /* and send the appropriate command */
3284 switch (jbuf->jb_type) {
3285 case JOINBUF_TYPE_CREATE:
3286 sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3287 "%s %Tu", chanlist, jbuf->jb_create);
3290 case JOINBUF_TYPE_PART:
3291 sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3292 jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3300 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3301 int IsInvited(struct Client* cptr, const void* chptr)
3305 for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3306 if (lp->value.chptr == chptr)
3311 /* RevealDelayedJoin: sends a join for a hidden user */
3313 void RevealDelayedJoin(struct Membership *member) {
3314 ClearDelayedJoin(member);
3315 sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, ":%H",
3317 CheckDelayedJoins(member->channel);
3320 /* CheckDelayedJoins: checks and clear +d if necessary */
3322 void CheckDelayedJoins(struct Channel *chan) {
3323 struct Membership *memb2;
3325 if (chan->mode.mode & MODE_WASDELJOINS) {
3326 for (memb2=chan->members;memb2;memb2=memb2->next_member)
3327 if (IsDelayedJoin(memb2))
3332 chan->mode.mode &= ~MODE_WASDELJOINS;
3333 sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL,