Fix bug #916138 so -l doesn't gobble an argument.
[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   int                 feat_oplevels = (chptr->mode.mode & MODE_APASS) != 0;
844
845   assert(0 != cptr);
846   assert(0 != chptr); 
847
848   if (IsLocalChannel(chptr->chname))
849     return;
850
851   member = chptr->members;
852   lp2 = chptr->banlist;
853
854   *modebuf = *parabuf = '\0';
855   channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
856
857   for (first = 1; full; first = 0)      /* Loop for multiple messages */
858   {
859     full = 0;                   /* Assume by default we get it
860                                  all in one message */
861
862     /* (Continued) prefix: "<Y> B <channel> <TS>" */
863     /* is there any better way we can do this? */
864     mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
865                    chptr->creationtime);
866
867     if (first && modebuf[1])    /* Add simple modes (Aiklmnpstu)
868                                  if first message */
869     {
870       /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
871       msgq_append(&me, mb, " %s", modebuf);
872
873       if (*parabuf)
874         msgq_append(&me, mb, " %s", parabuf);
875     }
876
877     /*
878      * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
879      *
880      * First find all opless members.
881      * Run 2 times over all members, to group the members with
882      * and without voice together.
883      * Then run 2 times over all opped members (which are ordered
884      * by op-level) to also group voice and non-voice together.
885      */
886     for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
887     {
888       while (member)
889       {
890         if (flag_cnt < 2 && IsChanOp(member))
891         {
892           /*
893            * The first loop (to find all non-voice/op), we count the ops.
894            * The second loop (to find all voiced non-ops), store the ops
895            * in a dynamic array.
896            */
897           if (flag_cnt == 0)
898             ++number_of_ops;
899           else
900             opped_members[opped_members_index++] = member;
901         }
902         /* Only handle the members with the flags that we are interested in. */
903         if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
904         {
905           if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
906             /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
907           {
908             full = 1;           /* Make sure we continue after
909                                    sending it so far */
910             /* Ensure the new BURST line contains the current
911              * ":mode", except when there is no mode yet. */
912             new_mode = (flag_cnt > 0) ? 1 : 0;
913             break;              /* Do not add this member to this message */
914           }
915           msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
916           first = 0;              /* From now on, use commas to add new nicks */
917
918           /*
919            * Do we have a nick with a new mode ?
920            * Or are we starting a new BURST line?
921            */
922           if (new_mode || !feat_oplevels)
923           {
924             /*
925              * This means we are at the _first_ member that has only
926              * voice, or the first member that has only ops, or the
927              * first member that has voice and ops (so we get here
928              * at most three times, plus once for every start of
929              * a continued BURST line where only these modes is current.
930              * In the two cases where the current mode includes ops,
931              * we need to add the _absolute_ value of the oplevel to the mode.
932              */
933             char tbuf[3 + MAXOPLEVELDIGITS] = ":";
934             int loc = 1;
935
936             if (HasVoice(member))       /* flag_cnt == 1 or 3 */
937               tbuf[loc++] = 'v';
938             if (IsChanOp(member))       /* flag_cnt == 2 or 3 */
939             {
940               /* append the absolute value of the oplevel */
941               if (feat_oplevels)
942                 loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", last_oplevel = member->oplevel);
943               else
944                 tbuf[loc++] = 'o';
945             }
946             tbuf[loc] = '\0';
947             msgq_append(&me, mb, tbuf);
948             new_mode = 0;
949           }
950           else if (flag_cnt > 1 && last_oplevel != member->oplevel)
951           {
952             /*
953              * This can't be the first member of a (continued) BURST
954              * message because then either flag_cnt == 0 or new_mode == 1
955              * Now we need to append the incremental value of the oplevel.
956              */
957             char tbuf[2 + MAXOPLEVELDIGITS];
958             ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
959             last_oplevel = member->oplevel;
960             msgq_append(&me, mb, tbuf);
961           }
962         }
963         /* Go to the next `member'. */
964         if (flag_cnt < 2)
965           member = member->next_member;
966         else
967           member = opped_members[++opped_members_index];
968       }
969       if (full)
970         break;
971
972       /* Point `member' at the start of the list again. */
973       if (flag_cnt == 0)
974       {
975         member = chptr->members;
976         /* Now, after one loop, we know the number of ops and can
977          * allocate the dynamic array with pointer to the ops. */
978         opped_members = (struct Membership**)
979           MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
980         opped_members[number_of_ops] = NULL;    /* Needed for loop termination */
981       }
982       else
983       {
984         /* At the end of the second loop, sort the opped members with
985          * increasing op-level, so that we will output them in the
986          * correct order (and all op-level increments stay positive) */
987         if (flag_cnt == 1)
988           qsort(opped_members, number_of_ops,
989                 sizeof(struct Membership*), compare_member_oplevel);
990         /* The third and fourth loop run only over the opped members. */
991         member = opped_members[(opped_members_index = 0)];
992       }
993
994     } /* loop over 0,+v,+o,+ov */
995
996     if (!full)
997     {
998       /* Attach all bans, space seperated " :%ban ban ..." */
999       for (first = 2; lp2; lp2 = lp2->next)
1000       {
1001         len = strlen(lp2->value.ban.banstr);
1002         if (msgq_bufleft(mb) < len + 1 + first)
1003           /* The +1 stands for the added ' '.
1004            * The +first stands for the added ":%".
1005            */
1006         {
1007           full = 1;
1008           break;
1009         }
1010         msgq_append(&me, mb, " %s%s", first ? ":%" : "",
1011                     lp2->value.ban.banstr);
1012         first = 0;
1013       }
1014     }
1015
1016     send_buffer(cptr, mb, 0);  /* Send this message */
1017     msgq_clean(mb);
1018   }                             /* Continue when there was something
1019                                  that didn't fit (full==1) */
1020   if (opped_members)
1021     MyFree(opped_members);
1022   if (feature_bool(FEAT_TOPIC_BURST) && (chptr->topic[0] != '\0'))
1023       sendcmdto_one(&me, CMD_TOPIC, cptr, "%H %Tu %Tu :%s", chptr,
1024                     chptr->creationtime, chptr->topic_time, chptr->topic);
1025 }
1026
1027 /*
1028  * pretty_mask
1029  *
1030  * by Carlo Wood (Run), 05 Oct 1998.
1031  *
1032  * Canonify a mask.
1033  *
1034  * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1035  * When the user name or host name are too long (USERLEN and HOSTLEN
1036  * respectively) then they are cut off at the start with a '*'.
1037  *
1038  * The following transformations are made:
1039  *
1040  * 1)   xxx             -> nick!*@*
1041  * 2)   xxx.xxx         -> *!*@host
1042  * 3)   xxx!yyy         -> nick!user@*
1043  * 4)   xxx@yyy         -> *!user@host
1044  * 5)   xxx!yyy@zzz     -> nick!user@host
1045  */
1046 char *pretty_mask(char *mask)
1047 {
1048   static char star[2] = { '*', 0 };
1049   static char retmask[NUH_BUFSIZE];
1050   char *last_dot = NULL;
1051   char *ptr;
1052
1053   /* Case 1: default */
1054   char *nick = mask;
1055   char *user = star;
1056   char *host = star;
1057
1058   /* Do a _single_ pass through the characters of the mask: */
1059   for (ptr = mask; *ptr; ++ptr)
1060   {
1061     if (*ptr == '!')
1062     {
1063       /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1064       user = ++ptr;
1065       host = star;
1066     }
1067     else if (*ptr == '@')
1068     {
1069       /* Case 4: Found last '@' (without finding a '!' yet) */
1070       nick = star;
1071       user = mask;
1072       host = ++ptr;
1073     }
1074     else if (*ptr == '.')
1075     {
1076       /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1077       last_dot = ptr;
1078       continue;
1079     }
1080     else
1081       continue;
1082     for (; *ptr; ++ptr)
1083     {
1084       if (*ptr == '@')
1085       {
1086         /* Case 4 or 5: Found last '@' */
1087         host = ptr + 1;
1088       }
1089     }
1090     break;
1091   }
1092   if (user == star && last_dot)
1093   {
1094     /* Case 2: */
1095     nick = star;
1096     user = star;
1097     host = mask;
1098   }
1099   /* Check lengths */
1100   if (nick != star)
1101   {
1102     char *nick_end = (user != star) ? user - 1 : ptr;
1103     if (nick_end - nick > NICKLEN)
1104       nick[NICKLEN] = 0;
1105     *nick_end = 0;
1106   }
1107   if (user != star)
1108   {
1109     char *user_end = (host != star) ? host - 1 : ptr;
1110     if (user_end - user > USERLEN)
1111     {
1112       user = user_end - USERLEN;
1113       *user = '*';
1114     }
1115     *user_end = 0;
1116   }
1117   if (host != star && ptr - host > HOSTLEN)
1118   {
1119     host = ptr - HOSTLEN;
1120     *host = '*';
1121   }
1122   return make_nick_user_host(retmask, nick, user, host);
1123 }
1124
1125 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1126 {
1127   struct SLink* lp;
1128
1129   assert(0 != cptr);
1130   assert(0 != chptr);
1131
1132   for (lp = chptr->banlist; lp; lp = lp->next)
1133     send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1134                lp->value.ban.who, lp->value.ban.when);
1135
1136   send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1137 }
1138
1139 /* We are now treating the <key> part of /join <channel list> <key> as a key
1140  * ring; that is, we try one key against the actual channel key, and if that
1141  * doesn't work, we try the next one, and so on. -Kev -Texaco
1142  * Returns: 0 on match, 1 otherwise
1143  * This version contributed by SeKs <intru@info.polymtl.ca>
1144  */
1145 static int compall(char *key, char *keyring)
1146 {
1147   char *p1;
1148
1149 top:
1150   p1 = key;                     /* point to the key... */
1151   while (*p1 && *p1 == *keyring)
1152   {                             /* step through the key and ring until they
1153                                    don't match... */
1154     p1++;
1155     keyring++;
1156   }
1157
1158   if (!*p1 && (!*keyring || *keyring == ','))
1159     /* ok, if we're at the end of the and also at the end of one of the keys
1160        in the keyring, we have a match */
1161     return 0;
1162
1163   if (!*keyring)                /* if we're at the end of the key ring, there
1164                                    weren't any matches, so we return 1 */
1165     return 1;
1166
1167   /* Not at the end of the key ring, so step
1168      through to the next key in the ring: */
1169   while (*keyring && *(keyring++) != ',');
1170
1171   goto top;                     /* and check it against the key */
1172 }
1173
1174 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1175 {
1176   int overrideJoin = 0;  
1177   
1178   /*
1179    * Now a banned user CAN join if invited -- Nemesi
1180    * Now a user CAN escape channel limit if invited -- bfriendly
1181    * Now a user CAN escape anything if invited -- Isomer
1182    */
1183
1184   if (IsInvited(sptr, chptr))
1185     return 0;
1186   
1187   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
1188      a HACK(4) notice will be sent if he would not have been supposed
1189      to join normally. */ 
1190   if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1191       !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1192       compall("OVERRIDE",key) == 0)
1193     overrideJoin = MAGIC_OPER_OVERRIDE;
1194
1195   if (chptr->mode.mode & MODE_INVITEONLY)
1196         return overrideJoin + ERR_INVITEONLYCHAN;
1197         
1198   if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1199         return overrideJoin + ERR_CHANNELISFULL;
1200
1201   if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1202         return overrideJoin + ERR_NEEDREGGEDNICK;
1203         
1204   if (is_banned(sptr, chptr, NULL))
1205         return overrideJoin + ERR_BANNEDFROMCHAN;
1206   
1207   /*
1208    * now using compall (above) to test against a whole key ring -Kev
1209    */
1210   if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1211     return overrideJoin + ERR_BADCHANNELKEY;
1212
1213   if (overrideJoin)     
1214         return ERR_DONTCHEAT;
1215         
1216   return 0;
1217 }
1218
1219 /*
1220  * Remove bells and commas from channel name
1221  */
1222 void clean_channelname(char *cn)
1223 {
1224   int i;
1225
1226   for (i = 0; cn[i]; i++) {
1227     if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1228       cn[i] = '\0';
1229       return;
1230     }
1231     if (IsChannelLower(cn[i])) {
1232       cn[i] = ToLower(cn[i]);
1233 #ifndef FIXME
1234       /*
1235        * Remove for .08+
1236        * toupper(0xd0)
1237        */
1238       if ((unsigned char)(cn[i]) == 0xd0)
1239         cn[i] = (char) 0xf0;
1240 #endif
1241     }
1242   }
1243 }
1244
1245 /*
1246  *  Get Channel block for i (and allocate a new channel
1247  *  block, if it didn't exists before).
1248  */
1249 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1250 {
1251   struct Channel *chptr;
1252   int len;
1253
1254   if (EmptyString(chname))
1255     return NULL;
1256
1257   len = strlen(chname);
1258   if (MyUser(cptr) && len > CHANNELLEN)
1259   {
1260     len = CHANNELLEN;
1261     *(chname + CHANNELLEN) = '\0';
1262   }
1263   if ((chptr = FindChannel(chname)))
1264     return (chptr);
1265   if (flag == CGT_CREATE)
1266   {
1267     chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1268     assert(0 != chptr);
1269     ++UserStats.channels;
1270     memset(chptr, 0, sizeof(struct Channel));
1271     strcpy(chptr->chname, chname);
1272     if (GlobalChannelList)
1273       GlobalChannelList->prev = chptr;
1274     chptr->prev = NULL;
1275     chptr->next = GlobalChannelList;
1276     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1277     GlobalChannelList = chptr;
1278     hAddChannel(chptr);
1279   }
1280   return chptr;
1281 }
1282
1283 void add_invite(struct Client *cptr, struct Channel *chptr)
1284 {
1285   struct SLink *inv, **tmp;
1286
1287   del_invite(cptr, chptr);
1288   /*
1289    * Delete last link in chain if the list is max length
1290    */
1291   assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1292   if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1293     del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1294   /*
1295    * Add client to channel invite list
1296    */
1297   inv = make_link();
1298   inv->value.cptr = cptr;
1299   inv->next = chptr->invites;
1300   chptr->invites = inv;
1301   /*
1302    * Add channel to the end of the client invite list
1303    */
1304   for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1305   inv = make_link();
1306   inv->value.chptr = chptr;
1307   inv->next = NULL;
1308   (*tmp) = inv;
1309   (cli_user(cptr))->invites++;
1310 }
1311
1312 /*
1313  * Delete Invite block from channel invite list and client invite list
1314  */
1315 void del_invite(struct Client *cptr, struct Channel *chptr)
1316 {
1317   struct SLink **inv, *tmp;
1318
1319   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1320     if (tmp->value.cptr == cptr)
1321     {
1322       *inv = tmp->next;
1323       free_link(tmp);
1324       tmp = 0;
1325       (cli_user(cptr))->invites--;
1326       break;
1327     }
1328
1329   for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1330     if (tmp->value.chptr == chptr)
1331     {
1332       *inv = tmp->next;
1333       free_link(tmp);
1334       tmp = 0;
1335       break;
1336     }
1337 }
1338
1339 /* List and skip all channels that are listen */
1340 void list_next_channels(struct Client *cptr, int nr)
1341 {
1342   struct ListingArgs *args = cli_listing(cptr);
1343   struct Channel *chptr = args->chptr;
1344   chptr->mode.mode &= ~MODE_LISTED;
1345   while (is_listed(chptr) || --nr >= 0)
1346   {
1347     for (; chptr; chptr = chptr->next)
1348     {
1349       if (!cli_user(cptr))
1350         continue;
1351       if (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) && 
1352           SecretChannel(chptr) && !find_channel_member(cptr, chptr))
1353         continue;
1354       if (chptr->users > args->min_users && chptr->users < args->max_users &&
1355           chptr->creationtime > args->min_time &&
1356           chptr->creationtime < args->max_time &&
1357           (!(args->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1358           chptr->topic_time > args->min_topic_time &&
1359           chptr->topic_time < args->max_topic_time)))
1360       {
1361         if ((args->flags & LISTARG_SHOWSECRET) || ShowChannel(cptr,chptr))
1362           send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1363                      chptr->topic);
1364         chptr = chptr->next;
1365         break;
1366       }
1367     }
1368     if (!chptr)
1369     {
1370       MyFree(cli_listing(cptr));
1371       cli_listing(cptr) = NULL;
1372       send_reply(cptr, RPL_LISTEND);
1373       break;
1374     }
1375   }
1376   if (chptr)
1377   {
1378     (cli_listing(cptr))->chptr = chptr;
1379     chptr->mode.mode |= MODE_LISTED;
1380   }
1381
1382   update_write(cptr);
1383 }
1384
1385 /*
1386  * Consider:
1387  *
1388  *                     client
1389  *                       |
1390  *                       c
1391  *                       |
1392  *     X --a--> A --b--> B --d--> D
1393  *                       |
1394  *                      who
1395  *
1396  * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1397  * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1398  *
1399  * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1400  *    Remove the user immediately when no users are left on the channel.
1401  * b) On server B : remove the user (who/lp) from the channel, send a
1402  *    PART upstream (to A) and pass on the KICK.
1403  * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1404  *    channel, and pass on the KICK.
1405  * d) On server D : remove the user (who/lp) from the channel, and pass on
1406  *    the KICK.
1407  *
1408  * Note:
1409  * - Setting the ZOMBIE flag never hurts, we either remove the
1410  *   client after that or we don't.
1411  * - The KICK message was already passed on, as should be in all cases.
1412  * - `who' is removed in all cases except case a) when users are left.
1413  * - A PART is only sent upstream in case b).
1414  *
1415  * 2 aug 97:
1416  *
1417  *              6
1418  *              |
1419  *  1 --- 2 --- 3 --- 4 --- 5
1420  *        |           |
1421  *      kicker       who
1422  *
1423  * We also need to turn 'who' into a zombie on servers 1 and 6,
1424  * because a KICK from 'who' (kicking someone else in that direction)
1425  * can arrive there afterwards - which should not be bounced itself.
1426  * Therefore case a) also applies for servers 1 and 6.
1427  *
1428  * --Run
1429  */
1430 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1431                  struct Client* sptr, struct Channel* chptr)
1432 {
1433   assert(0 != member);
1434   assert(0 != who);
1435   assert(0 != cptr);
1436   assert(0 != chptr);
1437
1438   /* Default for case a): */
1439   SetZombie(member);
1440
1441   /* Case b) or c) ?: */
1442   if (MyUser(who))      /* server 4 */
1443   {
1444     if (IsServer(cptr)) /* Case b) ? */
1445       sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1446     remove_user_from_channel(who, chptr);
1447     return;
1448   }
1449   if (cli_from(who) == cptr)        /* True on servers 1, 5 and 6 */
1450   {
1451     struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1452     for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1453       if (acptr == (cli_user(who))->server)   /* Case d) (server 5) */
1454       {
1455         remove_user_from_channel(who, chptr);
1456         return;
1457       }
1458   }
1459
1460   /* Case a) (servers 1, 2, 3 and 6) */
1461   if (channel_all_zombies(chptr))
1462     remove_user_from_channel(who, chptr);
1463
1464   /* XXX Can't actually call Debug here; if the channel is all zombies,
1465    * chptr will no longer exist when we get here.
1466   Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1467   */
1468 }
1469
1470 int number_of_zombies(struct Channel *chptr)
1471 {
1472   struct Membership* member;
1473   int                count = 0;
1474
1475   assert(0 != chptr);
1476   for (member = chptr->members; member; member = member->next_member) {
1477     if (IsZombie(member))
1478       ++count;
1479   }
1480   return count;
1481 }
1482
1483 /*
1484  * This helper function builds an argument string in strptr, consisting
1485  * of the original string, a space, and str1 and str2 concatenated (if,
1486  * of course, str2 is not NULL)
1487  */
1488 static void
1489 build_string(char *strptr, int *strptr_i, const char *str1,
1490              const char *str2, char c)
1491 {
1492   if (c)
1493     strptr[(*strptr_i)++] = c;
1494
1495   while (*str1)
1496     strptr[(*strptr_i)++] = *(str1++);
1497
1498   if (str2)
1499     while (*str2)
1500       strptr[(*strptr_i)++] = *(str2++);
1501
1502   strptr[(*strptr_i)] = '\0';
1503 }
1504
1505 /*
1506  * This is the workhorse of our ModeBuf suite; this actually generates the
1507  * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
1508  */
1509 static int
1510 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1511 {
1512   /* we only need the flags that don't take args right now */
1513   static int flags[] = {
1514 /*  MODE_CHANOP,        'o', */
1515 /*  MODE_VOICE,         'v', */
1516     MODE_PRIVATE,       'p',
1517     MODE_SECRET,        's',
1518     MODE_MODERATED,     'm',
1519     MODE_TOPICLIMIT,    't',
1520     MODE_INVITEONLY,    'i',
1521     MODE_NOPRIVMSGS,    'n',
1522     MODE_REGONLY,       'r',
1523     MODE_DELJOINS,      'D',
1524     MODE_WASDELJOINS,   'd',
1525 /*  MODE_KEY,           'k', */
1526 /*  MODE_BAN,           'b', */
1527     MODE_LIMIT,         'l',
1528 /*  MODE_APASS,         'A', */
1529 /*  MODE_UPASS,         'u', */
1530     0x0, 0x0
1531   };
1532   int i;
1533   int *flag_p;
1534
1535   struct Client *app_source; /* where the MODE appears to come from */
1536
1537   char addbuf[20]; /* accumulates +psmtin, etc. */
1538   int addbuf_i = 0;
1539   char rembuf[20]; /* accumulates -psmtin, etc. */
1540   int rembuf_i = 0;
1541   char *bufptr; /* we make use of indirection to simplify the code */
1542   int *bufptr_i;
1543
1544   char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1545   int addstr_i;
1546   char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1547   int remstr_i;
1548   char *strptr; /* more indirection to simplify the code */
1549   int *strptr_i;
1550
1551   int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1552   int tmp;
1553
1554   char limitbuf[20]; /* convert limits to strings */
1555
1556   unsigned int limitdel = MODE_LIMIT;
1557
1558   assert(0 != mbuf);
1559
1560   /* If the ModeBuf is empty, we have nothing to do */
1561   if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1562     return 0;
1563
1564   /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1565    */
1566   if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1567     app_source = &me;
1568   else
1569     app_source = mbuf->mb_source;
1570
1571   /*
1572    * Account for user we're bouncing; we have to get it in on the first
1573    * bounced MODE, or we could have problems
1574    */
1575   if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1576     totalbuflen -= 6; /* numeric nick == 5, plus one space */
1577
1578   /* Calculate the simple flags */
1579   for (flag_p = flags; flag_p[0]; flag_p += 2) {
1580     if (*flag_p & mbuf->mb_add)
1581       addbuf[addbuf_i++] = flag_p[1];
1582     else if (*flag_p & mbuf->mb_rem)
1583       rembuf[rembuf_i++] = flag_p[1];
1584   }
1585
1586   /* Now go through the modes with arguments... */
1587   for (i = 0; i < mbuf->mb_count; i++) {
1588     if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1589       bufptr = addbuf;
1590       bufptr_i = &addbuf_i;
1591     } else {
1592       bufptr = rembuf;
1593       bufptr_i = &rembuf_i;
1594     }
1595
1596     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1597       tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1598
1599       if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1600         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1601       else {
1602         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1603         totalbuflen -= IRCD_MAX(5, tmp) + 1;
1604       }
1605     } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1606       tmp = strlen(MB_STRING(mbuf, i));
1607
1608       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1609         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1610       else {
1611         char mode_char;
1612         switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1613         {
1614           case MODE_APASS:
1615             mode_char = 'A';
1616             break;
1617           case MODE_UPASS:
1618             mode_char = 'u';
1619             break;
1620           default:
1621             mode_char = 'b';
1622             break;
1623         }
1624         bufptr[(*bufptr_i)++] = mode_char;
1625         totalbuflen -= tmp + 1;
1626       }
1627     } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1628       tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1629              strlen(MB_STRING(mbuf, i)));
1630
1631       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1632         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1633       else {
1634         bufptr[(*bufptr_i)++] = 'k';
1635         totalbuflen -= tmp + 1;
1636       }
1637     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1638       /* if it's a limit, we also format the number */
1639       ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1640
1641       tmp = strlen(limitbuf);
1642
1643       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1644         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1645       else {
1646         bufptr[(*bufptr_i)++] = 'l';
1647         totalbuflen -= tmp + 1;
1648       }
1649     }
1650   }
1651
1652   /* terminate the mode strings */
1653   addbuf[addbuf_i] = '\0';
1654   rembuf[rembuf_i] = '\0';
1655
1656   /* If we're building a user visible MODE or HACK... */
1657   if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1658                        MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
1659                        MODEBUF_DEST_LOG)) {
1660     /* Set up the parameter strings */
1661     addstr[0] = '\0';
1662     addstr_i = 0;
1663     remstr[0] = '\0';
1664     remstr_i = 0;
1665
1666     for (i = 0; i < mbuf->mb_count; i++) {
1667       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1668         continue;
1669
1670       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1671         strptr = addstr;
1672         strptr_i = &addstr_i;
1673       } else {
1674         strptr = remstr;
1675         strptr_i = &remstr_i;
1676       }
1677
1678       /* deal with clients... */
1679       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1680         build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1681
1682       /* deal with bans... */
1683       else if (MB_TYPE(mbuf, i) & MODE_BAN)
1684         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1685
1686       /* deal with keys... */
1687       else if (MB_TYPE(mbuf, i) & MODE_KEY)
1688         build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1689                      "*" : MB_STRING(mbuf, i), 0, ' ');
1690
1691       /* deal with invisible passwords */
1692       else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1693         build_string(strptr, strptr_i, "*", 0, ' ');
1694
1695       /*
1696        * deal with limit; note we cannot include the limit parameter if we're
1697        * removing it
1698        */
1699       else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1700                (MODE_ADD | MODE_LIMIT))
1701         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1702     }
1703
1704     /* send the messages off to their destination */
1705     if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1706       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1707                            "[%Tu]",
1708                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1709                                     mbuf->mb_source : app_source),
1710                            mbuf->mb_channel->chname,
1711                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1712                            addbuf, remstr, addstr,
1713                            mbuf->mb_channel->creationtime);
1714
1715     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1716       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1717                            "%s%s%s%s%s%s [%Tu]",
1718                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ? 
1719                                     mbuf->mb_source : app_source),
1720                            mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1721                            rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1722                            mbuf->mb_channel->creationtime);
1723
1724     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1725       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1726                            "[%Tu]",
1727                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1728                                     mbuf->mb_source : app_source),
1729                            mbuf->mb_channel->chname,
1730                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1731                            addbuf, remstr, addstr,
1732                            mbuf->mb_channel->creationtime);
1733
1734     if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1735       log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1736                 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1737                 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1738                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1739
1740     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1741       sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1742                                 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1743                                 rembuf_i ? "-" : "", rembuf,
1744                                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1745   }
1746
1747   /* Now are we supposed to propagate to other servers? */
1748   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1749     /* set up parameter string */
1750     addstr[0] = '\0';
1751     addstr_i = 0;
1752     remstr[0] = '\0';
1753     remstr_i = 0;
1754
1755     /*
1756      * limit is supressed if we're removing it; we have to figure out which
1757      * direction is the direction for it to be removed, though...
1758      */
1759     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1760
1761     for (i = 0; i < mbuf->mb_count; i++) {
1762       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1763         continue;
1764
1765       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1766         strptr = addstr;
1767         strptr_i = &addstr_i;
1768       } else {
1769         strptr = remstr;
1770         strptr_i = &remstr_i;
1771       }
1772
1773       /* deal with modes that take clients */
1774       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1775         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1776
1777       /* deal with modes that take strings */
1778       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1779         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1780
1781       /*
1782        * deal with the limit.  Logic here is complicated; if HACK2 is set,
1783        * we're bouncing the mode, so sense is reversed, and we have to
1784        * include the original limit if it looks like it's being removed
1785        */
1786       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1787         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1788     }
1789
1790     /* we were told to deop the source */
1791     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1792       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1793       addbuf[addbuf_i] = '\0'; /* terminate the string... */
1794       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1795
1796       /* mark that we've done this, so we don't do it again */
1797       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1798     }
1799
1800     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1801       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1802       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1803                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
1804                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1805                             addbuf, remstr, addstr);
1806     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1807       /*
1808        * If HACK2 was set, we're bouncing; we send the MODE back to the
1809        * connection we got it from with the senses reversed and a TS of 0;
1810        * origin is us
1811        */
1812       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1813                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1814                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
1815                     mbuf->mb_channel->creationtime);
1816     } else {
1817       /*
1818        * We're propagating a normal MODE command to the rest of the network;
1819        * we send the actual channel TS unless this is a HACK3 or a HACK4
1820        */
1821       if (IsServer(mbuf->mb_source))
1822         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1823                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1824                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1825                               addbuf, remstr, addstr,
1826                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1827                               mbuf->mb_channel->creationtime);
1828       else
1829         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1830                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
1831                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1832                               addbuf, remstr, addstr);
1833     }
1834   }
1835
1836   /* We've drained the ModeBuf... */
1837   mbuf->mb_add = 0;
1838   mbuf->mb_rem = 0;
1839   mbuf->mb_count = 0;
1840
1841   /* reinitialize the mode-with-arg slots */
1842   for (i = 0; i < MAXMODEPARAMS; i++) {
1843     /* If we saved any, pack them down */
1844     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1845       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1846       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1847
1848       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1849         continue;
1850     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1851       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1852
1853     MB_TYPE(mbuf, i) = 0;
1854     MB_UINT(mbuf, i) = 0;
1855   }
1856
1857   /* If we're supposed to flush it all, do so--all hail tail recursion */
1858   if (all && mbuf->mb_count)
1859     return modebuf_flush_int(mbuf, 1);
1860
1861   return 0;
1862 }
1863
1864 /*
1865  * This routine just initializes a ModeBuf structure with the information
1866  * needed and the options given.
1867  */
1868 void
1869 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1870              struct Client *connect, struct Channel *chan, unsigned int dest)
1871 {
1872   int i;
1873
1874   assert(0 != mbuf);
1875   assert(0 != source);
1876   assert(0 != chan);
1877   assert(0 != dest);
1878
1879   if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1880
1881   mbuf->mb_add = 0;
1882   mbuf->mb_rem = 0;
1883   mbuf->mb_source = source;
1884   mbuf->mb_connect = connect;
1885   mbuf->mb_channel = chan;
1886   mbuf->mb_dest = dest;
1887   mbuf->mb_count = 0;
1888
1889   /* clear each mode-with-parameter slot */
1890   for (i = 0; i < MAXMODEPARAMS; i++) {
1891     MB_TYPE(mbuf, i) = 0;
1892     MB_UINT(mbuf, i) = 0;
1893   }
1894 }
1895
1896 /*
1897  * This routine simply adds modes to be added or deleted; do a binary OR
1898  * with either MODE_ADD or MODE_DEL
1899  */
1900 void
1901 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1902 {
1903   assert(0 != mbuf);
1904   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1905
1906   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1907            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1908            MODE_DELJOINS | MODE_WASDELJOINS);
1909
1910   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1911     return;
1912
1913   if (mode & MODE_ADD) {
1914     mbuf->mb_rem &= ~mode;
1915     mbuf->mb_add |= mode;
1916   } else {
1917     mbuf->mb_add &= ~mode;
1918     mbuf->mb_rem |= mode;
1919   }
1920 }
1921
1922 /*
1923  * This routine adds a mode to be added or deleted that takes a unsigned
1924  * int parameter; mode may *only* be the relevant mode flag ORed with one
1925  * of MODE_ADD or MODE_DEL
1926  */
1927 void
1928 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1929 {
1930   assert(0 != mbuf);
1931   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1932
1933   if (mode == (MODE_LIMIT | MODE_DEL)) {
1934       mbuf->mb_rem |= mode;
1935       return;
1936   }
1937   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1938   MB_UINT(mbuf, mbuf->mb_count) = uint;
1939
1940   /* when we've reached the maximal count, flush the buffer */
1941   if (++mbuf->mb_count >=
1942       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1943     modebuf_flush_int(mbuf, 0);
1944 }
1945
1946 /*
1947  * This routine adds a mode to be added or deleted that takes a string
1948  * parameter; mode may *only* be the relevant mode flag ORed with one of
1949  * MODE_ADD or MODE_DEL
1950  */
1951 void
1952 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1953                     int free)
1954 {
1955   assert(0 != mbuf);
1956   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1957
1958   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1959   MB_STRING(mbuf, mbuf->mb_count) = string;
1960
1961   /* when we've reached the maximal count, flush the buffer */
1962   if (++mbuf->mb_count >=
1963       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1964     modebuf_flush_int(mbuf, 0);
1965 }
1966
1967 /*
1968  * This routine adds a mode to be added or deleted that takes a client
1969  * parameter; mode may *only* be the relevant mode flag ORed with one of
1970  * MODE_ADD or MODE_DEL
1971  */
1972 void
1973 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1974                     struct Client *client)
1975 {
1976   assert(0 != mbuf);
1977   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1978
1979   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1980   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1981
1982   /* when we've reached the maximal count, flush the buffer */
1983   if (++mbuf->mb_count >=
1984       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1985     modebuf_flush_int(mbuf, 0);
1986 }
1987
1988 /*
1989  * This is the exported binding for modebuf_flush()
1990  */
1991 int
1992 modebuf_flush(struct ModeBuf *mbuf)
1993 {
1994   struct Membership *memb;
1995
1996   /* Check if MODE_WASDELJOINS should be set */
1997   if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1998       && (mbuf->mb_rem & MODE_DELJOINS)) {
1999     for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2000       if (IsDelayedJoin(memb)) {
2001           mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2002           mbuf->mb_add |= MODE_WASDELJOINS;
2003           mbuf->mb_rem &= ~MODE_WASDELJOINS;
2004           break;
2005       }
2006     }
2007   }
2008
2009   return modebuf_flush_int(mbuf, 1);
2010 }
2011
2012 /*
2013  * This extracts the simple modes contained in mbuf
2014  */
2015 void
2016 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2017 {
2018   static int flags[] = {
2019 /*  MODE_CHANOP,        'o', */
2020 /*  MODE_VOICE,         'v', */
2021     MODE_PRIVATE,       'p',
2022     MODE_SECRET,        's',
2023     MODE_MODERATED,     'm',
2024     MODE_TOPICLIMIT,    't',
2025     MODE_INVITEONLY,    'i',
2026     MODE_NOPRIVMSGS,    'n',
2027     MODE_KEY,           'k',
2028     MODE_APASS,         'A',
2029     MODE_UPASS,         'u',
2030 /*  MODE_BAN,           'b', */
2031     MODE_LIMIT,         'l',
2032     MODE_REGONLY,       'r',
2033     MODE_DELJOINS,      'D',
2034     0x0, 0x0
2035   };
2036   unsigned int add;
2037   int i, bufpos = 0, len;
2038   int *flag_p;
2039   char *key = 0, limitbuf[20];
2040   char *apass = 0, *upass = 0;
2041
2042   assert(0 != mbuf);
2043   assert(0 != buf);
2044
2045   buf[0] = '\0';
2046
2047   add = mbuf->mb_add;
2048
2049   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2050     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2051       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2052
2053       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2054         key = MB_STRING(mbuf, i);
2055       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2056         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2057       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2058         upass = MB_STRING(mbuf, i);
2059       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2060         apass = MB_STRING(mbuf, i);
2061     }
2062   }
2063
2064   if (!add)
2065     return;
2066
2067   buf[bufpos++] = '+'; /* start building buffer */
2068
2069   for (flag_p = flags; flag_p[0]; flag_p += 2)
2070     if (*flag_p & add)
2071       buf[bufpos++] = flag_p[1];
2072
2073   for (i = 0, len = bufpos; i < len; i++) {
2074     if (buf[i] == 'k')
2075       build_string(buf, &bufpos, key, 0, ' ');
2076     else if (buf[i] == 'l')
2077       build_string(buf, &bufpos, limitbuf, 0, ' ');
2078     else if (buf[i] == 'u')
2079       build_string(buf, &bufpos, upass, 0, ' ');
2080     else if (buf[i] == 'A')
2081       build_string(buf, &bufpos, apass, 0, ' ');
2082   }
2083
2084   buf[bufpos] = '\0';
2085
2086   return;
2087 }
2088
2089 /*
2090  * Simple function to invalidate bans
2091  */
2092 void
2093 mode_ban_invalidate(struct Channel *chan)
2094 {
2095   struct Membership *member;
2096
2097   for (member = chan->members; member; member = member->next_member)
2098     ClearBanValid(member);
2099 }
2100
2101 /*
2102  * Simple function to drop invite structures
2103  */
2104 void
2105 mode_invite_clear(struct Channel *chan)
2106 {
2107   while (chan->invites)
2108     del_invite(chan->invites->value.cptr, chan);
2109 }
2110
2111 /* What we've done for mode_parse so far... */
2112 #define DONE_LIMIT      0x01    /* We've set the limit */
2113 #define DONE_KEY        0x02    /* We've set the key */
2114 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2115 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2116 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2117 #define DONE_UPASS      0x20    /* We've set user pass */
2118 #define DONE_APASS      0x40    /* We've set admin pass */
2119
2120 struct ParseState {
2121   struct ModeBuf *mbuf;
2122   struct Client *cptr;
2123   struct Client *sptr;
2124   struct Channel *chptr;
2125   struct Membership *member;
2126   int parc;
2127   char **parv;
2128   unsigned int flags;
2129   unsigned int dir;
2130   unsigned int done;
2131   unsigned int add;
2132   unsigned int del;
2133   int args_used;
2134   int max_args;
2135   int numbans;
2136   struct SLink banlist[MAXPARA];
2137   struct {
2138     unsigned int flag;
2139     struct Client *client;
2140   } cli_change[MAXPARA];
2141 };
2142
2143 /*
2144  * Here's a helper function to deal with sending along "Not oper" or
2145  * "Not member" messages
2146  */
2147 static void
2148 send_notoper(struct ParseState *state)
2149 {
2150   if (state->done & DONE_NOTOPER)
2151     return;
2152
2153   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2154              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2155
2156   state->done |= DONE_NOTOPER;
2157 }
2158
2159 /*
2160  * Helper function to convert limits
2161  */
2162 static void
2163 mode_parse_limit(struct ParseState *state, int *flag_p)
2164 {
2165   unsigned int t_limit;
2166
2167   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2168     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2169       return;
2170
2171     if (state->parc <= 0) { /* warn if not enough args */
2172       if (MyUser(state->sptr))
2173         need_more_params(state->sptr, "MODE +l");
2174       return;
2175     }
2176
2177     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2178     state->parc--;
2179     state->max_args--;
2180
2181     if ((int)t_limit<0) /* don't permit a negative limit */
2182       return;
2183
2184     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2185         (!t_limit || t_limit == state->chptr->mode.limit))
2186       return;
2187   } else
2188     t_limit = state->chptr->mode.limit;
2189
2190   /* If they're not an oper, they can't change modes */
2191   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2192     send_notoper(state);
2193     return;
2194   }
2195
2196   /* Can't remove a limit that's not there */
2197   if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2198     return;
2199     
2200   /* Skip if this is a burst and a lower limit than this is set already */
2201   if ((state->flags & MODE_PARSE_BURST) &&
2202       (state->chptr->mode.mode & flag_p[0]) &&
2203       (state->chptr->mode.limit < t_limit))
2204     return;
2205
2206   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2207     return;
2208   state->done |= DONE_LIMIT;
2209
2210   if (!state->mbuf)
2211     return;
2212
2213   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2214
2215   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2216     if (state->dir & MODE_ADD) {
2217       state->chptr->mode.mode |= flag_p[0];
2218       state->chptr->mode.limit = t_limit;
2219     } else {
2220       state->chptr->mode.mode &= ~flag_p[0];
2221       state->chptr->mode.limit = 0;
2222     }
2223   }
2224 }
2225
2226 /*
2227  * Helper function to convert keys
2228  */
2229 static void
2230 mode_parse_key(struct ParseState *state, int *flag_p)
2231 {
2232   char *t_str, *s;
2233   int t_len;
2234
2235   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2236     return;
2237
2238   if (state->parc <= 0) { /* warn if not enough args */
2239     if (MyUser(state->sptr))
2240       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2241                        "MODE -k");
2242     return;
2243   }
2244
2245   t_str = state->parv[state->args_used++]; /* grab arg */
2246   state->parc--;
2247   state->max_args--;
2248
2249   /* If they're not an oper, they can't change modes */
2250   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2251     send_notoper(state);
2252     return;
2253   }
2254
2255   if (state->done & DONE_KEY) /* allow key to be set only once */
2256     return;
2257   state->done |= DONE_KEY;
2258
2259   t_len = KEYLEN;
2260
2261   /* clean up the key string */
2262   s = t_str;
2263   while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2264     s++;
2265   *s = '\0';
2266
2267   if (!*t_str) { /* warn if empty */
2268     if (MyUser(state->sptr))
2269       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2270                        "MODE -k");
2271     return;
2272   }
2273
2274   if (!state->mbuf)
2275     return;
2276
2277   /* Skip if this is a burst, we have a key already and the new key is 
2278    * after the old one alphabetically */
2279   if ((state->flags & MODE_PARSE_BURST) &&
2280       *(state->chptr->mode.key) &&
2281       ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2282     return;
2283
2284   /* can't add a key if one is set, nor can one remove the wrong key */
2285   if (!(state->flags & MODE_PARSE_FORCE))
2286     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2287         (state->dir == MODE_DEL &&
2288          ircd_strcmp(state->chptr->mode.key, t_str))) {
2289       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2290       return;
2291     }
2292
2293   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2294       !ircd_strcmp(state->chptr->mode.key, t_str))
2295     return; /* no key change */
2296
2297   if (state->flags & MODE_PARSE_BOUNCE) {
2298     if (*state->chptr->mode.key) /* reset old key */
2299       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2300                           state->chptr->mode.key, 0);
2301     else /* remove new bogus key */
2302       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2303   } else /* send new key */
2304     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2305
2306   if (state->flags & MODE_PARSE_SET) {
2307     if (state->dir == MODE_ADD) /* set the new key */
2308       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2309     else /* remove the old key */
2310       *state->chptr->mode.key = '\0';
2311   }
2312 }
2313
2314 /*
2315  * Helper function to convert user passes
2316  */
2317 static void
2318 mode_parse_upass(struct ParseState *state, int *flag_p)
2319 {
2320   char *t_str, *s;
2321   int t_len;
2322
2323   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2324     return;
2325
2326   if (state->parc <= 0) { /* warn if not enough args */
2327     if (MyUser(state->sptr))
2328       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2329                        "MODE -u");
2330     return;
2331   }
2332
2333   t_str = state->parv[state->args_used++]; /* grab arg */
2334   state->parc--;
2335   state->max_args--;
2336
2337   /* If they're not an oper, they can't change modes */
2338   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2339     send_notoper(state);
2340     return;
2341   }
2342
2343   /* If they are not the channel manager, they are not allowed to change it */
2344   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2345     if (*state->chptr->mode.apass) {
2346       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2347           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2348     } else {
2349       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2350           "Re-create the channel.  The channel must be *empty* for",
2351           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2352           "before it can be recreated.");
2353     }
2354     return;
2355   }
2356  
2357   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2358     return;
2359   state->done |= DONE_UPASS;
2360
2361   t_len = PASSLEN + 1;
2362
2363   /* clean up the upass string */
2364   s = t_str;
2365   while (*++s > ' ' && *s != ':' && --t_len)
2366     ;
2367   *s = '\0';
2368
2369   if (!*t_str) { /* warn if empty */
2370     if (MyUser(state->sptr))
2371       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2372                        "MODE -u");
2373     return;
2374   }
2375
2376   if (!state->mbuf)
2377     return;
2378
2379   if (!(state->flags & MODE_PARSE_FORCE))
2380     /* can't add the upass while apass is not set */
2381     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2382       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2383       return;
2384     }
2385     /* can't add a upass if one is set, nor can one remove the wrong upass */
2386     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2387         (state->dir == MODE_DEL &&
2388          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2389       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2390       return;
2391     }
2392
2393   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2394       !ircd_strcmp(state->chptr->mode.upass, t_str))
2395     return; /* no upass change */
2396
2397   if (state->flags & MODE_PARSE_BOUNCE) {
2398     if (*state->chptr->mode.upass) /* reset old upass */
2399       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2400                           state->chptr->mode.upass, 0);
2401     else /* remove new bogus upass */
2402       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2403   } else /* send new upass */
2404     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2405
2406   if (state->flags & MODE_PARSE_SET) {
2407     if (state->dir == MODE_ADD) /* set the new upass */
2408       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2409     else /* remove the old upass */
2410       *state->chptr->mode.upass = '\0';
2411   }
2412 }
2413
2414 /*
2415  * Helper function to convert admin passes
2416  */
2417 static void
2418 mode_parse_apass(struct ParseState *state, int *flag_p)
2419 {
2420   char *t_str, *s;
2421   int t_len;
2422
2423   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2424     return;
2425
2426   if (state->parc <= 0) { /* warn if not enough args */
2427     if (MyUser(state->sptr))
2428       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2429                        "MODE -A");
2430     return;
2431   }
2432
2433   t_str = state->parv[state->args_used++]; /* grab arg */
2434   state->parc--;
2435   state->max_args--;
2436
2437   /* If they're not an oper, they can't change modes */
2438   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2439     send_notoper(state);
2440     return;
2441   }
2442
2443   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2444   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2445     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2446     return;
2447   }
2448
2449   /* If they are not the channel manager, they are not allowed to change it */
2450   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2451     if (*state->chptr->mode.apass) {
2452       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2453           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2454     } else {
2455       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2456           "Re-create the channel.  The channel must be *empty* for",
2457           "at least a whole minute", "before it can be recreated.");
2458     }
2459     return;
2460   }
2461  
2462   if (state->done & DONE_APASS) /* allow apass to be set only once */
2463     return;
2464   state->done |= DONE_APASS;
2465
2466   t_len = PASSLEN + 1;
2467
2468   /* clean up the apass string */
2469   s = t_str;
2470   while (*++s > ' ' && *s != ':' && --t_len)
2471     ;
2472   *s = '\0';
2473
2474   if (!*t_str) { /* warn if empty */
2475     if (MyUser(state->sptr))
2476       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2477                        "MODE -A");
2478     return;
2479   }
2480
2481   if (!state->mbuf)
2482     return;
2483
2484   if (!(state->flags & MODE_PARSE_FORCE)) {
2485     /* can't remove the apass while upass is still set */
2486     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2487       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2488       return;
2489     }
2490     /* can't add an apass if one is set, nor can one remove the wrong apass */
2491     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2492         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2493       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2494       return;
2495     }
2496   }
2497
2498   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2499       !ircd_strcmp(state->chptr->mode.apass, t_str))
2500     return; /* no apass change */
2501
2502   if (state->flags & MODE_PARSE_BOUNCE) {
2503     if (*state->chptr->mode.apass) /* reset old apass */
2504       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2505                           state->chptr->mode.apass, 0);
2506     else /* remove new bogus apass */
2507       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2508   } else /* send new apass */
2509     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2510
2511   if (state->flags & MODE_PARSE_SET) {
2512     if (state->dir == MODE_ADD) { /* set the new apass */
2513       /* Make it VERY clear to the user that this is a one-time password */
2514       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2515       if (MyUser(state->sptr)) {
2516         send_reply(state->sptr, RPL_APASSWARN,
2517             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2518             "Are you SURE you want to use this as Admin password? ",
2519             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2520         send_reply(state->sptr, RPL_APASSWARN,
2521             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2522             "\" to remove the password and then immediately set a new one. "
2523             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2524             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2525             "Now set the channel user password (+u).");
2526       }
2527     } else { /* remove the old apass */
2528       *state->chptr->mode.apass = '\0';
2529       if (MyUser(state->sptr))
2530         send_reply(state->sptr, RPL_APASSWARN,
2531             "WARNING: You removed the channel Admin password MODE (+A). ",
2532             "If you would disconnect or leave the channel without setting a new password then you will ",
2533             "not be able to set it again and lose ownership of this channel! ",
2534             "SET A NEW PASSWORD NOW!", "");
2535     }
2536   }
2537 }
2538
2539 /*
2540  * Helper function to convert bans
2541  */
2542 static void
2543 mode_parse_ban(struct ParseState *state, int *flag_p)
2544 {
2545   char *t_str, *s;
2546   struct SLink *ban, *newban = 0;
2547
2548   if (state->parc <= 0) { /* Not enough args, send ban list */
2549     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2550       send_ban_list(state->sptr, state->chptr);
2551       state->done |= DONE_BANLIST;
2552     }
2553
2554     return;
2555   }
2556
2557   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2558     return;
2559
2560   t_str = state->parv[state->args_used++]; /* grab arg */
2561   state->parc--;
2562   state->max_args--;
2563
2564   /* If they're not an oper, they can't change modes */
2565   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2566     send_notoper(state);
2567     return;
2568   }
2569
2570   if ((s = strchr(t_str, ' ')))
2571     *s = '\0';
2572
2573   if (!*t_str || *t_str == ':') { /* warn if empty */
2574     if (MyUser(state->sptr))
2575       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2576                        "MODE -b");
2577     return;
2578   }
2579
2580   t_str = collapse(pretty_mask(t_str));
2581
2582   /* remember the ban for the moment... */
2583   if (state->dir == MODE_ADD) {
2584     newban = state->banlist + (state->numbans++);
2585     newban->next = 0;
2586
2587     DupString(newban->value.ban.banstr, t_str);
2588     newban->value.ban.who = cli_name(state->sptr);
2589     newban->value.ban.when = TStime();
2590
2591     newban->flags = CHFL_BAN | MODE_ADD;
2592
2593     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2594       newban->flags |= CHFL_BAN_IPMASK;
2595   }
2596
2597   if (!state->chptr->banlist) {
2598     state->chptr->banlist = newban; /* add our ban with its flags */
2599     state->done |= DONE_BANCLEAN;
2600     return;
2601   }
2602
2603   /* Go through all bans */
2604   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2605     /* first, clean the ban flags up a bit */
2606     if (!(state->done & DONE_BANCLEAN))
2607       /* Note: We're overloading *lots* of bits here; be careful! */
2608       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2609
2610     /* Bit meanings:
2611      *
2612      * MODE_ADD            - Ban was added; if we're bouncing modes,
2613      *                       then we'll remove it below; otherwise,
2614      *                       we'll have to allocate a real ban
2615      *
2616      * MODE_DEL            - Ban was marked for deletion; if we're
2617      *                       bouncing modes, we'll have to re-add it,
2618      *                       otherwise, we'll have to remove it
2619      *
2620      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2621      *                       with a ban already set; if we're
2622      *                       bouncing modes, we'll have to bounce
2623      *                       this one; otherwise, we'll just ignore
2624      *                       it when we process added bans
2625      */
2626
2627     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2628       ban->flags |= MODE_DEL; /* delete one ban */
2629
2630       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2631         break;
2632     } else if (state->dir == MODE_ADD) {
2633       /* if the ban already exists, don't worry about it */
2634       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2635         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2636         MyFree(newban->value.ban.banstr); /* stopper a leak */
2637         state->numbans--; /* deallocate last ban */
2638         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2639           break;
2640       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2641         if (!(ban->flags & MODE_DEL))
2642           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2643       } else if (!mmatch(t_str, ban->value.ban.banstr))
2644         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2645
2646       if (!ban->next && (newban->flags & MODE_ADD))
2647       {
2648         ban->next = newban; /* add our ban with its flags */
2649         break; /* get out of loop */
2650       }
2651     }
2652   }
2653   state->done |= DONE_BANCLEAN;
2654 }
2655
2656 /*
2657  * This is the bottom half of the ban processor
2658  */
2659 static void
2660 mode_process_bans(struct ParseState *state)
2661 {
2662   struct SLink *ban, *newban, *prevban, *nextban;
2663   int count = 0;
2664   int len = 0;
2665   int banlen;
2666   int changed = 0;
2667
2668   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2669     count++;
2670     banlen = strlen(ban->value.ban.banstr);
2671     len += banlen;
2672     nextban = ban->next;
2673
2674     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2675       if (prevban)
2676         prevban->next = 0; /* Break the list; ban isn't a real ban */
2677       else
2678         state->chptr->banlist = 0;
2679
2680       count--;
2681       len -= banlen;
2682
2683       MyFree(ban->value.ban.banstr);
2684
2685       continue;
2686     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2687       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2688                           ban->value.ban.banstr,
2689                           state->flags & MODE_PARSE_SET);
2690
2691       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2692         if (prevban) /* clip it out of the list... */
2693           prevban->next = ban->next;
2694         else
2695           state->chptr->banlist = ban->next;
2696
2697         count--;
2698         len -= banlen;
2699
2700         MyFree(ban->value.ban.who);
2701         free_link(ban);
2702
2703         changed++;
2704         continue; /* next ban; keep prevban like it is */
2705       } else
2706         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2707     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2708       if (prevban)
2709         prevban->next = 0; /* Break the list; ban isn't a real ban */
2710       else
2711         state->chptr->banlist = 0;
2712
2713       /* If we're supposed to ignore it, do so. */
2714       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2715           !(state->flags & MODE_PARSE_BOUNCE)) {
2716         count--;
2717         len -= banlen;
2718
2719         MyFree(ban->value.ban.banstr);
2720       } else {
2721         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2722             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2723              count > feature_int(FEAT_MAXBANS))) {
2724           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2725                      ban->value.ban.banstr);
2726           count--;
2727           len -= banlen;
2728
2729           MyFree(ban->value.ban.banstr);
2730         } else {
2731           /* add the ban to the buffer */
2732           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2733                               ban->value.ban.banstr,
2734                               !(state->flags & MODE_PARSE_SET));
2735
2736           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2737             newban = make_link();
2738             newban->value.ban.banstr = ban->value.ban.banstr;
2739             DupString(newban->value.ban.who, ban->value.ban.who);
2740             newban->value.ban.when = ban->value.ban.when;
2741             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2742
2743             newban->next = state->chptr->banlist; /* and link it in */
2744             state->chptr->banlist = newban;
2745
2746             changed++;
2747           }
2748         }
2749       }
2750     }
2751
2752     prevban = ban;
2753   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2754
2755   if (changed) /* if we changed the ban list, we must invalidate the bans */
2756     mode_ban_invalidate(state->chptr);
2757 }
2758
2759 /*
2760  * Helper function to process client changes
2761  */
2762 static void
2763 mode_parse_client(struct ParseState *state, int *flag_p)
2764 {
2765   char *t_str;
2766   struct Client *acptr;
2767   int i;
2768
2769   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2770     return;
2771
2772   if (state->parc <= 0) /* return if not enough args */
2773     return;
2774
2775   t_str = state->parv[state->args_used++]; /* grab arg */
2776   state->parc--;
2777   state->max_args--;
2778
2779   /* If they're not an oper, they can't change modes */
2780   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2781     send_notoper(state);
2782     return;
2783   }
2784
2785   if (MyUser(state->sptr)) /* find client we're manipulating */
2786     acptr = find_chasing(state->sptr, t_str, NULL);
2787   else
2788     acptr = findNUser(t_str);
2789
2790   if (!acptr)
2791     return; /* find_chasing() already reported an error to the user */
2792
2793   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2794     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2795                                        state->cli_change[i].flag & flag_p[0]))
2796       break; /* found a slot */
2797
2798   /* Store what we're doing to them */
2799   state->cli_change[i].flag = state->dir | flag_p[0];
2800   state->cli_change[i].client = acptr;
2801 }
2802
2803 /*
2804  * Helper function to process the changed client list
2805  */
2806 static void
2807 mode_process_clients(struct ParseState *state)
2808 {
2809   int i;
2810   struct Membership *member;
2811
2812   for (i = 0; state->cli_change[i].flag; i++) {
2813     assert(0 != state->cli_change[i].client);
2814
2815     /* look up member link */
2816     if (!(member = find_member_link(state->chptr,
2817                                     state->cli_change[i].client)) ||
2818         (MyUser(state->sptr) && IsZombie(member))) {
2819       if (MyUser(state->sptr))
2820         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2821                    cli_name(state->cli_change[i].client),
2822                    state->chptr->chname);
2823       continue;
2824     }
2825
2826     if ((state->cli_change[i].flag & MODE_ADD &&
2827          (state->cli_change[i].flag & member->status)) ||
2828         (state->cli_change[i].flag & MODE_DEL &&
2829          !(state->cli_change[i].flag & member->status)))
2830       continue; /* no change made, don't do anything */
2831
2832     /* see if the deop is allowed */
2833     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2834         (MODE_DEL | MODE_CHANOP)) {
2835       /* prevent +k users from being deopped */
2836       if (IsChannelService(state->cli_change[i].client)) {
2837         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2838           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2839                                state->chptr,
2840                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2841                                 cli_name((cli_user(state->sptr))->server)));
2842
2843         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2844           send_reply(state->sptr, ERR_ISCHANSERVICE,
2845                      cli_name(state->cli_change[i].client),
2846                      state->chptr->chname);
2847           continue;
2848         }
2849       }
2850
2851       /* check deop for local user */
2852       if (MyUser(state->sptr)) {
2853
2854         /* don't allow local opers to be deopped on local channels */
2855         if (state->cli_change[i].client != state->sptr &&
2856             IsLocalChannel(state->chptr->chname) &&
2857             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2858           send_reply(state->sptr, ERR_ISOPERLCHAN,
2859                      cli_name(state->cli_change[i].client),
2860                      state->chptr->chname);
2861           continue;
2862         }
2863
2864         if (feature_bool(FEAT_OPLEVELS)) {
2865         /* don't allow to deop members with an op level that is <= our own level */
2866         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2867                 && state->member
2868                 && OpLevel(member) <= OpLevel(state->member)) {
2869             int equal = (OpLevel(member) == OpLevel(state->member));
2870             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2871                        cli_name(state->cli_change[i].client),
2872                        state->chptr->chname,
2873                        OpLevel(state->member), OpLevel(member),
2874                        "deop", equal ? "the same" : "a higher");
2875           continue;
2876         }
2877       }
2878     }
2879     }
2880
2881     /* set op-level of member being opped */
2882     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2883         (MODE_ADD | MODE_CHANOP)) {
2884       /* If on a channel with upass set, someone with level x gives ops to someone else,
2885          then that person gets level x-1.  On other channels, where upass is not set,
2886          the level stays the same. */
2887       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2888       /* Someone being opped by a server gets op-level 0 */
2889       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2890       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2891     }
2892
2893     /* actually effect the change */
2894     if (state->flags & MODE_PARSE_SET) {
2895       if (state->cli_change[i].flag & MODE_ADD) {
2896         if (IsDelayedJoin(member))
2897           RevealDelayedJoin(member);
2898         member->status |= (state->cli_change[i].flag &
2899                            (MODE_CHANOP | MODE_VOICE));
2900         if (state->cli_change[i].flag & MODE_CHANOP)
2901           ClearDeopped(member);
2902       } else
2903         member->status &= ~(state->cli_change[i].flag &
2904                             (MODE_CHANOP | MODE_VOICE));
2905     }
2906
2907     /* accumulate the change */
2908     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2909                         state->cli_change[i].client);
2910   } /* for (i = 0; state->cli_change[i].flags; i++) */
2911 }
2912
2913 /*
2914  * Helper function to process the simple modes
2915  */
2916 static void
2917 mode_parse_mode(struct ParseState *state, int *flag_p)
2918 {
2919   /* If they're not an oper, they can't change modes */
2920   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2921     send_notoper(state);
2922     return;
2923   }
2924
2925   if (!state->mbuf)
2926     return;
2927
2928   if (state->dir == MODE_ADD) {
2929     state->add |= flag_p[0];
2930     state->del &= ~flag_p[0];
2931
2932     if (flag_p[0] & MODE_SECRET) {
2933       state->add &= ~MODE_PRIVATE;
2934       state->del |= MODE_PRIVATE;
2935     } else if (flag_p[0] & MODE_PRIVATE) {
2936       state->add &= ~MODE_SECRET;
2937       state->del |= MODE_SECRET;
2938     }
2939     if (flag_p[0] & MODE_DELJOINS) {
2940       state->add &= ~MODE_WASDELJOINS;
2941       state->del |= MODE_WASDELJOINS;
2942     }
2943   } else {
2944     state->add &= ~flag_p[0];
2945     state->del |= flag_p[0];
2946   }
2947
2948   assert(0 == (state->add & state->del));
2949   assert((MODE_SECRET | MODE_PRIVATE) !=
2950          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2951 }
2952
2953 /*
2954  * This routine is intended to parse MODE or OPMODE commands and effect the
2955  * changes (or just build the bounce buffer).  We pass the starting offset
2956  * as a 
2957  */
2958 int
2959 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2960            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2961            struct Membership* member)
2962 {
2963   static int chan_flags[] = {
2964     MODE_CHANOP,        'o',
2965     MODE_VOICE,         'v',
2966     MODE_PRIVATE,       'p',
2967     MODE_SECRET,        's',
2968     MODE_MODERATED,     'm',
2969     MODE_TOPICLIMIT,    't',
2970     MODE_INVITEONLY,    'i',
2971     MODE_NOPRIVMSGS,    'n',
2972     MODE_KEY,           'k',
2973     MODE_APASS,         'A',
2974     MODE_UPASS,         'u',
2975     MODE_BAN,           'b',
2976     MODE_LIMIT,         'l',
2977     MODE_REGONLY,       'r',
2978     MODE_DELJOINS,      'D',
2979     MODE_ADD,           '+',
2980     MODE_DEL,           '-',
2981     0x0, 0x0
2982   };
2983   int i;
2984   int *flag_p;
2985   unsigned int t_mode;
2986   char *modestr;
2987   struct ParseState state;
2988
2989   assert(0 != cptr);
2990   assert(0 != sptr);
2991   assert(0 != chptr);
2992   assert(0 != parc);
2993   assert(0 != parv);
2994
2995   state.mbuf = mbuf;
2996   state.cptr = cptr;
2997   state.sptr = sptr;
2998   state.chptr = chptr;
2999   state.member = member;
3000   state.parc = parc;
3001   state.parv = parv;
3002   state.flags = flags;
3003   state.dir = MODE_ADD;
3004   state.done = 0;
3005   state.add = 0;
3006   state.del = 0;
3007   state.args_used = 0;
3008   state.max_args = MAXMODEPARAMS;
3009   state.numbans = 0;
3010
3011   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3012     state.banlist[i].next = 0;
3013     state.banlist[i].value.ban.banstr = 0;
3014     state.banlist[i].value.ban.who = 0;
3015     state.banlist[i].value.ban.when = 0;
3016     state.banlist[i].flags = 0;
3017     state.cli_change[i].flag = 0;
3018     state.cli_change[i].client = 0;
3019   }
3020
3021   modestr = state.parv[state.args_used++];
3022   state.parc--;
3023
3024   while (*modestr) {
3025     for (; *modestr; modestr++) {
3026       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3027         if (flag_p[1] == *modestr)
3028           break;
3029
3030       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3031         if (MyUser(state.sptr))
3032           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3033         continue;
3034       }
3035
3036       switch (*modestr) {
3037       case '+': /* switch direction to MODE_ADD */
3038       case '-': /* switch direction to MODE_DEL */
3039         state.dir = flag_p[0];
3040         break;
3041
3042       case 'l': /* deal with limits */
3043         mode_parse_limit(&state, flag_p);
3044         break;
3045
3046       case 'k': /* deal with keys */
3047         mode_parse_key(&state, flag_p);
3048         break;
3049
3050       case 'A': /* deal with Admin passes */
3051         if (feature_bool(FEAT_OPLEVELS))
3052         mode_parse_apass(&state, flag_p);
3053         break;
3054
3055       case 'u': /* deal with user passes */
3056         if (feature_bool(FEAT_OPLEVELS))
3057         mode_parse_upass(&state, flag_p);
3058         break;
3059
3060       case 'b': /* deal with bans */
3061         mode_parse_ban(&state, flag_p);
3062         break;
3063
3064       case 'o': /* deal with ops/voice */
3065       case 'v':
3066         mode_parse_client(&state, flag_p);
3067         break;
3068
3069       default: /* deal with other modes */
3070         mode_parse_mode(&state, flag_p);
3071         break;
3072       } /* switch (*modestr) */
3073     } /* for (; *modestr; modestr++) */
3074
3075     if (state.flags & MODE_PARSE_BURST)
3076       break; /* don't interpret any more arguments */
3077
3078     if (state.parc > 0) { /* process next argument in string */
3079       modestr = state.parv[state.args_used++];
3080       state.parc--;
3081
3082       /* is it a TS? */
3083       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3084         time_t recv_ts;
3085
3086         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3087           break;                     /* we're then going to bounce the mode! */
3088
3089         recv_ts = atoi(modestr);
3090
3091         if (recv_ts && recv_ts < state.chptr->creationtime)
3092           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3093
3094         break; /* break out of while loop */
3095       } else if (state.flags & MODE_PARSE_STRICT ||
3096                  (MyUser(state.sptr) && state.max_args <= 0)) {
3097         state.parc++; /* we didn't actually gobble the argument */
3098         state.args_used--;
3099         break; /* break out of while loop */
3100       }
3101     }
3102   } /* while (*modestr) */
3103
3104   /*
3105    * the rest of the function finishes building resultant MODEs; if the
3106    * origin isn't a member or an oper, skip it.
3107    */
3108   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3109     return state.args_used; /* tell our parent how many args we gobbled */
3110
3111   t_mode = state.chptr->mode.mode;
3112
3113   if (state.del & t_mode) { /* delete any modes to be deleted... */
3114     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3115
3116     t_mode &= ~state.del;
3117   }
3118   if (state.add & ~t_mode) { /* add any modes to be added... */
3119     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3120
3121     t_mode |= state.add;
3122   }
3123
3124   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3125     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3126         !(t_mode & MODE_INVITEONLY))
3127       mode_invite_clear(state.chptr);
3128
3129     state.chptr->mode.mode = t_mode;
3130   }
3131
3132   if (state.flags & MODE_PARSE_WIPEOUT) {
3133     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3134       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3135                         state.chptr->mode.limit);
3136     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3137       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3138                           state.chptr->mode.key, 0);
3139     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3140       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3141                           state.chptr->mode.upass, 0);
3142     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3143       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3144                           state.chptr->mode.apass, 0);
3145   }
3146
3147   if (state.done & DONE_BANCLEAN) /* process bans */
3148     mode_process_bans(&state);
3149
3150   /* process client changes */
3151   if (state.cli_change[0].flag)
3152     mode_process_clients(&state);
3153
3154   return state.args_used; /* tell our parent how many args we gobbled */
3155 }
3156
3157 /*
3158  * Initialize a join buffer
3159  */
3160 void
3161 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3162              struct Client *connect, unsigned int type, char *comment,
3163              time_t create)
3164 {
3165   int i;
3166
3167   assert(0 != jbuf);
3168   assert(0 != source);
3169   assert(0 != connect);
3170
3171   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3172   jbuf->jb_connect = connect;
3173   jbuf->jb_type = type;
3174   jbuf->jb_comment = comment;
3175   jbuf->jb_create = create;
3176   jbuf->jb_count = 0;
3177   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3178                        type == JOINBUF_TYPE_PART ||
3179                        type == JOINBUF_TYPE_PARTALL) ?
3180                       STARTJOINLEN : STARTCREATELEN) +
3181                      (comment ? strlen(comment) + 2 : 0));
3182
3183   for (i = 0; i < MAXJOINARGS; i++)
3184     jbuf->jb_channels[i] = 0;
3185 }
3186
3187 /*
3188  * Add a channel to the join buffer
3189  */
3190 void
3191 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3192 {
3193   unsigned int len;
3194   int is_local;
3195
3196   assert(0 != jbuf);
3197
3198   if (!chan) {
3199     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3200       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3201
3202     return;
3203   }
3204
3205   is_local = IsLocalChannel(chan->chname);
3206
3207   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3208       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3209     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3210     if (IsUserParting(member))
3211       return;
3212     SetUserParting(member);
3213
3214     /* Send notification to channel */
3215     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3216       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3217                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3218                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3219     else if (MyUser(jbuf->jb_source))
3220       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3221                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3222                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3223     /* XXX: Shouldn't we send a PART here anyway? */
3224     /* to users on the channel?  Why?  From their POV, the user isn't on
3225      * the channel anymore anyway.  We don't send to servers until below,
3226      * when we gang all the channel parts together.  Note that this is
3227      * exactly the same logic, albeit somewhat more concise, as was in
3228      * the original m_part.c */
3229
3230     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3231         is_local) /* got to remove user here */
3232       remove_user_from_channel(jbuf->jb_source, chan);
3233   } else {
3234     /* Add user to channel */
3235     if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3236       add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3237     else
3238       add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3239
3240     /* send notification to all servers */
3241     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3242       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3243                             "%H %Tu", chan, chan->creationtime);
3244
3245     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3246       /* Send the notification to the channel */
3247       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3248
3249       /* send an op, too, if needed */
3250       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3251         sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3252                                          chan, jbuf->jb_source);
3253     } else if (MyUser(jbuf->jb_source))
3254       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3255   }
3256
3257   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3258       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3259     return; /* don't send to remote */
3260
3261   /* figure out if channel name will cause buffer to be overflowed */
3262   len = chan ? strlen(chan->chname) + 1 : 2;
3263   if (jbuf->jb_strlen + len > BUFSIZE)
3264     joinbuf_flush(jbuf);
3265
3266   /* add channel to list of channels to send and update counts */
3267   jbuf->jb_channels[jbuf->jb_count++] = chan;
3268   jbuf->jb_strlen += len;
3269
3270   /* if we've used up all slots, flush */
3271   if (jbuf->jb_count >= MAXJOINARGS)
3272     joinbuf_flush(jbuf);
3273 }
3274
3275 /*
3276  * Flush the channel list to remote servers
3277  */
3278 int
3279 joinbuf_flush(struct JoinBuf *jbuf)
3280 {
3281   char chanlist[BUFSIZE];
3282   int chanlist_i = 0;
3283   int i;
3284
3285   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3286       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3287     return 0; /* no joins to process */
3288
3289   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3290     build_string(chanlist, &chanlist_i,
3291                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3292                  i == 0 ? '\0' : ',');
3293     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3294       /* Remove user from channel */
3295       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3296
3297     jbuf->jb_channels[i] = 0; /* mark slot empty */
3298   }
3299
3300   jbuf->jb_count = 0; /* reset base counters */
3301   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3302                       STARTJOINLEN : STARTCREATELEN) +
3303                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3304
3305   /* and send the appropriate command */
3306   switch (jbuf->jb_type) {
3307   case JOINBUF_TYPE_CREATE:
3308     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3309                           "%s %Tu", chanlist, jbuf->jb_create);
3310     break;
3311
3312   case JOINBUF_TYPE_PART:
3313     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3314                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3315                           jbuf->jb_comment);
3316     break;
3317   }
3318
3319   return 0;
3320 }
3321
3322 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3323 int IsInvited(struct Client* cptr, const void* chptr)
3324 {
3325   struct SLink *lp;
3326
3327   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3328     if (lp->value.chptr == chptr)
3329       return 1;
3330   return 0;
3331 }
3332
3333 /* RevealDelayedJoin: sends a join for a hidden user */
3334
3335 void RevealDelayedJoin(struct Membership *member) {
3336   ClearDelayedJoin(member);
3337   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3338                                    member->channel);
3339   CheckDelayedJoins(member->channel);
3340 }
3341
3342 /* CheckDelayedJoins: checks and clear +d if necessary */
3343
3344 void CheckDelayedJoins(struct Channel *chan) {
3345   struct Membership *memb2;
3346   
3347   if (chan->mode.mode & MODE_WASDELJOINS) {
3348     for (memb2=chan->members;memb2;memb2=memb2->next_member)
3349       if (IsDelayedJoin(memb2))
3350         break;
3351     
3352     if (!memb2) {
3353       /* clear +d */
3354       chan->mode.mode &= ~MODE_WASDELJOINS;
3355       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
3356                                        "%H -d", chan);
3357     }
3358   }
3359 }