Send "XXYYY:o" instead of "XXYYY:0" for ops when oplevels are disabled.
[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 =  feature_bool(FEAT_OPLEVELS);
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   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1934   MB_UINT(mbuf, mbuf->mb_count) = uint;
1935
1936   /* when we've reached the maximal count, flush the buffer */
1937   if (++mbuf->mb_count >=
1938       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1939     modebuf_flush_int(mbuf, 0);
1940 }
1941
1942 /*
1943  * This routine adds a mode to be added or deleted that takes a string
1944  * parameter; mode may *only* be the relevant mode flag ORed with one of
1945  * MODE_ADD or MODE_DEL
1946  */
1947 void
1948 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1949                     int free)
1950 {
1951   assert(0 != mbuf);
1952   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1953
1954   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1955   MB_STRING(mbuf, mbuf->mb_count) = string;
1956
1957   /* when we've reached the maximal count, flush the buffer */
1958   if (++mbuf->mb_count >=
1959       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1960     modebuf_flush_int(mbuf, 0);
1961 }
1962
1963 /*
1964  * This routine adds a mode to be added or deleted that takes a client
1965  * parameter; mode may *only* be the relevant mode flag ORed with one of
1966  * MODE_ADD or MODE_DEL
1967  */
1968 void
1969 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1970                     struct Client *client)
1971 {
1972   assert(0 != mbuf);
1973   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1974
1975   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1976   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1977
1978   /* when we've reached the maximal count, flush the buffer */
1979   if (++mbuf->mb_count >=
1980       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1981     modebuf_flush_int(mbuf, 0);
1982 }
1983
1984 /*
1985  * This is the exported binding for modebuf_flush()
1986  */
1987 int
1988 modebuf_flush(struct ModeBuf *mbuf)
1989 {
1990   struct Membership *memb;
1991
1992   /* Check if MODE_WASDELJOINS should be set */
1993   if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1994       && (mbuf->mb_rem & MODE_DELJOINS)) {
1995     for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
1996       if (IsDelayedJoin(memb)) {
1997           mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
1998           mbuf->mb_add |= MODE_WASDELJOINS;
1999           mbuf->mb_rem &= ~MODE_WASDELJOINS;
2000           break;
2001       }
2002     }
2003   }
2004
2005   return modebuf_flush_int(mbuf, 1);
2006 }
2007
2008 /*
2009  * This extracts the simple modes contained in mbuf
2010  */
2011 void
2012 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2013 {
2014   static int flags[] = {
2015 /*  MODE_CHANOP,        'o', */
2016 /*  MODE_VOICE,         'v', */
2017     MODE_PRIVATE,       'p',
2018     MODE_SECRET,        's',
2019     MODE_MODERATED,     'm',
2020     MODE_TOPICLIMIT,    't',
2021     MODE_INVITEONLY,    'i',
2022     MODE_NOPRIVMSGS,    'n',
2023     MODE_KEY,           'k',
2024     MODE_APASS,         'A',
2025     MODE_UPASS,         'u',
2026 /*  MODE_BAN,           'b', */
2027     MODE_LIMIT,         'l',
2028     MODE_REGONLY,       'r',
2029     MODE_DELJOINS,      'D',
2030     0x0, 0x0
2031   };
2032   unsigned int add;
2033   int i, bufpos = 0, len;
2034   int *flag_p;
2035   char *key = 0, limitbuf[20];
2036   char *apass = 0, *upass = 0;
2037
2038   assert(0 != mbuf);
2039   assert(0 != buf);
2040
2041   buf[0] = '\0';
2042
2043   add = mbuf->mb_add;
2044
2045   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2046     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2047       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2048
2049       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2050         key = MB_STRING(mbuf, i);
2051       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2052         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2053       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2054         upass = MB_STRING(mbuf, i);
2055       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2056         apass = MB_STRING(mbuf, i);
2057     }
2058   }
2059
2060   if (!add)
2061     return;
2062
2063   buf[bufpos++] = '+'; /* start building buffer */
2064
2065   for (flag_p = flags; flag_p[0]; flag_p += 2)
2066     if (*flag_p & add)
2067       buf[bufpos++] = flag_p[1];
2068
2069   for (i = 0, len = bufpos; i < len; i++) {
2070     if (buf[i] == 'k')
2071       build_string(buf, &bufpos, key, 0, ' ');
2072     else if (buf[i] == 'l')
2073       build_string(buf, &bufpos, limitbuf, 0, ' ');
2074     else if (buf[i] == 'u')
2075       build_string(buf, &bufpos, upass, 0, ' ');
2076     else if (buf[i] == 'A')
2077       build_string(buf, &bufpos, apass, 0, ' ');
2078   }
2079
2080   buf[bufpos] = '\0';
2081
2082   return;
2083 }
2084
2085 /*
2086  * Simple function to invalidate bans
2087  */
2088 void
2089 mode_ban_invalidate(struct Channel *chan)
2090 {
2091   struct Membership *member;
2092
2093   for (member = chan->members; member; member = member->next_member)
2094     ClearBanValid(member);
2095 }
2096
2097 /*
2098  * Simple function to drop invite structures
2099  */
2100 void
2101 mode_invite_clear(struct Channel *chan)
2102 {
2103   while (chan->invites)
2104     del_invite(chan->invites->value.cptr, chan);
2105 }
2106
2107 /* What we've done for mode_parse so far... */
2108 #define DONE_LIMIT      0x01    /* We've set the limit */
2109 #define DONE_KEY        0x02    /* We've set the key */
2110 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2111 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2112 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2113 #define DONE_UPASS      0x20    /* We've set user pass */
2114 #define DONE_APASS      0x40    /* We've set admin pass */
2115
2116 struct ParseState {
2117   struct ModeBuf *mbuf;
2118   struct Client *cptr;
2119   struct Client *sptr;
2120   struct Channel *chptr;
2121   struct Membership *member;
2122   int parc;
2123   char **parv;
2124   unsigned int flags;
2125   unsigned int dir;
2126   unsigned int done;
2127   unsigned int add;
2128   unsigned int del;
2129   int args_used;
2130   int max_args;
2131   int numbans;
2132   struct SLink banlist[MAXPARA];
2133   struct {
2134     unsigned int flag;
2135     struct Client *client;
2136   } cli_change[MAXPARA];
2137 };
2138
2139 /*
2140  * Here's a helper function to deal with sending along "Not oper" or
2141  * "Not member" messages
2142  */
2143 static void
2144 send_notoper(struct ParseState *state)
2145 {
2146   if (state->done & DONE_NOTOPER)
2147     return;
2148
2149   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2150              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2151
2152   state->done |= DONE_NOTOPER;
2153 }
2154
2155 /*
2156  * Helper function to convert limits
2157  */
2158 static void
2159 mode_parse_limit(struct ParseState *state, int *flag_p)
2160 {
2161   unsigned int t_limit;
2162
2163   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2164     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2165       return;
2166
2167     if (state->parc <= 0) { /* warn if not enough args */
2168       if (MyUser(state->sptr))
2169         need_more_params(state->sptr, "MODE +l");
2170       return;
2171     }
2172
2173     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2174     state->parc--;
2175     state->max_args--;
2176
2177     if ((int)t_limit<0) /* don't permit a negative limit */
2178       return;
2179
2180     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2181         (!t_limit || t_limit == state->chptr->mode.limit))
2182       return;
2183   } else
2184     t_limit = state->chptr->mode.limit;
2185
2186   /* If they're not an oper, they can't change modes */
2187   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2188     send_notoper(state);
2189     return;
2190   }
2191
2192   /* Can't remove a limit that's not there */
2193   if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2194     return;
2195     
2196   /* Skip if this is a burst and a lower limit than this is set already */
2197   if ((state->flags & MODE_PARSE_BURST) &&
2198       (state->chptr->mode.mode & flag_p[0]) &&
2199       (state->chptr->mode.limit < t_limit))
2200     return;
2201
2202   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2203     return;
2204   state->done |= DONE_LIMIT;
2205
2206   if (!state->mbuf)
2207     return;
2208
2209   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2210
2211   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2212     if (state->dir & MODE_ADD) {
2213       state->chptr->mode.mode |= flag_p[0];
2214       state->chptr->mode.limit = t_limit;
2215     } else {
2216       state->chptr->mode.mode &= ~flag_p[0];
2217       state->chptr->mode.limit = 0;
2218     }
2219   }
2220 }
2221
2222 /*
2223  * Helper function to convert keys
2224  */
2225 static void
2226 mode_parse_key(struct ParseState *state, int *flag_p)
2227 {
2228   char *t_str, *s;
2229   int t_len;
2230
2231   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2232     return;
2233
2234   if (state->parc <= 0) { /* warn if not enough args */
2235     if (MyUser(state->sptr))
2236       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2237                        "MODE -k");
2238     return;
2239   }
2240
2241   t_str = state->parv[state->args_used++]; /* grab arg */
2242   state->parc--;
2243   state->max_args--;
2244
2245   /* If they're not an oper, they can't change modes */
2246   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2247     send_notoper(state);
2248     return;
2249   }
2250
2251   if (state->done & DONE_KEY) /* allow key to be set only once */
2252     return;
2253   state->done |= DONE_KEY;
2254
2255   t_len = KEYLEN;
2256
2257   /* clean up the key string */
2258   s = t_str;
2259   while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2260     s++;
2261   *s = '\0';
2262
2263   if (!*t_str) { /* warn if empty */
2264     if (MyUser(state->sptr))
2265       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2266                        "MODE -k");
2267     return;
2268   }
2269
2270   if (!state->mbuf)
2271     return;
2272
2273   /* Skip if this is a burst, we have a key already and the new key is 
2274    * after the old one alphabetically */
2275   if ((state->flags & MODE_PARSE_BURST) &&
2276       *(state->chptr->mode.key) &&
2277       ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2278     return;
2279
2280   /* can't add a key if one is set, nor can one remove the wrong key */
2281   if (!(state->flags & MODE_PARSE_FORCE))
2282     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2283         (state->dir == MODE_DEL &&
2284          ircd_strcmp(state->chptr->mode.key, t_str))) {
2285       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2286       return;
2287     }
2288
2289   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2290       !ircd_strcmp(state->chptr->mode.key, t_str))
2291     return; /* no key change */
2292
2293   if (state->flags & MODE_PARSE_BOUNCE) {
2294     if (*state->chptr->mode.key) /* reset old key */
2295       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2296                           state->chptr->mode.key, 0);
2297     else /* remove new bogus key */
2298       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2299   } else /* send new key */
2300     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2301
2302   if (state->flags & MODE_PARSE_SET) {
2303     if (state->dir == MODE_ADD) /* set the new key */
2304       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2305     else /* remove the old key */
2306       *state->chptr->mode.key = '\0';
2307   }
2308 }
2309
2310 /*
2311  * Helper function to convert user passes
2312  */
2313 static void
2314 mode_parse_upass(struct ParseState *state, int *flag_p)
2315 {
2316   char *t_str, *s;
2317   int t_len;
2318
2319   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2320     return;
2321
2322   if (state->parc <= 0) { /* warn if not enough args */
2323     if (MyUser(state->sptr))
2324       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2325                        "MODE -u");
2326     return;
2327   }
2328
2329   t_str = state->parv[state->args_used++]; /* grab arg */
2330   state->parc--;
2331   state->max_args--;
2332
2333   /* If they're not an oper, they can't change modes */
2334   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2335     send_notoper(state);
2336     return;
2337   }
2338
2339   /* If they are not the channel manager, they are not allowed to change it */
2340   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2341     if (*state->chptr->mode.apass) {
2342       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2343           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2344     } else {
2345       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2346           "Re-create the channel.  The channel must be *empty* for",
2347           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2348           "before it can be recreated.");
2349     }
2350     return;
2351   }
2352  
2353   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2354     return;
2355   state->done |= DONE_UPASS;
2356
2357   t_len = PASSLEN + 1;
2358
2359   /* clean up the upass string */
2360   s = t_str;
2361   while (*++s > ' ' && *s != ':' && --t_len)
2362     ;
2363   *s = '\0';
2364
2365   if (!*t_str) { /* warn if empty */
2366     if (MyUser(state->sptr))
2367       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2368                        "MODE -u");
2369     return;
2370   }
2371
2372   if (!state->mbuf)
2373     return;
2374
2375   if (!(state->flags & MODE_PARSE_FORCE))
2376     /* can't add the upass while apass is not set */
2377     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2378       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2379       return;
2380     }
2381     /* can't add a upass if one is set, nor can one remove the wrong upass */
2382     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2383         (state->dir == MODE_DEL &&
2384          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2385       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2386       return;
2387     }
2388
2389   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2390       !ircd_strcmp(state->chptr->mode.upass, t_str))
2391     return; /* no upass change */
2392
2393   if (state->flags & MODE_PARSE_BOUNCE) {
2394     if (*state->chptr->mode.upass) /* reset old upass */
2395       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2396                           state->chptr->mode.upass, 0);
2397     else /* remove new bogus upass */
2398       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2399   } else /* send new upass */
2400     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2401
2402   if (state->flags & MODE_PARSE_SET) {
2403     if (state->dir == MODE_ADD) /* set the new upass */
2404       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2405     else /* remove the old upass */
2406       *state->chptr->mode.upass = '\0';
2407   }
2408 }
2409
2410 /*
2411  * Helper function to convert admin passes
2412  */
2413 static void
2414 mode_parse_apass(struct ParseState *state, int *flag_p)
2415 {
2416   char *t_str, *s;
2417   int t_len;
2418
2419   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2420     return;
2421
2422   if (state->parc <= 0) { /* warn if not enough args */
2423     if (MyUser(state->sptr))
2424       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2425                        "MODE -A");
2426     return;
2427   }
2428
2429   t_str = state->parv[state->args_used++]; /* grab arg */
2430   state->parc--;
2431   state->max_args--;
2432
2433   /* If they're not an oper, they can't change modes */
2434   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2435     send_notoper(state);
2436     return;
2437   }
2438
2439   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2440   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2441     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2442     return;
2443   }
2444
2445   /* If they are not the channel manager, they are not allowed to change it */
2446   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2447     if (*state->chptr->mode.apass) {
2448       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2449           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2450     } else {
2451       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2452           "Re-create the channel.  The channel must be *empty* for",
2453           "at least a whole minute", "before it can be recreated.");
2454     }
2455     return;
2456   }
2457  
2458   if (state->done & DONE_APASS) /* allow apass to be set only once */
2459     return;
2460   state->done |= DONE_APASS;
2461
2462   t_len = PASSLEN + 1;
2463
2464   /* clean up the apass string */
2465   s = t_str;
2466   while (*++s > ' ' && *s != ':' && --t_len)
2467     ;
2468   *s = '\0';
2469
2470   if (!*t_str) { /* warn if empty */
2471     if (MyUser(state->sptr))
2472       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2473                        "MODE -A");
2474     return;
2475   }
2476
2477   if (!state->mbuf)
2478     return;
2479
2480   if (!(state->flags & MODE_PARSE_FORCE)) {
2481     /* can't remove the apass while upass is still set */
2482     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2483       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2484       return;
2485     }
2486     /* can't add an apass if one is set, nor can one remove the wrong apass */
2487     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2488         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2489       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2490       return;
2491     }
2492   }
2493
2494   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2495       !ircd_strcmp(state->chptr->mode.apass, t_str))
2496     return; /* no apass change */
2497
2498   if (state->flags & MODE_PARSE_BOUNCE) {
2499     if (*state->chptr->mode.apass) /* reset old apass */
2500       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2501                           state->chptr->mode.apass, 0);
2502     else /* remove new bogus apass */
2503       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2504   } else /* send new apass */
2505     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2506
2507   if (state->flags & MODE_PARSE_SET) {
2508     if (state->dir == MODE_ADD) { /* set the new apass */
2509       /* Make it VERY clear to the user that this is a one-time password */
2510       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2511       if (MyUser(state->sptr)) {
2512         send_reply(state->sptr, RPL_APASSWARN,
2513             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2514             "Are you SURE you want to use this as Admin password? ",
2515             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2516         send_reply(state->sptr, RPL_APASSWARN,
2517             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2518             "\" to remove the password and then immediately set a new one. "
2519             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2520             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2521             "Now set the channel user password (+u).");
2522       }
2523     } else { /* remove the old apass */
2524       *state->chptr->mode.apass = '\0';
2525       if (MyUser(state->sptr))
2526         send_reply(state->sptr, RPL_APASSWARN,
2527             "WARNING: You removed the channel Admin password MODE (+A). ",
2528             "If you would disconnect or leave the channel without setting a new password then you will ",
2529             "not be able to set it again and lose ownership of this channel! ",
2530             "SET A NEW PASSWORD NOW!", "");
2531     }
2532   }
2533 }
2534
2535 /*
2536  * Helper function to convert bans
2537  */
2538 static void
2539 mode_parse_ban(struct ParseState *state, int *flag_p)
2540 {
2541   char *t_str, *s;
2542   struct SLink *ban, *newban = 0;
2543
2544   if (state->parc <= 0) { /* Not enough args, send ban list */
2545     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2546       send_ban_list(state->sptr, state->chptr);
2547       state->done |= DONE_BANLIST;
2548     }
2549
2550     return;
2551   }
2552
2553   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2554     return;
2555
2556   t_str = state->parv[state->args_used++]; /* grab arg */
2557   state->parc--;
2558   state->max_args--;
2559
2560   /* If they're not an oper, they can't change modes */
2561   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2562     send_notoper(state);
2563     return;
2564   }
2565
2566   if ((s = strchr(t_str, ' ')))
2567     *s = '\0';
2568
2569   if (!*t_str || *t_str == ':') { /* warn if empty */
2570     if (MyUser(state->sptr))
2571       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2572                        "MODE -b");
2573     return;
2574   }
2575
2576   t_str = collapse(pretty_mask(t_str));
2577
2578   /* remember the ban for the moment... */
2579   if (state->dir == MODE_ADD) {
2580     newban = state->banlist + (state->numbans++);
2581     newban->next = 0;
2582
2583     DupString(newban->value.ban.banstr, t_str);
2584     newban->value.ban.who = cli_name(state->sptr);
2585     newban->value.ban.when = TStime();
2586
2587     newban->flags = CHFL_BAN | MODE_ADD;
2588
2589     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2590       newban->flags |= CHFL_BAN_IPMASK;
2591   }
2592
2593   if (!state->chptr->banlist) {
2594     state->chptr->banlist = newban; /* add our ban with its flags */
2595     state->done |= DONE_BANCLEAN;
2596     return;
2597   }
2598
2599   /* Go through all bans */
2600   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2601     /* first, clean the ban flags up a bit */
2602     if (!(state->done & DONE_BANCLEAN))
2603       /* Note: We're overloading *lots* of bits here; be careful! */
2604       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2605
2606     /* Bit meanings:
2607      *
2608      * MODE_ADD            - Ban was added; if we're bouncing modes,
2609      *                       then we'll remove it below; otherwise,
2610      *                       we'll have to allocate a real ban
2611      *
2612      * MODE_DEL            - Ban was marked for deletion; if we're
2613      *                       bouncing modes, we'll have to re-add it,
2614      *                       otherwise, we'll have to remove it
2615      *
2616      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2617      *                       with a ban already set; if we're
2618      *                       bouncing modes, we'll have to bounce
2619      *                       this one; otherwise, we'll just ignore
2620      *                       it when we process added bans
2621      */
2622
2623     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2624       ban->flags |= MODE_DEL; /* delete one ban */
2625
2626       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2627         break;
2628     } else if (state->dir == MODE_ADD) {
2629       /* if the ban already exists, don't worry about it */
2630       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2631         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2632         MyFree(newban->value.ban.banstr); /* stopper a leak */
2633         state->numbans--; /* deallocate last ban */
2634         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2635           break;
2636       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2637         if (!(ban->flags & MODE_DEL))
2638           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2639       } else if (!mmatch(t_str, ban->value.ban.banstr))
2640         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2641
2642       if (!ban->next && (newban->flags & MODE_ADD))
2643       {
2644         ban->next = newban; /* add our ban with its flags */
2645         break; /* get out of loop */
2646       }
2647     }
2648   }
2649   state->done |= DONE_BANCLEAN;
2650 }
2651
2652 /*
2653  * This is the bottom half of the ban processor
2654  */
2655 static void
2656 mode_process_bans(struct ParseState *state)
2657 {
2658   struct SLink *ban, *newban, *prevban, *nextban;
2659   int count = 0;
2660   int len = 0;
2661   int banlen;
2662   int changed = 0;
2663
2664   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2665     count++;
2666     banlen = strlen(ban->value.ban.banstr);
2667     len += banlen;
2668     nextban = ban->next;
2669
2670     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2671       if (prevban)
2672         prevban->next = 0; /* Break the list; ban isn't a real ban */
2673       else
2674         state->chptr->banlist = 0;
2675
2676       count--;
2677       len -= banlen;
2678
2679       MyFree(ban->value.ban.banstr);
2680
2681       continue;
2682     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2683       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2684                           ban->value.ban.banstr,
2685                           state->flags & MODE_PARSE_SET);
2686
2687       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2688         if (prevban) /* clip it out of the list... */
2689           prevban->next = ban->next;
2690         else
2691           state->chptr->banlist = ban->next;
2692
2693         count--;
2694         len -= banlen;
2695
2696         MyFree(ban->value.ban.who);
2697         free_link(ban);
2698
2699         changed++;
2700         continue; /* next ban; keep prevban like it is */
2701       } else
2702         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2703     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2704       if (prevban)
2705         prevban->next = 0; /* Break the list; ban isn't a real ban */
2706       else
2707         state->chptr->banlist = 0;
2708
2709       /* If we're supposed to ignore it, do so. */
2710       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2711           !(state->flags & MODE_PARSE_BOUNCE)) {
2712         count--;
2713         len -= banlen;
2714
2715         MyFree(ban->value.ban.banstr);
2716       } else {
2717         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2718             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2719              count > feature_int(FEAT_MAXBANS))) {
2720           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2721                      ban->value.ban.banstr);
2722           count--;
2723           len -= banlen;
2724
2725           MyFree(ban->value.ban.banstr);
2726         } else {
2727           /* add the ban to the buffer */
2728           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2729                               ban->value.ban.banstr,
2730                               !(state->flags & MODE_PARSE_SET));
2731
2732           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2733             newban = make_link();
2734             newban->value.ban.banstr = ban->value.ban.banstr;
2735             DupString(newban->value.ban.who, ban->value.ban.who);
2736             newban->value.ban.when = ban->value.ban.when;
2737             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2738
2739             newban->next = state->chptr->banlist; /* and link it in */
2740             state->chptr->banlist = newban;
2741
2742             changed++;
2743           }
2744         }
2745       }
2746     }
2747
2748     prevban = ban;
2749   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2750
2751   if (changed) /* if we changed the ban list, we must invalidate the bans */
2752     mode_ban_invalidate(state->chptr);
2753 }
2754
2755 /*
2756  * Helper function to process client changes
2757  */
2758 static void
2759 mode_parse_client(struct ParseState *state, int *flag_p)
2760 {
2761   char *t_str;
2762   struct Client *acptr;
2763   int i;
2764
2765   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2766     return;
2767
2768   if (state->parc <= 0) /* return if not enough args */
2769     return;
2770
2771   t_str = state->parv[state->args_used++]; /* grab arg */
2772   state->parc--;
2773   state->max_args--;
2774
2775   /* If they're not an oper, they can't change modes */
2776   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2777     send_notoper(state);
2778     return;
2779   }
2780
2781   if (MyUser(state->sptr)) /* find client we're manipulating */
2782     acptr = find_chasing(state->sptr, t_str, NULL);
2783   else
2784     acptr = findNUser(t_str);
2785
2786   if (!acptr)
2787     return; /* find_chasing() already reported an error to the user */
2788
2789   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2790     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2791                                        state->cli_change[i].flag & flag_p[0]))
2792       break; /* found a slot */
2793
2794   /* Store what we're doing to them */
2795   state->cli_change[i].flag = state->dir | flag_p[0];
2796   state->cli_change[i].client = acptr;
2797 }
2798
2799 /*
2800  * Helper function to process the changed client list
2801  */
2802 static void
2803 mode_process_clients(struct ParseState *state)
2804 {
2805   int i;
2806   struct Membership *member;
2807
2808   for (i = 0; state->cli_change[i].flag; i++) {
2809     assert(0 != state->cli_change[i].client);
2810
2811     /* look up member link */
2812     if (!(member = find_member_link(state->chptr,
2813                                     state->cli_change[i].client)) ||
2814         (MyUser(state->sptr) && IsZombie(member))) {
2815       if (MyUser(state->sptr))
2816         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2817                    cli_name(state->cli_change[i].client),
2818                    state->chptr->chname);
2819       continue;
2820     }
2821
2822     if ((state->cli_change[i].flag & MODE_ADD &&
2823          (state->cli_change[i].flag & member->status)) ||
2824         (state->cli_change[i].flag & MODE_DEL &&
2825          !(state->cli_change[i].flag & member->status)))
2826       continue; /* no change made, don't do anything */
2827
2828     /* see if the deop is allowed */
2829     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2830         (MODE_DEL | MODE_CHANOP)) {
2831       /* prevent +k users from being deopped */
2832       if (IsChannelService(state->cli_change[i].client)) {
2833         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2834           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2835                                state->chptr,
2836                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2837                                 cli_name((cli_user(state->sptr))->server)));
2838
2839         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2840           send_reply(state->sptr, ERR_ISCHANSERVICE,
2841                      cli_name(state->cli_change[i].client),
2842                      state->chptr->chname);
2843           continue;
2844         }
2845       }
2846
2847       /* check deop for local user */
2848       if (MyUser(state->sptr)) {
2849
2850         /* don't allow local opers to be deopped on local channels */
2851         if (state->cli_change[i].client != state->sptr &&
2852             IsLocalChannel(state->chptr->chname) &&
2853             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2854           send_reply(state->sptr, ERR_ISOPERLCHAN,
2855                      cli_name(state->cli_change[i].client),
2856                      state->chptr->chname);
2857           continue;
2858         }
2859
2860         if (feature_bool(FEAT_OPLEVELS)) {
2861         /* don't allow to deop members with an op level that is <= our own level */
2862         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2863                 && state->member
2864                 && OpLevel(member) <= OpLevel(state->member)) {
2865             int equal = (OpLevel(member) == OpLevel(state->member));
2866             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2867                        cli_name(state->cli_change[i].client),
2868                        state->chptr->chname,
2869                        OpLevel(state->member), OpLevel(member),
2870                        "deop", equal ? "the same" : "a higher");
2871           continue;
2872         }
2873       }
2874     }
2875     }
2876
2877     /* set op-level of member being opped */
2878     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2879         (MODE_ADD | MODE_CHANOP)) {
2880       /* If on a channel with upass set, someone with level x gives ops to someone else,
2881          then that person gets level x-1.  On other channels, where upass is not set,
2882          the level stays the same. */
2883       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2884       /* Someone being opped by a server gets op-level 0 */
2885       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2886       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2887     }
2888
2889     /* actually effect the change */
2890     if (state->flags & MODE_PARSE_SET) {
2891       if (state->cli_change[i].flag & MODE_ADD) {
2892         if (IsDelayedJoin(member))
2893           RevealDelayedJoin(member);
2894         member->status |= (state->cli_change[i].flag &
2895                            (MODE_CHANOP | MODE_VOICE));
2896         if (state->cli_change[i].flag & MODE_CHANOP)
2897           ClearDeopped(member);
2898       } else
2899         member->status &= ~(state->cli_change[i].flag &
2900                             (MODE_CHANOP | MODE_VOICE));
2901     }
2902
2903     /* accumulate the change */
2904     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2905                         state->cli_change[i].client);
2906   } /* for (i = 0; state->cli_change[i].flags; i++) */
2907 }
2908
2909 /*
2910  * Helper function to process the simple modes
2911  */
2912 static void
2913 mode_parse_mode(struct ParseState *state, int *flag_p)
2914 {
2915   /* If they're not an oper, they can't change modes */
2916   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2917     send_notoper(state);
2918     return;
2919   }
2920
2921   if (!state->mbuf)
2922     return;
2923
2924   if (state->dir == MODE_ADD) {
2925     state->add |= flag_p[0];
2926     state->del &= ~flag_p[0];
2927
2928     if (flag_p[0] & MODE_SECRET) {
2929       state->add &= ~MODE_PRIVATE;
2930       state->del |= MODE_PRIVATE;
2931     } else if (flag_p[0] & MODE_PRIVATE) {
2932       state->add &= ~MODE_SECRET;
2933       state->del |= MODE_SECRET;
2934     }
2935     if (flag_p[0] & MODE_DELJOINS) {
2936       state->add &= ~MODE_WASDELJOINS;
2937       state->del |= MODE_WASDELJOINS;
2938     }
2939   } else {
2940     state->add &= ~flag_p[0];
2941     state->del |= flag_p[0];
2942   }
2943
2944   assert(0 == (state->add & state->del));
2945   assert((MODE_SECRET | MODE_PRIVATE) !=
2946          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2947 }
2948
2949 /*
2950  * This routine is intended to parse MODE or OPMODE commands and effect the
2951  * changes (or just build the bounce buffer).  We pass the starting offset
2952  * as a 
2953  */
2954 int
2955 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2956            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2957            struct Membership* member)
2958 {
2959   static int chan_flags[] = {
2960     MODE_CHANOP,        'o',
2961     MODE_VOICE,         'v',
2962     MODE_PRIVATE,       'p',
2963     MODE_SECRET,        's',
2964     MODE_MODERATED,     'm',
2965     MODE_TOPICLIMIT,    't',
2966     MODE_INVITEONLY,    'i',
2967     MODE_NOPRIVMSGS,    'n',
2968     MODE_KEY,           'k',
2969     MODE_APASS,         'A',
2970     MODE_UPASS,         'u',
2971     MODE_BAN,           'b',
2972     MODE_LIMIT,         'l',
2973     MODE_REGONLY,       'r',
2974     MODE_DELJOINS,      'D',
2975     MODE_ADD,           '+',
2976     MODE_DEL,           '-',
2977     0x0, 0x0
2978   };
2979   int i;
2980   int *flag_p;
2981   unsigned int t_mode;
2982   char *modestr;
2983   struct ParseState state;
2984
2985   assert(0 != cptr);
2986   assert(0 != sptr);
2987   assert(0 != chptr);
2988   assert(0 != parc);
2989   assert(0 != parv);
2990
2991   state.mbuf = mbuf;
2992   state.cptr = cptr;
2993   state.sptr = sptr;
2994   state.chptr = chptr;
2995   state.member = member;
2996   state.parc = parc;
2997   state.parv = parv;
2998   state.flags = flags;
2999   state.dir = MODE_ADD;
3000   state.done = 0;
3001   state.add = 0;
3002   state.del = 0;
3003   state.args_used = 0;
3004   state.max_args = MAXMODEPARAMS;
3005   state.numbans = 0;
3006
3007   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3008     state.banlist[i].next = 0;
3009     state.banlist[i].value.ban.banstr = 0;
3010     state.banlist[i].value.ban.who = 0;
3011     state.banlist[i].value.ban.when = 0;
3012     state.banlist[i].flags = 0;
3013     state.cli_change[i].flag = 0;
3014     state.cli_change[i].client = 0;
3015   }
3016
3017   modestr = state.parv[state.args_used++];
3018   state.parc--;
3019
3020   while (*modestr) {
3021     for (; *modestr; modestr++) {
3022       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3023         if (flag_p[1] == *modestr)
3024           break;
3025
3026       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3027         if (MyUser(state.sptr))
3028           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3029         continue;
3030       }
3031
3032       switch (*modestr) {
3033       case '+': /* switch direction to MODE_ADD */
3034       case '-': /* switch direction to MODE_DEL */
3035         state.dir = flag_p[0];
3036         break;
3037
3038       case 'l': /* deal with limits */
3039         mode_parse_limit(&state, flag_p);
3040         break;
3041
3042       case 'k': /* deal with keys */
3043         mode_parse_key(&state, flag_p);
3044         break;
3045
3046       case 'A': /* deal with Admin passes */
3047         if (feature_bool(FEAT_OPLEVELS))
3048         mode_parse_apass(&state, flag_p);
3049         break;
3050
3051       case 'u': /* deal with user passes */
3052         if (feature_bool(FEAT_OPLEVELS))
3053         mode_parse_upass(&state, flag_p);
3054         break;
3055
3056       case 'b': /* deal with bans */
3057         mode_parse_ban(&state, flag_p);
3058         break;
3059
3060       case 'o': /* deal with ops/voice */
3061       case 'v':
3062         mode_parse_client(&state, flag_p);
3063         break;
3064
3065       default: /* deal with other modes */
3066         mode_parse_mode(&state, flag_p);
3067         break;
3068       } /* switch (*modestr) */
3069     } /* for (; *modestr; modestr++) */
3070
3071     if (state.flags & MODE_PARSE_BURST)
3072       break; /* don't interpret any more arguments */
3073
3074     if (state.parc > 0) { /* process next argument in string */
3075       modestr = state.parv[state.args_used++];
3076       state.parc--;
3077
3078       /* is it a TS? */
3079       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3080         time_t recv_ts;
3081
3082         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3083           break;                     /* we're then going to bounce the mode! */
3084
3085         recv_ts = atoi(modestr);
3086
3087         if (recv_ts && recv_ts < state.chptr->creationtime)
3088           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3089
3090         break; /* break out of while loop */
3091       } else if (state.flags & MODE_PARSE_STRICT ||
3092                  (MyUser(state.sptr) && state.max_args <= 0)) {
3093         state.parc++; /* we didn't actually gobble the argument */
3094         state.args_used--;
3095         break; /* break out of while loop */
3096       }
3097     }
3098   } /* while (*modestr) */
3099
3100   /*
3101    * the rest of the function finishes building resultant MODEs; if the
3102    * origin isn't a member or an oper, skip it.
3103    */
3104   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3105     return state.args_used; /* tell our parent how many args we gobbled */
3106
3107   t_mode = state.chptr->mode.mode;
3108
3109   if (state.del & t_mode) { /* delete any modes to be deleted... */
3110     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3111
3112     t_mode &= ~state.del;
3113   }
3114   if (state.add & ~t_mode) { /* add any modes to be added... */
3115     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3116
3117     t_mode |= state.add;
3118   }
3119
3120   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3121     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3122         !(t_mode & MODE_INVITEONLY))
3123       mode_invite_clear(state.chptr);
3124
3125     state.chptr->mode.mode = t_mode;
3126   }
3127
3128   if (state.flags & MODE_PARSE_WIPEOUT) {
3129     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3130       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3131                         state.chptr->mode.limit);
3132     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3133       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3134                           state.chptr->mode.key, 0);
3135     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3136       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3137                           state.chptr->mode.upass, 0);
3138     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3139       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3140                           state.chptr->mode.apass, 0);
3141   }
3142
3143   if (state.done & DONE_BANCLEAN) /* process bans */
3144     mode_process_bans(&state);
3145
3146   /* process client changes */
3147   if (state.cli_change[0].flag)
3148     mode_process_clients(&state);
3149
3150   return state.args_used; /* tell our parent how many args we gobbled */
3151 }
3152
3153 /*
3154  * Initialize a join buffer
3155  */
3156 void
3157 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3158              struct Client *connect, unsigned int type, char *comment,
3159              time_t create)
3160 {
3161   int i;
3162
3163   assert(0 != jbuf);
3164   assert(0 != source);
3165   assert(0 != connect);
3166
3167   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3168   jbuf->jb_connect = connect;
3169   jbuf->jb_type = type;
3170   jbuf->jb_comment = comment;
3171   jbuf->jb_create = create;
3172   jbuf->jb_count = 0;
3173   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3174                        type == JOINBUF_TYPE_PART ||
3175                        type == JOINBUF_TYPE_PARTALL) ?
3176                       STARTJOINLEN : STARTCREATELEN) +
3177                      (comment ? strlen(comment) + 2 : 0));
3178
3179   for (i = 0; i < MAXJOINARGS; i++)
3180     jbuf->jb_channels[i] = 0;
3181 }
3182
3183 /*
3184  * Add a channel to the join buffer
3185  */
3186 void
3187 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3188 {
3189   unsigned int len;
3190   int is_local;
3191
3192   assert(0 != jbuf);
3193
3194   if (!chan) {
3195     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3196       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3197
3198     return;
3199   }
3200
3201   is_local = IsLocalChannel(chan->chname);
3202
3203   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3204       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3205     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3206     if (IsUserParting(member))
3207       return;
3208     SetUserParting(member);
3209
3210     /* Send notification to channel */
3211     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3212       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3213                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3214                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3215     else if (MyUser(jbuf->jb_source))
3216       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3217                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3218                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3219     /* XXX: Shouldn't we send a PART here anyway? */
3220     /* to users on the channel?  Why?  From their POV, the user isn't on
3221      * the channel anymore anyway.  We don't send to servers until below,
3222      * when we gang all the channel parts together.  Note that this is
3223      * exactly the same logic, albeit somewhat more concise, as was in
3224      * the original m_part.c */
3225
3226     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3227         is_local) /* got to remove user here */
3228       remove_user_from_channel(jbuf->jb_source, chan);
3229   } else {
3230     /* Add user to channel */
3231     if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3232       add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3233     else
3234       add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3235
3236     /* send notification to all servers */
3237     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3238       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3239                             "%H %Tu", chan, chan->creationtime);
3240
3241     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3242       /* Send the notification to the channel */
3243       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3244
3245       /* send an op, too, if needed */
3246       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3247         sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3248                                          chan, jbuf->jb_source);
3249     } else if (MyUser(jbuf->jb_source))
3250       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3251   }
3252
3253   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3254       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3255     return; /* don't send to remote */
3256
3257   /* figure out if channel name will cause buffer to be overflowed */
3258   len = chan ? strlen(chan->chname) + 1 : 2;
3259   if (jbuf->jb_strlen + len > BUFSIZE)
3260     joinbuf_flush(jbuf);
3261
3262   /* add channel to list of channels to send and update counts */
3263   jbuf->jb_channels[jbuf->jb_count++] = chan;
3264   jbuf->jb_strlen += len;
3265
3266   /* if we've used up all slots, flush */
3267   if (jbuf->jb_count >= MAXJOINARGS)
3268     joinbuf_flush(jbuf);
3269 }
3270
3271 /*
3272  * Flush the channel list to remote servers
3273  */
3274 int
3275 joinbuf_flush(struct JoinBuf *jbuf)
3276 {
3277   char chanlist[BUFSIZE];
3278   int chanlist_i = 0;
3279   int i;
3280
3281   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3282       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3283     return 0; /* no joins to process */
3284
3285   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3286     build_string(chanlist, &chanlist_i,
3287                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3288                  i == 0 ? '\0' : ',');
3289     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3290       /* Remove user from channel */
3291       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3292
3293     jbuf->jb_channels[i] = 0; /* mark slot empty */
3294   }
3295
3296   jbuf->jb_count = 0; /* reset base counters */
3297   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3298                       STARTJOINLEN : STARTCREATELEN) +
3299                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3300
3301   /* and send the appropriate command */
3302   switch (jbuf->jb_type) {
3303   case JOINBUF_TYPE_CREATE:
3304     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3305                           "%s %Tu", chanlist, jbuf->jb_create);
3306     break;
3307
3308   case JOINBUF_TYPE_PART:
3309     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3310                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3311                           jbuf->jb_comment);
3312     break;
3313   }
3314
3315   return 0;
3316 }
3317
3318 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3319 int IsInvited(struct Client* cptr, const void* chptr)
3320 {
3321   struct SLink *lp;
3322
3323   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3324     if (lp->value.chptr == chptr)
3325       return 1;
3326   return 0;
3327 }
3328
3329 /* RevealDelayedJoin: sends a join for a hidden user */
3330
3331 void RevealDelayedJoin(struct Membership *member) {
3332   ClearDelayedJoin(member);
3333   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3334                                    member->channel);
3335   CheckDelayedJoins(member->channel);
3336 }
3337
3338 /* CheckDelayedJoins: checks and clear +d if necessary */
3339
3340 void CheckDelayedJoins(struct Channel *chan) {
3341   struct Membership *memb2;
3342   
3343   if (chan->mode.mode & MODE_WASDELJOINS) {
3344     for (memb2=chan->members;memb2;memb2=memb2->next_member)
3345       if (IsDelayedJoin(memb2))
3346         break;
3347     
3348     if (!memb2) {
3349       /* clear +d */
3350       chan->mode.mode &= ~MODE_WASDELJOINS;
3351       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
3352                                        "%H -d", chan);
3353     }
3354   }
3355 }