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