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