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.
46 #include "sprintf_irc.h"
47 #include "querycmds.h"
51 aChannel *channel = NullChn;
53 static void sendmodeto_one(aClient *cptr, char *from, char *name,
54 char *mode, char *param, time_t creationtime);
55 static void add_invite(aClient *, aChannel *);
56 static int add_banid(aClient *, aChannel *, char *, int, int);
57 static Link *next_overlapped_ban(void);
58 static Link *next_removed_overlapped_ban(void);
59 static int can_join(aClient *, aChannel *, char *);
60 static void channel_modes(aClient *, char *, char *, aChannel *);
61 static int del_banid(aChannel *, char *, int);
62 static int is_banned(aClient *, aChannel *, Link *);
63 static int number_of_zombies(aChannel *);
64 static int is_deopped(aClient *, aChannel *);
65 static int set_mode(aClient *, aClient *, aChannel *, int,
66 char **, char *, char *, char *, int *);
67 static void sub1_from_channel(aChannel *);
68 static void send_hack_notice(aClient *, aClient *, int, char *[], int, int);
69 static void clean_channelname(char *);
71 void del_invite(aClient *, aChannel *);
73 static char *PartFmt1 = ":%s PART %s";
74 static char *PartFmt2 = ":%s PART %s :%s";
76 * some buffers for rebuilding channel/nick lists with ,'s
78 static char nickbuf[BUFSIZE], buf[BUFSIZE];
79 static char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
80 static char nparabuf[MODEBUFLEN];
83 * Maximum acceptable lag time in seconds: A channel younger than
84 * this is not protected against hacking admins.
85 * Mainly here to check if the TS clocks really sync (otherwise this
86 * will start causing HACK notices.
87 * This value must be the same on all servers.
89 * This value has been increased to 1 day in order to distinguish this
90 * "normal" type of HACK wallops / desyncs, from possiblity still
93 #define TS_LAG_TIME ((time_t)86400)
96 * A Magic TS that is used for channels that are created by JOIN,
97 * a channel with this TS accepts all TS without complaining that
98 * it might receive later via MODE or CREATE.
100 #define MAGIC_REMOTE_JOIN_TS 1270080000
103 * return the length (>=0) of a chain of links.
105 static int list_length(Link *lp)
109 for (; lp; lp = lp->next)
117 * Find the client structure for a nick name (user) using history
118 * mechanism if necessary. If the client is not found, an error
119 * message (NO SUCH NICK) is generated. If the client was found
120 * through the history, chasing will be 1 and otherwise 0.
122 static aClient *find_chasing(aClient *sptr, char *user, int *chasing)
124 Reg2 aClient *who = FindClient(user);
130 if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
132 sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, user);
141 * Create a string of form "foo!bar@fubar" given foo, bar and fubar
142 * as the parameters. If NULL, they become "*".
144 static char *make_nick_user_host(char *nick, char *name, char *host)
146 static char namebuf[NICKLEN + USERLEN + HOSTLEN + 3];
147 sprintf_irc(namebuf, "%s!%s@%s", nick, name, host);
152 * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
153 * IP-number as the parameters. If NULL, they become "*".
155 static char *make_nick_user_ip(char *nick, char *name, struct in_addr ip)
157 static char ipbuf[NICKLEN + USERLEN + 16 + 3];
158 sprintf_irc(ipbuf, "%s!%s@%s", nick, name, inetntoa(ip));
165 * `cptr' must be the client adding the ban.
167 * If `change' is true then add `banid' to channel `chptr'.
168 * Returns 0 if the ban was added.
169 * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
170 * Return -1 otherwise.
172 * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
173 * when `change' is false, otherwise they will be removed from the banlist.
174 * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
175 * respectively will return these bans until NULL is returned.
177 * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
178 * is reset (unless a non-zero value is returned, in which case the
179 * CHFL_BAN_OVERLAPPED flag might not have been reset!).
183 static Link *next_ban, *prev_ban, *removed_bans_list;
185 static int add_banid(aClient *cptr, aChannel *chptr, char *banid,
186 int change, int firsttime)
188 Reg1 Link *ban, **banp;
189 Reg2 int cnt = 0, removed_bans = 0, len = strlen(banid);
194 if (prev_ban || removed_bans_list)
195 MyCoreDump; /* Memory leak */
199 for (banp = &chptr->banlist; *banp;)
201 len += strlen((*banp)->value.ban.banstr);
203 if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
205 if (!strcmp((*banp)->value.ban.banstr, banid))
207 (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
211 else if (!mmatch((*banp)->value.ban.banstr, banid))
213 if (!mmatch(banid, (*banp)->value.ban.banstr))
221 len -= strlen(tmp->value.ban.banstr);
225 /* Silently remove overlapping bans */
226 RunFree(tmp->value.ban.banstr);
227 RunFree(tmp->value.ban.who);
230 /* These will be sent to the user later as -b */
231 tmp->next = removed_bans_list;
232 removed_bans_list = tmp;
236 else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
238 tmp->flags |= CHFL_BAN_OVERLAPPED;
249 (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
250 banp = &(*banp)->next;
253 if (MyUser(cptr) && !removed_bans && (len > MAXBANLENGTH || (cnt >= MAXBANS)))
255 sendto_one(cptr, err_str(ERR_BANLISTFULL), me.name, cptr->name,
256 chptr->chname, banid);
263 ban->next = chptr->banlist;
264 ban->value.ban.banstr = (char *)RunMalloc(strlen(banid) + 1);
265 strcpy(ban->value.ban.banstr, banid);
266 ban->value.ban.who = (char *)RunMalloc(strlen(cptr->name) + 1);
267 strcpy(ban->value.ban.who, cptr->name);
268 ban->value.ban.when = now;
269 ban->flags = CHFL_BAN; /* This bit is never used I think... */
270 if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
271 ban->flags |= CHFL_BAN_IPMASK;
272 chptr->banlist = ban;
273 /* Erase ban-valid-bit */
274 for (ban = chptr->members; ban; ban = ban->next)
275 ban->flags &= ~CHFL_BANVALID; /* `ban' == channel member ! */
280 static Link *next_overlapped_ban(void)
282 Reg1 Link *tmp = next_ban;
286 for (ban = tmp->next; ban; ban = ban->next)
287 if ((ban->flags & CHFL_BAN_OVERLAPPED))
294 static Link *next_removed_overlapped_ban(void)
296 Reg1 Link *tmp = removed_bans_list;
299 if (prev_ban->value.ban.banstr) /* Can be set to NULL in set_mode() */
300 RunFree(prev_ban->value.ban.banstr);
301 RunFree(prev_ban->value.ban.who);
305 removed_bans_list = removed_bans_list->next;
313 * If `change' is true, delete `banid' from channel `chptr'.
314 * Returns `false' if removal was (or would have been) successful.
316 static int del_banid(aChannel *chptr, char *banid, int change)
323 for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
324 if (strCasediff(banid, (*ban)->value.ban.banstr) == 0)
330 RunFree(tmp->value.ban.banstr);
331 RunFree(tmp->value.ban.who);
333 /* Erase ban-valid-bit, for channel members that are banned */
334 for (tmp = chptr->members; tmp; tmp = tmp->next)
335 if ((tmp->flags & (CHFL_BANNED | CHFL_BANVALID)) ==
336 (CHFL_BANNED | CHFL_BANVALID))
337 tmp->flags &= ~CHFL_BANVALID; /* `tmp' == channel member */
345 * IsMember - returns Link * if a person is joined and not a zombie
347 Link *IsMember(aClient *cptr, aChannel *chptr)
350 return (((lp = find_user_link(chptr->members, cptr)) &&
351 !(lp->flags & CHFL_ZOMBIE)) ? lp : NULL);
355 * is_banned - a non-zero value if banned else 0.
357 static int is_banned(aClient *cptr, aChannel *chptr, Link *member)
360 char *s, *ip_s = NULL;
367 if ((member->flags & CHFL_BANVALID))
368 return (member->flags & CHFL_BANNED);
371 s = make_nick_user_host(cptr->name, cptr->user->username, cptr->user->host);
373 for (tmp = chptr->banlist; tmp; tmp = tmp->next)
375 if ((tmp->flags & CHFL_BAN_IPMASK))
378 ip_s = make_nick_user_ip(cptr->name, cptr->user->username, cptr->ip);
379 if (match(tmp->value.ban.banstr, ip_s) == 0)
382 else if (match(tmp->value.ban.banstr, s) == 0)
388 member->flags |= CHFL_BANVALID;
391 member->flags |= CHFL_BANNED;
396 member->flags &= ~CHFL_BANNED;
401 return (tmp != NULL);
405 * adds a user to a channel by adding another link to the channels member
408 static void add_user_to_channel(aChannel *chptr, aClient *who, int flags)
415 ptr->value.cptr = who;
417 ptr->next = chptr->members;
418 chptr->members = ptr;
422 ptr->value.chptr = chptr;
423 ptr->next = who->user->channel;
424 who->user->channel = ptr;
429 void remove_user_from_channel(aClient *sptr, aChannel *chptr)
433 Reg3 Link *lp = chptr->members;
435 for (; lp && (lp->flags & CHFL_ZOMBIE || lp->value.cptr == sptr);
439 for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
440 if (tmp->value.cptr == sptr)
446 for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next)
447 if (tmp->value.chptr == chptr)
453 sptr->user->joined--;
457 sptr = chptr->members->value.cptr;
460 sub1_from_channel(chptr);
462 sub1_from_channel(chptr);
465 int is_chan_op(aClient *cptr, aChannel *chptr)
470 if ((lp = find_user_link(chptr->members, cptr)) &&
471 !(lp->flags & CHFL_ZOMBIE))
472 return (lp->flags & CHFL_CHANOP);
477 static int is_deopped(aClient *cptr, aChannel *chptr)
482 if ((lp = find_user_link(chptr->members, cptr)))
483 return (lp->flags & CHFL_DEOPPED);
485 return (IsUser(cptr) ? 1 : 0);
488 int is_zombie(aClient *cptr, aChannel *chptr)
493 if ((lp = find_user_link(chptr->members, cptr)))
494 return (lp->flags & CHFL_ZOMBIE);
499 int has_voice(aClient *cptr, aChannel *chptr)
504 if ((lp = find_user_link(chptr->members, cptr)) &&
505 !(lp->flags & CHFL_ZOMBIE))
506 return (lp->flags & CHFL_VOICE);
511 int can_send(aClient *cptr, aChannel *chptr)
515 lp = IsMember(cptr, chptr);
517 if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
518 (lp->flags & CHFL_ZOMBIE)) && MyUser(cptr) && is_banned(cptr, chptr, lp))
521 if (chptr->mode.mode & MODE_MODERATED &&
522 (!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
523 (lp->flags & CHFL_ZOMBIE)))
524 return (MODE_MODERATED);
526 if (!lp && ((chptr->mode.mode & MODE_NOPRIVMSGS) ||
527 IsModelessChannel(chptr->chname)))
528 return (MODE_NOPRIVMSGS);
534 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
535 * with the parameters in pbuf.
537 static void channel_modes(aClient *cptr, char *mbuf, char *pbuf,
541 if (chptr->mode.mode & MODE_SECRET)
543 else if (chptr->mode.mode & MODE_PRIVATE)
545 if (chptr->mode.mode & MODE_MODERATED)
547 if (chptr->mode.mode & MODE_TOPICLIMIT)
549 if (chptr->mode.mode & MODE_INVITEONLY)
551 if (chptr->mode.mode & MODE_NOPRIVMSGS)
553 if (chptr->mode.limit)
556 sprintf_irc(pbuf, "%d", chptr->mode.limit);
558 if (*chptr->mode.key)
561 if (is_chan_op(cptr, chptr) || IsServer(cptr))
563 if (chptr->mode.limit)
565 strcat(pbuf, chptr->mode.key);
572 static int send_mode_list(aClient *cptr, char *chname, time_t creationtime,
573 Link *top, int mask, char flag)
576 Reg2 char *cp, *name;
577 int count = 0, send = 0, sent = 0;
579 cp = modebuf + strlen(modebuf);
580 if (*parabuf) /* mode +l or +k xx */
582 for (lp = top; lp; lp = lp->next)
584 if (!(lp->flags & mask))
586 if (mask == CHFL_BAN)
587 name = lp->value.ban.banstr;
589 name = lp->value.cptr->name;
590 if (strlen(parabuf) + strlen(name) + 11 < (size_t)MODEBUFLEN)
592 strcat(parabuf, " ");
593 strcat(parabuf, name);
604 /* cptr is always a server! So we send creationtimes */
605 sendmodeto_one(cptr, me.name, chname, modebuf, parabuf, creationtime);
613 strcpy(parabuf, name);
624 * send "cptr" a full list of the modes for channel chptr.
626 void send_channel_modes(aClient *cptr, aChannel *chptr)
629 if (IsLocalChannel(chptr->chname))
632 *modebuf = *parabuf = '\0';
633 channel_modes(cptr, modebuf, parabuf, chptr);
635 if (Protocol(cptr) < 10)
637 sent = send_mode_list(cptr, chptr->chname, chptr->creationtime,
638 chptr->members, CHFL_CHANOP, 'o');
639 if (!sent && chptr->creationtime)
640 sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT, me.name,
641 chptr->chname, modebuf, parabuf, chptr->creationtime);
642 else if (modebuf[1] || *parabuf)
643 sendmodeto_one(cptr, me.name,
644 chptr->chname, modebuf, parabuf, chptr->creationtime);
649 send_mode_list(cptr, chptr->chname, chptr->creationtime,
650 chptr->banlist, CHFL_BAN, 'b');
651 if (modebuf[1] || *parabuf)
652 sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
653 parabuf, chptr->creationtime);
658 send_mode_list(cptr, chptr->chname, chptr->creationtime,
659 chptr->members, CHFL_VOICE, 'v');
660 if (modebuf[1] || *parabuf)
661 sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
662 parabuf, chptr->creationtime);
666 static unsigned int current_flags[4] =
667 { 0, CHFL_CHANOP | CHFL_VOICE, CHFL_VOICE, CHFL_CHANOP };
668 int first = 1, full = 1, flag_cnt = 0, new_mode = 0;
670 Link *lp1 = chptr->members;
671 Link *lp2 = chptr->banlist;
672 for (first = 1; full; first = 0) /* Loop for multiple messages */
674 full = 0; /* Assume by default we get it
675 all in one message */
677 /* (Continued) prefix: "<Y> BURST <channel> <TS>" */
678 sprintf_irc(sendbuf, "%s BURST %s " TIME_T_FMT, NumServ(&me),
679 chptr->chname, chptr->creationtime);
680 sblen = strlen(sendbuf);
682 if (first && modebuf[1]) /* Add simple modes (iklmnpst)
685 /* prefix: "<Y> BURST <channel> <TS>[ <modes>[ <params>]]" */
686 sendbuf[sblen++] = ' ';
687 strcpy(sendbuf + sblen, modebuf);
688 sblen += strlen(modebuf);
691 sendbuf[sblen++] = ' ';
692 strcpy(sendbuf + sblen, parabuf);
693 sblen += strlen(parabuf);
697 /* Attach nicks, comma seperated " nick[:modes],nick[:modes],..." */
698 /* Run 4 times over all members, to group the members with the
699 * same mode together */
700 for (first = 1; flag_cnt < 4;
701 lp1 = chptr->members, new_mode = 1, flag_cnt++)
703 for (; lp1; lp1 = lp1->next)
705 if ((lp1->flags & (CHFL_CHANOP | CHFL_VOICE)) !=
706 current_flags[flag_cnt])
707 continue; /* Skip members with different flags */
708 if (sblen + NUMNICKLEN + 4 > BUFSIZE - 3)
709 /* The 4 is a possible ",:ov"
710 The -3 is for the "\r\n\0" that is added in send.c */
712 full = 1; /* Make sure we continue after
714 break; /* Do not add this member to this message */
716 sendbuf[sblen++] = first ? ' ' : ',';
717 first = 0; /* From now on, us comma's to add new nicks */
719 sprintf_irc(sendbuf + sblen, "%s%s", NumNick(lp1->value.cptr));
720 sblen += strlen(sendbuf + sblen);
722 if (new_mode) /* Do we have a nick with a new mode ? */
725 sendbuf[sblen++] = ':';
726 if (lp1->flags & CHFL_CHANOP)
727 sendbuf[sblen++] = 'o';
728 if (lp1->flags & CHFL_VOICE)
729 sendbuf[sblen++] = 'v';
738 /* Attach all bans, space seperated " :%ban ban ..." */
739 for (first = 2; lp2; lp2 = lp2->next)
741 len = strlen(lp2->value.ban.banstr);
742 if (sblen + len + 1 + first > BUFSIZE - 3)
743 /* The +1 stands for the added ' '.
744 * The +first stands for the added ":%".
745 * The -3 is for the "\r\n\0" that is added in send.c
754 sendbuf[sblen++] = ' ';
755 sendbuf[sblen++] = ':'; /* Will be last parameter */
756 sendbuf[sblen++] = '%'; /* To tell bans apart */
759 sendbuf[sblen++] = ' ';
760 strcpy(sendbuf + sblen, lp2->value.ban.banstr);
765 sendbuf[sblen] = '\0';
766 sendbufto_one(cptr); /* Send this message */
767 } /* Continue when there was something
768 that didn't fit (full==1) */
778 int m_mode(aClient *cptr, aClient *sptr, int parc, char *parv[])
783 /* Now, try to find the channel in question */
786 chptr = FindChannel(parv[1]);
787 if (chptr == NullChn)
788 return m_umode(cptr, sptr, parc, parv);
792 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE");
796 sptr->flags &= ~FLAGS_TS8;
799 clean_channelname(parv[1]);
800 else if (IsLocalChannel(parv[1]))
803 /* sending an error wasnt good, lets just send an empty mode reply.. poptix */
804 if (IsModelessChannel(chptr->chname))
807 sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
808 chptr->chname, "+nt", "");
814 *modebuf = *parabuf = '\0';
816 channel_modes(sptr, modebuf, parabuf, chptr);
817 sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
818 chptr->chname, modebuf, parabuf);
819 sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
820 chptr->chname, chptr->creationtime);
824 if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
825 modebuf, parabuf, nparabuf, &badop)))
827 sendto_one(sptr, err_str(IsMember(sptr, chptr) ? ERR_CHANOPRIVSNEEDED :
828 ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
833 send_hack_notice(cptr, sptr, parc, parv, badop, 1);
835 if (strlen(modebuf) > (size_t)1 || sendts > 0)
837 if (badop != 2 && strlen(modebuf) > (size_t)1)
838 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
839 parv[0], chptr->chname, modebuf, parabuf);
840 if (IsLocalChannel(chptr->chname))
842 /* We send a creationtime of 0, to mark it as a hack --Run */
843 if (IsServer(sptr) && (badop == 2 || sendts > 0))
845 if (*modebuf == '\0')
846 strcpy(modebuf, "+");
849 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s %s " TIME_T_FMT,
850 parv[0], chptr->chname, modebuf, parabuf,
851 (badop == 4) ? (time_t) 0 : chptr->creationtime);
852 sendto_highprot_butone(cptr, 10, ":%s MODE %s %s %s " TIME_T_FMT,
853 parv[0], chptr->chname, modebuf, nparabuf,
854 (badop == 4) ? (time_t) 0 : chptr->creationtime);
859 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s %s",
860 parv[0], chptr->chname, modebuf, parabuf);
861 sendto_highprot_butone(cptr, 10, ":%s MODE %s %s %s",
862 parv[0], chptr->chname, modebuf, nparabuf);
868 static int DoesOp(char *modebuf)
870 modebuf--; /* Is it possible that a mode
871 starts with o and not +o ? */
873 if (*modebuf == 'o' || *modebuf == 'v')
878 /* This function should be removed when all servers are 2.10 */
879 static void sendmodeto_one(aClient *cptr, char *from, char *name,
880 char *mode, char *param, time_t creationtime)
882 if (IsServer(cptr) && DoesOp(mode) && creationtime)
883 sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
884 from, name, mode, param, creationtime);
886 sendto_one(cptr, ":%s MODE %s %s %s", from, name, mode, param);
892 * by Carlo Wood (Run), 05 Oct 1998.
896 * When the nick is longer then NICKLEN, it is cut off (its an error of course).
897 * When the user name or host name are too long (USERLEN and HOSTLEN
898 * respectively) then they are cut off at the start with a '*'.
900 * The following transformations are made:
903 * 2) xxx.xxx -> *!*@host
904 * 3) xxx!yyy -> nick!user@*
905 * 4) xxx@yyy -> *!user@host
906 * 5) xxx!yyy@zzz -> nick!user@host
908 char *pretty_mask(char *mask)
910 static char star[2] = { '*', 0 };
911 char *last_dot = NULL;
914 /* Case 1: default */
919 /* Do a _single_ pass through the characters of the mask: */
920 for (ptr = mask; *ptr; ++ptr)
924 /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
928 else if (*ptr == '@')
930 /* Case 4: Found last '@' (without finding a '!' yet) */
935 else if (*ptr == '.')
937 /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
947 /* Case 4 or 5: Found last '@' */
953 if (user == star && last_dot)
963 char *nick_end = (user != star) ? user - 1 : ptr;
964 if (nick_end - nick > NICKLEN)
970 char *user_end = (host != star) ? host - 1 : ptr;
971 if (user_end - user > USERLEN)
973 user = user_end - USERLEN;
978 if (host != star && ptr - host > HOSTLEN)
980 host = ptr - HOSTLEN;
983 return make_nick_user_host(nick, user, host);
986 static char bmodebuf[MODEBUFLEN], bparambuf[MODEBUFLEN];
987 static char nbparambuf[MODEBUFLEN]; /* "Numeric" Bounce Parameter Buffer */
990 * Check and try to apply the channel modes passed in the parv array for
991 * the client ccptr to channel chptr. The resultant changes are printed
992 * into mbuf and pbuf (if any) and applied to the channel.
994 static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
995 char *parv[], char *mbuf, char *pbuf, char *npbuf, int *badop)
997 static Link chops[MAXPARA - 2]; /* This size is only needed when a broken
998 server sends more then MAXMODEPARAMS
1000 static int flags[] = {
1001 MODE_PRIVATE, 'p', MODE_SECRET, 's',
1002 MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
1003 MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i',
1004 MODE_VOICE, 'v', MODE_KEY, 'k',
1009 Reg2 char *curr = parv[0], *cp = NULL;
1011 Link *member, *tmp = NULL;
1012 unsigned int whatt = MODE_ADD, bwhatt = 0;
1013 int limitset = 0, bounce, add_banid_called = 0;
1014 size_t len, nlen, blen, nblen;
1016 unsigned int nusers = 0, newmode;
1017 int opcnt = 0, banlsent = 0;
1018 int doesdeop = 0, doesop = 0, hacknotice = 0, change, gotts = 0;
1021 static char numeric[16];
1022 char *bmbuf = bmodebuf, *bpbuf = bparambuf, *nbpbuf = nbparambuf;
1023 time_t newtime = (time_t) 0;
1026 *mbuf = *pbuf = *npbuf = *bmbuf = *bpbuf = *nbpbuf = '\0';
1031 mode = &(chptr->mode);
1032 memcpy(&oldm, mode, sizeof(Mode));
1034 * Mode is accepted when sptr is a channel operator
1035 * but also when the mode is received from a server.
1036 * At this point, let any member pass, so they are allowed
1039 if (!(IsServer(cptr) || (tmp = IsMember(sptr, chptr))))
1042 newmode = mode->mode;
1044 while (curr && *curr)
1059 if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1062 * Check for nickname changes and try to follow these
1063 * to make sure the right client is affected by the
1065 * Even if we find a nick with find_chasing() there
1066 * is still a reason to ignore in a special case.
1067 * We need to ignore the mode when:
1068 * - It is part of a net.burst (from a server and
1069 * a MODE_ADD). Ofcourse we don't ignore mode
1070 * changes from Uworld.
1071 * - The found nick is not on the right side off
1073 * This fixes the bug that when someone (tries to)
1074 * ride a net.break and does so with the nick of
1075 * someone on the otherside, that he is nick collided
1076 * (killed) but his +o still ops the other person.
1078 if (MyUser(sptr) || Protocol(cptr) < 10)
1080 if (!(who = find_chasing(sptr, parv[0], NULL)))
1085 if (!(who = findNUser(parv[0])))
1088 if (whatt == MODE_ADD && IsServer(sptr) && who->from != sptr->from &&
1089 !find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
1091 if (!(member = find_user_link(chptr->members, who)) ||
1092 (MyUser(sptr) && (member->flags & CHFL_ZOMBIE)))
1094 sendto_one(cptr, err_str(ERR_USERNOTINCHANNEL),
1095 me.name, cptr->name, who->name, chptr->chname);
1098 /* if the user is +k, prevent a deop from local user */
1099 if (whatt == MODE_DEL && IsChannelService(who) &&
1100 MyUser(cptr) && *curr == 'o')
1102 sendto_one(cptr, err_str(ERR_ISCHANSERVICE), me.name,
1103 cptr->name, parv[0], chptr->chname);
1106 if (whatt == MODE_ADD)
1108 lp = &chops[opcnt++];
1109 lp->value.cptr = who;
1110 if (IsServer(sptr) && (!(who->flags & FLAGS_TS8) || ((*curr == 'o') &&
1111 !(member->flags & (CHFL_SERVOPOK | CHFL_CHANOP)))))
1112 *badop = ((member->flags & CHFL_DEOPPED) && (*curr == 'o')) ? 2 : 3;
1113 lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
1114 lp->flags |= MODE_ADD;
1116 else if (whatt == MODE_DEL)
1118 lp = &chops[opcnt++];
1119 lp->value.cptr = who;
1120 doesdeop = 1; /* Also when -v */
1121 lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
1122 lp->flags |= MODE_DEL;
1131 /* check now so we eat the parameter if present */
1136 char *s = &(*parv)[-1];
1137 unsigned short count = KEYLEN + 1;
1139 while (*++s > ' ' && *s != ':' && --count);
1141 if (!**parv) /* nothing left in key */
1144 if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1146 if (whatt == MODE_ADD)
1148 if (*mode->key && !IsServer(cptr))
1149 sendto_one(cptr, err_str(ERR_KEYSET),
1150 me.name, cptr->name, chptr->chname);
1151 else if (!*mode->key || IsServer(cptr))
1153 lp = &chops[opcnt++];
1154 lp->value.cp = *parv;
1155 if (strlen(lp->value.cp) > (size_t)KEYLEN)
1156 lp->value.cp[KEYLEN] = '\0';
1157 lp->flags = MODE_KEY | MODE_ADD;
1161 else if (whatt == MODE_DEL)
1163 if (strCasediff(mode->key, *parv) == 0 || IsServer(cptr))
1165 lp = &chops[opcnt++];
1166 lp->value.cp = mode->key;
1167 lp->flags = MODE_KEY | MODE_DEL;
1175 if (banlsent) /* Only send it once */
1177 for (lp = chptr->banlist; lp; lp = lp->next)
1178 sendto_one(cptr, rpl_str(RPL_BANLIST), me.name, cptr->name,
1179 chptr->chname, lp->value.ban.banstr, lp->value.ban.who,
1180 lp->value.ban.when);
1181 sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST), me.name, cptr->name,
1191 if ((cp = strchr(*parv, ' ')))
1193 if (opcnt >= MAXMODEPARAMS || **parv == ':' || **parv == '\0')
1196 if (whatt == MODE_ADD)
1198 lp = &chops[opcnt++];
1199 lp->value.cp = *parv;
1200 lp->flags = MODE_ADD | MODE_BAN;
1202 else if (whatt == MODE_DEL)
1204 lp = &chops[opcnt++];
1205 lp->value.cp = *parv;
1206 lp->flags = MODE_DEL | MODE_BAN;
1211 * limit 'l' to only *1* change per mode command but
1216 if (whatt == MODE_ADD && --parc > 0)
1220 if (whatt == MODE_DEL)
1230 if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1232 if (!(nusers = atoi(*++parv)))
1234 lp = &chops[opcnt++];
1235 lp->flags = MODE_ADD | MODE_LIMIT;
1239 sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS),
1240 me.name, cptr->name, "MODE +l");
1242 case 'i': /* falls through for default case */
1243 if (whatt == MODE_DEL)
1244 while ((lp = chptr->invites))
1245 del_invite(lp->value.cptr, chptr);
1247 for (ip = flags; *ip; ip += 2)
1248 if (*(ip + 1) == *curr)
1253 if (whatt == MODE_ADD)
1255 if (*ip == MODE_PRIVATE)
1256 newmode &= ~MODE_SECRET;
1257 else if (*ip == MODE_SECRET)
1258 newmode &= ~MODE_PRIVATE;
1264 else if (!IsServer(cptr))
1265 sendto_one(cptr, err_str(ERR_UNKNOWNMODE),
1266 me.name, cptr->name, *curr);
1271 * Make sure mode strings such as "+m +t +p +i" are parsed
1274 if (!*curr && parc > 0)
1278 /* If this was from a server, and it is the last
1279 * parameter and it starts with a digit, it must
1280 * be the creationtime. --Run
1284 if (parc == 1 && isDigit(*curr))
1286 newtime = atoi(curr);
1287 if (newtime && chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
1289 chptr->creationtime = newtime;
1298 else if (newtime > chptr->creationtime)
1299 { /* It is a net-break ride if we have ops.
1300 bounce modes if we have ops. --Run */
1303 else if (chptr->creationtime == 0)
1305 if (chptr->creationtime == 0 || doesop)
1306 chptr->creationtime = newtime;
1314 * A legal *badop can occur when two
1315 * people join simultaneously a channel,
1316 * Allow for 10 min of lag (and thus hacking
1317 * on channels younger then 10 min) --Run
1319 else if (*badop == 0 ||
1320 chptr->creationtime > (TStime() - TS_LAG_TIME))
1322 if (newtime < chptr->creationtime)
1323 chptr->creationtime = newtime;
1332 } /* end of while loop for MODE processing */
1334 /* Now reject non chan ops */
1335 if (!IsServer(cptr) && (!tmp || !(tmp->flags & CHFL_CHANOP)))
1338 return (opcnt || newmode != mode->mode || limitset || keychange) ? 0 : -1;
1341 if (doesop && newtime == 0 && IsServer(sptr))
1345 (aconf = find_conf_host(cptr->confs, sptr->name, CONF_UWORLD)))
1348 bounce = (*badop == 1 || *badop == 2 || is_deopped(sptr, chptr)) ? 1 : 0;
1351 for (ip = flags; *ip; ip += 2)
1352 if ((*ip & newmode) && !(*ip & oldm.mode))
1356 if (bwhatt != MODE_DEL)
1361 *bmbuf++ = *(ip + 1);
1365 if (whatt != MODE_ADD)
1371 *mbuf++ = *(ip + 1);
1375 for (ip = flags; *ip; ip += 2)
1376 if ((*ip & oldm.mode) && !(*ip & newmode))
1380 if (bwhatt != MODE_ADD)
1385 *bmbuf++ = *(ip + 1);
1389 if (whatt != MODE_DEL)
1395 *mbuf++ = *(ip + 1);
1400 if (limitset && !nusers && mode->limit)
1404 if (bwhatt != MODE_ADD)
1410 sprintf(numeric, "%-15d", mode->limit);
1411 if ((cp = strchr(numeric, ' ')))
1413 strcat(bpbuf, numeric);
1414 blen += strlen(numeric);
1416 strcat(nbpbuf, numeric);
1417 nblen += strlen(numeric);
1418 strcat(nbpbuf, " ");
1422 if (whatt != MODE_DEL)
1427 mode->mode &= ~MODE_LIMIT;
1433 * Reconstruct "+bkov" chain.
1439 unsigned int prev_whatt = 0;
1441 for (; i < opcnt; i++)
1445 * make sure we have correct mode change sign
1447 if (whatt != (lp->flags & (MODE_ADD | MODE_DEL)))
1449 if (lp->flags & MODE_ADD)
1463 nlen = strlen(npbuf);
1465 * get c as the mode char and tmp as a pointer to
1466 * the parameter for this mode change.
1468 switch (lp->flags & MODE_WPARAS)
1472 cp = lp->value.cptr->name;
1476 cp = lp->value.cptr->name;
1480 * I made this a bit more user-friendly (tm):
1482 * nick!user = nick!user@*
1483 * user@host = *!user@host
1484 * host.name = *!*@host.name --Run
1487 cp = pretty_mask(lp->value.cp);
1495 sprintf(numeric, "%-15d", nusers);
1496 if ((cp = strchr(numeric, ' ')))
1502 /* What could be added: cp+' '+' '+<TS>+'\0' */
1503 if (len + strlen(cp) + 13 > (size_t)MODEBUFLEN ||
1504 nlen + strlen(cp) + NUMNICKLEN + 12 > (size_t)MODEBUFLEN)
1507 switch (lp->flags & MODE_WPARAS)
1510 if (strlen(cp) > (size_t)KEYLEN)
1511 *(cp + KEYLEN) = '\0';
1512 if ((whatt == MODE_ADD && (*mode->key == '\0' ||
1513 strCasediff(mode->key, cp) != 0)) ||
1514 (whatt == MODE_DEL && (*mode->key != '\0')))
1518 if (*mode->key == '\0')
1520 if (bwhatt != MODE_DEL)
1530 nblen += strlen(cp);
1531 strcat(nbpbuf, " ");
1536 if (bwhatt != MODE_ADD)
1541 strcat(bpbuf, mode->key);
1542 blen += strlen(mode->key);
1545 strcat(nbpbuf, mode->key);
1546 nblen += strlen(mode->key);
1547 strcat(nbpbuf, " ");
1552 if (*mbuf != '+' && *mbuf != '-')
1568 if (whatt == MODE_ADD)
1569 strncpy(mode->key, cp, KEYLEN);
1576 if (nusers && nusers != mode->limit)
1580 if (mode->limit == 0)
1582 if (bwhatt != MODE_DEL)
1590 if (bwhatt != MODE_ADD)
1595 sprintf(numeric, "%-15d", mode->limit);
1596 if ((cp = strchr(numeric, ' ')))
1598 strcat(bpbuf, numeric);
1599 blen += strlen(numeric);
1602 strcat(nbpbuf, numeric);
1603 nblen += strlen(numeric);
1604 strcat(nbpbuf, " ");
1609 if (*mbuf != '+' && *mbuf != '-')
1625 mode->limit = nusers;
1631 tmp = find_user_link(chptr->members, lp->value.cptr);
1632 if (lp->flags & MODE_ADD)
1634 change = (~tmp->flags) & CHFL_OVERLAP & lp->flags;
1635 if (change && bounce)
1637 if (lp->flags & MODE_CHANOP)
1638 tmp->flags |= CHFL_DEOPPED;
1639 if (bwhatt != MODE_DEL)
1645 strcat(bpbuf, lp->value.cptr->name);
1646 blen += strlen(lp->value.cptr->name);
1649 sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
1650 nblen += strlen(nbpbuf + nblen);
1655 tmp->flags |= lp->flags & CHFL_OVERLAP;
1656 if (lp->flags & MODE_CHANOP)
1658 tmp->flags &= ~CHFL_DEOPPED;
1660 tmp->flags &= ~CHFL_SERVOPOK;
1666 change = tmp->flags & CHFL_OVERLAP & lp->flags;
1667 if (change && bounce)
1669 if (lp->flags & MODE_CHANOP)
1670 tmp->flags &= ~CHFL_DEOPPED;
1671 if (bwhatt != MODE_ADD)
1677 strcat(bpbuf, lp->value.cptr->name);
1678 blen += strlen(lp->value.cptr->name);
1681 sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
1682 blen += strlen(bpbuf + blen);
1687 tmp->flags &= ~change;
1688 if ((change & MODE_CHANOP) && IsServer(sptr))
1689 tmp->flags |= CHFL_DEOPPED;
1692 if (change || *badop == 2 || *badop == 4)
1699 sprintf_irc(npbuf + nlen, "%s%s ", NumNick(lp->value.cptr));
1700 nlen += strlen(npbuf + nlen);
1701 npbuf[nlen++] = ' ';
1707 if (*mbuf != '+' && *mbuf != '-')
1715 * Only bans aren't bounced, it makes no sense to bounce last second
1716 * bans while propagating bans done before the net.rejoin. The reason
1717 * why I don't bounce net.rejoin bans is because it is too much
1718 * work to take care of too long strings adding the necessary TS to
1719 * net.burst bans -- RunLazy
1720 * We do have to check for *badop==2 now, we don't want HACKs to take
1723 * Since BURST - I *did* implement net.rejoin ban bouncing. So now it
1724 * certainly makes sense to also bounce 'last second' bans (bans done
1725 * after the net.junction). -- RunHardWorker
1727 if ((change = (whatt & MODE_ADD) &&
1728 !add_banid(sptr, chptr, cp, !bounce, !add_banid_called)))
1729 add_banid_called = 1;
1731 change = (whatt & MODE_DEL) && !del_banid(chptr, cp, !bounce);
1733 if (bounce && change)
1736 if ((whatt & MODE_ADD))
1738 if (bwhatt != MODE_DEL)
1744 else if ((whatt & MODE_DEL))
1746 if (bwhatt != MODE_ADD)
1758 nblen += strlen(cp);
1759 strcat(nbpbuf, " ");
1777 if (*mbuf != '+' && *mbuf != '-')
1784 } /* for (; i < opcnt; i++) */
1791 if (!hacknotice && *bmodebuf && chptr->creationtime)
1793 if (Protocol(cptr) < 10)
1794 sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
1795 me.name, chptr->chname, bmodebuf, bparambuf,
1796 *badop == 2 ? (time_t) 0 : chptr->creationtime);
1798 sendto_one(cptr, "%s MODE %s %s %s " TIME_T_FMT,
1799 NumServ(&me), chptr->chname, bmodebuf, nbparambuf,
1800 *badop == 2 ? (time_t) 0 : chptr->creationtime);
1802 /* If there are possibly bans to re-add, bounce them now */
1803 if (add_banid_called && bounce)
1805 Link *ban[6]; /* Max 6 bans at a time */
1806 size_t len[6], sblen, total_len;
1807 int cnt, delayed = 0;
1808 while (delayed || (ban[0] = next_overlapped_ban()))
1810 len[0] = strlen(ban[0]->value.ban.banstr);
1811 cnt = 1; /* We already got one ban :) */
1812 sblen = sprintf_irc(sendbuf, ":%s MODE %s +b",
1813 me.name, chptr->chname) - sendbuf;
1814 total_len = sblen + 1 + len[0]; /* 1 = ' ' */
1815 /* Find more bans: */
1817 while (cnt < 6 && (ban[cnt] = next_overlapped_ban()))
1819 len[cnt] = strlen(ban[cnt]->value.ban.banstr);
1820 if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
1822 delayed = cnt + 1; /* != 0 */
1825 sendbuf[sblen++] = 'b';
1826 total_len += 2 + len[cnt++]; /* 2 = "b " */
1830 sendbuf[sblen++] = ' ';
1831 strcpy(sendbuf + sblen, ban[cnt]->value.ban.banstr);
1834 sendbufto_one(cptr); /* Send bounce to uplink */
1836 ban[0] = ban[delayed - 1];
1839 /* Send -b's of overlapped bans to clients to keep them synchronized */
1840 if (add_banid_called && !bounce)
1843 char *banstr[6]; /* Max 6 bans at a time */
1844 size_t len[6], sblen, psblen, total_len;
1845 int cnt, delayed = 0;
1849 psblen = sprintf_irc(sendbuf, ":%s MODE %s -b",
1850 sptr->name, chptr->chname) - sendbuf;
1851 else /* We rely on IsRegistered(sptr) being true for MODE */
1852 psblen = sprintf_irc(sendbuf, ":%s!%s@%s MODE %s -b", sptr->name,
1853 sptr->user->username, sptr->user->host, chptr->chname) - sendbuf;
1854 while (delayed || (ban = next_removed_overlapped_ban()))
1858 len[0] = strlen((banstr[0] = ban->value.ban.banstr));
1859 ban->value.ban.banstr = NULL;
1861 cnt = 1; /* We already got one ban :) */
1863 total_len = sblen + 1 + len[0]; /* 1 = ' ' */
1864 /* Find more bans: */
1866 while (cnt < 6 && (ban = next_removed_overlapped_ban()))
1868 len[cnt] = strlen((banstr[cnt] = ban->value.ban.banstr));
1869 ban->value.ban.banstr = NULL;
1870 if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
1872 delayed = cnt + 1; /* != 0 */
1875 sendbuf[sblen++] = 'b';
1876 total_len += 2 + len[cnt++]; /* 2 = "b " */
1880 sendbuf[sblen++] = ' ';
1881 strcpy(sendbuf + sblen, banstr[cnt]);
1882 RunFree(banstr[cnt]);
1885 for (lp = chptr->members; lp; lp = lp->next)
1886 if (MyConnect(acptr = lp->value.cptr) && !(lp->flags & CHFL_ZOMBIE))
1887 sendbufto_one(acptr);
1890 banstr[0] = banstr[delayed - 1];
1891 len[0] = len[delayed - 1];
1896 return gotts ? 1 : -1;
1899 /* We are now treating the <key> part of /join <channel list> <key> as a key
1900 * ring; that is, we try one key against the actual channel key, and if that
1901 * doesn't work, we try the next one, and so on. -Kev -Texaco
1902 * Returns: 0 on match, 1 otherwise
1903 * This version contributed by SeKs <intru@info.polymtl.ca>
1905 static int compall(char *key, char *keyring)
1910 p1 = key; /* point to the key... */
1911 while (*p1 && *p1 == *keyring)
1912 { /* step through the key and ring until they
1918 if (!*p1 && (!*keyring || *keyring == ','))
1919 /* ok, if we're at the end of the and also at the end of one of the keys
1920 in the keyring, we have a match */
1923 if (!*keyring) /* if we're at the end of the key ring, there
1924 weren't any matches, so we return 1 */
1927 /* Not at the end of the key ring, so step
1928 through to the next key in the ring: */
1929 while (*keyring && *(keyring++) != ',');
1931 goto top; /* and check it against the key */
1934 static int can_join(aClient *sptr, aChannel *chptr, char *key)
1938 /* Now a banned user CAN join if invited -- Nemesi */
1939 /* Now a user CAN escape channel limit if invited -- bfriendly */
1940 if ((chptr->mode.mode & MODE_INVITEONLY) || (is_banned(sptr, chptr, NULL)
1941 || (chptr->mode.limit && chptr->users >= chptr->mode.limit)))
1943 for (lp = sptr->user->invited; lp; lp = lp->next)
1944 if (lp->value.chptr == chptr)
1948 if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1949 return (ERR_CHANNELISFULL);
1950 /* This can return an "Invite only" msg instead of the "You are banned"
1951 if _both_ conditions are true, but who can say what is more
1952 appropriate ? checking again IsBanned would be _SO_ cpu-xpensive ! */
1953 return ((chptr->mode.mode & MODE_INVITEONLY) ?
1954 ERR_INVITEONLYCHAN : ERR_BANNEDFROMCHAN);
1958 /* now using compall (above) to test against a whole key ring -Kev */
1959 if (*chptr->mode.key && (BadPtr(key) || compall(chptr->mode.key, key)))
1960 return (ERR_BADCHANNELKEY);
1966 * Remove bells and commas from channel name
1969 static void clean_channelname(char *cn)
1984 /* Missed the Icelandic letter ETH last time: */
1985 if ((unsigned char)(*cn) == 0xd0)
1993 * Get Channel block for i (and allocate a new channel
1994 * block, if it didn't exists before).
1996 static aChannel *get_channel(aClient *cptr, char *chname, int flag)
1998 Reg1 aChannel *chptr;
2004 len = strlen(chname);
2005 if (MyUser(cptr) && len > CHANNELLEN)
2008 *(chname + CHANNELLEN) = '\0';
2010 if ((chptr = FindChannel(chname)))
2014 chptr = (aChannel *)RunMalloc(sizeof(aChannel) + len);
2016 memset(chptr, 0, sizeof(aChannel));
2017 strcpy(chptr->chname, chname);
2019 channel->prevch = chptr;
2020 chptr->prevch = NULL;
2021 chptr->nextch = channel;
2022 chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
2029 static void add_invite(aClient *cptr, aChannel *chptr)
2031 Reg1 Link *inv, **tmp;
2033 del_invite(cptr, chptr);
2035 * Delete last link in chain if the list is max length
2037 if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
2038 del_invite(cptr, cptr->user->invited->value.chptr);
2040 * Add client to channel invite list
2043 inv->value.cptr = cptr;
2044 inv->next = chptr->invites;
2045 chptr->invites = inv;
2047 * Add channel to the end of the client invite list
2049 for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next));
2051 inv->value.chptr = chptr;
2057 * Delete Invite block from channel invite list and client invite list
2059 void del_invite(aClient *cptr, aChannel *chptr)
2061 Reg1 Link **inv, *tmp;
2063 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
2064 if (tmp->value.cptr == cptr)
2071 for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
2072 if (tmp->value.chptr == chptr)
2080 /* List and skip all channels that are listen */
2081 void list_next_channels(aClient *cptr, int nr)
2083 aListingArgs *args = cptr->listing;
2084 aChannel *chptr = args->chptr;
2085 chptr->mode.mode &= ~MODE_LISTED;
2086 while (is_listed(chptr) || --nr >= 0)
2088 for (; chptr; chptr = chptr->nextch)
2090 if (!cptr->user || (SecretChannel(chptr) && !IsMember(cptr, chptr)))
2092 if (chptr->users > args->min_users && chptr->users < args->max_users &&
2093 chptr->creationtime > args->min_time &&
2094 chptr->creationtime < args->max_time &&
2095 (!args->topic_limits || (*chptr->topic &&
2096 chptr->topic_time > args->min_topic_time &&
2097 chptr->topic_time < args->max_topic_time)))
2099 sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
2100 ShowChannel(cptr, chptr) ? chptr->chname : "*",
2101 chptr->users, ShowChannel(cptr, chptr) ? chptr->topic : "");
2102 chptr = chptr->nextch;
2108 RunFree(cptr->listing);
2109 cptr->listing = NULL;
2110 sendto_one(cptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
2116 cptr->listing->chptr = chptr;
2117 chptr->mode.mode |= MODE_LISTED;
2122 * Subtract one user from channel i (and free channel
2123 * block, if channel became empty).
2125 static void sub1_from_channel(aChannel *chptr)
2130 if (chptr->users > 1) /* Can be 0, called for an empty channel too */
2136 /* Channel became (or was) empty: Remove channel */
2137 if (is_listed(chptr))
2140 for (i = 0; i <= highest_fd; i++)
2143 if ((acptr = loc_clients[i]) && acptr->listing &&
2144 acptr->listing->chptr == chptr)
2146 list_next_channels(acptr, 1);
2147 break; /* Only one client can list a channel */
2152 * Now, find all invite links from channel structure
2154 while ((tmp = chptr->invites))
2155 del_invite(tmp->value.cptr, chptr);
2157 tmp = chptr->banlist;
2162 RunFree(obtmp->value.ban.banstr);
2163 RunFree(obtmp->value.ban.who);
2167 chptr->prevch->nextch = chptr->nextch;
2169 channel = chptr->nextch;
2171 chptr->nextch->prevch = chptr->prevch;
2174 RunFree((char *)chptr);
2180 * parv[0] = sender prefix
2182 * parv[2] = channel keys (client), or channel TS (server)
2184 int m_join(aClient *cptr, aClient *sptr, int parc, char *parv[])
2186 static char jbuf[BUFSIZE], mbuf[BUFSIZE];
2188 Reg3 aChannel *chptr;
2189 Reg4 char *name, *keysOrTS = NULL;
2190 int i = 0, zombie = 0, sendcreate = 0;
2191 unsigned int flags = 0;
2192 size_t jlen = 0, mlen = 0;
2194 char *p = NULL, *bufptr;
2196 if (parc < 2 || *parv[1] == '\0')
2198 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "JOIN");
2202 for (p = parv[1]; *p; p++) /* find the last "JOIN 0" in the line -Kev */
2204 && (*(p + 1) == ',' || *(p + 1) == '\0' || !isIrcCh(*(p + 1))))
2206 /* If it's a single "0", remember the place; we will start parsing
2207 the channels after the last 0 in the line -Kev */
2214 { /* Step through to the next comma or until the
2215 end of the line, in an attempt to save CPU
2217 while (*p != ',' && *p != '\0')
2223 keysOrTS = parv[2]; /* Remember where our keys are or the TS is;
2224 parv[2] needs to be NULL for the call to
2225 m_names below -Kev */
2228 *jbuf = *mbuf = '\0'; /* clear both join and mode buffers -Kev */
2230 * Rebuild list of channels joined to be the actual result of the
2231 * JOIN. Note that "JOIN 0" is the destructive problem.
2233 for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ","))
2236 if (MyConnect(sptr))
2237 clean_channelname(name);
2238 else if (IsLocalChannel(name))
2240 if (*name == '0' && *(name + 1) == '\0')
2242 /* Remove the user from all his channels -Kev */
2243 while ((lp = sptr->user->channel))
2245 chptr = lp->value.chptr;
2246 if (!is_zombie(sptr, chptr))
2247 sendto_channel_butserv(chptr, sptr, PartFmt2,
2248 parv[0], chptr->chname, "Left all channels");
2249 remove_user_from_channel(sptr, chptr);
2252 *mbuf = *jbuf = '\0';
2256 { /* not a /join 0, so treat it as
2257 a /join #channel -Kev */
2258 if (!IsChannelName(name))
2261 sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
2265 if (MyConnect(sptr))
2268 * Local client is first to enter previously nonexistant
2269 * channel so make them (rightfully) the Channel Operator.
2270 * This looks kind of ugly because we try to avoid calling the strlen()
2272 if (ChannelExists(name))
2274 flags = CHFL_DEOPPED;
2277 else if (strlen(name) > CHANNELLEN)
2279 *(name + CHANNELLEN) = '\0';
2280 if (ChannelExists(name))
2282 flags = CHFL_DEOPPED;
2287 flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
2293 flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
2297 if (sptr->user->joined >= MAXCHANNELSPERUSER)
2299 chptr = get_channel(sptr, name, !CREATE);
2300 sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
2301 me.name, parv[0], chptr ? chptr->chname : name);
2302 break; /* Can't return, else he won't get on ANY
2303 channels! Break out of the for loop instead.
2307 chptr = get_channel(sptr, name, CREATE);
2308 if (chptr && (lp = find_user_link(chptr->members, sptr)))
2310 if (lp->flags & CHFL_ZOMBIE)
2313 flags = lp->flags & (CHFL_DEOPPED | CHFL_SERVOPOK);
2314 remove_user_from_channel(sptr, chptr);
2315 chptr = get_channel(sptr, name, CREATE);
2320 name = chptr->chname;
2321 if (!chptr->creationtime) /* A remote JOIN created this channel ? */
2322 chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
2325 if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
2326 chptr->creationtime = atoi(keysOrTS);
2328 parc = 2; /* Don't pass it on */
2332 if (!MyConnect(sptr))
2333 flags = CHFL_DEOPPED;
2334 if (sptr->flags & FLAGS_TS8)
2335 flags |= CHFL_SERVOPOK;
2337 if (MyConnect(sptr))
2339 int created = chptr->users == 0;
2340 if (check_target_limit(sptr, chptr, chptr->chname, created))
2342 if (created) /* Did we create the channel? */
2343 sub1_from_channel(chptr); /* Remove it again! */
2346 if ((i = can_join(sptr, chptr, keysOrTS)))
2348 sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
2353 * Complete user entry to the new channel (if any)
2355 add_user_to_channel(chptr, sptr, flags);
2358 * Notify all other users on the new channel
2360 sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
2364 del_invite(sptr, chptr);
2365 if (chptr->topic[0] != '\0')
2367 sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
2368 parv[0], name, chptr->topic);
2369 sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
2370 chptr->topic_nick, chptr->topic_time);
2373 m_names(cptr, sptr, 2, parv);
2377 /* Select proper buffer; mbuf for creation, jbuf otherwise */
2380 continue; /* Head off local channels at the pass */
2382 bufptr = (sendcreate == 0) ? jbuf : mbuf;
2383 buflen = (sendcreate == 0) ? &jlen : &mlen;
2385 if (*buflen < BUFSIZE - len - 2)
2389 strcat(bufptr, ","); /* Add to join buf */
2392 strncat(bufptr, name, BUFSIZE - *buflen - 1);
2395 sendcreate = 0; /* Reset sendcreate */
2398 #ifndef NO_PROTOCOL9
2399 if (*jbuf || *mbuf) /* Propagate joins to P09 servers */
2400 sendto_lowprot_butone(cptr, 9, (*jbuf && *mbuf) ? ":%s JOIN %s,%s" :
2401 ":%s JOIN %s%s", parv[0], jbuf, mbuf);
2404 if (*jbuf) /* Propgate joins to P10 servers */
2406 sendto_serv_butone(cptr,
2407 parc > 2 ? ":%s JOIN %s %s" : ":%s JOIN %s", parv[0], jbuf, keysOrTS);
2409 sendto_highprot_butone(cptr, 10,
2410 parc > 2 ? ":%s JOIN %s %s" : ":%s JOIN %s", parv[0], jbuf, keysOrTS);
2412 if (*mbuf) /* and now creation events */
2414 sendto_serv_butone(cptr, "%s%s CREATE %s " TIME_T_FMT,
2415 NumNick(sptr), mbuf, TStime());
2417 sendto_highprot_butone(cptr, 10, "%s%s CREATE %s " TIME_T_FMT,
2418 NumNick(sptr), mbuf, TStime());
2422 { /* shouldn't ever set TS for remote JOIN's */
2424 { /* check for channels that need TS's */
2426 for (name = strtoken(&p, jbuf, ","); name; name = strtoken(&p, NULL, ","))
2428 chptr = get_channel(sptr, name, !CREATE);
2429 if (chptr && chptr->mode.mode & MODE_SENDTS)
2431 sendto_serv_butone(cptr, ":%s MODE %s + " TIME_T_FMT, me.name,
2432 chptr->chname, chptr->creationtime); /* ok, send TS */
2433 chptr->mode.mode &= ~MODE_SENDTS; /* reset flag */
2439 { /* ok, send along modes for creation events to P9 */
2441 for (name = strtoken(&p, mbuf, ","); name; name = strtoken(&p, NULL, ","))
2443 chptr = get_channel(sptr, name, !CREATE);
2444 sendto_lowprot_butone(cptr, 9, ":%s MODE %s +o %s " TIME_T_FMT,
2445 me.name, chptr->chname, parv[0], chptr->creationtime);
2455 * parv[0] = sender prefix
2456 * parv[1] = channel channelname
2457 * parv[2] = channel time stamp
2459 * This function does nothing, it does passes DESTRUCT to the other servers.
2460 * In the future we will start to use this message.
2463 int m_destruct(aClient *cptr, aClient *sptr, int parc, char *parv[])
2465 time_t chanTS; /* Creation time of the channel */
2467 if (parc < 3 || *parv[2] == '\0')
2471 /* Allow DESTRUCT from user */
2477 /* sanity checks: Only accept DESTRUCT messages from servers */
2478 if (!IsServer(sptr))
2481 /* Don't pass on DESTRUCT messages for channels that exist */
2482 if (FindChannel(parv[1]))
2485 chanTS = atoi(parv[2]);
2487 /* Pass on DESTRUCT message */
2488 sendto_highprot_butone(cptr, 10, "%s DESTRUCT %s " TIME_T_FMT,
2489 NumServ(sptr), parv[1], chanTS);
2497 * parv[0] = sender prefix
2498 * parv[1] = channel names
2499 * parv[2] = channel time stamp
2501 int m_create(aClient *cptr, aClient *sptr, int parc, char *parv[])
2503 char cbuf[BUFSIZE]; /* Buffer for list with channels
2504 that `sptr' really creates */
2505 time_t chanTS; /* Creation time for all channels
2506 in the comma seperated list */
2508 Reg5 aChannel *chptr;
2511 /* sanity checks: Only accept CREATE messages from servers */
2512 if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
2515 chanTS = atoi(parv[2]);
2517 *cbuf = '\0'; /* Start with empty buffer */
2519 /* For each channel in the comma seperated list: */
2520 for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ","))
2522 badop = 0; /* Default is to accept the op */
2523 if ((chptr = FindChannel(name)))
2525 name = chptr->chname;
2526 if (TStime() - chanTS > TS_LAG_TIME)
2528 /* A bounce would not be accepted anyway - if we get here something
2529 is wrong with the TS clock syncing (or we have more then
2530 TS_LAG_TIME lag, or an admin is hacking */
2532 /* This causes a HACK notice on all upstream servers: */
2533 if (Protocol(cptr) < 10)
2534 sendto_one(cptr, ":%s MODE %s -o %s 0", me.name, name, sptr->name);
2536 sendto_one(cptr, ":%s MODE %s -o %s%s 0",
2537 me.name, name, NumNick(sptr));
2538 /* This causes a WALLOPS on all downstream servers and a notice to our
2540 parv[1] = name; /* Corrupt parv[1], it is not used anymore anyway */
2541 send_hack_notice(cptr, sptr, parc, parv, badop, 2);
2543 else if (chptr->creationtime && chanTS > chptr->creationtime &&
2544 chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
2546 /* We (try) to bounce the mode, because the CREATE is used on an older
2547 channel, probably a net.ride */
2549 /* Send a deop upstream: */
2550 if (Protocol(cptr) < 10)
2551 sendto_one(cptr, ":%s MODE %s -o %s " TIME_T_FMT, me.name,
2552 name, sptr->name, chptr->creationtime);
2554 sendto_one(cptr, ":%s MODE %s -o %s%s " TIME_T_FMT, me.name,
2555 name, NumNick(sptr), chptr->creationtime);
2558 else /* Channel doesn't exist: create it */
2559 chptr = get_channel(sptr, name, CREATE);
2561 /* Add and mark ops */
2562 add_user_to_channel(chptr, sptr,
2563 (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
2565 /* Send user join to the local clients (if any) */
2566 sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
2568 if (badop) /* handle badop: convert CREATE into JOIN */
2569 sendto_serv_butone(cptr, ":%s JOIN %s " TIME_T_FMT,
2570 sptr->name, name, chptr->creationtime);
2573 /* Send the op to local clients:
2574 (if any; extremely unlikely, but it CAN happen) */
2575 if (!IsModelessChannel(name))
2576 sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
2577 sptr->user->server->name, name, parv[0]);
2579 /* Set/correct TS and add the channel to the
2580 buffer for accepted channels: */
2581 chptr->creationtime = chanTS;
2588 if (*cbuf) /* Any channel accepted with ops ? */
2591 sendto_serv_butone(cptr, "%s%s CREATE %s " TIME_T_FMT,
2592 NumNick(sptr), cbuf, chanTS);
2594 /* send CREATEs to 2.10 servers */
2595 sendto_highprot_butone(cptr, 10, "%s%s CREATE %s " TIME_T_FMT,
2596 NumNick(sptr), cbuf, chanTS);
2598 /* And JOIN + MODE to 2.9 servers; following
2599 is not needed after all are 2.10 */
2600 sendto_lowprot_butone(cptr, 9, ":%s JOIN %s", parv[0], cbuf);
2602 for (name = strtoken(&p, cbuf, ","); name; name = strtoken(&p, NULL, ","))
2603 sendto_lowprot_butone(cptr, 9, ":%s MODE %s +o %s " TIME_T_FMT,
2604 sptr->user->server->name, name, parv[0], chanTS);
2611 static size_t prefix_len;
2613 static void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
2614 int *send_itp, char is_a_ban, int mode)
2616 int first = *firstp;
2619 * Heh - we do not need to test if it still fits in the buffer, because
2620 * this BURST message is reconstructed from another BURST message, and
2621 * it only can become smaller. --Run
2624 if (*firstp) /* First token in this parameter ? */
2628 *send_itp = 1; /* Buffer contains data to be sent */
2629 sendbuf[(*sblenp)++] = ' ';
2632 sendbuf[(*sblenp)++] = ':'; /* Bans are always the last "parv" */
2633 sendbuf[(*sblenp)++] = is_a_ban;
2636 else /* Of course, 'send_it' is already set here */
2637 /* Seperate banmasks with a space because
2638 they can contain commas themselfs: */
2639 sendbuf[(*sblenp)++] = is_a_ban ? ' ' : ',';
2640 strcpy(sendbuf + *sblenp, token);
2641 *sblenp += strlen(token);
2642 if (!is_a_ban) /* nick list ? Need to take care
2643 of modes for nicks: */
2645 static int last_mode = 0;
2646 mode &= CHFL_CHANOP | CHFL_VOICE;
2649 if (last_mode != mode) /* Append mode like ':ov' if changed */
2652 sendbuf[(*sblenp)++] = ':';
2653 if (mode & CHFL_CHANOP)
2654 sendbuf[(*sblenp)++] = 'o';
2655 if (mode & CHFL_VOICE)
2656 sendbuf[(*sblenp)++] = 'v';
2658 sendbuf[*sblenp] = '\0';
2662 static void cancel_mode(aClient *sptr, aChannel *chptr, char m,
2663 const char *param, int *count)
2665 static char *pb, *sbp, *sbpi;
2666 int paramdoesntfit = 0;
2667 if (*count == -1) /* initialize ? */
2670 sprintf_irc(sendbuf, ":%s MODE %s -", sptr->name, chptr->chname);
2674 /* m == 0 means flush */
2679 size_t nplen = strlen(param);
2680 if (pb - parabuf + nplen + 23 > MODEBUFLEN)
2694 else if (*count == 0)
2696 if (*count == 6 || !m || paramdoesntfit)
2698 #ifndef NO_PROTOCOL9
2703 strcpy(sbp, parabuf);
2704 #ifndef NO_PROTOCOL9
2705 sbe = sbp + strlen(parabuf);
2707 for (member = chptr->members; member; member = member->next)
2708 if (MyUser(member->value.cptr))
2709 sendbufto_one(member->value.cptr);
2710 #ifndef NO_PROTOCOL9
2711 sprintf_irc(sbe, " " TIME_T_FMT, chptr->creationtime);
2712 /* Send 'sendbuf' to all 2.9 downlinks: */
2713 for (lp = me.serv->down; lp; lp = lp->next)
2714 if (Protocol(lp->value.cptr) < 10)
2715 sendbufto_one(lp->value.cptr);
2726 pb += strlen(param);
2732 * m_burst -- by Run carlo@runaway.xs4all.nl december 1995 till march 1997
2734 * parv[0] = sender prefix
2735 * parv[1] = channel name
2736 * parv[2] = channel timestamp
2737 * The meaning of the following parv[]'s depend on their first character:
2738 * If parv[n] starts with a '+':
2739 * Net burst, additive modes
2741 * parv[n+1] = <param> (optional)
2742 * parv[n+2] = <param> (optional)
2743 * If parv[n] starts with a '%', then n will be parc-1:
2744 * parv[n] = %<ban> <ban> <ban> ...
2745 * If parv[n] starts with another character:
2746 * parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
2747 * where <mode> is the channel mode (ov) of nick and all following nicks.
2750 * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
2752 * Anti net.ride code.
2754 * When the channel already exist, and its TS is larger then
2755 * the TS in the BURST message, then we cancel all existing modes.
2756 * If its is smaller then the received BURST message is ignored.
2757 * If it's equal, then the received modes are just added.
2759 int m_burst(aClient *cptr, aClient *sptr, int parc, char *parv[])
2761 Reg1 aChannel *chptr;
2763 int netride = 0, wipeout = 0, n;
2764 int send_it = 0, add_banid_not_called = 1;
2766 size_t sblen, mblen = 0;
2767 int mblen2, pblen2, cnt;
2769 char prev_key[KEYLEN + 1];
2771 #ifndef NO_PROTOCOL9
2775 /* BURST is only for servers and has at least 4 parameters */
2776 if (!IsServer(cptr) || parc < 4)
2783 if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
2786 sprintf_irc(sendbuf,
2787 ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
2788 sptr->name, parv[1], parv[2]);
2789 for (i = 3; i < parc - 1; ++i)
2790 p = sprintf_irc(p, " %s", parv[i]);
2791 sprintf_irc(p, " :%s", parv[parc - 1]);
2792 sendbufto_op_mask(SNO_HACK4);
2796 #if 1 /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
2798 if (MyConnect(sptr))
2800 return exit_client_msg(cptr, cptr, &me,
2801 "HACK: BURST message outside net.burst from %s", sptr->name);
2805 /* Find the channel, or create it - note that the creation time
2806 * will be 0 if it has to be created */
2807 chptr = get_channel(sptr, parv[1], CREATE);
2808 current_mode = &chptr->mode;
2809 prev_mode = chptr->mode.mode;
2810 if (*chptr->mode.key)
2812 prev_mode |= MODE_KEY;
2813 strcpy(prev_key, chptr->mode.key);
2815 if (chptr->mode.limit)
2816 prev_mode |= MODE_LIMIT;
2818 timestamp = atoi(parv[2]);
2820 /* Copy the new TS when the received creationtime appears to be older */
2821 if (!chptr->creationtime || chptr->creationtime > timestamp)
2823 /* Set the new timestamp */
2824 chptr->creationtime = timestamp;
2825 send_it = 1; /* Make sure we pass on the different timestamp ! */
2826 /* Mark all bans as needed to be wiped out */
2827 for (lp = chptr->banlist; lp; lp = lp->next)
2828 lp->flags |= CHFL_BURST_BAN_WIPEOUT;
2830 * Only the first BURST for this channel can have creationtime > timestamp,
2831 * so at this moment ALL members are on OUR side, and thus all net.riders:
2835 for (lp = chptr->members; lp; lp = lp->next)
2836 lp->flags &= ~CHFL_BURST_JOINED; /* Set later for nicks in the BURST msg */
2837 /* If `wipeout' is set then these will be deopped later. */
2839 /* If the entering creationtime is younger, ignore the modes */
2840 if (chptr->creationtime < timestamp)
2841 netride = 1; /* Only pass on the nicks (so they JOIN) */
2843 /* Prepare buffers to pass the message */
2844 *bparambuf = *bmodebuf = *parabuf = '\0';
2849 prefix_len = sblen = sprintf_irc(sendbuf, "%s BURST %s " TIME_T_FMT,
2850 NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
2852 /* Run over all remaining parameters */
2853 for (n = 3; n < parc; n++)
2854 switch (*parv[n]) /* What type is it ? mode, nicks or bans ? */
2856 case '+': /* modes */
2859 while (*(++p)) /* Run over all mode characters */
2861 switch (*p) /* which mode ? */
2864 * The following cases all do the following:
2865 * - In case wipeout needed, reset 'prev_mode' to indicate this
2866 * mode should not be cancelled.
2867 * - If wipeout or (not netride and the new mode is a change),
2868 * add it to bmodebuf and bparabuf for propagation.
2870 * - Add it to modebuf and parabuf for propagation to the
2871 * clients when not netride and the new mode is a change.
2873 * - If a +s is received, cancel a +p and sent a -p to the
2874 * clients too (if +p was set).
2875 * - If a +p is received and +s is set, ignore the +p.
2880 prev_mode &= ~MODE_INVITEONLY;
2881 if (!(tmp = netride ||
2882 (current_mode->mode & MODE_INVITEONLY)) || wipeout)
2884 bmodebuf[mblen++] = 'i';
2885 current_mode->mode |= MODE_INVITEONLY;
2888 modebuf[mblen2++] = 'i';
2894 char *param = parv[++n];
2895 prev_mode &= ~MODE_KEY;
2896 if (!(tmp = netride || (*current_mode->key &&
2897 (!strcmp(current_mode->key, param) ||
2898 (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
2901 bmodebuf[mblen++] = 'k';
2902 strcat(bparambuf, " ");
2903 strcat(bparambuf, param);
2904 strncpy(current_mode->key, param, KEYLEN);
2906 if (!tmp && !wipeout)
2908 modebuf[mblen2++] = 'k';
2909 parabuf[pblen2++] = ' ';
2910 strcpy(parabuf + pblen2, param);
2911 pblen2 += strlen(param);
2919 unsigned int param = atoi(parv[++n]);
2920 prev_mode &= ~MODE_LIMIT;
2921 if (!(tmp = netride || (current_mode->limit &&
2922 (current_mode->limit == param ||
2923 (!wipeout && current_mode->limit < param)))) || wipeout)
2925 bmodebuf[mblen++] = 'l';
2926 sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
2927 current_mode->limit = param;
2931 modebuf[mblen2++] = 'l';
2932 pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
2940 prev_mode &= ~MODE_MODERATED;
2941 if (!(tmp = netride ||
2942 (current_mode->mode & MODE_MODERATED)) || wipeout)
2944 bmodebuf[mblen++] = 'm';
2945 current_mode->mode |= MODE_MODERATED;
2948 modebuf[mblen2++] = 'm';
2954 prev_mode &= ~MODE_NOPRIVMSGS;
2955 if (!(tmp = netride ||
2956 (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
2958 bmodebuf[mblen++] = 'n';
2959 current_mode->mode |= MODE_NOPRIVMSGS;
2962 modebuf[mblen2++] = 'n';
2970 if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
2973 prev_mode &= ~MODE_PRIVATE;
2974 if (!(tmp = netride ||
2975 (current_mode->mode & MODE_PRIVATE)) || wipeout)
2977 bmodebuf[mblen++] = 'p';
2978 current_mode->mode |= MODE_PRIVATE;
2981 modebuf[mblen2++] = 'p';
2987 prev_mode &= ~MODE_SECRET;
2988 if (!(tmp = netride ||
2989 (current_mode->mode & MODE_SECRET)) || wipeout)
2991 bmodebuf[mblen++] = 's';
2992 current_mode->mode |= MODE_SECRET;
2995 modebuf[mblen2++] = 's';
2998 if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
3001 for (i = mblen2 - 1; i >= 0; --i)
3002 modebuf[i + 2] = modebuf[i];
3006 current_mode->mode &= ~MODE_PRIVATE;
3014 prev_mode &= ~MODE_TOPICLIMIT;
3015 if (!(tmp = netride ||
3016 (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
3018 bmodebuf[mblen++] = 't';
3019 current_mode->mode |= MODE_TOPICLIMIT;
3022 modebuf[mblen2++] = 't';
3026 } /* <-- while over all modes */
3028 bmodebuf[mblen] = '\0';
3029 sendbuf[sblen] = '\0';
3030 if (mblen) /* Anything to send at all ? */
3033 strcpy(sendbuf + sblen, " +");
3035 strcpy(sendbuf + sblen, bmodebuf);
3037 strcpy(sendbuf + sblen, bparambuf);
3038 sblen += strlen(bparambuf);
3040 break; /* Done mode part */
3042 case '%': /* bans */
3044 char *pv, *p = NULL, *ban;
3047 break; /* Ignore bans */
3048 /* Run over all bans */
3049 for (pv = parv[n] + 1; (ban = strtoken(&p, pv, " ")); pv = NULL)
3053 * The following part should do the following:
3054 * - If the new (un)ban is not a _change_ it is ignored.
3055 * - Else, add it to sendbuf for later use.
3056 * - If sendbuf is full, send it, and prepare a new
3057 * message in sendbuf.
3059 ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
3062 add_banid_not_called = 0;
3063 /* Mark this new ban so we can send it to the clients later */
3064 chptr->banlist->flags |= CHFL_BURST_BAN;
3067 /* A new ban was added or an existing one needs to be passed on.
3068 * Also add it to sendbuf: */
3069 add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
3071 break; /* Done bans part */
3073 default: /* nicks */
3075 char *pv, *p = NULL, *nick, *ptr;
3078 int default_mode = CHFL_DEOPPED;
3079 /* Run over all nicks */
3080 for (pv = parv[n]; (nick = strtoken(&p, pv, ",")); pv = NULL)
3083 if ((ptr = strchr(nick, ':'))) /* New default mode ? */
3085 *ptr = '\0'; /* Fix 'nick' */
3086 acptr = findNUser(nick);
3089 /* Calculate new mode change: */
3090 default_mode = CHFL_DEOPPED;
3094 default_mode |= CHFL_CHANOP;
3095 default_mode &= ~CHFL_DEOPPED;
3097 else if (*ptr == 'v')
3098 default_mode |= CHFL_VOICE;
3104 acptr = findNUser(nick);
3106 * Note that at this point we already received a 'NICK' for any
3107 * <nick> numeric that is joining (and possibly opped) here.
3108 * Therefore we consider the following situations:
3109 * - The <nick> numeric exists and is from the direction of cptr: ok
3110 * - The <nick> numeric does not exist:
3111 * Apparently this previous <nick> numeric was killed (upstream)
3112 * or it collided with an existing <nick> name.
3113 * - The <nick> numeric exists but is from another direction:
3114 * Apparently this previous <nick> numeric was killed,
3115 * and due to a reroute it signed on via another link (probably
3116 * a nick [numeric] collision).
3117 * Note that it can't be a QUIT or SQUIT, because a QUIT would
3118 * come from the same direction as the BURST (cptr) while an
3119 * upstream SQUIT removes the source (server) and we would thus
3120 * have this BURST ignored already.
3121 * This means that if we find the nick and it is from the correct
3122 * direction, it joins. If it doesn't exist or is from another
3123 * direction, we have to ignore it. If all nicks are ignored, we
3124 * remove the channel again when it is empty and don't propagate
3125 * the BURST message.
3127 if (acptr && acptr->from == cptr)
3130 * The following should do the following:
3131 * - Add it to sendbuf for later use.
3132 * - If sendbuf is full, send it, and prepare a new
3133 * message in sendbuf.
3135 add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
3137 /* Let is take effect: (Note that in the case of a netride
3138 * 'default_mode' is always CHFL_DEOPPED here). */
3139 add_user_to_channel(chptr, acptr, default_mode);
3140 chptr->members->flags |= CHFL_BURST_JOINED;
3142 } /* <-- Next nick */
3143 if (!chptr->members) /* All nicks collided and channel is empty ? */
3145 sub1_from_channel(chptr);
3146 return 0; /* Forget about the (rest of the) message... */
3148 break; /* Done nicks part */
3150 } /* <-- Next parameter if any */
3151 if (!chptr->members) /* This message only contained bans (then the previous
3152 message only contained collided nicks, see above) */
3154 sub1_from_channel(chptr);
3155 if (!add_banid_not_called)
3156 while (next_removed_overlapped_ban());
3157 return 0; /* Forget about the (rest of the) message... */
3160 /* The last (possibly only) message is always send here */
3161 if (send_it) /* Anything (left) to send ? */
3166 /* send 'sendbuf' to all downlinks */
3167 for (lp = me.serv->down; lp; lp = lp->next)
3169 if (lp->value.cptr == cptr)
3171 if (Protocol(lp->value.cptr) > 9)
3172 sendbufto_one(lp->value.cptr);
3176 * Now we finally can screw sendbuf again...
3177 * Send all changes to the local clients:
3179 * First send all joins and op them, because 2.9 servers
3180 * would protest with a HACK if we first de-opped people.
3181 * However, we don't send the +b bans yes, because we
3182 * DO first want to -b the old bans (otherwise it's confusing).
3185 /* Send all joins: */
3186 for (member = chptr->members; member; member = member->next)
3187 if (member->flags & CHFL_BURST_JOINED)
3189 sendto_channel_butserv(chptr, member->value.cptr, ":%s JOIN :%s",
3190 member->value.cptr->name, chptr->chname);
3191 #ifndef NO_PROTOCOL9
3192 /* And to 2.9 servers: */
3193 sendto_lowprot_butone(cptr, 9, ":%s JOIN %s",
3194 member->value.cptr->name, chptr->chname);
3200 /* Send all +o and +v modes: */
3201 for (member = chptr->members; member; member = member->next)
3203 if ((member->flags & CHFL_BURST_JOINED))
3205 int mode = CHFL_CHANOP;
3208 if ((member->flags & mode))
3210 modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
3211 parabuf[pblen2++] = ' ';
3212 strcpy(parabuf + pblen2, member->value.cptr->name);
3213 pblen2 += strlen(member->value.cptr->name);
3216 modebuf[mblen2] = 0;
3217 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3218 parv[0], chptr->chname, modebuf, parabuf);
3219 #ifndef NO_PROTOCOL9
3220 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
3221 parv[0], chptr->chname, modebuf, parabuf,
3222 chptr->creationtime);
3231 if (mode == CHFL_CHANOP)
3239 if (cnt > 0 || mblen2 > 1)
3241 modebuf[mblen2] = 0;
3242 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3243 parv[0], chptr->chname, modebuf, parabuf);
3244 #ifndef NO_PROTOCOL9
3245 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
3246 parv[0], chptr->chname, modebuf, parabuf, chptr->creationtime);
3250 #ifndef NO_PROTOCOL9
3251 else if (send_it && !ts_sent)
3253 sendto_lowprot_butone(cptr, 9, ":%s MODE %s + " TIME_T_FMT,
3254 parv[0], chptr->chname, chptr->creationtime);
3269 /* Now cancel all previous simple modes */
3270 if ((prev_mode & MODE_SECRET))
3271 cancel_mode(sptr, chptr, 's', NULL, &count);
3272 if ((prev_mode & MODE_PRIVATE))
3273 cancel_mode(sptr, chptr, 'p', NULL, &count);
3274 if ((prev_mode & MODE_MODERATED))
3275 cancel_mode(sptr, chptr, 'm', NULL, &count);
3276 if ((prev_mode & MODE_TOPICLIMIT))
3277 cancel_mode(sptr, chptr, 't', NULL, &count);
3278 if ((prev_mode & MODE_INVITEONLY))
3279 cancel_mode(sptr, chptr, 'i', NULL, &count);
3280 if ((prev_mode & MODE_NOPRIVMSGS))
3281 cancel_mode(sptr, chptr, 'n', NULL, &count);
3282 if ((prev_mode & MODE_LIMIT))
3284 current_mode->limit = 0;
3285 cancel_mode(sptr, chptr, 'l', NULL, &count);
3287 if ((prev_mode & MODE_KEY))
3289 *current_mode->key = 0;
3290 cancel_mode(sptr, chptr, 'k', prev_key, &count);
3292 current_mode->mode &= ~prev_mode;
3294 /* And deop and devoice all net.riders on my side */
3299 for (lp = chptr->members; lp; lp = lp->next)
3301 if ((lp->flags & CHFL_BURST_JOINED))
3302 continue; /* This is not a net.rider from
3303 this side of the net.junction */
3304 if ((lp->flags & mode))
3307 if (mode == CHFL_CHANOP)
3308 lp->flags |= CHFL_DEOPPED;
3309 cancel_mode(sptr, chptr, m, lp->value.cptr->name, &count);
3312 if (mode == CHFL_VOICE)
3318 /* And finally wipeout all bans that are left */
3319 for (ban = &chptr->banlist; *ban;)
3322 if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT))
3324 cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
3325 /* Copied from del_banid(): */
3327 RunFree(tmp->value.ban.banstr);
3328 RunFree(tmp->value.ban.who);
3330 /* Erase ban-valid-bit, for channel members that are banned */
3331 for (tmp = chptr->members; tmp; tmp = tmp->next)
3332 if ((tmp->flags & (CHFL_BANNED | CHFL_BANVALID)) ==
3333 (CHFL_BANNED | CHFL_BANVALID))
3334 tmp->flags &= ~CHFL_BANVALID; /* `tmp' == channel member */
3339 /* Also wipeout overlapped bans */
3340 if (!add_banid_not_called)
3343 while ((ban = next_removed_overlapped_ban()))
3344 cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
3346 cancel_mode(sptr, chptr, 0, NULL, &count); /* flush */
3349 if (send_it && !netride)
3354 if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
3357 bl = chptr->banlist;
3373 nblen = strlen(bl->value.ban.banstr);
3374 if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN) /* The last check is to make sure
3375 that the receiving 2.9 will
3376 still process this */
3378 /* Time to send buffer */
3379 modebuf[mblen2] = 0;
3380 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3381 parv[0], chptr->chname, modebuf, parabuf);
3382 #ifndef NO_PROTOCOL9
3383 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s",
3384 parv[0], chptr->chname, modebuf, parabuf);
3386 *modebuf = deban ? '-' : '+';
3391 if (!bl) /* Done ? */
3393 if (deban || (bl->flags & CHFL_BURST_BAN))
3395 /* Add ban to buffers and remove it */
3396 modebuf[mblen2++] = 'b';
3397 parabuf[pblen2++] = ' ';
3398 strcpy(parabuf + pblen2, bl->value.ban.banstr);
3401 bl->flags &= ~CHFL_BURST_BAN;
3405 if (!(bl = next_removed_overlapped_ban()))
3408 modebuf[mblen2++] = '+';
3409 bl = chptr->banlist;
3415 /* Flush MODE [-b]+b ...: */
3416 if (cnt > 0 || mblen2 > 1)
3418 modebuf[mblen2] = 0;
3419 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3420 parv[0], chptr->chname, modebuf, parabuf);
3421 #ifndef NO_PROTOCOL9
3422 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
3423 parv[0], chptr->chname, modebuf, parabuf, chptr->creationtime);
3426 #ifndef NO_PROTOCOL9
3427 else if (send_it && !ts_sent)
3428 sendto_lowprot_butone(cptr, 9, ":%s MODE %s + " TIME_T_FMT,
3429 parv[0], chptr->chname, chptr->creationtime);
3439 * parv[0] = sender prefix
3441 * parv[parc - 1] = comment
3443 int m_part(aClient *cptr, aClient *sptr, int parc, char *parv[])
3445 Reg1 aChannel *chptr;
3447 char *p = NULL, *name, pbuf[BUFSIZE];
3448 char *comment = (parc > 2 && !BadPtr(parv[parc - 1])) ? parv[parc - 1] : NULL;
3450 *pbuf = '\0'; /* Initialize the part buffer... -Kev */
3452 sptr->flags &= ~FLAGS_TS8;
3454 if (parc < 2 || parv[1][0] == '\0')
3456 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PART");
3460 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3462 chptr = get_channel(sptr, name, !CREATE);
3465 sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
3468 if (*name == '&' && !MyUser(sptr))
3470 /* Do not use IsMember here: zombies must be able to part too */
3471 if (!(lp = find_user_link(chptr->members, sptr)))
3473 /* Normal to get when our client did a kick
3474 for a remote client (who sends back a PART),
3475 so check for remote client or not --Run */
3477 sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
3481 /* Recreate the /part list for sending to servers */
3488 if (can_send(sptr, chptr) != 0) /* Returns 0 if we CAN send */
3490 /* Send part to all clients */
3491 if (!(lp->flags & CHFL_ZOMBIE))
3494 sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
3497 sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
3499 else if (MyUser(sptr))
3502 sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
3504 sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
3506 remove_user_from_channel(sptr, chptr);
3508 /* Send out the parts to all servers... -Kev */
3512 sendto_serv_butone(cptr, PartFmt2, parv[0], pbuf, comment);
3514 sendto_serv_butone(cptr, PartFmt1, parv[0], pbuf);
3522 * parv[0] = sender prefix
3524 * parv[2] = client to kick
3525 * parv[parc-1] = kick comment
3527 int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[])
3534 sptr->flags &= ~FLAGS_TS8;
3536 if (parc < 3 || *parv[1] == '\0')
3538 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KICK");
3543 send_hack_notice(cptr, sptr, parc, parv, 1, 3);
3545 comment = (BadPtr(parv[parc - 1])) ? parv[0] : parv[parc - 1];
3546 if (strlen(comment) > (size_t)TOPICLEN)
3547 comment[TOPICLEN] = '\0';
3549 *nickbuf = *buf = '\0';
3551 chptr = get_channel(sptr, parv[1], !CREATE);
3554 sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]);
3557 if (IsLocalChannel(parv[1]) && !MyUser(sptr))
3559 if (IsModelessChannel(parv[1]))
3561 sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
3565 if (!IsServer(cptr) && !is_chan_op(sptr, chptr))
3567 sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
3568 me.name, parv[0], chptr->chname);
3572 lp2 = find_user_link(chptr->members, sptr);
3573 if (MyUser(sptr) || Protocol(cptr) < 10)
3575 if (!(who = find_chasing(sptr, parv[2], NULL)))
3576 return 0; /* No such user left! */
3578 else if (!(who = findNUser(parv[2])))
3579 return 0; /* No such user left! */
3580 /* if the user is +k, prevent a kick from local user */
3581 if (IsChannelService(who) && MyUser(sptr))
3583 sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
3584 parv[0], who->name, chptr->chname);
3587 if (((lp = find_user_link(chptr->members, who)) &&
3588 !(lp->flags & CHFL_ZOMBIE)) || IsServer(sptr))
3590 if (who->from != cptr &&
3591 ((lp2 && (lp2->flags & CHFL_DEOPPED)) || (!lp2 && IsUser(sptr))))
3595 * cptr must be a server (or cptr == sptr and
3596 * sptr->flags can't have DEOPPED set
3597 * when CHANOP is set).
3599 sendto_one(cptr, ":%s JOIN %s", who->name, parv[1]);
3600 if (lp->flags & CHFL_CHANOP)
3602 if (Protocol(cptr) < 10)
3603 sendto_one(cptr, ":%s MODE %s +o %s " TIME_T_FMT,
3604 me.name, parv[1], who->name, chptr->creationtime);
3606 sendto_one(cptr, "%s MODE %s +o %s%s " TIME_T_FMT,
3607 NumServ(&me), parv[1], NumNick(who), chptr->creationtime);
3609 if (lp->flags & CHFL_VOICE)
3611 if (Protocol(cptr) < 10)
3612 sendto_one(cptr, ":%s MODE %s +v %s " TIME_T_FMT,
3613 me.name, chptr->chname, who->name, chptr->creationtime);
3615 sendto_one(cptr, "%s MODE %s +v %s%s " TIME_T_FMT,
3616 NumServ(&me), parv[1], NumNick(who), chptr->creationtime);
3622 sendto_channel_butserv(chptr, sptr,
3623 ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
3624 if (!IsLocalChannel(parv[1]))
3626 sendto_lowprot_butone(cptr, 9, ":%s KICK %s %s :%s",
3627 parv[0], chptr->chname, who->name, comment);
3628 sendto_highprot_butone(cptr, 10, ":%s KICK %s %s%s :%s",
3629 parv[0], parv[1], NumNick(who), comment);
3640 * X --a--> A --b--> B --d--> D
3644 * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
3645 * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
3647 * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
3648 * Remove the user immedeately when no users are left on the channel.
3649 * b) On server B : remove the user (who/lp) from the channel, send a
3650 * PART upstream (to A) and pass on the KICK.
3651 * c) KICKed by `client'; On server B : remove the user (who/lp) from the
3652 * channel, and pass on the KICK.
3653 * d) On server D : remove the user (who/lp) from the channel, and pass on
3657 * - Setting the ZOMBIE flag never hurts, we either remove the
3658 * client after that or we don't.
3659 * - The KICK message was already passed on, as should be in all cases.
3660 * - `who' is removed in all cases except case a) when users are left.
3661 * - A PART is only sent upstream in case b).
3667 * 1 --- 2 --- 3 --- 4 --- 5
3671 * We also need to turn 'who' into a zombie on servers 1 and 6,
3672 * because a KICK from 'who' (kicking someone else in that direction)
3673 * can arrive there afterwards - which should not be bounced itself.
3674 * Therefore case a) also applies for servers 1 and 6.
3678 /* Default for case a): */
3679 lp->flags |= CHFL_ZOMBIE;
3680 /* Case b) or c) ?: */
3681 if (MyUser(who)) /* server 4 */
3683 if (IsServer(cptr)) /* Case b) ? */
3684 sendto_one(cptr, PartFmt1, who->name, parv[1]);
3685 remove_user_from_channel(who, chptr);
3688 if (who->from == cptr) /* True on servers 1, 5 and 6 */
3690 aClient *acptr = IsServer(sptr) ? sptr : sptr->user->server;
3691 for (; acptr != &me; acptr = acptr->serv->up)
3692 if (acptr == who->user->server) /* Case d) (server 5) */
3694 remove_user_from_channel(who, chptr);
3698 /* Case a) (servers 1, 2, 3 and 6) */
3699 for (lp = chptr->members; lp; lp = lp->next)
3700 if (!(lp->flags & CHFL_ZOMBIE))
3703 remove_user_from_channel(who, chptr);
3706 sendto_op_mask(SNO_HACK2, "%s is now a zombie on %s",
3707 who->name, chptr->chname);
3712 else if (MyUser(sptr))
3713 sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
3714 me.name, parv[0], who->name, chptr->chname);
3722 * parv[0] = sender prefix
3724 * parv[parc - 1] = topic (if parc > 2)
3726 int m_topic(aClient *cptr, aClient *sptr, int parc, char *parv[])
3729 char *topic = NULL, *name, *p = NULL;
3733 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "TOPIC");
3738 topic = parv[parc - 1];
3740 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3743 if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
3744 ((topic || SecretChannel(chptr)) && !IsMember(sptr, chptr)))
3746 sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
3747 me.name, parv[0], chptr ? chptr->chname : name);
3750 if (IsModelessChannel(name))
3752 sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
3756 if (IsLocalChannel(name) && !MyUser(sptr))
3759 if (!topic) /* only asking for topic */
3761 if (chptr->topic[0] == '\0')
3762 sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname);
3765 sendto_one(sptr, rpl_str(RPL_TOPIC),
3766 me.name, parv[0], chptr->chname, chptr->topic);
3767 sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
3768 me.name, parv[0], chptr->chname,
3769 chptr->topic_nick, chptr->topic_time);
3772 else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
3773 is_chan_op(sptr, chptr)) && topic)
3775 /* setting a topic */
3776 strncpy(chptr->topic, topic, TOPICLEN);
3777 strncpy(chptr->topic_nick, sptr->name, NICKLEN);
3778 chptr->topic_time = now;
3779 sendto_serv_butone(cptr, ":%s TOPIC %s :%s",
3780 parv[0], chptr->chname, chptr->topic);
3781 sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
3782 parv[0], chptr->chname, chptr->topic);
3785 sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
3786 me.name, parv[0], chptr->chname);
3793 * parv[0] - sender prefix
3794 * parv[1] - user to invite
3795 * parv[2] - channel name
3797 * - INVITE now is accepted only if who does it is chanop (this of course
3798 * implies that channel must exist and he must be on it).
3800 * - On the other side it IS processed even if channel is NOT invite only
3801 * leaving room for other enhancements like inviting banned ppl. -- Nemesi
3804 int m_invite(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
3809 if (parc < 3 || *parv[2] == '\0')
3811 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "INVITE");
3815 if (!(acptr = FindUser(parv[1])))
3817 sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
3821 if (is_silenced(sptr, acptr))
3825 clean_channelname(parv[2]);
3826 else if (IsLocalChannel(parv[2]))
3829 if (*parv[2] == '0' || !IsChannelName(parv[2]))
3832 if (!(chptr = FindChannel(parv[2])))
3834 if (IsModelessChannel(parv[2]) || IsLocalChannel(parv[2]))
3836 sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[2]);
3840 /* Do not disallow to invite to non-existant #channels, otherwise they
3841 would simply first be created, causing only MORE bandwidth usage. */
3842 if (MyConnect(sptr))
3844 if (check_target_limit(sptr, acptr, acptr->name, 0))
3847 sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
3848 acptr->name, parv[2]);
3850 if (acptr->user->away)
3851 sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
3852 acptr->name, acptr->user->away);
3855 sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
3856 acptr->name, parv[2]);
3861 if (!IsMember(sptr, chptr))
3863 sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
3868 if (IsMember(acptr, chptr))
3870 sendto_one(sptr, err_str(ERR_USERONCHANNEL),
3871 me.name, parv[0], acptr->name, chptr->chname);
3875 if (MyConnect(sptr))
3877 if (!is_chan_op(sptr, chptr))
3879 sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
3880 me.name, parv[0], chptr->chname);
3884 /* If we get here, it was a VALID and meaningful INVITE */
3886 if (check_target_limit(sptr, acptr, acptr->name, 0))
3889 sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
3890 acptr->name, chptr->chname);
3892 if (acptr->user->away)
3893 sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
3894 acptr->name, acptr->user->away);
3897 if (MyConnect(acptr))
3898 add_invite(acptr, chptr);
3900 sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
3901 acptr->name, chptr->chname);
3906 static int number_of_zombies(aChannel *chptr)
3910 for (lp = chptr->members; lp; lp = lp->next)
3911 if (lp->flags & CHFL_ZOMBIE)
3919 * parv[0] = sender prefix
3920 * parv[1] = channel list or user/time limit
3921 * parv[2...] = more user/time limits
3923 int m_list(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
3926 char *name, *p = NULL;
3927 int show_usage = 0, show_channels = 0, param;
3928 aListingArgs args = {
3929 2147483647, /* max_time */
3931 4294967295U, /* max_users */
3933 0, /* topic_limits */
3934 2147483647, /* max_topic_time */
3935 0, /* min_topic_time */
3939 if (sptr->listing) /* Already listing ? */
3941 sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
3942 RunFree(sptr->listing);
3943 sptr->listing = NULL;
3944 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
3946 return 0; /* Let LIST abort a listing. */
3949 if (parc < 2) /* No arguments given to /LIST ? */
3951 #ifdef DEFAULT_LIST_PARAM
3952 static char *defparv[MAXPARA + 1];
3953 static int defparc = 0;
3954 static char lp[] = DEFAULT_LIST_PARAM;
3962 defparv[defparc++] = t = strtok(s, " ");
3963 while (t && defparc < MAXPARA)
3965 if ((t = strtok(NULL, " ")))
3966 defparv[defparc++] = t;
3969 for (i = 1; i < defparc; i++)
3970 parv[i] = defparv[i];
3973 #endif /* DEFAULT_LIST_PARAM */
3976 /* Decode command */
3977 for (param = 1; !show_usage && parv[param]; param++)
3979 char *p = parv[param];
3988 args.topic_limits = 1;
3994 if (*p != '<' && *p != '>')
4010 time_t val = atoi(p);
4013 if (val < 80000000) /* Toggle UTC/offset */
4017 * 'TStime() - chptr->creationtime < val * 60'
4019 * 'chptr->creationtime > TStime() - val * 60'
4022 args.min_time = TStime() - val * 60;
4024 args.min_topic_time = TStime() - val * 60;
4026 else if (is_time == 1) /* Creation time in UTC was entered */
4027 args.max_time = val;
4028 else /* Topic time in UTC was entered */
4029 args.max_topic_time = val;
4031 else if (val < 80000000)
4034 args.max_time = TStime() - val * 60;
4036 args.max_topic_time = TStime() - val * 60;
4038 else if (is_time == 1)
4039 args.min_time = val;
4041 args.min_topic_time = val;
4043 else if (p[-1] == '<')
4044 args.max_users = atoi(p);
4046 args.min_users = atoi(p);
4047 if ((p = strchr(p, ',')))
4053 if (!IsChannelName(p))
4058 if (parc != 2) /* Don't allow a mixture of channels with <,> */
4065 while (!show_usage && p); /* p points after comma, or is NULL */
4070 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4071 "Usage: \002/QUOTE LIST\002 \037parameters\037");
4072 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4073 "Where \037parameters\037 is a space or comma seperated "
4074 "list of one or more of:");
4075 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4076 " \002<\002\037max_users\037 ; Show all channels with less "
4077 "than \037max_users\037.");
4078 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4079 " \002>\002\037min_users\037 ; Show all channels with more "
4080 "than \037min_users\037.");
4081 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4082 " \002C<\002\037max_minutes\037 ; Channels that exist less "
4083 "than \037max_minutes\037.");
4084 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4085 " \002C>\002\037min_minutes\037 ; Channels that exist more "
4086 "than \037min_minutes\037.");
4087 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4088 " \002T<\002\037max_minutes\037 ; Channels with a topic last "
4089 "set less than \037max_minutes\037 ago.");
4090 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4091 " \002T>\002\037min_minutes\037 ; Channels with a topic last "
4092 "set more than \037min_minutes\037 ago.");
4093 sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4094 "Example: LIST <3,>1,C<10,T>0 ; 2 users, younger than 10 min., "
4099 sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
4103 if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
4104 args.max_topic_time > args.min_topic_time) /* Sanity check */
4106 if ((sptr->listing = (aListingArgs *)RunMalloc(sizeof(aListingArgs))))
4108 memcpy(sptr->listing, &args, sizeof(aListingArgs));
4109 if ((sptr->listing->chptr = channel))
4111 int m = channel->mode.mode & MODE_LISTED;
4112 list_next_channels(sptr, 64);
4113 channel->mode.mode |= m;
4116 RunFree(sptr->listing);
4117 sptr->listing = NULL;
4120 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
4124 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
4126 chptr = FindChannel(name);
4127 if (chptr && ShowChannel(sptr, chptr) && sptr->user)
4128 sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
4129 ShowChannel(sptr, chptr) ? chptr->chname : "*",
4130 chptr->users - number_of_zombies(chptr), chptr->topic);
4133 sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
4138 * m_names - Added by Jto 27 Apr 1989
4140 * parv[0] = sender prefix
4143 int m_names(aClient *cptr, aClient *sptr, int parc, char *parv[])
4145 Reg1 aChannel *chptr;
4146 Reg2 aClient *c2ptr;
4148 aChannel *ch2ptr = NULL;
4149 int idx, flag, len, mlen;
4150 char *s, *para = parc > 1 ? parv[1] : NULL;
4152 if (parc > 2 && hunt_server(1, cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
4155 mlen = strlen(me.name) + 10 + strlen(sptr->name);
4159 s = strchr(para, ',');
4163 m_names(cptr, sptr, parc, parv);
4165 clean_channelname(para);
4166 ch2ptr = FindChannel(para);
4170 * First, do all visible channels (public and the one user self is)
4173 for (chptr = channel; chptr; chptr = chptr->nextch)
4175 if ((chptr != ch2ptr) && !BadPtr(para))
4176 continue; /* -- wanted a specific channel */
4177 if (!MyConnect(sptr) && BadPtr(para))
4180 if (!ShowChannel(sptr, chptr))
4181 continue; /* -- users on this are not listed */
4184 /* Find users on same channel (defined by chptr) */
4187 len = strlen(chptr->chname);
4188 strcpy(buf + 2, chptr->chname);
4189 strcpy(buf + 2 + len, " :");
4191 if (PubChannel(chptr))
4193 else if (SecretChannel(chptr))
4197 for (lp = chptr->members; lp; lp = lp->next)
4199 c2ptr = lp->value.cptr;
4201 if (sptr != c2ptr && IsInvisible(c2ptr) && !IsMember(sptr, chptr))
4204 if (lp->flags & CHFL_ZOMBIE)
4206 if (lp->value.cptr != sptr)
4214 else if (lp->flags & CHFL_CHANOP)
4219 else if (lp->flags & CHFL_VOICE)
4224 strcat(buf, c2ptr->name);
4226 idx += strlen(c2ptr->name) + 1;
4231 sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
4232 if (c2ptr != findNUser(yxx))
4234 sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
4237 if (mlen + idx + NICKLEN + 11 > BUFSIZE)
4239 if (mlen + idx + NICKLEN + 5 > BUFSIZE)
4241 /* space, modifier, nick, \r \n \0 */
4243 sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4245 strncpy(buf + 2, chptr->chname, len + 1);
4248 if (PubChannel(chptr))
4250 else if (SecretChannel(chptr))
4257 sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4261 sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0],
4262 ch2ptr ? ch2ptr->chname : para);
4266 /* Second, do all non-public, non-secret channels in one big sweep */
4268 strcpy(buf, "* * :");
4271 for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
4274 int showflag = 0, secret = 0;
4277 if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
4282 lp = c2ptr->user->channel;
4284 * Don't show a client if they are on a secret channel or when
4285 * they are on a channel sptr is on since they have already
4286 * been show earlier. -avalon
4290 ch3ptr = lp->value.chptr;
4292 if (PubChannel(ch3ptr) || IsMember(sptr, ch3ptr))
4295 if (SecretChannel(ch3ptr))
4299 if (showflag) /* Have we already shown them ? */
4302 if (secret) /* On any secret channels ? */
4305 strcat(buf, c2ptr->name);
4307 idx += strlen(c2ptr->name) + 1;
4312 sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
4313 if (c2ptr != findNUser(yxx))
4315 sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
4320 if (mlen + idx + NICKLEN + 9 > BUFSIZE)
4322 if (mlen + idx + NICKLEN + 3 > BUFSIZE) /* space, \r\n\0 */
4325 sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4326 strcpy(buf, "* * :");
4332 sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4333 sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
4337 void send_user_joins(aClient *cptr, aClient *user)
4340 Reg2 aChannel *chptr;
4341 Reg3 int cnt = 0, len = 0, clen;
4345 strcpy(buf + 1, user->name);
4346 strcat(buf, " JOIN ");
4347 len = strlen(user->name) + 7;
4349 for (lp = user->user->channel; lp; lp = lp->next)
4351 chptr = lp->value.chptr;
4352 if ((mask = strchr(chptr->chname, ':')))
4353 if (match(++mask, cptr->name))
4355 if (*chptr->chname == '&')
4357 if (is_zombie(user, chptr))
4359 clen = strlen(chptr->chname);
4360 if (clen + 1 + len > BUFSIZE - 3)
4364 buf[len - 1] = '\0';
4365 sendto_one(cptr, "%s", buf);
4368 strcpy(buf + 1, user->name);
4369 strcat(buf, " JOIN ");
4370 len = strlen(user->name) + 7;
4373 strcpy(buf + len, chptr->chname);
4383 sendto_one(cptr, "%s", buf);
4389 * send_hack_notice()
4391 * parc & parv[] are the same as that of the calling function:
4392 * mtype == 1 is from m_mode, 2 is from m_create, 3 is from m_kick.
4394 * This function prepares sendbuf with the server notices and wallops
4395 * to be sent for all hacks. -Ghostwolf 18-May-97
4398 static void send_hack_notice(aClient *cptr, aClient *sptr, int parc,
4399 char *parv[], int badop, int mtype)
4402 static char params[MODEBUFLEN];
4404 chptr = FindChannel(parv[1]);
4407 if (Protocol(cptr) < 10) /* We don't get numeric nicks from P09 */
4408 { /* servers, so this can be sent "As Is" */
4413 strcat(params, " ");
4414 strcat(params, parv[i++]);
4416 sprintf_irc(sendbuf,
4417 ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s [" TIME_T_FMT
4418 "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop, parv[0],
4419 parv[1], parv[2], params, chptr->creationtime);
4420 sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop ==
4421 4) ? SNO_HACK4 : SNO_HACK2);
4423 if ((IsServer(sptr)) && (badop == 2))
4425 sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
4426 me.name, parv[0], parv[1], parv[2], params);
4427 sendbufto_serv_butone(cptr);
4430 else if (mtype == 3)
4432 sprintf_irc(sendbuf,
4433 ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
4434 me.name, sptr->name, parv[1], parv[2], parv[3]);
4435 sendbufto_op_mask(SNO_HACK4);
4440 /* P10 servers require numeric nick conversion before sending. */
4443 case 1: /* Convert nicks for MODE HACKs here */
4445 char *mode = parv[2];
4448 while (*mode && *mode != 'o' && *mode != 'v')
4450 strcat(params, " ");
4451 if (*mode == 'o' || *mode == 'v')
4453 register aClient *acptr;
4454 if ((acptr = findNUser(parv[i])) != NULL) /* Convert nicks here */
4455 strcat(params, acptr->name);
4458 strcat(params, "<");
4459 strcat(params, parv[i]);
4460 strcat(params, ">");
4463 else /* If it isn't a numnick, send it 'as is' */
4464 strcat(params, parv[i]);
4467 sprintf_irc(sendbuf,
4468 ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s ["
4469 TIME_T_FMT "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop,
4470 parv[0], parv[1], parv[2], params, chptr->creationtime);
4471 sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop ==
4472 4) ? SNO_HACK4 : SNO_HACK2);
4474 if ((IsServer(sptr)) && (badop == 2))
4476 sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
4477 me.name, parv[0], parv[1], parv[2], params);
4478 sendbufto_serv_butone(cptr);
4482 case 2: /* No conversion is needed for CREATE; the only numnick is sptr */
4484 sendto_serv_butone(cptr, ":%s DESYNCH :HACK: %s CREATE %s %s",
4485 me.name, sptr->name, chptr->chname, parv[2]);
4486 sendto_op_mask(SNO_HACK2, "HACK(2): %s CREATE %s %s",
4487 sptr->name, chptr->chname, parv[2]);
4490 case 3: /* Convert nick in KICK message */
4493 if ((acptr = findNUser(parv[2])) != NULL) /* attempt to convert nick */
4494 sprintf_irc(sendbuf,
4495 ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
4496 me.name, sptr->name, parv[1], acptr->name, parv[3]);
4497 else /* if conversion fails, send it 'as is' in <>'s */
4498 sprintf_irc(sendbuf,
4499 ":%s NOTICE * :*** Notice -- HACK: %s KICK %s <%s> :%s",
4500 me.name, sptr->name, parv[1], parv[2], parv[3]);
4501 sendbufto_op_mask(SNO_HACK4);