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