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