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