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