Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / m_burst.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_burst.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "channel.h"
91 #include "client.h"
92 #include "hash.h"
93 #include "ircd.h"
94 #include "ircd_alloc.h"
95 #include "ircd_reply.h"
96 #include "ircd_string.h"
97 #include "list.h"
98 #include "match.h"
99 #include "msg.h"
100 #include "numeric.h"
101 #include "numnicks.h"
102 #include "s_conf.h"
103 #include "s_misc.h"
104 #include "send.h"
105 #include "struct.h"
106 #include "support.h"
107
108 #include <assert.h>
109 #include <stdlib.h>
110 #include <string.h>
111
112 /*
113  * ms_burst - server message handler
114  *
115  * --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
116  *
117  * parv[0] = sender prefix
118  * parv[1] = channel name
119  * parv[2] = channel timestamp
120  * The meaning of the following parv[]'s depend on their first character:
121  * If parv[n] starts with a '+':
122  * Net burst, additive modes
123  *   parv[n] = <mode>
124  *   parv[n+1] = <param> (optional)
125  *   parv[n+2] = <param> (optional)
126  * If parv[n] starts with a '%', then n will be parc-1:
127  *   parv[n] = %<ban> <ban> <ban> ...
128  * If parv[n] starts with another character:
129  *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
130  *   where <mode> is the channel mode (ov) of nick and all following nicks.
131  *
132  * Example:
133  * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
134  *
135  * Anti net.ride code.
136  *
137  * When the channel already exist, and its TS is larger then
138  * the TS in the BURST message, then we cancel all existing modes.
139  * If its is smaller then the received BURST message is ignored.
140  * If it's equal, then the received modes are just added.
141  */
142 int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
143 {
144   struct ModeBuf modebuf, *mbuf = 0;
145   struct Channel *chptr;
146   time_t timestamp;
147   struct Membership *member;
148   struct SLink *lp, **lp_p;
149   unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST);
150   int param, nickpos = 0, banpos = 0;
151   char modestr[IRC_BUFSIZE], nickstr[IRC_BUFSIZE], banstr[IRC_BUFSIZE];
152
153   if (parc < 4)
154     return 0;
155
156   if (!IsBurst(sptr)) /* don't allow BURST outside of burst */
157     return exit_client_msg(cptr, cptr, &me, "HACK: BURST message outside "
158                            "net.burst from %s", sptr->name);
159
160   if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
161     return 0; /* can't create the channel? */
162
163   timestamp = atoi(parv[2]);
164
165   /* turn off burst joined flag */
166   for (member = chptr->members; member; member = member->next_member)
167     member->status &= ~CHFL_BURST_JOINED;
168
169   if (!chptr->creationtime) /* mark channel as created during BURST */
170     chptr->mode.mode |= MODE_BURSTADDED;
171
172   /* new channel or an older one */
173   if (!chptr->creationtime || chptr->creationtime > timestamp) {
174     chptr->creationtime = timestamp;
175
176     modebuf_init(mbuf = &modebuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL);
177     modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
178     chptr->mode.mode &= ~(MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET |
179                           MODE_MODERATED | MODE_TOPICLIMIT | MODE_INVITEONLY |
180                           MODE_NOPRIVMSGS);
181
182     parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */
183
184     /* mark bans for wipeout */
185     for (lp = chptr->banlist; lp; lp = lp->next)
186       lp->flags |= CHFL_BURST_BAN_WIPEOUT;
187   } else if (chptr->creationtime == timestamp) {
188     modebuf_init(mbuf = &modebuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL);
189
190     parse_flags |= MODE_PARSE_SET; /* set new modes */
191   }
192
193   param = 3; /* parse parameters */
194   while (param < parc) {
195     switch (*parv[param]) {
196     case '+': /* parameter introduces a mode string */
197       param += mode_parse(mbuf, cptr, sptr, chptr, parc - param,
198                           parv + param, parse_flags);
199       break;
200
201     case '%': /* parameter contains bans */
202       if (parse_flags & MODE_PARSE_SET) {
203         char *banlist = parv[param] + 1, *p = 0, *ban, *ptr;
204         struct SLink *newban;
205
206         for (ban = ircd_strtok(&p, banlist, " "); ban;
207              ban = ircd_strtok(&p, 0, " ")) {
208           ban = collapse(pretty_mask(ban));
209
210             /*
211              * Yeah, we should probably do this elsewhere, and make it better
212              * and more general; this will hold until we get there, though.
213              * I dislike the current add_banid API... -Kev
214              *
215              * I wish there were a better algo. for this than the n^2 one
216              * shown below *sigh*
217              */
218           for (lp = chptr->banlist; lp; lp = lp->next) {
219             if (!ircd_strcmp(lp->value.ban.banstr, ban)) {
220               ban = 0; /* don't add ban */
221               lp->flags &= ~CHFL_BURST_BAN_WIPEOUT; /* not wiping out */
222               break; /* new ban already existed; don't even repropagate */
223             } else if (!(lp->flags & CHFL_BURST_BAN_WIPEOUT) &&
224                        !mmatch(lp->value.ban.banstr, ban)) {
225               ban = 0; /* don't add ban unless wiping out bans */
226               break; /* new ban is encompassed by an existing one; drop */
227             } else if (!mmatch(ban, lp->value.ban.banstr))
228               lp->flags |= CHFL_BAN_OVERLAPPED; /* remove overlapping ban */
229
230             if (!lp->next)
231               break;
232           }
233
234           if (ban) { /* add the new ban to the end of the list */
235             /* Build ban buffer */
236             if (!banpos) {
237               banstr[banpos++] = ' ';
238               banstr[banpos++] = ':';
239               banstr[banpos++] = '%';
240             } else
241               banstr[banpos++] = ' ';
242             for (ptr = ban; *ptr; ptr++) /* add ban to buffer */
243               banstr[banpos++] = *ptr;
244
245             newban = make_link(); /* create new ban */
246
247             DupString(newban->value.ban.banstr, ban);
248             DupString(newban->value.ban.who, sptr->name);
249             newban->value.ban.when = TStime();
250
251             newban->flags = CHFL_BAN | CHFL_BURST_BAN; /* set flags */
252             if ((ptr = strrchr(ban, '@')) && check_if_ipmask(ptr + 1))
253               newban->flags |= CHFL_BAN_IPMASK;
254
255             newban->next = 0;
256             if (lp)
257               lp->next = newban; /* link it in */
258             else
259               chptr->banlist = newban;
260           }
261         }
262       } 
263       param++; /* look at next param */
264       break;
265
266     default: /* parameter contains clients */
267       {
268         struct Client *acptr;
269         char *nicklist = parv[param], *p = 0, *nick, *ptr;
270         int default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
271         int last_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
272
273         for (nick = ircd_strtok(&p, nicklist, ","); nick;
274              nick = ircd_strtok(&p, 0, " ")) {
275
276           if ((ptr = strchr(nick, ':'))) { /* new flags; deal */
277             *ptr++ = '\0';
278
279             if (parse_flags & MODE_PARSE_SET) {
280               for (default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; *ptr;
281                    ptr++) {
282                 if (*ptr == 'o') /* has oper status */
283                   default_mode = (default_mode & ~CHFL_DEOPPED) | CHFL_CHANOP;
284                 else if (*ptr == 'v') /* has voice status */
285                   default_mode |= CHFL_VOICE;
286                 else /* I don't recognize that flag */
287                   break; /* so stop processing */
288               }
289             }
290           }
291
292           if (!(acptr = findNUser(nick)) || acptr->from != cptr)
293             continue; /* ignore this client */
294
295           /* Build nick buffer */
296           nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */
297           nickpos++;
298
299           for (ptr = nick; *ptr; ptr++) /* store nick */
300             nickstr[nickpos++] = *ptr;
301
302           if (default_mode != last_mode) { /* if mode changed... */
303             last_mode = default_mode;
304
305             nickstr[nickpos++] = ':'; /* add a specifier */
306             if (default_mode & CHFL_CHANOP)
307               nickstr[nickpos++] = 'o';
308             if (default_mode & CHFL_VOICE)
309               nickstr[nickpos++] = 'v';
310           }
311
312           add_user_to_channel(chptr, acptr, default_mode);
313           sendcmdto_channel_butserv(acptr, CMD_JOIN, chptr, "%H", chptr);
314         }
315       }
316       param++;
317       break;
318     } /* switch (*parv[param]) { */
319   } /* while (param < parc) { */
320
321   nickstr[nickpos] = '\0';
322   banstr[banpos] = '\0';
323
324   if (parse_flags & MODE_PARSE_SET) {
325     modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */
326     modestr[0] = modestr[1] ? ' ' : '\0';
327   } else
328     modestr[0] = '\0';
329
330   sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr,
331                         chptr->creationtime, modestr, nickstr, banstr);
332
333   if (parse_flags & MODE_PARSE_WIPEOUT || banpos)
334     mode_ban_invalidate(chptr);
335
336   if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */
337     /* first deal with channel members */
338     for (member = chptr->members; member; member = member->next_member) {
339       if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
340         if (member->status & CHFL_CHANOP)
341           modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user);
342         if (member->status & CHFL_VOICE)
343           modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user);
344       } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
345         if (member->status & CHFL_CHANOP)
346           modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user);
347         if (member->status & CHFL_VOICE)
348           modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user);
349         member->status = ((member->status & ~(CHFL_CHANOP | CHFL_VOICE)) |
350                           CHFL_DEOPPED);
351       }
352     }
353
354     /* Now deal with channel bans */
355     lp_p = &chptr->banlist;
356     while (*lp_p) {
357       lp = *lp_p;
358
359       /* remove ban from channel */
360       if (lp->flags & (CHFL_BAN_OVERLAPPED | CHFL_BURST_BAN_WIPEOUT)) {
361         modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
362                             lp->value.ban.banstr, 1); /* let it free banstr */
363
364         *lp_p = lp->next; /* clip out of list */
365         MyFree(lp->value.ban.who); /* free who */
366         free_link(lp); /* free ban */
367         continue;
368       } else if (lp->flags & CHFL_BURST_BAN) /* add ban to channel */
369         modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN,
370                             lp->value.ban.banstr, 0); /* don't free banstr */
371
372       lp->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* reset the flag */
373       lp_p = &(*lp_p)->next;
374     }
375   }
376
377   return mbuf ? modebuf_flush(mbuf) : 0;
378 }
379 #if 0
380 int ms_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
381 {
382   struct Channel* chptr;
383   time_t          timestamp;
384   int             netride = 0;
385   int             wipeout = 0;
386   int             n;
387   int             send_it = 0;
388   int             add_banid_not_called = 1;
389   struct Mode*    current_mode;
390   size_t          sblen;
391   size_t          mblen = 0;
392   int             mblen2;
393   int             pblen2;
394   int             cnt;
395   int             prev_mode;
396   char            prev_key[KEYLEN + 1];
397   struct Membership* member;
398   struct SLink*   lp;
399   char modebuf[MODEBUFLEN];
400   char parabuf[MODEBUFLEN];
401   char bmodebuf[MODEBUFLEN];
402   char bparambuf[MODEBUFLEN];
403
404   /* BURST is only for servers and has at least 4 parameters */
405   if (!IsServer(cptr) || parc < 4)
406     return 0;
407
408   if (!IsBurst(sptr))
409   {
410     int i;
411     char *p;
412     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
413     {
414       p =
415           sprintf_irc(sendbuf,
416           ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
417           sptr->name, parv[1], parv[2]);
418       for (i = 3; i < parc - 1; ++i)
419         p = sprintf_irc(p, " %s", parv[i]);
420       sprintf_irc(p, " :%s", parv[parc - 1]);
421       sendbufto_op_mask(SNO_HACK4);
422     }
423     else
424     {
425 #if 1            /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
426       SetBurst(sptr);
427       if (MyConnect(sptr))
428 #endif
429         return exit_client_msg(cptr, cptr, &me,
430             "HACK: BURST message outside net.burst from %s", sptr->name);
431     }
432   }
433
434   /* Find the channel, or create it - note that the creation time
435    * will be 0 if it has to be created */
436   chptr = get_channel(sptr, parv[1], CGT_CREATE);
437   current_mode = &chptr->mode;
438   prev_mode = chptr->mode.mode;
439   if (*chptr->mode.key)
440   {
441     prev_mode |= MODE_KEY;
442     strcpy(prev_key, chptr->mode.key);
443   }
444   if (chptr->mode.limit)
445     prev_mode |= MODE_LIMIT;
446
447   timestamp = atoi(parv[2]);
448
449   /* Copy the new TS when the received creationtime appears to be older */
450   if (!chptr->creationtime || chptr->creationtime > timestamp)
451   {
452     /* Set the new timestamp */
453     chptr->creationtime = timestamp;
454     send_it = 1;                /* Make sure we pass on the different timestamp ! */
455     /* Mark all bans as needed to be wiped out */
456     for (lp = chptr->banlist; lp; lp = lp->next)
457       lp->flags |= CHFL_BURST_BAN_WIPEOUT;
458     /*
459      * Only the first BURST for this channel can have creationtime > timestamp,
460      * so at this moment ALL members are on OUR side, and thus all net.riders:
461      */
462     wipeout = 1;
463   }
464   for (member = chptr->members; member; member = member->next_member)
465     member->status &= ~CHFL_BURST_JOINED;    /* Set later for nicks in the BURST msg */
466   /* If `wipeout' is set then these will be deopped later. */
467
468   /* If the entering creationtime is younger, ignore the modes */
469   if (chptr->creationtime < timestamp)
470     netride = 1;                /* Only pass on the nicks (so they JOIN) */
471
472   /* Prepare buffers to pass the message */
473   *bparambuf = *bmodebuf = *parabuf = '\0';
474   pblen2 = 0;
475   *modebuf = '+';
476   mblen2 = 1;
477   cnt = 0;
478   sblen = sprintf_irc(sendbuf, "%s B %s " TIME_T_FMT,
479       NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
480
481   /* Run over all remaining parameters */
482   for (n = 3; n < parc; n++)
483     switch (*parv[n])           /* What type is it ? mode, nicks or bans ? */
484     {
485       case '+':         /* modes */
486       {
487         char *p = parv[n];
488         while (*(++p))          /* Run over all mode characters */
489         {
490           switch (*p)           /* which mode ? */
491           {
492               /*
493                * The following cases all do the following:
494                * - In case wipeout needed, reset 'prev_mode' to indicate this
495                *   mode should not be cancelled.
496                * - If wipeout or (not netride and the new mode is a change),
497                *   add it to bmodebuf and bparabuf for propagation.
498                * - Else ignore it.
499                * - Add it to modebuf and parabuf for propagation to the
500                *   clients when not netride and the new mode is a change.
501                * Special cases:
502                * - If a +s is received, cancel a +p and sent a -p to the
503                *   clients too (if +p was set).
504                * - If a +p is received and +s is set, ignore the +p.
505                */
506             case 'i':
507             {
508               int tmp;
509               prev_mode &= ~MODE_INVITEONLY;
510               if (!(tmp = netride ||
511                   (current_mode->mode & MODE_INVITEONLY)) || wipeout)
512               {
513                 bmodebuf[mblen++] = 'i';
514                 current_mode->mode |= MODE_INVITEONLY;
515               }
516               if (!tmp)
517                 modebuf[mblen2++] = 'i';
518               break;
519             }
520             case 'k':
521             {
522               int tmp;
523               char *param = parv[++n];
524               prev_mode &= ~MODE_KEY;
525               if (!(tmp = netride || (*current_mode->key &&
526                   (!strcmp(current_mode->key, param) ||
527                   (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
528                   wipeout)
529               {
530                 bmodebuf[mblen++] = 'k';
531                 strcat(bparambuf, " ");
532                 strcat(bparambuf, param);
533                 ircd_strncpy(current_mode->key, param, KEYLEN);
534               }
535               if (!tmp && !wipeout)
536               {
537                 modebuf[mblen2++] = 'k';
538                 parabuf[pblen2++] = ' ';
539                 strcpy(parabuf + pblen2, param);
540                 pblen2 += strlen(param);
541                 cnt++;
542               }
543               break;
544             }
545             case 'l':
546             {
547               int tmp;
548               unsigned int param = atoi(parv[++n]);
549               prev_mode &= ~MODE_LIMIT;
550               if (!(tmp = netride || (current_mode->limit &&
551                   (current_mode->limit == param ||
552                   (!wipeout && current_mode->limit < param)))) || wipeout)
553               {
554                 bmodebuf[mblen++] = 'l';
555                 sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
556                 current_mode->limit = param;
557               }
558               if (!tmp)
559               {
560                 modebuf[mblen2++] = 'l';
561                 pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
562                 cnt++;
563               }
564               break;
565             }
566             case 'm':
567             {
568               int tmp;
569               prev_mode &= ~MODE_MODERATED;
570               if (!(tmp = netride ||
571                   (current_mode->mode & MODE_MODERATED)) || wipeout)
572               {
573                 bmodebuf[mblen++] = 'm';
574                 current_mode->mode |= MODE_MODERATED;
575               }
576               if (!tmp)
577                 modebuf[mblen2++] = 'm';
578               break;
579             }
580             case 'n':
581             {
582               int tmp;
583               prev_mode &= ~MODE_NOPRIVMSGS;
584               if (!(tmp = netride ||
585                   (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
586               {
587                 bmodebuf[mblen++] = 'n';
588                 current_mode->mode |= MODE_NOPRIVMSGS;
589               }
590               if (!tmp)
591                 modebuf[mblen2++] = 'n';
592               break;
593             }
594             case 'p':
595             {
596               int tmp;
597
598               /* Special case: */
599               if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
600                 break;
601
602               prev_mode &= ~MODE_PRIVATE;
603               if (!(tmp = netride ||
604                   (current_mode->mode & MODE_PRIVATE)) || wipeout)
605               {
606                 bmodebuf[mblen++] = 'p';
607                 current_mode->mode |= MODE_PRIVATE;
608               }
609               if (!tmp)
610                 modebuf[mblen2++] = 'p';
611               break;
612             }
613             case 's':
614             {
615               int tmp;
616               prev_mode &= ~MODE_SECRET;
617               if (!(tmp = netride ||
618                   (current_mode->mode & MODE_SECRET)) || wipeout)
619               {
620                 bmodebuf[mblen++] = 's';
621                 current_mode->mode |= MODE_SECRET;
622               }
623               if (!tmp)
624                 modebuf[mblen2++] = 's';
625
626               /* Special case: */
627               if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
628               {
629                 int i;
630                 for (i = mblen2 - 1; i >= 0; --i)
631                   modebuf[i + 2] = modebuf[i];
632                 modebuf[0] = '-';
633                 modebuf[1] = 'p';
634                 mblen2 += 2;
635                 current_mode->mode &= ~MODE_PRIVATE;
636               }
637
638               break;
639             }
640             case 't':
641             {
642               int tmp;
643               prev_mode &= ~MODE_TOPICLIMIT;
644               if (!(tmp = netride ||
645                   (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
646               {
647                 bmodebuf[mblen++] = 't';
648                 current_mode->mode |= MODE_TOPICLIMIT;
649               }
650               if (!tmp)
651                 modebuf[mblen2++] = 't';
652               break;
653             }
654           }
655         }                       /* <-- while over all modes */
656
657         bmodebuf[mblen] = '\0';
658         sendbuf[sblen] = '\0';
659         if (mblen)              /* Anything to send at all ? */
660         {
661           send_it = 1;
662           strcpy(sendbuf + sblen, " +");
663           sblen += 2;
664           strcpy(sendbuf + sblen, bmodebuf);
665           sblen += mblen;
666           strcpy(sendbuf + sblen, bparambuf);
667           sblen += strlen(bparambuf);
668         }
669         break;                  /* Done mode part */
670       }
671       case '%':         /* bans */
672       {
673         char *pv, *p = 0, *ban;
674         int first = 1;
675         if (netride)
676           break;                /* Ignore bans */
677         /* Run over all bans */
678         for (pv = parv[n] + 1; (ban = ircd_strtok(&p, pv, " ")); pv = 0)
679         {
680           int ret;
681           /*
682            * The following part should do the following:
683            * - If the new (un)ban is not a _change_ it is ignored.
684            * - Else, add it to sendbuf for later use.
685            * - If sendbuf is full, send it, and prepare a new
686            *   message in sendbuf.
687            */
688           ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
689           if (ret == 0)
690           {
691             add_banid_not_called = 0;
692             /* Mark this new ban so we can send it to the clients later */
693             chptr->banlist->flags |= CHFL_BURST_BAN;
694           }
695           if (ret != -1)
696             /* A new ban was added or an existing one needs to be passed on.
697              * Also add it to sendbuf: */
698             add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
699         }
700         break;                  /* Done bans part */
701       }
702       default:                  /* nicks */
703       {
704         char *pv, *p = 0, *nick, *ptr;
705         int first = 1;
706         /* Default mode: */
707         int default_mode = CHFL_DEOPPED;
708         /* Run over all nicks */
709         for (pv = parv[n]; (nick = ircd_strtok(&p, pv, ",")); pv = 0)
710         {
711           struct Client *acptr;
712           if ((ptr = strchr(nick, ':')))        /* New default mode ? */
713           {
714             *ptr = '\0';        /* Fix 'nick' */
715             acptr = findNUser(nick);
716             if (!netride)
717             {
718               /* Calculate new mode change: */
719               default_mode = CHFL_DEOPPED;
720               while (*(++ptr))
721                 if (*ptr == 'o')
722                 {
723                   default_mode |= CHFL_CHANOP;
724                   default_mode &= ~CHFL_DEOPPED;
725                 }
726                 else if (*ptr == 'v')
727                   default_mode |= CHFL_VOICE;
728                 else
729                   break;
730             }
731           }
732           else
733             acptr = findNUser(nick);
734           /*
735            * Note that at this point we already received a 'NICK' for any
736            * <nick> numeric that is joining (and possibly opped) here.
737            * Therefore we consider the following situations:
738            * - The <nick> numeric exists and is from the direction of cptr: ok
739            * - The <nick> numeric does not exist:
740            *   Apparently this previous <nick> numeric was killed (upstream)
741            *   or it collided with an existing <nick> name.
742            * - The <nick> numeric exists but is from another direction:
743            *   Apparently this previous <nick> numeric was killed,
744            *   and due to a reroute it signed on via another link (probably
745            *   a nick [numeric] collision).
746            * Note that it can't be a QUIT or SQUIT, because a QUIT would
747            * come from the same direction as the BURST (cptr) while an
748            * upstream SQUIT removes the source (server) and we would thus
749            * have this BURST ignored already.
750            * This means that if we find the nick and it is from the correct
751            * direction, it joins. If it doesn't exist or is from another
752            * direction, we have to ignore it. If all nicks are ignored, we
753            * remove the channel again when it is empty and don't propagate
754            * the BURST message.
755            */
756           if (acptr && acptr->from == cptr)
757           {
758             /*
759              * The following should do the following:
760              * - Add it to sendbuf for later use.
761              * - If sendbuf is full, send it, and prepare a new
762              *   message in sendbuf.
763              */
764             add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
765                 default_mode);
766             /* Let is take effect: (Note that in the case of a netride
767              * 'default_mode' is always CHFL_DEOPPED here). */
768             add_user_to_channel(chptr, acptr, default_mode | CHFL_BURST_JOINED);
769           }
770         }                       /* <-- Next nick */
771         if (!chptr->members)    /* All nicks collided and channel is empty ? */
772         {
773           sub1_from_channel(chptr);
774           return 0;             /* Forget about the (rest of the) message... */
775         }
776         break;                  /* Done nicks part */
777       }
778     }                           /* <-- Next parameter if any */
779   if (!chptr->members)          /* This message only contained bans (then the previous
780                                    message only contained collided nicks, see above) */
781   {
782     sub1_from_channel(chptr);
783     if (!add_banid_not_called)
784       while (next_removed_overlapped_ban());
785     return 0;                   /* Forget about the (rest of the) message... */
786   }
787
788   /* The last (possibly only) message is always send here */
789   if (send_it)                  /* Anything (left) to send ? */
790   {
791     struct DLink *lp;
792     struct Membership* member;
793
794     /* send 'sendbuf' to all downlinks */
795     for (lp = me.serv->down; lp; lp = lp->next)
796     {
797       if (lp->value.cptr == cptr)
798         continue;
799       if (Protocol(lp->value.cptr) > 9)
800         sendbufto_one(lp->value.cptr);
801     }
802
803     /*
804      * Now we finally can screw sendbuf again...
805      * Send all changes to the local clients:
806      *
807      * First send all joins and op them, because 2.9 servers
808      * would protest with a HACK if we first de-opped people.
809      * However, we don't send the +b bans yes, because we
810      * DO first want to -b the old bans (otherwise it's confusing).
811      */
812
813     /* Send all joins: */
814     for (member = chptr->members; member; member = member->next_member)
815       if (IsBurstJoined(member))
816       {
817         sendto_channel_butserv(chptr, member->user, ":%s JOIN :%s",
818                                member->user->name, chptr->chname);
819       }
820
821     if (!netride)
822     {
823       /* Send all +o and +v modes: */
824       for (member = chptr->members; member; member = member->next_member)
825       {
826         if (IsBurstJoined(member))
827         {
828           int mode = CHFL_CHANOP;
829           for (;;)
830           {
831             if ((member->status & mode))
832             {
833               modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
834               parabuf[pblen2++] = ' ';
835               strcpy(parabuf + pblen2, member->user->name);
836               pblen2 += strlen(member->user->name);
837               if (6 == ++cnt)
838               {
839                 modebuf[mblen2] = 0;
840                 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
841                     parv[0], chptr->chname, modebuf, parabuf);
842                 *parabuf = 0;
843                 pblen2 = 0;
844                 mblen2 = 1;
845                 cnt = 0;
846               }
847             }
848             if (mode == CHFL_CHANOP)
849               mode = CHFL_VOICE;
850             else
851               break;
852           }
853         }
854       }
855       /* Flush MODEs: */
856       if (cnt > 0 || mblen2 > 1)
857       {
858         modebuf[mblen2] = 0;
859         sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
860             parv[0], chptr->chname, modebuf, parabuf);
861       }
862     }
863   }
864
865   if (wipeout)
866   {
867     struct Membership* member;
868     struct SLink**     ban;
869     int                mode;
870     char               m;
871     int                count = -1;
872
873     /* Now cancel all previous simple modes */
874     if ((prev_mode & MODE_SECRET))
875       cancel_mode(sptr, chptr, 's', 0, &count);
876     if ((prev_mode & MODE_PRIVATE))
877       cancel_mode(sptr, chptr, 'p', 0, &count);
878     if ((prev_mode & MODE_MODERATED))
879       cancel_mode(sptr, chptr, 'm', 0, &count);
880     if ((prev_mode & MODE_TOPICLIMIT))
881       cancel_mode(sptr, chptr, 't', 0, &count);
882     if ((prev_mode & MODE_INVITEONLY))
883       cancel_mode(sptr, chptr, 'i', 0, &count);
884     if ((prev_mode & MODE_NOPRIVMSGS))
885       cancel_mode(sptr, chptr, 'n', 0, &count);
886     if ((prev_mode & MODE_LIMIT))
887     {
888       current_mode->limit = 0;
889       cancel_mode(sptr, chptr, 'l', 0, &count);
890     }
891     if ((prev_mode & MODE_KEY))
892     {
893       *current_mode->key = 0;
894       cancel_mode(sptr, chptr, 'k', prev_key, &count);
895     }
896     current_mode->mode &= ~prev_mode;
897
898     /* And deop and devoice all net.riders on my side */
899     mode = CHFL_CHANOP;
900     m = 'o';
901     for (;;)
902     {
903       struct Membership* member_next = 0;
904
905       for (member = chptr->members; member; member = member_next)
906       {
907         member_next = member->next_member;
908         if (IsBurstJoined(member))
909           continue;             /* This is not a net.rider from
910                                    this side of the net.junction */
911 #if defined(NO_INVITE_NETRIDE)
912         /*
913          * Kick net riding users from invite only channels.
914          *  - Isomer 25-11-1999
915          */
916         if (chptr->mode.mode & MODE_INVITEONLY) {
917           /* kick is magical - lotsa zombies and other undead.
918            * I'm hoping this is the right idea, comments anyone?
919            * Set everyone to a zombie, remove ops, and then send kicks
920            * everywhere...
921            */
922            if (IsZombie(member)) { /* don't kick ppl twice */
923                 member->status = member->status & ~mode;
924                 continue;
925            }
926
927            sendto_highprot_butone(0, 10, "%s " TOK_KICK " %s %s%s :Net Rider",
928             NumServ(&me), chptr->chname, NumNick(member->user));
929            sendto_channel_butserv(chptr, sptr,
930             ":%s KICK %s %s :Net Rider", me.name, chptr->chname,
931             member->user->name);
932
933            if (MyUser(member->user)) {
934              sendto_lowprot_butone(0, 9, ":%s PART %s",
935                member->user->name, chptr->chname, member->user->name);
936              sendto_highprot_butone(0, 10, "%s%s PART %s",
937                NumNick(member->user), chptr->chname);
938              remove_user_from_channel(member->user, chptr);
939            }
940            else {
941              member->status = (member->status & ~mode) | CHFL_ZOMBIE;
942            }
943            continue;
944         }
945 #endif /* defined(NO_INVITE_NETRIDE) */
946         if ((member->status & mode))
947         {
948           member->status &= ~mode;
949           if (mode == CHFL_CHANOP)
950             SetDeopped(member);
951           cancel_mode(sptr, chptr, m, member->user->name, &count);
952         }
953       }
954       if (mode == CHFL_VOICE)
955         break;
956       mode = CHFL_VOICE;
957       m = 'v';
958     }
959
960     /* And finally wipeout all bans that are left */
961     for (ban = &chptr->banlist; *ban; ) {
962       struct SLink* tmp = *ban;
963       if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT)) {
964         struct Membership* member_z;
965
966         *ban = tmp->next;
967         cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
968
969         /* Copied from del_banid(): */
970         MyFree(tmp->value.ban.banstr);
971         MyFree(tmp->value.ban.who);
972         free_link(tmp);
973
974         /* Erase ban-valid-bit, for channel members that are banned */
975         for (member_z = chptr->members; member_z; member_z = member_z->next_member)
976           if ((member_z->status & CHFL_BANVALIDMASK) == CHFL_BANVALIDMASK)
977             ClearBanValid(member_z);
978       }
979       else
980         ban = &tmp->next;
981     }
982     /* Also wipeout overlapped bans */
983     if (!add_banid_not_called)
984     {
985       struct SLink *ban;
986       while ((ban = next_removed_overlapped_ban()))
987         cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
988     }
989     cancel_mode(sptr, chptr, 0, 0, &count);  /* flush */
990   }
991
992   if (send_it && !netride)
993   {
994     struct SLink *bl;
995     int deban;
996
997     if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
998     {
999       deban = 0;
1000       bl = chptr->banlist;
1001       *modebuf = '+';
1002     }
1003     else
1004     {
1005       deban = 1;
1006       *modebuf = '-';
1007     }
1008
1009     mblen2 = 1;
1010     pblen2 = 0;
1011     cnt = 0;
1012     for (;;)
1013     {
1014       size_t nblen = 0;
1015       if (bl)
1016         nblen = strlen(bl->value.ban.banstr);
1017       if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN) /* The last check is to make sure
1018                                                                            that the receiving 2.9 will
1019                                                                            still process this */
1020       {
1021         /* Time to send buffer */
1022         modebuf[mblen2] = 0;
1023         sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
1024             parv[0], chptr->chname, modebuf, parabuf);
1025         *modebuf = deban ? '-' : '+';
1026         mblen2 = 1;
1027         pblen2 = 0;
1028         cnt = 0;
1029       }
1030       if (!bl)                  /* Done ? */
1031         break;
1032       if (deban || (bl->flags & CHFL_BURST_BAN))
1033       {
1034         /* Add ban to buffers and remove it */
1035         modebuf[mblen2++] = 'b';
1036         parabuf[pblen2++] = ' ';
1037         strcpy(parabuf + pblen2, bl->value.ban.banstr);
1038         pblen2 += nblen;
1039         cnt++;
1040         bl->flags &= ~CHFL_BURST_BAN;
1041       }
1042       if (deban)
1043       {
1044         if (!(bl = next_removed_overlapped_ban()))
1045         {
1046           deban = 0;
1047           modebuf[mblen2++] = '+';
1048           bl = chptr->banlist;
1049         }
1050       }
1051       else
1052         bl = bl->next;
1053     }
1054     /* Flush MODE [-b]+b ...: */
1055     if (cnt > 0 || mblen2 > 1)
1056     {
1057       modebuf[mblen2] = 0;
1058       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
1059           parv[0], chptr->chname, modebuf, parabuf);
1060     }
1061   }
1062   return 0;
1063 }
1064 #endif
1065
1066 #if 0
1067 /*
1068  * m_burst  --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
1069  *
1070  * parv[0] = sender prefix
1071  * parv[1] = channel name
1072  * parv[2] = channel timestamp
1073  * The meaning of the following parv[]'s depend on their first character:
1074  * If parv[n] starts with a '+':
1075  * Net burst, additive modes
1076  *   parv[n] = <mode>
1077  *   parv[n+1] = <param> (optional)
1078  *   parv[n+2] = <param> (optional)
1079  * If parv[n] starts with a '%', then n will be parc-1:
1080  *   parv[n] = %<ban> <ban> <ban> ...
1081  * If parv[n] starts with another character:
1082  *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
1083  *   where <mode> is the channel mode (ov) of nick and all following nicks.
1084  *
1085  * Example:
1086  * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
1087  *
1088  * Anti net.ride code.
1089  *
1090  * When the channel already exist, and its TS is larger then
1091  * the TS in the BURST message, then we cancel all existing modes.
1092  * If its is smaller then the received BURST message is ignored.
1093  * If it's equal, then the received modes are just added.
1094  */
1095 int m_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1096 {
1097   struct Channel* chptr;
1098   time_t          timestamp;
1099   int             netride = 0;
1100   int             wipeout = 0;
1101   int             n;
1102   int             send_it = 0;
1103   int             add_banid_not_called = 1;
1104   struct Mode*    current_mode;
1105   size_t          sblen;
1106   size_t          mblen = 0;
1107   int             mblen2;
1108   int             pblen2;
1109   int             cnt;
1110   int             prev_mode;
1111   char            prev_key[KEYLEN + 1];
1112   struct Membership* member;
1113   struct SLink*   lp;
1114   char modebuf[MODEBUFLEN];
1115   char parabuf[MODEBUFLEN];
1116   char bmodebuf[MODEBUFLEN];
1117   char bparambuf[MODEBUFLEN];
1118
1119   /* BURST is only for servers and has at least 4 parameters */
1120   if (!IsServer(cptr) || parc < 4)
1121     return 0;
1122
1123   if (!IsBurst(sptr))
1124   {
1125     int i;
1126     char *p;
1127     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
1128     {
1129       p =
1130           sprintf_irc(sendbuf,
1131           ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
1132           sptr->name, parv[1], parv[2]);
1133       for (i = 3; i < parc - 1; ++i)
1134         p = sprintf_irc(p, " %s", parv[i]);
1135       sprintf_irc(p, " :%s", parv[parc - 1]);
1136       sendbufto_op_mask(SNO_HACK4);
1137     }
1138     else
1139     {
1140 #if 1                           /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
1141       SetBurst(sptr);
1142       if (MyConnect(sptr))
1143 #endif
1144         return exit_client_msg(cptr, cptr, &me,
1145             "HACK: BURST message outside net.burst from %s", sptr->name);
1146     }
1147   }
1148
1149   /* Find the channel, or create it - note that the creation time
1150    * will be 0 if it has to be created */
1151   chptr = get_channel(sptr, parv[1], CGT_CREATE);
1152   current_mode = &chptr->mode;
1153   prev_mode = chptr->mode.mode;
1154   if (*chptr->mode.key)
1155   {
1156     prev_mode |= MODE_KEY;
1157     strcpy(prev_key, chptr->mode.key);
1158   }
1159   if (chptr->mode.limit)
1160     prev_mode |= MODE_LIMIT;
1161
1162   timestamp = atoi(parv[2]);
1163
1164   /* Copy the new TS when the received creationtime appears to be older */
1165   if (!chptr->creationtime || chptr->creationtime > timestamp)
1166   {
1167     /* Set the new timestamp */
1168     chptr->creationtime = timestamp;
1169     send_it = 1;                /* Make sure we pass on the different timestamp ! */
1170     /* Mark all bans as needed to be wiped out */
1171     for (lp = chptr->banlist; lp; lp = lp->next)
1172       lp->flags |= CHFL_BURST_BAN_WIPEOUT;
1173     /*
1174      * Only the first BURST for this channel can have creationtime > timestamp,
1175      * so at this moment ALL members are on OUR side, and thus all net.riders:
1176      */
1177     wipeout = 1;
1178   }
1179   for (member = chptr->members; member; member = member->next_member)
1180     member->status &= ~CHFL_BURST_JOINED;    /* Set later for nicks in the BURST msg */
1181   /* If `wipeout' is set then these will be deopped later. */
1182
1183   /* If the entering creationtime is younger, ignore the modes */
1184   if (chptr->creationtime < timestamp)
1185     netride = 1;                /* Only pass on the nicks (so they JOIN) */
1186
1187   /* Prepare buffers to pass the message */
1188   *bparambuf = *bmodebuf = *parabuf = '\0';
1189   pblen2 = 0;
1190   *modebuf = '+';
1191   mblen2 = 1;
1192   cnt = 0;
1193   sblen = sprintf_irc(sendbuf, "%s B %s " TIME_T_FMT,
1194       NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
1195
1196   /* Run over all remaining parameters */
1197   for (n = 3; n < parc; n++)
1198     switch (*parv[n])           /* What type is it ? mode, nicks or bans ? */
1199     {
1200       case '+':         /* modes */
1201       {
1202         char *p = parv[n];
1203         while (*(++p))          /* Run over all mode characters */
1204         {
1205           switch (*p)           /* which mode ? */
1206           {
1207               /*
1208                * The following cases all do the following:
1209                * - In case wipeout needed, reset 'prev_mode' to indicate this
1210                *   mode should not be cancelled.
1211                * - If wipeout or (not netride and the new mode is a change),
1212                *   add it to bmodebuf and bparabuf for propagation.
1213                * - Else ignore it.
1214                * - Add it to modebuf and parabuf for propagation to the
1215                *   clients when not netride and the new mode is a change.
1216                * Special cases:
1217                * - If a +s is received, cancel a +p and sent a -p to the
1218                *   clients too (if +p was set).
1219                * - If a +p is received and +s is set, ignore the +p.
1220                */
1221             case 'i':
1222             {
1223               int tmp;
1224               prev_mode &= ~MODE_INVITEONLY;
1225               if (!(tmp = netride ||
1226                   (current_mode->mode & MODE_INVITEONLY)) || wipeout)
1227               {
1228                 bmodebuf[mblen++] = 'i';
1229                 current_mode->mode |= MODE_INVITEONLY;
1230               }
1231               if (!tmp)
1232                 modebuf[mblen2++] = 'i';
1233               break;
1234             }
1235             case 'k':
1236             {
1237               int tmp;
1238               char *param = parv[++n];
1239               prev_mode &= ~MODE_KEY;
1240               if (!(tmp = netride || (*current_mode->key &&
1241                   (!strcmp(current_mode->key, param) ||
1242                   (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
1243                   wipeout)
1244               {
1245                 bmodebuf[mblen++] = 'k';
1246                 strcat(bparambuf, " ");
1247                 strcat(bparambuf, param);
1248                 ircd_strncpy(current_mode->key, param, KEYLEN);
1249               }
1250               if (!tmp && !wipeout)
1251               {
1252                 modebuf[mblen2++] = 'k';
1253                 parabuf[pblen2++] = ' ';
1254                 strcpy(parabuf + pblen2, param);
1255                 pblen2 += strlen(param);
1256                 cnt++;
1257               }
1258               break;
1259             }
1260             case 'l':
1261             {
1262               int tmp;
1263               unsigned int param = atoi(parv[++n]);
1264               prev_mode &= ~MODE_LIMIT;
1265               if (!(tmp = netride || (current_mode->limit &&
1266                   (current_mode->limit == param ||
1267                   (!wipeout && current_mode->limit < param)))) || wipeout)
1268               {
1269                 bmodebuf[mblen++] = 'l';
1270                 sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
1271                 current_mode->limit = param;
1272               }
1273               if (!tmp)
1274               {
1275                 modebuf[mblen2++] = 'l';
1276                 pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
1277                 cnt++;
1278               }
1279               break;
1280             }
1281             case 'm':
1282             {
1283               int tmp;
1284               prev_mode &= ~MODE_MODERATED;
1285               if (!(tmp = netride ||
1286                   (current_mode->mode & MODE_MODERATED)) || wipeout)
1287               {
1288                 bmodebuf[mblen++] = 'm';
1289                 current_mode->mode |= MODE_MODERATED;
1290               }
1291               if (!tmp)
1292                 modebuf[mblen2++] = 'm';
1293               break;
1294             }
1295             case 'n':
1296             {
1297               int tmp;
1298               prev_mode &= ~MODE_NOPRIVMSGS;
1299               if (!(tmp = netride ||
1300                   (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
1301               {
1302                 bmodebuf[mblen++] = 'n';
1303                 current_mode->mode |= MODE_NOPRIVMSGS;
1304               }
1305               if (!tmp)
1306                 modebuf[mblen2++] = 'n';
1307               break;
1308             }
1309             case 'p':
1310             {
1311               int tmp;
1312
1313               /* Special case: */
1314               if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
1315                 break;
1316
1317               prev_mode &= ~MODE_PRIVATE;
1318               if (!(tmp = netride ||
1319                   (current_mode->mode & MODE_PRIVATE)) || wipeout)
1320               {
1321                 bmodebuf[mblen++] = 'p';
1322                 current_mode->mode |= MODE_PRIVATE;
1323               }
1324               if (!tmp)
1325                 modebuf[mblen2++] = 'p';
1326               break;
1327             }
1328             case 's':
1329             {
1330               int tmp;
1331               prev_mode &= ~MODE_SECRET;
1332               if (!(tmp = netride ||
1333                   (current_mode->mode & MODE_SECRET)) || wipeout)
1334               {
1335                 bmodebuf[mblen++] = 's';
1336                 current_mode->mode |= MODE_SECRET;
1337               }
1338               if (!tmp)
1339                 modebuf[mblen2++] = 's';
1340
1341               /* Special case: */
1342               if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
1343               {
1344                 int i;
1345                 for (i = mblen2 - 1; i >= 0; --i)
1346                   modebuf[i + 2] = modebuf[i];
1347                 modebuf[0] = '-';
1348                 modebuf[1] = 'p';
1349                 mblen2 += 2;
1350                 current_mode->mode &= ~MODE_PRIVATE;
1351               }
1352
1353               break;
1354             }
1355             case 't':
1356             {
1357               int tmp;
1358               prev_mode &= ~MODE_TOPICLIMIT;
1359               if (!(tmp = netride ||
1360                   (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
1361               {
1362                 bmodebuf[mblen++] = 't';
1363                 current_mode->mode |= MODE_TOPICLIMIT;
1364               }
1365               if (!tmp)
1366                 modebuf[mblen2++] = 't';
1367               break;
1368             }
1369           }
1370         }                       /* <-- while over all modes */
1371
1372         bmodebuf[mblen] = '\0';
1373         sendbuf[sblen] = '\0';
1374         if (mblen)              /* Anything to send at all ? */
1375         {
1376           send_it = 1;
1377           strcpy(sendbuf + sblen, " +");
1378           sblen += 2;
1379           strcpy(sendbuf + sblen, bmodebuf);
1380           sblen += mblen;
1381           strcpy(sendbuf + sblen, bparambuf);
1382           sblen += strlen(bparambuf);
1383         }
1384         break;                  /* Done mode part */
1385       }
1386       case '%':         /* bans */
1387       {
1388         char *pv, *p = 0, *ban;
1389         int first = 1;
1390         if (netride)
1391           break;                /* Ignore bans */
1392         /* Run over all bans */
1393         for (pv = parv[n] + 1; (ban = ircd_strtok(&p, pv, " ")); pv = 0)
1394         {
1395           int ret;
1396           /*
1397            * The following part should do the following:
1398            * - If the new (un)ban is not a _change_ it is ignored.
1399            * - Else, add it to sendbuf for later use.
1400            * - If sendbuf is full, send it, and prepare a new
1401            *   message in sendbuf.
1402            */
1403           ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
1404           if (ret == 0)
1405           {
1406             add_banid_not_called = 0;
1407             /* Mark this new ban so we can send it to the clients later */
1408             chptr->banlist->flags |= CHFL_BURST_BAN;
1409           }
1410           if (ret != -1)
1411             /* A new ban was added or an existing one needs to be passed on.
1412              * Also add it to sendbuf: */
1413             add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
1414         }
1415         break;                  /* Done bans part */
1416       }
1417       default:                  /* nicks */
1418       {
1419         char *pv, *p = 0, *nick, *ptr;
1420         int first = 1;
1421         /* Default mode: */
1422         int default_mode = CHFL_DEOPPED;
1423         /* Run over all nicks */
1424         for (pv = parv[n]; (nick = ircd_strtok(&p, pv, ",")); pv = 0)
1425         {
1426           struct Client *acptr;
1427           if ((ptr = strchr(nick, ':')))        /* New default mode ? */
1428           {
1429             *ptr = '\0';        /* Fix 'nick' */
1430             acptr = findNUser(nick);
1431             if (!netride)
1432             {
1433               /* Calculate new mode change: */
1434               default_mode = CHFL_DEOPPED;
1435               while (*(++ptr))
1436                 if (*ptr == 'o')
1437                 {
1438                   default_mode |= CHFL_CHANOP;
1439                   default_mode &= ~CHFL_DEOPPED;
1440                 }
1441                 else if (*ptr == 'v')
1442                   default_mode |= CHFL_VOICE;
1443                 else
1444                   break;
1445             }
1446           }
1447           else
1448             acptr = findNUser(nick);
1449           /*
1450            * Note that at this point we already received a 'NICK' for any
1451            * <nick> numeric that is joining (and possibly opped) here.
1452            * Therefore we consider the following situations:
1453            * - The <nick> numeric exists and is from the direction of cptr: ok
1454            * - The <nick> numeric does not exist:
1455            *   Apparently this previous <nick> numeric was killed (upstream)
1456            *   or it collided with an existing <nick> name.
1457            * - The <nick> numeric exists but is from another direction:
1458            *   Apparently this previous <nick> numeric was killed,
1459            *   and due to a reroute it signed on via another link (probably
1460            *   a nick [numeric] collision).
1461            * Note that it can't be a QUIT or SQUIT, because a QUIT would
1462            * come from the same direction as the BURST (cptr) while an
1463            * upstream SQUIT removes the source (server) and we would thus
1464            * have this BURST ignored already.
1465            * This means that if we find the nick and it is from the correct
1466            * direction, it joins. If it doesn't exist or is from another
1467            * direction, we have to ignore it. If all nicks are ignored, we
1468            * remove the channel again when it is empty and don't propagate
1469            * the BURST message.
1470            */
1471           if (acptr && acptr->from == cptr)
1472           {
1473             /*
1474              * The following should do the following:
1475              * - Add it to sendbuf for later use.
1476              * - If sendbuf is full, send it, and prepare a new
1477              *   message in sendbuf.
1478              */
1479             add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
1480                 default_mode);
1481             /* Let is take effect: (Note that in the case of a netride
1482              * 'default_mode' is always CHFL_DEOPPED here). */
1483             add_user_to_channel(chptr, acptr, default_mode | CHFL_BURST_JOINED);
1484           }
1485         }                       /* <-- Next nick */
1486         if (!chptr->members)    /* All nicks collided and channel is empty ? */
1487         {
1488           sub1_from_channel(chptr);
1489           return 0;             /* Forget about the (rest of the) message... */
1490         }
1491         break;                  /* Done nicks part */
1492       }
1493     }                           /* <-- Next parameter if any */
1494   if (!chptr->members)          /* This message only contained bans (then the previous
1495                                    message only contained collided nicks, see above) */
1496   {
1497     sub1_from_channel(chptr);
1498     if (!add_banid_not_called)
1499       while (next_removed_overlapped_ban());
1500     return 0;                   /* Forget about the (rest of the) message... */
1501   }
1502
1503   /* The last (possibly only) message is always send here */
1504   if (send_it)                  /* Anything (left) to send ? */
1505   {
1506     struct DLink *lp;
1507     struct Membership* member;
1508
1509     /* send 'sendbuf' to all downlinks */
1510     for (lp = me.serv->down; lp; lp = lp->next)
1511     {
1512       if (lp->value.cptr == cptr)
1513         continue;
1514       if (Protocol(lp->value.cptr) > 9)
1515         sendbufto_one(lp->value.cptr);
1516     }
1517
1518     /*
1519      * Now we finally can screw sendbuf again...
1520      * Send all changes to the local clients:
1521      *
1522      * First send all joins and op them, because 2.9 servers
1523      * would protest with a HACK if we first de-opped people.
1524      * However, we don't send the +b bans yes, because we
1525      * DO first want to -b the old bans (otherwise it's confusing).
1526      */
1527
1528     /* Send all joins: */
1529     for (member = chptr->members; member; member = member->next_member)
1530       if (IsBurstJoined(member))
1531       {
1532         sendto_channel_butserv(chptr, member->user, ":%s JOIN :%s",
1533                                member->user->name, chptr->chname);
1534       }
1535
1536     if (!netride)
1537     {
1538       /* Send all +o and +v modes: */
1539       for (member = chptr->members; member; member = member->next_member)
1540       {
1541         if (IsBurstJoined(member))
1542         {
1543           int mode = CHFL_CHANOP;
1544           for (;;)
1545           {
1546             if ((member->status & mode))
1547             {
1548               modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
1549               parabuf[pblen2++] = ' ';
1550               strcpy(parabuf + pblen2, member->user->name);
1551               pblen2 += strlen(member->user->name);
1552               if (6 == ++cnt)
1553               {
1554                 modebuf[mblen2] = 0;
1555                 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
1556                     parv[0], chptr->chname, modebuf, parabuf);
1557                 *parabuf = 0;
1558                 pblen2 = 0;
1559                 mblen2 = 1;
1560                 cnt = 0;
1561               }
1562             }
1563             if (mode == CHFL_CHANOP)
1564               mode = CHFL_VOICE;
1565             else
1566               break;
1567           }
1568         }
1569       }
1570       /* Flush MODEs: */
1571       if (cnt > 0 || mblen2 > 1)
1572       {
1573         modebuf[mblen2] = 0;
1574         sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
1575             parv[0], chptr->chname, modebuf, parabuf);
1576       }
1577     }
1578   }
1579
1580   if (wipeout)
1581   {
1582     struct Membership* member;
1583     struct SLink**     ban;
1584     int                mode;
1585     char               m;
1586     int                count = -1;
1587
1588     /* Now cancel all previous simple modes */
1589     if ((prev_mode & MODE_SECRET))
1590       cancel_mode(sptr, chptr, 's', 0, &count);
1591     if ((prev_mode & MODE_PRIVATE))
1592       cancel_mode(sptr, chptr, 'p', 0, &count);
1593     if ((prev_mode & MODE_MODERATED))
1594       cancel_mode(sptr, chptr, 'm', 0, &count);
1595     if ((prev_mode & MODE_TOPICLIMIT))
1596       cancel_mode(sptr, chptr, 't', 0, &count);
1597     if ((prev_mode & MODE_INVITEONLY))
1598       cancel_mode(sptr, chptr, 'i', 0, &count);
1599     if ((prev_mode & MODE_NOPRIVMSGS))
1600       cancel_mode(sptr, chptr, 'n', 0, &count);
1601     if ((prev_mode & MODE_LIMIT))
1602     {
1603       current_mode->limit = 0;
1604       cancel_mode(sptr, chptr, 'l', 0, &count);
1605     }
1606     if ((prev_mode & MODE_KEY))
1607     {
1608       *current_mode->key = 0;
1609       cancel_mode(sptr, chptr, 'k', prev_key, &count);
1610     }
1611     current_mode->mode &= ~prev_mode;
1612
1613     /* And deop and devoice all net.riders on my side */
1614     mode = CHFL_CHANOP;
1615     m = 'o';
1616     for (;;)
1617     {
1618       struct Membership* member_next = 0;
1619
1620       for (member = chptr->members; member; member = member_next)
1621       {
1622         member_next = member->next_member;
1623         if (IsBurstJoined(member))
1624           continue;             /* This is not a net.rider from
1625                                    this side of the net.junction */
1626 #if defined(NO_INVITE_NETRIDE)
1627         /*
1628          * Kick net riding users from invite only channels.
1629          *  - Isomer 25-11-1999
1630          */
1631         if (chptr->mode.mode & MODE_INVITEONLY) {
1632           /* kick is magical - lotsa zombies and other undead.
1633            * I'm hoping this is the right idea, comments anyone?
1634            * Set everyone to a zombie, remove ops, and then send kicks
1635            * everywhere...
1636            */
1637            if (IsZombie(member)) { /* don't kick ppl twice */
1638                 member->status = member->status & ~mode;
1639                 continue;
1640            }
1641            member->status = (member->status & ~mode) | CHFL_ZOMBIE;
1642
1643            sendto_highprot_butone(0, 10, "%s " TOK_KICK "%s %s%s :Net Rider",
1644             NumServ(&me), chptr->chname, NumNick(member->user));
1645            sendto_channel_butserv(chptr, sptr,
1646             ":%s KICK %s %s :Net Rider", me.name, chptr->chname,
1647             member->user->name);
1648
1649            if (MyUser(member->user)) {
1650              sendto_lowprot_butone(0, 9, ":%s PART %s",
1651                member->user->name, chptr->chname, member->user->name);
1652              sendto_highprot_butone(0, 10, "%s%s PART %s",
1653                NumNick(member->user), chptr->chname);
1654              remove_user_from_channel(member->user, chptr);
1655            }
1656            else {
1657              member->status = (member->status & ~mode) | CHFL_ZOMBIE;
1658            }
1659            continue;
1660         }
1661 #endif /* defined(NO_INVITE_NETRIDE) */
1662         if ((member->status & mode))
1663         {
1664           member->status &= ~mode;
1665           if (mode == CHFL_CHANOP)
1666             SetDeopped(member);
1667           cancel_mode(sptr, chptr, m, member->user->name, &count);
1668         }
1669       }
1670       if (mode == CHFL_VOICE)
1671         break;
1672       mode = CHFL_VOICE;
1673       m = 'v';
1674     }
1675
1676     /* And finally wipeout all bans that are left */
1677     for (ban = &chptr->banlist; *ban; ) {
1678       struct SLink* tmp = *ban;
1679       if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT)) {
1680         struct Membership* member_z;
1681
1682         *ban = tmp->next;
1683         cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
1684
1685         /* Copied from del_banid(): */
1686         MyFree(tmp->value.ban.banstr);
1687         MyFree(tmp->value.ban.who);
1688         free_link(tmp);
1689
1690         /* Erase ban-valid-bit, for channel members that are banned */
1691         for (member_z = chptr->members; member_z; member_z = member_z->next_member)
1692           if ((member_z->status & CHFL_BANVALIDMASK) == CHFL_BANVALIDMASK)
1693             ClearBanValid(member_z);
1694       }
1695       else
1696         ban = &tmp->next;
1697     }
1698     /* Also wipeout overlapped bans */
1699     if (!add_banid_not_called)
1700     {
1701       struct SLink *ban;
1702       while ((ban = next_removed_overlapped_ban()))
1703         cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
1704     }
1705     cancel_mode(sptr, chptr, 0, 0, &count);  /* flush */
1706   }
1707
1708   if (send_it && !netride)
1709   {
1710     struct SLink *bl;
1711     int deban;
1712
1713     if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
1714     {
1715       deban = 0;
1716       bl = chptr->banlist;
1717       *modebuf = '+';
1718     }
1719     else
1720     {
1721       deban = 1;
1722       *modebuf = '-';
1723     }
1724
1725     mblen2 = 1;
1726     pblen2 = 0;
1727     cnt = 0;
1728     for (;;)
1729     {
1730       size_t nblen = 0;
1731       if (bl)
1732         nblen = strlen(bl->value.ban.banstr);
1733       if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN) /* The last check is to make sure
1734                                                                            that the receiving 2.9 will
1735                                                                            still process this */
1736       {
1737         /* Time to send buffer */
1738         modebuf[mblen2] = 0;
1739         sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
1740             parv[0], chptr->chname, modebuf, parabuf);
1741         *modebuf = deban ? '-' : '+';
1742         mblen2 = 1;
1743         pblen2 = 0;
1744         cnt = 0;
1745       }
1746       if (!bl)                  /* Done ? */
1747         break;
1748       if (deban || (bl->flags & CHFL_BURST_BAN))
1749       {
1750         /* Add ban to buffers and remove it */
1751         modebuf[mblen2++] = 'b';
1752         parabuf[pblen2++] = ' ';
1753         strcpy(parabuf + pblen2, bl->value.ban.banstr);
1754         pblen2 += nblen;
1755         cnt++;
1756         bl->flags &= ~CHFL_BURST_BAN;
1757       }
1758       if (deban)
1759       {
1760         if (!(bl = next_removed_overlapped_ban()))
1761         {
1762           deban = 0;
1763           modebuf[mblen2++] = '+';
1764           bl = chptr->banlist;
1765         }
1766       }
1767       else
1768         bl = bl->next;
1769     }
1770     /* Flush MODE [-b]+b ...: */
1771     if (cnt > 0 || mblen2 > 1)
1772     {
1773       modebuf[mblen2] = 0;
1774       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
1775           parv[0], chptr->chname, modebuf, parabuf);
1776     }
1777   }
1778
1779   return 0;
1780 }
1781 #endif /* 0 */
1782