Revert r1340 (it was apparently always buggy).
[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 #include "config.h"
83
84 #include "channel.h"
85 #include "client.h"
86 #include "hash.h"
87 #include "ircd.h"
88 #include "ircd_alloc.h"
89 #include "ircd_features.h"
90 #include "ircd_log.h"
91 #include "ircd_reply.h"
92 #include "ircd_string.h"
93 #include "list.h"
94 #include "match.h"
95 #include "msg.h"
96 #include "numeric.h"
97 #include "numnicks.h"
98 #include "s_conf.h"
99 #include "s_misc.h"
100 #include "send.h"
101 #include "struct.h"
102 #include "ircd_snprintf.h"
103
104 /* #include <assert.h> -- Now using assert in ircd_log.h */
105 #include <stdlib.h>
106 #include <string.h>
107 #include <ctype.h>
108
109 static int
110 netride_modes(int parc, char **parv, const char *curr_key)
111 {
112   char *modes = parv[0];
113   int result = 0;
114
115   assert(modes && modes[0] == '+');
116   while (*modes) {
117     switch (*modes++) {
118     case '-':
119       return -1;
120     case 'i':
121       result |= MODE_INVITEONLY;
122       break;
123     case 'k':
124       if (strcmp(curr_key, *++parv))
125         result |= MODE_KEY;
126       break;
127     case 'l':
128       ++parv;
129       break;
130     case 'r':
131       result |= MODE_REGONLY;
132       break;
133     }
134   }
135   return result;
136 }
137
138 /*
139  * ms_burst - server message handler
140  *
141  * --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
142  *
143  * parv[0] = sender prefix
144  * parv[1] = channel name
145  * parv[2] = channel timestamp
146  * The meaning of the following parv[]'s depend on their first character:
147  * If parv[n] starts with a '+':
148  * Net burst, additive modes
149  *   parv[n] = <mode>
150  *   parv[n+1] = <param> (optional)
151  *   parv[n+2] = <param> (optional)
152  * If parv[n] starts with a '%', then n will be parc-1:
153  *   parv[n] = %<ban> <ban> <ban> ...
154  * If parv[n] starts with another character:
155  *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
156  *   where <mode> defines the mode and op-level
157  *   for nick and all following nicks until the
158  *   next <mode> field.
159  *   Digits in the <mode> field have of two meanings:
160  *   1) if it is the first field in this BURST message
161  *      that contains digits, and/or when a 'v' is
162  *      present in the <mode>:
163  *      The absolute value of the op-level.
164  *   2) if there are only digits in this field and
165  *      it is not the first field with digits:
166  *      An op-level increment relative to the previous
167  *      op-level.
168  *   First all modeless nicks must be emmitted,
169  *   then all combinations of modes without ops
170  *   (currently that is only 'v') followed by the same
171  *   series but then with ops (currently 'o','ov').
172  *
173  * Example:
174  * "A8 B #test 87654321 +ntkAl key secret 123 A8AAG,A8AAC:v,A8AAA:0,A8AAF:2,A8AAD,A8AAB:v1,A8AAE:1 :%ban1 ban2"
175  *
176  * <mode> list example:
177  *
178  * "xxx,sss:v,ttt,aaa:123,bbb,ccc:2,ddd,kkk:v2,lll:2,mmm"
179  *
180  * means
181  *
182  *  xxx         // first modeless nicks
183  *  sss +v      // then opless nicks
184  *  ttt +v      // no ":<mode>": everything stays the same
185  *  aaa -123    // first field with digit: absolute value
186  *  bbb -123
187  *  ccc -125    // only digits, not first field: increment
188  *  ddd -125
189  *  kkk -2 +v   // field with a 'v': absolute value
190  *  lll -4 +v   // only digits: increment
191  *  mmm -4 +v
192  *
193  * Anti net.ride code.
194  *
195  * When the channel already exist, and its TS is larger than
196  * the TS in the BURST message, then we cancel all existing modes.
197  * If its is smaller then the received BURST message is ignored.
198  * If it's equal, then the received modes are just added.
199  *
200  * BURST is also accepted outside a netburst now because it
201  * is sent upstream as reaction to a DESTRUCT message.  For
202  * these BURST messages it is possible that the listed channel
203  * members are already joined.
204  */
205 int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
206 {
207   struct ModeBuf modebuf, *mbuf = 0;
208   struct Channel *chptr;
209   time_t timestamp;
210   struct Membership *member, *nmember;
211   struct Ban *lp, **lp_p;
212   unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST);
213   int param, nickpos = 0, banpos = 0;
214   char modestr[BUFSIZE], nickstr[BUFSIZE], banstr[BUFSIZE];
215
216   if (parc < 3)
217     return protocol_violation(sptr,"Too few parameters for BURST");
218
219   if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
220     return 0; /* can't create the channel? */
221
222   timestamp = atoi(parv[2]);
223
224   if (chptr->creationtime)      /* 0 for new (empty) channels,
225                                    i.e. when this server just restarted. */
226   {
227     if (parc == 3)              /* Zannel BURST? */
228     {
229       /* An empty channel without +A set, will cause a BURST message
230          with exactly 3 parameters (because all modes have been reset).
231          If the timestamp on such channels is only a few seconds older
232          from our own, then we ignore this burst: we do not deop our
233          own side.
234          Likewise, we expect the other (empty) side to copy our timestamp
235          from our own BURST message, even though it is slightly larger.
236
237          The reason for this is to allow people to join an empty
238          non-A channel (a zannel) during a net.split, and not be
239          deopped when the net reconnects (with another zannel). When
240          someone joins a split zannel, their side increments the TS by one.
241          If they cycle a few times then we still don't have a reason to
242          deop them. Theoretically I see no reason not to accept ANY timestamp,
243          but to be sure, we only accept timestamps that are just a few
244          seconds off (one second for each time they cycled the channel). */
245
246       /* Don't even deop users who cycled four times during the net.break. */
247       if (timestamp < chptr->creationtime &&
248           chptr->creationtime <= timestamp + 4 &&
249           chptr->users != 0)    /* Only do this when WE have users, so that
250                                    if we do this the BURST that we sent has
251                                    parc > 3 and the other side will use the
252                                    test below: */
253         timestamp = chptr->creationtime; /* Do not deop our side. */
254     }
255     else if (chptr->creationtime < timestamp &&
256              timestamp <= chptr->creationtime + 4 &&
257              chptr->users == 0)
258     {
259       /* If one side of the net.junction does the above
260          timestamp = chptr->creationtime, then the other
261          side must do this: */
262       chptr->creationtime = timestamp;  /* Use the same TS on both sides. */
263     }
264     /* In more complex cases, we might still end up with a
265        creationtime desync of a few seconds, but that should
266        be synced automatically rather quickly (every JOIN
267        caries a timestamp and will sync it; modes by users do
268        not carry timestamps and are accepted regardless).
269        Only when nobody joins the channel on the side with
270        the oldest timestamp before a new net.break occurs
271        precisely inbetween the desync, an unexpected bounce
272        might happen on reconnect. */
273   }
274
275   if (!chptr->creationtime || chptr->creationtime > timestamp) {
276     /*
277      * Kick local members if channel is +i or +k and our TS was larger
278      * than the burst TS (anti net.ride). The modes hack is here because
279      * we have to do this before mode_parse, as chptr may go away.
280      */
281     for (param = 3; param < parc; param++)
282     {
283       int check_modes;
284       if (parv[param][0] != '+')
285         continue;
286       check_modes = netride_modes(parc - param, parv + param, chptr->mode.key);
287       if (check_modes < 0)
288       {
289         if (chptr->users == 0)
290           sub1_from_channel(chptr);
291         return protocol_violation(sptr, "Invalid mode string in BURST");
292       }
293       else if (check_modes)
294       {
295         /* Clear any outstanding rogue invites */
296         mode_invite_clear(chptr);
297         for (member = chptr->members; member; member = nmember)
298         {
299           nmember = member->next_member;
300           if (!MyUser(member->user) || IsZombie(member))
301             continue;
302           /* Kick as netrider if key mismatch *or* remote channel is
303            * +i (unless user is an oper) *or* remote channel is +r
304            * (unless user has an account).
305            */
306           if (!(check_modes & MODE_KEY)
307               && (!(check_modes & MODE_INVITEONLY) || IsAnOper(member->user))
308               && (!(check_modes & MODE_REGONLY) || IsAccount(member->user)))
309             continue;
310           sendcmdto_serv_butone(&me, CMD_KICK, NULL, "%H %C :Net Rider", chptr, member->user);
311           sendcmdto_channel_butserv_butone(&his, CMD_KICK, chptr, NULL, 0, "%H %C :Net Rider", chptr, member->user);
312           make_zombie(member, member->user, &me, &me, chptr);
313         }
314       }
315       break;
316     }
317
318     /* If the channel had only locals, it went away by now. */
319     if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE)))
320       return 0; /* can't create the channel? */
321   }
322
323   /* turn off burst joined flag */
324   for (member = chptr->members; member; member = member->next_member)
325     member->status &= ~(CHFL_BURST_JOINED|CHFL_BURST_ALREADY_OPPED|CHFL_BURST_ALREADY_VOICED);
326
327   if (!chptr->creationtime) /* mark channel as created during BURST */
328     chptr->mode.mode |= MODE_BURSTADDED;
329
330   /* new channel or an older one */
331   if (!chptr->creationtime || chptr->creationtime > timestamp) {
332     chptr->creationtime = timestamp;
333
334     modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
335                  MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
336     modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */
337     chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS;
338
339     /* wipeout any limit and keys that are set */
340     parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT);
341
342     /* mark bans for wipeout */
343     for (lp = chptr->banlist; lp; lp = lp->next)
344       lp->flags |= BAN_BURST_WIPEOUT;
345
346     /* clear topic set by netrider (if set) */
347     if (*chptr->topic) {
348       *chptr->topic = '\0';
349       *chptr->topic_nick = '\0';
350       chptr->topic_time = 0;
351       sendcmdto_channel_butserv_butone(&his, CMD_TOPIC, chptr, NULL, 0,
352                                        "%H :%s", chptr, chptr->topic);
353     }
354   } else if (chptr->creationtime == timestamp) {
355     modebuf_init(mbuf = &modebuf, &me, cptr, chptr,
356                  MODEBUF_DEST_CHANNEL | MODEBUF_DEST_NOKEY);
357
358     parse_flags |= MODE_PARSE_SET; /* set new modes */
359   }
360
361   param = 3; /* parse parameters */
362   while (param < parc) {
363     switch (*parv[param]) {
364     case '+': /* parameter introduces a mode string */
365       param += mode_parse(mbuf, cptr, sptr, chptr, parc - param,
366                           parv + param, parse_flags, NULL);
367       break;
368
369     case '%': /* parameter contains bans */
370       if (parse_flags & MODE_PARSE_SET) {
371         char *banlist = parv[param] + 1, *p = 0, *ban, *ptr;
372         struct Ban *newban;
373
374         for (ban = ircd_strtok(&p, banlist, " "); ban;
375              ban = ircd_strtok(&p, 0, " ")) {
376           ban = collapse(pretty_mask(ban));
377
378             /*
379              * Yeah, we should probably do this elsewhere, and make it better
380              * and more general; this will hold until we get there, though.
381              * I dislike the current add_banid API... -Kev
382              *
383              * I wish there were a better algo. for this than the n^2 one
384              * shown below *sigh*
385              */
386           for (lp = chptr->banlist; lp; lp = lp->next) {
387             if (!ircd_strcmp(lp->banstr, ban)) {
388               ban = 0; /* don't add ban */
389               lp->flags &= ~BAN_BURST_WIPEOUT; /* not wiping out */
390               break; /* new ban already existed; don't even repropagate */
391             } else if (!(lp->flags & BAN_BURST_WIPEOUT) &&
392                        !mmatch(lp->banstr, ban)) {
393               ban = 0; /* don't add ban unless wiping out bans */
394               break; /* new ban is encompassed by an existing one; drop */
395             } else if (!mmatch(ban, lp->banstr))
396               lp->flags |= BAN_OVERLAPPED; /* remove overlapping ban */
397
398             if (!lp->next)
399               break;
400           }
401
402           if (ban) { /* add the new ban to the end of the list */
403             /* Build ban buffer */
404             if (!banpos) {
405               banstr[banpos++] = ' ';
406               banstr[banpos++] = ':';
407               banstr[banpos++] = '%';
408             } else
409               banstr[banpos++] = ' ';
410             for (ptr = ban; *ptr; ptr++) /* add ban to buffer */
411               banstr[banpos++] = *ptr;
412
413             newban = make_ban(ban); /* create new ban */
414             strcpy(newban->who, "*");
415             newban->when = TStime();
416             newban->flags |= BAN_BURSTED;
417             newban->next = 0;
418             if (lp)
419               lp->next = newban; /* link it in */
420             else
421               chptr->banlist = newban;
422           }
423         }
424       } 
425       param++; /* look at next param */
426       break;
427
428     default: /* parameter contains clients */
429       {
430         struct Client *acptr;
431         char *nicklist = parv[param], *p = 0, *nick, *ptr;
432         int current_mode, last_mode, base_mode;
433         int oplevel = -1;       /* Mark first field with digits: means the same as 'o' (but with level). */
434         int last_oplevel = 0;
435         struct Membership* member;
436
437         base_mode = CHFL_DEOPPED | CHFL_BURST_JOINED;
438         if (chptr->mode.mode & MODE_DELJOINS)
439             base_mode |= CHFL_DELAYED;
440         current_mode = last_mode = base_mode;
441
442         for (nick = ircd_strtok(&p, nicklist, ","); nick;
443              nick = ircd_strtok(&p, 0, ",")) {
444
445           if ((ptr = strchr(nick, ':'))) { /* new flags; deal */
446             *ptr++ = '\0';
447
448             if (parse_flags & MODE_PARSE_SET) {
449               int current_mode_needs_reset;
450               for (current_mode_needs_reset = 1; *ptr; ptr++) {
451                 if (*ptr == 'o') { /* has oper status */
452                   /*
453                    * An 'o' is pre-oplevel protocol, so this is only for
454                    * backwards compatibility.  Give them an op-level of
455                    * MAXOPLEVEL so everyone can deop them.
456                    */
457                   oplevel = MAXOPLEVEL;
458                   if (current_mode_needs_reset) {
459                     current_mode = base_mode;
460                     current_mode_needs_reset = 0;
461                   }
462                   current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
463                   /*
464                    * Older servers may send XXYYY:ov, in which case we
465                    * do not want to use the code for 'v' below.
466                    */
467                   if (ptr[1] == 'v') {
468                     current_mode |= CHFL_VOICE;
469                     ptr++;
470                   }
471                 }
472                 else if (*ptr == 'v') { /* has voice status */
473                   if (current_mode_needs_reset) {
474                     current_mode = base_mode;
475                     current_mode_needs_reset = 0;
476                   }
477                   current_mode = (current_mode & ~CHFL_DELAYED) | CHFL_VOICE;
478                   oplevel = -1; /* subsequent digits are an absolute op-level value. */
479                 }
480                 else if (IsDigit(*ptr)) {
481                   int level_increment = 0;
482                   if (oplevel == -1) { /* op-level is absolute value? */
483                     if (current_mode_needs_reset) {
484                       current_mode = base_mode;
485                       current_mode_needs_reset = 0;
486                     }
487                     oplevel = 0;
488                   }
489                   current_mode = (current_mode & ~(CHFL_DEOPPED | CHFL_DELAYED)) | CHFL_CHANOP;
490                   do {
491                     level_increment = 10 * level_increment + *ptr++ - '0';
492                   } while (IsDigit(*ptr));
493                   --ptr;
494                   oplevel += level_increment;
495                   if (oplevel > MAXOPLEVEL) {
496                     protocol_violation(sptr, "Invalid cumulative oplevel %u during burst", oplevel);
497                     oplevel = MAXOPLEVEL;
498                     break;
499                   }
500                 }
501                 else { /* I don't recognize that flag */
502                   protocol_violation(sptr, "Invalid flag '%c' in nick part of burst", *ptr);
503                   break; /* so stop processing */
504                 }
505               }
506             }
507           }
508
509           if (!(acptr = findNUser(nick)) || cli_from(acptr) != cptr)
510             continue; /* ignore this client */
511
512           /* Build nick buffer */
513           nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */
514           nickpos++;
515
516           for (ptr = nick; *ptr; ptr++) /* store nick */
517             nickstr[nickpos++] = *ptr;
518
519           if (current_mode != last_mode) { /* if mode changed... */
520             last_mode = current_mode;
521             last_oplevel = oplevel;
522
523             nickstr[nickpos++] = ':'; /* add a specifier */
524             if (current_mode & CHFL_VOICE)
525               nickstr[nickpos++] = 'v';
526             if (current_mode & CHFL_CHANOP)
527             {
528               if (oplevel != MAXOPLEVEL)
529                 nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel);
530               else
531                 nickstr[nickpos++] = 'o';
532             }
533           } else if (current_mode & CHFL_CHANOP && oplevel != last_oplevel) { /* if just op level changed... */
534             nickstr[nickpos++] = ':'; /* add a specifier */
535             nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel - last_oplevel);
536             last_oplevel = oplevel;
537           }
538
539           if (!(member = find_member_link(chptr, acptr)))
540           {
541             add_user_to_channel(chptr, acptr, current_mode, oplevel);
542             if (!(current_mode & CHFL_DELAYED))
543               sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, 0, "%H", chptr);
544           }
545           else
546           {
547             /* The member was already joined (either by CREATE or JOIN).
548                Remember the current mode. */
549             if (member->status & CHFL_CHANOP)
550               member->status |= CHFL_BURST_ALREADY_OPPED;
551             if (member->status & CHFL_VOICE)
552               member->status |= CHFL_BURST_ALREADY_VOICED;
553             /* Synchronize with the burst. */
554             member->status |= CHFL_BURST_JOINED | (current_mode & (CHFL_CHANOP|CHFL_VOICE));
555             SetOpLevel(member, oplevel);
556           }
557         }
558       }
559       param++;
560       break;
561     } /* switch (*parv[param]) */
562   } /* while (param < parc) */
563
564   nickstr[nickpos] = '\0';
565   banstr[banpos] = '\0';
566
567   if (parse_flags & MODE_PARSE_SET) {
568     modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */
569     modestr[0] = modestr[1] ? ' ' : '\0';
570   } else
571     modestr[0] = '\0';
572
573   sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr,
574                         chptr->creationtime, modestr, nickstr, banstr);
575
576   if (parse_flags & MODE_PARSE_WIPEOUT || banpos)
577     mode_ban_invalidate(chptr);
578
579   if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */
580     /* first deal with channel members */
581     for (member = chptr->members; member; member = member->next_member) {
582       if (member->status & CHFL_BURST_JOINED) { /* joined during burst */
583         if ((member->status & CHFL_CHANOP) && !(member->status & CHFL_BURST_ALREADY_OPPED))
584           modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user, OpLevel(member));
585         if ((member->status & CHFL_VOICE) && !(member->status & CHFL_BURST_ALREADY_VOICED))
586           modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user, OpLevel(member));
587       } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */
588         if (member->status & CHFL_CHANOP)
589           modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user, OpLevel(member));
590         if (member->status & CHFL_VOICE)
591           modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user, OpLevel(member));
592         member->status = (member->status
593                           & ~(CHFL_CHANNEL_MANAGER | CHFL_CHANOP | CHFL_VOICE))
594                          | CHFL_DEOPPED;
595       }
596     }
597
598     /* Now deal with channel bans */
599     lp_p = &chptr->banlist;
600     while (*lp_p) {
601       lp = *lp_p;
602
603       /* remove ban from channel */
604       if (lp->flags & (BAN_OVERLAPPED | BAN_BURST_WIPEOUT)) {
605         char *bandup;
606         DupString(bandup, lp->banstr);
607         modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
608                             bandup, 1);
609         *lp_p = lp->next; /* clip out of list */
610         free_ban(lp);
611         continue;
612       } else if (lp->flags & BAN_BURSTED) /* add ban to channel */
613         modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN,
614                             lp->banstr, 0); /* don't free banstr */
615
616       lp->flags &= BAN_IPMASK; /* reset the flag */
617       lp_p = &(*lp_p)->next;
618     }
619   }
620
621   return mbuf ? modebuf_flush(mbuf) : 0;
622 }