91044d00c43638fcabc49e512b9fc0934d75abfe
[ircu2.10.12-pk.git] / ircd / channel.c
1 /*
2  * IRC - Internet Relay Chat, ircd/channel.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Co Center
5  *
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)
9  * any later version.
10  *
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.
15  *
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.
19  */
20
21 #include "sys.h"
22 #include <stdlib.h>
23 #include "h.h"
24 #include "struct.h"
25 #include "channel.h"
26 #include "parse.h"
27 #include "whowas.h"
28 #include "send.h"
29 #include "s_err.h"
30 #include "numeric.h"
31 #include "ircd.h"
32 #include "common.h"
33 #include "match.h"
34 #include "list.h"
35 #include "hash.h"
36 #include "s_misc.h"
37 #include "s_user.h"
38 #include "s_conf.h"
39 #include "s_bsd.h"
40 #include "msg.h"
41 #include "common.h"
42 #include "s_serv.h"
43 #include "channel.h"
44 #include "support.h"
45 #include "numnicks.h"
46 #include "sprintf_irc.h"
47 #include "querycmds.h"
48
49 RCSTAG_CC("$Id$");
50
51 aChannel *channel = NullChn;
52
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 *);
70
71 void del_invite(aClient *, aChannel *);
72
73 static char *PartFmt1 = ":%s PART %s";
74 static char *PartFmt2 = ":%s PART %s :%s";
75 /*
76  * some buffers for rebuilding channel/nick lists with ,'s
77  */
78 static char nickbuf[BUFSIZE], buf[BUFSIZE];
79 static char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
80 static char nparabuf[MODEBUFLEN];
81
82 /*
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.
88  *
89  * This value has been increased to 1 day in order to distinguish this
90  * "normal" type of HACK wallops / desyncs, from possiblity still
91  * existing bugs.
92  */
93 #define TS_LAG_TIME ((time_t)86400)
94
95 /*
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.
99  */
100 #define MAGIC_REMOTE_JOIN_TS 1270080000
101
102 /*
103  * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
104  * but the only way to do it without changing set_mode intensively.
105  */
106 int LocalChanOperMode = 0;
107
108 /*
109  * return the length (>=0) of a chain of links.
110  */
111 static int list_length(Link *lp)
112 {
113   Reg2 int count = 0;
114
115   for (; lp; lp = lp->next)
116     count++;
117   return count;
118 }
119
120 /*
121  * find_chasing
122  *
123  * Find the client structure for a nick name (user) using history
124  * mechanism if necessary. If the client is not found, an error
125  * message (NO SUCH NICK) is generated. If the client was found
126  * through the history, chasing will be 1 and otherwise 0.
127  */
128 static aClient *find_chasing(aClient *sptr, char *user, int *chasing)
129 {
130   Reg2 aClient *who = FindClient(user);
131
132   if (chasing)
133     *chasing = 0;
134   if (who)
135     return who;
136   if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
137   {
138     sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, user);
139     return NULL;
140   }
141   if (chasing)
142     *chasing = 1;
143   return who;
144 }
145
146 /*
147  * Create a string of form "foo!bar@fubar" given foo, bar and fubar
148  * as the parameters.  If NULL, they become "*".
149  */
150 static char *make_nick_user_host(char *nick, char *name, char *host)
151 {
152   static char namebuf[NICKLEN + USERLEN + HOSTLEN + 3];
153   sprintf_irc(namebuf, "%s!%s@%s", nick, name, host);
154   return namebuf;
155 }
156
157 /*
158  * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
159  * IP-number as the parameters.  If NULL, they become "*".
160  */
161 static char *make_nick_user_ip(char *nick, char *name, struct in_addr ip)
162 {
163   static char ipbuf[NICKLEN + USERLEN + 16 + 3];
164   sprintf_irc(ipbuf, "%s!%s@%s", nick, name, inetntoa(ip));
165   return ipbuf;
166 }
167
168 /*
169  * add_banid
170  *
171  * `cptr' must be the client adding the ban.
172  *
173  * If `change' is true then add `banid' to channel `chptr'.
174  * Returns 0 if the ban was added.
175  * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
176  * Return -1 otherwise.
177  *
178  * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
179  * when `change' is false, otherwise they will be removed from the banlist.
180  * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
181  * respectively will return these bans until NULL is returned.
182  *
183  * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
184  * is reset (unless a non-zero value is returned, in which case the
185  * CHFL_BAN_OVERLAPPED flag might not have been reset!).
186  *
187  * --Run
188  */
189 static Link *next_ban, *prev_ban, *removed_bans_list;
190
191 static int add_banid(aClient *cptr, aChannel *chptr, char *banid,
192     int change, int firsttime)
193 {
194   Reg1 Link *ban, **banp;
195   Reg2 int cnt = 0, removed_bans = 0, len = strlen(banid);
196
197   if (firsttime)
198   {
199     next_ban = NULL;
200     if (prev_ban || removed_bans_list)
201       MyCoreDump;               /* Memory leak */
202   }
203   if (MyUser(cptr))
204     collapse(banid);
205   for (banp = &chptr->banlist; *banp;)
206   {
207     len += strlen((*banp)->value.ban.banstr);
208     ++cnt;
209     if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
210     {
211       if (!strcmp((*banp)->value.ban.banstr, banid))
212       {
213         (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
214         return -2;
215       }
216     }
217     else if (!mmatch((*banp)->value.ban.banstr, banid))
218       return -1;
219     if (!mmatch(banid, (*banp)->value.ban.banstr))
220     {
221       Link *tmp = *banp;
222       if (change)
223       {
224         if (MyUser(cptr))
225         {
226           cnt--;
227           len -= strlen(tmp->value.ban.banstr);
228         }
229         *banp = tmp->next;
230 #if 0
231         /* Silently remove overlapping bans */
232         RunFree(tmp->value.ban.banstr);
233         RunFree(tmp->value.ban.who);
234         free_link(tmp);
235 #else
236         /* These will be sent to the user later as -b */
237         tmp->next = removed_bans_list;
238         removed_bans_list = tmp;
239         removed_bans = 1;
240 #endif
241       }
242       else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
243       {
244         tmp->flags |= CHFL_BAN_OVERLAPPED;
245         if (!next_ban)
246           next_ban = tmp;
247         banp = &tmp->next;
248       }
249       else
250         banp = &tmp->next;
251     }
252     else
253     {
254       if (firsttime)
255         (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
256       banp = &(*banp)->next;
257     }
258   }
259   if (MyUser(cptr) && !removed_bans && (len > MAXBANLENGTH || (cnt >= MAXBANS)))
260   {
261     sendto_one(cptr, err_str(ERR_BANLISTFULL), me.name, cptr->name,
262         chptr->chname, banid);
263     return -1;
264   }
265   if (change)
266   {
267     char *ip_start;
268     ban = make_link();
269     ban->next = chptr->banlist;
270     ban->value.ban.banstr = (char *)RunMalloc(strlen(banid) + 1);
271     strcpy(ban->value.ban.banstr, banid);
272     ban->value.ban.who = (char *)RunMalloc(strlen(cptr->name) + 1);
273     strcpy(ban->value.ban.who, cptr->name);
274     ban->value.ban.when = now;
275     ban->flags = CHFL_BAN;      /* This bit is never used I think... */
276     if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
277       ban->flags |= CHFL_BAN_IPMASK;
278     chptr->banlist = ban;
279     /* Erase ban-valid-bit */
280     for (ban = chptr->members; ban; ban = ban->next)
281       ban->flags &= ~CHFL_BANVALID;     /* `ban' == channel member ! */
282   }
283   return 0;
284 }
285
286 static Link *next_overlapped_ban(void)
287 {
288   Reg1 Link *tmp = next_ban;
289   if (tmp)
290   {
291     Reg2 Link *ban;
292     for (ban = tmp->next; ban; ban = ban->next)
293       if ((ban->flags & CHFL_BAN_OVERLAPPED))
294         break;
295     next_ban = ban;
296   }
297   return tmp;
298 }
299
300 static Link *next_removed_overlapped_ban(void)
301 {
302   Reg1 Link *tmp = removed_bans_list;
303   if (prev_ban)
304   {
305     if (prev_ban->value.ban.banstr)     /* Can be set to NULL in set_mode() */
306       RunFree(prev_ban->value.ban.banstr);
307     RunFree(prev_ban->value.ban.who);
308     free_link(prev_ban);
309   }
310   if (tmp)
311     removed_bans_list = removed_bans_list->next;
312   prev_ban = tmp;
313   return tmp;
314 }
315
316 /*
317  * del_banid
318  *
319  * If `change' is true, delete `banid' from channel `chptr'.
320  * Returns `false' if removal was (or would have been) successful.
321  */
322 static int del_banid(aChannel *chptr, char *banid, int change)
323 {
324   Reg1 Link **ban;
325   Reg2 Link *tmp;
326
327   if (!banid)
328     return -1;
329   for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
330     if (strCasediff(banid, (*ban)->value.ban.banstr) == 0)
331     {
332       tmp = *ban;
333       if (change)
334       {
335         *ban = tmp->next;
336         RunFree(tmp->value.ban.banstr);
337         RunFree(tmp->value.ban.who);
338         free_link(tmp);
339         /* Erase ban-valid-bit, for channel members that are banned */
340         for (tmp = chptr->members; tmp; tmp = tmp->next)
341           if ((tmp->flags & (CHFL_BANNED | CHFL_BANVALID)) ==
342               (CHFL_BANNED | CHFL_BANVALID))
343             tmp->flags &= ~CHFL_BANVALID;       /* `tmp' == channel member */
344       }
345       return 0;
346     }
347   return -1;
348 }
349
350 /*
351  * IsMember - returns Link * if a person is joined and not a zombie
352  */
353 Link *IsMember(aClient *cptr, aChannel *chptr)
354 {
355   Link *lp;
356   return (((lp = find_user_link(chptr->members, cptr)) &&
357       !(lp->flags & CHFL_ZOMBIE)) ? lp : NULL);
358 }
359
360 /*
361  * is_banned - a non-zero value if banned else 0.
362  */
363 static int is_banned(aClient *cptr, aChannel *chptr, Link *member)
364 {
365   Reg1 Link *tmp;
366   char *s, *ip_s = NULL;
367
368   if (!IsUser(cptr))
369     return 0;
370
371   if (member)
372   {
373     if ((member->flags & CHFL_BANVALID))
374       return (member->flags & CHFL_BANNED);
375   }
376
377   s = make_nick_user_host(cptr->name, cptr->user->username, cptr->user->host);
378
379   for (tmp = chptr->banlist; tmp; tmp = tmp->next)
380   {
381     if ((tmp->flags & CHFL_BAN_IPMASK))
382     {
383       if (!ip_s)
384         ip_s = make_nick_user_ip(cptr->name, cptr->user->username, cptr->ip);
385       if (match(tmp->value.ban.banstr, ip_s) == 0)
386         break;
387     }
388     else if (match(tmp->value.ban.banstr, s) == 0)
389       break;
390   }
391
392   if (member)
393   {
394     member->flags |= CHFL_BANVALID;
395     if (tmp)
396     {
397       member->flags |= CHFL_BANNED;
398       return 1;
399     }
400     else
401     {
402       member->flags &= ~CHFL_BANNED;
403       return 0;
404     }
405   }
406
407   return (tmp != NULL);
408 }
409
410 /*
411  * adds a user to a channel by adding another link to the channels member
412  * chain.
413  */
414 static void add_user_to_channel(aChannel *chptr, aClient *who, int flags)
415 {
416   Reg1 Link *ptr;
417
418   if (who->user)
419   {
420     ptr = make_link();
421     ptr->value.cptr = who;
422     ptr->flags = flags;
423     ptr->next = chptr->members;
424     chptr->members = ptr;
425     chptr->users++;
426
427     ptr = make_link();
428     ptr->value.chptr = chptr;
429     ptr->next = who->user->channel;
430     who->user->channel = ptr;
431     who->user->joined++;
432   }
433 }
434
435 void remove_user_from_channel(aClient *sptr, aChannel *chptr)
436 {
437   Reg1 Link **curr;
438   Reg2 Link *tmp;
439   Reg3 Link *lp = chptr->members;
440
441   for (; lp && (lp->flags & CHFL_ZOMBIE || lp->value.cptr == sptr);
442       lp = lp->next);
443   for (;;)
444   {
445     for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
446       if (tmp->value.cptr == sptr)
447       {
448         *curr = tmp->next;
449         free_link(tmp);
450         break;
451       }
452     for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next)
453       if (tmp->value.chptr == chptr)
454       {
455         *curr = tmp->next;
456         free_link(tmp);
457         break;
458       }
459     sptr->user->joined--;
460     if (lp)
461       break;
462     if (chptr->members)
463       sptr = chptr->members->value.cptr;
464     else
465       break;
466     sub1_from_channel(chptr);
467   }
468   sub1_from_channel(chptr);
469 }
470
471 int is_chan_op(aClient *cptr, aChannel *chptr)
472 {
473   Reg1 Link *lp;
474
475   if (chptr)
476     if ((lp = find_user_link(chptr->members, cptr)) &&
477         !(lp->flags & CHFL_ZOMBIE))
478       return (lp->flags & CHFL_CHANOP);
479
480   return 0;
481 }
482
483 static int is_deopped(aClient *cptr, aChannel *chptr)
484 {
485   Reg1 Link *lp;
486
487   if (chptr)
488     if ((lp = find_user_link(chptr->members, cptr)))
489       return (lp->flags & CHFL_DEOPPED);
490
491   return (IsUser(cptr) ? 1 : 0);
492 }
493
494 int is_zombie(aClient *cptr, aChannel *chptr)
495 {
496   Reg1 Link *lp;
497
498   if (chptr)
499     if ((lp = find_user_link(chptr->members, cptr)))
500       return (lp->flags & CHFL_ZOMBIE);
501
502   return 0;
503 }
504
505 int has_voice(aClient *cptr, aChannel *chptr)
506 {
507   Reg1 Link *lp;
508
509   if (chptr)
510     if ((lp = find_user_link(chptr->members, cptr)) &&
511         !(lp->flags & CHFL_ZOMBIE))
512       return (lp->flags & CHFL_VOICE);
513
514   return 0;
515 }
516
517 int can_send(aClient *cptr, aChannel *chptr)
518 {
519   Reg1 Link *lp;
520
521   lp = IsMember(cptr, chptr);
522
523   if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
524       (lp->flags & CHFL_ZOMBIE)) && MyUser(cptr) && is_banned(cptr, chptr, lp))
525     return (MODE_BAN);
526
527   if (chptr->mode.mode & MODE_MODERATED &&
528       (!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
529       (lp->flags & CHFL_ZOMBIE)))
530     return (MODE_MODERATED);
531
532   if (!lp && ((chptr->mode.mode & MODE_NOPRIVMSGS) ||
533       IsModelessChannel(chptr->chname)))
534     return (MODE_NOPRIVMSGS);
535
536   return 0;
537 }
538
539 /*
540  * write the "simple" list of channel modes for channel chptr onto buffer mbuf
541  * with the parameters in pbuf.
542  */
543 static void channel_modes(aClient *cptr, char *mbuf, char *pbuf,
544     aChannel *chptr)
545 {
546   *mbuf++ = '+';
547   if (chptr->mode.mode & MODE_SECRET)
548     *mbuf++ = 's';
549   else if (chptr->mode.mode & MODE_PRIVATE)
550     *mbuf++ = 'p';
551   if (chptr->mode.mode & MODE_MODERATED)
552     *mbuf++ = 'm';
553   if (chptr->mode.mode & MODE_TOPICLIMIT)
554     *mbuf++ = 't';
555   if (chptr->mode.mode & MODE_INVITEONLY)
556     *mbuf++ = 'i';
557   if (chptr->mode.mode & MODE_NOPRIVMSGS)
558     *mbuf++ = 'n';
559   if (chptr->mode.limit)
560   {
561     *mbuf++ = 'l';
562     sprintf_irc(pbuf, "%d", chptr->mode.limit);
563   }
564   if (*chptr->mode.key)
565   {
566     *mbuf++ = 'k';
567     if (is_chan_op(cptr, chptr) || IsServer(cptr))
568     {
569       if (chptr->mode.limit)
570         strcat(pbuf, " ");
571       strcat(pbuf, chptr->mode.key);
572     }
573   }
574   *mbuf = '\0';
575   return;
576 }
577
578 static int send_mode_list(aClient *cptr, char *chname, time_t creationtime,
579     Link *top, int mask, char flag)
580 {
581   Reg1 Link *lp;
582   Reg2 char *cp, *name;
583   int count = 0, send = 0, sent = 0;
584
585   cp = modebuf + strlen(modebuf);
586   if (*parabuf)                 /* mode +l or +k xx */
587     count = 1;
588   for (lp = top; lp; lp = lp->next)
589   {
590     if (!(lp->flags & mask))
591       continue;
592     if (mask == CHFL_BAN)
593       name = lp->value.ban.banstr;
594     else
595       name = lp->value.cptr->name;
596     if (strlen(parabuf) + strlen(name) + 11 < (size_t)MODEBUFLEN)
597     {
598       strcat(parabuf, " ");
599       strcat(parabuf, name);
600       count++;
601       *cp++ = flag;
602       *cp = '\0';
603     }
604     else if (*parabuf)
605       send = 1;
606     if (count == 6)
607       send = 1;
608     if (send)
609     {
610       /* cptr is always a server! So we send creationtimes */
611       sendmodeto_one(cptr, me.name, chname, modebuf, parabuf, creationtime);
612       sent = 1;
613       send = 0;
614       *parabuf = '\0';
615       cp = modebuf;
616       *cp++ = '+';
617       if (count != 6)
618       {
619         strcpy(parabuf, name);
620         *cp++ = flag;
621       }
622       count = 0;
623       *cp = '\0';
624     }
625   }
626   return sent;
627 }
628
629 /*
630  * send "cptr" a full list of the modes for channel chptr.
631  */
632 void send_channel_modes(aClient *cptr, aChannel *chptr)
633 {
634   int sent;
635   if (IsLocalChannel(chptr->chname))
636     return;
637
638   *modebuf = *parabuf = '\0';
639   channel_modes(cptr, modebuf, parabuf, chptr);
640
641   if (Protocol(cptr) < 10)
642   {
643     sent = send_mode_list(cptr, chptr->chname, chptr->creationtime,
644         chptr->members, CHFL_CHANOP, 'o');
645     if (!sent && chptr->creationtime)
646       sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT, me.name,
647           chptr->chname, modebuf, parabuf, chptr->creationtime);
648     else if (modebuf[1] || *parabuf)
649       sendmodeto_one(cptr, me.name,
650           chptr->chname, modebuf, parabuf, chptr->creationtime);
651
652     *parabuf = '\0';
653     *modebuf = '+';
654     modebuf[1] = '\0';
655     send_mode_list(cptr, chptr->chname, chptr->creationtime,
656         chptr->banlist, CHFL_BAN, 'b');
657     if (modebuf[1] || *parabuf)
658       sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
659           parabuf, chptr->creationtime);
660
661     *parabuf = '\0';
662     *modebuf = '+';
663     modebuf[1] = '\0';
664     send_mode_list(cptr, chptr->chname, chptr->creationtime,
665         chptr->members, CHFL_VOICE, 'v');
666     if (modebuf[1] || *parabuf)
667       sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
668           parabuf, chptr->creationtime);
669   }
670   else
671   {
672     static unsigned int current_flags[4] =
673         { 0, CHFL_CHANOP | CHFL_VOICE, CHFL_VOICE, CHFL_CHANOP };
674     int first = 1, full = 1, flag_cnt = 0, new_mode = 0;
675     size_t len, sblen;
676     Link *lp1 = chptr->members;
677     Link *lp2 = chptr->banlist;
678     for (first = 1; full; first = 0)    /* Loop for multiple messages */
679     {
680       full = 0;                 /* Assume by default we get it
681                                    all in one message */
682
683       /* (Continued) prefix: "<Y> BURST <channel> <TS>" */
684       sprintf_irc(sendbuf, "%s BURST %s " TIME_T_FMT, NumServ(&me),
685           chptr->chname, chptr->creationtime);
686       sblen = strlen(sendbuf);
687
688       if (first && modebuf[1])  /* Add simple modes (iklmnpst)
689                                    if first message */
690       {
691         /* prefix: "<Y> BURST <channel> <TS>[ <modes>[ <params>]]" */
692         sendbuf[sblen++] = ' ';
693         strcpy(sendbuf + sblen, modebuf);
694         sblen += strlen(modebuf);
695         if (*parabuf)
696         {
697           sendbuf[sblen++] = ' ';
698           strcpy(sendbuf + sblen, parabuf);
699           sblen += strlen(parabuf);
700         }
701       }
702
703       /* Attach nicks, comma seperated " nick[:modes],nick[:modes],..." */
704       /* Run 4 times over all members, to group the members with the
705        * same mode together */
706       for (first = 1; flag_cnt < 4;
707           lp1 = chptr->members, new_mode = 1, flag_cnt++)
708       {
709         for (; lp1; lp1 = lp1->next)
710         {
711           if ((lp1->flags & (CHFL_CHANOP | CHFL_VOICE)) !=
712               current_flags[flag_cnt])
713             continue;           /* Skip members with different flags */
714           if (sblen + NUMNICKLEN + 4 > BUFSIZE - 3)
715             /* The 4 is a possible ",:ov"
716                The -3 is for the "\r\n\0" that is added in send.c */
717           {
718             full = 1;           /* Make sure we continue after
719                                    sending it so far */
720             break;              /* Do not add this member to this message */
721           }
722           sendbuf[sblen++] = first ? ' ' : ',';
723           first = 0;            /* From now on, us comma's to add new nicks */
724
725           sprintf_irc(sendbuf + sblen, "%s%s", NumNick(lp1->value.cptr));
726           sblen += strlen(sendbuf + sblen);
727
728           if (new_mode)         /* Do we have a nick with a new mode ? */
729           {
730             new_mode = 0;
731             if (lp1->flags & (CHFL_CHANOP | CHFL_VOICE)) {
732               sendbuf[sblen++] = ':';
733               if (lp1->flags & CHFL_CHANOP)
734                 sendbuf[sblen++] = 'o';
735               if (lp1->flags & CHFL_VOICE)
736                 sendbuf[sblen++] = 'v';
737             }
738           }
739         }
740         if (full)
741           break;
742       }
743
744       if (!full)
745       {
746         /* Attach all bans, space seperated " :%ban ban ..." */
747         for (first = 2; lp2; lp2 = lp2->next)
748         {
749           len = strlen(lp2->value.ban.banstr);
750           if (sblen + len + 1 + first > BUFSIZE - 3)
751             /* The +1 stands for the added ' '.
752              * The +first stands for the added ":%".
753              * The -3 is for the "\r\n\0" that is added in send.c
754              */
755           {
756             full = 1;
757             break;
758           }
759           if (first)
760           {
761             first = 0;
762             sendbuf[sblen++] = ' ';
763             sendbuf[sblen++] = ':';     /* Will be last parameter */
764             sendbuf[sblen++] = '%';     /* To tell bans apart */
765           }
766           else
767             sendbuf[sblen++] = ' ';
768           strcpy(sendbuf + sblen, lp2->value.ban.banstr);
769           sblen += len;
770         }
771       }
772
773       sendbuf[sblen] = '\0';
774       sendbufto_one(cptr);      /* Send this message */
775     }                           /* Continue when there was something
776                                    that didn't fit (full==1) */
777   }
778 }
779
780 /*
781  * m_mode
782  * parv[0] - sender
783  * parv[1] - channel
784  */
785
786 int m_mode(aClient *cptr, aClient *sptr, int parc, char *parv[])
787 {
788   int badop, sendts;
789   aChannel *chptr;
790
791   /* Now, try to find the channel in question */
792   if (parc > 1)
793   {
794     chptr = FindChannel(parv[1]);
795     if (chptr == NullChn)
796       return m_umode(cptr, sptr, parc, parv);
797   }
798   else
799   {
800     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE");
801     return 0;
802   }
803
804   sptr->flags &= ~FLAGS_TS8;
805
806   if (MyUser(sptr))
807     clean_channelname(parv[1]);
808   else if (IsLocalChannel(parv[1]))
809     return 0;
810
811   /* sending an error wasnt good, lets just send an empty mode reply..  poptix */
812   if (IsModelessChannel(chptr->chname))
813   {
814     if (IsUser(sptr))
815       sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
816           chptr->chname, "+nt", "");
817     return 0;
818   }
819
820   if (parc < 3)
821   {
822     *modebuf = *parabuf = '\0';
823     modebuf[1] = '\0';
824     channel_modes(sptr, modebuf, parabuf, chptr);
825     sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
826         chptr->chname, modebuf, parabuf);
827     sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
828         chptr->chname, chptr->creationtime);
829     return 0;
830   }
831
832   LocalChanOperMode = 0;
833
834   if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
835       modebuf, parabuf, nparabuf, &badop)))
836   {
837     sendto_one(sptr, err_str(IsMember(sptr, chptr) ? ERR_CHANOPRIVSNEEDED :
838         ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
839     return 0;
840   }
841
842   if (badop >= 2)
843     send_hack_notice(cptr, sptr, parc, parv, badop, 1);
844
845   if (strlen(modebuf) > (size_t)1 || sendts > 0)
846   {
847     if (badop != 2 && strlen(modebuf) > (size_t)1)
848     {
849 #ifdef OPER_MODE_LCHAN
850       if (LocalChanOperMode) {
851          sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s",
852                                 me.name, chptr->chname, modebuf, parabuf);
853          sendto_op_mask(SNO_HACK4, 
854                         "OPER MODE: %s MODE %s %s %s",
855                         sptr->name,chptr->chname,modebuf,parabuf);
856        }
857        else
858 #endif
859       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
860           parv[0], chptr->chname, modebuf, parabuf);
861     }
862     if (IsLocalChannel(chptr->chname))
863       return 0;
864     /* We send a creationtime of 0, to mark it as a hack --Run */
865     if (IsServer(sptr) && (badop == 2 || sendts > 0))
866     {
867       if (*modebuf == '\0')
868         strcpy(modebuf, "+");
869       if (badop != 2)
870       {
871         sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s %s " TIME_T_FMT,
872             parv[0], chptr->chname, modebuf, parabuf,
873             (badop == 4) ? (time_t) 0 : chptr->creationtime);
874         sendto_highprot_butone(cptr, 10, ":%s MODE %s %s %s " TIME_T_FMT,
875             parv[0], chptr->chname, modebuf, nparabuf,
876             (badop == 4) ? (time_t) 0 : chptr->creationtime);
877       }
878     }
879     else
880     {
881       sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s %s",
882           parv[0], chptr->chname, modebuf, parabuf);
883       sendto_highprot_butone(cptr, 10, ":%s MODE %s %s %s",
884           parv[0], chptr->chname, modebuf, nparabuf);
885     }
886   }
887   return 0;
888 }
889
890 static int DoesOp(char *modebuf)
891 {
892   modebuf--;                    /* Is it possible that a mode
893                                    starts with o and not +o ? */
894   while (*++modebuf)
895     if (*modebuf == 'o' || *modebuf == 'v')
896       return (1);
897   return 0;
898 }
899
900 /* This function should be removed when all servers are 2.10 */
901 static void sendmodeto_one(aClient *cptr, char *from, char *name,
902     char *mode, char *param, time_t creationtime)
903 {
904   if (IsServer(cptr) && DoesOp(mode) && creationtime)
905     sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
906         from, name, mode, param, creationtime);
907   else
908     sendto_one(cptr, ":%s MODE %s %s %s", from, name, mode, param);
909 }
910
911 /*
912  * pretty_mask
913  *
914  * by Carlo Wood (Run), 05 Oct 1998.
915  *
916  * Canonify a mask.
917  *
918  * When the nick is longer then NICKLEN, it is cut off (its an error of course).
919  * When the user name or host name are too long (USERLEN and HOSTLEN
920  * respectively) then they are cut off at the start with a '*'.
921  *
922  * The following transformations are made:
923  *
924  * 1)   xxx             -> nick!*@*
925  * 2)   xxx.xxx         -> *!*@host
926  * 3)   xxx!yyy         -> nick!user@*
927  * 4)   xxx@yyy         -> *!user@host
928  * 5)   xxx!yyy@zzz     -> nick!user@host
929  */
930 char *pretty_mask(char *mask)
931 {
932   static char star[2] = { '*', 0 };
933   char *last_dot = NULL;
934   char *ptr;
935
936   /* Case 1: default */
937   char *nick = mask;
938   char *user = star;
939   char *host = star;
940
941   /* Do a _single_ pass through the characters of the mask: */
942   for (ptr = mask; *ptr; ++ptr)
943   {
944     if (*ptr == '!')
945     {
946       /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
947       user = ++ptr;
948       host = star;
949     }
950     else if (*ptr == '@')
951     {
952       /* Case 4: Found last '@' (without finding a '!' yet) */
953       nick = star;
954       user = mask;
955       host = ++ptr;
956     }
957     else if (*ptr == '.')
958     {
959       /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
960       last_dot = ptr;
961       continue;
962     }
963     else
964       continue;
965     for (; *ptr; ++ptr)
966     {
967       if (*ptr == '@')
968       {
969         /* Case 4 or 5: Found last '@' */
970         host = ptr + 1;
971       }
972     }
973     break;
974   }
975   if (user == star && last_dot)
976   {
977     /* Case 2: */
978     nick = star;
979     user = star;
980     host = mask;
981   }
982   /* Check lengths */
983   if (nick != star)
984   {
985     char *nick_end = (user != star) ? user - 1 : ptr;
986     if (nick_end - nick > NICKLEN)
987       nick[NICKLEN] = 0;
988     *nick_end = 0;
989   }
990   if (user != star)
991   {
992     char *user_end = (host != star) ? host - 1 : ptr;
993     if (user_end - user > USERLEN)
994     {
995       user = user_end - USERLEN;
996       *user = '*';
997     }
998     *user_end = 0;
999   }
1000   if (host != star && ptr - host > HOSTLEN)
1001   {
1002     host = ptr - HOSTLEN;
1003     *host = '*';
1004   }
1005   return make_nick_user_host(nick, user, host);
1006 }
1007
1008 static char bmodebuf[MODEBUFLEN], bparambuf[MODEBUFLEN];
1009 static char nbparambuf[MODEBUFLEN];     /* "Numeric" Bounce Parameter Buffer */
1010
1011 /*
1012  * Check and try to apply the channel modes passed in the parv array for
1013  * the client ccptr to channel chptr.  The resultant changes are printed
1014  * into mbuf and pbuf (if any) and applied to the channel.
1015  */
1016 static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
1017     char *parv[], char *mbuf, char *pbuf, char *npbuf, int *badop)
1018 {
1019   static Link chops[MAXPARA - 2];       /* This size is only needed when a broken
1020                                            server sends more then MAXMODEPARAMS
1021                                            parameters */
1022   static int flags[] = {
1023     MODE_PRIVATE, 'p', MODE_SECRET, 's',
1024     MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
1025     MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i',
1026     MODE_VOICE, 'v', MODE_KEY, 'k',
1027     0x0, 0x0
1028   };
1029
1030   Reg1 Link *lp;
1031   Reg2 char *curr = parv[0], *cp = NULL;
1032   Reg3 int *ip;
1033   Link *member, *tmp = NULL;
1034   unsigned int whatt = MODE_ADD, bwhatt = 0;
1035   int limitset = 0, bounce, add_banid_called = 0;
1036   size_t len, nlen, blen, nblen;
1037   int keychange = 0;
1038   unsigned int nusers = 0, newmode;
1039   int opcnt = 0, banlsent = 0;
1040   int doesdeop = 0, doesop = 0, hacknotice = 0, change, gotts = 0;
1041   aClient *who;
1042   Mode *mode, oldm;
1043   static char numeric[16];
1044   char *bmbuf = bmodebuf, *bpbuf = bparambuf, *nbpbuf = nbparambuf;
1045   time_t newtime = (time_t) 0;
1046   aConfItem *aconf;
1047
1048   *mbuf = *pbuf = *npbuf = *bmbuf = *bpbuf = *nbpbuf = '\0';
1049   *badop = 0;
1050   if (parc < 1)
1051     return 0;
1052
1053   mode = &(chptr->mode);
1054   memcpy(&oldm, mode, sizeof(Mode));
1055   /*
1056    * Mode is accepted when sptr is a channel operator
1057    * but also when the mode is received from a server.
1058    * At this point, let any member pass, so they are allowed
1059    * to see the bans.
1060    */
1061   if (!(IsServer(cptr) || (tmp = IsMember(sptr, chptr))))
1062     return 0;
1063
1064 #ifdef OPER_MODE_LCHAN
1065   if (IsOperOnLocalChannel(sptr, chptr->chname) && !(tmp->flags & CHFL_CHANOP))
1066     LocalChanOperMode = 1;
1067 #endif
1068
1069   newmode = mode->mode;
1070
1071   while (curr && *curr)
1072   {
1073     switch (*curr)
1074     {
1075       case '+':
1076         whatt = MODE_ADD;
1077         break;
1078       case '-':
1079         whatt = MODE_DEL;
1080         break;
1081       case 'o':
1082       case 'v':
1083         if (--parc <= 0)
1084           break;
1085         parv++;
1086         if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1087           break;
1088         /*
1089          * Check for nickname changes and try to follow these
1090          * to make sure the right client is affected by the
1091          * mode change.
1092          * Even if we find a nick with find_chasing() there
1093          * is still a reason to ignore in a special case.
1094          * We need to ignore the mode when:
1095          * - It is part of a net.burst (from a server and
1096          *   a MODE_ADD). Ofcourse we don't ignore mode
1097          *   changes from Uworld.
1098          * - The found nick is not on the right side off
1099          *   the net.junction.
1100          * This fixes the bug that when someone (tries to)
1101          * ride a net.break and does so with the nick of
1102          * someone on the otherside, that he is nick collided
1103          * (killed) but his +o still ops the other person.
1104          */
1105         if (MyUser(sptr) || Protocol(cptr) < 10)
1106         {
1107           if (!(who = find_chasing(sptr, parv[0], NULL)))
1108             break;
1109         }
1110         else
1111         {
1112           if (!(who = findNUser(parv[0])))
1113             break;
1114         }
1115         if (whatt == MODE_ADD && IsServer(sptr) && who->from != sptr->from &&
1116             !find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
1117           break;
1118         if (!(member = find_user_link(chptr->members, who)) ||
1119             (MyUser(sptr) && (member->flags & CHFL_ZOMBIE)))
1120         {
1121           sendto_one(cptr, err_str(ERR_USERNOTINCHANNEL),
1122               me.name, cptr->name, who->name, chptr->chname);
1123           break;
1124         }
1125         /* if the user is +k, prevent a deop from local user */
1126         if (whatt == MODE_DEL && IsChannelService(who) &&
1127             MyUser(cptr) && *curr == 'o')
1128         {
1129           sendto_one(cptr, err_str(ERR_ISCHANSERVICE), me.name,
1130               cptr->name, parv[0], chptr->chname);
1131           break;
1132         }
1133 #ifdef NO_OPER_DEOP_LCHAN
1134         /*
1135          * if the user is an oper on a local channel, prevent him
1136          * from being deoped. that oper can deop himself though.
1137          */
1138         if (whatt == MODE_DEL && IsOperOnLocalChannel(who, chptr->chname) && 
1139             (who != sptr) && MyUser(cptr) && *curr == 'o')
1140         {
1141           sendto_one(cptr, err_str(ERR_ISOPERLCHAN), me.name,
1142                      cptr->name, parv[0], chptr->chname);
1143           break;
1144         }
1145 #endif
1146         if (whatt == MODE_ADD)
1147         {
1148           lp = &chops[opcnt++];
1149           lp->value.cptr = who;
1150           if (IsServer(sptr) && (!(who->flags & FLAGS_TS8) || ((*curr == 'o') &&
1151               !(member->flags & (CHFL_SERVOPOK | CHFL_CHANOP)))))
1152             *badop = ((member->flags & CHFL_DEOPPED) && (*curr == 'o')) ? 2 : 3;
1153           lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
1154           lp->flags |= MODE_ADD;
1155         }
1156         else if (whatt == MODE_DEL)
1157         {
1158           lp = &chops[opcnt++];
1159           lp->value.cptr = who;
1160           doesdeop = 1;         /* Also when -v */
1161           lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
1162           lp->flags |= MODE_DEL;
1163         }
1164         if (*curr == 'o')
1165           doesop = 1;
1166         break;
1167       case 'k':
1168         if (--parc <= 0)
1169           break;
1170         parv++;
1171         /* check now so we eat the parameter if present */
1172         if (keychange)
1173           break;
1174         else
1175         {
1176           char *s = &(*parv)[-1];
1177           unsigned short count = KEYLEN + 1;
1178
1179           while (*++s > ' ' && *s != ':' && --count);
1180           *s = '\0';
1181           if (!**parv)          /* nothing left in key */
1182             break;
1183         }
1184         if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1185           break;
1186         if (whatt == MODE_ADD)
1187         {
1188           if (*mode->key && !IsServer(cptr))
1189             sendto_one(cptr, err_str(ERR_KEYSET),
1190                 me.name, cptr->name, chptr->chname);
1191           else if (!*mode->key || IsServer(cptr))
1192           {
1193             lp = &chops[opcnt++];
1194             lp->value.cp = *parv;
1195             if (strlen(lp->value.cp) > (size_t)KEYLEN)
1196               lp->value.cp[KEYLEN] = '\0';
1197             lp->flags = MODE_KEY | MODE_ADD;
1198             keychange = 1;
1199           }
1200         }
1201         else if (whatt == MODE_DEL)
1202         {
1203           if (strCasediff(mode->key, *parv) == 0 || IsServer(cptr))
1204           {
1205             lp = &chops[opcnt++];
1206             lp->value.cp = mode->key;
1207             lp->flags = MODE_KEY | MODE_DEL;
1208             keychange = 1;
1209           }
1210         }
1211         break;
1212       case 'b':
1213         if (--parc <= 0)
1214         {
1215           if (banlsent)         /* Only send it once */
1216             break;
1217           for (lp = chptr->banlist; lp; lp = lp->next)
1218             sendto_one(cptr, rpl_str(RPL_BANLIST), me.name, cptr->name,
1219                 chptr->chname, lp->value.ban.banstr, lp->value.ban.who,
1220                 lp->value.ban.when);
1221           sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST), me.name, cptr->name,
1222               chptr->chname);
1223           banlsent = 1;
1224           break;
1225         }
1226         parv++;
1227         if (BadPtr(*parv))
1228           break;
1229         if (MyUser(sptr))
1230         {
1231           if ((cp = strchr(*parv, ' ')))
1232             *cp = 0;
1233           if (opcnt >= MAXMODEPARAMS || **parv == ':' || **parv == '\0')
1234             break;
1235         }
1236         if (whatt == MODE_ADD)
1237         {
1238           lp = &chops[opcnt++];
1239           lp->value.cp = *parv;
1240           lp->flags = MODE_ADD | MODE_BAN;
1241         }
1242         else if (whatt == MODE_DEL)
1243         {
1244           lp = &chops[opcnt++];
1245           lp->value.cp = *parv;
1246           lp->flags = MODE_DEL | MODE_BAN;
1247         }
1248         break;
1249       case 'l':
1250         /*
1251          * limit 'l' to only *1* change per mode command but
1252          * eat up others.
1253          */
1254         if (limitset)
1255         {
1256           if (whatt == MODE_ADD && --parc > 0)
1257             parv++;
1258           break;
1259         }
1260         if (whatt == MODE_DEL)
1261         {
1262           limitset = 1;
1263           nusers = 0;
1264           break;
1265         }
1266         if (--parc > 0)
1267         {
1268           if (BadPtr(*parv))
1269             break;
1270           if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1271             break;
1272           if (!(nusers = atoi(*++parv)))
1273             continue;
1274           lp = &chops[opcnt++];
1275           lp->flags = MODE_ADD | MODE_LIMIT;
1276           limitset = 1;
1277           break;
1278         }
1279         sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS),
1280             me.name, cptr->name, "MODE +l");
1281         break;
1282       case 'i':         /* falls through for default case */
1283         if (whatt == MODE_DEL)
1284           while ((lp = chptr->invites))
1285             del_invite(lp->value.cptr, chptr);
1286       default:
1287         for (ip = flags; *ip; ip += 2)
1288           if (*(ip + 1) == *curr)
1289             break;
1290
1291         if (*ip)
1292         {
1293           if (whatt == MODE_ADD)
1294           {
1295             if (*ip == MODE_PRIVATE)
1296               newmode &= ~MODE_SECRET;
1297             else if (*ip == MODE_SECRET)
1298               newmode &= ~MODE_PRIVATE;
1299             newmode |= *ip;
1300           }
1301           else
1302             newmode &= ~*ip;
1303         }
1304         else if (!IsServer(cptr))
1305           sendto_one(cptr, err_str(ERR_UNKNOWNMODE),
1306               me.name, cptr->name, *curr);
1307         break;
1308     }
1309     curr++;
1310     /*
1311      * Make sure mode strings such as "+m +t +p +i" are parsed
1312      * fully.
1313      */
1314     if (!*curr && parc > 0)
1315     {
1316       curr = *++parv;
1317       parc--;
1318       /* If this was from a server, and it is the last
1319        * parameter and it starts with a digit, it must
1320        * be the creationtime.  --Run
1321        */
1322       if (IsServer(sptr))
1323       {
1324         if (parc == 1 && isDigit(*curr))
1325         {
1326           newtime = atoi(curr);
1327           if (newtime && chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
1328           {
1329             chptr->creationtime = newtime;
1330             *badop = 0;
1331           }
1332           gotts = 1;
1333           if (newtime == 0)
1334           {
1335             *badop = 2;
1336             hacknotice = 1;
1337           }
1338           else if (newtime > chptr->creationtime)
1339           {                     /* It is a net-break ride if we have ops.
1340                                    bounce modes if we have ops.  --Run */
1341             if (doesdeop)
1342               *badop = 2;
1343             else if (chptr->creationtime == 0)
1344             {
1345               if (chptr->creationtime == 0 || doesop)
1346                 chptr->creationtime = newtime;
1347               *badop = 0;
1348             }
1349             /* Bounce: */
1350             else
1351               *badop = 1;
1352           }
1353           /*
1354            * A legal *badop can occur when two
1355            * people join simultaneously a channel,
1356            * Allow for 10 min of lag (and thus hacking
1357            * on channels younger then 10 min) --Run
1358            */
1359           else if (*badop == 0 ||
1360               chptr->creationtime > (TStime() - TS_LAG_TIME))
1361           {
1362             if (newtime < chptr->creationtime)
1363               chptr->creationtime = newtime;
1364             *badop = 0;
1365           }
1366           break;
1367         }
1368       }
1369       else
1370         *badop = 0;
1371     }
1372   }                             /* end of while loop for MODE processing */
1373
1374   /*
1375    * Now reject non chan ops. Accept modes from opers on local channels
1376    * even if they are deopped
1377    */
1378 #ifdef OPER_MODE_LCHAN
1379   if (!IsServer(cptr) && 
1380       (!tmp || !((tmp->flags & CHFL_CHANOP) || 
1381                  IsOperOnLocalChannel(sptr, chptr->chname))))
1382 #else
1383   if (!IsServer(cptr) && (!tmp || !(tmp->flags & CHFL_CHANOP)))
1384 #endif
1385   {
1386     *badop = 0;
1387     return (opcnt || newmode != mode->mode || limitset || keychange) ? 0 : -1;
1388   }
1389
1390   if (doesop && newtime == 0 && IsServer(sptr))
1391     *badop = 2;
1392
1393   if (*badop >= 2 &&
1394       (aconf = find_conf_host(cptr->confs, sptr->name, CONF_UWORLD)))
1395     *badop = 4;
1396
1397 #ifdef OPER_MODE_LCHAN
1398   bounce = (*badop == 1 || *badop == 2 || 
1399             (is_deopped(sptr, chptr) && 
1400              !IsOperOnLocalChannel(sptr, chptr->chname))) ? 1 : 0;
1401 #else
1402   bounce = (*badop == 1 || *badop == 2 || is_deopped(sptr, chptr)) ? 1 : 0;
1403 #endif
1404
1405   whatt = 0;
1406   for (ip = flags; *ip; ip += 2)
1407     if ((*ip & newmode) && !(*ip & oldm.mode))
1408     {
1409       if (bounce)
1410       {
1411         if (bwhatt != MODE_DEL)
1412         {
1413           *bmbuf++ = '-';
1414           bwhatt = MODE_DEL;
1415         }
1416         *bmbuf++ = *(ip + 1);
1417       }
1418       else
1419       {
1420         if (whatt != MODE_ADD)
1421         {
1422           *mbuf++ = '+';
1423           whatt = MODE_ADD;
1424         }
1425         mode->mode |= *ip;
1426         *mbuf++ = *(ip + 1);
1427       }
1428     }
1429
1430   for (ip = flags; *ip; ip += 2)
1431     if ((*ip & oldm.mode) && !(*ip & newmode))
1432     {
1433       if (bounce)
1434       {
1435         if (bwhatt != MODE_ADD)
1436         {
1437           *bmbuf++ = '+';
1438           bwhatt = MODE_ADD;
1439         }
1440         *bmbuf++ = *(ip + 1);
1441       }
1442       else
1443       {
1444         if (whatt != MODE_DEL)
1445         {
1446           *mbuf++ = '-';
1447           whatt = MODE_DEL;
1448         }
1449         mode->mode &= ~*ip;
1450         *mbuf++ = *(ip + 1);
1451       }
1452     }
1453
1454   blen = nblen = 0;
1455   if (limitset && !nusers && mode->limit)
1456   {
1457     if (bounce)
1458     {
1459       if (bwhatt != MODE_ADD)
1460       {
1461         *bmbuf++ = '+';
1462         bwhatt = MODE_ADD;
1463       }
1464       *bmbuf++ = 'l';
1465       sprintf(numeric, "%-15d", mode->limit);
1466       if ((cp = strchr(numeric, ' ')))
1467         *cp = '\0';
1468       strcat(bpbuf, numeric);
1469       blen += strlen(numeric);
1470       strcat(bpbuf, " ");
1471       strcat(nbpbuf, numeric);
1472       nblen += strlen(numeric);
1473       strcat(nbpbuf, " ");
1474     }
1475     else
1476     {
1477       if (whatt != MODE_DEL)
1478       {
1479         *mbuf++ = '-';
1480         whatt = MODE_DEL;
1481       }
1482       mode->mode &= ~MODE_LIMIT;
1483       mode->limit = 0;
1484       *mbuf++ = 'l';
1485     }
1486   }
1487   /*
1488    * Reconstruct "+bkov" chain.
1489    */
1490   if (opcnt)
1491   {
1492     Reg1 int i = 0;
1493     Reg2 char c = 0;
1494     unsigned int prev_whatt = 0;
1495
1496     for (; i < opcnt; i++)
1497     {
1498       lp = &chops[i];
1499       /*
1500        * make sure we have correct mode change sign
1501        */
1502       if (whatt != (lp->flags & (MODE_ADD | MODE_DEL)))
1503       {
1504         if (lp->flags & MODE_ADD)
1505         {
1506           *mbuf++ = '+';
1507           prev_whatt = whatt;
1508           whatt = MODE_ADD;
1509         }
1510         else
1511         {
1512           *mbuf++ = '-';
1513           prev_whatt = whatt;
1514           whatt = MODE_DEL;
1515         }
1516       }
1517       len = strlen(pbuf);
1518       nlen = strlen(npbuf);
1519       /*
1520        * get c as the mode char and tmp as a pointer to
1521        * the parameter for this mode change.
1522        */
1523       switch (lp->flags & MODE_WPARAS)
1524       {
1525         case MODE_CHANOP:
1526           c = 'o';
1527           cp = lp->value.cptr->name;
1528           break;
1529         case MODE_VOICE:
1530           c = 'v';
1531           cp = lp->value.cptr->name;
1532           break;
1533         case MODE_BAN:
1534           /*
1535            * I made this a bit more user-friendly (tm):
1536            * nick = nick!*@*
1537            * nick!user = nick!user@*
1538            * user@host = *!user@host
1539            * host.name = *!*@host.name    --Run
1540            */
1541           c = 'b';
1542           cp = pretty_mask(lp->value.cp);
1543           break;
1544         case MODE_KEY:
1545           c = 'k';
1546           cp = lp->value.cp;
1547           break;
1548         case MODE_LIMIT:
1549           c = 'l';
1550           sprintf(numeric, "%-15d", nusers);
1551           if ((cp = strchr(numeric, ' ')))
1552             *cp = '\0';
1553           cp = numeric;
1554           break;
1555       }
1556
1557       /* What could be added: cp+' '+' '+<TS>+'\0' */
1558       if (len + strlen(cp) + 13 > (size_t)MODEBUFLEN ||
1559           nlen + strlen(cp) + NUMNICKLEN + 12 > (size_t)MODEBUFLEN)
1560         break;
1561
1562       switch (lp->flags & MODE_WPARAS)
1563       {
1564         case MODE_KEY:
1565           if (strlen(cp) > (size_t)KEYLEN)
1566             *(cp + KEYLEN) = '\0';
1567           if ((whatt == MODE_ADD && (*mode->key == '\0' ||
1568               strCasediff(mode->key, cp) != 0)) ||
1569               (whatt == MODE_DEL && (*mode->key != '\0')))
1570           {
1571             if (bounce)
1572             {
1573               if (*mode->key == '\0')
1574               {
1575                 if (bwhatt != MODE_DEL)
1576                 {
1577                   *bmbuf++ = '-';
1578                   bwhatt = MODE_DEL;
1579                 }
1580                 strcat(bpbuf, cp);
1581                 blen += strlen(cp);
1582                 strcat(bpbuf, " ");
1583                 blen++;
1584                 strcat(nbpbuf, cp);
1585                 nblen += strlen(cp);
1586                 strcat(nbpbuf, " ");
1587                 nblen++;
1588               }
1589               else
1590               {
1591                 if (bwhatt != MODE_ADD)
1592                 {
1593                   *bmbuf++ = '+';
1594                   bwhatt = MODE_ADD;
1595                 }
1596                 strcat(bpbuf, mode->key);
1597                 blen += strlen(mode->key);
1598                 strcat(bpbuf, " ");
1599                 blen++;
1600                 strcat(nbpbuf, mode->key);
1601                 nblen += strlen(mode->key);
1602                 strcat(nbpbuf, " ");
1603                 nblen++;
1604               }
1605               *bmbuf++ = c;
1606               mbuf--;
1607               if (*mbuf != '+' && *mbuf != '-')
1608                 mbuf++;
1609               else
1610                 whatt = prev_whatt;
1611             }
1612             else
1613             {
1614               *mbuf++ = c;
1615               strcat(pbuf, cp);
1616               len += strlen(cp);
1617               strcat(pbuf, " ");
1618               len++;
1619               strcat(npbuf, cp);
1620               nlen += strlen(cp);
1621               strcat(npbuf, " ");
1622               nlen++;
1623               if (whatt == MODE_ADD)
1624                 strncpy(mode->key, cp, KEYLEN);
1625               else
1626                 *mode->key = '\0';
1627             }
1628           }
1629           break;
1630         case MODE_LIMIT:
1631           if (nusers && nusers != mode->limit)
1632           {
1633             if (bounce)
1634             {
1635               if (mode->limit == 0)
1636               {
1637                 if (bwhatt != MODE_DEL)
1638                 {
1639                   *bmbuf++ = '-';
1640                   bwhatt = MODE_DEL;
1641                 }
1642               }
1643               else
1644               {
1645                 if (bwhatt != MODE_ADD)
1646                 {
1647                   *bmbuf++ = '+';
1648                   bwhatt = MODE_ADD;
1649                 }
1650                 sprintf(numeric, "%-15d", mode->limit);
1651                 if ((cp = strchr(numeric, ' ')))
1652                   *cp = '\0';
1653                 strcat(bpbuf, numeric);
1654                 blen += strlen(numeric);
1655                 strcat(bpbuf, " ");
1656                 blen++;
1657                 strcat(nbpbuf, numeric);
1658                 nblen += strlen(numeric);
1659                 strcat(nbpbuf, " ");
1660                 nblen++;
1661               }
1662               *bmbuf++ = c;
1663               mbuf--;
1664               if (*mbuf != '+' && *mbuf != '-')
1665                 mbuf++;
1666               else
1667                 whatt = prev_whatt;
1668             }
1669             else
1670             {
1671               *mbuf++ = c;
1672               strcat(pbuf, cp);
1673               len += strlen(cp);
1674               strcat(pbuf, " ");
1675               len++;
1676               strcat(npbuf, cp);
1677               nlen += strlen(cp);
1678               strcat(npbuf, " ");
1679               nlen++;
1680               mode->limit = nusers;
1681             }
1682           }
1683           break;
1684         case MODE_CHANOP:
1685         case MODE_VOICE:
1686           tmp = find_user_link(chptr->members, lp->value.cptr);
1687           if (lp->flags & MODE_ADD)
1688           {
1689             change = (~tmp->flags) & CHFL_OVERLAP & lp->flags;
1690             if (change && bounce)
1691             {
1692               if (lp->flags & MODE_CHANOP)
1693                 tmp->flags |= CHFL_DEOPPED;
1694               if (bwhatt != MODE_DEL)
1695               {
1696                 *bmbuf++ = '-';
1697                 bwhatt = MODE_DEL;
1698               }
1699               *bmbuf++ = c;
1700               strcat(bpbuf, lp->value.cptr->name);
1701               blen += strlen(lp->value.cptr->name);
1702               strcat(bpbuf, " ");
1703               blen++;
1704               sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
1705               nblen += strlen(nbpbuf + nblen);
1706               change = 0;
1707             }
1708             else if (change)
1709             {
1710               tmp->flags |= lp->flags & CHFL_OVERLAP;
1711               if (lp->flags & MODE_CHANOP)
1712               {
1713                 tmp->flags &= ~CHFL_DEOPPED;
1714                 if (IsServer(sptr))
1715                   tmp->flags &= ~CHFL_SERVOPOK;
1716               }
1717             }
1718           }
1719           else
1720           {
1721             change = tmp->flags & CHFL_OVERLAP & lp->flags;
1722             if (change && bounce)
1723             {
1724               if (lp->flags & MODE_CHANOP)
1725                 tmp->flags &= ~CHFL_DEOPPED;
1726               if (bwhatt != MODE_ADD)
1727               {
1728                 *bmbuf++ = '+';
1729                 bwhatt = MODE_ADD;
1730               }
1731               *bmbuf++ = c;
1732               strcat(bpbuf, lp->value.cptr->name);
1733               blen += strlen(lp->value.cptr->name);
1734               strcat(bpbuf, " ");
1735               blen++;
1736               sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
1737               blen += strlen(bpbuf + blen);
1738               change = 0;
1739             }
1740             else
1741             {
1742               tmp->flags &= ~change;
1743               if ((change & MODE_CHANOP) && IsServer(sptr))
1744                 tmp->flags |= CHFL_DEOPPED;
1745             }
1746           }
1747           if (change || *badop == 2 || *badop == 4)
1748           {
1749             *mbuf++ = c;
1750             strcat(pbuf, cp);
1751             len += strlen(cp);
1752             strcat(pbuf, " ");
1753             len++;
1754             sprintf_irc(npbuf + nlen, "%s%s ", NumNick(lp->value.cptr));
1755             nlen += strlen(npbuf + nlen);
1756             npbuf[nlen++] = ' ';
1757             npbuf[nlen] = 0;
1758           }
1759           else
1760           {
1761             mbuf--;
1762             if (*mbuf != '+' && *mbuf != '-')
1763               mbuf++;
1764             else
1765               whatt = prev_whatt;
1766           }
1767           break;
1768         case MODE_BAN:
1769 /*
1770  * Only bans aren't bounced, it makes no sense to bounce last second
1771  * bans while propagating bans done before the net.rejoin. The reason
1772  * why I don't bounce net.rejoin bans is because it is too much
1773  * work to take care of too long strings adding the necessary TS to
1774  * net.burst bans -- RunLazy
1775  * We do have to check for *badop==2 now, we don't want HACKs to take
1776  * effect.
1777  *
1778  * Since BURST - I *did* implement net.rejoin ban bouncing. So now it
1779  * certainly makes sense to also bounce 'last second' bans (bans done
1780  * after the net.junction). -- RunHardWorker
1781  */
1782           if ((change = (whatt & MODE_ADD) &&
1783               !add_banid(sptr, chptr, cp, !bounce, !add_banid_called)))
1784             add_banid_called = 1;
1785           else
1786             change = (whatt & MODE_DEL) && !del_banid(chptr, cp, !bounce);
1787
1788           if (bounce && change)
1789           {
1790             change = 0;
1791             if ((whatt & MODE_ADD))
1792             {
1793               if (bwhatt != MODE_DEL)
1794               {
1795                 *bmbuf++ = '-';
1796                 bwhatt = MODE_DEL;
1797               }
1798             }
1799             else if ((whatt & MODE_DEL))
1800             {
1801               if (bwhatt != MODE_ADD)
1802               {
1803                 *bmbuf++ = '+';
1804                 bwhatt = MODE_ADD;
1805               }
1806             }
1807             *bmbuf++ = c;
1808             strcat(bpbuf, cp);
1809             blen += strlen(cp);
1810             strcat(bpbuf, " ");
1811             blen++;
1812             strcat(nbpbuf, cp);
1813             nblen += strlen(cp);
1814             strcat(nbpbuf, " ");
1815             nblen++;
1816           }
1817           if (change)
1818           {
1819             *mbuf++ = c;
1820             strcat(pbuf, cp);
1821             len += strlen(cp);
1822             strcat(pbuf, " ");
1823             len++;
1824             strcat(npbuf, cp);
1825             nlen += strlen(cp);
1826             strcat(npbuf, " ");
1827             nlen++;
1828           }
1829           else
1830           {
1831             mbuf--;
1832             if (*mbuf != '+' && *mbuf != '-')
1833               mbuf++;
1834             else
1835               whatt = prev_whatt;
1836           }
1837           break;
1838       }
1839     }                           /* for (; i < opcnt; i++) */
1840   }                             /* if (opcnt) */
1841
1842   *mbuf++ = '\0';
1843   *bmbuf++ = '\0';
1844
1845   /* Bounce here */
1846   if (!hacknotice && *bmodebuf && chptr->creationtime)
1847   {
1848     if (Protocol(cptr) < 10)
1849       sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
1850           me.name, chptr->chname, bmodebuf, bparambuf,
1851           *badop == 2 ? (time_t) 0 : chptr->creationtime);
1852     else
1853       sendto_one(cptr, "%s MODE %s %s %s " TIME_T_FMT,
1854           NumServ(&me), chptr->chname, bmodebuf, nbparambuf,
1855           *badop == 2 ? (time_t) 0 : chptr->creationtime);
1856   }
1857   /* If there are possibly bans to re-add, bounce them now */
1858   if (add_banid_called && bounce)
1859   {
1860     Link *ban[6];               /* Max 6 bans at a time */
1861     size_t len[6], sblen, total_len;
1862     int cnt, delayed = 0;
1863     while (delayed || (ban[0] = next_overlapped_ban()))
1864     {
1865       len[0] = strlen(ban[0]->value.ban.banstr);
1866       cnt = 1;                  /* We already got one ban :) */
1867       sblen = sprintf_irc(sendbuf, ":%s MODE %s +b",
1868           me.name, chptr->chname) - sendbuf;
1869       total_len = sblen + 1 + len[0];   /* 1 = ' ' */
1870       /* Find more bans: */
1871       delayed = 0;
1872       while (cnt < 6 && (ban[cnt] = next_overlapped_ban()))
1873       {
1874         len[cnt] = strlen(ban[cnt]->value.ban.banstr);
1875         if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
1876         {
1877           delayed = cnt + 1;    /* != 0 */
1878           break;                /* Flush */
1879         }
1880         sendbuf[sblen++] = 'b';
1881         total_len += 2 + len[cnt++];    /* 2 = "b " */
1882       }
1883       while (cnt--)
1884       {
1885         sendbuf[sblen++] = ' ';
1886         strcpy(sendbuf + sblen, ban[cnt]->value.ban.banstr);
1887         sblen += len[cnt];
1888       }
1889       sendbufto_one(cptr);      /* Send bounce to uplink */
1890       if (delayed)
1891         ban[0] = ban[delayed - 1];
1892     }
1893   }
1894   /* Send -b's of overlapped bans to clients to keep them synchronized */
1895   if (add_banid_called && !bounce)
1896   {
1897     Link *ban;
1898     char *banstr[6];            /* Max 6 bans at a time */
1899     size_t len[6], sblen, psblen, total_len;
1900     int cnt, delayed = 0;
1901     Link *lp;
1902     aClient *acptr;
1903     if (IsServer(sptr))
1904       psblen = sprintf_irc(sendbuf, ":%s MODE %s -b",
1905           sptr->name, chptr->chname) - sendbuf;
1906     else                        /* We rely on IsRegistered(sptr) being true for MODE */
1907       psblen = sprintf_irc(sendbuf, ":%s!%s@%s MODE %s -b", sptr->name,
1908           sptr->user->username, sptr->user->host, chptr->chname) - sendbuf;
1909     while (delayed || (ban = next_removed_overlapped_ban()))
1910     {
1911       if (!delayed)
1912       {
1913         len[0] = strlen((banstr[0] = ban->value.ban.banstr));
1914         ban->value.ban.banstr = NULL;
1915       }
1916       cnt = 1;                  /* We already got one ban :) */
1917       sblen = psblen;
1918       total_len = sblen + 1 + len[0];   /* 1 = ' ' */
1919       /* Find more bans: */
1920       delayed = 0;
1921       while (cnt < 6 && (ban = next_removed_overlapped_ban()))
1922       {
1923         len[cnt] = strlen((banstr[cnt] = ban->value.ban.banstr));
1924         ban->value.ban.banstr = NULL;
1925         if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
1926         {
1927           delayed = cnt + 1;    /* != 0 */
1928           break;                /* Flush */
1929         }
1930         sendbuf[sblen++] = 'b';
1931         total_len += 2 + len[cnt++];    /* 2 = "b " */
1932       }
1933       while (cnt--)
1934       {
1935         sendbuf[sblen++] = ' ';
1936         strcpy(sendbuf + sblen, banstr[cnt]);
1937         RunFree(banstr[cnt]);
1938         sblen += len[cnt];
1939       }
1940       for (lp = chptr->members; lp; lp = lp->next)
1941         if (MyConnect(acptr = lp->value.cptr) && !(lp->flags & CHFL_ZOMBIE))
1942           sendbufto_one(acptr);
1943       if (delayed)
1944       {
1945         banstr[0] = banstr[delayed - 1];
1946         len[0] = len[delayed - 1];
1947       }
1948     }
1949   }
1950
1951   return gotts ? 1 : -1;
1952 }
1953
1954 /* We are now treating the <key> part of /join <channel list> <key> as a key
1955  * ring; that is, we try one key against the actual channel key, and if that
1956  * doesn't work, we try the next one, and so on. -Kev -Texaco
1957  * Returns: 0 on match, 1 otherwise
1958  * This version contributed by SeKs <intru@info.polymtl.ca>
1959  */
1960 static int compall(char *key, char *keyring)
1961 {
1962   register char *p1;
1963
1964 top:
1965   p1 = key;                     /* point to the key... */
1966   while (*p1 && *p1 == *keyring)
1967   {                             /* step through the key and ring until they
1968                                    don't match... */
1969     p1++;
1970     keyring++;
1971   }
1972
1973   if (!*p1 && (!*keyring || *keyring == ','))
1974     /* ok, if we're at the end of the and also at the end of one of the keys
1975        in the keyring, we have a match */
1976     return 0;
1977
1978   if (!*keyring)                /* if we're at the end of the key ring, there
1979                                    weren't any matches, so we return 1 */
1980     return 1;
1981
1982   /* Not at the end of the key ring, so step
1983      through to the next key in the ring: */
1984   while (*keyring && *(keyring++) != ',');
1985
1986   goto top;                     /* and check it against the key */
1987 }
1988
1989 static int can_join(aClient *sptr, aChannel *chptr, char *key)
1990 {
1991   Reg1 Link *lp;
1992   int overrideJoin = 0;  
1993   
1994 #ifdef OPER_WALK_THROUGH_LMODES
1995   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
1996      a HACK(4) notice will be sent if he would not have been supposed
1997      to join normally. */ 
1998   if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && 
1999        compall("OVERRIDE",key) == 0)
2000     overrideJoin = MAGIC_OPER_OVERRIDE;
2001 #endif
2002   /*
2003    * Now a banned user CAN join if invited -- Nemesi
2004    * Now a user CAN escape channel limit if invited -- bfriendly
2005    */
2006   if ((chptr->mode.mode & MODE_INVITEONLY) || (is_banned(sptr, chptr, NULL)
2007       || (chptr->mode.limit && chptr->users >= chptr->mode.limit)))
2008   {
2009     for (lp = sptr->user->invited; lp; lp = lp->next)
2010       if (lp->value.chptr == chptr)
2011         break;
2012     if (!lp)
2013     {
2014       if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
2015         return (overrideJoin + ERR_CHANNELISFULL);
2016       /*
2017        * This can return an "Invite only" msg instead of the "You are banned"
2018        * if _both_ conditions are true, but who can say what is more
2019        * appropriate ? checking again IsBanned would be _SO_ cpu-xpensive !
2020        */
2021       return overrideJoin + ((chptr->mode.mode & MODE_INVITEONLY) ?
2022           ERR_INVITEONLYCHAN : ERR_BANNEDFROMCHAN);
2023     }
2024   }
2025
2026   /* now using compall (above) to test against a whole key ring -Kev */
2027   if (*chptr->mode.key && (BadPtr(key) || compall(chptr->mode.key, key)))
2028     return overrideJoin + (ERR_BADCHANNELKEY);
2029
2030   return 0;
2031 }
2032
2033 /*
2034  * Remove bells and commas from channel name
2035  */
2036
2037 static void clean_channelname(char *cn)
2038 {
2039   for (; *cn; cn++)
2040   {
2041     if (!isIrcCh(*cn))
2042     {
2043       *cn = '\0';
2044       return;
2045     }
2046     if (isIrcCl(*cn))
2047 #ifndef FIXME
2048     {
2049 #endif
2050       *cn = toLower(*cn);
2051 #ifndef FIXME
2052       /* Missed the Icelandic letter ETH last time: */
2053       if ((unsigned char)(*cn) == 0xd0)
2054         *cn = (char)0xf0;
2055     }
2056 #endif
2057   }
2058 }
2059
2060 /*
2061  *  Get Channel block for i (and allocate a new channel
2062  *  block, if it didn't exists before).
2063  */
2064 static aChannel *get_channel(aClient *cptr, char *chname, int flag)
2065 {
2066   Reg1 aChannel *chptr;
2067   int len;
2068
2069   if (BadPtr(chname))
2070     return NULL;
2071
2072   len = strlen(chname);
2073   if (MyUser(cptr) && len > CHANNELLEN)
2074   {
2075     len = CHANNELLEN;
2076     *(chname + CHANNELLEN) = '\0';
2077   }
2078   if ((chptr = FindChannel(chname)))
2079     return (chptr);
2080   if (flag == CREATE)
2081   {
2082     chptr = (aChannel *)RunMalloc(sizeof(aChannel) + len);
2083     ++nrof.channels;
2084     memset(chptr, 0, sizeof(aChannel));
2085     strcpy(chptr->chname, chname);
2086     if (channel)
2087       channel->prevch = chptr;
2088     chptr->prevch = NULL;
2089     chptr->nextch = channel;
2090     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
2091     channel = chptr;
2092     hAddChannel(chptr);
2093   }
2094   return chptr;
2095 }
2096
2097 static void add_invite(aClient *cptr, aChannel *chptr)
2098 {
2099   Reg1 Link *inv, **tmp;
2100
2101   del_invite(cptr, chptr);
2102   /*
2103    * Delete last link in chain if the list is max length
2104    */
2105   if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
2106     del_invite(cptr, cptr->user->invited->value.chptr);
2107   /*
2108    * Add client to channel invite list
2109    */
2110   inv = make_link();
2111   inv->value.cptr = cptr;
2112   inv->next = chptr->invites;
2113   chptr->invites = inv;
2114   /*
2115    * Add channel to the end of the client invite list
2116    */
2117   for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next));
2118   inv = make_link();
2119   inv->value.chptr = chptr;
2120   inv->next = NULL;
2121   (*tmp) = inv;
2122 }
2123
2124 /*
2125  * Delete Invite block from channel invite list and client invite list
2126  */
2127 void del_invite(aClient *cptr, aChannel *chptr)
2128 {
2129   Reg1 Link **inv, *tmp;
2130
2131   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
2132     if (tmp->value.cptr == cptr)
2133     {
2134       *inv = tmp->next;
2135       free_link(tmp);
2136       break;
2137     }
2138
2139   for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
2140     if (tmp->value.chptr == chptr)
2141     {
2142       *inv = tmp->next;
2143       free_link(tmp);
2144       break;
2145     }
2146 }
2147
2148 /* List and skip all channels that are listen */
2149 void list_next_channels(aClient *cptr, int nr)
2150 {
2151   aListingArgs *args = cptr->listing;
2152   aChannel *chptr = args->chptr;
2153   chptr->mode.mode &= ~MODE_LISTED;
2154   while (is_listed(chptr) || --nr >= 0)
2155   {
2156     for (; chptr; chptr = chptr->nextch)
2157     {
2158       if (!cptr->user || (SecretChannel(chptr) && !IsMember(cptr, chptr)))
2159         continue;
2160       if (chptr->users > args->min_users && chptr->users < args->max_users &&
2161           chptr->creationtime > args->min_time &&
2162           chptr->creationtime < args->max_time &&
2163           (!args->topic_limits || (*chptr->topic &&
2164           chptr->topic_time > args->min_topic_time &&
2165           chptr->topic_time < args->max_topic_time)))
2166       {
2167         sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
2168             ShowChannel(cptr, chptr) ? chptr->chname : "*",
2169             chptr->users, ShowChannel(cptr, chptr) ? chptr->topic : "");
2170         chptr = chptr->nextch;
2171         break;
2172       }
2173     }
2174     if (!chptr)
2175     {
2176       RunFree(cptr->listing);
2177       cptr->listing = NULL;
2178       sendto_one(cptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
2179       break;
2180     }
2181   }
2182   if (chptr)
2183   {
2184     cptr->listing->chptr = chptr;
2185     chptr->mode.mode |= MODE_LISTED;
2186   }
2187 }
2188
2189 /*
2190  *  Subtract one user from channel i (and free channel
2191  *  block, if channel became empty).
2192  */
2193 static void sub1_from_channel(aChannel *chptr)
2194 {
2195   Reg2 Link *tmp;
2196   Link *obtmp;
2197
2198   if (chptr->users > 1)         /* Can be 0, called for an empty channel too */
2199   {
2200     --chptr->users;
2201     return;
2202   }
2203
2204   /* Channel became (or was) empty: Remove channel */
2205   if (is_listed(chptr))
2206   {
2207     int i;
2208     for (i = 0; i <= highest_fd; i++)
2209     {
2210       aClient *acptr;
2211       if ((acptr = loc_clients[i]) && acptr->listing &&
2212           acptr->listing->chptr == chptr)
2213       {
2214         list_next_channels(acptr, 1);
2215         break;                  /* Only one client can list a channel */
2216       }
2217     }
2218   }
2219   /*
2220    * Now, find all invite links from channel structure
2221    */
2222   while ((tmp = chptr->invites))
2223     del_invite(tmp->value.cptr, chptr);
2224
2225   tmp = chptr->banlist;
2226   while (tmp)
2227   {
2228     obtmp = tmp;
2229     tmp = tmp->next;
2230     RunFree(obtmp->value.ban.banstr);
2231     RunFree(obtmp->value.ban.who);
2232     free_link(obtmp);
2233   }
2234   if (chptr->prevch)
2235     chptr->prevch->nextch = chptr->nextch;
2236   else
2237     channel = chptr->nextch;
2238   if (chptr->nextch)
2239     chptr->nextch->prevch = chptr->prevch;
2240   hRemChannel(chptr);
2241   --nrof.channels;
2242   RunFree((char *)chptr);
2243 }
2244
2245 /*
2246  * m_join
2247  *
2248  * parv[0] = sender prefix
2249  * parv[1] = channel
2250  * parv[2] = channel keys (client), or channel TS (server)
2251  */
2252 int m_join(aClient *cptr, aClient *sptr, int parc, char *parv[])
2253 {
2254   static char jbuf[BUFSIZE], mbuf[BUFSIZE];
2255   Reg1 Link *lp;
2256   Reg3 aChannel *chptr;
2257   Reg4 char *name, *keysOrTS = NULL;
2258   int i = 0, zombie = 0, sendcreate = 0;
2259   unsigned int flags = 0;
2260   size_t jlen = 0, mlen = 0;
2261   size_t *buflen;
2262   char *p = NULL, *bufptr;
2263
2264   if (parc < 2 || *parv[1] == '\0')
2265   {
2266     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "JOIN");
2267     return 0;
2268   }
2269
2270   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
2271     if (*p == '0'
2272         && (*(p + 1) == ',' || *(p + 1) == '\0' || !isIrcCh(*(p + 1))))
2273     {
2274       /* If it's a single "0", remember the place; we will start parsing
2275          the channels after the last 0 in the line -Kev */
2276       parv[1] = p;
2277       if (!*(p + 1))
2278         break;
2279       p++;
2280     }
2281     else
2282     {                           /* Step through to the next comma or until the
2283                                    end of the line, in an attempt to save CPU
2284                                    -Kev */
2285       while (*p != ',' && *p != '\0')
2286         p++;
2287       if (!*p)
2288         break;
2289     }
2290
2291   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
2292                                    parv[2] needs to be NULL for the call to
2293                                    m_names below -Kev */
2294   parv[2] = p = NULL;
2295
2296   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
2297   /*
2298    *  Rebuild list of channels joined to be the actual result of the
2299    *  JOIN.  Note that "JOIN 0" is the destructive problem.
2300    */
2301   for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ","))
2302   {
2303     size_t len;
2304     if (MyConnect(sptr))
2305       clean_channelname(name);
2306     else if (IsLocalChannel(name))
2307       continue;
2308     if (*name == '0' && *(name + 1) == '\0')
2309     {
2310       /* Remove the user from all his channels -Kev */
2311       while ((lp = sptr->user->channel))
2312       {
2313         chptr = lp->value.chptr;
2314         if (!is_zombie(sptr, chptr))
2315           sendto_channel_butserv(chptr, sptr, PartFmt2,
2316               parv[0], chptr->chname, "Left all channels");
2317         remove_user_from_channel(sptr, chptr);
2318       }
2319       /* Just in case */
2320       *mbuf = *jbuf = '\0';
2321       mlen = jlen = 0;
2322     }
2323     else
2324     {                           /* not a /join 0, so treat it as
2325                                    a /join #channel -Kev */
2326       if (!IsChannelName(name))
2327       {
2328         if (MyUser(sptr))
2329           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
2330         continue;
2331       }
2332
2333       if (MyConnect(sptr))
2334       { 
2335 #ifdef BADCHAN
2336         if(bad_channel(name) && !IsAnOper(sptr))
2337         {
2338           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0],name);
2339           continue;
2340         }
2341 #endif
2342
2343         /*
2344          * Local client is first to enter previously nonexistant
2345          * channel so make them (rightfully) the Channel Operator.
2346          * This looks kind of ugly because we try to avoid calling the strlen()
2347          */
2348         if (ChannelExists(name))
2349         {
2350           flags = CHFL_DEOPPED;
2351           sendcreate = 0;
2352         }
2353         else if (strlen(name) > CHANNELLEN)
2354         {
2355           *(name + CHANNELLEN) = '\0';
2356           if (ChannelExists(name))
2357           {
2358             flags = CHFL_DEOPPED;
2359             sendcreate = 0;
2360           }
2361           else
2362           {
2363             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
2364             sendcreate = 1;
2365           }
2366         }
2367         else
2368         {
2369           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
2370           sendcreate = 1;
2371         }
2372
2373 #ifdef OPER_NO_CHAN_LIMIT
2374         /*
2375          * Opers are allowed to join any number of channels
2376          */
2377         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
2378 #else
2379         if (sptr->user->joined >= MAXCHANNELSPERUSER)
2380 #endif
2381         {
2382           chptr = get_channel(sptr, name, !CREATE);
2383           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
2384               me.name, parv[0], chptr ? chptr->chname : name);
2385           break;                /* Can't return, else he won't get on ANY
2386                                    channels!  Break out of the for loop instead.
2387                                    -Kev */
2388         }
2389       }
2390       chptr = get_channel(sptr, name, CREATE);
2391       if (chptr && (lp = find_user_link(chptr->members, sptr)))
2392       {
2393         if (lp->flags & CHFL_ZOMBIE)
2394         {
2395           zombie = 1;
2396           flags = lp->flags & (CHFL_DEOPPED | CHFL_SERVOPOK);
2397           remove_user_from_channel(sptr, chptr);
2398           chptr = get_channel(sptr, name, CREATE);
2399         }
2400         else
2401           continue;
2402       }
2403       name = chptr->chname;
2404       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
2405         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
2406       if (parc > 2)
2407       {
2408         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
2409           chptr->creationtime = atoi(keysOrTS);
2410         else
2411           parc = 2;             /* Don't pass it on */
2412       }
2413       if (!zombie)
2414       {
2415         if (!MyConnect(sptr))
2416           flags = CHFL_DEOPPED;
2417         if (sptr->flags & FLAGS_TS8)
2418           flags |= CHFL_SERVOPOK;
2419       }
2420       if (MyConnect(sptr))
2421       {
2422         int created = chptr->users == 0;
2423         if (check_target_limit(sptr, chptr, chptr->chname, created))
2424         {
2425           if (created)          /* Did we create the channel? */
2426             sub1_from_channel(chptr);   /* Remove it again! */
2427           continue;
2428         }
2429         if ((i = can_join(sptr, chptr, keysOrTS)))
2430         {
2431 #ifdef OPER_WALK_THROUGH_LMODES
2432           if (i > MAGIC_OPER_OVERRIDE)
2433           {
2434             switch(i - MAGIC_OPER_OVERRIDE)
2435             {
2436               case ERR_CHANNELISFULL: i = 'l'; break;
2437               case ERR_INVITEONLYCHAN: i = 'i'; break;
2438               case ERR_BANNEDFROMCHAN: i = 'b'; break;
2439               case ERR_BADCHANNELKEY: i = 'k'; break;
2440             }
2441             sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
2442           }
2443           else
2444           {
2445             sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
2446             continue; 
2447           }
2448 #else     
2449           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
2450           continue;
2451 #endif
2452         }
2453       }
2454       /*
2455        * Complete user entry to the new channel (if any)
2456        */
2457       add_user_to_channel(chptr, sptr, flags);
2458
2459       /*
2460        * Notify all other users on the new channel
2461        */
2462       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
2463
2464       if (MyUser(sptr))
2465       {
2466         del_invite(sptr, chptr);
2467         if (chptr->topic[0] != '\0')
2468         {
2469           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
2470               parv[0], name, chptr->topic);
2471           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
2472               chptr->topic_nick, chptr->topic_time);
2473         }
2474         parv[1] = name;
2475         m_names(cptr, sptr, 2, parv);
2476       }
2477     }
2478
2479     /* Select proper buffer; mbuf for creation, jbuf otherwise */
2480
2481     if (*name == '&')
2482       continue;                 /* Head off local channels at the pass */
2483
2484     bufptr = (sendcreate == 0) ? jbuf : mbuf;
2485     buflen = (sendcreate == 0) ? &jlen : &mlen;
2486     len = strlen(name);
2487     if (*buflen < BUFSIZE - len - 2)
2488     {
2489       if (*bufptr)
2490       {
2491         strcat(bufptr, ",");    /* Add to join buf */
2492         *buflen += 1;
2493       }
2494       strncat(bufptr, name, BUFSIZE - *buflen - 1);
2495       *buflen += len;
2496     }
2497     sendcreate = 0;             /* Reset sendcreate */
2498   }
2499
2500 #ifndef NO_PROTOCOL9
2501   if (*jbuf || *mbuf)           /* Propagate joins to P09 servers */
2502     sendto_lowprot_butone(cptr, 9, (*jbuf && *mbuf) ? ":%s JOIN %s,%s" :
2503         ":%s JOIN %s%s", parv[0], jbuf, mbuf);
2504 #endif
2505
2506   if (*jbuf)                    /* Propgate joins to P10 servers */
2507 #ifdef NO_PROTOCOL9
2508     sendto_serv_butone(cptr,
2509         parc > 2 ? ":%s JOIN %s %s" : ":%s JOIN %s", parv[0], jbuf, keysOrTS);
2510 #else
2511     sendto_highprot_butone(cptr, 10,
2512         parc > 2 ? ":%s JOIN %s %s" : ":%s JOIN %s", parv[0], jbuf, keysOrTS);
2513 #endif
2514   if (*mbuf)                    /* and now creation events */
2515 #ifdef NO_PROTOCOL9
2516     sendto_serv_butone(cptr, "%s%s CREATE %s " TIME_T_FMT,
2517         NumNick(sptr), mbuf, TStime());
2518 #else
2519     sendto_highprot_butone(cptr, 10, "%s%s CREATE %s " TIME_T_FMT,
2520         NumNick(sptr), mbuf, TStime());
2521 #endif
2522
2523   if (MyUser(sptr))
2524   {                             /* shouldn't ever set TS for remote JOIN's */
2525     if (*jbuf)
2526     {                           /* check for channels that need TS's */
2527       p = NULL;
2528       for (name = strtoken(&p, jbuf, ","); name; name = strtoken(&p, NULL, ","))
2529       {
2530         chptr = get_channel(sptr, name, !CREATE);
2531         if (chptr && chptr->mode.mode & MODE_SENDTS)
2532         {                       /* send a TS? */
2533           sendto_serv_butone(cptr, ":%s MODE %s + " TIME_T_FMT, me.name,
2534               chptr->chname, chptr->creationtime);      /* ok, send TS */
2535           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
2536         }
2537       }
2538     }
2539
2540     if (*mbuf)
2541     {                           /* ok, send along modes for creation events to P9 */
2542       p = NULL;
2543       for (name = strtoken(&p, mbuf, ","); name; name = strtoken(&p, NULL, ","))
2544       {
2545         chptr = get_channel(sptr, name, !CREATE);
2546         sendto_lowprot_butone(cptr, 9, ":%s MODE %s +o %s " TIME_T_FMT,
2547             me.name, chptr->chname, parv[0], chptr->creationtime);
2548       }
2549     }
2550   }
2551   return 0;
2552 }
2553
2554 /*
2555  * m_destruct
2556  *
2557  * parv[0] = sender prefix
2558  * parv[1] = channel channelname
2559  * parv[2] = channel time stamp
2560  *
2561  * This function does nothing, it does passes DESTRUCT to the other servers.
2562  * In the future we will start to use this message.
2563  *
2564  */
2565 int m_destruct(aClient *cptr, aClient *sptr, int parc, char *parv[])
2566 {
2567   time_t chanTS;                /* Creation time of the channel */
2568
2569   if (parc < 3 || *parv[2] == '\0')
2570     return 0;
2571
2572 #ifdef GODMODE
2573   /* Allow DESTRUCT from user */
2574   if (MyUser(sptr))
2575     sptr = &me;
2576   else
2577 #endif
2578
2579     /* sanity checks: Only accept DESTRUCT messages from servers */
2580   if (!IsServer(sptr))
2581     return 0;
2582
2583   /* Don't pass on DESTRUCT messages for channels that exist */
2584   if (FindChannel(parv[1]))
2585     return 0;
2586
2587   chanTS = atoi(parv[2]);
2588
2589   /* Pass on DESTRUCT message */
2590   sendto_highprot_butone(cptr, 10, "%s DESTRUCT %s " TIME_T_FMT,
2591       NumServ(sptr), parv[1], chanTS);
2592
2593   return 0;
2594 }
2595
2596 /*
2597  * m_create
2598  *
2599  * parv[0] = sender prefix
2600  * parv[1] = channel names
2601  * parv[2] = channel time stamp
2602  */
2603 int m_create(aClient *cptr, aClient *sptr, int parc, char *parv[])
2604 {
2605   char cbuf[BUFSIZE];           /* Buffer for list with channels
2606                                    that `sptr' really creates */
2607   time_t chanTS;                /* Creation time for all channels
2608                                    in the comma seperated list */
2609   char *p, *name;
2610   Reg5 aChannel *chptr;
2611   int badop;
2612
2613   /* sanity checks: Only accept CREATE messages from servers */
2614   if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
2615     return 0;
2616
2617   chanTS = atoi(parv[2]);
2618
2619   *cbuf = '\0';                 /* Start with empty buffer */
2620
2621   /* For each channel in the comma seperated list: */
2622   for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ","))
2623   {
2624     badop = 0;                  /* Default is to accept the op */
2625     if ((chptr = FindChannel(name)))
2626     {
2627       name = chptr->chname;
2628       if (TStime() - chanTS > TS_LAG_TIME)
2629       {
2630         /* A bounce would not be accepted anyway - if we get here something
2631            is wrong with the TS clock syncing (or we have more then
2632            TS_LAG_TIME lag, or an admin is hacking */
2633         badop = 2;
2634         /* This causes a HACK notice on all upstream servers: */
2635         if (Protocol(cptr) < 10)
2636           sendto_one(cptr, ":%s MODE %s -o %s 0", me.name, name, sptr->name);
2637         else
2638           sendto_one(cptr, ":%s MODE %s -o %s%s 0",
2639               me.name, name, NumNick(sptr));
2640         /* This causes a WALLOPS on all downstream servers and a notice to our
2641            own opers: */
2642         parv[1] = name;         /* Corrupt parv[1], it is not used anymore anyway */
2643         send_hack_notice(cptr, sptr, parc, parv, badop, 2);
2644       }
2645       else if (chptr->creationtime && chanTS > chptr->creationtime &&
2646           chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
2647       {
2648         /* We (try) to bounce the mode, because the CREATE is used on an older
2649            channel, probably a net.ride */
2650         badop = 1;
2651         /* Send a deop upstream: */
2652         if (Protocol(cptr) < 10)
2653           sendto_one(cptr, ":%s MODE %s -o %s " TIME_T_FMT, me.name,
2654               name, sptr->name, chptr->creationtime);
2655         else
2656           sendto_one(cptr, ":%s MODE %s -o %s%s " TIME_T_FMT, me.name,
2657               name, NumNick(sptr), chptr->creationtime);
2658       }
2659     }
2660     else                        /* Channel doesn't exist: create it */
2661       chptr = get_channel(sptr, name, CREATE);
2662
2663     /* Add and mark ops */
2664     add_user_to_channel(chptr, sptr,
2665         (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
2666
2667     /* Send user join to the local clients (if any) */
2668     sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
2669
2670     if (badop)                  /* handle badop: convert CREATE into JOIN */
2671       sendto_serv_butone(cptr, ":%s JOIN %s " TIME_T_FMT,
2672           sptr->name, name, chptr->creationtime);
2673     else
2674     {
2675       /* Send the op to local clients:
2676          (if any; extremely unlikely, but it CAN happen) */
2677       if (!IsModelessChannel(name))
2678         sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
2679             sptr->user->server->name, name, parv[0]);
2680
2681       /* Set/correct TS and add the channel to the
2682          buffer for accepted channels: */
2683       chptr->creationtime = chanTS;
2684       if (*cbuf)
2685         strcat(cbuf, ",");
2686       strcat(cbuf, name);
2687     }
2688   }
2689
2690   if (*cbuf)                    /* Any channel accepted with ops ? */
2691   {
2692 #ifdef NO_PROTOCOL9
2693     sendto_serv_butone(cptr, "%s%s CREATE %s " TIME_T_FMT,
2694         NumNick(sptr), cbuf, chanTS);
2695 #else
2696     /* send CREATEs to 2.10 servers */
2697     sendto_highprot_butone(cptr, 10, "%s%s CREATE %s " TIME_T_FMT,
2698         NumNick(sptr), cbuf, chanTS);
2699
2700     /* And JOIN + MODE to 2.9 servers; following
2701        is not needed after all are 2.10 */
2702     sendto_lowprot_butone(cptr, 9, ":%s JOIN %s", parv[0], cbuf);
2703     p = NULL;
2704     for (name = strtoken(&p, cbuf, ","); name; name = strtoken(&p, NULL, ","))
2705       sendto_lowprot_butone(cptr, 9, ":%s MODE %s +o %s " TIME_T_FMT,
2706           sptr->user->server->name, name, parv[0], chanTS);
2707 #endif
2708   }
2709
2710   return 0;
2711 }
2712
2713 static size_t prefix_len;
2714
2715 static void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
2716     int *send_itp, char is_a_ban, int mode)
2717 {
2718   int first = *firstp;
2719
2720   /*
2721    * Heh - we do not need to test if it still fits in the buffer, because
2722    * this BURST message is reconstructed from another BURST message, and
2723    * it only can become smaller. --Run
2724    */
2725
2726   if (*firstp)                  /* First token in this parameter ? */
2727   {
2728     *firstp = 0;
2729     if (*send_itp == 0)
2730       *send_itp = 1;            /* Buffer contains data to be sent */
2731     sendbuf[(*sblenp)++] = ' ';
2732     if (is_a_ban)
2733     {
2734       sendbuf[(*sblenp)++] = ':';       /* Bans are always the last "parv" */
2735       sendbuf[(*sblenp)++] = is_a_ban;
2736     }
2737   }
2738   else                          /* Of course, 'send_it' is already set here */
2739     /* Seperate banmasks with a space because
2740        they can contain commas themselfs: */
2741     sendbuf[(*sblenp)++] = is_a_ban ? ' ' : ',';
2742   strcpy(sendbuf + *sblenp, token);
2743   *sblenp += strlen(token);
2744   if (!is_a_ban)                /* nick list ? Need to take care
2745                                    of modes for nicks: */
2746   {
2747     static int last_mode = 0;
2748     mode &= CHFL_CHANOP | CHFL_VOICE;
2749     if (first)
2750       last_mode = 0;
2751     if (last_mode != mode)      /* Append mode like ':ov' if changed */
2752     {
2753       last_mode = mode;
2754       sendbuf[(*sblenp)++] = ':';
2755       if (mode & CHFL_CHANOP)
2756         sendbuf[(*sblenp)++] = 'o';
2757       if (mode & CHFL_VOICE)
2758         sendbuf[(*sblenp)++] = 'v';
2759     }
2760     sendbuf[*sblenp] = '\0';
2761   }
2762 }
2763
2764 static void cancel_mode(aClient *sptr, aChannel *chptr, char m,
2765     const char *param, int *count)
2766 {
2767   static char *pb, *sbp, *sbpi;
2768   int paramdoesntfit = 0;
2769   if (*count == -1)             /* initialize ? */
2770   {
2771     sbp = sbpi =
2772         sprintf_irc(sendbuf, ":%s MODE %s -", sptr->name, chptr->chname);
2773     pb = parabuf;
2774     *count = 0;
2775   }
2776   /* m == 0 means flush */
2777   if (m)
2778   {
2779     if (param)
2780     {
2781       size_t nplen = strlen(param);
2782       if (pb - parabuf + nplen + 23 > MODEBUFLEN)
2783         paramdoesntfit = 1;
2784       else
2785       {
2786         *sbp++ = m;
2787         *pb++ = ' ';
2788         strcpy(pb, param);
2789         pb += nplen;
2790         ++*count;
2791       }
2792     }
2793     else
2794       *sbp++ = m;
2795   }
2796   else if (*count == 0)
2797     return;
2798   if (*count == 6 || !m || paramdoesntfit)
2799   {
2800 #ifndef NO_PROTOCOL9
2801     Dlink *lp;
2802     char *sbe;
2803 #endif
2804     Link *member;
2805     strcpy(sbp, parabuf);
2806 #ifndef NO_PROTOCOL9
2807     sbe = sbp + strlen(parabuf);
2808 #endif
2809     for (member = chptr->members; member; member = member->next)
2810       if (MyUser(member->value.cptr))
2811         sendbufto_one(member->value.cptr);
2812 #ifndef NO_PROTOCOL9
2813     sprintf_irc(sbe, " " TIME_T_FMT, chptr->creationtime);
2814     /* Send 'sendbuf' to all 2.9 downlinks: */
2815     for (lp = me.serv->down; lp; lp = lp->next)
2816       if (Protocol(lp->value.cptr) < 10)
2817         sendbufto_one(lp->value.cptr);
2818 #endif
2819     sbp = sbpi;
2820     pb = parabuf;
2821     *count = 0;
2822   }
2823   if (paramdoesntfit)
2824   {
2825     *sbp++ = m;
2826     *pb++ = ' ';
2827     strcpy(pb, param);
2828     pb += strlen(param);
2829     ++*count;
2830   }
2831 }
2832
2833 /*
2834  * m_burst  --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
2835  *
2836  * parv[0] = sender prefix
2837  * parv[1] = channel name
2838  * parv[2] = channel timestamp
2839  * The meaning of the following parv[]'s depend on their first character:
2840  * If parv[n] starts with a '+':
2841  * Net burst, additive modes
2842  *   parv[n] = <mode>
2843  *   parv[n+1] = <param> (optional)
2844  *   parv[n+2] = <param> (optional)
2845  * If parv[n] starts with a '%', then n will be parc-1:
2846  *   parv[n] = %<ban> <ban> <ban> ...
2847  * If parv[n] starts with another character:
2848  *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
2849  *   where <mode> is the channel mode (ov) of nick and all following nicks.
2850  *
2851  * Example:
2852  * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
2853  *
2854  * Anti net.ride code.
2855  *
2856  * When the channel already exist, and its TS is larger then
2857  * the TS in the BURST message, then we cancel all existing modes.
2858  * If its is smaller then the received BURST message is ignored.
2859  * If it's equal, then the received modes are just added.
2860  */
2861 int m_burst(aClient *cptr, aClient *sptr, int parc, char *parv[])
2862 {
2863   Reg1 aChannel *chptr;
2864   time_t timestamp;
2865   int netride = 0, wipeout = 0, n;
2866   int send_it = 0, add_banid_not_called = 1;
2867   Mode *current_mode;
2868   size_t sblen, mblen = 0;
2869   int mblen2, pblen2, cnt;
2870   int prev_mode;
2871   char prev_key[KEYLEN + 1];
2872   Link *lp;
2873 #ifndef NO_PROTOCOL9
2874   int ts_sent = 0;
2875 #endif
2876
2877   /* BURST is only for servers and has at least 4 parameters */
2878   if (!IsServer(cptr) || parc < 4)
2879     return 0;
2880
2881   if (!IsBurst(sptr))
2882   {
2883     int i;
2884     char *p;
2885     if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
2886     {
2887       p =
2888           sprintf_irc(sendbuf,
2889           ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
2890           sptr->name, parv[1], parv[2]);
2891       for (i = 3; i < parc - 1; ++i)
2892         p = sprintf_irc(p, " %s", parv[i]);
2893       sprintf_irc(p, " :%s", parv[parc - 1]);
2894       sendbufto_op_mask(SNO_HACK4);
2895     }
2896     else
2897     {
2898 #if 1                           /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
2899       SetBurst(sptr);
2900       if (MyConnect(sptr))
2901 #endif
2902         return exit_client_msg(cptr, cptr, &me,
2903             "HACK: BURST message outside net.burst from %s", sptr->name);
2904     }
2905   }
2906
2907   /* Find the channel, or create it - note that the creation time
2908    * will be 0 if it has to be created */
2909   chptr = get_channel(sptr, parv[1], CREATE);
2910   current_mode = &chptr->mode;
2911   prev_mode = chptr->mode.mode;
2912   if (*chptr->mode.key)
2913   {
2914     prev_mode |= MODE_KEY;
2915     strcpy(prev_key, chptr->mode.key);
2916   }
2917   if (chptr->mode.limit)
2918     prev_mode |= MODE_LIMIT;
2919
2920   timestamp = atoi(parv[2]);
2921
2922   /* Copy the new TS when the received creationtime appears to be older */
2923   if (!chptr->creationtime || chptr->creationtime > timestamp)
2924   {
2925     /* Set the new timestamp */
2926     chptr->creationtime = timestamp;
2927     send_it = 1;                /* Make sure we pass on the different timestamp ! */
2928     /* Mark all bans as needed to be wiped out */
2929     for (lp = chptr->banlist; lp; lp = lp->next)
2930       lp->flags |= CHFL_BURST_BAN_WIPEOUT;
2931     /*
2932      * Only the first BURST for this channel can have creationtime > timestamp,
2933      * so at this moment ALL members are on OUR side, and thus all net.riders:
2934      */
2935     wipeout = 1;
2936   }
2937   for (lp = chptr->members; lp; lp = lp->next)
2938     lp->flags &= ~CHFL_BURST_JOINED;    /* Set later for nicks in the BURST msg */
2939   /* If `wipeout' is set then these will be deopped later. */
2940
2941   /* If the entering creationtime is younger, ignore the modes */
2942   if (chptr->creationtime < timestamp)
2943     netride = 1;                /* Only pass on the nicks (so they JOIN) */
2944
2945   /* Prepare buffers to pass the message */
2946   *bparambuf = *bmodebuf = *parabuf = '\0';
2947   pblen2 = 0;
2948   *modebuf = '+';
2949   mblen2 = 1;
2950   cnt = 0;
2951   prefix_len = sblen = sprintf_irc(sendbuf, "%s BURST %s " TIME_T_FMT,
2952       NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
2953
2954   /* Run over all remaining parameters */
2955   for (n = 3; n < parc; n++)
2956     switch (*parv[n])           /* What type is it ? mode, nicks or bans ? */
2957     {
2958       case '+':         /* modes */
2959       {
2960         char *p = parv[n];
2961         while (*(++p))          /* Run over all mode characters */
2962         {
2963           switch (*p)           /* which mode ? */
2964           {
2965               /*
2966                * The following cases all do the following:
2967                * - In case wipeout needed, reset 'prev_mode' to indicate this
2968                *   mode should not be cancelled.
2969                * - If wipeout or (not netride and the new mode is a change),
2970                *   add it to bmodebuf and bparabuf for propagation.
2971                * - Else ignore it.
2972                * - Add it to modebuf and parabuf for propagation to the
2973                *   clients when not netride and the new mode is a change.
2974                * Special cases:
2975                * - If a +s is received, cancel a +p and sent a -p to the
2976                *   clients too (if +p was set).
2977                * - If a +p is received and +s is set, ignore the +p.
2978                */
2979             case 'i':
2980             {
2981               register int tmp;
2982               prev_mode &= ~MODE_INVITEONLY;
2983               if (!(tmp = netride ||
2984                   (current_mode->mode & MODE_INVITEONLY)) || wipeout)
2985               {
2986                 bmodebuf[mblen++] = 'i';
2987                 current_mode->mode |= MODE_INVITEONLY;
2988               }
2989               if (!tmp)
2990                 modebuf[mblen2++] = 'i';
2991               break;
2992             }
2993             case 'k':
2994             {
2995               register int tmp;
2996               char *param = parv[++n];
2997               prev_mode &= ~MODE_KEY;
2998               if (!(tmp = netride || (*current_mode->key &&
2999                   (!strcmp(current_mode->key, param) ||
3000                   (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
3001                   wipeout)
3002               {
3003                 bmodebuf[mblen++] = 'k';
3004                 strcat(bparambuf, " ");
3005                 strcat(bparambuf, param);
3006                 strncpy(current_mode->key, param, KEYLEN);
3007               }
3008               if (!tmp && !wipeout)
3009               {
3010                 modebuf[mblen2++] = 'k';
3011                 parabuf[pblen2++] = ' ';
3012                 strcpy(parabuf + pblen2, param);
3013                 pblen2 += strlen(param);
3014                 cnt++;
3015               }
3016               break;
3017             }
3018             case 'l':
3019             {
3020               register int tmp;
3021               unsigned int param = atoi(parv[++n]);
3022               prev_mode &= ~MODE_LIMIT;
3023               if (!(tmp = netride || (current_mode->limit &&
3024                   (current_mode->limit == param ||
3025                   (!wipeout && current_mode->limit < param)))) || wipeout)
3026               {
3027                 bmodebuf[mblen++] = 'l';
3028                 sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
3029                 current_mode->limit = param;
3030               }
3031               if (!tmp)
3032               {
3033                 modebuf[mblen2++] = 'l';
3034                 pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
3035                 cnt++;
3036               }
3037               break;
3038             }
3039             case 'm':
3040             {
3041               register int tmp;
3042               prev_mode &= ~MODE_MODERATED;
3043               if (!(tmp = netride ||
3044                   (current_mode->mode & MODE_MODERATED)) || wipeout)
3045               {
3046                 bmodebuf[mblen++] = 'm';
3047                 current_mode->mode |= MODE_MODERATED;
3048               }
3049               if (!tmp)
3050                 modebuf[mblen2++] = 'm';
3051               break;
3052             }
3053             case 'n':
3054             {
3055               register int tmp;
3056               prev_mode &= ~MODE_NOPRIVMSGS;
3057               if (!(tmp = netride ||
3058                   (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
3059               {
3060                 bmodebuf[mblen++] = 'n';
3061                 current_mode->mode |= MODE_NOPRIVMSGS;
3062               }
3063               if (!tmp)
3064                 modebuf[mblen2++] = 'n';
3065               break;
3066             }
3067             case 'p':
3068             {
3069               register int tmp;
3070
3071               /* Special case: */
3072               if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
3073                 break;
3074
3075               prev_mode &= ~MODE_PRIVATE;
3076               if (!(tmp = netride ||
3077                   (current_mode->mode & MODE_PRIVATE)) || wipeout)
3078               {
3079                 bmodebuf[mblen++] = 'p';
3080                 current_mode->mode |= MODE_PRIVATE;
3081               }
3082               if (!tmp)
3083                 modebuf[mblen2++] = 'p';
3084               break;
3085             }
3086             case 's':
3087             {
3088               register int tmp;
3089               prev_mode &= ~MODE_SECRET;
3090               if (!(tmp = netride ||
3091                   (current_mode->mode & MODE_SECRET)) || wipeout)
3092               {
3093                 bmodebuf[mblen++] = 's';
3094                 current_mode->mode |= MODE_SECRET;
3095               }
3096               if (!tmp)
3097                 modebuf[mblen2++] = 's';
3098
3099               /* Special case: */
3100               if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
3101               {
3102                 int i;
3103                 for (i = mblen2 - 1; i >= 0; --i)
3104                   modebuf[i + 2] = modebuf[i];
3105                 modebuf[0] = '-';
3106                 modebuf[1] = 'p';
3107                 mblen2 += 2;
3108                 current_mode->mode &= ~MODE_PRIVATE;
3109               }
3110
3111               break;
3112             }
3113             case 't':
3114             {
3115               register int tmp;
3116               prev_mode &= ~MODE_TOPICLIMIT;
3117               if (!(tmp = netride ||
3118                   (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
3119               {
3120                 bmodebuf[mblen++] = 't';
3121                 current_mode->mode |= MODE_TOPICLIMIT;
3122               }
3123               if (!tmp)
3124                 modebuf[mblen2++] = 't';
3125               break;
3126             }
3127           }
3128         }                       /* <-- while over all modes */
3129
3130         bmodebuf[mblen] = '\0';
3131         sendbuf[sblen] = '\0';
3132         if (mblen)              /* Anything to send at all ? */
3133         {
3134           send_it = 1;
3135           strcpy(sendbuf + sblen, " +");
3136           sblen += 2;
3137           strcpy(sendbuf + sblen, bmodebuf);
3138           sblen += mblen;
3139           strcpy(sendbuf + sblen, bparambuf);
3140           sblen += strlen(bparambuf);
3141         }
3142         break;                  /* Done mode part */
3143       }
3144       case '%':         /* bans */
3145       {
3146         char *pv, *p = NULL, *ban;
3147         int first = 1;
3148         if (netride)
3149           break;                /* Ignore bans */
3150         /* Run over all bans */
3151         for (pv = parv[n] + 1; (ban = strtoken(&p, pv, " ")); pv = NULL)
3152         {
3153           int ret;
3154           /*
3155            * The following part should do the following:
3156            * - If the new (un)ban is not a _change_ it is ignored.
3157            * - Else, add it to sendbuf for later use.
3158            * - If sendbuf is full, send it, and prepare a new
3159            *   message in sendbuf.
3160            */
3161           ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
3162           if (ret == 0)
3163           {
3164             add_banid_not_called = 0;
3165             /* Mark this new ban so we can send it to the clients later */
3166             chptr->banlist->flags |= CHFL_BURST_BAN;
3167           }
3168           if (ret != -1)
3169             /* A new ban was added or an existing one needs to be passed on.
3170              * Also add it to sendbuf: */
3171             add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
3172         }
3173         break;                  /* Done bans part */
3174       }
3175       default:                  /* nicks */
3176       {
3177         char *pv, *p = NULL, *nick, *ptr;
3178         int first = 1;
3179         /* Default mode: */
3180         int default_mode = CHFL_DEOPPED;
3181         /* Run over all nicks */
3182         for (pv = parv[n]; (nick = strtoken(&p, pv, ",")); pv = NULL)
3183         {
3184           aClient *acptr;
3185           if ((ptr = strchr(nick, ':')))        /* New default mode ? */
3186           {
3187             *ptr = '\0';        /* Fix 'nick' */
3188             acptr = findNUser(nick);
3189             if (!netride)
3190             {
3191               /* Calculate new mode change: */
3192               default_mode = CHFL_DEOPPED;
3193               while (*(++ptr))
3194                 if (*ptr == 'o')
3195                 {
3196                   default_mode |= CHFL_CHANOP;
3197                   default_mode &= ~CHFL_DEOPPED;
3198                 }
3199                 else if (*ptr == 'v')
3200                   default_mode |= CHFL_VOICE;
3201                 else
3202                   break;
3203             }
3204           }
3205           else
3206             acptr = findNUser(nick);
3207           /*
3208            * Note that at this point we already received a 'NICK' for any
3209            * <nick> numeric that is joining (and possibly opped) here.
3210            * Therefore we consider the following situations:
3211            * - The <nick> numeric exists and is from the direction of cptr: ok
3212            * - The <nick> numeric does not exist:
3213            *   Apparently this previous <nick> numeric was killed (upstream)
3214            *   or it collided with an existing <nick> name.
3215            * - The <nick> numeric exists but is from another direction:
3216            *   Apparently this previous <nick> numeric was killed,
3217            *   and due to a reroute it signed on via another link (probably
3218            *   a nick [numeric] collision).
3219            * Note that it can't be a QUIT or SQUIT, because a QUIT would
3220            * come from the same direction as the BURST (cptr) while an
3221            * upstream SQUIT removes the source (server) and we would thus
3222            * have this BURST ignored already.
3223            * This means that if we find the nick and it is from the correct
3224            * direction, it joins. If it doesn't exist or is from another
3225            * direction, we have to ignore it. If all nicks are ignored, we
3226            * remove the channel again when it is empty and don't propagate
3227            * the BURST message.
3228            */
3229           if (acptr && acptr->from == cptr)
3230           {
3231             /*
3232              * The following should do the following:
3233              * - Add it to sendbuf for later use.
3234              * - If sendbuf is full, send it, and prepare a new
3235              *   message in sendbuf.
3236              */
3237             add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
3238                 default_mode);
3239             /* Let is take effect: (Note that in the case of a netride
3240              * 'default_mode' is always CHFL_DEOPPED here). */
3241             add_user_to_channel(chptr, acptr, default_mode);
3242             chptr->members->flags |= CHFL_BURST_JOINED;
3243           }
3244         }                       /* <-- Next nick */
3245         if (!chptr->members)    /* All nicks collided and channel is empty ? */
3246         {
3247           sub1_from_channel(chptr);
3248           return 0;             /* Forget about the (rest of the) message... */
3249         }
3250         break;                  /* Done nicks part */
3251       }
3252     }                           /* <-- Next parameter if any */
3253   if (!chptr->members)          /* This message only contained bans (then the previous
3254                                    message only contained collided nicks, see above) */
3255   {
3256     sub1_from_channel(chptr);
3257     if (!add_banid_not_called)
3258       while (next_removed_overlapped_ban());
3259     return 0;                   /* Forget about the (rest of the) message... */
3260   }
3261
3262   /* The last (possibly only) message is always send here */
3263   if (send_it)                  /* Anything (left) to send ? */
3264   {
3265     Dlink *lp;
3266     Link *member;
3267
3268     /* send 'sendbuf' to all downlinks */
3269     for (lp = me.serv->down; lp; lp = lp->next)
3270     {
3271       if (lp->value.cptr == cptr)
3272         continue;
3273       if (Protocol(lp->value.cptr) > 9)
3274         sendbufto_one(lp->value.cptr);
3275     }
3276
3277     /*
3278      * Now we finally can screw sendbuf again...
3279      * Send all changes to the local clients:
3280      *
3281      * First send all joins and op them, because 2.9 servers
3282      * would protest with a HACK if we first de-opped people.
3283      * However, we don't send the +b bans yes, because we
3284      * DO first want to -b the old bans (otherwise it's confusing).
3285      */
3286
3287     /* Send all joins: */
3288     for (member = chptr->members; member; member = member->next)
3289       if (member->flags & CHFL_BURST_JOINED)
3290       {
3291         sendto_channel_butserv(chptr, member->value.cptr, ":%s JOIN :%s",
3292             member->value.cptr->name, chptr->chname);
3293 #ifndef NO_PROTOCOL9
3294         /* And to 2.9 servers: */
3295         sendto_lowprot_butone(cptr, 9, ":%s JOIN %s",
3296             member->value.cptr->name, chptr->chname);
3297 #endif
3298       }
3299
3300     if (!netride)
3301     {
3302       /* Send all +o and +v modes: */
3303       for (member = chptr->members; member; member = member->next)
3304       {
3305         if ((member->flags & CHFL_BURST_JOINED))
3306         {
3307           int mode = CHFL_CHANOP;
3308           for (;;)
3309           {
3310             if ((member->flags & mode))
3311             {
3312               modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
3313               parabuf[pblen2++] = ' ';
3314               strcpy(parabuf + pblen2, member->value.cptr->name);
3315               pblen2 += strlen(member->value.cptr->name);
3316               if (6 == ++cnt)
3317               {
3318                 modebuf[mblen2] = 0;
3319                 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3320                     parv[0], chptr->chname, modebuf, parabuf);
3321 #ifndef NO_PROTOCOL9
3322                 sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
3323                     parv[0], chptr->chname, modebuf, parabuf,
3324                     chptr->creationtime);
3325                 ts_sent = 1;
3326 #endif
3327                 *parabuf = 0;
3328                 pblen2 = 0;
3329                 mblen2 = 1;
3330                 cnt = 0;
3331               }
3332             }
3333             if (mode == CHFL_CHANOP)
3334               mode = CHFL_VOICE;
3335             else
3336               break;
3337           }
3338         }
3339       }
3340       /* Flush MODEs: */
3341       if (cnt > 0 || mblen2 > 1)
3342       {
3343         modebuf[mblen2] = 0;
3344         sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3345             parv[0], chptr->chname, modebuf, parabuf);
3346 #ifndef NO_PROTOCOL9
3347         sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
3348             parv[0], chptr->chname, modebuf, parabuf, chptr->creationtime);
3349         ts_sent = 1;
3350 #endif
3351       }
3352 #ifndef NO_PROTOCOL9
3353       else if (send_it && !ts_sent)
3354       {
3355         sendto_lowprot_butone(cptr, 9, ":%s MODE %s + " TIME_T_FMT,
3356             parv[0], chptr->chname, chptr->creationtime);
3357         ts_sent = 1;
3358       }
3359 #endif
3360     }
3361   }
3362
3363   if (wipeout)
3364   {
3365     Link *lp;
3366     Link **ban;
3367     int mode;
3368     char m;
3369     int count = -1;
3370
3371     /* Now cancel all previous simple modes */
3372     if ((prev_mode & MODE_SECRET))
3373       cancel_mode(sptr, chptr, 's', NULL, &count);
3374     if ((prev_mode & MODE_PRIVATE))
3375       cancel_mode(sptr, chptr, 'p', NULL, &count);
3376     if ((prev_mode & MODE_MODERATED))
3377       cancel_mode(sptr, chptr, 'm', NULL, &count);
3378     if ((prev_mode & MODE_TOPICLIMIT))
3379       cancel_mode(sptr, chptr, 't', NULL, &count);
3380     if ((prev_mode & MODE_INVITEONLY))
3381       cancel_mode(sptr, chptr, 'i', NULL, &count);
3382     if ((prev_mode & MODE_NOPRIVMSGS))
3383       cancel_mode(sptr, chptr, 'n', NULL, &count);
3384     if ((prev_mode & MODE_LIMIT))
3385     {
3386       current_mode->limit = 0;
3387       cancel_mode(sptr, chptr, 'l', NULL, &count);
3388     }
3389     if ((prev_mode & MODE_KEY))
3390     {
3391       *current_mode->key = 0;
3392       cancel_mode(sptr, chptr, 'k', prev_key, &count);
3393     }
3394     current_mode->mode &= ~prev_mode;
3395
3396     /* And deop and devoice all net.riders on my side */
3397     mode = CHFL_CHANOP;
3398     m = 'o';
3399     for (;;)
3400     {
3401       for (lp = chptr->members; lp; lp = lp->next)
3402       {
3403         if ((lp->flags & CHFL_BURST_JOINED))
3404           continue;             /* This is not a net.rider from
3405                                    this side of the net.junction */
3406         if ((lp->flags & mode))
3407         {
3408           lp->flags &= ~mode;
3409           if (mode == CHFL_CHANOP)
3410             lp->flags |= CHFL_DEOPPED;
3411           cancel_mode(sptr, chptr, m, lp->value.cptr->name, &count);
3412         }
3413       }
3414       if (mode == CHFL_VOICE)
3415         break;
3416       mode = CHFL_VOICE;
3417       m = 'v';
3418     }
3419
3420     /* And finally wipeout all bans that are left */
3421     for (ban = &chptr->banlist; *ban;)
3422     {
3423       Link *tmp = *ban;
3424       if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT))
3425       {
3426         cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
3427         /* Copied from del_banid(): */
3428         *ban = tmp->next;
3429         RunFree(tmp->value.ban.banstr);
3430         RunFree(tmp->value.ban.who);
3431         free_link(tmp);
3432         /* Erase ban-valid-bit, for channel members that are banned */
3433         for (tmp = chptr->members; tmp; tmp = tmp->next)
3434           if ((tmp->flags & (CHFL_BANNED | CHFL_BANVALID)) ==
3435               (CHFL_BANNED | CHFL_BANVALID))
3436             tmp->flags &= ~CHFL_BANVALID;       /* `tmp' == channel member */
3437       }
3438       else
3439         ban = &tmp->next;
3440     }
3441     /* Also wipeout overlapped bans */
3442     if (!add_banid_not_called)
3443     {
3444       Link *ban;
3445       while ((ban = next_removed_overlapped_ban()))
3446         cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
3447     }
3448     cancel_mode(sptr, chptr, 0, NULL, &count);  /* flush */
3449   }
3450
3451   if (send_it && !netride)
3452   {
3453     Link *bl;
3454     int deban;
3455
3456     if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
3457     {
3458       deban = 0;
3459       bl = chptr->banlist;
3460       *modebuf = '+';
3461     }
3462     else
3463     {
3464       deban = 1;
3465       *modebuf = '-';
3466     }
3467
3468     mblen2 = 1;
3469     pblen2 = 0;
3470     cnt = 0;
3471     for (;;)
3472     {
3473       size_t nblen = 0;
3474       if (bl)
3475         nblen = strlen(bl->value.ban.banstr);
3476       if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN) /* The last check is to make sure
3477                                                                            that the receiving 2.9 will
3478                                                                            still process this */
3479       {
3480         /* Time to send buffer */
3481         modebuf[mblen2] = 0;
3482         sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3483             parv[0], chptr->chname, modebuf, parabuf);
3484 #ifndef NO_PROTOCOL9
3485         sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s",
3486             parv[0], chptr->chname, modebuf, parabuf);
3487 #endif
3488         *modebuf = deban ? '-' : '+';
3489         mblen2 = 1;
3490         pblen2 = 0;
3491         cnt = 0;
3492       }
3493       if (!bl)                  /* Done ? */
3494         break;
3495       if (deban || (bl->flags & CHFL_BURST_BAN))
3496       {
3497         /* Add ban to buffers and remove it */
3498         modebuf[mblen2++] = 'b';
3499         parabuf[pblen2++] = ' ';
3500         strcpy(parabuf + pblen2, bl->value.ban.banstr);
3501         pblen2 += nblen;
3502         cnt++;
3503         bl->flags &= ~CHFL_BURST_BAN;
3504       }
3505       if (deban)
3506       {
3507         if (!(bl = next_removed_overlapped_ban()))
3508         {
3509           deban = 0;
3510           modebuf[mblen2++] = '+';
3511           bl = chptr->banlist;
3512         }
3513       }
3514       else
3515         bl = bl->next;
3516     }
3517     /* Flush MODE [-b]+b ...: */
3518     if (cnt > 0 || mblen2 > 1)
3519     {
3520       modebuf[mblen2] = 0;
3521       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
3522           parv[0], chptr->chname, modebuf, parabuf);
3523 #ifndef NO_PROTOCOL9
3524       sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
3525           parv[0], chptr->chname, modebuf, parabuf, chptr->creationtime);
3526 #endif
3527     }
3528 #ifndef NO_PROTOCOL9
3529     else if (send_it && !ts_sent)
3530       sendto_lowprot_butone(cptr, 9, ":%s MODE %s + " TIME_T_FMT,
3531           parv[0], chptr->chname, chptr->creationtime);
3532 #endif
3533   }
3534
3535   return 0;
3536 }
3537
3538 /*
3539  * m_part
3540  *
3541  * parv[0] = sender prefix
3542  * parv[1] = channel
3543  * parv[parc - 1] = comment
3544  */
3545 int m_part(aClient *cptr, aClient *sptr, int parc, char *parv[])
3546 {
3547   Reg1 aChannel *chptr;
3548   Reg2 Link *lp;
3549   char *p = NULL, *name, pbuf[BUFSIZE];
3550   char *comment = (parc > 2 && !BadPtr(parv[parc - 1])) ? parv[parc - 1] : NULL;
3551
3552   *pbuf = '\0';                 /* Initialize the part buffer... -Kev */
3553
3554   sptr->flags &= ~FLAGS_TS8;
3555
3556   if (parc < 2 || parv[1][0] == '\0')
3557   {
3558     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PART");
3559     return 0;
3560   }
3561
3562   for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3563   {
3564     chptr = get_channel(sptr, name, !CREATE);
3565     if (!chptr)
3566     {
3567       sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
3568       continue;
3569     }
3570     if (*name == '&' && !MyUser(sptr))
3571       continue;
3572     /* Do not use IsMember here: zombies must be able to part too */
3573     if (!(lp = find_user_link(chptr->members, sptr)))
3574     {
3575       /* Normal to get when our client did a kick
3576          for a remote client (who sends back a PART),
3577          so check for remote client or not --Run */
3578       if (MyUser(sptr))
3579         sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
3580             chptr->chname);
3581       continue;
3582     }
3583     /* Recreate the /part list for sending to servers */
3584     if (*name != '&')
3585     {
3586       if (*pbuf)
3587         strcat(pbuf, ",");
3588       strcat(pbuf, name);
3589     }
3590     if (can_send(sptr, chptr) != 0)     /* Returns 0 if we CAN send */
3591       comment = NULL;
3592     /* Send part to all clients */
3593     if (!(lp->flags & CHFL_ZOMBIE))
3594     {
3595       if (comment)
3596         sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
3597             comment);
3598       else
3599         sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
3600     }
3601     else if (MyUser(sptr))
3602     {
3603       if (comment)
3604         sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
3605       else
3606         sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
3607     }
3608     remove_user_from_channel(sptr, chptr);
3609   }
3610   /* Send out the parts to all servers... -Kev */
3611   if (*pbuf)
3612   {
3613     if (comment)
3614       sendto_serv_butone(cptr, PartFmt2, parv[0], pbuf, comment);
3615     else
3616       sendto_serv_butone(cptr, PartFmt1, parv[0], pbuf);
3617   }
3618   return 0;
3619 }
3620
3621 /*
3622  * m_kick
3623  *
3624  * parv[0] = sender prefix
3625  * parv[1] = channel
3626  * parv[2] = client to kick
3627  * parv[parc-1] = kick comment
3628  */
3629 int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[])
3630 {
3631   aClient *who;
3632   aChannel *chptr;
3633   char *comment;
3634   Link *lp, *lp2;
3635
3636   sptr->flags &= ~FLAGS_TS8;
3637
3638   if (parc < 3 || *parv[1] == '\0')
3639   {
3640     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KICK");
3641     return 0;
3642   }
3643
3644   if (IsServer(sptr))
3645     send_hack_notice(cptr, sptr, parc, parv, 1, 3);
3646
3647   comment = (BadPtr(parv[parc - 1])) ? parv[0] : parv[parc - 1];
3648   if (strlen(comment) > (size_t)TOPICLEN)
3649     comment[TOPICLEN] = '\0';
3650
3651   *nickbuf = *buf = '\0';
3652
3653   chptr = get_channel(sptr, parv[1], !CREATE);
3654   if (!chptr)
3655   {
3656     sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]);
3657     return 0;
3658   }
3659   if (IsLocalChannel(parv[1]) && !MyUser(sptr))
3660     return 0;
3661   if (IsModelessChannel(parv[1]))
3662   {
3663     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
3664         chptr->chname);
3665     return 0;
3666   }
3667   if (!IsServer(cptr) && !is_chan_op(sptr, chptr))
3668   {
3669     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
3670         me.name, parv[0], chptr->chname);
3671     return 0;
3672   }
3673
3674   lp2 = find_user_link(chptr->members, sptr);
3675   if (MyUser(sptr) || Protocol(cptr) < 10)
3676   {
3677     if (!(who = find_chasing(sptr, parv[2], NULL)))
3678       return 0;                 /* No such user left! */
3679   }
3680   else if (!(who = findNUser(parv[2])))
3681     return 0;                   /* No such user left! */
3682   /* if the user is +k, prevent a kick from local user */
3683   if (IsChannelService(who) && MyUser(sptr))
3684   {
3685     sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
3686         parv[0], who->name, chptr->chname);
3687     return 0;
3688   }
3689 #ifdef NO_OPER_DEOP_LCHAN
3690   /*
3691    * Prevent kicking opers from local channels -DM-
3692    */
3693   if (IsOperOnLocalChannel(who, chptr->chname))
3694   {
3695     sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
3696                parv[0], who->name, chptr->chname);
3697     return 0;
3698   }
3699 #endif
3700
3701   if (((lp = find_user_link(chptr->members, who)) &&
3702       !(lp->flags & CHFL_ZOMBIE)) || IsServer(sptr))
3703   {
3704     if (who->from != cptr &&
3705         ((lp2 && (lp2->flags & CHFL_DEOPPED)) || (!lp2 && IsUser(sptr))))
3706     {
3707       /*
3708        * Bounce here:
3709        * cptr must be a server (or cptr == sptr and
3710        * sptr->flags can't have DEOPPED set
3711        * when CHANOP is set).
3712        */
3713       sendto_one(cptr, ":%s JOIN %s", who->name, parv[1]);
3714       if (lp->flags & CHFL_CHANOP)
3715       {
3716         if (Protocol(cptr) < 10)
3717           sendto_one(cptr, ":%s MODE %s +o %s " TIME_T_FMT,
3718               me.name, parv[1], who->name, chptr->creationtime);
3719         else
3720           sendto_one(cptr, "%s MODE %s +o %s%s " TIME_T_FMT,
3721               NumServ(&me), parv[1], NumNick(who), chptr->creationtime);
3722       }
3723       if (lp->flags & CHFL_VOICE)
3724       {
3725         if (Protocol(cptr) < 10)
3726           sendto_one(cptr, ":%s MODE %s +v %s " TIME_T_FMT,
3727               me.name, chptr->chname, who->name, chptr->creationtime);
3728         else
3729           sendto_one(cptr, "%s MODE %s +v %s%s " TIME_T_FMT,
3730               NumServ(&me), parv[1], NumNick(who), chptr->creationtime);
3731       }
3732     }
3733     else
3734     {
3735       if (lp)
3736         sendto_channel_butserv(chptr, sptr,
3737             ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
3738       if (!IsLocalChannel(parv[1]))
3739       {
3740         sendto_lowprot_butone(cptr, 9, ":%s KICK %s %s :%s",
3741             parv[0], chptr->chname, who->name, comment);
3742         sendto_highprot_butone(cptr, 10, ":%s KICK %s %s%s :%s",
3743             parv[0], parv[1], NumNick(who), comment);
3744       }
3745       if (lp)
3746       {
3747 /*
3748  * Consider:
3749  *
3750  *                     client
3751  *                       |
3752  *                       c
3753  *                       |
3754  *     X --a--> A --b--> B --d--> D
3755  *                       |
3756  *                      who
3757  *
3758  * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
3759  * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
3760  *
3761  * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
3762  *    Remove the user immedeately when no users are left on the channel.
3763  * b) On server B : remove the user (who/lp) from the channel, send a
3764  *    PART upstream (to A) and pass on the KICK.
3765  * c) KICKed by `client'; On server B : remove the user (who/lp) from the
3766  *    channel, and pass on the KICK.
3767  * d) On server D : remove the user (who/lp) from the channel, and pass on
3768  *    the KICK.
3769  *
3770  * Note:
3771  * - Setting the ZOMBIE flag never hurts, we either remove the
3772  *   client after that or we don't.
3773  * - The KICK message was already passed on, as should be in all cases.
3774  * - `who' is removed in all cases except case a) when users are left.
3775  * - A PART is only sent upstream in case b).
3776  *
3777  * 2 aug 97:
3778  *
3779  *              6
3780  *              |
3781  *  1 --- 2 --- 3 --- 4 --- 5
3782  *        |           |
3783  *      kicker       who
3784  *
3785  * We also need to turn 'who' into a zombie on servers 1 and 6,
3786  * because a KICK from 'who' (kicking someone else in that direction)
3787  * can arrive there afterwards - which should not be bounced itself.
3788  * Therefore case a) also applies for servers 1 and 6.
3789  *
3790  * --Run
3791  */
3792         /* Default for case a): */
3793         lp->flags |= CHFL_ZOMBIE;
3794         /* Case b) or c) ?: */
3795         if (MyUser(who))        /* server 4 */
3796         {
3797           if (IsServer(cptr))   /* Case b) ? */
3798             sendto_one(cptr, PartFmt1, who->name, parv[1]);
3799           remove_user_from_channel(who, chptr);
3800           return 0;
3801         }
3802         if (who->from == cptr)  /* True on servers 1, 5 and 6 */
3803         {
3804           aClient *acptr = IsServer(sptr) ? sptr : sptr->user->server;
3805           for (; acptr != &me; acptr = acptr->serv->up)
3806             if (acptr == who->user->server)     /* Case d) (server 5) */
3807             {
3808               remove_user_from_channel(who, chptr);
3809               return 0;
3810             }
3811         }
3812         /* Case a) (servers 1, 2, 3 and 6) */
3813         for (lp = chptr->members; lp; lp = lp->next)
3814           if (!(lp->flags & CHFL_ZOMBIE))
3815             break;
3816         if (!lp)
3817           remove_user_from_channel(who, chptr);
3818 #ifdef GODMODE
3819         else
3820           sendto_op_mask(SNO_HACK2, "%s is now a zombie on %s",
3821               who->name, chptr->chname);
3822 #endif
3823       }
3824     }
3825   }
3826   else if (MyUser(sptr))
3827     sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
3828         me.name, parv[0], who->name, chptr->chname);
3829
3830   return 0;
3831 }
3832
3833 /*
3834  * m_topic
3835  *
3836  * parv[0]        = sender prefix
3837  * parv[1]        = channel
3838  * parv[parc - 1] = topic (if parc > 2)
3839  */
3840 int m_topic(aClient *cptr, aClient *sptr, int parc, char *parv[])
3841 {
3842   aChannel *chptr;
3843   char *topic = NULL, *name, *p = NULL;
3844
3845   if (parc < 2)
3846   {
3847     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "TOPIC");
3848     return 0;
3849   }
3850
3851   if (parc > 2)
3852     topic = parv[parc - 1];
3853
3854   for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3855   {
3856     chptr = NULL;
3857     if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
3858         ((topic || SecretChannel(chptr)) && !IsMember(sptr, chptr)))
3859     {
3860       sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
3861           me.name, parv[0], chptr ? chptr->chname : name);
3862       continue;
3863     }
3864     if (IsModelessChannel(name))
3865     {
3866       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
3867           chptr->chname);
3868       continue;
3869     }
3870     if (IsLocalChannel(name) && !MyUser(sptr))
3871       continue;
3872
3873     if (!topic)                 /* only asking  for topic  */
3874     {
3875       if (chptr->topic[0] == '\0')
3876         sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname);
3877       else
3878       {
3879         sendto_one(sptr, rpl_str(RPL_TOPIC),
3880             me.name, parv[0], chptr->chname, chptr->topic);
3881         sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
3882             me.name, parv[0], chptr->chname,
3883             chptr->topic_nick, chptr->topic_time);
3884       }
3885     }
3886     else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
3887         is_chan_op(sptr, chptr)) && topic)
3888     {
3889       /* setting a topic */
3890       strncpy(chptr->topic, topic, TOPICLEN);
3891       strncpy(chptr->topic_nick, sptr->name, NICKLEN);
3892       chptr->topic_time = now;
3893       sendto_serv_butone(cptr, ":%s TOPIC %s :%s",
3894           parv[0], chptr->chname, chptr->topic);
3895       sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
3896           parv[0], chptr->chname, chptr->topic);
3897     }
3898     else
3899       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
3900           me.name, parv[0], chptr->chname);
3901   }
3902   return 0;
3903 }
3904
3905 /*
3906  * m_invite
3907  *   parv[0] - sender prefix
3908  *   parv[1] - user to invite
3909  *   parv[2] - channel name
3910  *
3911  * - INVITE now is accepted only if who does it is chanop (this of course
3912  *   implies that channel must exist and he must be on it).
3913  *
3914  * - On the other side it IS processed even if channel is NOT invite only
3915  *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
3916  *
3917  */
3918 int m_invite(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
3919 {
3920   aClient *acptr;
3921   aChannel *chptr;
3922
3923   if (parc < 3 || *parv[2] == '\0')
3924   {
3925     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "INVITE");
3926     return 0;
3927   }
3928
3929   if (!(acptr = FindUser(parv[1])))
3930   {
3931     sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
3932     return 0;
3933   }
3934
3935   if (is_silenced(sptr, acptr))
3936     return 0;
3937
3938   if (MyUser(sptr))
3939     clean_channelname(parv[2]);
3940   else if (IsLocalChannel(parv[2]))
3941     return 0;
3942
3943   if (*parv[2] == '0' || !IsChannelName(parv[2]))
3944     return 0;
3945
3946   if (!(chptr = FindChannel(parv[2])))
3947   {
3948     if (IsModelessChannel(parv[2]) || IsLocalChannel(parv[2]))
3949     {
3950       sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[2]);
3951       return 0;
3952     }
3953
3954     /* Do not disallow to invite to non-existant #channels, otherwise they
3955        would simply first be created, causing only MORE bandwidth usage. */
3956     if (MyConnect(sptr))
3957     {
3958       if (check_target_limit(sptr, acptr, acptr->name, 0))
3959         return 0;
3960
3961       sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
3962           acptr->name, parv[2]);
3963
3964       if (acptr->user->away)
3965         sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
3966             acptr->name, acptr->user->away);
3967     }
3968
3969     sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
3970         acptr->name, parv[2]);
3971
3972     return 0;
3973   }
3974
3975   if (!IsMember(sptr, chptr))
3976   {
3977     sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
3978         chptr->chname);
3979     return 0;
3980   }
3981
3982   if (IsMember(acptr, chptr))
3983   {
3984     sendto_one(sptr, err_str(ERR_USERONCHANNEL),
3985         me.name, parv[0], acptr->name, chptr->chname);
3986     return 0;
3987   }
3988
3989   if (MyConnect(sptr))
3990   {
3991     if (!is_chan_op(sptr, chptr))
3992     {
3993       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
3994           me.name, parv[0], chptr->chname);
3995       return 0;
3996     }
3997
3998     /* If we get here, it was a VALID and meaningful INVITE */
3999
4000     if (check_target_limit(sptr, acptr, acptr->name, 0))
4001       return 0;
4002
4003     sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
4004         acptr->name, chptr->chname);
4005
4006     if (acptr->user->away)
4007       sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
4008           acptr->name, acptr->user->away);
4009   }
4010
4011   if (MyConnect(acptr))
4012     add_invite(acptr, chptr);
4013
4014   sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
4015       acptr->name, chptr->chname);
4016
4017   return 0;
4018 }
4019
4020 static int number_of_zombies(aChannel *chptr)
4021 {
4022   Reg1 Link *lp;
4023   Reg2 int count = 0;
4024   for (lp = chptr->members; lp; lp = lp->next)
4025     if (lp->flags & CHFL_ZOMBIE)
4026       count++;
4027   return count;
4028 }
4029
4030 /*
4031  * m_list
4032  *
4033  * parv[0] = sender prefix
4034  * parv[1] = channel list or user/time limit
4035  * parv[2...] = more user/time limits
4036  */
4037 int m_list(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
4038 {
4039   aChannel *chptr;
4040   char *name, *p = NULL;
4041   int show_usage = 0, show_channels = 0, param;
4042   aListingArgs args = {
4043     2147483647,                 /* max_time */
4044     0,                          /* min_time */
4045     4294967295U,                /* max_users */
4046     0,                          /* min_users */
4047     0,                          /* topic_limits */
4048     2147483647,                 /* max_topic_time */
4049     0,                          /* min_topic_time */
4050     NULL                        /* chptr */
4051   };
4052
4053   if (sptr->listing)            /* Already listing ? */
4054   {
4055     sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
4056     RunFree(sptr->listing);
4057     sptr->listing = NULL;
4058     sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
4059     if (parc < 2)
4060       return 0;                 /* Let LIST abort a listing. */
4061   }
4062
4063   if (parc < 2)                 /* No arguments given to /LIST ? */
4064   {
4065 #ifdef DEFAULT_LIST_PARAM
4066     static char *defparv[MAXPARA + 1];
4067     static int defparc = 0;
4068     static char lp[] = DEFAULT_LIST_PARAM;
4069     int i;
4070
4071     if (!defparc)
4072     {
4073       char *s = lp, *t;
4074
4075       defparc = 1;
4076       defparv[defparc++] = t = strtok(s, " ");
4077       while (t && defparc < MAXPARA)
4078       {
4079         if ((t = strtok(NULL, " ")))
4080           defparv[defparc++] = t;
4081       }
4082     }
4083     for (i = 1; i < defparc; i++)
4084       parv[i] = defparv[i];
4085     parv[i] = NULL;
4086     parc = defparc;
4087 #endif /* DEFAULT_LIST_PARAM */
4088   }
4089
4090   /* Decode command */
4091   for (param = 1; !show_usage && parv[param]; param++)
4092   {
4093     char *p = parv[param];
4094     do
4095     {
4096       int is_time = 0;
4097       switch (*p)
4098       {
4099         case 'T':
4100         case 't':
4101           is_time++;
4102           args.topic_limits = 1;
4103           /* Fall through */
4104         case 'C':
4105         case 'c':
4106           is_time++;
4107           p++;
4108           if (*p != '<' && *p != '>')
4109           {
4110             show_usage = 1;
4111             break;
4112           }
4113           /* Fall through */
4114         case '<':
4115         case '>':
4116         {
4117           p++;
4118           if (!isDigit(*p))
4119             show_usage = 1;
4120           else
4121           {
4122             if (is_time)
4123             {
4124               time_t val = atoi(p);
4125               if (p[-1] == '<')
4126               {
4127                 if (val < 80000000)     /* Toggle UTC/offset */
4128                 {
4129                   /*
4130                    * Demands that
4131                    * 'TStime() - chptr->creationtime < val * 60'
4132                    * Which equals
4133                    * 'chptr->creationtime > TStime() - val * 60'
4134                    */
4135                   if (is_time == 1)
4136                     args.min_time = TStime() - val * 60;
4137                   else
4138                     args.min_topic_time = TStime() - val * 60;
4139                 }
4140                 else if (is_time == 1)  /* Creation time in UTC was entered */
4141                   args.max_time = val;
4142                 else            /* Topic time in UTC was entered */
4143                   args.max_topic_time = val;
4144               }
4145               else if (val < 80000000)
4146               {
4147                 if (is_time == 1)
4148                   args.max_time = TStime() - val * 60;
4149                 else
4150                   args.max_topic_time = TStime() - val * 60;
4151               }
4152               else if (is_time == 1)
4153                 args.min_time = val;
4154               else
4155                 args.min_topic_time = val;
4156             }
4157             else if (p[-1] == '<')
4158               args.max_users = atoi(p);
4159             else
4160               args.min_users = atoi(p);
4161             if ((p = strchr(p, ',')))
4162               p++;
4163           }
4164           break;
4165         }
4166         default:
4167           if (!IsChannelName(p))
4168           {
4169             show_usage = 1;
4170             break;
4171           }
4172           if (parc != 2)        /* Don't allow a mixture of channels with <,> */
4173             show_usage = 1;
4174           show_channels = 1;
4175           p = NULL;
4176           break;
4177       }
4178     }
4179     while (!show_usage && p);   /* p points after comma, or is NULL */
4180   }
4181
4182   if (show_usage)
4183   {
4184     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4185         "Usage: \002/QUOTE LIST\002 \037parameters\037");
4186     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4187         "Where \037parameters\037 is a space or comma seperated "
4188         "list of one or more of:");
4189     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4190         " \002<\002\037max_users\037    ; Show all channels with less "
4191         "than \037max_users\037.");
4192     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4193         " \002>\002\037min_users\037    ; Show all channels with more "
4194         "than \037min_users\037.");
4195     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4196         " \002C<\002\037max_minutes\037 ; Channels that exist less "
4197         "than \037max_minutes\037.");
4198     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4199         " \002C>\002\037min_minutes\037 ; Channels that exist more "
4200         "than \037min_minutes\037.");
4201     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4202         " \002T<\002\037max_minutes\037 ; Channels with a topic last "
4203         "set less than \037max_minutes\037 ago.");
4204     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4205         " \002T>\002\037min_minutes\037 ; Channels with a topic last "
4206         "set more than \037min_minutes\037 ago.");
4207     sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
4208         "Example: LIST <3,>1,C<10,T>0  ; 2 users, younger than 10 min., "
4209         "topic set.");
4210     return 0;
4211   }
4212
4213   sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
4214
4215   if (!show_channels)
4216   {
4217     if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
4218         args.max_topic_time > args.min_topic_time)      /* Sanity check */
4219     {
4220       if ((sptr->listing = (aListingArgs *)RunMalloc(sizeof(aListingArgs))))
4221       {
4222         memcpy(sptr->listing, &args, sizeof(aListingArgs));
4223         if ((sptr->listing->chptr = channel))
4224         {
4225           int m = channel->mode.mode & MODE_LISTED;
4226           list_next_channels(sptr, 64);
4227           channel->mode.mode |= m;
4228           return 0;
4229         }
4230         RunFree(sptr->listing);
4231         sptr->listing = NULL;
4232       }
4233     }
4234     sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
4235     return 0;
4236   }
4237
4238   for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
4239   {
4240     chptr = FindChannel(name);
4241     if (chptr && ShowChannel(sptr, chptr) && sptr->user)
4242       sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
4243           ShowChannel(sptr, chptr) ? chptr->chname : "*",
4244           chptr->users - number_of_zombies(chptr), chptr->topic);
4245   }
4246
4247   sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
4248   return 0;
4249 }
4250
4251 /*
4252  * m_names                              - Added by Jto 27 Apr 1989
4253  *
4254  * parv[0] = sender prefix
4255  * parv[1] = channel
4256  */
4257 int m_names(aClient *cptr, aClient *sptr, int parc, char *parv[])
4258 {
4259   Reg1 aChannel *chptr;
4260   Reg2 aClient *c2ptr;
4261   Reg3 Link *lp;
4262   aChannel *ch2ptr = NULL;
4263   int idx, flag, len, mlen;
4264   char *s, *para = parc > 1 ? parv[1] : NULL;
4265
4266   if (parc > 2 && hunt_server(1, cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
4267     return 0;
4268
4269   mlen = strlen(me.name) + 10 + strlen(sptr->name);
4270
4271   if (!BadPtr(para))
4272   {
4273     s = strchr(para, ',');
4274     if (s)
4275     {
4276       parv[1] = ++s;
4277       m_names(cptr, sptr, parc, parv);
4278     }
4279     clean_channelname(para);
4280     ch2ptr = FindChannel(para);
4281   }
4282
4283   /*
4284    * First, do all visible channels (public and the one user self is)
4285    */
4286
4287   for (chptr = channel; chptr; chptr = chptr->nextch)
4288   {
4289     if ((chptr != ch2ptr) && !BadPtr(para))
4290       continue;                 /* -- wanted a specific channel */
4291     if (!MyConnect(sptr) && BadPtr(para))
4292       continue;
4293 #ifndef GODMODE
4294     if (!ShowChannel(sptr, chptr))
4295       continue;                 /* -- users on this are not listed */
4296 #endif
4297
4298     /* Find users on same channel (defined by chptr) */
4299
4300     strcpy(buf, "* ");
4301     len = strlen(chptr->chname);
4302     strcpy(buf + 2, chptr->chname);
4303     strcpy(buf + 2 + len, " :");
4304
4305     if (PubChannel(chptr))
4306       *buf = '=';
4307     else if (SecretChannel(chptr))
4308       *buf = '@';
4309     idx = len + 4;
4310     flag = 1;
4311     for (lp = chptr->members; lp; lp = lp->next)
4312     {
4313       c2ptr = lp->value.cptr;
4314 #ifndef GODMODE
4315       if (sptr != c2ptr && IsInvisible(c2ptr) && !IsMember(sptr, chptr))
4316         continue;
4317 #endif
4318       if (lp->flags & CHFL_ZOMBIE)
4319       {
4320         if (lp->value.cptr != sptr)
4321           continue;
4322         else
4323         {
4324           strcat(buf, "!");
4325           idx++;
4326         }
4327       }
4328       else if (lp->flags & CHFL_CHANOP)
4329       {
4330         strcat(buf, "@");
4331         idx++;
4332       }
4333       else if (lp->flags & CHFL_VOICE)
4334       {
4335         strcat(buf, "+");
4336         idx++;
4337       }
4338       strcat(buf, c2ptr->name);
4339       strcat(buf, " ");
4340       idx += strlen(c2ptr->name) + 1;
4341       flag = 1;
4342 #ifdef GODMODE
4343       {
4344         char yxx[6];
4345         sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
4346         if (c2ptr != findNUser(yxx))
4347           MyCoreDump;
4348         sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
4349         idx += 6;
4350       }
4351       if (mlen + idx + NICKLEN + 11 > BUFSIZE)
4352 #else
4353       if (mlen + idx + NICKLEN + 5 > BUFSIZE)
4354 #endif
4355         /* space, modifier, nick, \r \n \0 */
4356       {
4357         sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4358         strcpy(buf, "* ");
4359         strncpy(buf + 2, chptr->chname, len + 1);
4360         buf[len + 2] = 0;
4361         strcat(buf, " :");
4362         if (PubChannel(chptr))
4363           *buf = '=';
4364         else if (SecretChannel(chptr))
4365           *buf = '@';
4366         idx = len + 4;
4367         flag = 0;
4368       }
4369     }
4370     if (flag)
4371       sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4372   }
4373   if (!BadPtr(para))
4374   {
4375     sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0],
4376         ch2ptr ? ch2ptr->chname : para);
4377     return (1);
4378   }
4379
4380   /* Second, do all non-public, non-secret channels in one big sweep */
4381
4382   strcpy(buf, "* * :");
4383   idx = 5;
4384   flag = 0;
4385   for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
4386   {
4387     aChannel *ch3ptr;
4388     int showflag = 0, secret = 0;
4389
4390 #ifndef GODMODE
4391     if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
4392 #else
4393     if (!IsUser(c2ptr))
4394 #endif
4395       continue;
4396     lp = c2ptr->user->channel;
4397     /*
4398      * Don't show a client if they are on a secret channel or when
4399      * they are on a channel sptr is on since they have already
4400      * been show earlier. -avalon
4401      */
4402     while (lp)
4403     {
4404       ch3ptr = lp->value.chptr;
4405 #ifndef GODMODE
4406       if (PubChannel(ch3ptr) || IsMember(sptr, ch3ptr))
4407 #endif
4408         showflag = 1;
4409       if (SecretChannel(ch3ptr))
4410         secret = 1;
4411       lp = lp->next;
4412     }
4413     if (showflag)               /* Have we already shown them ? */
4414       continue;
4415 #ifndef GODMODE
4416     if (secret)                 /* On any secret channels ? */
4417       continue;
4418 #endif
4419     strcat(buf, c2ptr->name);
4420     strcat(buf, " ");
4421     idx += strlen(c2ptr->name) + 1;
4422     flag = 1;
4423 #ifdef GODMODE
4424     {
4425       char yxx[6];
4426       sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
4427       if (c2ptr != findNUser(yxx))
4428         MyCoreDump;
4429       sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
4430       idx += 6;
4431     }
4432 #endif
4433 #ifdef GODMODE
4434     if (mlen + idx + NICKLEN + 9 > BUFSIZE)
4435 #else
4436     if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
4437 #endif
4438     {
4439       sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4440       strcpy(buf, "* * :");
4441       idx = 5;
4442       flag = 0;
4443     }
4444   }
4445   if (flag)
4446     sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
4447   sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
4448   return (1);
4449 }
4450
4451 void send_user_joins(aClient *cptr, aClient *user)
4452 {
4453   Reg1 Link *lp;
4454   Reg2 aChannel *chptr;
4455   Reg3 int cnt = 0, len = 0, clen;
4456   char *mask;
4457
4458   *buf = ':';
4459   strcpy(buf + 1, user->name);
4460   strcat(buf, " JOIN ");
4461   len = strlen(user->name) + 7;
4462
4463   for (lp = user->user->channel; lp; lp = lp->next)
4464   {
4465     chptr = lp->value.chptr;
4466     if ((mask = strchr(chptr->chname, ':')))
4467       if (match(++mask, cptr->name))
4468         continue;
4469     if (*chptr->chname == '&')
4470       continue;
4471     if (is_zombie(user, chptr))
4472       continue;
4473     clen = strlen(chptr->chname);
4474     if (clen + 1 + len > BUFSIZE - 3)
4475     {
4476       if (cnt)
4477       {
4478         buf[len - 1] = '\0';
4479         sendto_one(cptr, "%s", buf);
4480       }
4481       *buf = ':';
4482       strcpy(buf + 1, user->name);
4483       strcat(buf, " JOIN ");
4484       len = strlen(user->name) + 7;
4485       cnt = 0;
4486     }
4487     strcpy(buf + len, chptr->chname);
4488     cnt++;
4489     len += clen;
4490     if (lp->next)
4491     {
4492       len++;
4493       strcat(buf, ",");
4494     }
4495   }
4496   if (*buf && cnt)
4497     sendto_one(cptr, "%s", buf);
4498
4499   return;
4500 }
4501
4502 /*
4503  * send_hack_notice()
4504  *
4505  * parc & parv[] are the same as that of the calling function:
4506  *   mtype == 1 is from m_mode, 2 is from m_create, 3 is from m_kick.
4507  *
4508  * This function prepares sendbuf with the server notices and wallops
4509  *   to be sent for all hacks.  -Ghostwolf 18-May-97
4510  */
4511
4512 static void send_hack_notice(aClient *cptr, aClient *sptr, int parc,
4513     char *parv[], int badop, int mtype)
4514 {
4515   aChannel *chptr;
4516   static char params[MODEBUFLEN];
4517   int i = 3;
4518   chptr = FindChannel(parv[1]);
4519   *params = '\0';
4520
4521   if (Protocol(cptr) < 10)      /* We don't get numeric nicks from P09  */
4522   {                             /* servers, so this can be sent "As Is" */
4523     if (mtype == 1)
4524     {
4525       while (i < parc)
4526       {
4527         strcat(params, " ");
4528         strcat(params, parv[i++]);
4529       }
4530       sprintf_irc(sendbuf,
4531           ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s [" TIME_T_FMT
4532           "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop, parv[0],
4533           parv[1], parv[2], params, chptr->creationtime);
4534       sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop ==
4535           4) ? SNO_HACK4 : SNO_HACK2);
4536
4537       if ((IsServer(sptr)) && (badop == 2))
4538       {
4539         sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
4540             me.name, parv[0], parv[1], parv[2], params);
4541         sendbufto_serv_butone(cptr);
4542       }
4543     }
4544     else if (mtype == 3)
4545     {
4546       sprintf_irc(sendbuf,
4547           ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
4548           me.name, sptr->name, parv[1], parv[2], parv[3]);
4549       sendbufto_op_mask(SNO_HACK4);
4550     }
4551   }
4552   else
4553   {
4554     /* P10 servers require numeric nick conversion before sending. */
4555     switch (mtype)
4556     {
4557       case 1:                   /* Convert nicks for MODE HACKs here  */
4558       {
4559         char *mode = parv[2];
4560         while (i < parc)
4561         {
4562           while (*mode && *mode != 'o' && *mode != 'v')
4563             ++mode;
4564           strcat(params, " ");
4565           if (*mode == 'o' || *mode == 'v')
4566           {
4567             register aClient *acptr;
4568             if ((acptr = findNUser(parv[i])) != NULL)   /* Convert nicks here */
4569               strcat(params, acptr->name);
4570             else
4571             {
4572               strcat(params, "<");
4573               strcat(params, parv[i]);
4574               strcat(params, ">");
4575             }
4576           }
4577           else                  /* If it isn't a numnick, send it 'as is' */
4578             strcat(params, parv[i]);
4579           i++;
4580         }
4581         sprintf_irc(sendbuf,
4582             ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s ["
4583             TIME_T_FMT "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop,
4584             parv[0], parv[1], parv[2], params, chptr->creationtime);
4585         sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop ==
4586             4) ? SNO_HACK4 : SNO_HACK2);
4587
4588         if ((IsServer(sptr)) && (badop == 2))
4589         {
4590           sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
4591               me.name, parv[0], parv[1], parv[2], params);
4592           sendbufto_serv_butone(cptr);
4593         }
4594         break;
4595       }
4596       case 2:                   /* No conversion is needed for CREATE; the only numnick is sptr */
4597       {
4598         sendto_serv_butone(cptr, ":%s DESYNCH :HACK: %s CREATE %s %s",
4599             me.name, sptr->name, chptr->chname, parv[2]);
4600         sendto_op_mask(SNO_HACK2, "HACK(2): %s CREATE %s %s",
4601             sptr->name, chptr->chname, parv[2]);
4602         break;
4603       }
4604       case 3:                   /* Convert nick in KICK message */
4605       {
4606         aClient *acptr;
4607         if ((acptr = findNUser(parv[2])) != NULL)       /* attempt to convert nick */
4608           sprintf_irc(sendbuf,
4609               ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
4610               me.name, sptr->name, parv[1], acptr->name, parv[3]);
4611         else                    /* if conversion fails, send it 'as is' in <>'s */
4612           sprintf_irc(sendbuf,
4613               ":%s NOTICE * :*** Notice -- HACK: %s KICK %s <%s> :%s",
4614               me.name, sptr->name, parv[1], parv[2], parv[3]);
4615         sendbufto_op_mask(SNO_HACK4);
4616         break;
4617       }
4618     }
4619   }
4620 }