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