Apply minor fixes from patches@, SF tracker, and others.
[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     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   int overrideJoin = 0;  
1175   
1176   /*
1177    * Now a banned user CAN join if invited -- Nemesi
1178    * Now a user CAN escape channel limit if invited -- bfriendly
1179    * Now a user CAN escape anything if invited -- Isomer
1180    */
1181
1182   if (IsInvited(sptr, chptr))
1183     return 0;
1184   
1185   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
1186      a HACK(4) notice will be sent if he would not have been supposed
1187      to join normally. */ 
1188   if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1189       !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1190       compall("OVERRIDE",key) == 0)
1191     overrideJoin = MAGIC_OPER_OVERRIDE;
1192
1193   if (chptr->mode.mode & MODE_INVITEONLY)
1194         return overrideJoin + ERR_INVITEONLYCHAN;
1195         
1196   if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1197         return overrideJoin + ERR_CHANNELISFULL;
1198
1199   if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1200         return overrideJoin + ERR_NEEDREGGEDNICK;
1201         
1202   if (is_banned(sptr, chptr, NULL))
1203         return overrideJoin + ERR_BANNEDFROMCHAN;
1204   
1205   /*
1206    * now using compall (above) to test against a whole key ring -Kev
1207    */
1208   if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1209     return overrideJoin + ERR_BADCHANNELKEY;
1210
1211   if (overrideJoin)     
1212         return ERR_DONTCHEAT;
1213         
1214   return 0;
1215 }
1216
1217 /*
1218  * Remove bells and commas from channel name
1219  */
1220 void clean_channelname(char *cn)
1221 {
1222   int i;
1223
1224   for (i = 0; cn[i]; i++) {
1225     if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1226       cn[i] = '\0';
1227       return;
1228     }
1229     if (IsChannelLower(cn[i])) {
1230       cn[i] = ToLower(cn[i]);
1231 #ifndef FIXME
1232       /*
1233        * Remove for .08+
1234        * toupper(0xd0)
1235        */
1236       if ((unsigned char)(cn[i]) == 0xd0)
1237         cn[i] = (char) 0xf0;
1238 #endif
1239     }
1240   }
1241 }
1242
1243 /*
1244  *  Get Channel block for i (and allocate a new channel
1245  *  block, if it didn't exists before).
1246  */
1247 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1248 {
1249   struct Channel *chptr;
1250   int len;
1251
1252   if (EmptyString(chname))
1253     return NULL;
1254
1255   len = strlen(chname);
1256   if (MyUser(cptr) && len > CHANNELLEN)
1257   {
1258     len = CHANNELLEN;
1259     *(chname + CHANNELLEN) = '\0';
1260   }
1261   if ((chptr = FindChannel(chname)))
1262     return (chptr);
1263   if (flag == CGT_CREATE)
1264   {
1265     chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1266     assert(0 != chptr);
1267     ++UserStats.channels;
1268     memset(chptr, 0, sizeof(struct Channel));
1269     strcpy(chptr->chname, chname);
1270     if (GlobalChannelList)
1271       GlobalChannelList->prev = chptr;
1272     chptr->prev = NULL;
1273     chptr->next = GlobalChannelList;
1274     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1275     GlobalChannelList = chptr;
1276     hAddChannel(chptr);
1277   }
1278   return chptr;
1279 }
1280
1281 void add_invite(struct Client *cptr, struct Channel *chptr)
1282 {
1283   struct SLink *inv, **tmp;
1284
1285   del_invite(cptr, chptr);
1286   /*
1287    * Delete last link in chain if the list is max length
1288    */
1289   assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1290   if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1291     del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1292   /*
1293    * Add client to channel invite list
1294    */
1295   inv = make_link();
1296   inv->value.cptr = cptr;
1297   inv->next = chptr->invites;
1298   chptr->invites = inv;
1299   /*
1300    * Add channel to the end of the client invite list
1301    */
1302   for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1303   inv = make_link();
1304   inv->value.chptr = chptr;
1305   inv->next = NULL;
1306   (*tmp) = inv;
1307   (cli_user(cptr))->invites++;
1308 }
1309
1310 /*
1311  * Delete Invite block from channel invite list and client invite list
1312  */
1313 void del_invite(struct Client *cptr, struct Channel *chptr)
1314 {
1315   struct SLink **inv, *tmp;
1316
1317   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1318     if (tmp->value.cptr == cptr)
1319     {
1320       *inv = tmp->next;
1321       free_link(tmp);
1322       tmp = 0;
1323       (cli_user(cptr))->invites--;
1324       break;
1325     }
1326
1327   for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1328     if (tmp->value.chptr == chptr)
1329     {
1330       *inv = tmp->next;
1331       free_link(tmp);
1332       tmp = 0;
1333       break;
1334     }
1335 }
1336
1337 /* List and skip all channels that are listen */
1338 void list_next_channels(struct Client *cptr, int nr)
1339 {
1340   struct ListingArgs *args = cli_listing(cptr);
1341   struct Channel *chptr = args->chptr;
1342   chptr->mode.mode &= ~MODE_LISTED;
1343   while (is_listed(chptr) || --nr >= 0)
1344   {
1345     for (; chptr; chptr = chptr->next)
1346     {
1347       if (!cli_user(cptr))
1348         continue;
1349       if (!(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->flags & LISTARG_TOPICLIMITS) || (*chptr->topic &&
1356           chptr->topic_time > args->min_topic_time &&
1357           chptr->topic_time < args->max_topic_time)))
1358       {
1359         if ((args->flags & LISTARG_SHOWSECRET) || 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                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1726                                     mbuf->mb_source : app_source),
1727                            mbuf->mb_channel->chname,
1728                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1729                            addbuf, remstr, addstr,
1730                            mbuf->mb_channel->creationtime);
1731
1732     if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1733       log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1734                 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1735                 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1736                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1737
1738     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1739       sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1740                                 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1741                                 rembuf_i ? "-" : "", rembuf,
1742                                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1743   }
1744
1745   /* Now are we supposed to propagate to other servers? */
1746   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1747     /* set up parameter string */
1748     addstr[0] = '\0';
1749     addstr_i = 0;
1750     remstr[0] = '\0';
1751     remstr_i = 0;
1752
1753     /*
1754      * limit is supressed if we're removing it; we have to figure out which
1755      * direction is the direction for it to be removed, though...
1756      */
1757     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1758
1759     for (i = 0; i < mbuf->mb_count; i++) {
1760       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1761         continue;
1762
1763       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1764         strptr = addstr;
1765         strptr_i = &addstr_i;
1766       } else {
1767         strptr = remstr;
1768         strptr_i = &remstr_i;
1769       }
1770
1771       /* deal with modes that take clients */
1772       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1773         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1774
1775       /* deal with modes that take strings */
1776       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1777         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1778
1779       /*
1780        * deal with the limit.  Logic here is complicated; if HACK2 is set,
1781        * we're bouncing the mode, so sense is reversed, and we have to
1782        * include the original limit if it looks like it's being removed
1783        */
1784       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1785         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1786     }
1787
1788     /* we were told to deop the source */
1789     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1790       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1791       addbuf[addbuf_i] = '\0'; /* terminate the string... */
1792       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1793
1794       /* mark that we've done this, so we don't do it again */
1795       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1796     }
1797
1798     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1799       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1800       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1801                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
1802                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1803                             addbuf, remstr, addstr);
1804     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1805       /*
1806        * If HACK2 was set, we're bouncing; we send the MODE back to the
1807        * connection we got it from with the senses reversed and a TS of 0;
1808        * origin is us
1809        */
1810       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1811                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1812                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
1813                     mbuf->mb_channel->creationtime);
1814     } else {
1815       /*
1816        * We're propagating a normal MODE command to the rest of the network;
1817        * we send the actual channel TS unless this is a HACK3 or a HACK4
1818        */
1819       if (IsServer(mbuf->mb_source))
1820         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1821                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1822                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1823                               addbuf, remstr, addstr,
1824                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1825                               mbuf->mb_channel->creationtime);
1826       else
1827         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1828                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
1829                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1830                               addbuf, remstr, addstr);
1831     }
1832   }
1833
1834   /* We've drained the ModeBuf... */
1835   mbuf->mb_add = 0;
1836   mbuf->mb_rem = 0;
1837   mbuf->mb_count = 0;
1838
1839   /* reinitialize the mode-with-arg slots */
1840   for (i = 0; i < MAXMODEPARAMS; i++) {
1841     /* If we saved any, pack them down */
1842     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1843       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1844       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1845
1846       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1847         continue;
1848     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1849       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1850
1851     MB_TYPE(mbuf, i) = 0;
1852     MB_UINT(mbuf, i) = 0;
1853   }
1854
1855   /* If we're supposed to flush it all, do so--all hail tail recursion */
1856   if (all && mbuf->mb_count)
1857     return modebuf_flush_int(mbuf, 1);
1858
1859   return 0;
1860 }
1861
1862 /*
1863  * This routine just initializes a ModeBuf structure with the information
1864  * needed and the options given.
1865  */
1866 void
1867 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1868              struct Client *connect, struct Channel *chan, unsigned int dest)
1869 {
1870   int i;
1871
1872   assert(0 != mbuf);
1873   assert(0 != source);
1874   assert(0 != chan);
1875   assert(0 != dest);
1876
1877   if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1878
1879   mbuf->mb_add = 0;
1880   mbuf->mb_rem = 0;
1881   mbuf->mb_source = source;
1882   mbuf->mb_connect = connect;
1883   mbuf->mb_channel = chan;
1884   mbuf->mb_dest = dest;
1885   mbuf->mb_count = 0;
1886
1887   /* clear each mode-with-parameter slot */
1888   for (i = 0; i < MAXMODEPARAMS; i++) {
1889     MB_TYPE(mbuf, i) = 0;
1890     MB_UINT(mbuf, i) = 0;
1891   }
1892 }
1893
1894 /*
1895  * This routine simply adds modes to be added or deleted; do a binary OR
1896  * with either MODE_ADD or MODE_DEL
1897  */
1898 void
1899 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1900 {
1901   assert(0 != mbuf);
1902   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1903
1904   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1905            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1906            MODE_DELJOINS | MODE_WASDELJOINS);
1907
1908   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1909     return;
1910
1911   if (mode & MODE_ADD) {
1912     mbuf->mb_rem &= ~mode;
1913     mbuf->mb_add |= mode;
1914   } else {
1915     mbuf->mb_add &= ~mode;
1916     mbuf->mb_rem |= mode;
1917   }
1918 }
1919
1920 /*
1921  * This routine adds a mode to be added or deleted that takes a unsigned
1922  * int parameter; mode may *only* be the relevant mode flag ORed with one
1923  * of MODE_ADD or MODE_DEL
1924  */
1925 void
1926 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1927 {
1928   assert(0 != mbuf);
1929   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1930
1931   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1932   MB_UINT(mbuf, mbuf->mb_count) = uint;
1933
1934   /* when we've reached the maximal count, flush the buffer */
1935   if (++mbuf->mb_count >=
1936       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1937     modebuf_flush_int(mbuf, 0);
1938 }
1939
1940 /*
1941  * This routine adds a mode to be added or deleted that takes a string
1942  * parameter; mode may *only* be the relevant mode flag ORed with one of
1943  * MODE_ADD or MODE_DEL
1944  */
1945 void
1946 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1947                     int free)
1948 {
1949   assert(0 != mbuf);
1950   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1951
1952   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1953   MB_STRING(mbuf, mbuf->mb_count) = string;
1954
1955   /* when we've reached the maximal count, flush the buffer */
1956   if (++mbuf->mb_count >=
1957       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1958     modebuf_flush_int(mbuf, 0);
1959 }
1960
1961 /*
1962  * This routine adds a mode to be added or deleted that takes a client
1963  * parameter; mode may *only* be the relevant mode flag ORed with one of
1964  * MODE_ADD or MODE_DEL
1965  */
1966 void
1967 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1968                     struct Client *client)
1969 {
1970   assert(0 != mbuf);
1971   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1972
1973   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1974   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1975
1976   /* when we've reached the maximal count, flush the buffer */
1977   if (++mbuf->mb_count >=
1978       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1979     modebuf_flush_int(mbuf, 0);
1980 }
1981
1982 /*
1983  * This is the exported binding for modebuf_flush()
1984  */
1985 int
1986 modebuf_flush(struct ModeBuf *mbuf)
1987 {
1988   struct Membership *memb;
1989
1990   /* Check if MODE_WASDELJOINS should be set */
1991   if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
1992       && (mbuf->mb_rem & MODE_DELJOINS)) {
1993     for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
1994       if (IsDelayedJoin(memb)) {
1995           mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
1996           mbuf->mb_add |= MODE_WASDELJOINS;
1997           mbuf->mb_rem &= ~MODE_WASDELJOINS;
1998           break;
1999       }
2000     }
2001   }
2002
2003   return modebuf_flush_int(mbuf, 1);
2004 }
2005
2006 /*
2007  * This extracts the simple modes contained in mbuf
2008  */
2009 void
2010 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2011 {
2012   static int flags[] = {
2013 /*  MODE_CHANOP,        'o', */
2014 /*  MODE_VOICE,         'v', */
2015     MODE_PRIVATE,       'p',
2016     MODE_SECRET,        's',
2017     MODE_MODERATED,     'm',
2018     MODE_TOPICLIMIT,    't',
2019     MODE_INVITEONLY,    'i',
2020     MODE_NOPRIVMSGS,    'n',
2021     MODE_KEY,           'k',
2022     MODE_APASS,         'A',
2023     MODE_UPASS,         'u',
2024 /*  MODE_BAN,           'b', */
2025     MODE_LIMIT,         'l',
2026     MODE_REGONLY,       'r',
2027     MODE_DELJOINS,      'D',
2028     0x0, 0x0
2029   };
2030   unsigned int add;
2031   int i, bufpos = 0, len;
2032   int *flag_p;
2033   char *key = 0, limitbuf[20];
2034   char *apass = 0, *upass = 0;
2035
2036   assert(0 != mbuf);
2037   assert(0 != buf);
2038
2039   buf[0] = '\0';
2040
2041   add = mbuf->mb_add;
2042
2043   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2044     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2045       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2046
2047       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2048         key = MB_STRING(mbuf, i);
2049       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2050         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2051       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2052         upass = MB_STRING(mbuf, i);
2053       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2054         apass = MB_STRING(mbuf, i);
2055     }
2056   }
2057
2058   if (!add)
2059     return;
2060
2061   buf[bufpos++] = '+'; /* start building buffer */
2062
2063   for (flag_p = flags; flag_p[0]; flag_p += 2)
2064     if (*flag_p & add)
2065       buf[bufpos++] = flag_p[1];
2066
2067   for (i = 0, len = bufpos; i < len; i++) {
2068     if (buf[i] == 'k')
2069       build_string(buf, &bufpos, key, 0, ' ');
2070     else if (buf[i] == 'l')
2071       build_string(buf, &bufpos, limitbuf, 0, ' ');
2072     else if (buf[i] == 'u')
2073       build_string(buf, &bufpos, upass, 0, ' ');
2074     else if (buf[i] == 'A')
2075       build_string(buf, &bufpos, apass, 0, ' ');
2076   }
2077
2078   buf[bufpos] = '\0';
2079
2080   return;
2081 }
2082
2083 /*
2084  * Simple function to invalidate bans
2085  */
2086 void
2087 mode_ban_invalidate(struct Channel *chan)
2088 {
2089   struct Membership *member;
2090
2091   for (member = chan->members; member; member = member->next_member)
2092     ClearBanValid(member);
2093 }
2094
2095 /*
2096  * Simple function to drop invite structures
2097  */
2098 void
2099 mode_invite_clear(struct Channel *chan)
2100 {
2101   while (chan->invites)
2102     del_invite(chan->invites->value.cptr, chan);
2103 }
2104
2105 /* What we've done for mode_parse so far... */
2106 #define DONE_LIMIT      0x01    /* We've set the limit */
2107 #define DONE_KEY        0x02    /* We've set the key */
2108 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2109 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2110 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2111 #define DONE_UPASS      0x20    /* We've set user pass */
2112 #define DONE_APASS      0x40    /* We've set admin pass */
2113
2114 struct ParseState {
2115   struct ModeBuf *mbuf;
2116   struct Client *cptr;
2117   struct Client *sptr;
2118   struct Channel *chptr;
2119   struct Membership *member;
2120   int parc;
2121   char **parv;
2122   unsigned int flags;
2123   unsigned int dir;
2124   unsigned int done;
2125   unsigned int add;
2126   unsigned int del;
2127   int args_used;
2128   int max_args;
2129   int numbans;
2130   struct SLink banlist[MAXPARA];
2131   struct {
2132     unsigned int flag;
2133     struct Client *client;
2134   } cli_change[MAXPARA];
2135 };
2136
2137 /*
2138  * Here's a helper function to deal with sending along "Not oper" or
2139  * "Not member" messages
2140  */
2141 static void
2142 send_notoper(struct ParseState *state)
2143 {
2144   if (state->done & DONE_NOTOPER)
2145     return;
2146
2147   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2148              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2149
2150   state->done |= DONE_NOTOPER;
2151 }
2152
2153 /*
2154  * Helper function to convert limits
2155  */
2156 static void
2157 mode_parse_limit(struct ParseState *state, int *flag_p)
2158 {
2159   unsigned int t_limit;
2160
2161   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2162     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2163       return;
2164
2165     if (state->parc <= 0) { /* warn if not enough args */
2166       if (MyUser(state->sptr))
2167         need_more_params(state->sptr, "MODE +l");
2168       return;
2169     }
2170
2171     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2172     state->parc--;
2173     state->max_args--;
2174
2175     if ((int)t_limit<0) /* don't permit a negative limit */
2176       return;
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   /* Can't remove a limit that's not there */
2191   if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2192     return;
2193     
2194   /* Skip if this is a burst and a lower limit than this is set already */
2195   if ((state->flags & MODE_PARSE_BURST) &&
2196       (state->chptr->mode.mode & flag_p[0]) &&
2197       (state->chptr->mode.limit < t_limit))
2198     return;
2199
2200   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2201     return;
2202   state->done |= DONE_LIMIT;
2203
2204   if (!state->mbuf)
2205     return;
2206
2207   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2208
2209   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2210     if (state->dir & MODE_ADD) {
2211       state->chptr->mode.mode |= flag_p[0];
2212       state->chptr->mode.limit = t_limit;
2213     } else {
2214       state->chptr->mode.mode &= ~flag_p[0];
2215       state->chptr->mode.limit = 0;
2216     }
2217   }
2218 }
2219
2220 /*
2221  * Helper function to convert keys
2222  */
2223 static void
2224 mode_parse_key(struct ParseState *state, int *flag_p)
2225 {
2226   char *t_str, *s;
2227   int t_len;
2228
2229   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2230     return;
2231
2232   if (state->parc <= 0) { /* warn if not enough args */
2233     if (MyUser(state->sptr))
2234       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2235                        "MODE -k");
2236     return;
2237   }
2238
2239   t_str = state->parv[state->args_used++]; /* grab arg */
2240   state->parc--;
2241   state->max_args--;
2242
2243   /* If they're not an oper, they can't change modes */
2244   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2245     send_notoper(state);
2246     return;
2247   }
2248
2249   if (state->done & DONE_KEY) /* allow key to be set only once */
2250     return;
2251   state->done |= DONE_KEY;
2252
2253   t_len = KEYLEN;
2254
2255   /* clean up the key string */
2256   s = t_str;
2257   while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2258     s++;
2259   *s = '\0';
2260
2261   if (!*t_str) { /* warn if empty */
2262     if (MyUser(state->sptr))
2263       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2264                        "MODE -k");
2265     return;
2266   }
2267
2268   if (!state->mbuf)
2269     return;
2270
2271   /* Skip if this is a burst, we have a key already and the new key is 
2272    * after the old one alphabetically */
2273   if ((state->flags & MODE_PARSE_BURST) &&
2274       *(state->chptr->mode.key) &&
2275       ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2276     return;
2277
2278   /* can't add a key if one is set, nor can one remove the wrong key */
2279   if (!(state->flags & MODE_PARSE_FORCE))
2280     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2281         (state->dir == MODE_DEL &&
2282          ircd_strcmp(state->chptr->mode.key, t_str))) {
2283       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2284       return;
2285     }
2286
2287   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2288       !ircd_strcmp(state->chptr->mode.key, t_str))
2289     return; /* no key change */
2290
2291   if (state->flags & MODE_PARSE_BOUNCE) {
2292     if (*state->chptr->mode.key) /* reset old key */
2293       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2294                           state->chptr->mode.key, 0);
2295     else /* remove new bogus key */
2296       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2297   } else /* send new key */
2298     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2299
2300   if (state->flags & MODE_PARSE_SET) {
2301     if (state->dir == MODE_ADD) /* set the new key */
2302       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2303     else /* remove the old key */
2304       *state->chptr->mode.key = '\0';
2305   }
2306 }
2307
2308 /*
2309  * Helper function to convert user passes
2310  */
2311 static void
2312 mode_parse_upass(struct ParseState *state, int *flag_p)
2313 {
2314   char *t_str, *s;
2315   int t_len;
2316
2317   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2318     return;
2319
2320   if (state->parc <= 0) { /* warn if not enough args */
2321     if (MyUser(state->sptr))
2322       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2323                        "MODE -u");
2324     return;
2325   }
2326
2327   t_str = state->parv[state->args_used++]; /* grab arg */
2328   state->parc--;
2329   state->max_args--;
2330
2331   /* If they're not an oper, they can't change modes */
2332   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2333     send_notoper(state);
2334     return;
2335   }
2336
2337   /* If they are not the channel manager, they are not allowed to change it */
2338   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2339     if (*state->chptr->mode.apass) {
2340       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2341           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2342     } else {
2343       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2344           "Re-create the channel.  The channel must be *empty* for",
2345           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2346           "before it can be recreated.");
2347     }
2348     return;
2349   }
2350  
2351   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2352     return;
2353   state->done |= DONE_UPASS;
2354
2355   t_len = PASSLEN + 1;
2356
2357   /* clean up the upass string */
2358   s = t_str;
2359   while (*++s > ' ' && *s != ':' && --t_len)
2360     ;
2361   *s = '\0';
2362
2363   if (!*t_str) { /* warn if empty */
2364     if (MyUser(state->sptr))
2365       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2366                        "MODE -u");
2367     return;
2368   }
2369
2370   if (!state->mbuf)
2371     return;
2372
2373   if (!(state->flags & MODE_PARSE_FORCE))
2374     /* can't add the upass while apass is not set */
2375     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2376       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2377       return;
2378     }
2379     /* can't add a upass if one is set, nor can one remove the wrong upass */
2380     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2381         (state->dir == MODE_DEL &&
2382          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2383       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2384       return;
2385     }
2386
2387   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2388       !ircd_strcmp(state->chptr->mode.upass, t_str))
2389     return; /* no upass change */
2390
2391   if (state->flags & MODE_PARSE_BOUNCE) {
2392     if (*state->chptr->mode.upass) /* reset old upass */
2393       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2394                           state->chptr->mode.upass, 0);
2395     else /* remove new bogus upass */
2396       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2397   } else /* send new upass */
2398     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2399
2400   if (state->flags & MODE_PARSE_SET) {
2401     if (state->dir == MODE_ADD) /* set the new upass */
2402       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2403     else /* remove the old upass */
2404       *state->chptr->mode.upass = '\0';
2405   }
2406 }
2407
2408 /*
2409  * Helper function to convert admin passes
2410  */
2411 static void
2412 mode_parse_apass(struct ParseState *state, int *flag_p)
2413 {
2414   char *t_str, *s;
2415   int t_len;
2416
2417   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2418     return;
2419
2420   if (state->parc <= 0) { /* warn if not enough args */
2421     if (MyUser(state->sptr))
2422       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2423                        "MODE -A");
2424     return;
2425   }
2426
2427   t_str = state->parv[state->args_used++]; /* grab arg */
2428   state->parc--;
2429   state->max_args--;
2430
2431   /* If they're not an oper, they can't change modes */
2432   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2433     send_notoper(state);
2434     return;
2435   }
2436
2437   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2438   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2439     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2440     return;
2441   }
2442
2443   /* If they are not the channel manager, they are not allowed to change it */
2444   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2445     if (*state->chptr->mode.apass) {
2446       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2447           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2448     } else {
2449       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2450           "Re-create the channel.  The channel must be *empty* for",
2451           "at least a whole minute", "before it can be recreated.");
2452     }
2453     return;
2454   }
2455  
2456   if (state->done & DONE_APASS) /* allow apass to be set only once */
2457     return;
2458   state->done |= DONE_APASS;
2459
2460   t_len = PASSLEN + 1;
2461
2462   /* clean up the apass string */
2463   s = t_str;
2464   while (*++s > ' ' && *s != ':' && --t_len)
2465     ;
2466   *s = '\0';
2467
2468   if (!*t_str) { /* warn if empty */
2469     if (MyUser(state->sptr))
2470       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2471                        "MODE -A");
2472     return;
2473   }
2474
2475   if (!state->mbuf)
2476     return;
2477
2478   if (!(state->flags & MODE_PARSE_FORCE)) {
2479     /* can't remove the apass while upass is still set */
2480     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2481       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2482       return;
2483     }
2484     /* can't add an apass if one is set, nor can one remove the wrong apass */
2485     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2486         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2487       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2488       return;
2489     }
2490   }
2491
2492   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2493       !ircd_strcmp(state->chptr->mode.apass, t_str))
2494     return; /* no apass change */
2495
2496   if (state->flags & MODE_PARSE_BOUNCE) {
2497     if (*state->chptr->mode.apass) /* reset old apass */
2498       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2499                           state->chptr->mode.apass, 0);
2500     else /* remove new bogus apass */
2501       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2502   } else /* send new apass */
2503     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2504
2505   if (state->flags & MODE_PARSE_SET) {
2506     if (state->dir == MODE_ADD) { /* set the new apass */
2507       /* Make it VERY clear to the user that this is a one-time password */
2508       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2509       if (MyUser(state->sptr)) {
2510         send_reply(state->sptr, RPL_APASSWARN,
2511             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2512             "Are you SURE you want to use this as Admin password? ",
2513             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2514         send_reply(state->sptr, RPL_APASSWARN,
2515             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2516             "\" to remove the password and then immediately set a new one. "
2517             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2518             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2519             "Now set the channel user password (+u).");
2520       }
2521     } else { /* remove the old apass */
2522       *state->chptr->mode.apass = '\0';
2523       if (MyUser(state->sptr))
2524         send_reply(state->sptr, RPL_APASSWARN,
2525             "WARNING: You removed the channel Admin password MODE (+A). ",
2526             "If you would disconnect or leave the channel without setting a new password then you will ",
2527             "not be able to set it again and lose ownership of this channel! ",
2528             "SET A NEW PASSWORD NOW!", "");
2529     }
2530   }
2531 }
2532
2533 /*
2534  * Helper function to convert bans
2535  */
2536 static void
2537 mode_parse_ban(struct ParseState *state, int *flag_p)
2538 {
2539   char *t_str, *s;
2540   struct SLink *ban, *newban = 0;
2541
2542   if (state->parc <= 0) { /* Not enough args, send ban list */
2543     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2544       send_ban_list(state->sptr, state->chptr);
2545       state->done |= DONE_BANLIST;
2546     }
2547
2548     return;
2549   }
2550
2551   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2552     return;
2553
2554   t_str = state->parv[state->args_used++]; /* grab arg */
2555   state->parc--;
2556   state->max_args--;
2557
2558   /* If they're not an oper, they can't change modes */
2559   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2560     send_notoper(state);
2561     return;
2562   }
2563
2564   if ((s = strchr(t_str, ' ')))
2565     *s = '\0';
2566
2567   if (!*t_str || *t_str == ':') { /* warn if empty */
2568     if (MyUser(state->sptr))
2569       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2570                        "MODE -b");
2571     return;
2572   }
2573
2574   t_str = collapse(pretty_mask(t_str));
2575
2576   /* remember the ban for the moment... */
2577   if (state->dir == MODE_ADD) {
2578     newban = state->banlist + (state->numbans++);
2579     newban->next = 0;
2580
2581     DupString(newban->value.ban.banstr, t_str);
2582     newban->value.ban.who = cli_name(state->sptr);
2583     newban->value.ban.when = TStime();
2584
2585     newban->flags = CHFL_BAN | MODE_ADD;
2586
2587     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2588       newban->flags |= CHFL_BAN_IPMASK;
2589   }
2590
2591   if (!state->chptr->banlist) {
2592     state->chptr->banlist = newban; /* add our ban with its flags */
2593     state->done |= DONE_BANCLEAN;
2594     return;
2595   }
2596
2597   /* Go through all bans */
2598   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2599     /* first, clean the ban flags up a bit */
2600     if (!(state->done & DONE_BANCLEAN))
2601       /* Note: We're overloading *lots* of bits here; be careful! */
2602       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2603
2604     /* Bit meanings:
2605      *
2606      * MODE_ADD            - Ban was added; if we're bouncing modes,
2607      *                       then we'll remove it below; otherwise,
2608      *                       we'll have to allocate a real ban
2609      *
2610      * MODE_DEL            - Ban was marked for deletion; if we're
2611      *                       bouncing modes, we'll have to re-add it,
2612      *                       otherwise, we'll have to remove it
2613      *
2614      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2615      *                       with a ban already set; if we're
2616      *                       bouncing modes, we'll have to bounce
2617      *                       this one; otherwise, we'll just ignore
2618      *                       it when we process added bans
2619      */
2620
2621     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2622       ban->flags |= MODE_DEL; /* delete one ban */
2623
2624       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2625         break;
2626     } else if (state->dir == MODE_ADD) {
2627       /* if the ban already exists, don't worry about it */
2628       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2629         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2630         MyFree(newban->value.ban.banstr); /* stopper a leak */
2631         state->numbans--; /* deallocate last ban */
2632         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2633           break;
2634       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2635         if (!(ban->flags & MODE_DEL))
2636           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2637       } else if (!mmatch(t_str, ban->value.ban.banstr))
2638         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2639
2640       if (!ban->next && (newban->flags & MODE_ADD))
2641       {
2642         ban->next = newban; /* add our ban with its flags */
2643         break; /* get out of loop */
2644       }
2645     }
2646   }
2647   state->done |= DONE_BANCLEAN;
2648 }
2649
2650 /*
2651  * This is the bottom half of the ban processor
2652  */
2653 static void
2654 mode_process_bans(struct ParseState *state)
2655 {
2656   struct SLink *ban, *newban, *prevban, *nextban;
2657   int count = 0;
2658   int len = 0;
2659   int banlen;
2660   int changed = 0;
2661
2662   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2663     count++;
2664     banlen = strlen(ban->value.ban.banstr);
2665     len += banlen;
2666     nextban = ban->next;
2667
2668     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2669       if (prevban)
2670         prevban->next = 0; /* Break the list; ban isn't a real ban */
2671       else
2672         state->chptr->banlist = 0;
2673
2674       count--;
2675       len -= banlen;
2676
2677       MyFree(ban->value.ban.banstr);
2678
2679       continue;
2680     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2681       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2682                           ban->value.ban.banstr,
2683                           state->flags & MODE_PARSE_SET);
2684
2685       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2686         if (prevban) /* clip it out of the list... */
2687           prevban->next = ban->next;
2688         else
2689           state->chptr->banlist = ban->next;
2690
2691         count--;
2692         len -= banlen;
2693
2694         MyFree(ban->value.ban.who);
2695         free_link(ban);
2696
2697         changed++;
2698         continue; /* next ban; keep prevban like it is */
2699       } else
2700         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2701     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2702       if (prevban)
2703         prevban->next = 0; /* Break the list; ban isn't a real ban */
2704       else
2705         state->chptr->banlist = 0;
2706
2707       /* If we're supposed to ignore it, do so. */
2708       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2709           !(state->flags & MODE_PARSE_BOUNCE)) {
2710         count--;
2711         len -= banlen;
2712
2713         MyFree(ban->value.ban.banstr);
2714       } else {
2715         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2716             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2717              count > feature_int(FEAT_MAXBANS))) {
2718           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2719                      ban->value.ban.banstr);
2720           count--;
2721           len -= banlen;
2722
2723           MyFree(ban->value.ban.banstr);
2724         } else {
2725           /* add the ban to the buffer */
2726           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2727                               ban->value.ban.banstr,
2728                               !(state->flags & MODE_PARSE_SET));
2729
2730           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2731             newban = make_link();
2732             newban->value.ban.banstr = ban->value.ban.banstr;
2733             DupString(newban->value.ban.who, ban->value.ban.who);
2734             newban->value.ban.when = ban->value.ban.when;
2735             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2736
2737             newban->next = state->chptr->banlist; /* and link it in */
2738             state->chptr->banlist = newban;
2739
2740             changed++;
2741           }
2742         }
2743       }
2744     }
2745
2746     prevban = ban;
2747   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2748
2749   if (changed) /* if we changed the ban list, we must invalidate the bans */
2750     mode_ban_invalidate(state->chptr);
2751 }
2752
2753 /*
2754  * Helper function to process client changes
2755  */
2756 static void
2757 mode_parse_client(struct ParseState *state, int *flag_p)
2758 {
2759   char *t_str;
2760   struct Client *acptr;
2761   int i;
2762
2763   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2764     return;
2765
2766   if (state->parc <= 0) /* return if not enough args */
2767     return;
2768
2769   t_str = state->parv[state->args_used++]; /* grab arg */
2770   state->parc--;
2771   state->max_args--;
2772
2773   /* If they're not an oper, they can't change modes */
2774   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2775     send_notoper(state);
2776     return;
2777   }
2778
2779   if (MyUser(state->sptr)) /* find client we're manipulating */
2780     acptr = find_chasing(state->sptr, t_str, NULL);
2781   else
2782     acptr = findNUser(t_str);
2783
2784   if (!acptr)
2785     return; /* find_chasing() already reported an error to the user */
2786
2787   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2788     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2789                                        state->cli_change[i].flag & flag_p[0]))
2790       break; /* found a slot */
2791
2792   /* Store what we're doing to them */
2793   state->cli_change[i].flag = state->dir | flag_p[0];
2794   state->cli_change[i].client = acptr;
2795 }
2796
2797 /*
2798  * Helper function to process the changed client list
2799  */
2800 static void
2801 mode_process_clients(struct ParseState *state)
2802 {
2803   int i;
2804   struct Membership *member;
2805
2806   for (i = 0; state->cli_change[i].flag; i++) {
2807     assert(0 != state->cli_change[i].client);
2808
2809     /* look up member link */
2810     if (!(member = find_member_link(state->chptr,
2811                                     state->cli_change[i].client)) ||
2812         (MyUser(state->sptr) && IsZombie(member))) {
2813       if (MyUser(state->sptr))
2814         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2815                    cli_name(state->cli_change[i].client),
2816                    state->chptr->chname);
2817       continue;
2818     }
2819
2820     if ((state->cli_change[i].flag & MODE_ADD &&
2821          (state->cli_change[i].flag & member->status)) ||
2822         (state->cli_change[i].flag & MODE_DEL &&
2823          !(state->cli_change[i].flag & member->status)))
2824       continue; /* no change made, don't do anything */
2825
2826     /* see if the deop is allowed */
2827     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2828         (MODE_DEL | MODE_CHANOP)) {
2829       /* prevent +k users from being deopped */
2830       if (IsChannelService(state->cli_change[i].client)) {
2831         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2832           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2833                                state->chptr,
2834                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2835                                 cli_name((cli_user(state->sptr))->server)));
2836
2837         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2838           send_reply(state->sptr, ERR_ISCHANSERVICE,
2839                      cli_name(state->cli_change[i].client),
2840                      state->chptr->chname);
2841           continue;
2842         }
2843       }
2844
2845       /* check deop for local user */
2846       if (MyUser(state->sptr)) {
2847
2848         /* don't allow local opers to be deopped on local channels */
2849         if (state->cli_change[i].client != state->sptr &&
2850             IsLocalChannel(state->chptr->chname) &&
2851             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2852           send_reply(state->sptr, ERR_ISOPERLCHAN,
2853                      cli_name(state->cli_change[i].client),
2854                      state->chptr->chname);
2855           continue;
2856         }
2857
2858         if (feature_bool(FEAT_OPLEVELS)) {
2859         /* don't allow to deop members with an op level that is <= our own level */
2860         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2861                 && state->member
2862                 && OpLevel(member) <= OpLevel(state->member)) {
2863             int equal = (OpLevel(member) == OpLevel(state->member));
2864             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2865                        cli_name(state->cli_change[i].client),
2866                        state->chptr->chname,
2867                        OpLevel(state->member), OpLevel(member),
2868                        "deop", equal ? "the same" : "a higher");
2869           continue;
2870         }
2871       }
2872     }
2873     }
2874
2875     /* set op-level of member being opped */
2876     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2877         (MODE_ADD | MODE_CHANOP)) {
2878       /* If on a channel with upass set, someone with level x gives ops to someone else,
2879          then that person gets level x-1.  On other channels, where upass is not set,
2880          the level stays the same. */
2881       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2882       /* Someone being opped by a server gets op-level 0 */
2883       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2884       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2885     }
2886
2887     /* actually effect the change */
2888     if (state->flags & MODE_PARSE_SET) {
2889       if (state->cli_change[i].flag & MODE_ADD) {
2890         if (IsDelayedJoin(member))
2891           RevealDelayedJoin(member);
2892         member->status |= (state->cli_change[i].flag &
2893                            (MODE_CHANOP | MODE_VOICE));
2894         if (state->cli_change[i].flag & MODE_CHANOP)
2895           ClearDeopped(member);
2896       } else
2897         member->status &= ~(state->cli_change[i].flag &
2898                             (MODE_CHANOP | MODE_VOICE));
2899     }
2900
2901     /* accumulate the change */
2902     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2903                         state->cli_change[i].client);
2904   } /* for (i = 0; state->cli_change[i].flags; i++) */
2905 }
2906
2907 /*
2908  * Helper function to process the simple modes
2909  */
2910 static void
2911 mode_parse_mode(struct ParseState *state, int *flag_p)
2912 {
2913   /* If they're not an oper, they can't change modes */
2914   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2915     send_notoper(state);
2916     return;
2917   }
2918
2919   if (!state->mbuf)
2920     return;
2921
2922   if (state->dir == MODE_ADD) {
2923     state->add |= flag_p[0];
2924     state->del &= ~flag_p[0];
2925
2926     if (flag_p[0] & MODE_SECRET) {
2927       state->add &= ~MODE_PRIVATE;
2928       state->del |= MODE_PRIVATE;
2929     } else if (flag_p[0] & MODE_PRIVATE) {
2930       state->add &= ~MODE_SECRET;
2931       state->del |= MODE_SECRET;
2932     }
2933     if (flag_p[0] & MODE_DELJOINS) {
2934       state->add &= ~MODE_WASDELJOINS;
2935       state->del |= MODE_WASDELJOINS;
2936     }
2937   } else {
2938     state->add &= ~flag_p[0];
2939     state->del |= flag_p[0];
2940   }
2941
2942   assert(0 == (state->add & state->del));
2943   assert((MODE_SECRET | MODE_PRIVATE) !=
2944          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2945 }
2946
2947 /*
2948  * This routine is intended to parse MODE or OPMODE commands and effect the
2949  * changes (or just build the bounce buffer).  We pass the starting offset
2950  * as a 
2951  */
2952 int
2953 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2954            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2955            struct Membership* member)
2956 {
2957   static int chan_flags[] = {
2958     MODE_CHANOP,        'o',
2959     MODE_VOICE,         'v',
2960     MODE_PRIVATE,       'p',
2961     MODE_SECRET,        's',
2962     MODE_MODERATED,     'm',
2963     MODE_TOPICLIMIT,    't',
2964     MODE_INVITEONLY,    'i',
2965     MODE_NOPRIVMSGS,    'n',
2966     MODE_KEY,           'k',
2967     MODE_APASS,         'A',
2968     MODE_UPASS,         'u',
2969     MODE_BAN,           'b',
2970     MODE_LIMIT,         'l',
2971     MODE_REGONLY,       'r',
2972     MODE_DELJOINS,      'D',
2973     MODE_ADD,           '+',
2974     MODE_DEL,           '-',
2975     0x0, 0x0
2976   };
2977   int i;
2978   int *flag_p;
2979   unsigned int t_mode;
2980   char *modestr;
2981   struct ParseState state;
2982
2983   assert(0 != cptr);
2984   assert(0 != sptr);
2985   assert(0 != chptr);
2986   assert(0 != parc);
2987   assert(0 != parv);
2988
2989   state.mbuf = mbuf;
2990   state.cptr = cptr;
2991   state.sptr = sptr;
2992   state.chptr = chptr;
2993   state.member = member;
2994   state.parc = parc;
2995   state.parv = parv;
2996   state.flags = flags;
2997   state.dir = MODE_ADD;
2998   state.done = 0;
2999   state.add = 0;
3000   state.del = 0;
3001   state.args_used = 0;
3002   state.max_args = MAXMODEPARAMS;
3003   state.numbans = 0;
3004
3005   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3006     state.banlist[i].next = 0;
3007     state.banlist[i].value.ban.banstr = 0;
3008     state.banlist[i].value.ban.who = 0;
3009     state.banlist[i].value.ban.when = 0;
3010     state.banlist[i].flags = 0;
3011     state.cli_change[i].flag = 0;
3012     state.cli_change[i].client = 0;
3013   }
3014
3015   modestr = state.parv[state.args_used++];
3016   state.parc--;
3017
3018   while (*modestr) {
3019     for (; *modestr; modestr++) {
3020       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3021         if (flag_p[1] == *modestr)
3022           break;
3023
3024       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3025         if (MyUser(state.sptr))
3026           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3027         continue;
3028       }
3029
3030       switch (*modestr) {
3031       case '+': /* switch direction to MODE_ADD */
3032       case '-': /* switch direction to MODE_DEL */
3033         state.dir = flag_p[0];
3034         break;
3035
3036       case 'l': /* deal with limits */
3037         mode_parse_limit(&state, flag_p);
3038         break;
3039
3040       case 'k': /* deal with keys */
3041         mode_parse_key(&state, flag_p);
3042         break;
3043
3044       case 'A': /* deal with Admin passes */
3045         if (feature_bool(FEAT_OPLEVELS))
3046         mode_parse_apass(&state, flag_p);
3047         break;
3048
3049       case 'u': /* deal with user passes */
3050         if (feature_bool(FEAT_OPLEVELS))
3051         mode_parse_upass(&state, flag_p);
3052         break;
3053
3054       case 'b': /* deal with bans */
3055         mode_parse_ban(&state, flag_p);
3056         break;
3057
3058       case 'o': /* deal with ops/voice */
3059       case 'v':
3060         mode_parse_client(&state, flag_p);
3061         break;
3062
3063       default: /* deal with other modes */
3064         mode_parse_mode(&state, flag_p);
3065         break;
3066       } /* switch (*modestr) */
3067     } /* for (; *modestr; modestr++) */
3068
3069     if (state.flags & MODE_PARSE_BURST)
3070       break; /* don't interpret any more arguments */
3071
3072     if (state.parc > 0) { /* process next argument in string */
3073       modestr = state.parv[state.args_used++];
3074       state.parc--;
3075
3076       /* is it a TS? */
3077       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3078         time_t recv_ts;
3079
3080         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3081           break;                     /* we're then going to bounce the mode! */
3082
3083         recv_ts = atoi(modestr);
3084
3085         if (recv_ts && recv_ts < state.chptr->creationtime)
3086           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3087
3088         break; /* break out of while loop */
3089       } else if (state.flags & MODE_PARSE_STRICT ||
3090                  (MyUser(state.sptr) && state.max_args <= 0)) {
3091         state.parc++; /* we didn't actually gobble the argument */
3092         state.args_used--;
3093         break; /* break out of while loop */
3094       }
3095     }
3096   } /* while (*modestr) */
3097
3098   /*
3099    * the rest of the function finishes building resultant MODEs; if the
3100    * origin isn't a member or an oper, skip it.
3101    */
3102   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3103     return state.args_used; /* tell our parent how many args we gobbled */
3104
3105   t_mode = state.chptr->mode.mode;
3106
3107   if (state.del & t_mode) { /* delete any modes to be deleted... */
3108     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3109
3110     t_mode &= ~state.del;
3111   }
3112   if (state.add & ~t_mode) { /* add any modes to be added... */
3113     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3114
3115     t_mode |= state.add;
3116   }
3117
3118   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3119     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3120         !(t_mode & MODE_INVITEONLY))
3121       mode_invite_clear(state.chptr);
3122
3123     state.chptr->mode.mode = t_mode;
3124   }
3125
3126   if (state.flags & MODE_PARSE_WIPEOUT) {
3127     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3128       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3129                         state.chptr->mode.limit);
3130     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3131       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3132                           state.chptr->mode.key, 0);
3133     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3134       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3135                           state.chptr->mode.upass, 0);
3136     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3137       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3138                           state.chptr->mode.apass, 0);
3139   }
3140
3141   if (state.done & DONE_BANCLEAN) /* process bans */
3142     mode_process_bans(&state);
3143
3144   /* process client changes */
3145   if (state.cli_change[0].flag)
3146     mode_process_clients(&state);
3147
3148   return state.args_used; /* tell our parent how many args we gobbled */
3149 }
3150
3151 /*
3152  * Initialize a join buffer
3153  */
3154 void
3155 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3156              struct Client *connect, unsigned int type, char *comment,
3157              time_t create)
3158 {
3159   int i;
3160
3161   assert(0 != jbuf);
3162   assert(0 != source);
3163   assert(0 != connect);
3164
3165   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3166   jbuf->jb_connect = connect;
3167   jbuf->jb_type = type;
3168   jbuf->jb_comment = comment;
3169   jbuf->jb_create = create;
3170   jbuf->jb_count = 0;
3171   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3172                        type == JOINBUF_TYPE_PART ||
3173                        type == JOINBUF_TYPE_PARTALL) ?
3174                       STARTJOINLEN : STARTCREATELEN) +
3175                      (comment ? strlen(comment) + 2 : 0));
3176
3177   for (i = 0; i < MAXJOINARGS; i++)
3178     jbuf->jb_channels[i] = 0;
3179 }
3180
3181 /*
3182  * Add a channel to the join buffer
3183  */
3184 void
3185 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3186 {
3187   unsigned int len;
3188   int is_local;
3189
3190   assert(0 != jbuf);
3191
3192   if (!chan) {
3193     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3194       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3195
3196     return;
3197   }
3198
3199   is_local = IsLocalChannel(chan->chname);
3200
3201   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3202       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3203     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3204     if (IsUserParting(member))
3205       return;
3206     SetUserParting(member);
3207
3208     /* Send notification to channel */
3209     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3210       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3211                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3212                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3213     else if (MyUser(jbuf->jb_source))
3214       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3215                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3216                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3217     /* XXX: Shouldn't we send a PART here anyway? */
3218     /* to users on the channel?  Why?  From their POV, the user isn't on
3219      * the channel anymore anyway.  We don't send to servers until below,
3220      * when we gang all the channel parts together.  Note that this is
3221      * exactly the same logic, albeit somewhat more concise, as was in
3222      * the original m_part.c */
3223
3224     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3225         is_local) /* got to remove user here */
3226       remove_user_from_channel(jbuf->jb_source, chan);
3227   } else {
3228     /* Add user to channel */
3229     if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3230       add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3231     else
3232       add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3233
3234     /* send notification to all servers */
3235     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3236       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3237                             "%H %Tu", chan, chan->creationtime);
3238
3239     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3240       /* Send the notification to the channel */
3241       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3242
3243       /* send an op, too, if needed */
3244       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3245         sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3246                                          chan, jbuf->jb_source);
3247     } else if (MyUser(jbuf->jb_source))
3248       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3249   }
3250
3251   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3252       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3253     return; /* don't send to remote */
3254
3255   /* figure out if channel name will cause buffer to be overflowed */
3256   len = chan ? strlen(chan->chname) + 1 : 2;
3257   if (jbuf->jb_strlen + len > BUFSIZE)
3258     joinbuf_flush(jbuf);
3259
3260   /* add channel to list of channels to send and update counts */
3261   jbuf->jb_channels[jbuf->jb_count++] = chan;
3262   jbuf->jb_strlen += len;
3263
3264   /* if we've used up all slots, flush */
3265   if (jbuf->jb_count >= MAXJOINARGS)
3266     joinbuf_flush(jbuf);
3267 }
3268
3269 /*
3270  * Flush the channel list to remote servers
3271  */
3272 int
3273 joinbuf_flush(struct JoinBuf *jbuf)
3274 {
3275   char chanlist[BUFSIZE];
3276   int chanlist_i = 0;
3277   int i;
3278
3279   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3280       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3281     return 0; /* no joins to process */
3282
3283   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3284     build_string(chanlist, &chanlist_i,
3285                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3286                  i == 0 ? '\0' : ',');
3287     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3288       /* Remove user from channel */
3289       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3290
3291     jbuf->jb_channels[i] = 0; /* mark slot empty */
3292   }
3293
3294   jbuf->jb_count = 0; /* reset base counters */
3295   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3296                       STARTJOINLEN : STARTCREATELEN) +
3297                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3298
3299   /* and send the appropriate command */
3300   switch (jbuf->jb_type) {
3301   case JOINBUF_TYPE_CREATE:
3302     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3303                           "%s %Tu", chanlist, jbuf->jb_create);
3304     break;
3305
3306   case JOINBUF_TYPE_PART:
3307     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3308                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3309                           jbuf->jb_comment);
3310     break;
3311   }
3312
3313   return 0;
3314 }
3315
3316 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3317 int IsInvited(struct Client* cptr, const void* chptr)
3318 {
3319   struct SLink *lp;
3320
3321   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3322     if (lp->value.chptr == chptr)
3323       return 1;
3324   return 0;
3325 }
3326
3327 /* RevealDelayedJoin: sends a join for a hidden user */
3328
3329 void RevealDelayedJoin(struct Membership *member) {
3330   ClearDelayedJoin(member);
3331   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3332                                    member->channel);
3333   CheckDelayedJoins(member->channel);
3334 }
3335
3336 /* CheckDelayedJoins: checks and clear +d if necessary */
3337
3338 void CheckDelayedJoins(struct Channel *chan) {
3339   struct Membership *memb2;
3340   
3341   if (chan->mode.mode & MODE_WASDELJOINS) {
3342     for (memb2=chan->members;memb2;memb2=memb2->next_member)
3343       if (IsDelayedJoin(memb2))
3344         break;
3345     
3346     if (!memb2) {
3347       /* clear +d */
3348       chan->mode.mode &= ~MODE_WASDELJOINS;
3349       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
3350                                        "%H -d", chan);
3351     }
3352   }
3353 }