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