IPv6 support (hopefully with fewer future transition pains)
[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 "config.h"
23
24 #include "channel.h"
25 #include "client.h"
26 #include "destruct_event.h"
27 #include "hash.h"
28 #include "ircd.h"
29 #include "ircd_alloc.h"
30 #include "ircd_chattr.h"
31 #include "ircd_defs.h"
32 #include "ircd_features.h"
33 #include "ircd_log.h"
34 #include "ircd_reply.h"
35 #include "ircd_snprintf.h"
36 #include "ircd_string.h"
37 #include "list.h"
38 #include "match.h"
39 #include "msg.h"
40 #include "msgq.h"
41 #include "numeric.h"
42 #include "numnicks.h"
43 #include "querycmds.h"
44 #include "s_bsd.h"
45 #include "s_conf.h"
46 #include "s_debug.h"
47 #include "s_misc.h"
48 #include "s_user.h"
49 #include "send.h"
50 #include "struct.h"
51 #include "support.h"
52 #include "sys.h"
53 #include "whowas.h"
54
55 #include <assert.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59
60 struct Channel* GlobalChannelList = 0;
61
62 static unsigned int membershipAllocCount;
63 static struct Membership* membershipFreeList;
64
65 void del_invite(struct Client *, struct Channel *);
66
67 const char* const PartFmt1     = ":%s " MSG_PART " %s";
68 const char* const PartFmt2     = ":%s " MSG_PART " %s :%s";
69 const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
70 const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
71
72
73 static struct SLink* next_ban;
74 static struct SLink* prev_ban;
75 static struct SLink* removed_bans_list;
76
77 /*
78  * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
79  * but the only way to do it without changing set_mode intensively.
80  */
81 int LocalChanOperMode = 0;
82
83 #if !defined(NDEBUG)
84 /*
85  * return the length (>=0) of a chain of links.
86  */
87 static int list_length(struct SLink *lp)
88 {
89   int count = 0;
90
91   for (; lp; lp = lp->next)
92     ++count;
93   return count;
94 }
95 #endif
96
97 struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
98 {
99   struct Membership *m;
100   assert(0 != cptr);
101   assert(0 != chptr);
102   
103   /* Servers don't have member links */
104   if (IsServer(cptr)||IsMe(cptr))
105      return 0;
106   
107   /* +k users are typically on a LOT of channels.  So we iterate over who
108    * is in the channel.  X/W are +k and are in about 5800 channels each.
109    * however there are typically no more than 1000 people in a channel
110    * at a time.
111    */
112   if (IsChannelService(cptr)) {
113     m = chptr->members;
114     while (m) {
115       assert(m->channel == chptr);
116       if (m->user == cptr)
117         return m;
118       m = m->next_member;
119     }
120   }
121   /* Users on the other hand aren't allowed on more than 15 channels.  50%
122    * of users that are on channels are on 2 or less, 95% are on 7 or less,
123    * and 99% are on 10 or less.
124    */
125   else {
126    m = (cli_user(cptr))->channel;
127    while (m) {
128      assert(m->user == cptr);
129      if (m->channel == chptr)
130        return m;
131      m = m->next_channel;
132    }
133   }
134   return 0;
135 }
136
137 /*
138  * find_chasing - Find the client structure for a nick name (user)
139  * using history mechanism if necessary. If the client is not found, an error
140  * message (NO SUCH NICK) is generated. If the client was found
141  * through the history, chasing will be 1 and otherwise 0.
142  */
143 struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
144 {
145   struct Client* who = FindClient(user);
146
147   if (chasing)
148     *chasing = 0;
149   if (who)
150     return who;
151
152   if (!(who = get_history(user, feature_int(FEAT_KILLCHASETIMELIMIT)))) {
153     send_reply(sptr, ERR_NOSUCHNICK, user);
154     return 0;
155   }
156   if (chasing)
157     *chasing = 1;
158   return who;
159 }
160
161 /*
162  * Create a string of form "foo!bar@fubar" given foo, bar and fubar
163  * as the parameters.  If NULL, they become "*".
164  */
165 #define NUH_BUFSIZE     (NICKLEN + USERLEN + HOSTLEN + 3)
166 static char *make_nick_user_host(char *namebuf, const char *nick,
167                                  const char *name, const char *host)
168 {
169   ircd_snprintf(0, namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
170   return namebuf;
171 }
172
173 /*
174  * Create a string of form "foo!bar@123.456.789.123" given foo, bar and the
175  * IP-number as the parameters.  If NULL, they become "*".
176  */
177 #define NUI_BUFSIZE     (NICKLEN + USERLEN + SOCKIPLEN + 4)
178 static char *make_nick_user_ip(char *ipbuf, char *nick, char *name,
179                                const struct irc_in_addr *ip)
180 {
181   ircd_snprintf(0, ipbuf, NUI_BUFSIZE, "%s!%s@%s", nick, name, ircd_ntoa(ip));
182   return ipbuf;
183 }
184
185 /*
186  * Subtract one user from channel i (and free channel
187  * block, if channel became empty).
188  * Returns: true  (1) if channel still has members.
189  *          false (0) if the channel is now empty.
190  */
191 int sub1_from_channel(struct Channel* chptr)
192 {
193   if (chptr->users > 1)         /* Can be 0, called for an empty channel too */
194   {
195     assert(0 != chptr->members);
196     --chptr->users;
197     return 1;
198   }
199
200   chptr->users = 0;
201
202   /*
203    * Also channels without Apass set need to be kept alive,
204    * otherwise Bad Guys(tm) would be able to takeover
205    * existing channels too easily, and then set an Apass!
206    * However, if a channel without Apass becomes empty
207    * then we try to be kind to them and remove possible
208    * limiting modes.
209    */
210   chptr->mode.mode &= ~MODE_INVITEONLY;
211   chptr->mode.limit = 0;
212   /*
213    * We do NOT reset a possible key or bans because when
214    * the 'channel owners' can't get in because of a key
215    * or ban then apparently there was a fight/takeover
216    * on the channel and we want them to contact IRC opers
217    * who then will educate them on the use of Apass/upass.
218    */
219
220    if (feature_bool(FEAT_OPLEVELS)) {
221   if (TStime() - chptr->creationtime < 172800)  /* Channel younger than 48 hours? */
222     schedule_destruct_event_1m(chptr);          /* Get rid of it in approximately 4-5 minutes */
223   else
224     schedule_destruct_event_48h(chptr);         /* Get rid of it in approximately 48 hours */
225    } else
226        destruct_channel(chptr);
227
228   return 0;
229 }
230
231 int destruct_channel(struct Channel* chptr)
232 {
233   struct SLink *tmp;
234   struct SLink *obtmp;
235
236   assert(0 == chptr->members);
237
238   /* Channel became (or was) empty: Remove channel */
239   if (is_listed(chptr))
240   {
241     int i;
242     for (i = 0; i <= HighestFd; i++)
243     {
244       struct Client *acptr = 0;
245       if ((acptr = LocalClientArray[i]) && cli_listing(acptr) &&
246           (cli_listing(acptr))->chptr == chptr)
247       {
248         list_next_channels(acptr, 1);
249         break;                  /* Only one client can list a channel */
250       }
251     }
252   }
253   /*
254    * Now, find all invite links from channel structure
255    */
256   while ((tmp = chptr->invites))
257     del_invite(tmp->value.cptr, chptr);
258
259   tmp = chptr->banlist;
260   while (tmp)
261   {
262     obtmp = tmp;
263     tmp = tmp->next;
264     MyFree(obtmp->value.ban.banstr);
265     MyFree(obtmp->value.ban.who);
266     free_link(obtmp);
267   }
268   if (chptr->prev)
269     chptr->prev->next = chptr->next;
270   else
271     GlobalChannelList = chptr->next;
272   if (chptr->next)
273     chptr->next->prev = chptr->prev;
274   hRemChannel(chptr);
275   --UserStats.channels;
276   /*
277    * make sure that channel actually got removed from hash table
278    */
279   assert(chptr->hnext == chptr);
280   MyFree(chptr);
281   return 0;
282 }
283
284 /*
285  * add_banid
286  *
287  * `cptr' must be the client adding the ban.
288  *
289  * If `change' is true then add `banid' to channel `chptr'.
290  * Returns 0 if the ban was added.
291  * Returns -2 if the ban already existed and was marked CHFL_BURST_BAN_WIPEOUT.
292  * Return -1 otherwise.
293  *
294  * Those bans that overlapped with `banid' are flagged with CHFL_BAN_OVERLAPPED
295  * when `change' is false, otherwise they will be removed from the banlist.
296  * Subsequently calls to next_overlapped_ban() or next_removed_overlapped_ban()
297  * respectively will return these bans until NULL is returned.
298  *
299  * If `firsttime' is true, the ban list as returned by next_overlapped_ban()
300  * is reset (unless a non-zero value is returned, in which case the
301  * CHFL_BAN_OVERLAPPED flag might not have been reset!).
302  *
303  * --Run
304  */
305 int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
306                      int change, int firsttime)
307 {
308   struct SLink*  ban;
309   struct SLink** banp;
310   int            cnt = 0;
311   int            removed_bans = 0;
312   int            len = strlen(banid);
313
314   if (firsttime)
315   {
316     next_ban = NULL;
317     assert(0 == prev_ban);
318     assert(0 == removed_bans_list);
319   }
320   if (MyUser(cptr))
321     collapse(banid);
322   for (banp = &chptr->banlist; *banp;)
323   {
324     len += strlen((*banp)->value.ban.banstr);
325     ++cnt;
326     if (((*banp)->flags & CHFL_BURST_BAN_WIPEOUT))
327     {
328       if (!strcmp((*banp)->value.ban.banstr, banid))
329       {
330         (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
331         return -2;
332       }
333     }
334     else if (!mmatch((*banp)->value.ban.banstr, banid))
335       return -1;
336     if (!mmatch(banid, (*banp)->value.ban.banstr))
337     {
338       struct SLink *tmp = *banp;
339       if (change)
340       {
341         if (MyUser(cptr))
342         {
343           cnt--;
344           len -= strlen(tmp->value.ban.banstr);
345         }
346         *banp = tmp->next;
347         /* These will be sent to the user later as -b */
348         tmp->next = removed_bans_list;
349         removed_bans_list = tmp;
350         removed_bans = 1;
351       }
352       else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
353       {
354         tmp->flags |= CHFL_BAN_OVERLAPPED;
355         if (!next_ban)
356           next_ban = tmp;
357         banp = &tmp->next;
358       }
359       else
360         banp = &tmp->next;
361     }
362     else
363     {
364       if (firsttime)
365         (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
366       banp = &(*banp)->next;
367     }
368   }
369   if (MyUser(cptr) && !removed_bans &&
370       (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
371        (cnt >= feature_int(FEAT_MAXBANS))))
372   {
373     send_reply(cptr, ERR_BANLISTFULL, chptr->chname, banid);
374     return -1;
375   }
376   if (change)
377   {
378     char*              ip_start;
379     struct Membership* member;
380     ban = make_link();
381     ban->next = chptr->banlist;
382
383     ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
384     assert(0 != ban->value.ban.banstr);
385     strcpy(ban->value.ban.banstr, banid);
386
387     if (IsServer(cptr) && feature_bool(FEAT_HIS_BANWHO))
388       DupString(ban->value.ban.who, cli_name(&me));
389     else
390       DupString(ban->value.ban.who, cli_name(cptr));
391     assert(0 != ban->value.ban.who);
392
393     ban->value.ban.when = TStime();
394     ban->flags = CHFL_BAN;      /* This bit is never used I think... */
395     if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
396       ban->flags |= CHFL_BAN_IPMASK;
397     chptr->banlist = ban;
398
399     /*
400      * Erase ban-valid-bit
401      */
402     for (member = chptr->members; member; member = member->next_member)
403       ClearBanValid(member);     /* `ban' == channel member ! */
404   }
405   return 0;
406 }
407
408 struct SLink *next_removed_overlapped_ban(void)
409 {
410   struct SLink *tmp = removed_bans_list;
411   if (prev_ban)
412   {
413     if (prev_ban->value.ban.banstr)     /* Can be set to NULL in set_mode() */
414       MyFree(prev_ban->value.ban.banstr);
415     MyFree(prev_ban->value.ban.who);
416     free_link(prev_ban);
417     prev_ban = 0;
418   }
419   if (tmp)
420     removed_bans_list = removed_bans_list->next;
421   prev_ban = tmp;
422   return tmp;
423 }
424
425 /*
426  * find_channel_member - returns Membership * if a person is joined and not a zombie
427  */
428 struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
429 {
430   struct Membership* member;
431   assert(0 != chptr);
432
433   member = find_member_link(chptr, cptr);
434   return (member && !IsZombie(member)) ? member : 0;
435 }
436
437 /*
438  * is_banned - a non-zero value if banned else 0.
439  */
440 static int is_banned(struct Client *cptr, struct Channel *chptr,
441                      struct Membership* member)
442 {
443   struct SLink* tmp;
444   char          tmphost[HOSTLEN + 1];
445   char          nu_host[NUH_BUFSIZE];
446   char          nu_realhost[NUH_BUFSIZE];
447   char          nu_ip[NUI_BUFSIZE];
448   char*         s;
449   char*         sr = NULL;
450   char*         ip_s = NULL;
451
452   if (!IsUser(cptr))
453     return 0;
454
455   if (member && IsBanValid(member))
456     return IsBanned(member);
457
458   s = make_nick_user_host(nu_host, cli_name(cptr), (cli_user(cptr))->username,
459                           (cli_user(cptr))->host);
460   if (IsAccount(cptr))
461   {
462     if (HasHiddenHost(cptr))
463     {
464       sr = make_nick_user_host(nu_realhost, cli_name(cptr),
465                                (cli_user(cptr))->username,
466                                cli_user(cptr)->realhost);
467     }
468     else
469     {
470       ircd_snprintf(0, tmphost, HOSTLEN, "%s.%s",
471                     cli_user(cptr)->account, feature_str(FEAT_HIDDEN_HOST));
472       sr = make_nick_user_host(nu_realhost, cli_name(cptr),
473                                cli_user(cptr)->username,
474                                tmphost);      
475     }
476   }
477
478   for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
479     if ((tmp->flags & CHFL_BAN_IPMASK)) {
480       if (!ip_s)
481         ip_s = make_nick_user_ip(nu_ip, cli_name(cptr),
482                                  (cli_user(cptr))->username, &cli_ip(cptr));
483       if (match(tmp->value.ban.banstr, ip_s) == 0)
484         break;
485     }
486     if (match(tmp->value.ban.banstr, s) == 0)
487       break;
488     else if (sr && match(tmp->value.ban.banstr, sr) == 0)
489       break;
490   }
491
492   if (member) {
493     SetBanValid(member);
494     if (tmp) {
495       SetBanned(member);
496       return 1;
497     }
498     else {
499       ClearBanned(member);
500       return 0;
501     }
502   }
503
504   return (tmp != NULL);
505 }
506
507 /*
508  * adds a user to a channel by adding another link to the channels member
509  * chain.
510  */
511 void add_user_to_channel(struct Channel* chptr, struct Client* who,
512                                 unsigned int flags, int oplevel)
513 {
514   assert(0 != chptr);
515   assert(0 != who);
516
517   if (cli_user(who)) {
518    
519     struct Membership* member = membershipFreeList;
520     if (member)
521       membershipFreeList = member->next_member;
522     else {
523       member = (struct Membership*) MyMalloc(sizeof(struct Membership));
524       ++membershipAllocCount;
525     }
526
527     assert(0 != member);
528     member->user         = who;
529     member->channel      = chptr;
530     member->status       = flags;
531     member->oplevel      = oplevel;
532
533     member->next_member  = chptr->members;
534     if (member->next_member)
535       member->next_member->prev_member = member;
536     member->prev_member  = 0; 
537     chptr->members       = member;
538
539     member->next_channel = (cli_user(who))->channel;
540     if (member->next_channel)
541       member->next_channel->prev_channel = member;
542     member->prev_channel = 0;
543     (cli_user(who))->channel = member;
544
545     if (chptr->destruct_event)
546       remove_destruct_event(chptr);
547     ++chptr->users;
548     ++((cli_user(who))->joined);
549   }
550 }
551
552 static int remove_member_from_channel(struct Membership* member)
553 {
554   struct Channel* chptr;
555   assert(0 != member);
556   chptr = member->channel;
557   /*
558    * unlink channel member list
559    */
560   if (member->next_member)
561     member->next_member->prev_member = member->prev_member;
562   if (member->prev_member)
563     member->prev_member->next_member = member->next_member;
564   else
565     member->channel->members = member->next_member; 
566
567   /*
568    * If this is the last delayed-join user, may have to clear WASDELJOINS.
569    */
570   if (IsDelayedJoin(member))
571     CheckDelayedJoins(chptr);
572
573   /*
574    * unlink client channel list
575    */
576   if (member->next_channel)
577     member->next_channel->prev_channel = member->prev_channel;
578   if (member->prev_channel)
579     member->prev_channel->next_channel = member->next_channel;
580   else
581     (cli_user(member->user))->channel = member->next_channel;
582
583   --(cli_user(member->user))->joined;
584
585   member->next_member = membershipFreeList;
586   membershipFreeList = member;
587
588   return sub1_from_channel(chptr);
589 }
590
591 static int channel_all_zombies(struct Channel* chptr)
592 {
593   struct Membership* member;
594
595   for (member = chptr->members; member; member = member->next_member) {
596     if (!IsZombie(member))
597       return 0;
598   }
599   return 1;
600 }
601       
602
603 void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
604 {
605   
606   struct Membership* member;
607   assert(0 != chptr);
608
609   if ((member = find_member_link(chptr, cptr))) {
610     if (remove_member_from_channel(member)) {
611       if (channel_all_zombies(chptr)) {
612         /*
613          * XXX - this looks dangerous but isn't if we got the referential
614          * integrity right for channels
615          */
616         while (remove_member_from_channel(chptr->members))
617           ;
618       }
619     }
620   }
621 }
622
623 void remove_user_from_all_channels(struct Client* cptr)
624 {
625   struct Membership* chan;
626   assert(0 != cptr);
627   assert(0 != cli_user(cptr));
628
629   while ((chan = (cli_user(cptr))->channel))
630     remove_user_from_channel(cptr, chan->channel);
631 }
632
633 int is_chan_op(struct Client *cptr, struct Channel *chptr)
634 {
635   struct Membership* member;
636   assert(chptr);
637   if ((member = find_member_link(chptr, cptr)))
638     return (!IsZombie(member) && IsChanOp(member));
639
640   return 0;
641 }
642
643 int is_zombie(struct Client *cptr, struct Channel *chptr)
644 {
645   struct Membership* member;
646
647   assert(0 != chptr);
648
649   if ((member = find_member_link(chptr, cptr)))
650       return IsZombie(member);
651   return 0;
652 }
653
654 int has_voice(struct Client* cptr, struct Channel* chptr)
655 {
656   struct Membership* member;
657
658   assert(0 != chptr);
659   if ((member = find_member_link(chptr, cptr)))
660     return (!IsZombie(member) && HasVoice(member));
661
662   return 0;
663 }
664
665 int member_can_send_to_channel(struct Membership* member, int reveal)
666 {
667   assert(0 != member);
668
669   /* Discourage using the Apass to get op.  They should use the upass. */
670   if (IsChannelManager(member) && *member->channel->mode.upass)
671     return 0;
672
673   if (IsVoicedOrOpped(member))
674     return 1;
675   /*
676    * If it's moderated, and you aren't a priviledged user, you can't
677    * speak.  
678    */
679   if (member->channel->mode.mode & MODE_MODERATED)
680     return 0;
681   /*
682    * If you're banned then you can't speak either.
683    * but because of the amount of CPU time that is_banned chews
684    * we only check it for our clients.
685    */
686   if (MyUser(member->user) && is_banned(member->user, member->channel, member))
687     return 0;
688
689   if (IsDelayedJoin(member) && reveal)
690     RevealDelayedJoin(member);
691
692   return 1;
693 }
694
695 int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
696 {
697   struct Membership *member;
698   assert(0 != cptr); 
699   /*
700    * Servers can always speak on channels.
701    */
702   if (IsServer(cptr))
703     return 1;
704
705   member = find_channel_member(cptr, chptr);
706
707   /*
708    * You can't speak if you're off channel, and it is +n (no external messages)
709    * or +m (moderated).
710    */
711   if (!member) {
712     if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
713         ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)))
714       return 0;
715     else
716       return !is_banned(cptr, chptr, NULL);
717   }
718   return member_can_send_to_channel(member, reveal);
719 }
720
721 /*
722  * find_no_nickchange_channel
723  * if a member and not (opped or voiced) and (banned or moderated)
724  * return the name of the first channel banned on
725  */
726 const char* find_no_nickchange_channel(struct Client* cptr)
727 {
728   if (MyUser(cptr)) {
729     struct Membership* member;
730     for (member = (cli_user(cptr))->channel; member;
731          member = member->next_channel) {
732         if (!IsVoicedOrOpped(member) &&
733             (is_banned(cptr, member->channel, member) ||
734              (member->channel->mode.mode & MODE_MODERATED)))
735         return member->channel->chname;
736     }
737   }
738   return 0;
739 }
740
741
742 /*
743  * write the "simple" list of channel modes for channel chptr onto buffer mbuf
744  * with the parameters in pbuf.
745  */
746 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
747                           struct Channel *chptr, struct Membership *member)
748 {
749   int previous_parameter = 0;
750
751   assert(0 != mbuf);
752   assert(0 != pbuf);
753   assert(0 != chptr);
754
755   *mbuf++ = '+';
756   if (chptr->mode.mode & MODE_SECRET)
757     *mbuf++ = 's';
758   else if (chptr->mode.mode & MODE_PRIVATE)
759     *mbuf++ = 'p';
760   if (chptr->mode.mode & MODE_MODERATED)
761     *mbuf++ = 'm';
762   if (chptr->mode.mode & MODE_TOPICLIMIT)
763     *mbuf++ = 't';
764   if (chptr->mode.mode & MODE_INVITEONLY)
765     *mbuf++ = 'i';
766   if (chptr->mode.mode & MODE_NOPRIVMSGS)
767     *mbuf++ = 'n';
768   if (chptr->mode.mode & MODE_REGONLY)
769     *mbuf++ = 'r';
770   if (chptr->mode.mode & MODE_DELJOINS)
771     *mbuf++ = 'D';
772   else if (MyUser(cptr) && (chptr->mode.mode & MODE_WASDELJOINS))
773     *mbuf++ = 'd';
774   if (chptr->mode.limit) {
775     *mbuf++ = 'l';
776     ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
777     previous_parameter = 1;
778   }
779
780   if (*chptr->mode.key) {
781     *mbuf++ = 'k';
782     if (previous_parameter)
783       strcat(pbuf, " ");
784     if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
785       strcat(pbuf, chptr->mode.key);
786     } else
787       strcat(pbuf, "*");
788     previous_parameter = 1;
789   }
790   if (*chptr->mode.apass) {
791     *mbuf++ = 'A';
792     if (previous_parameter)
793       strcat(pbuf, " ");
794     if (IsServer(cptr)) {
795       strcat(pbuf, chptr->mode.apass);
796     } else
797       strcat(pbuf, "*");
798     previous_parameter = 1;
799   }
800   if (*chptr->mode.upass) {
801     *mbuf++ = 'u';
802     if (previous_parameter)
803       strcat(pbuf, " ");
804     if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
805       strcat(pbuf, chptr->mode.upass);
806     } else
807       strcat(pbuf, "*");
808   }
809   *mbuf = '\0';
810 }
811
812 int compare_member_oplevel(const void *mp1, const void *mp2)
813 {
814   struct Membership const* member1 = *(struct Membership const**)mp1;
815   struct Membership const* member2 = *(struct Membership const**)mp2;
816   if (member1->oplevel == member2->oplevel)
817     return 0;
818   return (member1->oplevel < member2->oplevel) ? -1 : 1;
819 }
820
821 /*
822  * send "cptr" a full list of the modes for channel chptr.
823  */
824 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
825 {
826   /* The order in which modes are generated is now mandatory */
827   static unsigned int current_flags[4] =
828       { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
829   int                first = 1;
830   int                full  = 1;
831   int                flag_cnt = 0;
832   int                new_mode = 0;
833   size_t             len;
834   struct Membership* member;
835   struct SLink*      lp2;
836   char modebuf[MODEBUFLEN];
837   char parabuf[MODEBUFLEN];
838   struct MsgBuf *mb;
839   int                 number_of_ops = 0;
840   int                 opped_members_index = 0;
841   struct Membership** opped_members = NULL;
842   int                 last_oplevel = 0;
843
844   assert(0 != cptr);
845   assert(0 != chptr); 
846
847   if (IsLocalChannel(chptr->chname))
848     return;
849
850   member = chptr->members;
851   lp2 = chptr->banlist;
852
853   *modebuf = *parabuf = '\0';
854   channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
855
856   for (first = 1; full; first = 0)      /* Loop for multiple messages */
857   {
858     full = 0;                   /* Assume by default we get it
859                                  all in one message */
860
861     /* (Continued) prefix: "<Y> B <channel> <TS>" */
862     /* is there any better way we can do this? */
863     mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
864                    chptr->creationtime);
865
866     if (first && modebuf[1])    /* Add simple modes (Aiklmnpstu)
867                                  if first message */
868     {
869       /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
870       msgq_append(&me, mb, " %s", modebuf);
871
872       if (*parabuf)
873         msgq_append(&me, mb, " %s", parabuf);
874     }
875
876     /*
877      * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
878      *
879      * First find all opless members.
880      * Run 2 times over all members, to group the members with
881      * and without voice together.
882      * Then run 2 times over all opped members (which are ordered
883      * by op-level) to also group voice and non-voice together.
884      */
885     for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
886     {
887       while (member)
888       {
889         if (flag_cnt < 2 && IsChanOp(member))
890         {
891           /*
892            * The first loop (to find all non-voice/op), we count the ops.
893            * The second loop (to find all voiced non-ops), store the ops
894            * in a dynamic array.
895            */
896           if (flag_cnt == 0)
897             ++number_of_ops;
898           else
899             opped_members[opped_members_index++] = member;
900         }
901         /* Only handle the members with the flags that we are interested in. */
902         if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
903         {
904           if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
905             /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
906           {
907             full = 1;           /* Make sure we continue after
908                                    sending it so far */
909             /* Ensure the new BURST line contains the current
910              * ":mode", except when there is no mode yet. */
911             new_mode = (flag_cnt > 0) ? 1 : 0;
912             break;              /* Do not add this member to this message */
913           }
914           msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
915           first = 0;              /* From now on, use commas to add new nicks */
916
917           /*
918            * Do we have a nick with a new mode ?
919            * Or are we starting a new BURST line?
920            */
921           if (new_mode)
922           {
923             /*
924              * This means we are at the _first_ member that has only
925              * voice, or the first member that has only ops, or the
926              * first member that has voice and ops (so we get here
927              * at most three times, plus once for every start of
928              * a continued BURST line where only these modes is current.
929              * In the two cases where the current mode includes ops,
930              * we need to add the _absolute_ value of the oplevel to the mode.
931              */
932             char tbuf[3 + MAXOPLEVELDIGITS] = ":";
933             int loc = 1;
934
935             if (HasVoice(member))       /* flag_cnt == 1 or 3 */
936               tbuf[loc++] = 'v';
937             if (IsChanOp(member))       /* flag_cnt == 2 or 3 */
938             {
939               /* append the absolute value of the oplevel */
940               loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
941               last_oplevel = member->oplevel;
942             }
943             tbuf[loc] = '\0';
944             msgq_append(&me, mb, tbuf);
945             new_mode = 0;
946           }
947           else if (flag_cnt > 1 && last_oplevel != member->oplevel)
948           {
949             /*
950              * This can't be the first member of a (continued) BURST
951              * message because then either flag_cnt == 0 or new_mode == 1
952              * Now we need to append the incremental value of the oplevel.
953              */
954             char tbuf[2 + MAXOPLEVELDIGITS];
955             ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
956             last_oplevel = member->oplevel;
957             msgq_append(&me, mb, tbuf);
958           }
959         }
960         /* Go to the next `member'. */
961         if (flag_cnt < 2)
962           member = member->next_member;
963         else
964           member = opped_members[++opped_members_index];
965       }
966       if (full)
967         break;
968
969       /* Point `member' at the start of the list again. */
970       if (flag_cnt == 0)
971       {
972         member = chptr->members;
973         /* Now, after one loop, we know the number of ops and can
974          * allocate the dynamic array with pointer to the ops. */
975         opped_members = (struct Membership**)
976           MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
977         opped_members[number_of_ops] = NULL;    /* Needed for loop termination */
978       }
979       else
980       {
981         /* At the end of the second loop, sort the opped members with
982          * increasing op-level, so that we will output them in the
983          * correct order (and all op-level increments stay positive) */
984         if (flag_cnt == 1)
985           qsort(opped_members, number_of_ops,
986                 sizeof(struct Membership*), compare_member_oplevel);
987         /* The third and fourth loop run only over the opped members. */
988         member = opped_members[(opped_members_index = 0)];
989       }
990
991     } /* loop over 0,+v,+o,+ov */
992
993     if (!full)
994     {
995       /* Attach all bans, space seperated " :%ban ban ..." */
996       for (first = 2; lp2; lp2 = lp2->next)
997       {
998         len = strlen(lp2->value.ban.banstr);
999         if (msgq_bufleft(mb) < len + 1 + first)
1000           /* The +1 stands for the added ' '.
1001            * The +first stands for the added ":%".
1002            */
1003         {
1004           full = 1;
1005           break;
1006         }
1007         msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1008                     lp2->value.ban.banstr);
1009         first = 0;
1010       }
1011     }
1012
1013     send_buffer(cptr, mb, 0);  /* Send this message */
1014     msgq_clean(mb);
1015   }                             /* Continue when there was something
1016                                  that didn't fit (full==1) */
1017   if (opped_members)
1018     MyFree(opped_members);
1019   if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1020       sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1021                     chptr->creationtime, chptr->topic_time, chptr->topic);
1022 }
1023
1024 /*
1025  * pretty_mask
1026  *
1027  * by Carlo Wood (Run), 05 Oct 1998.
1028  *
1029  * Canonify a mask.
1030  *
1031  * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1032  * When the user name or host name are too long (USERLEN and HOSTLEN
1033  * respectively) then they are cut off at the start with a '*'.
1034  *
1035  * The following transformations are made:
1036  *
1037  * 1)   xxx             -> nick!*@*
1038  * 2)   xxx.xxx         -> *!*@host
1039  * 3)   xxx!yyy         -> nick!user@*
1040  * 4)   xxx@yyy         -> *!user@host
1041  * 5)   xxx!yyy@zzz     -> nick!user@host
1042  */
1043 char *pretty_mask(char *mask)
1044 {
1045   static char star[2] = { '*', 0 };
1046   static char retmask[NUH_BUFSIZE];
1047   char *last_dot = NULL;
1048   char *ptr;
1049
1050   /* Case 1: default */
1051   char *nick = mask;
1052   char *user = star;
1053   char *host = star;
1054
1055   /* Do a _single_ pass through the characters of the mask: */
1056   for (ptr = mask; *ptr; ++ptr)
1057   {
1058     if (*ptr == '!')
1059     {
1060       /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1061       user = ++ptr;
1062       host = star;
1063     }
1064     else if (*ptr == '@')
1065     {
1066       /* Case 4: Found last '@' (without finding a '!' yet) */
1067       nick = star;
1068       user = mask;
1069       host = ++ptr;
1070     }
1071     else if (*ptr == '.')
1072     {
1073       /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1074       last_dot = ptr;
1075       continue;
1076     }
1077     else
1078       continue;
1079     for (; *ptr; ++ptr)
1080     {
1081       if (*ptr == '@')
1082       {
1083         /* Case 4 or 5: Found last '@' */
1084         host = ptr + 1;
1085       }
1086     }
1087     break;
1088   }
1089   if (user == star && last_dot)
1090   {
1091     /* Case 2: */
1092     nick = star;
1093     user = star;
1094     host = mask;
1095   }
1096   /* Check lengths */
1097   if (nick != star)
1098   {
1099     char *nick_end = (user != star) ? user - 1 : ptr;
1100     if (nick_end - nick > NICKLEN)
1101       nick[NICKLEN] = 0;
1102     *nick_end = 0;
1103   }
1104   if (user != star)
1105   {
1106     char *user_end = (host != star) ? host - 1 : ptr;
1107     if (user_end - user > USERLEN)
1108     {
1109       user = user_end - USERLEN;
1110       *user = '*';
1111     }
1112     *user_end = 0;
1113   }
1114   if (host != star && ptr - host > HOSTLEN)
1115   {
1116     host = ptr - HOSTLEN;
1117     *host = '*';
1118   }
1119   return make_nick_user_host(retmask, nick, user, host);
1120 }
1121
1122 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1123 {
1124   struct SLink* lp;
1125
1126   assert(0 != cptr);
1127   assert(0 != chptr);
1128
1129   for (lp = chptr->banlist; lp; lp = lp->next)
1130     send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1131                lp->value.ban.who, lp->value.ban.when);
1132
1133   send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1134 }
1135
1136 /* We are now treating the <key> part of /join <channel list> <key> as a key
1137  * ring; that is, we try one key against the actual channel key, and if that
1138  * doesn't work, we try the next one, and so on. -Kev -Texaco
1139  * Returns: 0 on match, 1 otherwise
1140  * This version contributed by SeKs <intru@info.polymtl.ca>
1141  */
1142 static int compall(char *key, char *keyring)
1143 {
1144   char *p1;
1145
1146 top:
1147   p1 = key;                     /* point to the key... */
1148   while (*p1 && *p1 == *keyring)
1149   {                             /* step through the key and ring until they
1150                                    don't match... */
1151     p1++;
1152     keyring++;
1153   }
1154
1155   if (!*p1 && (!*keyring || *keyring == ','))
1156     /* ok, if we're at the end of the and also at the end of one of the keys
1157        in the keyring, we have a match */
1158     return 0;
1159
1160   if (!*keyring)                /* if we're at the end of the key ring, there
1161                                    weren't any matches, so we return 1 */
1162     return 1;
1163
1164   /* Not at the end of the key ring, so step
1165      through to the next key in the ring: */
1166   while (*keyring && *(keyring++) != ',');
1167
1168   goto top;                     /* and check it against the key */
1169 }
1170
1171 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1172 {
1173   int overrideJoin = 0;  
1174   
1175   /*
1176    * Now a banned user CAN join if invited -- Nemesi
1177    * Now a user CAN escape channel limit if invited -- bfriendly
1178    * Now a user CAN escape anything if invited -- Isomer
1179    */
1180
1181   if (IsInvited(sptr, chptr))
1182     return 0;
1183   
1184   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
1185      a HACK(4) notice will be sent if he would not have been supposed
1186      to join normally. */ 
1187   if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1188       !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1189       compall("OVERRIDE",key) == 0)
1190     overrideJoin = MAGIC_OPER_OVERRIDE;
1191
1192   if (chptr->mode.mode & MODE_INVITEONLY)
1193         return overrideJoin + ERR_INVITEONLYCHAN;
1194         
1195   if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1196         return overrideJoin + ERR_CHANNELISFULL;
1197
1198   if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1199         return overrideJoin + ERR_NEEDREGGEDNICK;
1200         
1201   if (is_banned(sptr, chptr, NULL))
1202         return overrideJoin + ERR_BANNEDFROMCHAN;
1203   
1204   /*
1205    * now using compall (above) to test against a whole key ring -Kev
1206    */
1207   if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1208     return overrideJoin + ERR_BADCHANNELKEY;
1209
1210   if (overrideJoin)     
1211         return ERR_DONTCHEAT;
1212         
1213   return 0;
1214 }
1215
1216 /*
1217  * Remove bells and commas from channel name
1218  */
1219 void clean_channelname(char *cn)
1220 {
1221   int i;
1222
1223   for (i = 0; cn[i]; i++) {
1224     if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1225       cn[i] = '\0';
1226       return;
1227     }
1228     if (IsChannelLower(cn[i])) {
1229       cn[i] = ToLower(cn[i]);
1230 #ifndef FIXME
1231       /*
1232        * Remove for .08+
1233        * toupper(0xd0)
1234        */
1235       if ((unsigned char)(cn[i]) == 0xd0)
1236         cn[i] = (char) 0xf0;
1237 #endif
1238     }
1239   }
1240 }
1241
1242 /*
1243  *  Get Channel block for i (and allocate a new channel
1244  *  block, if it didn't exists before).
1245  */
1246 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1247 {
1248   struct Channel *chptr;
1249   int len;
1250
1251   if (EmptyString(chname))
1252     return NULL;
1253
1254   len = strlen(chname);
1255   if (MyUser(cptr) && len > CHANNELLEN)
1256   {
1257     len = CHANNELLEN;
1258     *(chname + CHANNELLEN) = '\0';
1259   }
1260   if ((chptr = FindChannel(chname)))
1261     return (chptr);
1262   if (flag == CGT_CREATE)
1263   {
1264     chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1265     assert(0 != chptr);
1266     ++UserStats.channels;
1267     memset(chptr, 0, sizeof(struct Channel));
1268     strcpy(chptr->chname, chname);
1269     if (GlobalChannelList)
1270       GlobalChannelList->prev = chptr;
1271     chptr->prev = NULL;
1272     chptr->next = GlobalChannelList;
1273     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1274     GlobalChannelList = chptr;
1275     hAddChannel(chptr);
1276   }
1277   return chptr;
1278 }
1279
1280 void add_invite(struct Client *cptr, struct Channel *chptr)
1281 {
1282   struct SLink *inv, **tmp;
1283
1284   del_invite(cptr, chptr);
1285   /*
1286    * Delete last link in chain if the list is max length
1287    */
1288   assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1289   if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1290     del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1291   /*
1292    * Add client to channel invite list
1293    */
1294   inv = make_link();
1295   inv->value.cptr = cptr;
1296   inv->next = chptr->invites;
1297   chptr->invites = inv;
1298   /*
1299    * Add channel to the end of the client invite list
1300    */
1301   for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1302   inv = make_link();
1303   inv->value.chptr = chptr;
1304   inv->next = NULL;
1305   (*tmp) = inv;
1306   (cli_user(cptr))->invites++;
1307 }
1308
1309 /*
1310  * Delete Invite block from channel invite list and client invite list
1311  */
1312 void del_invite(struct Client *cptr, struct Channel *chptr)
1313 {
1314   struct SLink **inv, *tmp;
1315
1316   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1317     if (tmp->value.cptr == cptr)
1318     {
1319       *inv = tmp->next;
1320       free_link(tmp);
1321       tmp = 0;
1322       (cli_user(cptr))->invites--;
1323       break;
1324     }
1325
1326   for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1327     if (tmp->value.chptr == chptr)
1328     {
1329       *inv = tmp->next;
1330       free_link(tmp);
1331       tmp = 0;
1332       break;
1333     }
1334 }
1335
1336 /* List and skip all channels that are listen */
1337 void list_next_channels(struct Client *cptr, int nr)
1338 {
1339   struct ListingArgs *args = cli_listing(cptr);
1340   struct Channel *chptr = args->chptr;
1341   chptr->mode.mode &= ~MODE_LISTED;
1342   while (is_listed(chptr) || --nr >= 0)
1343   {
1344     for (; chptr; chptr = chptr->next)
1345     {
1346       if (!cli_user(cptr))
1347         continue;
1348       if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) && 
1349           SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1350         continue;
1351       if (chptr->users > args->min_users && chptr->users < args->max_users &&
1352           chptr->creationtime > args->min_time &&
1353           chptr->creationtime < args->max_time &&
1354           (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1355           chptr->topic_time > args->min_topic_time &&
1356           chptr->topic_time < args->max_topic_time)))
1357       {
1358         if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1359           send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1360                      chptr->topic);
1361         chptr = chptr->next;
1362         break;
1363       }
1364     }
1365     if (!chptr)
1366     {
1367       MyFree(cli_listing(cptr));
1368       cli_listing(cptr) = NULL;
1369       send_reply(cptr, RPL_LISTEND);
1370       break;
1371     }
1372   }
1373   if (chptr)
1374   {
1375     (cli_listing(cptr))->chptr = chptr;
1376     chptr->mode.mode |= MODE_LISTED;
1377   }
1378
1379   update_write(cptr);
1380 }
1381
1382 /*
1383  * Consider:
1384  *
1385  *                     client
1386  *                       |
1387  *                       c
1388  *                       |
1389  *     X --a--> A --b--> B --d--> D
1390  *                       |
1391  *                      who
1392  *
1393  * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1394  * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1395  *
1396  * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1397  *    Remove the user immediately when no users are left on the channel.
1398  * b) On server B : remove the user (who/lp) from the channel, send a
1399  *    PART upstream (to A) and pass on the KICK.
1400  * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1401  *    channel, and pass on the KICK.
1402  * d) On server D : remove the user (who/lp) from the channel, and pass on
1403  *    the KICK.
1404  *
1405  * Note:
1406  * - Setting the ZOMBIE flag never hurts, we either remove the
1407  *   client after that or we don't.
1408  * - The KICK message was already passed on, as should be in all cases.
1409  * - `who' is removed in all cases except case a) when users are left.
1410  * - A PART is only sent upstream in case b).
1411  *
1412  * 2 aug 97:
1413  *
1414  *              6
1415  *              |
1416  *  1 --- 2 --- 3 --- 4 --- 5
1417  *        |           |
1418  *      kicker       who
1419  *
1420  * We also need to turn 'who' into a zombie on servers 1 and 6,
1421  * because a KICK from 'who' (kicking someone else in that direction)
1422  * can arrive there afterwards - which should not be bounced itself.
1423  * Therefore case a) also applies for servers 1 and 6.
1424  *
1425  * --Run
1426  */
1427 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1428                  struct Client* sptr, struct Channel* chptr)
1429 {
1430   assert(0 != member);
1431   assert(0 != who);
1432   assert(0 != cptr);
1433   assert(0 != chptr);
1434
1435   /* Default for case a): */
1436   SetZombie(member);
1437
1438   /* Case b) or c) ?: */
1439   if (MyUser(who))      /* server 4 */
1440   {
1441     if (IsServer(cptr)) /* Case b) ? */
1442       sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1443     remove_user_from_channel(who, chptr);
1444     return;
1445   }
1446   if (cli_from(who) == cptr)        /* True on servers 1, 5 and 6 */
1447   {
1448     struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1449     for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1450       if (acptr == (cli_user(who))->server)   /* Case d) (server 5) */
1451       {
1452         remove_user_from_channel(who, chptr);
1453         return;
1454       }
1455   }
1456
1457   /* Case a) (servers 1, 2, 3 and 6) */
1458   if (channel_all_zombies(chptr))
1459     remove_user_from_channel(who, chptr);
1460
1461   /* XXX Can't actually call Debug here; if the channel is all zombies,
1462    * chptr will no longer exist when we get here.
1463   Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1464   */
1465 }
1466
1467 int number_of_zombies(struct Channel *chptr)
1468 {
1469   struct Membership* member;
1470   int                count = 0;
1471
1472   assert(0 != chptr);
1473   for (member = chptr->members; member; member = member->next_member) {
1474     if (IsZombie(member))
1475       ++count;
1476   }
1477   return count;
1478 }
1479
1480 /*
1481  * This helper function builds an argument string in strptr, consisting
1482  * of the original string, a space, and str1 and str2 concatenated (if,
1483  * of course, str2 is not NULL)
1484  */
1485 static void
1486 build_string(char *strptr, int *strptr_i, const char *str1,
1487              const char *str2, char c)
1488 {
1489   if (c)
1490     strptr[(*strptr_i)++] = c;
1491
1492   while (*str1)
1493     strptr[(*strptr_i)++] = *(str1++);
1494
1495   if (str2)
1496     while (*str2)
1497       strptr[(*strptr_i)++] = *(str2++);
1498
1499   strptr[(*strptr_i)] = '\0';
1500 }
1501
1502 /*
1503  * This is the workhorse of our ModeBuf suite; this actually generates the
1504  * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
1505  */
1506 static int
1507 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1508 {
1509   /* we only need the flags that don't take args right now */
1510   static int flags[] = {
1511 /*  MODE_CHANOP,        'o', */
1512 /*  MODE_VOICE,         'v', */
1513     MODE_PRIVATE,       'p',
1514     MODE_SECRET,        's',
1515     MODE_MODERATED,     'm',
1516     MODE_TOPICLIMIT,    't',
1517     MODE_INVITEONLY,    'i',
1518     MODE_NOPRIVMSGS,    'n',
1519     MODE_REGONLY,       'r',
1520     MODE_DELJOINS,      'D',
1521     MODE_WASDELJOINS,   'd',
1522 /*  MODE_KEY,           'k', */
1523 /*  MODE_BAN,           'b', */
1524 /*  MODE_LIMIT,         'l', */
1525 /*  MODE_APASS,         'A', */
1526 /*  MODE_UPASS,         'u', */
1527     0x0, 0x0
1528   };
1529   int i;
1530   int *flag_p;
1531
1532   struct Client *app_source; /* where the MODE appears to come from */
1533
1534   char addbuf[20]; /* accumulates +psmtin, etc. */
1535   int addbuf_i = 0;
1536   char rembuf[20]; /* accumulates -psmtin, etc. */
1537   int rembuf_i = 0;
1538   char *bufptr; /* we make use of indirection to simplify the code */
1539   int *bufptr_i;
1540
1541   char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1542   int addstr_i;
1543   char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1544   int remstr_i;
1545   char *strptr; /* more indirection to simplify the code */
1546   int *strptr_i;
1547
1548   int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1549   int tmp;
1550
1551   char limitbuf[20]; /* convert limits to strings */
1552
1553   unsigned int limitdel = MODE_LIMIT;
1554
1555   assert(0 != mbuf);
1556
1557   /* If the ModeBuf is empty, we have nothing to do */
1558   if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1559     return 0;
1560
1561   /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1562    */
1563   if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1564     app_source = &me;
1565   else
1566     app_source = mbuf->mb_source;
1567
1568   /*
1569    * Account for user we're bouncing; we have to get it in on the first
1570    * bounced MODE, or we could have problems
1571    */
1572   if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1573     totalbuflen -= 6; /* numeric nick == 5, plus one space */
1574
1575   /* Calculate the simple flags */
1576   for (flag_p = flags; flag_p[0]; flag_p += 2) {
1577     if (*flag_p & mbuf->mb_add)
1578       addbuf[addbuf_i++] = flag_p[1];
1579     else if (*flag_p & mbuf->mb_rem)
1580       rembuf[rembuf_i++] = flag_p[1];
1581   }
1582
1583   /* Now go through the modes with arguments... */
1584   for (i = 0; i < mbuf->mb_count; i++) {
1585     if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1586       bufptr = addbuf;
1587       bufptr_i = &addbuf_i;
1588     } else {
1589       bufptr = rembuf;
1590       bufptr_i = &rembuf_i;
1591     }
1592
1593     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1594       tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1595
1596       if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1597         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1598       else {
1599         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1600         totalbuflen -= IRCD_MAX(5, tmp) + 1;
1601       }
1602     } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1603       tmp = strlen(MB_STRING(mbuf, i));
1604
1605       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1606         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1607       else {
1608         char mode_char;
1609         switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1610         {
1611           case MODE_APASS:
1612             mode_char = 'A';
1613             break;
1614           case MODE_UPASS:
1615             mode_char = 'u';
1616             break;
1617           default:
1618             mode_char = 'b';
1619             break;
1620         }
1621         bufptr[(*bufptr_i)++] = mode_char;
1622         totalbuflen -= tmp + 1;
1623       }
1624     } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1625       tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1626              strlen(MB_STRING(mbuf, i)));
1627
1628       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1629         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1630       else {
1631         bufptr[(*bufptr_i)++] = 'k';
1632         totalbuflen -= tmp + 1;
1633       }
1634     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1635       /* if it's a limit, we also format the number */
1636       ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1637
1638       tmp = strlen(limitbuf);
1639
1640       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1641         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1642       else {
1643         bufptr[(*bufptr_i)++] = 'l';
1644         totalbuflen -= tmp + 1;
1645       }
1646     }
1647   }
1648
1649   /* terminate the mode strings */
1650   addbuf[addbuf_i] = '\0';
1651   rembuf[rembuf_i] = '\0';
1652
1653   /* If we're building a user visible MODE or HACK... */
1654   if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1655                        MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
1656                        MODEBUF_DEST_LOG)) {
1657     /* Set up the parameter strings */
1658     addstr[0] = '\0';
1659     addstr_i = 0;
1660     remstr[0] = '\0';
1661     remstr_i = 0;
1662
1663     for (i = 0; i < mbuf->mb_count; i++) {
1664       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1665         continue;
1666
1667       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1668         strptr = addstr;
1669         strptr_i = &addstr_i;
1670       } else {
1671         strptr = remstr;
1672         strptr_i = &remstr_i;
1673       }
1674
1675       /* deal with clients... */
1676       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1677         build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1678
1679       /* deal with bans... */
1680       else if (MB_TYPE(mbuf, i) & MODE_BAN)
1681         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1682
1683       /* deal with keys... */
1684       else if (MB_TYPE(mbuf, i) & MODE_KEY)
1685         build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1686                      "*" : MB_STRING(mbuf, i), 0, ' ');
1687
1688       /* deal with invisible passwords */
1689       else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1690         build_string(strptr, strptr_i, "*", 0, ' ');
1691
1692       /*
1693        * deal with limit; note we cannot include the limit parameter if we're
1694        * removing it
1695        */
1696       else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1697                (MODE_ADD | MODE_LIMIT))
1698         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1699     }
1700
1701     /* send the messages off to their destination */
1702     if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1703       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1704                            "[%Tu]",
1705                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1706                                     mbuf->mb_source : app_source),
1707                            mbuf->mb_channel->chname,
1708                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1709                            addbuf, remstr, addstr,
1710                            mbuf->mb_channel->creationtime);
1711
1712     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1713       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1714                            "%s%s%s%s%s%s [%Tu]",
1715                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ? 
1716                                     mbuf->mb_source : app_source),
1717                            mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1718                            rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1719                            mbuf->mb_channel->creationtime);
1720
1721     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1722       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1723                            "[%Tu]",
1724                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1725                                     mbuf->mb_source : app_source),
1726                            mbuf->mb_channel->chname,
1727                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1728                            addbuf, remstr, addstr,
1729                            mbuf->mb_channel->creationtime);
1730
1731     if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1732       log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1733                 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1734                 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1735                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1736
1737     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1738       sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1739                                 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1740                                 rembuf_i ? "-" : "", rembuf,
1741                                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1742   }
1743
1744   /* Now are we supposed to propagate to other servers? */
1745   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1746     /* set up parameter string */
1747     addstr[0] = '\0';
1748     addstr_i = 0;
1749     remstr[0] = '\0';
1750     remstr_i = 0;
1751
1752     /*
1753      * limit is supressed if we're removing it; we have to figure out which
1754      * direction is the direction for it to be removed, though...
1755      */
1756     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1757
1758     for (i = 0; i < mbuf->mb_count; i++) {
1759       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1760         continue;
1761
1762       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1763         strptr = addstr;
1764         strptr_i = &addstr_i;
1765       } else {
1766         strptr = remstr;
1767         strptr_i = &remstr_i;
1768       }
1769
1770       /* deal with modes that take clients */
1771       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1772         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1773
1774       /* deal with modes that take strings */
1775       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1776         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1777
1778       /*
1779        * deal with the limit.  Logic here is complicated; if HACK2 is set,
1780        * we're bouncing the mode, so sense is reversed, and we have to
1781        * include the original limit if it looks like it's being removed
1782        */
1783       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1784         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1785     }
1786
1787     /* we were told to deop the source */
1788     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1789       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1790       addbuf[addbuf_i] = '\0'; /* terminate the string... */
1791       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1792
1793       /* mark that we've done this, so we don't do it again */
1794       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1795     }
1796
1797     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1798       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1799       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1800                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
1801                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1802                             addbuf, remstr, addstr);
1803     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1804       /*
1805        * If HACK2 was set, we're bouncing; we send the MODE back to the
1806        * connection we got it from with the senses reversed and a TS of 0;
1807        * origin is us
1808        */
1809       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1810                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1811                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
1812                     mbuf->mb_channel->creationtime);
1813     } else {
1814       /*
1815        * We're propagating a normal MODE command to the rest of the network;
1816        * we send the actual channel TS unless this is a HACK3 or a HACK4
1817        */
1818       if (IsServer(mbuf->mb_source))
1819         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1820                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1821                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1822                               addbuf, remstr, addstr,
1823                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1824                               mbuf->mb_channel->creationtime);
1825       else
1826         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1827                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
1828                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1829                               addbuf, remstr, addstr);
1830     }
1831   }
1832
1833   /* We've drained the ModeBuf... */
1834   mbuf->mb_add = 0;
1835   mbuf->mb_rem = 0;
1836   mbuf->mb_count = 0;
1837
1838   /* reinitialize the mode-with-arg slots */
1839   for (i = 0; i < MAXMODEPARAMS; i++) {
1840     /* If we saved any, pack them down */
1841     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1842       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1843       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1844
1845       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1846         continue;
1847     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1848       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1849
1850     MB_TYPE(mbuf, i) = 0;
1851     MB_UINT(mbuf, i) = 0;
1852   }
1853
1854   /* If we're supposed to flush it all, do so--all hail tail recursion */
1855   if (all && mbuf->mb_count)
1856     return modebuf_flush_int(mbuf, 1);
1857
1858   return 0;
1859 }
1860
1861 /*
1862  * This routine just initializes a ModeBuf structure with the information
1863  * needed and the options given.
1864  */
1865 void
1866 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1867              struct Client *connect, struct Channel *chan, unsigned int dest)
1868 {
1869   int i;
1870
1871   assert(0 != mbuf);
1872   assert(0 != source);
1873   assert(0 != chan);
1874   assert(0 != dest);
1875
1876   if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1877
1878   mbuf->mb_add = 0;
1879   mbuf->mb_rem = 0;
1880   mbuf->mb_source = source;
1881   mbuf->mb_connect = connect;
1882   mbuf->mb_channel = chan;
1883   mbuf->mb_dest = dest;
1884   mbuf->mb_count = 0;
1885
1886   /* clear each mode-with-parameter slot */
1887   for (i = 0; i < MAXMODEPARAMS; i++) {
1888     MB_TYPE(mbuf, i) = 0;
1889     MB_UINT(mbuf, i) = 0;
1890   }
1891 }
1892
1893 /*
1894  * This routine simply adds modes to be added or deleted; do a binary OR
1895  * with either MODE_ADD or MODE_DEL
1896  */
1897 void
1898 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1899 {
1900   assert(0 != mbuf);
1901   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1902
1903   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1904            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1905            MODE_DELJOINS | MODE_WASDELJOINS);
1906
1907   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1908     return;
1909
1910   if (mode & MODE_ADD) {
1911     mbuf->mb_rem &= ~mode;
1912     mbuf->mb_add |= mode;
1913   } else {
1914     mbuf->mb_add &= ~mode;
1915     mbuf->mb_rem |= mode;
1916   }
1917 }
1918
1919 /*
1920  * This routine adds a mode to be added or deleted that takes a unsigned
1921  * int parameter; mode may *only* be the relevant mode flag ORed with one
1922  * of MODE_ADD or MODE_DEL
1923  */
1924 void
1925 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1926 {
1927   assert(0 != mbuf);
1928   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1929
1930   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1931   MB_UINT(mbuf, mbuf->mb_count) = uint;
1932
1933   /* when we've reached the maximal count, flush the buffer */
1934   if (++mbuf->mb_count >=
1935       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1936     modebuf_flush_int(mbuf, 0);
1937 }
1938
1939 /*
1940  * This routine adds a mode to be added or deleted that takes a string
1941  * parameter; mode may *only* be the relevant mode flag ORed with one of
1942  * MODE_ADD or MODE_DEL
1943  */
1944 void
1945 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1946                     int free)
1947 {
1948   assert(0 != mbuf);
1949   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1950
1951   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1952   MB_STRING(mbuf, mbuf->mb_count) = string;
1953
1954   /* when we've reached the maximal count, flush the buffer */
1955   if (++mbuf->mb_count >=
1956       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1957     modebuf_flush_int(mbuf, 0);
1958 }
1959
1960 /*
1961  * This routine adds a mode to be added or deleted that takes a client
1962  * parameter; mode may *only* be the relevant mode flag ORed with one of
1963  * MODE_ADD or MODE_DEL
1964  */
1965 void
1966 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1967                     struct Client *client)
1968 {
1969   assert(0 != mbuf);
1970   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1971
1972   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1973   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1974
1975   /* when we've reached the maximal count, flush the buffer */
1976   if (++mbuf->mb_count >=
1977       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1978     modebuf_flush_int(mbuf, 0);
1979 }
1980
1981 /*
1982  * This is the exported binding for modebuf_flush()
1983  */
1984 int
1985 modebuf_flush(struct ModeBuf *mbuf)
1986 {
1987   struct Membership *memb;
1988
1989   /* Check if MODE_WASDELJOINS should be set */
1990   if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1991       && (mbuf->mb_rem & MODE_DELJOINS)) {
1992     for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
1993       if (IsDelayedJoin(memb)) {
1994           mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
1995           mbuf->mb_add |= MODE_WASDELJOINS;
1996           mbuf->mb_rem &= ~MODE_WASDELJOINS;
1997           break;
1998       }
1999     }
2000   }
2001
2002   return modebuf_flush_int(mbuf, 1);
2003 }
2004
2005 /*
2006  * This extracts the simple modes contained in mbuf
2007  */
2008 void
2009 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2010 {
2011   static int flags[] = {
2012 /*  MODE_CHANOP,        'o', */
2013 /*  MODE_VOICE,         'v', */
2014     MODE_PRIVATE,       'p',
2015     MODE_SECRET,        's',
2016     MODE_MODERATED,     'm',
2017     MODE_TOPICLIMIT,    't',
2018     MODE_INVITEONLY,    'i',
2019     MODE_NOPRIVMSGS,    'n',
2020     MODE_KEY,           'k',
2021     MODE_APASS,         'A',
2022     MODE_UPASS,         'u',
2023 /*  MODE_BAN,           'b', */
2024     MODE_LIMIT,         'l',
2025     MODE_REGONLY,       'r',
2026     MODE_DELJOINS,      'D',
2027     0x0, 0x0
2028   };
2029   unsigned int add;
2030   int i, bufpos = 0, len;
2031   int *flag_p;
2032   char *key = 0, limitbuf[20];
2033   char *apass = 0, *upass = 0;
2034
2035   assert(0 != mbuf);
2036   assert(0 != buf);
2037
2038   buf[0] = '\0';
2039
2040   add = mbuf->mb_add;
2041
2042   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2043     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2044       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2045
2046       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2047         key = MB_STRING(mbuf, i);
2048       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2049         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2050       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2051         upass = MB_STRING(mbuf, i);
2052       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2053         apass = MB_STRING(mbuf, i);
2054     }
2055   }
2056
2057   if (!add)
2058     return;
2059
2060   buf[bufpos++] = '+'; /* start building buffer */
2061
2062   for (flag_p = flags; flag_p[0]; flag_p += 2)
2063     if (*flag_p & add)
2064       buf[bufpos++] = flag_p[1];
2065
2066   for (i = 0, len = bufpos; i < len; i++) {
2067     if (buf[i] == 'k')
2068       build_string(buf, &bufpos, key, 0, ' ');
2069     else if (buf[i] == 'l')
2070       build_string(buf, &bufpos, limitbuf, 0, ' ');
2071     else if (buf[i] == 'u')
2072       build_string(buf, &bufpos, upass, 0, ' ');
2073     else if (buf[i] == 'A')
2074       build_string(buf, &bufpos, apass, 0, ' ');
2075   }
2076
2077   buf[bufpos] = '\0';
2078
2079   return;
2080 }
2081
2082 /*
2083  * Simple function to invalidate bans
2084  */
2085 void
2086 mode_ban_invalidate(struct Channel *chan)
2087 {
2088   struct Membership *member;
2089
2090   for (member = chan->members; member; member = member->next_member)
2091     ClearBanValid(member);
2092 }
2093
2094 /*
2095  * Simple function to drop invite structures
2096  */
2097 void
2098 mode_invite_clear(struct Channel *chan)
2099 {
2100   while (chan->invites)
2101     del_invite(chan->invites->value.cptr, chan);
2102 }
2103
2104 /* What we've done for mode_parse so far... */
2105 #define DONE_LIMIT      0x01    /* We've set the limit */
2106 #define DONE_KEY        0x02    /* We've set the key */
2107 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2108 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2109 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2110 #define DONE_UPASS      0x20    /* We've set user pass */
2111 #define DONE_APASS      0x40    /* We've set admin pass */
2112
2113 struct ParseState {
2114   struct ModeBuf *mbuf;
2115   struct Client *cptr;
2116   struct Client *sptr;
2117   struct Channel *chptr;
2118   struct Membership *member;
2119   int parc;
2120   char **parv;
2121   unsigned int flags;
2122   unsigned int dir;
2123   unsigned int done;
2124   unsigned int add;
2125   unsigned int del;
2126   int args_used;
2127   int max_args;
2128   int numbans;
2129   struct SLink banlist[MAXPARA];
2130   struct {
2131     unsigned int flag;
2132     struct Client *client;
2133   } cli_change[MAXPARA];
2134 };
2135
2136 /*
2137  * Here's a helper function to deal with sending along "Not oper" or
2138  * "Not member" messages
2139  */
2140 static void
2141 send_notoper(struct ParseState *state)
2142 {
2143   if (state->done & DONE_NOTOPER)
2144     return;
2145
2146   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2147              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2148
2149   state->done |= DONE_NOTOPER;
2150 }
2151
2152 /*
2153  * Helper function to convert limits
2154  */
2155 static void
2156 mode_parse_limit(struct ParseState *state, int *flag_p)
2157 {
2158   unsigned int t_limit;
2159
2160   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2161     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2162       return;
2163
2164     if (state->parc <= 0) { /* warn if not enough args */
2165       if (MyUser(state->sptr))
2166         need_more_params(state->sptr, "MODE +l");
2167       return;
2168     }
2169
2170     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2171     state->parc--;
2172     state->max_args--;
2173
2174     if ((int)t_limit<0) /* don't permit a negative limit */
2175       return;
2176
2177     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2178         (!t_limit || t_limit == state->chptr->mode.limit))
2179       return;
2180   } else
2181     t_limit = state->chptr->mode.limit;
2182
2183   /* If they're not an oper, they can't change modes */
2184   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2185     send_notoper(state);
2186     return;
2187   }
2188
2189   /* Can't remove a limit that's not there */
2190   if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2191     return;
2192     
2193   /* Skip if this is a burst and a lower limit than this is set already */
2194   if ((state->flags & MODE_PARSE_BURST) &&
2195       (state->chptr->mode.mode & flag_p[0]) &&
2196       (state->chptr->mode.limit < t_limit))
2197     return;
2198
2199   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2200     return;
2201   state->done |= DONE_LIMIT;
2202
2203   if (!state->mbuf)
2204     return;
2205
2206   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2207
2208   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2209     if (state->dir & MODE_ADD) {
2210       state->chptr->mode.mode |= flag_p[0];
2211       state->chptr->mode.limit = t_limit;
2212     } else {
2213       state->chptr->mode.mode &= ~flag_p[0];
2214       state->chptr->mode.limit = 0;
2215     }
2216   }
2217 }
2218
2219 /*
2220  * Helper function to convert keys
2221  */
2222 static void
2223 mode_parse_key(struct ParseState *state, int *flag_p)
2224 {
2225   char *t_str, *s;
2226   int t_len;
2227
2228   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2229     return;
2230
2231   if (state->parc <= 0) { /* warn if not enough args */
2232     if (MyUser(state->sptr))
2233       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2234                        "MODE -k");
2235     return;
2236   }
2237
2238   t_str = state->parv[state->args_used++]; /* grab arg */
2239   state->parc--;
2240   state->max_args--;
2241
2242   /* If they're not an oper, they can't change modes */
2243   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2244     send_notoper(state);
2245     return;
2246   }
2247
2248   if (state->done & DONE_KEY) /* allow key to be set only once */
2249     return;
2250   state->done |= DONE_KEY;
2251
2252   t_len = KEYLEN;
2253
2254   /* clean up the key string */
2255   s = t_str;
2256   while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2257     s++;
2258   *s = '\0';
2259
2260   if (!*t_str) { /* warn if empty */
2261     if (MyUser(state->sptr))
2262       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2263                        "MODE -k");
2264     return;
2265   }
2266
2267   if (!state->mbuf)
2268     return;
2269
2270   /* Skip if this is a burst, we have a key already and the new key is 
2271    * after the old one alphabetically */
2272   if ((state->flags & MODE_PARSE_BURST) &&
2273       *(state->chptr->mode.key) &&
2274       ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2275     return;
2276
2277   /* can't add a key if one is set, nor can one remove the wrong key */
2278   if (!(state->flags & MODE_PARSE_FORCE))
2279     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2280         (state->dir == MODE_DEL &&
2281          ircd_strcmp(state->chptr->mode.key, t_str))) {
2282       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2283       return;
2284     }
2285
2286   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2287       !ircd_strcmp(state->chptr->mode.key, t_str))
2288     return; /* no key change */
2289
2290   if (state->flags & MODE_PARSE_BOUNCE) {
2291     if (*state->chptr->mode.key) /* reset old key */
2292       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2293                           state->chptr->mode.key, 0);
2294     else /* remove new bogus key */
2295       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2296   } else /* send new key */
2297     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2298
2299   if (state->flags & MODE_PARSE_SET) {
2300     if (state->dir == MODE_ADD) /* set the new key */
2301       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2302     else /* remove the old key */
2303       *state->chptr->mode.key = '\0';
2304   }
2305 }
2306
2307 /*
2308  * Helper function to convert user passes
2309  */
2310 static void
2311 mode_parse_upass(struct ParseState *state, int *flag_p)
2312 {
2313   char *t_str, *s;
2314   int t_len;
2315
2316   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2317     return;
2318
2319   if (state->parc <= 0) { /* warn if not enough args */
2320     if (MyUser(state->sptr))
2321       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2322                        "MODE -u");
2323     return;
2324   }
2325
2326   t_str = state->parv[state->args_used++]; /* grab arg */
2327   state->parc--;
2328   state->max_args--;
2329
2330   /* If they're not an oper, they can't change modes */
2331   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2332     send_notoper(state);
2333     return;
2334   }
2335
2336   /* If they are not the channel manager, they are not allowed to change it */
2337   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2338     if (*state->chptr->mode.apass) {
2339       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2340           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2341     } else {
2342       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2343           "Re-create the channel.  The channel must be *empty* for",
2344           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2345           "before it can be recreated.");
2346     }
2347     return;
2348   }
2349  
2350   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2351     return;
2352   state->done |= DONE_UPASS;
2353
2354   t_len = PASSLEN + 1;
2355
2356   /* clean up the upass string */
2357   s = t_str;
2358   while (*++s > ' ' && *s != ':' && --t_len)
2359     ;
2360   *s = '\0';
2361
2362   if (!*t_str) { /* warn if empty */
2363     if (MyUser(state->sptr))
2364       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2365                        "MODE -u");
2366     return;
2367   }
2368
2369   if (!state->mbuf)
2370     return;
2371
2372   if (!(state->flags & MODE_PARSE_FORCE))
2373     /* can't add the upass while apass is not set */
2374     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2375       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2376       return;
2377     }
2378     /* can't add a upass if one is set, nor can one remove the wrong upass */
2379     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2380         (state->dir == MODE_DEL &&
2381          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2382       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2383       return;
2384     }
2385
2386   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2387       !ircd_strcmp(state->chptr->mode.upass, t_str))
2388     return; /* no upass change */
2389
2390   if (state->flags & MODE_PARSE_BOUNCE) {
2391     if (*state->chptr->mode.upass) /* reset old upass */
2392       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2393                           state->chptr->mode.upass, 0);
2394     else /* remove new bogus upass */
2395       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2396   } else /* send new upass */
2397     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2398
2399   if (state->flags & MODE_PARSE_SET) {
2400     if (state->dir == MODE_ADD) /* set the new upass */
2401       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2402     else /* remove the old upass */
2403       *state->chptr->mode.upass = '\0';
2404   }
2405 }
2406
2407 /*
2408  * Helper function to convert admin passes
2409  */
2410 static void
2411 mode_parse_apass(struct ParseState *state, int *flag_p)
2412 {
2413   char *t_str, *s;
2414   int t_len;
2415
2416   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2417     return;
2418
2419   if (state->parc <= 0) { /* warn if not enough args */
2420     if (MyUser(state->sptr))
2421       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2422                        "MODE -A");
2423     return;
2424   }
2425
2426   t_str = state->parv[state->args_used++]; /* grab arg */
2427   state->parc--;
2428   state->max_args--;
2429
2430   /* If they're not an oper, they can't change modes */
2431   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2432     send_notoper(state);
2433     return;
2434   }
2435
2436   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2437   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2438     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2439     return;
2440   }
2441
2442   /* If they are not the channel manager, they are not allowed to change it */
2443   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2444     if (*state->chptr->mode.apass) {
2445       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2446           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2447     } else {
2448       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2449           "Re-create the channel.  The channel must be *empty* for",
2450           "at least a whole minute", "before it can be recreated.");
2451     }
2452     return;
2453   }
2454  
2455   if (state->done & DONE_APASS) /* allow apass to be set only once */
2456     return;
2457   state->done |= DONE_APASS;
2458
2459   t_len = PASSLEN + 1;
2460
2461   /* clean up the apass string */
2462   s = t_str;
2463   while (*++s > ' ' && *s != ':' && --t_len)
2464     ;
2465   *s = '\0';
2466
2467   if (!*t_str) { /* warn if empty */
2468     if (MyUser(state->sptr))
2469       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2470                        "MODE -A");
2471     return;
2472   }
2473
2474   if (!state->mbuf)
2475     return;
2476
2477   if (!(state->flags & MODE_PARSE_FORCE)) {
2478     /* can't remove the apass while upass is still set */
2479     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2480       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2481       return;
2482     }
2483     /* can't add an apass if one is set, nor can one remove the wrong apass */
2484     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2485         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2486       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2487       return;
2488     }
2489   }
2490
2491   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2492       !ircd_strcmp(state->chptr->mode.apass, t_str))
2493     return; /* no apass change */
2494
2495   if (state->flags & MODE_PARSE_BOUNCE) {
2496     if (*state->chptr->mode.apass) /* reset old apass */
2497       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2498                           state->chptr->mode.apass, 0);
2499     else /* remove new bogus apass */
2500       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2501   } else /* send new apass */
2502     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2503
2504   if (state->flags & MODE_PARSE_SET) {
2505     if (state->dir == MODE_ADD) { /* set the new apass */
2506       /* Make it VERY clear to the user that this is a one-time password */
2507       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2508       if (MyUser(state->sptr)) {
2509         send_reply(state->sptr, RPL_APASSWARN,
2510             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2511             "Are you SURE you want to use this as Admin password? ",
2512             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2513         send_reply(state->sptr, RPL_APASSWARN,
2514             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2515             "\" to remove the password and then immediately set a new one. "
2516             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2517             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2518             "Now set the channel user password (+u).");
2519       }
2520     } else { /* remove the old apass */
2521       *state->chptr->mode.apass = '\0';
2522       if (MyUser(state->sptr))
2523         send_reply(state->sptr, RPL_APASSWARN,
2524             "WARNING: You removed the channel Admin password MODE (+A). ",
2525             "If you would disconnect or leave the channel without setting a new password then you will ",
2526             "not be able to set it again and lose ownership of this channel! ",
2527             "SET A NEW PASSWORD NOW!", "");
2528     }
2529   }
2530 }
2531
2532 /*
2533  * Helper function to convert bans
2534  */
2535 static void
2536 mode_parse_ban(struct ParseState *state, int *flag_p)
2537 {
2538   char *t_str, *s;
2539   struct SLink *ban, *newban = 0;
2540
2541   if (state->parc <= 0) { /* Not enough args, send ban list */
2542     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2543       send_ban_list(state->sptr, state->chptr);
2544       state->done |= DONE_BANLIST;
2545     }
2546
2547     return;
2548   }
2549
2550   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2551     return;
2552
2553   t_str = state->parv[state->args_used++]; /* grab arg */
2554   state->parc--;
2555   state->max_args--;
2556
2557   /* If they're not an oper, they can't change modes */
2558   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2559     send_notoper(state);
2560     return;
2561   }
2562
2563   if ((s = strchr(t_str, ' ')))
2564     *s = '\0';
2565
2566   if (!*t_str || *t_str == ':') { /* warn if empty */
2567     if (MyUser(state->sptr))
2568       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2569                        "MODE -b");
2570     return;
2571   }
2572
2573   t_str = collapse(pretty_mask(t_str));
2574
2575   /* remember the ban for the moment... */
2576   if (state->dir == MODE_ADD) {
2577     newban = state->banlist + (state->numbans++);
2578     newban->next = 0;
2579
2580     DupString(newban->value.ban.banstr, t_str);
2581     newban->value.ban.who = cli_name(state->sptr);
2582     newban->value.ban.when = TStime();
2583
2584     newban->flags = CHFL_BAN | MODE_ADD;
2585
2586     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2587       newban->flags |= CHFL_BAN_IPMASK;
2588   }
2589
2590   if (!state->chptr->banlist) {
2591     state->chptr->banlist = newban; /* add our ban with its flags */
2592     state->done |= DONE_BANCLEAN;
2593     return;
2594   }
2595
2596   /* Go through all bans */
2597   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2598     /* first, clean the ban flags up a bit */
2599     if (!(state->done & DONE_BANCLEAN))
2600       /* Note: We're overloading *lots* of bits here; be careful! */
2601       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2602
2603     /* Bit meanings:
2604      *
2605      * MODE_ADD            - Ban was added; if we're bouncing modes,
2606      *                       then we'll remove it below; otherwise,
2607      *                       we'll have to allocate a real ban
2608      *
2609      * MODE_DEL            - Ban was marked for deletion; if we're
2610      *                       bouncing modes, we'll have to re-add it,
2611      *                       otherwise, we'll have to remove it
2612      *
2613      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2614      *                       with a ban already set; if we're
2615      *                       bouncing modes, we'll have to bounce
2616      *                       this one; otherwise, we'll just ignore
2617      *                       it when we process added bans
2618      */
2619
2620     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2621       ban->flags |= MODE_DEL; /* delete one ban */
2622
2623       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2624         break;
2625     } else if (state->dir == MODE_ADD) {
2626       /* if the ban already exists, don't worry about it */
2627       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2628         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2629         MyFree(newban->value.ban.banstr); /* stopper a leak */
2630         state->numbans--; /* deallocate last ban */
2631         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2632           break;
2633       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2634         if (!(ban->flags & MODE_DEL))
2635           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2636       } else if (!mmatch(t_str, ban->value.ban.banstr))
2637         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2638
2639       if (!ban->next && (newban->flags & MODE_ADD))
2640       {
2641         ban->next = newban; /* add our ban with its flags */
2642         break; /* get out of loop */
2643       }
2644     }
2645   }
2646   state->done |= DONE_BANCLEAN;
2647 }
2648
2649 /*
2650  * This is the bottom half of the ban processor
2651  */
2652 static void
2653 mode_process_bans(struct ParseState *state)
2654 {
2655   struct SLink *ban, *newban, *prevban, *nextban;
2656   int count = 0;
2657   int len = 0;
2658   int banlen;
2659   int changed = 0;
2660
2661   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2662     count++;
2663     banlen = strlen(ban->value.ban.banstr);
2664     len += banlen;
2665     nextban = ban->next;
2666
2667     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2668       if (prevban)
2669         prevban->next = 0; /* Break the list; ban isn't a real ban */
2670       else
2671         state->chptr->banlist = 0;
2672
2673       count--;
2674       len -= banlen;
2675
2676       MyFree(ban->value.ban.banstr);
2677
2678       continue;
2679     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2680       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2681                           ban->value.ban.banstr,
2682                           state->flags & MODE_PARSE_SET);
2683
2684       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2685         if (prevban) /* clip it out of the list... */
2686           prevban->next = ban->next;
2687         else
2688           state->chptr->banlist = ban->next;
2689
2690         count--;
2691         len -= banlen;
2692
2693         MyFree(ban->value.ban.who);
2694         free_link(ban);
2695
2696         changed++;
2697         continue; /* next ban; keep prevban like it is */
2698       } else
2699         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2700     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2701       if (prevban)
2702         prevban->next = 0; /* Break the list; ban isn't a real ban */
2703       else
2704         state->chptr->banlist = 0;
2705
2706       /* If we're supposed to ignore it, do so. */
2707       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2708           !(state->flags & MODE_PARSE_BOUNCE)) {
2709         count--;
2710         len -= banlen;
2711
2712         MyFree(ban->value.ban.banstr);
2713       } else {
2714         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2715             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2716              count > feature_int(FEAT_MAXBANS))) {
2717           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2718                      ban->value.ban.banstr);
2719           count--;
2720           len -= banlen;
2721
2722           MyFree(ban->value.ban.banstr);
2723         } else {
2724           /* add the ban to the buffer */
2725           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2726                               ban->value.ban.banstr,
2727                               !(state->flags & MODE_PARSE_SET));
2728
2729           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2730             newban = make_link();
2731             newban->value.ban.banstr = ban->value.ban.banstr;
2732             DupString(newban->value.ban.who, ban->value.ban.who);
2733             newban->value.ban.when = ban->value.ban.when;
2734             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2735
2736             newban->next = state->chptr->banlist; /* and link it in */
2737             state->chptr->banlist = newban;
2738
2739             changed++;
2740           }
2741         }
2742       }
2743     }
2744
2745     prevban = ban;
2746   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2747
2748   if (changed) /* if we changed the ban list, we must invalidate the bans */
2749     mode_ban_invalidate(state->chptr);
2750 }
2751
2752 /*
2753  * Helper function to process client changes
2754  */
2755 static void
2756 mode_parse_client(struct ParseState *state, int *flag_p)
2757 {
2758   char *t_str;
2759   struct Client *acptr;
2760   int i;
2761
2762   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2763     return;
2764
2765   if (state->parc <= 0) /* return if not enough args */
2766     return;
2767
2768   t_str = state->parv[state->args_used++]; /* grab arg */
2769   state->parc--;
2770   state->max_args--;
2771
2772   /* If they're not an oper, they can't change modes */
2773   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2774     send_notoper(state);
2775     return;
2776   }
2777
2778   if (MyUser(state->sptr)) /* find client we're manipulating */
2779     acptr = find_chasing(state->sptr, t_str, NULL);
2780   else
2781     acptr = findNUser(t_str);
2782
2783   if (!acptr)
2784     return; /* find_chasing() already reported an error to the user */
2785
2786   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2787     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2788                                        state->cli_change[i].flag & flag_p[0]))
2789       break; /* found a slot */
2790
2791   /* Store what we're doing to them */
2792   state->cli_change[i].flag = state->dir | flag_p[0];
2793   state->cli_change[i].client = acptr;
2794 }
2795
2796 /*
2797  * Helper function to process the changed client list
2798  */
2799 static void
2800 mode_process_clients(struct ParseState *state)
2801 {
2802   int i;
2803   struct Membership *member;
2804
2805   for (i = 0; state->cli_change[i].flag; i++) {
2806     assert(0 != state->cli_change[i].client);
2807
2808     /* look up member link */
2809     if (!(member = find_member_link(state->chptr,
2810                                     state->cli_change[i].client)) ||
2811         (MyUser(state->sptr) && IsZombie(member))) {
2812       if (MyUser(state->sptr))
2813         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2814                    cli_name(state->cli_change[i].client),
2815                    state->chptr->chname);
2816       continue;
2817     }
2818
2819     if ((state->cli_change[i].flag & MODE_ADD &&
2820          (state->cli_change[i].flag & member->status)) ||
2821         (state->cli_change[i].flag & MODE_DEL &&
2822          !(state->cli_change[i].flag & member->status)))
2823       continue; /* no change made, don't do anything */
2824
2825     /* see if the deop is allowed */
2826     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2827         (MODE_DEL | MODE_CHANOP)) {
2828       /* prevent +k users from being deopped */
2829       if (IsChannelService(state->cli_change[i].client)) {
2830         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2831           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2832                                state->chptr,
2833                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2834                                 cli_name((cli_user(state->sptr))->server)));
2835
2836         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2837           send_reply(state->sptr, ERR_ISCHANSERVICE,
2838                      cli_name(state->cli_change[i].client),
2839                      state->chptr->chname);
2840           continue;
2841         }
2842       }
2843
2844       /* check deop for local user */
2845       if (MyUser(state->sptr)) {
2846
2847         /* don't allow local opers to be deopped on local channels */
2848         if (state->cli_change[i].client != state->sptr &&
2849             IsLocalChannel(state->chptr->chname) &&
2850             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2851           send_reply(state->sptr, ERR_ISOPERLCHAN,
2852                      cli_name(state->cli_change[i].client),
2853                      state->chptr->chname);
2854           continue;
2855         }
2856
2857         if (feature_bool(FEAT_OPLEVELS)) {
2858         /* don't allow to deop members with an op level that is <= our own level */
2859         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2860                 && state->member
2861                 && OpLevel(member) <= OpLevel(state->member)) {
2862             int equal = (OpLevel(member) == OpLevel(state->member));
2863             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2864                        cli_name(state->cli_change[i].client),
2865                        state->chptr->chname,
2866                        OpLevel(state->member), OpLevel(member),
2867                        "deop", equal ? "the same" : "a higher");
2868           continue;
2869         }
2870       }
2871     }
2872     }
2873
2874     /* set op-level of member being opped */
2875     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2876         (MODE_ADD | MODE_CHANOP)) {
2877       /* If on a channel with upass set, someone with level x gives ops to someone else,
2878          then that person gets level x-1.  On other channels, where upass is not set,
2879          the level stays the same. */
2880       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2881       /* Someone being opped by a server gets op-level 0 */
2882       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2883       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2884     }
2885
2886     /* actually effect the change */
2887     if (state->flags & MODE_PARSE_SET) {
2888       if (state->cli_change[i].flag & MODE_ADD) {
2889         if (IsDelayedJoin(member))
2890           RevealDelayedJoin(member);
2891         member->status |= (state->cli_change[i].flag &
2892                            (MODE_CHANOP | MODE_VOICE));
2893         if (state->cli_change[i].flag & MODE_CHANOP)
2894           ClearDeopped(member);
2895       } else
2896         member->status &= ~(state->cli_change[i].flag &
2897                             (MODE_CHANOP | MODE_VOICE));
2898     }
2899
2900     /* accumulate the change */
2901     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2902                         state->cli_change[i].client);
2903   } /* for (i = 0; state->cli_change[i].flags; i++) */
2904 }
2905
2906 /*
2907  * Helper function to process the simple modes
2908  */
2909 static void
2910 mode_parse_mode(struct ParseState *state, int *flag_p)
2911 {
2912   /* If they're not an oper, they can't change modes */
2913   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2914     send_notoper(state);
2915     return;
2916   }
2917
2918   if (!state->mbuf)
2919     return;
2920
2921   if (state->dir == MODE_ADD) {
2922     state->add |= flag_p[0];
2923     state->del &= ~flag_p[0];
2924
2925     if (flag_p[0] & MODE_SECRET) {
2926       state->add &= ~MODE_PRIVATE;
2927       state->del |= MODE_PRIVATE;
2928     } else if (flag_p[0] & MODE_PRIVATE) {
2929       state->add &= ~MODE_SECRET;
2930       state->del |= MODE_SECRET;
2931     }
2932     if (flag_p[0] & MODE_DELJOINS) {
2933       state->add &= ~MODE_WASDELJOINS;
2934       state->del |= MODE_WASDELJOINS;
2935     }
2936   } else {
2937     state->add &= ~flag_p[0];
2938     state->del |= flag_p[0];
2939   }
2940
2941   assert(0 == (state->add & state->del));
2942   assert((MODE_SECRET | MODE_PRIVATE) !=
2943          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2944 }
2945
2946 /*
2947  * This routine is intended to parse MODE or OPMODE commands and effect the
2948  * changes (or just build the bounce buffer).  We pass the starting offset
2949  * as a 
2950  */
2951 int
2952 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2953            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2954            struct Membership* member)
2955 {
2956   static int chan_flags[] = {
2957     MODE_CHANOP,        'o',
2958     MODE_VOICE,         'v',
2959     MODE_PRIVATE,       'p',
2960     MODE_SECRET,        's',
2961     MODE_MODERATED,     'm',
2962     MODE_TOPICLIMIT,    't',
2963     MODE_INVITEONLY,    'i',
2964     MODE_NOPRIVMSGS,    'n',
2965     MODE_KEY,           'k',
2966     MODE_APASS,         'A',
2967     MODE_UPASS,         'u',
2968     MODE_BAN,           'b',
2969     MODE_LIMIT,         'l',
2970     MODE_REGONLY,       'r',
2971     MODE_DELJOINS,      'D',
2972     MODE_ADD,           '+',
2973     MODE_DEL,           '-',
2974     0x0, 0x0
2975   };
2976   int i;
2977   int *flag_p;
2978   unsigned int t_mode;
2979   char *modestr;
2980   struct ParseState state;
2981
2982   assert(0 != cptr);
2983   assert(0 != sptr);
2984   assert(0 != chptr);
2985   assert(0 != parc);
2986   assert(0 != parv);
2987
2988   state.mbuf = mbuf;
2989   state.cptr = cptr;
2990   state.sptr = sptr;
2991   state.chptr = chptr;
2992   state.member = member;
2993   state.parc = parc;
2994   state.parv = parv;
2995   state.flags = flags;
2996   state.dir = MODE_ADD;
2997   state.done = 0;
2998   state.add = 0;
2999   state.del = 0;
3000   state.args_used = 0;
3001   state.max_args = MAXMODEPARAMS;
3002   state.numbans = 0;
3003
3004   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3005     state.banlist[i].next = 0;
3006     state.banlist[i].value.ban.banstr = 0;
3007     state.banlist[i].value.ban.who = 0;
3008     state.banlist[i].value.ban.when = 0;
3009     state.banlist[i].flags = 0;
3010     state.cli_change[i].flag = 0;
3011     state.cli_change[i].client = 0;
3012   }
3013
3014   modestr = state.parv[state.args_used++];
3015   state.parc--;
3016
3017   while (*modestr) {
3018     for (; *modestr; modestr++) {
3019       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3020         if (flag_p[1] == *modestr)
3021           break;
3022
3023       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3024         if (MyUser(state.sptr))
3025           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3026         continue;
3027       }
3028
3029       switch (*modestr) {
3030       case '+': /* switch direction to MODE_ADD */
3031       case '-': /* switch direction to MODE_DEL */
3032         state.dir = flag_p[0];
3033         break;
3034
3035       case 'l': /* deal with limits */
3036         mode_parse_limit(&state, flag_p);
3037         break;
3038
3039       case 'k': /* deal with keys */
3040         mode_parse_key(&state, flag_p);
3041         break;
3042
3043       case 'A': /* deal with Admin passes */
3044         if (feature_bool(FEAT_OPLEVELS))
3045         mode_parse_apass(&state, flag_p);
3046         break;
3047
3048       case 'u': /* deal with user passes */
3049         if (feature_bool(FEAT_OPLEVELS))
3050         mode_parse_upass(&state, flag_p);
3051         break;
3052
3053       case 'b': /* deal with bans */
3054         mode_parse_ban(&state, flag_p);
3055         break;
3056
3057       case 'o': /* deal with ops/voice */
3058       case 'v':
3059         mode_parse_client(&state, flag_p);
3060         break;
3061
3062       default: /* deal with other modes */
3063         mode_parse_mode(&state, flag_p);
3064         break;
3065       } /* switch (*modestr) */
3066     } /* for (; *modestr; modestr++) */
3067
3068     if (state.flags & MODE_PARSE_BURST)
3069       break; /* don't interpret any more arguments */
3070
3071     if (state.parc > 0) { /* process next argument in string */
3072       modestr = state.parv[state.args_used++];
3073       state.parc--;
3074
3075       /* is it a TS? */
3076       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3077         time_t recv_ts;
3078
3079         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3080           break;                     /* we're then going to bounce the mode! */
3081
3082         recv_ts = atoi(modestr);
3083
3084         if (recv_ts && recv_ts < state.chptr->creationtime)
3085           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3086
3087         break; /* break out of while loop */
3088       } else if (state.flags & MODE_PARSE_STRICT ||
3089                  (MyUser(state.sptr) && state.max_args <= 0)) {
3090         state.parc++; /* we didn't actually gobble the argument */
3091         state.args_used--;
3092         break; /* break out of while loop */
3093       }
3094     }
3095   } /* while (*modestr) */
3096
3097   /*
3098    * the rest of the function finishes building resultant MODEs; if the
3099    * origin isn't a member or an oper, skip it.
3100    */
3101   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3102     return state.args_used; /* tell our parent how many args we gobbled */
3103
3104   t_mode = state.chptr->mode.mode;
3105
3106   if (state.del & t_mode) { /* delete any modes to be deleted... */
3107     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3108
3109     t_mode &= ~state.del;
3110   }
3111   if (state.add & ~t_mode) { /* add any modes to be added... */
3112     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3113
3114     t_mode |= state.add;
3115   }
3116
3117   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3118     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3119         !(t_mode & MODE_INVITEONLY))
3120       mode_invite_clear(state.chptr);
3121
3122     state.chptr->mode.mode = t_mode;
3123   }
3124
3125   if (state.flags & MODE_PARSE_WIPEOUT) {
3126     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3127       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3128                         state.chptr->mode.limit);
3129     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3130       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3131                           state.chptr->mode.key, 0);
3132     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3133       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3134                           state.chptr->mode.upass, 0);
3135     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3136       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3137                           state.chptr->mode.apass, 0);
3138   }
3139
3140   if (state.done & DONE_BANCLEAN) /* process bans */
3141     mode_process_bans(&state);
3142
3143   /* process client changes */
3144   if (state.cli_change[0].flag)
3145     mode_process_clients(&state);
3146
3147   return state.args_used; /* tell our parent how many args we gobbled */
3148 }
3149
3150 /*
3151  * Initialize a join buffer
3152  */
3153 void
3154 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3155              struct Client *connect, unsigned int type, char *comment,
3156              time_t create)
3157 {
3158   int i;
3159
3160   assert(0 != jbuf);
3161   assert(0 != source);
3162   assert(0 != connect);
3163
3164   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3165   jbuf->jb_connect = connect;
3166   jbuf->jb_type = type;
3167   jbuf->jb_comment = comment;
3168   jbuf->jb_create = create;
3169   jbuf->jb_count = 0;
3170   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3171                        type == JOINBUF_TYPE_PART ||
3172                        type == JOINBUF_TYPE_PARTALL) ?
3173                       STARTJOINLEN : STARTCREATELEN) +
3174                      (comment ? strlen(comment) + 2 : 0));
3175
3176   for (i = 0; i < MAXJOINARGS; i++)
3177     jbuf->jb_channels[i] = 0;
3178 }
3179
3180 /*
3181  * Add a channel to the join buffer
3182  */
3183 void
3184 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3185 {
3186   unsigned int len;
3187   int is_local;
3188
3189   assert(0 != jbuf);
3190
3191   if (!chan) {
3192     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3193       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3194
3195     return;
3196   }
3197
3198   is_local = IsLocalChannel(chan->chname);
3199
3200   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3201       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3202     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3203     if (IsUserParting(member))
3204       return;
3205     SetUserParting(member);
3206
3207     /* Send notification to channel */
3208     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3209       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3210                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3211                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3212     else if (MyUser(jbuf->jb_source))
3213       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3214                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3215                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3216     /* XXX: Shouldn't we send a PART here anyway? */
3217     /* to users on the channel?  Why?  From their POV, the user isn't on
3218      * the channel anymore anyway.  We don't send to servers until below,
3219      * when we gang all the channel parts together.  Note that this is
3220      * exactly the same logic, albeit somewhat more concise, as was in
3221      * the original m_part.c */
3222
3223     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3224         is_local) /* got to remove user here */
3225       remove_user_from_channel(jbuf->jb_source, chan);
3226   } else {
3227     /* Add user to channel */
3228     if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3229       add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3230     else
3231       add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3232
3233     /* send notification to all servers */
3234     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3235       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3236                             "%H %Tu", chan, chan->creationtime);
3237
3238     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3239       /* Send the notification to the channel */
3240       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3241
3242       /* send an op, too, if needed */
3243       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3244         sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3245                                          chan, jbuf->jb_source);
3246     } else if (MyUser(jbuf->jb_source))
3247       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3248   }
3249
3250   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3251       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3252     return; /* don't send to remote */
3253
3254   /* figure out if channel name will cause buffer to be overflowed */
3255   len = chan ? strlen(chan->chname) + 1 : 2;
3256   if (jbuf->jb_strlen + len > BUFSIZE)
3257     joinbuf_flush(jbuf);
3258
3259   /* add channel to list of channels to send and update counts */
3260   jbuf->jb_channels[jbuf->jb_count++] = chan;
3261   jbuf->jb_strlen += len;
3262
3263   /* if we've used up all slots, flush */
3264   if (jbuf->jb_count >= MAXJOINARGS)
3265     joinbuf_flush(jbuf);
3266 }
3267
3268 /*
3269  * Flush the channel list to remote servers
3270  */
3271 int
3272 joinbuf_flush(struct JoinBuf *jbuf)
3273 {
3274   char chanlist[BUFSIZE];
3275   int chanlist_i = 0;
3276   int i;
3277
3278   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3279       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3280     return 0; /* no joins to process */
3281
3282   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3283     build_string(chanlist, &chanlist_i,
3284                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3285                  i == 0 ? '\0' : ',');
3286     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3287       /* Remove user from channel */
3288       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3289
3290     jbuf->jb_channels[i] = 0; /* mark slot empty */
3291   }
3292
3293   jbuf->jb_count = 0; /* reset base counters */
3294   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3295                       STARTJOINLEN : STARTCREATELEN) +
3296                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3297
3298   /* and send the appropriate command */
3299   switch (jbuf->jb_type) {
3300   case JOINBUF_TYPE_CREATE:
3301     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3302                           "%s %Tu", chanlist, jbuf->jb_create);
3303     break;
3304
3305   case JOINBUF_TYPE_PART:
3306     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3307                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3308                           jbuf->jb_comment);
3309     break;
3310   }
3311
3312   return 0;
3313 }
3314
3315 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3316 int IsInvited(struct Client* cptr, const void* chptr)
3317 {
3318   struct SLink *lp;
3319
3320   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3321     if (lp->value.chptr == chptr)
3322       return 1;
3323   return 0;
3324 }
3325
3326 /* RevealDelayedJoin: sends a join for a hidden user */
3327
3328 void RevealDelayedJoin(struct Membership *member) {
3329   ClearDelayedJoin(member);
3330   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3331                                    member->channel);
3332   CheckDelayedJoins(member->channel);
3333 }
3334
3335 /* CheckDelayedJoins: checks and clear +d if necessary */
3336
3337 void CheckDelayedJoins(struct Channel *chan) {
3338   struct Membership *memb2;
3339   
3340   if (chan->mode.mode & MODE_WASDELJOINS) {
3341     for (memb2=chan->members;memb2;memb2=memb2->next_member)
3342       if (IsDelayedJoin(memb2))
3343         break;
3344     
3345     if (!memb2) {
3346       /* clear +d */
3347       chan->mode.mode &= ~MODE_WASDELJOINS;
3348       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
3349                                        "%H -d", chan);
3350     }
3351   }
3352 }