Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / channel.c
1 /*
2  * IRC - Internet Relay Chat, ircd/channel.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Co Center
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id$
21  */
22 #include "channel.h"
23 #include "client.h"
24 #include "hash.h"
25 #include "ircd.h"
26 #include "ircd_alloc.h"
27 #include "ircd_chattr.h"
28 #include "ircd_reply.h"
29 #include "ircd_snprintf.h"
30 #include "ircd_string.h"
31 #include "list.h"
32 #include "match.h"
33 #include "msg.h"
34 #include "numeric.h"
35 #include "numnicks.h"
36 #include "querycmds.h"
37 #include "s_bsd.h"
38 #include "s_conf.h"
39 #include "s_debug.h"
40 #include "s_misc.h"
41 #include "s_user.h"
42 #include "send.h"
43 #include "sprintf_irc.h"
44 #include "struct.h"
45 #include "support.h"
46 #include "sys.h"
47 #include "whowas.h"
48
49 #include <assert.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 struct Channel* GlobalChannelList = 0;
55
56 static unsigned int membershipAllocCount;
57 static struct Membership* membershipFreeList;
58
59 static struct SLink *next_overlapped_ban(void);
60 static int del_banid(struct Channel *, char *, int);
61 void del_invite(struct Client *, struct Channel *);
62
63 const char* const PartFmt1     = ":%s " MSG_PART " %s";
64 const char* const PartFmt2     = ":%s " MSG_PART " %s :%s";
65 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
66 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
67
68
69 static struct SLink* next_ban;
70 static struct SLink* prev_ban;
71 static struct SLink* removed_bans_list;
72
73 /*
74  * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
75  * but the only way to do it without changing set_mode intensively.
76  */
77 int LocalChanOperMode = 0;
78
79 #if !defined(NDEBUG)
80 /*
81  * return the length (>=0) of a chain of links.
82  */
83 static int list_length(struct SLink *lp)
84 {
85   int count = 0;
86
87   for (; lp; lp = lp->next)
88     ++count;
89   return count;
90 }
91 #endif
92
93 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
94 {
95   struct Membership *m;
96   assert(0 != cptr);
97   assert(0 != chptr);
98   
99   /* Servers don't have member links */
100   if (IsServer(cptr)||IsMe(cptr))
101      return 0;
102   
103   /* +k users are typically on a LOT of channels.  So we iterate over who
104    * is in the channel.  X/W are +k and are in about 5800 channels each.
105    * however there are typically no more than 1000 people in a channel
106    * at a time.
107    */
108   if (IsChannelService(cptr)) {
109     m = chptr->members;
110     while (m) {
111       assert(m->channel == chptr);
112       if (m->user == cptr)
113         return m;
114       m = m->next_member;
115     }
116   }
117   /* Users on the other hand aren't allowed on more than 15 channels.  50%
118    * of users that are on channels are on 2 or less, 95% are on 7 or less,
119    * and 99% are on 10 or less.
120    */
121   else {
122    m = cptr->user->channel;
123    while (m) {
124      assert(m->user == cptr);
125      if (m->channel == chptr)
126        return m;
127      m = m->next_channel;
128    }
129   }
130   return 0;
131 }
132
133 /*
134  * find_chasing - Find the client structure for a nick name (user)
135  * using history mechanism if necessary. If the client is not found, an error
136  * message (NO SUCH NICK) is generated. If the client was found
137  * through the history, chasing will be 1 and otherwise 0.
138  */
139 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
140 {
141   struct Client* who = FindClient(user);
142
143   if (chasing)
144     *chasing = 0;
145   if (who)
146     return who;
147
148   if (!(who = get_history(user, KILLCHASETIMELIMIT))) {
149     send_reply(sptr, ERR_NOSUCHNICK, user);
150     return 0;
151   }
152   if (chasing)
153     *chasing = 1;
154   return who;
155 }
156
157 /*
158  * Create a string of form "foo!bar@fubar" given foo, bar and fubar
159  * as the parameters.  If NULL, they become "*".
160  */
161 static char *make_nick_user_host(const char *nick, const char *name,
162                                  const char *host)
163 {
164   static char namebuf[NICKLEN + USERLEN + HOSTLEN + 3];
165   sprintf_irc(namebuf, "%s!%s@%s", nick, name, host);
166   return namebuf;
167 }
168
169 /*
170  * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
171  * IP-number as the parameters.  If NULL, they become "*".
172  */
173 static char *make_nick_user_ip(char *nick, char *name, struct in_addr ip)
174 {
175   static char ipbuf[NICKLEN + USERLEN + 16 + 3];
176   sprintf_irc(ipbuf, "%s!%s@%s", nick, name, ircd_ntoa((const char*) &ip));
177   return ipbuf;
178 }
179
180 #if 0
181 static int DoesOp(const char* modebuf)
182 {
183   assert(0 != modebuf);
184   while (*modebuf) {
185     if (*modebuf == 'o' || *modebuf == 'v')
186       return 1;
187     ++modebuf;
188   }
189   return 0;
190 }
191
192 /*
193  * This function should be removed when all servers are 2.10
194  */
195 static void sendmodeto_one(struct Client* cptr, const char* from,
196                            const char* name, const char* mode,
197                            const char* param, time_t creationtime)
198 {
199   if (IsServer(cptr) && DoesOp(mode) && creationtime)
200     sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT, /* XXX DEAD */
201                from, name, mode, param, creationtime);
202   else
203     sendto_one(cptr, ":%s MODE %s %s %s", from, name, mode, param); /* XXX DEAD */
204 }
205 #endif /* 0 */
206
207 /*
208  * Subtract one user from channel i (and free channel
209  * block, if channel became empty).
210  * Returns: true  (1) if channel still exists
211  *          false (0) if the channel was destroyed
212  */
213 int sub1_from_channel(struct Channel* chptr)
214 {
215   struct SLink *tmp;
216   struct SLink *obtmp;
217
218   if (chptr->users > 1)         /* Can be 0, called for an empty channel too */
219   {
220     assert(0 != chptr->members);
221     --chptr->users;
222     return 1;
223   }
224
225   assert(0 == chptr->members);
226
227   /* Channel became (or was) empty: Remove channel */
228   if (is_listed(chptr))
229   {
230     int i;
231     for (i = 0; i <= HighestFd; i++)
232     {
233       struct Client *acptr = 0;
234       if ((acptr = LocalClientArray[i]) && acptr->listing &&
235           acptr->listing->chptr == chptr)
236       {
237         list_next_channels(acptr, 1);
238         break;                  /* Only one client can list a channel */
239       }
240     }
241   }
242   /*
243    * Now, find all invite links from channel structure
244    */
245   while ((tmp = chptr->invites))
246     del_invite(tmp->value.cptr, chptr);
247
248   tmp = chptr->banlist;
249   while (tmp)
250   {
251     obtmp = tmp;
252     tmp = tmp->next;
253     MyFree(obtmp->value.ban.banstr);
254     MyFree(obtmp->value.ban.who);
255     free_link(obtmp);
256   }
257   if (chptr->prev)
258     chptr->prev->next = chptr->next;
259   else
260     GlobalChannelList = chptr->next;
261   if (chptr->next)
262     chptr->next->prev = chptr->prev;
263   hRemChannel(chptr);
264   --UserStats.channels;
265   /*
266    * make sure that channel actually got removed from hash table
267    */
268   assert(chptr->hnext == chptr);
269   MyFree(chptr);
270   return 0;
271 }
272
273 /*
274  * add_banid
275  *
276  * `cptr' must be the client adding the ban.
277  *
278  * If `change' is true then add `banid' to channel `chptr'.
279  * Returns 0 if the ban was added.
280  * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
281  * Return -1 otherwise.
282  *
283  * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
284  * when `change' is false, otherwise they will be removed from the banlist.
285  * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
286  * respectively will return these bans until NULL is returned.
287  *
288  * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
289  * is reset (unless a non-zero value is returned, in which case the
290  * CHFL_BAN_OVERLAPPED flag might not have been reset!).
291  *
292  * --Run
293  */
294 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
295                      int change, int firsttime)
296 {
297   struct SLink*  ban;
298   struct SLink** banp;
299   int            cnt = 0;
300   int            removed_bans = 0;
301   int            len = strlen(banid);
302
303   if (firsttime)
304   {
305     next_ban = NULL;
306     assert(0 == prev_ban);
307     assert(0 == removed_bans_list);
308   }
309   if (MyUser(cptr))
310     collapse(banid);
311   for (banp = &chptr->banlist; *banp;)
312   {
313     len += strlen((*banp)->value.ban.banstr);
314     ++cnt;
315     if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
316     {
317       if (!strcmp((*banp)->value.ban.banstr, banid))
318       {
319         (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
320         return -2;
321       }
322     }
323     else if (!mmatch((*banp)->value.ban.banstr, banid))
324       return -1;
325     if (!mmatch(banid, (*banp)->value.ban.banstr))
326     {
327       struct SLink *tmp = *banp;
328       if (change)
329       {
330         if (MyUser(cptr))
331         {
332           cnt--;
333           len -= strlen(tmp->value.ban.banstr);
334         }
335         *banp = tmp->next;
336 #if 0
337         /* Silently remove overlapping bans */
338         MyFree(tmp->value.ban.banstr);
339         MyFree(tmp->value.ban.who);
340         free_link(tmp);
341         tmp = 0;
342 #else
343         /* These will be sent to the user later as -b */
344         tmp->next = removed_bans_list;
345         removed_bans_list = tmp;
346         removed_bans = 1;
347 #endif
348       }
349       else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
350       {
351         tmp->flags |= CHFL_BAN_OVERLAPPED;
352         if (!next_ban)
353           next_ban = tmp;
354         banp = &tmp->next;
355       }
356       else
357         banp = &tmp->next;
358     }
359     else
360     {
361       if (firsttime)
362         (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
363       banp = &(*banp)->next;
364     }
365   }
366   if (MyUser(cptr) && !removed_bans && (len > MAXBANLENGTH || (cnt >= MAXBANS)))
367   {
368     send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
369     return -1;
370   }
371   if (change)
372   {
373     char*              ip_start;
374     struct Membership* member;
375     ban = make_link();
376     ban->next = chptr->banlist;
377
378     ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
379     assert(0 != ban->value.ban.banstr);
380     strcpy(ban->value.ban.banstr, banid);
381
382     ban->value.ban.who = (char*) MyMalloc(strlen(cptr->name) + 1);
383     assert(0 != ban->value.ban.who);
384     strcpy(ban->value.ban.who, cptr->name);
385
386     ban->value.ban.when = TStime();
387     ban->flags = CHFL_BAN;      /* This bit is never used I think... */
388     if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
389       ban->flags |= CHFL_BAN_IPMASK;
390     chptr->banlist = ban;
391
392     /*
393      * Erase ban-valid-bit
394      */
395     for (member = chptr->members; member; member = member->next_member)
396       ClearBanValid(member);     /* `ban' == channel member ! */
397   }
398   return 0;
399 }
400
401 static struct SLink *next_overlapped_ban(void)
402 {
403   struct SLink *tmp = next_ban;
404   if (tmp)
405   {
406     struct SLink *ban;
407     for (ban = tmp->next; ban; ban = ban->next)
408       if ((ban->flags & CHFL_BAN_OVERLAPPED))
409         break;
410     next_ban = ban;
411   }
412   return tmp;
413 }
414
415 struct SLink *next_removed_overlapped_ban(void)
416 {
417   struct SLink *tmp = removed_bans_list;
418   if (prev_ban)
419   {
420     if (prev_ban->value.ban.banstr)     /* Can be set to NULL in set_mode() */
421       MyFree(prev_ban->value.ban.banstr);
422     MyFree(prev_ban->value.ban.who);
423     free_link(prev_ban);
424     prev_ban = 0;
425   }
426   if (tmp)
427     removed_bans_list = removed_bans_list->next;
428   prev_ban = tmp;
429   return tmp;
430 }
431
432 /*
433  * del_banid
434  *
435  * If `change' is true, delete `banid' from channel `chptr'.
436  * Returns `false' if removal was (or would have been) successful.
437  */
438 static int del_banid(struct Channel *chptr, char *banid, int change)
439 {
440   struct SLink **ban;
441   struct SLink *tmp;
442
443   if (!banid)
444     return -1;
445   for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next)) {
446     if (0 == ircd_strcmp(banid, (*ban)->value.ban.banstr))
447     {
448       tmp = *ban;
449       if (change)
450       {
451         struct Membership* member;
452         *ban = tmp->next;
453         MyFree(tmp->value.ban.banstr);
454         MyFree(tmp->value.ban.who);
455         free_link(tmp);
456         /*
457          * Erase ban-valid-bit, for channel members that are banned
458          */
459         for (member = chptr->members; member; member = member->next_member)
460           if (CHFL_BANVALIDMASK == (member->status & CHFL_BANVALIDMASK))
461             ClearBanValid(member);       /* `tmp' == channel member */
462       }
463       return 0;
464     }
465   }
466   return -1;
467 }
468
469 /*
470  * find_channel_member - returns Membership * if a person is joined and not a zombie
471  */
472 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
473 {
474   struct Membership* member;
475   assert(0 != chptr);
476
477   member = find_member_link(chptr, cptr);
478   return (member && !IsZombie(member)) ? member : 0;
479 }
480
481 /*
482  * is_banned - a non-zero value if banned else 0.
483  */
484 static int is_banned(struct Client *cptr, struct Channel *chptr,
485                      struct Membership* member)
486 {
487   struct SLink* tmp;
488   char*         s;
489   char*         ip_s = NULL;
490
491   if (!IsUser(cptr))
492     return 0;
493
494   if (member && IsBanValid(member))
495     return IsBanned(member);
496
497   s = make_nick_user_host(cptr->name, cptr->user->username, cptr->user->host);
498
499   for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
500     if ((tmp->flags & CHFL_BAN_IPMASK)) {
501       if (!ip_s)
502         ip_s = make_nick_user_ip(cptr->name, cptr->user->username, cptr->ip);
503       if (match(tmp->value.ban.banstr, ip_s) == 0)
504         break;
505     }
506     else if (match(tmp->value.ban.banstr, s) == 0)
507       break;
508   }
509
510   if (member) {
511     SetBanValid(member);
512     if (tmp) {
513       SetBanned(member);
514       return 1;
515     }
516     else {
517       ClearBanned(member);
518       return 0;
519     }
520   }
521
522   return (tmp != NULL);
523 }
524
525 /*
526  * adds a user to a channel by adding another link to the channels member
527  * chain.
528  */
529 void add_user_to_channel(struct Channel* chptr, struct Client* who,
530                                 unsigned int flags)
531 {
532   assert(0 != chptr);
533   assert(0 != who);
534
535   if (who->user) {
536    
537     struct Membership* member = membershipFreeList;
538     if (member)
539       membershipFreeList = member->next_member;
540     else {
541       member = (struct Membership*) MyMalloc(sizeof(struct Membership));
542       ++membershipAllocCount;
543     }
544
545     assert(0 != member);
546     member->user         = who;
547     member->channel      = chptr;
548     member->status       = flags;
549
550     member->next_member  = chptr->members;
551     if (member->next_member)
552       member->next_member->prev_member = member;
553     member->prev_member  = 0; 
554     chptr->members       = member;
555
556     member->next_channel = who->user->channel;
557     if (member->next_channel)
558       member->next_channel->prev_channel = member;
559     member->prev_channel = 0;
560     who->user->channel = member;
561
562     ++chptr->users;
563     ++who->user->joined;
564   }
565 }
566
567 static int remove_member_from_channel(struct Membership* member)
568 {
569   struct Channel* chptr;
570   assert(0 != member);
571   chptr = member->channel;
572   /*
573    * unlink channel member list
574    */
575   if (member->next_member)
576     member->next_member->prev_member = member->prev_member;
577   if (member->prev_member)
578     member->prev_member->next_member = member->next_member;
579   else
580     member->channel->members = member->next_member; 
581       
582   /*
583    * unlink client channel list
584    */
585   if (member->next_channel)
586     member->next_channel->prev_channel = member->prev_channel;
587   if (member->prev_channel)
588     member->prev_channel->next_channel = member->next_channel;
589   else
590     member->user->user->channel = member->next_channel;
591
592   --member->user->user->joined;
593
594   member->next_member = membershipFreeList;
595   membershipFreeList = member;
596
597   return sub1_from_channel(chptr);
598 }
599
600 static int channel_all_zombies(struct Channel* chptr)
601 {
602   struct Membership* member;
603
604   for (member = chptr->members; member; member = member->next_member) {
605     if (!IsZombie(member))
606       return 0;
607   }
608   return 1;
609 }
610       
611
612 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
613 {
614   
615   struct Membership* member;
616   assert(0 != chptr);
617
618   if ((member = find_member_link(chptr, cptr))) {
619     if (remove_member_from_channel(member)) {
620       if (channel_all_zombies(chptr)) {
621         /*
622          * XXX - this looks dangerous but isn't if we got the referential
623          * integrity right for channels
624          */
625         while (remove_member_from_channel(chptr->members))
626           ;
627       }
628     }
629   }
630 }
631
632 void remove_user_from_all_channels(struct Client* cptr)
633 {
634   struct Membership* chan;
635   assert(0 != cptr);
636   assert(0 != cptr->user);
637
638   while ((chan = cptr->user->channel))
639     remove_user_from_channel(cptr, chan->channel);
640 }
641
642 int is_chan_op(struct Client *cptr, struct Channel *chptr)
643 {
644   struct Membership* member;
645   assert(chptr);
646   if ((member = find_member_link(chptr, cptr)))
647     return (!IsZombie(member) && IsChanOp(member));
648
649   return 0;
650 }
651
652 static int is_deopped(struct Client *cptr, struct Channel *chptr)
653 {
654   struct Membership* member;
655
656   assert(0 != chptr);
657   if ((member = find_member_link(chptr, cptr)))
658     return IsDeopped(member);
659
660   return (IsUser(cptr) ? 1 : 0);
661 }
662
663 int is_zombie(struct Client *cptr, struct Channel *chptr)
664 {
665   struct Membership* member;
666
667   assert(0 != chptr);
668
669   if ((member = find_member_link(chptr, cptr)))
670       return IsZombie(member);
671   return 0;
672 }
673
674 int has_voice(struct Client* cptr, struct Channel* chptr)
675 {
676   struct Membership* member;
677
678   assert(0 != chptr);
679   if ((member = find_member_link(chptr, cptr)))
680     return (!IsZombie(member) && HasVoice(member));
681
682   return 0;
683 }
684
685 int member_can_send_to_channel(struct Membership* member)
686 {
687   assert(0 != member);
688
689   if (IsVoicedOrOpped(member))
690     return 1;
691   /*
692    * If it's moderated, and you aren't a priviledged user, you can't
693    * speak.  
694    */
695   if (member->channel->mode.mode & MODE_MODERATED)
696     return 0;
697   /*
698    * If you're banned then you can't speak either.
699    * but because of the amount of CPU time that is_banned chews
700    * we only check it for our clients.
701    */
702   if (MyUser(member->user) && is_banned(member->user, member->channel, member))
703     return 0;
704   return 1;
705 }
706
707 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr)
708 {
709   struct Membership *member;
710   assert(0 != cptr); 
711   /*
712    * Servers can always speak on channels.
713    */
714   if (IsServer(cptr))
715     return 1;
716
717   member = find_channel_member(cptr, chptr);
718
719   /*
720    * You can't speak if your off channel, if the channel is modeless, or
721    * +n.(no external messages)
722    */
723   if (!member) {
724     if ((chptr->mode.mode & MODE_NOPRIVMSGS) || IsModelessChannel(chptr->chname)) 
725       return 0;
726     else
727       return 1;
728   }
729   return member_can_send_to_channel(member); 
730 }
731
732 /*
733  * find_no_nickchange_channel
734  * if a member and not opped or voiced and banned
735  * return the name of the first channel banned on
736  */
737 const char* find_no_nickchange_channel(struct Client* cptr)
738 {
739   if (MyUser(cptr)) {
740     struct Membership* member;
741     for (member = cptr->user->channel; member; member = member->next_channel) {
742       if (!IsVoicedOrOpped(member) && is_banned(cptr, member->channel, member))
743         return member->channel->chname;
744     }
745   }
746   return 0;
747 }
748
749
750 /*
751  * write the "simple" list of channel modes for channel chptr onto buffer mbuf
752  * with the parameters in pbuf.
753  */
754 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf,
755                           struct Channel *chptr)
756 {
757   assert(0 != mbuf);
758   assert(0 != pbuf);
759   assert(0 != chptr);
760
761   *mbuf++ = '+';
762   if (chptr->mode.mode & MODE_SECRET)
763     *mbuf++ = 's';
764   else if (chptr->mode.mode & MODE_PRIVATE)
765     *mbuf++ = 'p';
766   if (chptr->mode.mode & MODE_MODERATED)
767     *mbuf++ = 'm';
768   if (chptr->mode.mode & MODE_TOPICLIMIT)
769     *mbuf++ = 't';
770   if (chptr->mode.mode & MODE_INVITEONLY)
771     *mbuf++ = 'i';
772   if (chptr->mode.mode & MODE_NOPRIVMSGS)
773     *mbuf++ = 'n';
774   if (chptr->mode.limit) {
775     *mbuf++ = 'l';
776     sprintf_irc(pbuf, "%d", chptr->mode.limit);
777   }
778
779   if (*chptr->mode.key) {
780     *mbuf++ = 'k';
781     if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
782       if (chptr->mode.limit)
783         strcat(pbuf, " ");
784       strcat(pbuf, chptr->mode.key);
785     }
786   }
787   *mbuf = '\0';
788 }
789
790 #if 0
791 static int send_mode_list(struct Client *cptr, char *chname,
792                           time_t creationtime, struct SLink *top,
793                           int mask, char flag)
794 {
795   struct SLink* lp;
796   char*         cp;
797   char*         name;
798   int           count = 0;
799   int           send = 0;
800   int           sent = 0;
801
802   cp = modebuf + strlen(modebuf);
803   if (*parabuf)                 /* mode +l or +k xx */
804     count = 1;
805   for (lp = top; lp; lp = lp->next)
806   {
807     if (!(lp->flags & mask))
808       continue;
809     if (mask == CHFL_BAN)
810       name = lp->value.ban.banstr;
811     else
812       name = lp->value.cptr->name;
813     if (strlen(parabuf) + strlen(name) + 11 < MODEBUFLEN)
814     {
815       strcat(parabuf, " ");
816       strcat(parabuf, name);
817       count++;
818       *cp++ = flag;
819       *cp = '\0';
820     }
821     else if (*parabuf)
822       send = 1;
823     if (count == 6)
824       send = 1;
825     if (send)
826     {
827       /* cptr is always a server! So we send creationtimes */
828       sendmodeto_one(cptr, me.name, chname, modebuf, parabuf, creationtime);
829       sent = 1;
830       send = 0;
831       *parabuf = '\0';
832       cp = modebuf;
833       *cp++ = '+';
834       if (count != 6)
835       {
836         strcpy(parabuf, name);
837         *cp++ = flag;
838       }
839       count = 0;
840       *cp = '\0';
841     }
842   }
843   return sent;
844 }
845
846 #endif /* 0 */
847
848 /*
849  * send "cptr" a full list of the modes for channel chptr.
850  */
851 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
852 {
853   static unsigned int current_flags[4] =
854       { 0, CHFL_CHANOP | CHFL_VOICE, CHFL_VOICE, CHFL_CHANOP };
855   int                first = 1;
856   int                full  = 1;
857   int                flag_cnt = 0;
858   int                new_mode = 0;
859   size_t             len;
860   size_t             sblen;
861   struct Membership* member;
862   struct SLink*      lp2;
863   char modebuf[MODEBUFLEN];
864   char parabuf[MODEBUFLEN];
865   char sndbuf[IRC_BUFSIZE];
866
867   assert(0 != cptr);
868   assert(0 != chptr); 
869
870   if (IsLocalChannel(chptr->chname))
871     return;
872
873   member = chptr->members;
874   lp2 = chptr->banlist;
875
876   *modebuf = *parabuf = '\0';
877   channel_modes(cptr, modebuf, parabuf, chptr);
878
879   for (first = 1; full; first = 0)      /* Loop for multiple messages */
880   {
881     full = 0;                   /* Assume by default we get it
882                                  all in one message */
883
884     /* (Continued) prefix: "<Y> B <channel> <TS>" */
885     /* is there any better way we can do this? */
886     sblen = ircd_snprintf(&me, sndbuf, sizeof(sndbuf), "%C " TOK_BURST
887                           " %H %Tu", &me, chptr, chptr->creationtime);
888
889     if (first && modebuf[1])    /* Add simple modes (iklmnpst)
890                                  if first message */
891     {
892       /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
893       sndbuf[sblen++] = ' ';
894       strcpy(sndbuf + sblen, modebuf);
895       sblen += strlen(modebuf);
896       if (*parabuf)
897       {
898         sndbuf[sblen++] = ' ';
899         strcpy(sndbuf + sblen, parabuf);
900         sblen += strlen(parabuf);
901       }
902     }
903
904     /*
905      * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
906      *
907      * Run 4 times over all members, to group the members with the
908      * same mode together
909      */
910     for (first = 1; flag_cnt < 4;
911          member = chptr->members, new_mode = 1, flag_cnt++)
912     {
913       for (; member; member = member->next_member)
914       {
915         if ((member->status & CHFL_VOICED_OR_OPPED) !=
916             current_flags[flag_cnt])
917           continue;             /* Skip members with different flags */
918         if (sblen + NUMNICKLEN + 4 > BUFSIZE - 3)
919           /* The 4 is a possible ",:ov"
920              The -3 is for the "\r\n\0" that is added in send.c */
921         {
922           full = 1;           /* Make sure we continue after
923                                  sending it so far */
924           new_mode = 1;       /* Ensure the new BURST line contains the current
925                                  mode. --Gte */
926           break;              /* Do not add this member to this message */
927         }
928         sndbuf[sblen++] = first ? ' ' : ',';
929         first = 0;              /* From now on, us comma's to add new nicks */
930
931         sblen += ircd_snprintf(&me, sndbuf + sblen, sizeof(sndbuf) - sblen,
932                                "%C", member->user);
933         /*
934          * Do we have a nick with a new mode ?
935          * Or are we starting a new BURST line?
936          */
937         if (new_mode)
938         {
939           new_mode = 0;
940           if (IsVoicedOrOpped(member)) {
941             sndbuf[sblen++] = ':';
942             if (IsChanOp(member))
943               sndbuf[sblen++] = 'o';
944             if (HasVoice(member))
945               sndbuf[sblen++] = 'v';
946           }
947         }
948       }
949       if (full)
950         break;
951     }
952
953     if (!full)
954     {
955       /* Attach all bans, space seperated " :%ban ban ..." */
956       for (first = 2; lp2; lp2 = lp2->next)
957       {
958         len = strlen(lp2->value.ban.banstr);
959         if (sblen + len + 1 + first > BUFSIZE - 3)
960           /* The +1 stands for the added ' '.
961            * The +first stands for the added ":%".
962            * The -3 is for the "\r\n\0" that is added in send.c
963            */
964         {
965           full = 1;
966           break;
967         }
968         if (first)
969         {
970           first = 0;
971           sndbuf[sblen++] = ' ';
972           sndbuf[sblen++] = ':';       /* Will be last parameter */
973           sndbuf[sblen++] = '%';       /* To tell bans apart */
974         }
975         else
976           sndbuf[sblen++] = ' ';
977         strcpy(sndbuf + sblen, lp2->value.ban.banstr);
978         sblen += len;
979       }
980     }
981
982     sndbuf[sblen] = '\0';
983     send_buffer(cptr, sndbuf);  /* Send this message */
984   }                             /* Continue when there was something
985                                  that didn't fit (full==1) */
986 }
987
988 /*
989  * pretty_mask
990  *
991  * by Carlo Wood (Run), 05 Oct 1998.
992  *
993  * Canonify a mask.
994  *
995  * When the nick is longer then NICKLEN, it is cut off (its an error of course).
996  * When the user name or host name are too long (USERLEN and HOSTLEN
997  * respectively) then they are cut off at the start with a '*'.
998  *
999  * The following transformations are made:
1000  *
1001  * 1)   xxx             -> nick!*@*
1002  * 2)   xxx.xxx         -> *!*@host
1003  * 3)   xxx!yyy         -> nick!user@*
1004  * 4)   xxx@yyy         -> *!user@host
1005  * 5)   xxx!yyy@zzz     -> nick!user@host
1006  */
1007 char *pretty_mask(char *mask)
1008 {
1009   static char star[2] = { '*', 0 };
1010   char *last_dot = NULL;
1011   char *ptr;
1012
1013   /* Case 1: default */
1014   char *nick = mask;
1015   char *user = star;
1016   char *host = star;
1017
1018   /* Do a _single_ pass through the characters of the mask: */
1019   for (ptr = mask; *ptr; ++ptr)
1020   {
1021     if (*ptr == '!')
1022     {
1023       /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1024       user = ++ptr;
1025       host = star;
1026     }
1027     else if (*ptr == '@')
1028     {
1029       /* Case 4: Found last '@' (without finding a '!' yet) */
1030       nick = star;
1031       user = mask;
1032       host = ++ptr;
1033     }
1034     else if (*ptr == '.')
1035     {
1036       /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1037       last_dot = ptr;
1038       continue;
1039     }
1040     else
1041       continue;
1042     for (; *ptr; ++ptr)
1043     {
1044       if (*ptr == '@')
1045       {
1046         /* Case 4 or 5: Found last '@' */
1047         host = ptr + 1;
1048       }
1049     }
1050     break;
1051   }
1052   if (user == star && last_dot)
1053   {
1054     /* Case 2: */
1055     nick = star;
1056     user = star;
1057     host = mask;
1058   }
1059   /* Check lengths */
1060   if (nick != star)
1061   {
1062     char *nick_end = (user != star) ? user - 1 : ptr;
1063     if (nick_end - nick > NICKLEN)
1064       nick[NICKLEN] = 0;
1065     *nick_end = 0;
1066   }
1067   if (user != star)
1068   {
1069     char *user_end = (host != star) ? host - 1 : ptr;
1070     if (user_end - user > USERLEN)
1071     {
1072       user = user_end - USERLEN;
1073       *user = '*';
1074     }
1075     *user_end = 0;
1076   }
1077   if (host != star && ptr - host > HOSTLEN)
1078   {
1079     host = ptr - HOSTLEN;
1080     *host = '*';
1081   }
1082   return make_nick_user_host(nick, user, host);
1083 }
1084
1085 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1086 {
1087   struct SLink* lp;
1088
1089   assert(0 != cptr);
1090   assert(0 != chptr);
1091
1092   for (lp = chptr->banlist; lp; lp = lp->next)
1093     send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1094                lp->value.ban.who, lp->value.ban.when);
1095
1096   send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1097 }
1098
1099 /*
1100  * Check and try to apply the channel modes passed in the parv array for
1101  * the client ccptr to channel chptr.  The resultant changes are printed
1102  * into mbuf and pbuf (if any) and applied to the channel.
1103  */
1104 int set_mode(struct Client* cptr, struct Client* sptr,
1105                     struct Channel* chptr, int parc, char* parv[],
1106                     char* mbuf, char* pbuf, char* npbuf, int* badop)
1107
1108   /* 
1109    * This size is only needed when a broken
1110    * server sends more then MAXMODEPARAMS
1111    * parameters
1112    */
1113   static struct SLink chops[MAXPARA - 2];
1114   static int flags[] = {
1115     MODE_PRIVATE,    'p',
1116     MODE_SECRET,     's',
1117     MODE_MODERATED,  'm',
1118     MODE_NOPRIVMSGS, 'n',
1119     MODE_TOPICLIMIT, 't',
1120     MODE_INVITEONLY, 'i',
1121     MODE_VOICE,      'v',
1122     MODE_KEY,        'k',
1123     0x0, 0x0
1124   };
1125
1126   char bmodebuf[MODEBUFLEN];
1127   char bparambuf[MODEBUFLEN];
1128   char nbparambuf[MODEBUFLEN];     /* "Numeric" Bounce Parameter Buffer */
1129   struct SLink*      lp;
1130   char*              curr = parv[0];
1131   char*              cp = NULL;
1132   int*               ip;
1133   struct Membership* member_x;
1134   struct Membership* member_y;
1135   unsigned int       whatt = MODE_ADD;
1136   unsigned int       bwhatt = 0;
1137   int                limitset = 0;
1138   int                bounce;
1139   int                add_banid_called = 0;
1140   size_t             len;
1141   size_t             nlen;
1142   size_t             blen;
1143   size_t             nblen;
1144   int                keychange = 0;
1145   unsigned int       nusers = 0;
1146   unsigned int       newmode;
1147   int                opcnt = 0;
1148   int                banlsent = 0;
1149   int                doesdeop = 0;
1150   int                doesop = 0;
1151   int                hacknotice = 0;
1152   int                change;
1153   int                gotts = 0;
1154   struct Client*     who;
1155   struct Mode*       mode;
1156   struct Mode        oldm;
1157   static char        numeric[16];
1158   char*              bmbuf = bmodebuf;
1159   char*              bpbuf = bparambuf;
1160   char*              nbpbuf = nbparambuf;
1161   time_t             newtime = 0;
1162   struct ConfItem*   aconf;
1163
1164   *mbuf = *pbuf = *npbuf = *bmbuf = *bpbuf = *nbpbuf = '\0';
1165   *badop = 0;
1166   if (parc < 1)
1167     return 0;
1168   /*
1169    * Mode is accepted when sptr is a channel operator
1170    * but also when the mode is received from a server.
1171    * At this point, let any member pass, so they are allowed
1172    * to see the bans.
1173    */
1174   member_y = find_channel_member(sptr, chptr);
1175   if (!(IsServer(cptr) || member_y))
1176     return 0;
1177
1178 #ifdef OPER_MODE_LCHAN
1179   if (IsOperOnLocalChannel(sptr, chptr->chname) && !IsChanOp(member_y))
1180     LocalChanOperMode = 1;
1181 #endif
1182
1183   mode = &(chptr->mode);
1184   memcpy(&oldm, mode, sizeof(struct Mode));
1185
1186   newmode = mode->mode;
1187
1188   while (curr && *curr) {
1189     switch (*curr) {
1190       case '+':
1191         whatt = MODE_ADD;
1192         break;
1193       case '-':
1194         whatt = MODE_DEL;
1195         break;
1196       case 'o':
1197       case 'v':
1198         if (--parc <= 0)
1199           break;
1200         parv++;
1201         if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1202           break;
1203         /*
1204          * Check for nickname changes and try to follow these
1205          * to make sure the right client is affected by the
1206          * mode change.
1207          * Even if we find a nick with find_chasing() there
1208          * is still a reason to ignore in a special case.
1209          * We need to ignore the mode when:
1210          * - It is part of a net.burst (from a server and
1211          *   a MODE_ADD). Ofcourse we don't ignore mode
1212          *   changes from Uworld.
1213          * - The found nick is not on the right side off
1214          *   the net.junction.
1215          * This fixes the bug that when someone (tries to)
1216          * ride a net.break and does so with the nick of
1217          * someone on the otherside, that he is nick collided
1218          * (killed) but his +o still ops the other person.
1219          */
1220         if (MyUser(sptr))
1221         {
1222           if (!(who = find_chasing(sptr, parv[0], NULL)))
1223             break;
1224         }
1225         else
1226         {
1227           if (!(who = findNUser(parv[0])))
1228             break;
1229         }
1230         if (whatt == MODE_ADD && IsServer(sptr) && who->from != sptr->from &&
1231             !find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
1232           break;
1233
1234         if (!(member_x = find_member_link(chptr, who)) ||
1235             (MyUser(sptr) && IsZombie(member_x)))
1236         {
1237           send_reply(cptr, ERR_USERNOTINCHANNEL, who->name, chptr->chname);
1238           break;
1239         }
1240         /*
1241          * if the user is +k, prevent a deop from local user
1242          */
1243         if (whatt == MODE_DEL && IsChannelService(who) && *curr == 'o') {
1244           /*
1245            * XXX - CHECKME
1246            */
1247           if (MyUser(cptr)) {
1248             send_reply(cptr, ERR_ISCHANSERVICE, parv[0], chptr->chname);
1249             break;
1250            }
1251            else {
1252              sprintf_irc(sendbuf,":%s NOTICE * :*** Notice -- Deop of +k user on %s by %s", /* XXX set_mode only called by old m_mode */
1253                          me.name,chptr->chname,cptr->name);             
1254            }
1255         }
1256 #ifdef NO_OPER_DEOP_LCHAN
1257         /*
1258          * if the user is an oper on a local channel, prevent him
1259          * from being deoped. that oper can deop himself though.
1260          */
1261         if (whatt == MODE_DEL && IsOperOnLocalChannel(who, chptr->chname) &&
1262             (who != sptr) && MyUser(cptr) && *curr == 'o')
1263         {
1264           send_reply(cptr, ERR_ISOPERLCHAN, parv[0], chptr->chname);
1265           break;
1266         }
1267 #endif
1268         if (whatt == MODE_ADD)
1269         {
1270           lp = &chops[opcnt++];
1271           lp->value.cptr = who;
1272           if (IsServer(sptr) && (!(who->flags & FLAGS_TS8) || ((*curr == 'o') &&
1273               !(member_x->status & (CHFL_SERVOPOK | CHFL_CHANOP)))))
1274             *badop = ((member_x->status & CHFL_DEOPPED) && (*curr == 'o')) ? 2 : 3;
1275           lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
1276           lp->flags |= MODE_ADD;
1277         }
1278         else if (whatt == MODE_DEL)
1279         {
1280           lp = &chops[opcnt++];
1281           lp->value.cptr = who;
1282           doesdeop = 1;         /* Also when -v */
1283           lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
1284           lp->flags |= MODE_DEL;
1285         }
1286         if (*curr == 'o')
1287           doesop = 1;
1288         break;
1289       case 'k':
1290         if (--parc <= 0)
1291           break;
1292         parv++;
1293         /* check now so we eat the parameter if present */
1294         if (keychange)
1295           break;
1296         else
1297         {
1298           char *s = &(*parv)[-1];
1299           unsigned short count = KEYLEN + 1;
1300
1301           while (*++s > ' ' && *s != ':' && --count);
1302           *s = '\0';
1303           if (!**parv)          /* nothing left in key */
1304             break;
1305         }
1306         if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1307           break;
1308         if (whatt == MODE_ADD)
1309         {
1310           if (*mode->key && !IsServer(cptr))
1311             send_reply(cptr, ERR_KEYSET, chptr->chname);
1312           else if (!*mode->key || IsServer(cptr))
1313           {
1314             lp = &chops[opcnt++];
1315             lp->value.cp = *parv;
1316             if (strlen(lp->value.cp) > KEYLEN)
1317               lp->value.cp[KEYLEN] = '\0';
1318             lp->flags = MODE_KEY | MODE_ADD;
1319             keychange = 1;
1320           }
1321         }
1322         else if (whatt == MODE_DEL)
1323         {
1324           /* Debug((DEBUG_INFO, "removing key: mode->key: >%s< *parv: >%s<", mode->key, *parv)); */
1325           if (0 == ircd_strcmp(mode->key, *parv) || IsServer(cptr))
1326           {
1327             /* Debug((DEBUG_INFO, "key matched")); */
1328             lp = &chops[opcnt++];
1329             lp->value.cp = mode->key;
1330             lp->flags = MODE_KEY | MODE_DEL;
1331             keychange = 1;
1332           }
1333         }
1334         break;
1335       case 'b':
1336         if (--parc <= 0) {
1337           if (0 == banlsent) {
1338             /*
1339              * Only send it once
1340              */
1341             send_ban_list(cptr, chptr);
1342             banlsent = 1;
1343           }
1344           break;
1345         }
1346         parv++;
1347         if (EmptyString(*parv))
1348           break;
1349         if (MyUser(sptr))
1350         {
1351           if ((cp = strchr(*parv, ' ')))
1352             *cp = 0;
1353           if (opcnt >= MAXMODEPARAMS || **parv == ':' || **parv == '\0')
1354             break;
1355         }
1356         if (whatt == MODE_ADD)
1357         {
1358           lp = &chops[opcnt++];
1359           lp->value.cp = *parv;
1360           lp->flags = MODE_ADD | MODE_BAN;
1361         }
1362         else if (whatt == MODE_DEL)
1363         {
1364           lp = &chops[opcnt++];
1365           lp->value.cp = *parv;
1366           lp->flags = MODE_DEL | MODE_BAN;
1367         }
1368         break;
1369       case 'l':
1370         /*
1371          * limit 'l' to only *1* change per mode command but
1372          * eat up others.
1373          */
1374         if (limitset)
1375         {
1376           if (whatt == MODE_ADD && --parc > 0)
1377             parv++;
1378           break;
1379         }
1380         if (whatt == MODE_DEL)
1381         {
1382           limitset = 1;
1383           nusers = 0;
1384           break;
1385         }
1386         if (--parc > 0)
1387         {
1388           if (EmptyString(*parv))
1389             break;
1390           if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
1391             break;
1392           if (!(nusers = atoi(*++parv)))
1393             continue;
1394           lp = &chops[opcnt++];
1395           lp->flags = MODE_ADD | MODE_LIMIT;
1396           limitset = 1;
1397           break;
1398         }
1399         need_more_params(cptr, "MODE +l");
1400         break;
1401       case 'i':         /* falls through for default case */
1402         if (whatt == MODE_DEL)
1403           while ((lp = chptr->invites))
1404             del_invite(lp->value.cptr, chptr);
1405       default:
1406         for (ip = flags; *ip; ip += 2)
1407           if (*(ip + 1) == *curr)
1408             break;
1409
1410         if (*ip)
1411         {
1412           if (whatt == MODE_ADD)
1413           {
1414             if (*ip == MODE_PRIVATE)
1415               newmode &= ~MODE_SECRET;
1416             else if (*ip == MODE_SECRET)
1417               newmode &= ~MODE_PRIVATE;
1418             newmode |= *ip;
1419           }
1420           else
1421             newmode &= ~*ip;
1422         }
1423         else if (!IsServer(cptr))
1424           send_reply(cptr, ERR_UNKNOWNMODE, *curr);
1425         break;
1426     }
1427     curr++;
1428     /*
1429      * Make sure mode strings such as "+m +t +p +i" are parsed
1430      * fully.
1431      */
1432     if (!*curr && parc > 0)
1433     {
1434       curr = *++parv;
1435       parc--;
1436       /* If this was from a server, and it is the last
1437        * parameter and it starts with a digit, it must
1438        * be the creationtime.  --Run
1439        */
1440       if (IsServer(sptr))
1441       {
1442         if (parc == 1 && IsDigit(*curr))
1443         {
1444           newtime = atoi(curr);
1445           if (newtime && chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
1446           {
1447             chptr->creationtime = newtime;
1448             *badop = 0;
1449           }
1450           gotts = 1;
1451           if (newtime == 0)
1452           {
1453             *badop = 2;
1454             hacknotice = 1;
1455           }
1456           else if (newtime > chptr->creationtime)
1457           {                     /* It is a net-break ride if we have ops.
1458                                    bounce modes if we have ops.  --Run */
1459             if (doesdeop)
1460               *badop = 2;
1461             else if (chptr->creationtime == 0)
1462             {
1463               if (chptr->creationtime == 0 || doesop)
1464                 chptr->creationtime = newtime;
1465               *badop = 0;
1466             }
1467             /* Bounce: */
1468             else
1469               *badop = 1;
1470           }
1471           /*
1472            * A legal *badop can occur when two
1473            * people join simultaneously a channel,
1474            * Allow for 10 min of lag (and thus hacking
1475            * on channels younger then 10 min) --Run
1476            */
1477           else if (*badop == 0 ||
1478               chptr->creationtime > (TStime() - TS_LAG_TIME))
1479           {
1480             if (newtime < chptr->creationtime)
1481               chptr->creationtime = newtime;
1482             *badop = 0;
1483           }
1484           break;
1485         }
1486       }
1487       else
1488         *badop = 0;
1489     }
1490   }                             /* end of while loop for MODE processing */
1491
1492 #ifdef OPER_MODE_LCHAN
1493   /*
1494    * Now reject non chan ops. Accept modes from opers on local channels
1495    * even if they are deopped
1496    */
1497   if (!IsServer(cptr) &&
1498       (!member_y || !(IsChanOp(member_y) ||
1499                  IsOperOnLocalChannel(sptr, chptr->chname))))
1500 #else
1501   if (!IsServer(cptr) && (!member_y || !IsChanOp(member_y)))
1502 #endif
1503   {
1504     *badop = 0;
1505     return (opcnt || newmode != mode->mode || limitset || keychange) ? 0 : -1;
1506   }
1507
1508   if (doesop && newtime == 0 && IsServer(sptr))
1509     *badop = 2;
1510
1511   if (*badop >= 2 &&
1512       (aconf = find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)))
1513     *badop = 4;
1514
1515 #ifdef OPER_MODE_LCHAN
1516   bounce = (*badop == 1 || *badop == 2 ||
1517             (is_deopped(sptr, chptr) &&
1518              !IsOperOnLocalChannel(sptr, chptr->chname))) ? 1 : 0;
1519 #else
1520   bounce = (*badop == 1 || *badop == 2 || is_deopped(sptr, chptr)) ? 1 : 0;
1521 #endif
1522
1523   whatt = 0;
1524   for (ip = flags; *ip; ip += 2) {
1525     if ((*ip & newmode) && !(*ip & oldm.mode))
1526     {
1527       if (bounce)
1528       {
1529         if (bwhatt != MODE_DEL)
1530         {
1531           *bmbuf++ = '-';
1532           bwhatt = MODE_DEL;
1533         }
1534         *bmbuf++ = *(ip + 1);
1535       }
1536       else
1537       {
1538         if (whatt != MODE_ADD)
1539         {
1540           *mbuf++ = '+';
1541           whatt = MODE_ADD;
1542         }
1543         mode->mode |= *ip;
1544         *mbuf++ = *(ip + 1);
1545       }
1546     }
1547   }
1548   for (ip = flags; *ip; ip += 2) {
1549     if ((*ip & oldm.mode) && !(*ip & newmode))
1550     {
1551       if (bounce)
1552       {
1553         if (bwhatt != MODE_ADD)
1554         {
1555           *bmbuf++ = '+';
1556           bwhatt = MODE_ADD;
1557         }
1558         *bmbuf++ = *(ip + 1);
1559       }
1560       else
1561       {
1562         if (whatt != MODE_DEL)
1563         {
1564           *mbuf++ = '-';
1565           whatt = MODE_DEL;
1566         }
1567         mode->mode &= ~*ip;
1568         *mbuf++ = *(ip + 1);
1569       }
1570     }
1571   }
1572   blen = nblen = 0;
1573   if (limitset && !nusers && mode->limit)
1574   {
1575     if (bounce)
1576     {
1577       if (bwhatt != MODE_ADD)
1578       {
1579         *bmbuf++ = '+';
1580         bwhatt = MODE_ADD;
1581       }
1582       *bmbuf++ = 'l';
1583       sprintf(numeric, "%-15d", mode->limit);
1584       if ((cp = strchr(numeric, ' ')))
1585         *cp = '\0';
1586       strcat(bpbuf, numeric);
1587       blen += strlen(numeric);
1588       strcat(bpbuf, " ");
1589       strcat(nbpbuf, numeric);
1590       nblen += strlen(numeric);
1591       strcat(nbpbuf, " ");
1592     }
1593     else
1594     {
1595       if (whatt != MODE_DEL)
1596       {
1597         *mbuf++ = '-';
1598         whatt = MODE_DEL;
1599       }
1600       mode->mode &= ~MODE_LIMIT;
1601       mode->limit = 0;
1602       *mbuf++ = 'l';
1603     }
1604   }
1605   /*
1606    * Reconstruct "+bkov" chain.
1607    */
1608   if (opcnt)
1609   {
1610     int i = 0;
1611     char c = 0;
1612     unsigned int prev_whatt = 0;
1613
1614     for (; i < opcnt; i++)
1615     {
1616       lp = &chops[i];
1617       /*
1618        * make sure we have correct mode change sign
1619        */
1620       if (whatt != (lp->flags & (MODE_ADD | MODE_DEL)))
1621       {
1622         if (lp->flags & MODE_ADD)
1623         {
1624           *mbuf++ = '+';
1625           prev_whatt = whatt;
1626           whatt = MODE_ADD;
1627         }
1628         else
1629         {
1630           *mbuf++ = '-';
1631           prev_whatt = whatt;
1632           whatt = MODE_DEL;
1633         }
1634       }
1635       len = strlen(pbuf);
1636       nlen = strlen(npbuf);
1637       /*
1638        * get c as the mode char and tmp as a pointer to
1639        * the parameter for this mode change.
1640        */
1641       switch (lp->flags & MODE_WPARAS)
1642       {
1643         case MODE_CHANOP:
1644           c = 'o';
1645           cp = lp->value.cptr->name;
1646           break;
1647         case MODE_VOICE:
1648           c = 'v';
1649           cp = lp->value.cptr->name;
1650           break;
1651         case MODE_BAN:
1652           /*
1653            * I made this a bit more user-friendly (tm):
1654            * nick = nick!*@*
1655            * nick!user = nick!user@*
1656            * user@host = *!user@host
1657            * host.name = *!*@host.name    --Run
1658            */
1659           c = 'b';
1660           cp = pretty_mask(lp->value.cp);
1661           break;
1662         case MODE_KEY:
1663           c = 'k';
1664           cp = lp->value.cp;
1665           break;
1666         case MODE_LIMIT:
1667           c = 'l';
1668           sprintf(numeric, "%-15d", nusers);
1669           if ((cp = strchr(numeric, ' ')))
1670             *cp = '\0';
1671           cp = numeric;
1672           break;
1673       }
1674
1675       /* What could be added: cp+' '+' '+<TS>+'\0' */
1676       if (len + strlen(cp) + 13 > MODEBUFLEN ||
1677           nlen + strlen(cp) + NUMNICKLEN + 12 > MODEBUFLEN)
1678         break;
1679
1680       switch (lp->flags & MODE_WPARAS)
1681       {
1682         case MODE_KEY:
1683           if (strlen(cp) > KEYLEN)
1684             *(cp + KEYLEN) = '\0';
1685           if ((whatt == MODE_ADD && (*mode->key == '\0' ||
1686                0 != ircd_strcmp(mode->key, cp))) ||
1687               (whatt == MODE_DEL && (*mode->key != '\0')))
1688           {
1689             if (bounce)
1690             {
1691               if (*mode->key == '\0')
1692               {
1693                 if (bwhatt != MODE_DEL)
1694                 {
1695                   *bmbuf++ = '-';
1696                   bwhatt = MODE_DEL;
1697                 }
1698                 strcat(bpbuf, cp);
1699                 blen += strlen(cp);
1700                 strcat(bpbuf, " ");
1701                 blen++;
1702                 strcat(nbpbuf, cp);
1703                 nblen += strlen(cp);
1704                 strcat(nbpbuf, " ");
1705                 nblen++;
1706               }
1707               else
1708               {
1709                 if (bwhatt != MODE_ADD)
1710                 {
1711                   *bmbuf++ = '+';
1712                   bwhatt = MODE_ADD;
1713                 }
1714                 strcat(bpbuf, mode->key);
1715                 blen += strlen(mode->key);
1716                 strcat(bpbuf, " ");
1717                 blen++;
1718                 strcat(nbpbuf, mode->key);
1719                 nblen += strlen(mode->key);
1720                 strcat(nbpbuf, " ");
1721                 nblen++;
1722               }
1723               *bmbuf++ = c;
1724               mbuf--;
1725               if (*mbuf != '+' && *mbuf != '-')
1726                 mbuf++;
1727               else
1728                 whatt = prev_whatt;
1729             }
1730             else
1731             {
1732               *mbuf++ = c;
1733               strcat(pbuf, cp);
1734               len += strlen(cp);
1735               strcat(pbuf, " ");
1736               len++;
1737               strcat(npbuf, cp);
1738               nlen += strlen(cp);
1739               strcat(npbuf, " ");
1740               nlen++;
1741               if (whatt == MODE_ADD)
1742                 ircd_strncpy(mode->key, cp, KEYLEN);
1743               else
1744                 *mode->key = '\0';
1745             }
1746           }
1747           break;
1748         case MODE_LIMIT:
1749           if (nusers && nusers != mode->limit)
1750           {
1751             if (bounce)
1752             {
1753               if (mode->limit == 0)
1754               {
1755                 if (bwhatt != MODE_DEL)
1756                 {
1757                   *bmbuf++ = '-';
1758                   bwhatt = MODE_DEL;
1759                 }
1760               }
1761               else
1762               {
1763                 if (bwhatt != MODE_ADD)
1764                 {
1765                   *bmbuf++ = '+';
1766                   bwhatt = MODE_ADD;
1767                 }
1768                 sprintf(numeric, "%-15d", mode->limit);
1769                 if ((cp = strchr(numeric, ' ')))
1770                   *cp = '\0';
1771                 strcat(bpbuf, numeric);
1772                 blen += strlen(numeric);
1773                 strcat(bpbuf, " ");
1774                 blen++;
1775                 strcat(nbpbuf, numeric);
1776                 nblen += strlen(numeric);
1777                 strcat(nbpbuf, " ");
1778                 nblen++;
1779               }
1780               *bmbuf++ = c;
1781               mbuf--;
1782               if (*mbuf != '+' && *mbuf != '-')
1783                 mbuf++;
1784               else
1785                 whatt = prev_whatt;
1786             }
1787             else
1788             {
1789               *mbuf++ = c;
1790               strcat(pbuf, cp);
1791               len += strlen(cp);
1792               strcat(pbuf, " ");
1793               len++;
1794               strcat(npbuf, cp);
1795               nlen += strlen(cp);
1796               strcat(npbuf, " ");
1797               nlen++;
1798               mode->limit = nusers;
1799             }
1800           }
1801           break;
1802         case MODE_CHANOP:
1803         case MODE_VOICE:
1804           member_y = find_member_link(chptr, lp->value.cptr);
1805           if (lp->flags & MODE_ADD)
1806           {
1807             change = (~member_y->status) & CHFL_VOICED_OR_OPPED & lp->flags;
1808             if (change && bounce)
1809             {
1810               if (lp->flags & MODE_CHANOP)
1811                 SetDeopped(member_y);
1812
1813               if (bwhatt != MODE_DEL)
1814               {
1815                 *bmbuf++ = '-';
1816                 bwhatt = MODE_DEL;
1817               }
1818               *bmbuf++ = c;
1819               strcat(bpbuf, lp->value.cptr->name);
1820               blen += strlen(lp->value.cptr->name);
1821               strcat(bpbuf, " ");
1822               blen++;
1823               sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
1824               nblen += strlen(nbpbuf + nblen);
1825               change = 0;
1826             }
1827             else if (change)
1828             {
1829               member_y->status |= lp->flags & CHFL_VOICED_OR_OPPED;
1830               if (IsChanOp(member_y))
1831               {
1832                 ClearDeopped(member_y);
1833                 if (IsServer(sptr))
1834                   ClearServOpOk(member_y);
1835               }
1836             }
1837           }
1838           else
1839           {
1840             change = member_y->status & CHFL_VOICED_OR_OPPED & lp->flags;
1841             if (change && bounce)
1842             {
1843               if (lp->flags & MODE_CHANOP)
1844                 ClearDeopped(member_y);
1845               if (bwhatt != MODE_ADD)
1846               {
1847                 *bmbuf++ = '+';
1848                 bwhatt = MODE_ADD;
1849               }
1850               *bmbuf++ = c;
1851               strcat(bpbuf, lp->value.cptr->name);
1852               blen += strlen(lp->value.cptr->name);
1853               strcat(bpbuf, " ");
1854               blen++;
1855               sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
1856               blen += strlen(bpbuf + blen);
1857               change = 0;
1858             }
1859             else
1860             {
1861               member_y->status &= ~change;
1862               if ((change & MODE_CHANOP) && IsServer(sptr))
1863                 SetDeopped(member_y);
1864             }
1865           }
1866           if (change || *badop == 2 || *badop == 4)
1867           {
1868             *mbuf++ = c;
1869             strcat(pbuf, cp);
1870             len += strlen(cp);
1871             strcat(pbuf, " ");
1872             len++;
1873             sprintf_irc(npbuf + nlen, "%s%s ", NumNick(lp->value.cptr));
1874             nlen += strlen(npbuf + nlen);
1875             npbuf[nlen++] = ' ';
1876             npbuf[nlen] = 0;
1877           }
1878           else
1879           {
1880             mbuf--;
1881             if (*mbuf != '+' && *mbuf != '-')
1882               mbuf++;
1883             else
1884               whatt = prev_whatt;
1885           }
1886           break;
1887         case MODE_BAN:
1888 /*
1889  * Only bans aren't bounced, it makes no sense to bounce last second
1890  * bans while propagating bans done before the net.rejoin. The reason
1891  * why I don't bounce net.rejoin bans is because it is too much
1892  * work to take care of too long strings adding the necessary TS to
1893  * net.burst bans -- RunLazy
1894  * We do have to check for *badop==2 now, we don't want HACKs to take
1895  * effect.
1896  *
1897  * Since BURST - I *did* implement net.rejoin ban bouncing. So now it
1898  * certainly makes sense to also bounce 'last second' bans (bans done
1899  * after the net.junction). -- RunHardWorker
1900  */
1901           if ((change = (whatt & MODE_ADD) &&
1902               !add_banid(sptr, chptr, cp, !bounce, !add_banid_called)))
1903             add_banid_called = 1;
1904           else
1905             change = (whatt & MODE_DEL) && !del_banid(chptr, cp, !bounce);
1906
1907           if (bounce && change)
1908           {
1909             change = 0;
1910             if ((whatt & MODE_ADD))
1911             {
1912               if (bwhatt != MODE_DEL)
1913               {
1914                 *bmbuf++ = '-';
1915                 bwhatt = MODE_DEL;
1916               }
1917             }
1918             else if ((whatt & MODE_DEL))
1919             {
1920               if (bwhatt != MODE_ADD)
1921               {
1922                 *bmbuf++ = '+';
1923                 bwhatt = MODE_ADD;
1924               }
1925             }
1926             *bmbuf++ = c;
1927             strcat(bpbuf, cp);
1928             blen += strlen(cp);
1929             strcat(bpbuf, " ");
1930             blen++;
1931             strcat(nbpbuf, cp);
1932             nblen += strlen(cp);
1933             strcat(nbpbuf, " ");
1934             nblen++;
1935           }
1936           if (change)
1937           {
1938             *mbuf++ = c;
1939             strcat(pbuf, cp);
1940             len += strlen(cp);
1941             strcat(pbuf, " ");
1942             len++;
1943             strcat(npbuf, cp);
1944             nlen += strlen(cp);
1945             strcat(npbuf, " ");
1946             nlen++;
1947           }
1948           else
1949           {
1950             mbuf--;
1951             if (*mbuf != '+' && *mbuf != '-')
1952               mbuf++;
1953             else
1954               whatt = prev_whatt;
1955           }
1956           break;
1957       }
1958     }                           /* for (; i < opcnt; i++) */
1959   }                             /* if (opcnt) */
1960
1961   *mbuf++ = '\0';
1962   *bmbuf++ = '\0';
1963
1964   /* Bounce here */
1965   if (!hacknotice && *bmodebuf && chptr->creationtime)
1966   {
1967     sendcmdto_one(&me, CMD_MODE, cptr, "%H %s %s %Tu", chptr, bmodebuf,
1968                   nbparambuf, *badop == 2 ? (time_t) 0 : chptr->creationtime);
1969   }
1970   /* If there are possibly bans to re-add, bounce them now */
1971   if (add_banid_called && bounce)
1972   {
1973     struct SLink *ban[6];               /* Max 6 bans at a time */
1974     size_t len[6], sblen, total_len;
1975     int cnt, delayed = 0;
1976     while (delayed || (ban[0] = next_overlapped_ban()))
1977     {
1978       len[0] = strlen(ban[0]->value.ban.banstr);
1979       cnt = 1;                  /* We already got one ban :) */
1980       /* XXX sendbuf used to send ban bounces! */
1981       sblen = sprintf_irc(sendbuf, ":%s MODE %s +b", /* XXX set_mode only called by old m_mode */
1982           me.name, chptr->chname) - sendbuf; /* XXX set_mode only called by old m_mode */
1983       total_len = sblen + 1 + len[0];   /* 1 = ' ' */
1984       /* Find more bans: */
1985       delayed = 0;
1986       while (cnt < 6 && (ban[cnt] = next_overlapped_ban()))
1987       {
1988         len[cnt] = strlen(ban[cnt]->value.ban.banstr);
1989         if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
1990         {
1991           delayed = cnt + 1;    /* != 0 */
1992           break;                /* Flush */
1993         }
1994         sendbuf[sblen++] = 'b'; /* XXX set_mode only called by old m_mode */
1995         total_len += 2 + len[cnt++];    /* 2 = "b " */
1996       }
1997       while (cnt--)
1998       {
1999         sendbuf[sblen++] = ' '; /* XXX set_mode only called by old m_mode */
2000         strcpy(sendbuf + sblen, ban[cnt]->value.ban.banstr); /* XXX set_mode only called by old m_mode */
2001         sblen += len[cnt];
2002       }
2003       sendbufto_one(cptr);      /* Send bounce to uplink */ /* XXX set_mode only called by old m_mode */
2004       if (delayed)
2005         ban[0] = ban[delayed - 1];
2006     }
2007   }
2008   /* Send -b's of overlapped bans to clients to keep them synchronized */
2009   if (add_banid_called && !bounce)
2010   {
2011     struct SLink *ban;
2012     char *banstr[6];            /* Max 6 bans at a time */
2013     size_t len[6], sblen, psblen, total_len;
2014     int cnt, delayed = 0;
2015     struct Membership* member_z;
2016     struct Client *acptr;
2017     if (IsServer(sptr))
2018       /* XXX sendbuf used to send ban bounces! */
2019       psblen = sprintf_irc(sendbuf, ":%s MODE %s -b", /* XXX set_mode only called by old m_mode */
2020           sptr->name, chptr->chname) - sendbuf; /* XXX set_mode only called by old m_mode */
2021     else                        /* We rely on IsRegistered(sptr) being true for MODE */
2022       psblen = sprintf_irc(sendbuf, ":%s!%s@%s MODE %s -b", sptr->name, /* XXX set_mode only called by old m_mode */
2023           sptr->user->username, sptr->user->host, chptr->chname) - sendbuf; /* XXX set_mode only called by old m_mode */
2024     while (delayed || (ban = next_removed_overlapped_ban()))
2025     {
2026       if (!delayed)
2027       {
2028         len[0] = strlen((banstr[0] = ban->value.ban.banstr));
2029         ban->value.ban.banstr = NULL;
2030       }
2031       cnt = 1;                  /* We already got one ban :) */
2032       sblen = psblen;
2033       total_len = sblen + 1 + len[0];   /* 1 = ' ' */
2034       /* Find more bans: */
2035       delayed = 0;
2036       while (cnt < 6 && (ban = next_removed_overlapped_ban()))
2037       {
2038         len[cnt] = strlen((banstr[cnt] = ban->value.ban.banstr));
2039         ban->value.ban.banstr = NULL;
2040         if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
2041         {
2042           delayed = cnt + 1;    /* != 0 */
2043           break;                /* Flush */
2044         }
2045         sendbuf[sblen++] = 'b'; /* XXX set_mode only called by old m_mode */
2046         total_len += 2 + len[cnt++];    /* 2 = "b " */
2047       }
2048       while (cnt--)
2049       {
2050         sendbuf[sblen++] = ' '; /* XXX set_mode only called by old m_mode */
2051         strcpy(sendbuf + sblen, banstr[cnt]); /* XXX set_mode only called by old m_mode */
2052         MyFree(banstr[cnt]);
2053         sblen += len[cnt];
2054       }
2055       for (member_z = chptr->members; member_z; member_z = member_z->next_member) {
2056         acptr = member_z->user;
2057         if (MyConnect(acptr) && !IsZombie(member_z))
2058           sendbufto_one(acptr); /* XXX set_mode only called by old m_mode */
2059       }
2060       if (delayed)
2061       {
2062         banstr[0] = banstr[delayed - 1];
2063         len[0] = len[delayed - 1];
2064       }
2065     }
2066   }
2067
2068   return gotts ? 1 : -1;
2069 }
2070
2071 /* We are now treating the <key> part of /join <channel list> <key> as a key
2072  * ring; that is, we try one key against the actual channel key, and if that
2073  * doesn't work, we try the next one, and so on. -Kev -Texaco
2074  * Returns: 0 on match, 1 otherwise
2075  * This version contributed by SeKs <intru@info.polymtl.ca>
2076  */
2077 static int compall(char *key, char *keyring)
2078 {
2079   char *p1;
2080
2081 top:
2082   p1 = key;                     /* point to the key... */
2083   while (*p1 && *p1 == *keyring)
2084   {                             /* step through the key and ring until they
2085                                    don't match... */
2086     p1++;
2087     keyring++;
2088   }
2089
2090   if (!*p1 && (!*keyring || *keyring == ','))
2091     /* ok, if we're at the end of the and also at the end of one of the keys
2092        in the keyring, we have a match */
2093     return 0;
2094
2095   if (!*keyring)                /* if we're at the end of the key ring, there
2096                                    weren't any matches, so we return 1 */
2097     return 1;
2098
2099   /* Not at the end of the key ring, so step
2100      through to the next key in the ring: */
2101   while (*keyring && *(keyring++) != ',');
2102
2103   goto top;                     /* and check it against the key */
2104 }
2105
2106 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
2107 {
2108   struct SLink *lp;
2109   int overrideJoin = 0;  
2110   
2111   /*
2112    * Now a banned user CAN join if invited -- Nemesi
2113    * Now a user CAN escape channel limit if invited -- bfriendly
2114    * Now a user CAN escape anything if invited -- Isomer
2115    */
2116
2117   for (lp = sptr->user->invited; lp; lp = lp->next)
2118     if (lp->value.chptr == chptr)
2119       return 0;
2120   
2121 #ifdef OPER_WALK_THROUGH_LMODES
2122   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
2123      a HACK(4) notice will be sent if he would not have been supposed
2124      to join normally. */ 
2125   if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && compall("OVERRIDE",key) == 0)
2126   {
2127     overrideJoin = MAGIC_OPER_OVERRIDE;
2128   }
2129 #endif
2130
2131   if (chptr->mode.mode & MODE_INVITEONLY)
2132         return overrideJoin + ERR_INVITEONLYCHAN;
2133         
2134   if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
2135         return overrideJoin + ERR_CHANNELISFULL;
2136         
2137   if (is_banned(sptr, chptr, NULL))
2138         return overrideJoin + ERR_BANNEDFROMCHAN;
2139   
2140   /*
2141    * now using compall (above) to test against a whole key ring -Kev
2142    */
2143   if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
2144     return overrideJoin + ERR_BADCHANNELKEY;
2145
2146   if (overrideJoin)     
2147         return ERR_DONTCHEAT;
2148         
2149   return 0;
2150 }
2151
2152 /*
2153  * Remove bells and commas from channel name
2154  */
2155 void clean_channelname(char *cn)
2156 {
2157   int i;
2158
2159   for (i = 0; cn[i]; i++) {
2160     if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
2161       cn[i] = '\0';
2162       return;
2163     }
2164     if (IsChannelLower(cn[i])) {
2165       cn[i] = ToLower(cn[i]);
2166 #ifndef FIXME
2167       /*
2168        * Remove for .08+
2169        * toupper(0xd0)
2170        */
2171       if ((unsigned char)(cn[i]) == 0xd0)
2172         cn[i] = (char) 0xf0;
2173 #endif
2174     }
2175   }
2176 }
2177
2178 /*
2179  *  Get Channel block for i (and allocate a new channel
2180  *  block, if it didn't exists before).
2181  */
2182 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
2183 {
2184   struct Channel *chptr;
2185   int len;
2186
2187   if (EmptyString(chname))
2188     return NULL;
2189
2190   len = strlen(chname);
2191   if (MyUser(cptr) && len > CHANNELLEN)
2192   {
2193     len = CHANNELLEN;
2194     *(chname + CHANNELLEN) = '\0';
2195   }
2196   if ((chptr = FindChannel(chname)))
2197     return (chptr);
2198   if (flag == CGT_CREATE)
2199   {
2200     chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
2201     assert(0 != chptr);
2202     ++UserStats.channels;
2203     memset(chptr, 0, sizeof(struct Channel));
2204     strcpy(chptr->chname, chname);
2205     if (GlobalChannelList)
2206       GlobalChannelList->prev = chptr;
2207     chptr->prev = NULL;
2208     chptr->next = GlobalChannelList;
2209     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
2210     GlobalChannelList = chptr;
2211     hAddChannel(chptr);
2212   }
2213   return chptr;
2214 }
2215
2216 void add_invite(struct Client *cptr, struct Channel *chptr)
2217 {
2218   struct SLink *inv, **tmp;
2219
2220   del_invite(cptr, chptr);
2221   /*
2222    * Delete last link in chain if the list is max length
2223    */
2224   assert(list_length(cptr->user->invited) == cptr->user->invites);
2225   if (cptr->user->invites>=MAXCHANNELSPERUSER)
2226     del_invite(cptr, cptr->user->invited->value.chptr);
2227   /*
2228    * Add client to channel invite list
2229    */
2230   inv = make_link();
2231   inv->value.cptr = cptr;
2232   inv->next = chptr->invites;
2233   chptr->invites = inv;
2234   /*
2235    * Add channel to the end of the client invite list
2236    */
2237   for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next));
2238   inv = make_link();
2239   inv->value.chptr = chptr;
2240   inv->next = NULL;
2241   (*tmp) = inv;
2242   cptr->user->invites++;
2243 }
2244
2245 /*
2246  * Delete Invite block from channel invite list and client invite list
2247  */
2248 void del_invite(struct Client *cptr, struct Channel *chptr)
2249 {
2250   struct SLink **inv, *tmp;
2251
2252   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
2253     if (tmp->value.cptr == cptr)
2254     {
2255       *inv = tmp->next;
2256       free_link(tmp);
2257       tmp = 0;
2258       cptr->user->invites--;
2259       break;
2260     }
2261
2262   for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
2263     if (tmp->value.chptr == chptr)
2264     {
2265       *inv = tmp->next;
2266       free_link(tmp);
2267       tmp = 0;
2268       break;
2269     }
2270 }
2271
2272 /* List and skip all channels that are listen */
2273 void list_next_channels(struct Client *cptr, int nr)
2274 {
2275   struct ListingArgs *args = cptr->listing;
2276   struct Channel *chptr = args->chptr;
2277   chptr->mode.mode &= ~MODE_LISTED;
2278   while (is_listed(chptr) || --nr >= 0)
2279   {
2280     for (; chptr; chptr = chptr->next)
2281     {
2282       if (!cptr->user || (SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
2283         continue;
2284       if (chptr->users > args->min_users && chptr->users < args->max_users &&
2285           chptr->creationtime > args->min_time &&
2286           chptr->creationtime < args->max_time &&
2287           (!args->topic_limits || (*chptr->topic &&
2288           chptr->topic_time > args->min_topic_time &&
2289           chptr->topic_time < args->max_topic_time)))
2290       {
2291         if (ShowChannel(cptr,chptr))
2292           send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
2293                      chptr->topic);
2294         chptr = chptr->next;
2295         break;
2296       }
2297     }
2298     if (!chptr)
2299     {
2300       MyFree(cptr->listing);
2301       cptr->listing = NULL;
2302       send_reply(cptr, RPL_LISTEND);
2303       break;
2304     }
2305   }
2306   if (chptr)
2307   {
2308     cptr->listing->chptr = chptr;
2309     chptr->mode.mode |= MODE_LISTED;
2310   }
2311 }
2312
2313 /* XXX AIEEEE! sendbuf is an institution here :( */
2314 void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
2315     int *send_itp, char is_a_ban, int mode)
2316 {
2317   int first = *firstp;
2318
2319   /*
2320    * Heh - we do not need to test if it still fits in the buffer, because
2321    * this BURST message is reconstructed from another BURST message, and
2322    * it only can become smaller. --Run
2323    */
2324
2325   if (*firstp)                  /* First token in this parameter ? */
2326   {
2327     *firstp = 0;
2328     if (*send_itp == 0)
2329       *send_itp = 1;            /* Buffer contains data to be sent */
2330     sendbuf[(*sblenp)++] = ' '; /* XXX add_token_to_sendbuf only called by old m_burst */
2331     if (is_a_ban)
2332     {
2333       sendbuf[(*sblenp)++] = ':';       /* Bans are always the last "parv" */ /* XXX add_token_to_sendbuf only called by old m_burst */
2334       sendbuf[(*sblenp)++] = is_a_ban; /* XXX add_token_to_sendbuf only called by old m_burst */
2335     }
2336   }
2337   else                          /* Of course, 'send_it' is already set here */
2338     /* Seperate banmasks with a space because
2339        they can contain commas themselfs: */
2340     sendbuf[(*sblenp)++] = is_a_ban ? ' ' : ','; /* XXX add_token_to_sendbuf only called by old m_burst */
2341   strcpy(sendbuf + *sblenp, token); /* XXX add_token_to_sendbuf only called by old m_burst */
2342   *sblenp += strlen(token);
2343   if (!is_a_ban)                /* nick list ? Need to take care
2344                                    of modes for nicks: */
2345   {
2346     static int last_mode = 0;
2347     mode &= CHFL_CHANOP | CHFL_VOICE;
2348     if (first)
2349       last_mode = 0;
2350     if (last_mode != mode)      /* Append mode like ':ov' if changed */
2351     {
2352       last_mode = mode;
2353       sendbuf[(*sblenp)++] = ':'; /* XXX add_token_to_sendbuf only called by old m_burst */
2354       if (mode & CHFL_CHANOP)
2355         sendbuf[(*sblenp)++] = 'o'; /* XXX add_token_to_sendbuf only called by old m_burst */
2356       if (mode & CHFL_VOICE)
2357         sendbuf[(*sblenp)++] = 'v'; /* XXX add_token_to_sendbuf only called by old m_burst */
2358     }
2359     sendbuf[*sblenp] = '\0'; /* XXX add_token_to_sendbuf only called by old m_burst */
2360   }
2361 }
2362
2363 void cancel_mode(struct Client *sptr, struct Channel *chptr, char m,
2364                         const char *param, int *count)
2365 {
2366   static char* pb;
2367   static char* sbp;
2368   static char* sbpi;
2369   int          paramdoesntfit = 0;
2370   char parabuf[MODEBUFLEN];
2371
2372   assert(0 != sptr);
2373   assert(0 != chptr);
2374   assert(0 != count);
2375   
2376   if (*count == -1)             /* initialize ? */
2377   {
2378     /* XXX sendbuf used! */
2379     sbp = sbpi =
2380         sprintf_irc(sendbuf, ":%s MODE %s -", sptr->name, chptr->chname); /* XXX cancel_mode only called from old ms_burst */
2381     pb = parabuf;
2382     *count = 0;
2383   }
2384   /* m == 0 means flush */
2385   if (m)
2386   {
2387     if (param)
2388     {
2389       size_t nplen = strlen(param);
2390       if (pb - parabuf + nplen + 23 > MODEBUFLEN)
2391         paramdoesntfit = 1;
2392       else
2393       {
2394         *sbp++ = m;
2395         *pb++ = ' ';
2396         strcpy(pb, param);
2397         pb += nplen;
2398         ++*count;
2399       }
2400     }
2401     else
2402       *sbp++ = m;
2403   }
2404   else if (*count == 0)
2405     return;
2406   if (*count == 6 || !m || paramdoesntfit)
2407   {
2408     struct Membership* member;
2409     strcpy(sbp, parabuf);
2410     for (member = chptr->members; member; member = member->next_member)
2411       if (MyUser(member->user))
2412         sendbufto_one(member->user); /* XXX cancel_mode only called from old ms_burst */
2413     sbp = sbpi;
2414     pb = parabuf;
2415     *count = 0;
2416   }
2417   if (paramdoesntfit)
2418   {
2419     *sbp++ = m;
2420     *pb++ = ' ';
2421     strcpy(pb, param);
2422     pb += strlen(param);
2423     ++*count;
2424   }
2425 }
2426
2427
2428 /*
2429  * Consider:
2430  *
2431  *                     client
2432  *                       |
2433  *                       c
2434  *                       |
2435  *     X --a--> A --b--> B --d--> D
2436  *                       |
2437  *                      who
2438  *
2439  * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
2440  * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
2441  *
2442  * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
2443  *    Remove the user immedeately when no users are left on the channel.
2444  * b) On server B : remove the user (who/lp) from the channel, send a
2445  *    PART upstream (to A) and pass on the KICK.
2446  * c) KICKed by `client'; On server B : remove the user (who/lp) from the
2447  *    channel, and pass on the KICK.
2448  * d) On server D : remove the user (who/lp) from the channel, and pass on
2449  *    the KICK.
2450  *
2451  * Note:
2452  * - Setting the ZOMBIE flag never hurts, we either remove the
2453  *   client after that or we don't.
2454  * - The KICK message was already passed on, as should be in all cases.
2455  * - `who' is removed in all cases except case a) when users are left.
2456  * - A PART is only sent upstream in case b).
2457  *
2458  * 2 aug 97:
2459  *
2460  *              6
2461  *              |
2462  *  1 --- 2 --- 3 --- 4 --- 5
2463  *        |           |
2464  *      kicker       who
2465  *
2466  * We also need to turn 'who' into a zombie on servers 1 and 6,
2467  * because a KICK from 'who' (kicking someone else in that direction)
2468  * can arrive there afterwards - which should not be bounced itself.
2469  * Therefore case a) also applies for servers 1 and 6.
2470  *
2471  * --Run
2472  */
2473 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
2474                  struct Client* sptr, struct Channel* chptr)
2475 {
2476   assert(0 != member);
2477   assert(0 != who);
2478   assert(0 != cptr);
2479   assert(0 != chptr);
2480
2481   /* Default for case a): */
2482   SetZombie(member);
2483
2484   /* Case b) or c) ?: */
2485   if (MyUser(who))      /* server 4 */
2486   {
2487     if (IsServer(cptr)) /* Case b) ? */
2488       sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
2489     remove_user_from_channel(who, chptr);
2490     return;
2491   }
2492   if (who->from == cptr)        /* True on servers 1, 5 and 6 */
2493   {
2494     struct Client *acptr = IsServer(sptr) ? sptr : sptr->user->server;
2495     for (; acptr != &me; acptr = acptr->serv->up)
2496       if (acptr == who->user->server)   /* Case d) (server 5) */
2497       {
2498         remove_user_from_channel(who, chptr);
2499         return;
2500       }
2501   }
2502
2503   /* Case a) (servers 1, 2, 3 and 6) */
2504   if (channel_all_zombies(chptr))
2505     remove_user_from_channel(who, chptr);
2506
2507   /* XXX Can't actually call Debug here; if the channel is all zombies,
2508    * chptr will no longer exist when we get here.
2509   Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
2510   */
2511 }
2512
2513 int number_of_zombies(struct Channel *chptr)
2514 {
2515   struct Membership* member;
2516   int                count = 0;
2517
2518   assert(0 != chptr);
2519   for (member = chptr->members; member; member = member->next_member) {
2520     if (IsZombie(member))
2521       ++count;
2522   }
2523   return count;
2524 }
2525
2526 /*
2527  * send_hack_notice()
2528  *
2529  * parc & parv[] are the same as that of the calling function:
2530  *   mtype == 1 is from m_mode, 2 is from m_create, 3 is from m_kick.
2531  *
2532  * This function prepares sendbuf with the server notices and wallops
2533  *   to be sent for all hacks.  -Ghostwolf 18-May-97
2534  */
2535 /* XXX let's get rid of this if we can */
2536 void send_hack_notice(struct Client *cptr, struct Client *sptr, int parc,
2537                       char *parv[], int badop, int mtype)
2538 {
2539   struct Channel *chptr;
2540   static char params[MODEBUFLEN];
2541   int i = 3;
2542   chptr = FindChannel(parv[1]);
2543   *params = '\0';
2544
2545   /* P10 servers require numeric nick conversion before sending. */
2546   switch (mtype)
2547   {
2548     case 1:                     /* Convert nicks for MODE HACKs here  */
2549     {
2550       char *mode = parv[2];
2551       while (i < parc)
2552       {
2553         while (*mode && *mode != 'o' && *mode != 'v')
2554           ++mode;
2555         strcat(params, " ");
2556         if (*mode == 'o' || *mode == 'v')
2557         {
2558           /*
2559            * blindly stumble through parameter list hoping one of them
2560            * might turn out to be a numeric nick
2561            * NOTE: this should not cause a problem but _may_ end up finding
2562            * something we aren't looking for. findNUser should be able to
2563            * handle any garbage that is thrown at it, but may return a client
2564            * if we happen to get lucky with a mode string or a timestamp
2565            */
2566           struct Client *acptr;
2567           if ((acptr = findNUser(parv[i])) != NULL)     /* Convert nicks here */
2568             strcat(params, acptr->name);
2569           else
2570           {
2571             strcat(params, "<");
2572             strcat(params, parv[i]);
2573             strcat(params, ">");
2574           }
2575         }
2576         else                    /* If it isn't a numnick, send it 'as is' */
2577           strcat(params, parv[i]);
2578         i++;
2579       }
2580       sprintf_irc(sendbuf, /* XXX send_hack_notice only called from old m_mode */
2581           ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s ["
2582           TIME_T_FMT "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop,
2583           parv[0], parv[1], parv[2], params, chptr->creationtime);
2584       sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop == /* XXX DYING */ /* XXX send_hack_notice only called from old m_mode */
2585           4) ? SNO_HACK4 : SNO_HACK2);
2586
2587       if ((IsServer(sptr)) && (badop == 2))
2588       {
2589         sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s", /* XXX send_hack_notice only called from old m_mode */
2590             me.name, parv[0], parv[1], parv[2], params);
2591         sendbufto_serv_butone(cptr); /* XXX DYING */ /* XXX send_hack_notice only called from old m_mode */
2592       }
2593       break;
2594     }
2595     case 2:                     /* No conversion is needed for CREATE; the only numnick is sptr */
2596     {
2597       sendto_serv_butone(cptr, ":%s DESYNCH :HACK: %s CREATE %s %s", /* XXX DYING */
2598           me.name, sptr->name, chptr->chname, parv[2]);
2599       sendto_op_mask(SNO_HACK2, "HACK(2): %s CREATE %s %s", /* XXX DYING */
2600           sptr->name, chptr->chname, parv[2]);
2601       break;
2602     }
2603     case 3:                     /* Convert nick in KICK message */
2604     {
2605       struct Client *acptr;
2606       if ((acptr = findNUser(parv[2])) != NULL) /* attempt to convert nick */
2607         sprintf_irc(sendbuf, /* XXX send_hack_notice only called from old m_mode */
2608             ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
2609             me.name, sptr->name, parv[1], acptr->name, parv[3]);
2610       else                      /* if conversion fails, send it 'as is' in <>'s */
2611         sprintf_irc(sendbuf, /* XXX send_hack_notice only called from old m_mode */
2612             ":%s NOTICE * :*** Notice -- HACK: %s KICK %s <%s> :%s",
2613             me.name, sptr->name, parv[1], parv[2], parv[3]);
2614       sendbufto_op_mask(SNO_HACK4); /* XXX DYING */ /* XXX send_hack_notice only called from old m_mode */
2615       break;
2616     }
2617   }
2618 }
2619
2620 /*
2621  * This helper function builds an argument string in strptr, consisting
2622  * of the original string, a space, and str1 and str2 concatenated (if,
2623  * of course, str2 is not NULL)
2624  */
2625 static void
2626 build_string(char *strptr, int *strptr_i, char *str1, char *str2, char c)
2627 {
2628   if (c)
2629     strptr[(*strptr_i)++] = c;
2630
2631   while (*str1)
2632     strptr[(*strptr_i)++] = *(str1++);
2633
2634   if (str2)
2635     while (*str2)
2636       strptr[(*strptr_i)++] = *(str2++);
2637
2638   strptr[(*strptr_i)] = '\0';
2639 }
2640
2641 /*
2642  * This is the workhorse of our ModeBuf suite; this actually generates the
2643  * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
2644  */
2645 static int
2646 modebuf_flush_int(struct ModeBuf *mbuf, int all)
2647 {
2648   /* we only need the flags that don't take args right now */
2649   static int flags[] = {
2650 /*  MODE_CHANOP,        'o', */
2651 /*  MODE_VOICE,         'v', */
2652     MODE_PRIVATE,       'p',
2653     MODE_SECRET,        's',
2654     MODE_MODERATED,     'm',
2655     MODE_TOPICLIMIT,    't',
2656     MODE_INVITEONLY,    'i',
2657     MODE_NOPRIVMSGS,    'n',
2658 /*  MODE_KEY,           'k', */
2659 /*  MODE_BAN,           'b', */
2660 /*  MODE_LIMIT,         'l', */
2661     0x0, 0x0
2662   };
2663   int i;
2664   int *flag_p;
2665
2666   struct Client *app_source; /* where the MODE appears to come from */
2667
2668   char addbuf[20]; /* accumulates +psmtin, etc. */
2669   int addbuf_i = 0;
2670   char rembuf[20]; /* accumulates -psmtin, etc. */
2671   int rembuf_i = 0;
2672   char *bufptr; /* we make use of indirection to simplify the code */
2673   int *bufptr_i;
2674
2675   char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
2676   int addstr_i;
2677   char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
2678   int remstr_i;
2679   char *strptr; /* more indirection to simplify the code */
2680   int *strptr_i;
2681
2682   int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
2683   int tmp;
2684
2685   char limitbuf[20]; /* convert limits to strings */
2686
2687   unsigned int limitdel = MODE_LIMIT;
2688
2689   assert(0 != mbuf);
2690
2691   /* If the ModeBuf is empty, we have nothing to do */
2692   if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
2693     return 0;
2694
2695   /* Ok, if we were given the OPMODE flag, hide the source if its a user */
2696   if (mbuf->mb_dest & MODEBUF_DEST_OPMODE && !IsServer(mbuf->mb_source))
2697     app_source = mbuf->mb_source->user->server;
2698   else
2699     app_source = mbuf->mb_source;
2700
2701   /*
2702    * Account for user we're bouncing; we have to get it in on the first
2703    * bounced MODE, or we could have problems
2704    */
2705   if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
2706     totalbuflen -= 6; /* numeric nick == 5, plus one space */
2707
2708   /* Calculate the simple flags */
2709   for (flag_p = flags; flag_p[0]; flag_p += 2) {
2710     if (*flag_p & mbuf->mb_add)
2711       addbuf[addbuf_i++] = flag_p[1];
2712     else if (*flag_p & mbuf->mb_rem)
2713       rembuf[rembuf_i++] = flag_p[1];
2714   }
2715
2716   /* Now go through the modes with arguments... */
2717   for (i = 0; i < mbuf->mb_count; i++) {
2718     if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2719       bufptr = addbuf;
2720       bufptr_i = &addbuf_i;
2721     } else {
2722       bufptr = rembuf;
2723       bufptr_i = &rembuf_i;
2724     }
2725
2726     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
2727       tmp = strlen(MB_CLIENT(mbuf, i)->name);
2728
2729       if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
2730         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
2731       else {
2732         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
2733         totalbuflen -= IRCD_MAX(5, tmp) + 1;
2734       }
2735     } else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN)) {
2736       tmp = strlen(MB_STRING(mbuf, i));
2737
2738       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
2739         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
2740       else {
2741         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_KEY ? 'k' : 'b';
2742         totalbuflen -= tmp + 1;
2743       }
2744     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
2745       /* if it's a limit, we also format the number */
2746       sprintf_irc(limitbuf, "%d", MB_UINT(mbuf, i));
2747
2748       tmp = strlen(limitbuf);
2749
2750       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
2751         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
2752       else {
2753         bufptr[(*bufptr_i)++] = 'l';
2754         totalbuflen -= tmp + 1;
2755       }
2756     }
2757   }
2758
2759   /* terminate the mode strings */
2760   addbuf[addbuf_i] = '\0';
2761   rembuf[rembuf_i] = '\0';
2762
2763   /* If we're building a user visible MODE or HACK... */
2764   if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
2765                        MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
2766                        MODEBUF_DEST_LOG)) {
2767     /* Set up the parameter strings */
2768     addstr[0] = '\0';
2769     addstr_i = 0;
2770     remstr[0] = '\0';
2771     remstr_i = 0;
2772
2773     for (i = 0; i < mbuf->mb_count; i++) {
2774       if (MB_TYPE(mbuf, i) & MODE_SAVE)
2775         continue;
2776
2777       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2778         strptr = addstr;
2779         strptr_i = &addstr_i;
2780       } else {
2781         strptr = remstr;
2782         strptr_i = &remstr_i;
2783       }
2784
2785       /* deal with clients... */
2786       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2787         build_string(strptr, strptr_i, MB_CLIENT(mbuf, i)->name, 0, ' ');
2788
2789       /* deal with strings... */
2790       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN))
2791         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2792
2793       /*
2794        * deal with limit; note we cannot include the limit parameter if we're
2795        * removing it
2796        */
2797       else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
2798                (MODE_ADD | MODE_LIMIT))
2799         build_string(strptr, strptr_i, limitbuf, 0, ' ');
2800     }
2801
2802     /* send the messages off to their destination */
2803     if (mbuf->mb_dest & MODEBUF_DEST_HACK2) {
2804       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
2805                            "[%Tu]", app_source->name, mbuf->mb_channel->chname,
2806                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2807                            addbuf, remstr, addstr,
2808                            mbuf->mb_channel->creationtime);
2809       sendcmdto_serv_butone(&me, CMD_DESYNCH, mbuf->mb_connect,
2810                             ":HACK: %s MODE %s %s%s%s%s%s%s [%Tu]",
2811                             app_source->name, mbuf->mb_channel->chname,
2812                             rembuf_i ? "-" : "", rembuf,
2813                             addbuf_i ? "+" : "", addbuf, remstr, addstr,
2814                             mbuf->mb_channel->creationtime);
2815     }
2816
2817     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
2818       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
2819                            "%s%s%s%s%s%s [%Tu]", app_source->name,
2820                            mbuf->mb_channel->chname, rembuf_i ? "-" : "",
2821                            rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
2822                            mbuf->mb_channel->creationtime);
2823
2824     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
2825       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
2826                            "[%Tu]", app_source->name, mbuf->mb_channel->chname,
2827                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2828                            addbuf, remstr, addstr,
2829                            mbuf->mb_channel->creationtime);
2830
2831 #ifdef OPATH
2832     if (mbuf->mb_dest & MODEBUF_DEST_LOG) {
2833       write_log(OPATH, "%Tu %#C OPMODE %H %s%s%s%s%s%s\n", TStime(),
2834                 mbuf->mb_source, mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
2835                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2836     }
2837 #endif
2838
2839     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
2840       sendcmdto_channel_butserv(app_source, CMD_MODE, mbuf->mb_channel,
2841                                 "%H %s%s%s%s%s%s", mbuf->mb_channel,
2842                                 rembuf_i ? "-" : "", rembuf,
2843                                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
2844   }
2845
2846   /* Now are we supposed to propagate to other servers? */
2847   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
2848     /* set up parameter string */
2849     addstr[0] = '\0';
2850     addstr_i = 0;
2851     remstr[0] = '\0';
2852     remstr_i = 0;
2853
2854     /*
2855      * limit is supressed if we're removing it; we have to figure out which
2856      * direction is the direction for it to be removed, though...
2857      */
2858     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
2859
2860     for (i = 0; i < mbuf->mb_count; i++) {
2861       if (MB_TYPE(mbuf, i) & MODE_SAVE)
2862         continue;
2863
2864       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
2865         strptr = addstr;
2866         strptr_i = &addstr_i;
2867       } else {
2868         strptr = remstr;
2869         strptr_i = &remstr_i;
2870       }
2871
2872       /* deal with modes that take clients */
2873       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
2874         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
2875
2876       /* deal with modes that take strings */
2877       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN))
2878         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
2879
2880       /*
2881        * deal with the limit.  Logic here is complicated; if HACK2 is set,
2882        * we're bouncing the mode, so sense is reversed, and we have to
2883        * include the original limit if it looks like it's being removed
2884        */
2885       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
2886         build_string(strptr, strptr_i, limitbuf, 0, ' ');
2887     }
2888
2889     /* we were told to deop the source */
2890     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
2891       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
2892       addbuf[addbuf_i] = '\0'; /* terminate the string... */
2893       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
2894
2895       /* mark that we've done this, so we don't do it again */
2896       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
2897     }
2898
2899     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
2900       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
2901       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
2902                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
2903                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2904                             addbuf, remstr, addstr);
2905     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
2906       /*
2907        * If HACK2 was set, we're bouncing; we send the MODE back to the
2908        * connection we got it from with the senses reversed and a TS of 0;
2909        * origin is us
2910        */
2911       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
2912                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
2913                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
2914                     mbuf->mb_channel->creationtime);
2915     } else {
2916       /*
2917        * We're propagating a normal MODE command to the rest of the network;
2918        * we send the actual channel TS unless this is a HACK3 or a HACK4
2919        */
2920       if (IsServer(mbuf->mb_source))
2921         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2922                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
2923                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2924                               addbuf, remstr, addstr,
2925                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
2926                               mbuf->mb_channel->creationtime);
2927       else
2928         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
2929                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
2930                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
2931                               addbuf, remstr, addstr);
2932     }
2933   }
2934
2935   /* We've drained the ModeBuf... */
2936   mbuf->mb_add = 0;
2937   mbuf->mb_rem = 0;
2938   mbuf->mb_count = 0;
2939
2940   /* reinitialize the mode-with-arg slots */
2941   for (i = 0; i < MAXMODEPARAMS; i++) {
2942     /* If we saved any, pack them down */
2943     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
2944       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
2945       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
2946
2947       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
2948         continue;
2949     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
2950       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
2951
2952     MB_TYPE(mbuf, i) = 0;
2953     MB_UINT(mbuf, i) = 0;
2954   }
2955
2956   /* If we're supposed to flush it all, do so--all hail tail recursion */
2957   if (all && mbuf->mb_count)
2958     return modebuf_flush_int(mbuf, 1);
2959
2960   return 0;
2961 }
2962
2963 /*
2964  * This routine just initializes a ModeBuf structure with the information
2965  * needed and the options given.
2966  */
2967 void
2968 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
2969              struct Client *connect, struct Channel *chan, unsigned int dest)
2970 {
2971   int i;
2972
2973   assert(0 != mbuf);
2974   assert(0 != source);
2975   assert(0 != chan);
2976   assert(0 != dest);
2977
2978   mbuf->mb_add = 0;
2979   mbuf->mb_rem = 0;
2980   mbuf->mb_source = source;
2981   mbuf->mb_connect = connect;
2982   mbuf->mb_channel = chan;
2983   mbuf->mb_dest = dest;
2984   mbuf->mb_count = 0;
2985
2986   /* clear each mode-with-parameter slot */
2987   for (i = 0; i < MAXMODEPARAMS; i++) {
2988     MB_TYPE(mbuf, i) = 0;
2989     MB_UINT(mbuf, i) = 0;
2990   }
2991 }
2992
2993 /*
2994  * This routine simply adds modes to be added or deleted; do a binary OR
2995  * with either MODE_ADD or MODE_DEL
2996  */
2997 void
2998 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
2999 {
3000   assert(0 != mbuf);
3001   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
3002
3003   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
3004            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS);
3005
3006   if (mode & MODE_ADD) {
3007     mbuf->mb_rem &= ~mode;
3008     mbuf->mb_add |= mode;
3009   } else {
3010     mbuf->mb_add &= ~mode;
3011     mbuf->mb_rem |= mode;
3012   }
3013 }
3014
3015 /*
3016  * This routine adds a mode to be added or deleted that takes a unsigned
3017  * int parameter; mode may *only* be the relevant mode flag ORed with one
3018  * of MODE_ADD or MODE_DEL
3019  */
3020 void
3021 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
3022 {
3023   assert(0 != mbuf);
3024   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
3025
3026   MB_TYPE(mbuf, mbuf->mb_count) = mode;
3027   MB_UINT(mbuf, mbuf->mb_count) = uint;
3028
3029   /* when we've reached the maximal count, flush the buffer */
3030   if (++mbuf->mb_count >=
3031       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
3032     modebuf_flush_int(mbuf, 0);
3033 }
3034
3035 /*
3036  * This routine adds a mode to be added or deleted that takes a string
3037  * parameter; mode may *only* be the relevant mode flag ORed with one of
3038  * MODE_ADD or MODE_DEL
3039  */
3040 void
3041 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
3042                     int free)
3043 {
3044   assert(0 != mbuf);
3045   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
3046
3047   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
3048   MB_STRING(mbuf, mbuf->mb_count) = string;
3049
3050   /* when we've reached the maximal count, flush the buffer */
3051   if (++mbuf->mb_count >=
3052       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
3053     modebuf_flush_int(mbuf, 0);
3054 }
3055
3056 /*
3057  * This routine adds a mode to be added or deleted that takes a client
3058  * parameter; mode may *only* be the relevant mode flag ORed with one of
3059  * MODE_ADD or MODE_DEL
3060  */
3061 void
3062 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
3063                     struct Client *client)
3064 {
3065   assert(0 != mbuf);
3066   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
3067
3068   MB_TYPE(mbuf, mbuf->mb_count) = mode;
3069   MB_CLIENT(mbuf, mbuf->mb_count) = client;
3070
3071   /* when we've reached the maximal count, flush the buffer */
3072   if (++mbuf->mb_count >=
3073       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
3074     modebuf_flush_int(mbuf, 0);
3075 }
3076
3077 /*
3078  * This is the exported binding for modebuf_flush()
3079  */
3080 int
3081 modebuf_flush(struct ModeBuf *mbuf)
3082 {
3083   return modebuf_flush_int(mbuf, 1);
3084 }
3085
3086 /*
3087  * This extracts the simple modes contained in mbuf
3088  */
3089 void
3090 modebuf_extract(struct ModeBuf *mbuf, char *buf)
3091 {
3092   static int flags[] = {
3093 /*  MODE_CHANOP,        'o', */
3094 /*  MODE_VOICE,         'v', */
3095     MODE_PRIVATE,       'p',
3096     MODE_SECRET,        's',
3097     MODE_MODERATED,     'm',
3098     MODE_TOPICLIMIT,    't',
3099     MODE_INVITEONLY,    'i',
3100     MODE_NOPRIVMSGS,    'n',
3101     MODE_KEY,           'k',
3102 /*  MODE_BAN,           'b', */
3103     MODE_LIMIT,         'l',
3104     0x0, 0x0
3105   };
3106   unsigned int add;
3107   int i, bufpos = 0, len;
3108   int *flag_p;
3109   char *key = 0, limitbuf[20];
3110
3111   assert(0 != mbuf);
3112   assert(0 != buf);
3113
3114   buf[0] = '\0';
3115
3116   add = mbuf->mb_add;
3117
3118   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
3119     if (MB_TYPE(mbuf, i) & MODE_ADD) {
3120       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT);
3121
3122       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
3123         key = MB_STRING(mbuf, i);
3124       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
3125         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%d", MB_UINT(mbuf, i));
3126     }
3127   }
3128
3129   if (!add)
3130     return;
3131
3132   buf[bufpos++] = '+'; /* start building buffer */
3133
3134   for (flag_p = flags; flag_p[0]; flag_p += 2)
3135     if (*flag_p & add)
3136       buf[bufpos++] = flag_p[1];
3137
3138   for (i = 0, len = bufpos; i < len; i++) {
3139     if (buf[i] == 'k')
3140       build_string(buf, &bufpos, key, 0, ' ');
3141     else if (buf[i] == 'l')
3142       build_string(buf, &bufpos, limitbuf, 0, ' ');
3143   }
3144
3145   buf[bufpos] = '\0';
3146
3147   return;
3148 }
3149
3150 /*
3151  * Simple function to invalidate bans
3152  */
3153 void
3154 mode_ban_invalidate(struct Channel *chan)
3155 {
3156   struct Membership *member;
3157
3158   for (member = chan->members; member; member = member->next_member)
3159     ClearBanValid(member);
3160 }
3161
3162 /*
3163  * Simple function to drop invite structures
3164  */
3165 void
3166 mode_invite_clear(struct Channel *chan)
3167 {
3168   while (chan->invites)
3169     del_invite(chan->invites->value.cptr, chan);
3170 }
3171
3172 /* What we've done for mode_parse so far... */
3173 #define DONE_LIMIT      0x01    /* We've set the limit */
3174 #define DONE_KEY        0x02    /* We've set the key */
3175 #define DONE_BANLIST    0x04    /* We've sent the ban list */
3176 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
3177 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
3178
3179 struct ParseState {
3180   struct ModeBuf *mbuf;
3181   struct Client *cptr;
3182   struct Client *sptr;
3183   struct Channel *chptr;
3184   int parc;
3185   char **parv;
3186   unsigned int flags;
3187   unsigned int dir;
3188   unsigned int done;
3189   unsigned int add;
3190   unsigned int del;
3191   int args_used;
3192   int max_args;
3193   int numbans;
3194   struct SLink banlist[MAXPARA];
3195   struct {
3196     unsigned int flag;
3197     struct Client *client;
3198   } cli_change[MAXPARA];
3199 };
3200
3201 /*
3202  * Here's a helper function to deal with sending along "Not oper" or
3203  * "Not member" messages
3204  */
3205 static void
3206 send_notoper(struct ParseState *state)
3207 {
3208   if (state->done & DONE_NOTOPER)
3209     return;
3210
3211   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
3212              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
3213
3214   state->done |= DONE_NOTOPER;
3215 }
3216
3217 /*
3218  * Helper function to convert limits
3219  */
3220 static void
3221 mode_parse_limit(struct ParseState *state, int *flag_p)
3222 {
3223   unsigned int t_limit;
3224
3225   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
3226     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
3227       return;
3228
3229     if (state->parc <= 0) { /* warn if not enough args */
3230       if (MyUser(state->sptr))
3231         need_more_params(state->sptr, "MODE +l");
3232       return;
3233     }
3234
3235     t_limit = atoi(state->parv[state->args_used++]); /* grab arg */
3236     state->parc--;
3237     state->max_args--;
3238
3239     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
3240         (!t_limit || t_limit == state->chptr->mode.limit))
3241       return;
3242   } else
3243     t_limit = state->chptr->mode.limit;
3244
3245   /* If they're not an oper, they can't change modes */
3246   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3247     send_notoper(state);
3248     return;
3249   }
3250
3251   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
3252     return;
3253   state->done |= DONE_LIMIT;
3254
3255   if (!state->mbuf)
3256     return;
3257
3258   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
3259
3260   if (state->flags & MODE_PARSE_SET) { /* set the limit */
3261     if (state->dir & MODE_ADD) {
3262       state->chptr->mode.mode |= flag_p[0];
3263       state->chptr->mode.limit = t_limit;
3264     } else {
3265       state->chptr->mode.mode &= ~flag_p[0];
3266       state->chptr->mode.limit = 0;
3267     }
3268   }
3269 }
3270
3271 /*
3272  * Helper function to convert keys
3273  */
3274 static void
3275 mode_parse_key(struct ParseState *state, int *flag_p)
3276 {
3277   char *t_str, *s;
3278   int t_len;
3279
3280   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3281     return;
3282
3283   if (state->parc <= 0) { /* warn if not enough args */
3284     if (MyUser(state->sptr))
3285       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
3286                        "MODE -k");
3287     return;
3288   }
3289
3290   t_str = state->parv[state->args_used++]; /* grab arg */
3291   state->parc--;
3292   state->max_args--;
3293
3294   /* If they're not an oper, they can't change modes */
3295   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3296     send_notoper(state);
3297     return;
3298   }
3299
3300   if (state->done & DONE_KEY) /* allow key to be set only once */
3301     return;
3302   state->done |= DONE_KEY;
3303
3304   t_len = KEYLEN + 1;
3305
3306   /* clean up the key string */
3307   s = t_str;
3308   while (*++s > ' ' && *s != ':' && --t_len)
3309     ;
3310   *s = '\0';
3311
3312   if (!*t_str) { /* warn if empty */
3313     if (MyUser(state->sptr))
3314       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
3315                        "MODE -k");
3316     return;
3317   }
3318
3319   if (!state->mbuf)
3320     return;
3321
3322   /* can't add a key if one is set, nor can one remove the wrong key */
3323   if (!(state->flags & MODE_PARSE_FORCE))
3324     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
3325         (state->dir == MODE_DEL &&
3326          ircd_strcmp(state->chptr->mode.key, t_str))) {
3327       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
3328       return;
3329     }
3330
3331   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
3332       !ircd_strcmp(state->chptr->mode.key, t_str))
3333     return; /* no key change */
3334
3335   if (state->flags & MODE_PARSE_BOUNCE) {
3336     if (*state->chptr->mode.key) /* reset old key */
3337       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
3338                           state->chptr->mode.key, 0);
3339     else /* remove new bogus key */
3340       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
3341   } else /* send new key */
3342     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
3343
3344   if (state->flags & MODE_PARSE_SET) {
3345     if (state->dir == MODE_ADD) /* set the new key */
3346       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
3347     else /* remove the old key */
3348       *state->chptr->mode.key = '\0';
3349   }
3350 }
3351
3352 /*
3353  * Helper function to convert bans
3354  */
3355 static void
3356 mode_parse_ban(struct ParseState *state, int *flag_p)
3357 {
3358   char *t_str, *s;
3359   struct SLink *ban, *newban = 0;
3360
3361   if (state->parc <= 0) { /* Not enough args, send ban list */
3362     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
3363       send_ban_list(state->sptr, state->chptr);
3364       state->done |= DONE_BANLIST;
3365     }
3366
3367     return;
3368   }
3369
3370   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3371     return;
3372
3373   t_str = state->parv[state->args_used++]; /* grab arg */
3374   state->parc--;
3375   state->max_args--;
3376
3377   /* If they're not an oper, they can't change modes */
3378   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3379     send_notoper(state);
3380     return;
3381   }
3382
3383   if ((s = strchr(t_str, ' ')))
3384     *s = '\0';
3385
3386   if (!*t_str || *t_str == ':') { /* warn if empty */
3387     if (MyUser(state->sptr))
3388       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
3389                        "MODE -b");
3390     return;
3391   }
3392
3393   t_str = collapse(pretty_mask(t_str));
3394
3395   /* remember the ban for the moment... */
3396   if (state->dir == MODE_ADD) {
3397     newban = state->banlist + (state->numbans++);
3398     newban->next = 0;
3399
3400     DupString(newban->value.ban.banstr, t_str);
3401     newban->value.ban.who = state->sptr->name;
3402     newban->value.ban.when = TStime();
3403
3404     newban->flags = CHFL_BAN | MODE_ADD;
3405
3406     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
3407       newban->flags |= CHFL_BAN_IPMASK;
3408   }
3409
3410   if (!state->chptr->banlist) {
3411     state->chptr->banlist = newban; /* add our ban with its flags */
3412     state->done |= DONE_BANCLEAN;
3413     return;
3414   }
3415
3416   /* Go through all bans */
3417   for (ban = state->chptr->banlist; ban; ban = ban->next) {
3418     /* first, clean the ban flags up a bit */
3419     if (!(state->done & DONE_BANCLEAN))
3420       /* Note: We're overloading *lots* of bits here; be careful! */
3421       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
3422
3423     /* Bit meanings:
3424      *
3425      * MODE_ADD            - Ban was added; if we're bouncing modes,
3426      *                       then we'll remove it below; otherwise,
3427      *                       we'll have to allocate a real ban
3428      *
3429      * MODE_DEL            - Ban was marked for deletion; if we're
3430      *                       bouncing modes, we'll have to re-add it,
3431      *                       otherwise, we'll have to remove it
3432      *
3433      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
3434      *                       with a ban already set; if we're
3435      *                       bouncing modes, we'll have to bounce
3436      *                       this one; otherwise, we'll just ignore
3437      *                       it when we process added bans
3438      */
3439
3440     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
3441       ban->flags |= MODE_DEL; /* delete one ban */
3442
3443       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
3444         break;
3445     } else if (state->dir == MODE_ADD) {
3446       /* if the ban already exists, don't worry about it */
3447       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
3448         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
3449           break;
3450         continue;
3451       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
3452         if (!(ban->flags & MODE_DEL))
3453           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
3454       } else if (!mmatch(t_str, ban->value.ban.banstr))
3455         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
3456
3457       if (!ban->next) {
3458         ban->next = newban; /* add our ban with its flags */
3459         break; /* get out of loop */
3460       }
3461     }
3462   }
3463   state->done |= DONE_BANCLEAN;
3464 }
3465
3466 /*
3467  * This is the bottom half of the ban processor
3468  */
3469 static void
3470 mode_process_bans(struct ParseState *state)
3471 {
3472   struct SLink *ban, *newban, *prevban, *nextban;
3473   int count = 0;
3474   int len = 0;
3475   int banlen;
3476   int changed = 0;
3477
3478   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
3479     count++;
3480     banlen = strlen(ban->value.ban.banstr);
3481     len += banlen;
3482     nextban = ban->next;
3483
3484     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
3485       if (prevban)
3486         prevban->next = 0; /* Break the list; ban isn't a real ban */
3487       else
3488         state->chptr->banlist = 0;
3489
3490       count--;
3491       len -= banlen;
3492
3493       MyFree(ban->value.ban.banstr);
3494
3495       continue;
3496     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
3497       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
3498                           ban->value.ban.banstr,
3499                           state->flags & MODE_PARSE_SET);
3500
3501       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
3502         if (prevban) /* clip it out of the list... */
3503           prevban->next = ban->next;
3504         else
3505           state->chptr->banlist = ban->next;
3506
3507         count--;
3508         len -= banlen;
3509
3510         MyFree(ban->value.ban.who);
3511         free_link(ban);
3512
3513         changed++;
3514         continue; /* next ban; keep prevban like it is */
3515       } else
3516         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
3517     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
3518       if (prevban)
3519         prevban->next = 0; /* Break the list; ban isn't a real ban */
3520       else
3521         state->chptr->banlist = 0;
3522
3523       /* If we're supposed to ignore it, do so. */
3524       if (ban->flags & CHFL_BAN_OVERLAPPED &&
3525           !(state->flags & MODE_PARSE_BOUNCE)) {
3526         count--;
3527         len -= banlen;
3528
3529         MyFree(ban->value.ban.banstr);
3530       } else {
3531         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
3532             (len > MAXBANLENGTH || count >= MAXBANS)) {
3533           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
3534                      ban->value.ban.banstr);
3535           count--;
3536           len -= banlen;
3537
3538           MyFree(ban->value.ban.banstr);
3539         } else {
3540           /* add the ban to the buffer */
3541           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
3542                               ban->value.ban.banstr,
3543                               !(state->flags & MODE_PARSE_SET));
3544
3545           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
3546             newban = make_link();
3547             newban->value.ban.banstr = ban->value.ban.banstr;
3548             DupString(newban->value.ban.who, ban->value.ban.who);
3549             newban->value.ban.when = ban->value.ban.when;
3550             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
3551
3552             newban->next = state->chptr->banlist; /* and link it in */
3553             state->chptr->banlist = newban;
3554
3555             changed++;
3556           }
3557         }
3558       }
3559     }
3560
3561     prevban = ban;
3562   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
3563
3564   if (changed) /* if we changed the ban list, we must invalidate the bans */
3565     mode_ban_invalidate(state->chptr);
3566 }
3567
3568 /*
3569  * Helper function to process client changes
3570  */
3571 static void
3572 mode_parse_client(struct ParseState *state, int *flag_p)
3573 {
3574   char *t_str;
3575   struct Client *acptr;
3576   int i;
3577
3578   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
3579     return;
3580
3581   if (state->parc <= 0) /* return if not enough args */
3582     return;
3583
3584   t_str = state->parv[state->args_used++]; /* grab arg */
3585   state->parc--;
3586   state->max_args--;
3587
3588   /* If they're not an oper, they can't change modes */
3589   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3590     send_notoper(state);
3591     return;
3592   }
3593
3594   if (MyUser(state->sptr)) /* find client we're manipulating */
3595     acptr = find_chasing(state->sptr, t_str, NULL);
3596   else
3597     acptr = findNUser(t_str);
3598
3599   if (!acptr)
3600     return; /* find_chasing() already reported an error to the user */
3601
3602   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
3603     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
3604                                        state->cli_change[i].flag & flag_p[0]))
3605       break; /* found a slot */
3606
3607   /* Store what we're doing to them */
3608   state->cli_change[i].flag = state->dir | flag_p[0];
3609   state->cli_change[i].client = acptr;
3610 }
3611
3612 /*
3613  * Helper function to process the changed client list
3614  */
3615 static void
3616 mode_process_clients(struct ParseState *state)
3617 {
3618   int i;
3619   struct Membership *member;
3620
3621   for (i = 0; state->cli_change[i].flag; i++) {
3622     assert(0 != state->cli_change[i].client);
3623
3624     /* look up member link */
3625     if (!(member = find_member_link(state->chptr,
3626                                     state->cli_change[i].client)) ||
3627         (MyUser(state->sptr) && IsZombie(member))) {
3628       if (MyUser(state->sptr))
3629         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3630                    state->cli_change[i].client->name, state->chptr->chname);
3631       continue;
3632     }
3633
3634     if ((state->cli_change[i].flag & MODE_ADD &&
3635          (state->cli_change[i].flag & member->status)) ||
3636         (state->cli_change[i].flag & MODE_DEL &&
3637          !(state->cli_change[i].flag & member->status)))
3638       continue; /* no change made, don't do anything */
3639
3640     /* see if the deop is allowed */
3641     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3642         (MODE_DEL | MODE_CHANOP)) {
3643       /* prevent +k users from being deopped */
3644       if (IsChannelService(state->cli_change[i].client)) {
3645         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3646           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3647                                state->chptr,
3648                                (IsServer(state->sptr) ? state->sptr->name :
3649                                 state->sptr->user->server->name));
3650
3651         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3652           send_reply(state->sptr, ERR_ISCHANSERVICE,
3653                      state->cli_change[i].client->name, state->chptr->chname);
3654           continue;
3655         }
3656       }
3657
3658 #ifdef NO_OPER_DEOP_LCHAN
3659       /* don't allow local opers to be deopped on local channels */
3660       if (MyUser(state->sptr) && state->cli_change[i].client != state->sptr &&
3661           IsOperOnLocalChannel(state->cli_change[i].client,
3662                                state->chptr->chname)) {
3663         send_reply(state->sptr, ERR_ISOPERLCHAN,
3664                    state->cli_change[i].client->name, state->chptr->chname);
3665         continue;
3666       }
3667 #endif
3668     }
3669
3670     /* accumulate the change */
3671     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3672                         state->cli_change[i].client);
3673
3674     /* actually effect the change */
3675     if (state->flags & MODE_PARSE_SET) {
3676       if (state->cli_change[i].flag & MODE_ADD) {
3677         member->status |= (state->cli_change[i].flag &
3678                            (MODE_CHANOP | MODE_VOICE));
3679         if (state->cli_change[i].flag & MODE_CHANOP)
3680           ClearDeopped(member);
3681       } else
3682         member->status &= ~(state->cli_change[i].flag &
3683                             (MODE_CHANOP | MODE_VOICE));
3684     }
3685   } /* for (i = 0; state->cli_change[i].flags; i++) { */
3686 }
3687
3688 /*
3689  * Helper function to process the simple modes
3690  */
3691 static void
3692 mode_parse_mode(struct ParseState *state, int *flag_p)
3693 {
3694   /* If they're not an oper, they can't change modes */
3695   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3696     send_notoper(state);
3697     return;
3698   }
3699
3700   if (!state->mbuf)
3701     return;
3702
3703   if (state->dir == MODE_ADD) {
3704     state->add |= flag_p[0];
3705     state->del &= ~flag_p[0];
3706
3707     if (flag_p[0] & MODE_SECRET) {
3708       state->add &= ~MODE_PRIVATE;
3709       state->del |= MODE_PRIVATE;
3710     } else if (flag_p[0] & MODE_PRIVATE) {
3711       state->add &= ~MODE_SECRET;
3712       state->del |= MODE_SECRET;
3713     }
3714   } else {
3715     state->add &= ~flag_p[0];
3716     state->del |= flag_p[0];
3717   }
3718
3719   assert(0 == (state->add & state->del));
3720   assert((MODE_SECRET | MODE_PRIVATE) !=
3721          (state->add & (MODE_SECRET | MODE_PRIVATE)));
3722 }
3723
3724 /*
3725  * This routine is intended to parse MODE or OPMODE commands and effect the
3726  * changes (or just build the bounce buffer).  We pass the starting offset
3727  * as a 
3728  */
3729 int
3730 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3731            struct Channel *chptr, int parc, char *parv[], unsigned int flags)
3732 {
3733   static int chan_flags[] = {
3734     MODE_CHANOP,        'o',
3735     MODE_VOICE,         'v',
3736     MODE_PRIVATE,       'p',
3737     MODE_SECRET,        's',
3738     MODE_MODERATED,     'm',
3739     MODE_TOPICLIMIT,    't',
3740     MODE_INVITEONLY,    'i',
3741     MODE_NOPRIVMSGS,    'n',
3742     MODE_KEY,           'k',
3743     MODE_BAN,           'b',
3744     MODE_LIMIT,         'l',
3745     MODE_ADD,           '+',
3746     MODE_DEL,           '-',
3747     0x0, 0x0
3748   };
3749   int i;
3750   int *flag_p;
3751   unsigned int t_mode;
3752   char *modestr;
3753   struct ParseState state;
3754
3755   assert(0 != cptr);
3756   assert(0 != sptr);
3757   assert(0 != chptr);
3758   assert(0 != parc);
3759   assert(0 != parv);
3760
3761   state.mbuf = mbuf;
3762   state.cptr = cptr;
3763   state.sptr = sptr;
3764   state.chptr = chptr;
3765   state.parc = parc;
3766   state.parv = parv;
3767   state.flags = flags;
3768   state.dir = MODE_ADD;
3769   state.done = 0;
3770   state.add = 0;
3771   state.del = 0;
3772   state.args_used = 0;
3773   state.max_args = MAXMODEPARAMS;
3774   state.numbans = 0;
3775
3776   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3777     state.banlist[i].next = 0;
3778     state.banlist[i].value.ban.banstr = 0;
3779     state.banlist[i].value.ban.who = 0;
3780     state.banlist[i].value.ban.when = 0;
3781     state.banlist[i].flags = 0;
3782     state.cli_change[i].flag = 0;
3783     state.cli_change[i].client = 0;
3784   }
3785
3786   modestr = state.parv[state.args_used++];
3787   state.parc--;
3788
3789   while (*modestr) {
3790     for (; *modestr; modestr++) {
3791       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3792         if (flag_p[1] == *modestr)
3793           break;
3794
3795       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3796         if (MyUser(state.sptr))
3797           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3798         continue;
3799       }
3800
3801       switch (*modestr) {
3802       case '+': /* switch direction to MODE_ADD */
3803       case '-': /* switch direction to MODE_DEL */
3804         state.dir = flag_p[0];
3805         break;
3806
3807       case 'l': /* deal with limits */
3808         mode_parse_limit(&state, flag_p);
3809         break;
3810
3811       case 'k': /* deal with keys */
3812         mode_parse_key(&state, flag_p);
3813         break;
3814
3815       case 'b': /* deal with bans */
3816         mode_parse_ban(&state, flag_p);
3817         break;
3818
3819       case 'o': /* deal with ops/voice */
3820       case 'v':
3821         mode_parse_client(&state, flag_p);
3822         break;
3823
3824       default: /* deal with other modes */
3825         mode_parse_mode(&state, flag_p);
3826         break;
3827       } /* switch (*modestr) { */
3828     } /* for (; *modestr; modestr++) { */
3829
3830     if (state.flags & MODE_PARSE_BURST)
3831       break; /* don't interpret any more arguments */
3832
3833     if (state.parc > 0) { /* process next argument in string */
3834       modestr = state.parv[state.args_used++];
3835       state.parc--;
3836
3837       /* is it a TS? */
3838       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3839         time_t recv_ts;
3840
3841         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3842           break;                     /* we're then going to bounce the mode! */
3843
3844         recv_ts = atoi(modestr);
3845
3846         if (recv_ts && recv_ts < state.chptr->creationtime)
3847           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3848
3849         break; /* break out of while loop */
3850       } else if (state.flags & MODE_PARSE_STRICT ||
3851                  (MyUser(state.sptr) && state.max_args <= 0)) {
3852         state.parc++; /* we didn't actually gobble the argument */
3853         state.args_used--;
3854         break; /* break out of while loop */
3855       }
3856     }
3857   } /* while (*modestr) { */
3858
3859   /*
3860    * the rest of the function finishes building resultant MODEs; if the
3861    * origin isn't a member or an oper, skip it.
3862    */
3863   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3864     return state.args_used; /* tell our parent how many args we gobbled */
3865
3866   t_mode = state.chptr->mode.mode;
3867
3868   if (state.del & t_mode) { /* delete any modes to be deleted... */
3869     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3870
3871     t_mode &= ~state.del;
3872   }
3873   if (state.add & ~t_mode) { /* add any modes to be added... */
3874     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3875
3876     t_mode |= state.add;
3877   }
3878
3879   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3880     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3881         !(t_mode & MODE_INVITEONLY))
3882       mode_invite_clear(state.chptr);
3883
3884     state.chptr->mode.mode = t_mode;
3885   }
3886
3887   if (state.flags & MODE_PARSE_WIPEOUT) {
3888     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3889       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3890                         state.chptr->mode.limit);
3891     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3892       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3893                           state.chptr->mode.key, 0);
3894   }
3895
3896   if (state.done & DONE_BANCLEAN) /* process bans */
3897     mode_process_bans(&state);
3898
3899   /* process client changes */
3900   if (state.cli_change[0].flag)
3901     mode_process_clients(&state);
3902
3903   return state.args_used; /* tell our parent how many args we gobbled */
3904 }
3905
3906 /*
3907  * Initialize a join buffer
3908  */
3909 void
3910 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3911              struct Client *connect, unsigned int type, char *comment,
3912              time_t create)
3913 {
3914   int i;
3915
3916   assert(0 != jbuf);
3917   assert(0 != source);
3918   assert(0 != connect);
3919
3920   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3921   jbuf->jb_connect = connect;
3922   jbuf->jb_type = type;
3923   jbuf->jb_comment = comment;
3924   jbuf->jb_create = create;
3925   jbuf->jb_count = 0;
3926   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3927                        type == JOINBUF_TYPE_PART ||
3928                        type == JOINBUF_TYPE_PARTALL) ?
3929                       STARTJOINLEN : STARTCREATELEN) +
3930                      (comment ? strlen(comment) + 2 : 0));
3931
3932   for (i = 0; i < MAXJOINARGS; i++)
3933     jbuf->jb_channels[i] = 0;
3934 }
3935
3936 /*
3937  * Add a channel to the join buffer
3938  */
3939 void
3940 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3941 {
3942   unsigned int len;
3943
3944   assert(0 != jbuf);
3945
3946   if (chan) {
3947     if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3948         jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3949       /* Send notification to channel */
3950       if (!(flags & CHFL_ZOMBIE))
3951         sendcmdto_channel_butserv(jbuf->jb_source, CMD_PART, chan,
3952                                   (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3953                                   ":%H" : "%H :%s", chan, jbuf->jb_comment);
3954       else if (MyUser(jbuf->jb_source))
3955         sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3956                       (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3957                       ":%H" : "%H :%s", chan, jbuf->jb_comment);
3958       /* XXX: Shouldn't we send a PART here anyway? */
3959       /* to users on the channel?  Why?  From their POV, the user isn't on
3960        * the channel anymore anyway.  We don't send to servers until below,
3961        * when we gang all the channel parts together.  Note that this is
3962        * exactly the same logic, albeit somewhat more concise, as was in
3963        * the original m_part.c */
3964
3965       if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3966           IsLocalChannel(chan->chname)) /* got to remove user here */
3967         remove_user_from_channel(jbuf->jb_source, chan);
3968     } else {
3969       /* Add user to channel */
3970       add_user_to_channel(chan, jbuf->jb_source, flags);
3971
3972       /* Send the notification to the channel */
3973       sendcmdto_channel_butserv(jbuf->jb_source, CMD_JOIN, chan, ":%H", chan);
3974
3975       /* send an op, too, if needed */
3976       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE &&
3977           !IsModelessChannel(chan->chname))
3978         sendcmdto_channel_butserv(jbuf->jb_source, CMD_MODE, chan, "%H +o %C",
3979                                   chan, jbuf->jb_source);
3980     }
3981
3982     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || IsLocalChannel(chan->chname))
3983       return; /* don't send to remote */
3984   }
3985
3986   /* figure out if channel name will cause buffer to be overflowed */
3987   len = chan ? strlen(chan->chname) + 1 : 2;
3988   if (jbuf->jb_strlen + len > IRC_BUFSIZE)
3989     joinbuf_flush(jbuf);
3990
3991   /* add channel to list of channels to send and update counts */
3992   jbuf->jb_channels[jbuf->jb_count++] = chan;
3993   jbuf->jb_strlen += len;
3994
3995   /* if we've used up all slots, flush */
3996   if (jbuf->jb_count >= MAXJOINARGS)
3997     joinbuf_flush(jbuf);
3998 }
3999
4000 /*
4001  * Flush the channel list to remote servers
4002  */
4003 int
4004 joinbuf_flush(struct JoinBuf *jbuf)
4005 {
4006   char chanlist[IRC_BUFSIZE];
4007   int chanlist_i = 0;
4008   int i;
4009
4010   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL)
4011     return 0; /* no joins to process */
4012
4013   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
4014     build_string(chanlist, &chanlist_i,
4015                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
4016                  i == 0 ? '\0' : ',');
4017     if (JOINBUF_TYPE_PART == jbuf->jb_type)
4018       /* Remove user from channel */
4019       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
4020
4021     jbuf->jb_channels[i] = 0; /* mark slot empty */
4022   }
4023
4024   jbuf->jb_count = 0; /* reset base counters */
4025   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_JOIN ||
4026                       jbuf->jb_type == JOINBUF_TYPE_PART ?
4027                       STARTJOINLEN : STARTCREATELEN) +
4028                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
4029
4030   /* and send the appropriate command */
4031   switch (jbuf->jb_type) {
4032   case JOINBUF_TYPE_JOIN:
4033     sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
4034                           "%s", chanlist);
4035     break;
4036
4037   case JOINBUF_TYPE_CREATE:
4038     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
4039                           "%s %Tu", chanlist, jbuf->jb_create);
4040     break;
4041
4042   case JOINBUF_TYPE_PART:
4043     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
4044                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
4045                           jbuf->jb_comment);
4046     break;
4047   }
4048
4049   return 0;
4050 }