Add ZANNELS feature; tweak recreate after bogus DESTRUCT.
[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 (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source) || IsMe(mbuf->mb_source))
1595     app_source = &his;
1596   else
1597     app_source = mbuf->mb_source;
1598
1599   /*
1600    * Account for user we're bouncing; we have to get it in on the first
1601    * bounced MODE, or we could have problems
1602    */
1603   if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1604     totalbuflen -= 6; /* numeric nick == 5, plus one space */
1605
1606   /* Calculate the simple flags */
1607   for (flag_p = flags; flag_p[0]; flag_p += 2) {
1608     if (*flag_p & mbuf->mb_add)
1609       addbuf[addbuf_i++] = flag_p[1];
1610     else if (*flag_p & mbuf->mb_rem)
1611       rembuf[rembuf_i++] = flag_p[1];
1612   }
1613
1614   /* Some flags may be for local display only. */
1615   for (flag_p = local_flags; flag_p[0]; flag_p += 2) {
1616     if (*flag_p & mbuf->mb_add)
1617       addbuf_local[addbuf_local_i++] = flag_p[1];
1618     else if (*flag_p & mbuf->mb_rem)
1619       rembuf_local[rembuf_local_i++] = flag_p[1];
1620   }
1621
1622   /* Now go through the modes with arguments... */
1623   for (i = 0; i < mbuf->mb_count; i++) {
1624     if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1625       bufptr = addbuf;
1626       bufptr_i = &addbuf_i;
1627     } else {
1628       bufptr = rembuf;
1629       bufptr_i = &rembuf_i;
1630     }
1631
1632     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1633       tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1634
1635       if ((totalbuflen - IRCD_MAX(9, tmp)) <= 0) /* don't overflow buffer */
1636         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1637       else {
1638         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1639         totalbuflen -= IRCD_MAX(9, tmp) + 1;
1640       }
1641     } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1642       tmp = strlen(MB_STRING(mbuf, i));
1643
1644       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1645         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1646       else {
1647         char mode_char;
1648         switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1649         {
1650           case MODE_APASS:
1651             mode_char = 'A';
1652             break;
1653           case MODE_UPASS:
1654             mode_char = 'U';
1655             break;
1656           default:
1657             mode_char = 'b';
1658             break;
1659         }
1660         bufptr[(*bufptr_i)++] = mode_char;
1661         totalbuflen -= tmp + 1;
1662       }
1663     } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1664       tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1665              strlen(MB_STRING(mbuf, i)));
1666
1667       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1668         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1669       else {
1670         bufptr[(*bufptr_i)++] = 'k';
1671         totalbuflen -= tmp + 1;
1672       }
1673     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1674       /* if it's a limit, we also format the number */
1675       ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1676
1677       tmp = strlen(limitbuf);
1678
1679       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1680         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1681       else {
1682         bufptr[(*bufptr_i)++] = 'l';
1683         totalbuflen -= tmp + 1;
1684       }
1685     }
1686   }
1687
1688   /* terminate the mode strings */
1689   addbuf[addbuf_i] = '\0';
1690   rembuf[rembuf_i] = '\0';
1691   addbuf_local[addbuf_local_i] = '\0';
1692   rembuf_local[rembuf_local_i] = '\0';
1693
1694   /* If we're building a user visible MODE or HACK... */
1695   if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1696                        MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
1697                        MODEBUF_DEST_LOG)) {
1698     /* Set up the parameter strings */
1699     addstr[0] = '\0';
1700     addstr_i = 0;
1701     remstr[0] = '\0';
1702     remstr_i = 0;
1703
1704     for (i = 0; i < mbuf->mb_count; i++) {
1705       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1706         continue;
1707
1708       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1709         strptr = addstr;
1710         strptr_i = &addstr_i;
1711       } else {
1712         strptr = remstr;
1713         strptr_i = &remstr_i;
1714       }
1715
1716       /* deal with clients... */
1717       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1718         build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1719
1720       /* deal with bans... */
1721       else if (MB_TYPE(mbuf, i) & MODE_BAN)
1722         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1723
1724       /* deal with keys... */
1725       else if (MB_TYPE(mbuf, i) & MODE_KEY)
1726         build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1727                      "*" : MB_STRING(mbuf, i), 0, ' ');
1728
1729       /* deal with invisible passwords */
1730       else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1731         build_string(strptr, strptr_i, "*", 0, ' ');
1732
1733       /*
1734        * deal with limit; note we cannot include the limit parameter if we're
1735        * removing it
1736        */
1737       else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1738                (MODE_ADD | MODE_LIMIT))
1739         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1740     }
1741
1742     /* send the messages off to their destination */
1743     if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1744       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1745                            "[%Tu]",
1746                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1747                                     mbuf->mb_source : app_source),
1748                            mbuf->mb_channel->chname,
1749                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1750                            addbuf, remstr, addstr,
1751                            mbuf->mb_channel->creationtime);
1752
1753     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1754       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1755                            "%s%s%s%s%s%s [%Tu]",
1756                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ? 
1757                                     mbuf->mb_source : app_source),
1758                            mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1759                            rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1760                            mbuf->mb_channel->creationtime);
1761
1762     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1763       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1764                            "[%Tu]",
1765                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1766                                     mbuf->mb_source : app_source),
1767                            mbuf->mb_channel->chname,
1768                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1769                            addbuf, remstr, addstr,
1770                            mbuf->mb_channel->creationtime);
1771
1772     if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1773       log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1774                 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1775                 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1776                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1777
1778     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1779       sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL, 0,
1780                                        "%H %s%s%s%s%s%s%s%s", mbuf->mb_channel,
1781                                        rembuf_i || rembuf_local_i ? "-" : "",
1782                                        rembuf, rembuf_local,
1783                                        addbuf_i || addbuf_local_i ? "+" : "",
1784                                        addbuf, addbuf_local,
1785                                        remstr, addstr);
1786   }
1787
1788   /* Now are we supposed to propagate to other servers? */
1789   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1790     /* set up parameter string */
1791     addstr[0] = '\0';
1792     addstr_i = 0;
1793     remstr[0] = '\0';
1794     remstr_i = 0;
1795
1796     /*
1797      * limit is supressed if we're removing it; we have to figure out which
1798      * direction is the direction for it to be removed, though...
1799      */
1800     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_DEL : MODE_ADD;
1801
1802     for (i = 0; i < mbuf->mb_count; i++) {
1803       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1804         continue;
1805
1806       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1807         strptr = addstr;
1808         strptr_i = &addstr_i;
1809       } else {
1810         strptr = remstr;
1811         strptr_i = &remstr_i;
1812       }
1813
1814       /* if we're changing oplevels we know the oplevel, pass it on */
1815       if (mbuf->mb_channel->mode.apass[0]
1816           && (MB_TYPE(mbuf, i) & MODE_CHANOP)
1817           && MB_OPLEVEL(mbuf, i) < MAXOPLEVEL)
1818           *strptr_i += ircd_snprintf(0, strptr + *strptr_i, BUFSIZE - *strptr_i,
1819                                      " %s%s:%d",
1820                                      NumNick(MB_CLIENT(mbuf, i)),
1821                                      MB_OPLEVEL(mbuf, i));
1822
1823       /* deal with other modes that take clients */
1824       else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1825         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1826
1827       /* deal with modes that take strings */
1828       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1829         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1830
1831       /*
1832        * deal with the limit.  Logic here is complicated; if HACK2 is set,
1833        * we're bouncing the mode, so sense is reversed, and we have to
1834        * include the original limit if it looks like it's being removed
1835        */
1836       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1837         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1838     }
1839
1840     /* we were told to deop the source */
1841     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1842       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1843       addbuf[addbuf_i] = '\0'; /* terminate the string... */
1844       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1845
1846       /* mark that we've done this, so we don't do it again */
1847       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1848     }
1849
1850     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1851       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1852       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1853                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
1854                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1855                             addbuf, remstr, addstr);
1856     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1857       /*
1858        * If HACK2 was set, we're bouncing; we send the MODE back to the
1859        * connection we got it from with the senses reversed and a TS of 0;
1860        * origin is us
1861        */
1862       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1863                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1864                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
1865                     mbuf->mb_channel->creationtime);
1866     } else {
1867       /*
1868        * We're propagating a normal MODE command to the rest of the network;
1869        * we send the actual channel TS unless this is a HACK3 or a HACK4
1870        */
1871       if (IsServer(mbuf->mb_source))
1872         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1873                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1874                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1875                               addbuf, remstr, addstr,
1876                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1877                               mbuf->mb_channel->creationtime);
1878       else
1879         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1880                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
1881                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1882                               addbuf, remstr, addstr);
1883     }
1884   }
1885
1886   /* We've drained the ModeBuf... */
1887   mbuf->mb_add = 0;
1888   mbuf->mb_rem = 0;
1889   mbuf->mb_count = 0;
1890
1891   /* reinitialize the mode-with-arg slots */
1892   for (i = 0; i < MAXMODEPARAMS; i++) {
1893     /* If we saved any, pack them down */
1894     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1895       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1896       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1897
1898       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1899         continue;
1900     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1901       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1902
1903     MB_TYPE(mbuf, i) = 0;
1904     MB_UINT(mbuf, i) = 0;
1905   }
1906
1907   /* If we're supposed to flush it all, do so--all hail tail recursion */
1908   if (all && mbuf->mb_count)
1909     return modebuf_flush_int(mbuf, 1);
1910
1911   return 0;
1912 }
1913
1914 /** Initialise a modebuf
1915  * This routine just initializes a ModeBuf structure with the information
1916  * needed and the options given.
1917  *
1918  * @param mbuf          The mode buffer to initialise.
1919  * @param source        The client that is performing the mode.
1920  * @param connect       ?
1921  * @param chan          The channel that the mode is being performed upon.
1922  * @param dest          ?
1923  */
1924 void
1925 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1926              struct Client *connect, struct Channel *chan, unsigned int dest)
1927 {
1928   int i;
1929
1930   assert(0 != mbuf);
1931   assert(0 != source);
1932   assert(0 != chan);
1933   assert(0 != dest);
1934
1935   if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1936
1937   mbuf->mb_add = 0;
1938   mbuf->mb_rem = 0;
1939   mbuf->mb_source = source;
1940   mbuf->mb_connect = connect;
1941   mbuf->mb_channel = chan;
1942   mbuf->mb_dest = dest;
1943   mbuf->mb_count = 0;
1944
1945   /* clear each mode-with-parameter slot */
1946   for (i = 0; i < MAXMODEPARAMS; i++) {
1947     MB_TYPE(mbuf, i) = 0;
1948     MB_UINT(mbuf, i) = 0;
1949   }
1950 }
1951
1952 /** Append a new mode to a modebuf
1953  * This routine simply adds modes to be added or deleted; do a binary OR
1954  * with either MODE_ADD or MODE_DEL
1955  *
1956  * @param mbuf          Mode buffer
1957  * @param mode          MODE_ADD or MODE_DEL OR'd with MODE_PRIVATE etc.
1958  */
1959 void
1960 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1961 {
1962   assert(0 != mbuf);
1963   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1964
1965   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1966            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY |
1967            MODE_DELJOINS | MODE_WASDELJOINS);
1968
1969   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1970     return;
1971
1972   if (mode & MODE_ADD) {
1973     mbuf->mb_rem &= ~mode;
1974     mbuf->mb_add |= mode;
1975   } else {
1976     mbuf->mb_add &= ~mode;
1977     mbuf->mb_rem |= mode;
1978   }
1979 }
1980
1981 /** Append a mode that takes an int argument to the modebuf
1982  *
1983  * This routine adds a mode to be added or deleted that takes a unsigned
1984  * int parameter; mode may *only* be the relevant mode flag ORed with one
1985  * of MODE_ADD or MODE_DEL
1986  *
1987  * @param mbuf          The mode buffer to append to.
1988  * @param mode          The mode to append.
1989  * @param uint          The argument to the mode.
1990  */
1991 void
1992 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1993 {
1994   assert(0 != mbuf);
1995   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1996
1997   if (mode == (MODE_LIMIT | ((mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_ADD : MODE_DEL))) {
1998       mbuf->mb_rem |= mode;
1999       return;
2000   }
2001   MB_TYPE(mbuf, mbuf->mb_count) = mode;
2002   MB_UINT(mbuf, mbuf->mb_count) = uint;
2003
2004   /* when we've reached the maximal count, flush the buffer */
2005   if (++mbuf->mb_count >=
2006       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2007     modebuf_flush_int(mbuf, 0);
2008 }
2009
2010 /** append a string mode
2011  * This routine adds a mode to be added or deleted that takes a string
2012  * parameter; mode may *only* be the relevant mode flag ORed with one of
2013  * MODE_ADD or MODE_DEL
2014  *
2015  * @param mbuf          The mode buffer to append to.
2016  * @param mode          The mode to append.
2017  * @param string        The string parameter to append.
2018  * @param free          If the string should be free'd later.
2019  */
2020 void
2021 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
2022                     int free)
2023 {
2024   assert(0 != mbuf);
2025   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2026
2027   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
2028   MB_STRING(mbuf, mbuf->mb_count) = string;
2029
2030   /* when we've reached the maximal count, flush the buffer */
2031   if (++mbuf->mb_count >=
2032       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2033     modebuf_flush_int(mbuf, 0);
2034 }
2035
2036 /** Append a mode on a client to a modebuf.
2037  * This routine adds a mode to be added or deleted that takes a client
2038  * parameter; mode may *only* be the relevant mode flag ORed with one of
2039  * MODE_ADD or MODE_DEL
2040  *
2041  * @param mbuf          The modebuf to append the mode to.
2042  * @param mode          The mode to append.
2043  * @param client        The client argument to append.
2044  * @param oplevel       The oplevel the user had or will have
2045  */
2046 void
2047 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
2048                     struct Client *client, int oplevel)
2049 {
2050   assert(0 != mbuf);
2051   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
2052
2053   MB_TYPE(mbuf, mbuf->mb_count) = mode;
2054   MB_CLIENT(mbuf, mbuf->mb_count) = client;
2055   MB_OPLEVEL(mbuf, mbuf->mb_count) = oplevel;
2056
2057   /* when we've reached the maximal count, flush the buffer */
2058   if (++mbuf->mb_count >=
2059       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
2060     modebuf_flush_int(mbuf, 0);
2061 }
2062
2063 /** The exported binding for modebuf_flush()
2064  *
2065  * @param mbuf  The mode buffer to flush.
2066  * 
2067  * @see modebuf_flush_int()
2068  */
2069 int
2070 modebuf_flush(struct ModeBuf *mbuf)
2071 {
2072   struct Membership *memb;
2073
2074   /* Check if MODE_WASDELJOINS should be set */
2075   if (!(mbuf->mb_channel->mode.mode & (MODE_DELJOINS | MODE_WASDELJOINS))
2076       && (mbuf->mb_rem & MODE_DELJOINS)) {
2077     for (memb = mbuf->mb_channel->members; memb; memb = memb->next_member) {
2078       if (IsDelayedJoin(memb)) {
2079           mbuf->mb_channel->mode.mode |= MODE_WASDELJOINS;
2080           mbuf->mb_add |= MODE_WASDELJOINS;
2081           mbuf->mb_rem &= ~MODE_WASDELJOINS;
2082           break;
2083       }
2084     }
2085   }
2086
2087   return modebuf_flush_int(mbuf, 1);
2088 }
2089
2090 /* This extracts the simple modes contained in mbuf
2091  *
2092  * @param mbuf          The mode buffer to extract the modes from.
2093  * @param buf           The string buffer to write the modes into.
2094  */
2095 void
2096 modebuf_extract(struct ModeBuf *mbuf, char *buf)
2097 {
2098   static int flags[] = {
2099 /*  MODE_CHANOP,        'o', */
2100 /*  MODE_VOICE,         'v', */
2101     MODE_PRIVATE,       'p',
2102     MODE_SECRET,        's',
2103     MODE_MODERATED,     'm',
2104     MODE_TOPICLIMIT,    't',
2105     MODE_INVITEONLY,    'i',
2106     MODE_NOPRIVMSGS,    'n',
2107     MODE_KEY,           'k',
2108     MODE_APASS,         'A',
2109     MODE_UPASS,         'U',
2110 /*  MODE_BAN,           'b', */
2111     MODE_LIMIT,         'l',
2112     MODE_REGONLY,       'r',
2113     MODE_DELJOINS,      'D',
2114     0x0, 0x0
2115   };
2116   unsigned int add;
2117   int i, bufpos = 0, len;
2118   int *flag_p;
2119   char *key = 0, limitbuf[20];
2120   char *apass = 0, *upass = 0;
2121
2122   assert(0 != mbuf);
2123   assert(0 != buf);
2124
2125   buf[0] = '\0';
2126
2127   add = mbuf->mb_add;
2128
2129   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2130     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2131       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2132
2133       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2134         key = MB_STRING(mbuf, i);
2135       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2136         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2137       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2138         upass = MB_STRING(mbuf, i);
2139       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2140         apass = MB_STRING(mbuf, i);
2141     }
2142   }
2143
2144   if (!add)
2145     return;
2146
2147   buf[bufpos++] = '+'; /* start building buffer */
2148
2149   for (flag_p = flags; flag_p[0]; flag_p += 2)
2150     if (*flag_p & add)
2151       buf[bufpos++] = flag_p[1];
2152
2153   for (i = 0, len = bufpos; i < len; i++) {
2154     if (buf[i] == 'k')
2155       build_string(buf, &bufpos, key, 0, ' ');
2156     else if (buf[i] == 'l')
2157       build_string(buf, &bufpos, limitbuf, 0, ' ');
2158     else if (buf[i] == 'U')
2159       build_string(buf, &bufpos, upass, 0, ' ');
2160     else if (buf[i] == 'A')
2161       build_string(buf, &bufpos, apass, 0, ' ');
2162   }
2163
2164   buf[bufpos] = '\0';
2165
2166   return;
2167 }
2168
2169 /** Simple function to invalidate bans
2170  *
2171  * This function sets all bans as being valid.
2172  *
2173  * @param chan  The channel to operate on.
2174  */
2175 void
2176 mode_ban_invalidate(struct Channel *chan)
2177 {
2178   struct Membership *member;
2179
2180   for (member = chan->members; member; member = member->next_member)
2181     ClearBanValid(member);
2182 }
2183
2184 /** Simple function to drop invite structures
2185  *
2186  * Remove all the invites on the channel.
2187  *
2188  * @param chan          Channel to remove invites from.
2189  *
2190  */
2191 void
2192 mode_invite_clear(struct Channel *chan)
2193 {
2194   while (chan->invites)
2195     del_invite(chan->invites->value.cptr, chan);
2196 }
2197
2198 /* What we've done for mode_parse so far... */
2199 #define DONE_LIMIT      0x01    /**< We've set the limit */
2200 #define DONE_KEY        0x02    /**< We've set the key */
2201 #define DONE_BANLIST    0x04    /**< We've sent the ban list */
2202 #define DONE_NOTOPER    0x08    /**< We've sent a "Not oper" error */
2203 #define DONE_BANCLEAN   0x10    /**< We've cleaned bans... */
2204 #define DONE_UPASS      0x20    /**< We've set user pass */
2205 #define DONE_APASS      0x40    /**< We've set admin pass */
2206
2207 struct ParseState {
2208   struct ModeBuf *mbuf;
2209   struct Client *cptr;
2210   struct Client *sptr;
2211   struct Channel *chptr;
2212   struct Membership *member;
2213   int parc;
2214   char **parv;
2215   unsigned int flags;
2216   unsigned int dir;
2217   unsigned int done;
2218   unsigned int add;
2219   unsigned int del;
2220   int args_used;
2221   int max_args;
2222   int numbans;
2223   struct Ban banlist[MAXPARA];
2224   struct {
2225     unsigned int flag;
2226     unsigned short oplevel;
2227     struct Client *client;
2228   } cli_change[MAXPARA];
2229 };
2230
2231 /** Helper function to send "Not oper" or "Not member" messages
2232  * Here's a helper function to deal with sending along "Not oper" or
2233  * "Not member" messages
2234  *
2235  * @param state         Parsing State object
2236  */
2237 static void
2238 send_notoper(struct ParseState *state)
2239 {
2240   if (state->done & DONE_NOTOPER)
2241     return;
2242
2243   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2244              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2245
2246   state->done |= DONE_NOTOPER;
2247 }
2248
2249 /** Parse a limit
2250  * Helper function to convert limits
2251  *
2252  * @param state         Parsing state object.
2253  * @param flag_p        ?
2254  */
2255 static void
2256 mode_parse_limit(struct ParseState *state, int *flag_p)
2257 {
2258   unsigned int t_limit;
2259
2260   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2261     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2262       return;
2263
2264     if (state->parc <= 0) { /* warn if not enough args */
2265       if (MyUser(state->sptr))
2266         need_more_params(state->sptr, "MODE +l");
2267       return;
2268     }
2269
2270     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2271     state->parc--;
2272     state->max_args--;
2273
2274     if ((int)t_limit<0) /* don't permit a negative limit */
2275       return;
2276
2277     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2278         (!t_limit || t_limit == state->chptr->mode.limit))
2279       return;
2280   } else
2281     t_limit = state->chptr->mode.limit;
2282
2283   /* If they're not an oper, they can't change modes */
2284   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2285     send_notoper(state);
2286     return;
2287   }
2288
2289   /* Can't remove a limit that's not there */
2290   if (state->dir == MODE_DEL && !state->chptr->mode.limit)
2291     return;
2292     
2293   /* Skip if this is a burst and a lower limit than this is set already */
2294   if ((state->flags & MODE_PARSE_BURST) &&
2295       (state->chptr->mode.mode & flag_p[0]) &&
2296       (state->chptr->mode.limit < t_limit))
2297     return;
2298
2299   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2300     return;
2301   state->done |= DONE_LIMIT;
2302
2303   if (!state->mbuf)
2304     return;
2305
2306   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2307
2308   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2309     if (state->dir & MODE_ADD) {
2310       state->chptr->mode.mode |= flag_p[0];
2311       state->chptr->mode.limit = t_limit;
2312     } else {
2313       state->chptr->mode.mode &= ~flag_p[0];
2314       state->chptr->mode.limit = 0;
2315     }
2316   }
2317 }
2318
2319 /** Helper function to clean key-like parameters. */
2320 static void
2321 clean_key(char *s)
2322 {
2323   int t_len = KEYLEN;
2324
2325   while (*s > ' ' && *s != ':' && *s != ',' && t_len--)
2326     s++;
2327   *s = '\0';
2328 }
2329
2330 /*
2331  * Helper function to convert keys
2332  */
2333 static void
2334 mode_parse_key(struct ParseState *state, int *flag_p)
2335 {
2336   char *t_str;
2337
2338   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2339     return;
2340
2341   if (state->parc <= 0) { /* warn if not enough args */
2342     if (MyUser(state->sptr))
2343       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2344                        "MODE -k");
2345     return;
2346   }
2347
2348   t_str = state->parv[state->args_used++]; /* grab arg */
2349   state->parc--;
2350   state->max_args--;
2351
2352   /* If they're not an oper, they can't change modes */
2353   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2354     send_notoper(state);
2355     return;
2356   }
2357
2358   if (state->done & DONE_KEY) /* allow key to be set only once */
2359     return;
2360   state->done |= DONE_KEY;
2361
2362   /* clean up the key string */
2363   clean_key(t_str);
2364   if (!*t_str || *t_str == ':') { /* warn if empty */
2365     if (MyUser(state->sptr))
2366       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2367                        "MODE -k");
2368     return;
2369   }
2370
2371   if (!state->mbuf)
2372     return;
2373
2374   /* Skip if this is a burst, we have a key already and the new key is 
2375    * after the old one alphabetically */
2376   if ((state->flags & MODE_PARSE_BURST) &&
2377       *(state->chptr->mode.key) &&
2378       ircd_strcmp(state->chptr->mode.key, t_str) <= 0)
2379     return;
2380
2381   /* can't add a key if one is set, nor can one remove the wrong key */
2382   if (!(state->flags & MODE_PARSE_FORCE))
2383     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2384         (state->dir == MODE_DEL &&
2385          ircd_strcmp(state->chptr->mode.key, t_str))) {
2386       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2387       return;
2388     }
2389
2390   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2391       !ircd_strcmp(state->chptr->mode.key, t_str))
2392     return; /* no key change */
2393
2394   if (state->flags & MODE_PARSE_BOUNCE) {
2395     if (*state->chptr->mode.key) /* reset old key */
2396       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2397                           state->chptr->mode.key, 0);
2398     else /* remove new bogus key */
2399       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2400   } else /* send new key */
2401     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2402
2403   if (state->flags & MODE_PARSE_SET) {
2404     if (state->dir == MODE_DEL) /* remove the old key */
2405       *state->chptr->mode.key = '\0';
2406     else if (!state->chptr->mode.key[0]
2407              || ircd_strcmp(t_str, state->chptr->mode.key) < 0)
2408       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2409   }
2410 }
2411
2412 /*
2413  * Helper function to convert user passes
2414  */
2415 static void
2416 mode_parse_upass(struct ParseState *state, int *flag_p)
2417 {
2418   char *t_str;
2419
2420   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2421     return;
2422
2423   if (state->parc <= 0) { /* warn if not enough args */
2424     if (MyUser(state->sptr))
2425       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2426                        "MODE -U");
2427     return;
2428   }
2429
2430   t_str = state->parv[state->args_used++]; /* grab arg */
2431   state->parc--;
2432   state->max_args--;
2433
2434   /* If they're not an oper, they can't change modes */
2435   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2436     send_notoper(state);
2437     return;
2438   }
2439
2440   /* If a non-service user is trying to force it, refuse. */
2441   if (state->flags & MODE_PARSE_FORCE && MyUser(state->sptr)
2442       && !HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
2443     send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2444                state->chptr->chname);
2445     return;
2446   }
2447
2448   /* If they are not the channel manager, they are not allowed to change it */
2449   if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2450     if (*state->chptr->mode.apass) {
2451       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2452                  state->chptr->chname);
2453     } else {
2454       send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname,
2455           (TStime() - state->chptr->creationtime < 172800) ?
2456           "approximately 4-5 minutes" : "approximately 48 hours");
2457     }
2458     return;
2459   }
2460
2461   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2462     return;
2463   state->done |= DONE_UPASS;
2464
2465   /* clean up the upass string */
2466   clean_key(t_str);
2467   if (!*t_str || *t_str == ':') { /* warn if empty */
2468     if (MyUser(state->sptr))
2469       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +U" :
2470                        "MODE -U");
2471     return;
2472   }
2473
2474   if (!state->mbuf)
2475     return;
2476
2477   if (!(state->flags & MODE_PARSE_FORCE)) {
2478     /* can't add the upass while apass is not set */
2479     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2480       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2481       return;
2482     }
2483     /* cannot set a +U password that is the same as +A */
2484     if (state->dir == MODE_ADD && !ircd_strcmp(state->chptr->mode.apass, t_str)) {
2485       send_reply(state->sptr, ERR_UPASS_SAME_APASS, state->chptr->chname);
2486       return;
2487     }
2488     /* can't add a upass if one is set, nor can one remove the wrong upass */
2489     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2490         (state->dir == MODE_DEL &&
2491          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2492       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2493       return;
2494     }
2495   }
2496
2497   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2498       !ircd_strcmp(state->chptr->mode.upass, t_str))
2499     return; /* no upass change */
2500
2501   if (state->flags & MODE_PARSE_BOUNCE) {
2502     if (*state->chptr->mode.upass) /* reset old upass */
2503       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2504                           state->chptr->mode.upass, 0);
2505     else /* remove new bogus upass */
2506       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2507   } else /* send new upass */
2508     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2509
2510   if (state->flags & MODE_PARSE_SET) {
2511     if (state->dir == MODE_DEL) /* remove the old upass */
2512       *state->chptr->mode.upass = '\0';
2513     else if (state->chptr->mode.upass[0] == '\0'
2514              || ircd_strcmp(t_str, state->chptr->mode.upass) < 0)
2515       ircd_strncpy(state->chptr->mode.upass, t_str, KEYLEN);
2516   }
2517 }
2518
2519 /*
2520  * Helper function to convert admin passes
2521  */
2522 static void
2523 mode_parse_apass(struct ParseState *state, int *flag_p)
2524 {
2525   struct Membership *memb;
2526   char *t_str;
2527
2528   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2529     return;
2530
2531   if (state->parc <= 0) { /* warn if not enough args */
2532     if (MyUser(state->sptr))
2533       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2534                        "MODE -A");
2535     return;
2536   }
2537
2538   t_str = state->parv[state->args_used++]; /* grab arg */
2539   state->parc--;
2540   state->max_args--;
2541
2542   /* If they're not an oper, they can't change modes */
2543   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2544     send_notoper(state);
2545     return;
2546   }
2547
2548   if (MyUser(state->sptr)) {
2549     if (state->flags & MODE_PARSE_FORCE) {
2550       /* If an unprivileged oper is trying to force it, refuse. */
2551       if (!HasPriv(state->sptr, PRIV_APASS_OPMODE)) {
2552         send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2553                    state->chptr->chname);
2554         return;
2555       }
2556     } else {
2557       /* If they are not the channel manager, they are not allowed to change it. */
2558       if (!IsChannelManager(state->member)) {
2559         if (*state->chptr->mode.apass) {
2560           send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2561                      state->chptr->chname);
2562         } else {
2563           send_reply(state->sptr, ERR_NOMANAGER, state->chptr->chname,
2564                      (TStime() - state->chptr->creationtime < 172800) ?
2565                      "approximately 4-5 minutes" : "approximately 48 hours");
2566         }
2567         return;
2568       }
2569       /* Can't remove the Apass while Upass is still set. */
2570       if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2571         send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2572         return;
2573       }
2574       /* Can't add an Apass if one is set, nor can one remove the wrong Apass. */
2575       if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2576           (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2577         send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2578         return;
2579       }
2580     }
2581
2582     /* Forbid removing the Apass if the channel is older than 48 hours
2583      * unless an oper is doing it. */
2584     if (TStime() - state->chptr->creationtime >= 172800
2585         && state->dir == MODE_DEL
2586         && !IsAnOper(state->sptr)) {
2587       send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2588       return;
2589     }
2590   }
2591
2592   if (state->done & DONE_APASS) /* allow apass to be set only once */
2593     return;
2594   state->done |= DONE_APASS;
2595
2596   /* clean up the apass string */
2597   clean_key(t_str);
2598   if (!*t_str || *t_str == ':') { /* warn if empty */
2599     if (MyUser(state->sptr))
2600       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2601                        "MODE -A");
2602     return;
2603   }
2604
2605   if (!state->mbuf)
2606     return;
2607
2608   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2609       !ircd_strcmp(state->chptr->mode.apass, t_str))
2610     return; /* no apass change */
2611
2612   if (state->flags & MODE_PARSE_BOUNCE) {
2613     if (*state->chptr->mode.apass) /* reset old apass */
2614       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2615                           state->chptr->mode.apass, 0);
2616     else /* remove new bogus apass */
2617       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2618   } else /* send new apass */
2619     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2620
2621   if (state->flags & MODE_PARSE_SET) {
2622     if (state->dir == MODE_ADD) { /* set the new apass */
2623       /* Only accept the new apass if there is no current apass
2624        * (e.g. when a user sets it) or the new one is "less" than the
2625        * old (for resolving conflicts during burst).
2626        */
2627       if (state->chptr->mode.apass[0] == '\0'
2628           || ircd_strcmp(t_str, state->chptr->mode.apass) < 0)
2629         ircd_strncpy(state->chptr->mode.apass, t_str, KEYLEN);
2630       /* Make it VERY clear to the user that this is a one-time password */
2631       if (MyUser(state->sptr)) {
2632         send_reply(state->sptr, RPL_APASSWARN_SET, state->chptr->mode.apass);
2633         send_reply(state->sptr, RPL_APASSWARN_SECRET, state->chptr->chname,
2634                    state->chptr->mode.apass);
2635       }
2636       /* Give the channel manager level 0 ops.
2637          There should not be tested for IsChannelManager here because
2638          on the local server it is impossible to set the apass if one
2639          isn't a channel manager and remote servers might need to sync
2640          the oplevel here: when someone creates a channel (and becomes
2641          channel manager) during a net.break, and only sets the Apass
2642          after the net rejoined, they will have oplevel MAXOPLEVEL on
2643          all remote servers. */
2644       if (state->member)
2645         SetOpLevel(state->member, 0);
2646     } else { /* remove the old apass */
2647       *state->chptr->mode.apass = '\0';
2648       /* Clear Upass so that there is never a Upass set when a zannel is burst. */
2649       *state->chptr->mode.upass = '\0';
2650       if (MyUser(state->sptr))
2651         send_reply(state->sptr, RPL_APASSWARN_CLEAR);
2652       /* Revert everyone to MAXOPLEVEL. */
2653       for (memb = state->chptr->members; memb; memb = memb->next_member) {
2654         if (memb->status & MODE_CHANOP)
2655           SetOpLevel(memb, MAXOPLEVEL);
2656       }
2657     }
2658   }
2659 }
2660
2661 /** Compare one ban's extent to another.
2662  * This works very similarly to mmatch() but it knows about CIDR masks
2663  * and ban exceptions.  If both bans are CIDR-based, compare their
2664  * address bits; otherwise, use mmatch().
2665  * @param[in] old_ban One ban.
2666  * @param[in] new_ban Another ban.
2667  * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2668  */
2669 static int
2670 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2671 {
2672   int res;
2673   assert(old_ban != NULL);
2674   assert(new_ban != NULL);
2675   /* A ban is never treated as a superset of an exception. */
2676   if (!(old_ban->flags & BAN_EXCEPTION)
2677       && (new_ban->flags & BAN_EXCEPTION))
2678     return 1;
2679   /* If either is not an address mask, match the text masks. */
2680   if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2681     return mmatch(old_ban->banstr, new_ban->banstr);
2682   /* If the old ban has a longer prefix than new, it cannot be a superset. */
2683   if (old_ban->addrbits > new_ban->addrbits)
2684     return 1;
2685   /* Compare the masks before the hostname part.  */
2686   old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2687   res = mmatch(old_ban->banstr, new_ban->banstr);
2688   old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2689   if (res)
2690     return res;
2691   /* Compare the addresses. */
2692   return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2693 }
2694
2695 /** Add a ban from a ban list and mark bans that should be removed
2696  * because they overlap.
2697  *
2698  * There are three invariants for a ban list.  First, no ban may be
2699  * more specific than another ban.  Second, no exception may be more
2700  * specific than another exception.  Finally, no ban may be more
2701  * specific than any exception.
2702  *
2703  * @param[in,out] banlist Pointer to head of list.
2704  * @param[in] newban Ban (or exception) to add (or remove).
2705  * @param[in] do_free If non-zero, free \a newban on failure.
2706  * @return Zero if \a newban could be applied, non-zero if not.
2707  */
2708 int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
2709 {
2710   struct Ban *ban;
2711   size_t count = 0;
2712
2713   assert(newban->flags & (BAN_ADD|BAN_DEL));
2714   if (newban->flags & BAN_ADD) {
2715     size_t totlen = 0;
2716     /* If a less specific entry is found, fail.  */
2717     for (ban = *banlist; ban; ban = ban->next) {
2718       if (!bmatch(ban, newban)) {
2719         if (do_free)
2720           free_ban(newban);
2721         return 1;
2722       }
2723       if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2724         count++;
2725         totlen += strlen(ban->banstr);
2726       }
2727     }
2728     /* Mark more specific entries and add this one to the end of the list. */
2729     while ((ban = *banlist) != NULL) {
2730       if (!bmatch(newban, ban)) {
2731         ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2732       }
2733       banlist = &ban->next;
2734     }
2735     *banlist = newban;
2736     return 0;
2737   } else if (newban->flags & BAN_DEL) {
2738     size_t remove_count = 0;
2739     /* Mark more specific entries. */
2740     for (ban = *banlist; ban; ban = ban->next) {
2741       if (!bmatch(newban, ban)) {
2742         ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2743         remove_count++;
2744       }
2745     }
2746     if (remove_count)
2747         return 0;
2748     /* If no matches were found, fail. */
2749     if (do_free)
2750       free_ban(newban);
2751     return 3;
2752   }
2753   if (do_free)
2754     free_ban(newban);
2755   return 4;
2756 }
2757
2758 /*
2759  * Helper function to convert bans
2760  */
2761 static void
2762 mode_parse_ban(struct ParseState *state, int *flag_p)
2763 {
2764   char *t_str, *s;
2765   struct Ban *ban, *newban;
2766
2767   if (state->parc <= 0) { /* Not enough args, send ban list */
2768     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2769       send_ban_list(state->sptr, state->chptr);
2770       state->done |= DONE_BANLIST;
2771     }
2772
2773     return;
2774   }
2775
2776   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2777     return;
2778
2779   t_str = state->parv[state->args_used++]; /* grab arg */
2780   state->parc--;
2781   state->max_args--;
2782
2783   /* If they're not an oper, they can't change modes */
2784   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2785     send_notoper(state);
2786     return;
2787   }
2788
2789   if ((s = strchr(t_str, ' ')))
2790     *s = '\0';
2791
2792   if (!*t_str || *t_str == ':') { /* warn if empty */
2793     if (MyUser(state->sptr))
2794       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2795                        "MODE -b");
2796     return;
2797   }
2798
2799   /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2800   if (!(state->done & DONE_BANCLEAN)) {
2801     for (ban = state->chptr->banlist; ban; ban = ban->next)
2802       ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2803     state->done |= DONE_BANCLEAN;
2804   }
2805
2806   /* remember the ban for the moment... */
2807   newban = state->banlist + (state->numbans++);
2808   newban->next = 0;
2809   newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2810       | (*flag_p == MODE_BAN ? 0 : BAN_EXCEPTION);
2811   set_ban_mask(newban, collapse(pretty_mask(t_str)));
2812   ircd_strncpy(newban->who, IsUser(state->sptr) ? cli_name(state->sptr) : "*", NICKLEN);
2813   newban->when = TStime();
2814   apply_ban(&state->chptr->banlist, newban, 0);
2815 }
2816
2817 /*
2818  * This is the bottom half of the ban processor
2819  */
2820 static void
2821 mode_process_bans(struct ParseState *state)
2822 {
2823   struct Ban *ban, *newban, *prevban, *nextban;
2824   int count = 0;
2825   int len = 0;
2826   int banlen;
2827   int changed = 0;
2828
2829   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2830     count++;
2831     banlen = strlen(ban->banstr);
2832     len += banlen;
2833     nextban = ban->next;
2834
2835     if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2836       if (prevban)
2837         prevban->next = 0; /* Break the list; ban isn't a real ban */
2838       else
2839         state->chptr->banlist = 0;
2840
2841       count--;
2842       len -= banlen;
2843
2844       continue;
2845     } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2846       char *bandup;
2847       DupString(bandup, ban->banstr);
2848       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2849                           bandup, 1);
2850
2851       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2852         if (prevban) /* clip it out of the list... */
2853           prevban->next = ban->next;
2854         else
2855           state->chptr->banlist = ban->next;
2856
2857         count--;
2858         len -= banlen;
2859         free_ban(ban);
2860
2861         changed++;
2862         continue; /* next ban; keep prevban like it is */
2863       } else
2864         ban->flags &= BAN_IPMASK; /* unset other flags */
2865     } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2866       if (prevban)
2867         prevban->next = 0; /* Break the list; ban isn't a real ban */
2868       else
2869         state->chptr->banlist = 0;
2870
2871       /* If we're supposed to ignore it, do so. */
2872       if (ban->flags & BAN_OVERLAPPED &&
2873           !(state->flags & MODE_PARSE_BOUNCE)) {
2874         count--;
2875         len -= banlen;
2876       } else {
2877         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2878             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2879              count > feature_int(FEAT_MAXBANS))) {
2880           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2881                      ban->banstr);
2882           count--;
2883           len -= banlen;
2884         } else {
2885           char *bandup;
2886           /* add the ban to the buffer */
2887           DupString(bandup, ban->banstr);
2888           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2889                               bandup, 1);
2890
2891           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2892             newban = make_ban(ban->banstr);
2893             strcpy(newban->who, ban->who);
2894             newban->when = ban->when;
2895             newban->flags = ban->flags & BAN_IPMASK;
2896
2897             newban->next = state->chptr->banlist; /* and link it in */
2898             state->chptr->banlist = newban;
2899
2900             changed++;
2901           }
2902         }
2903       }
2904     }
2905
2906     prevban = ban;
2907   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2908
2909   if (changed) /* if we changed the ban list, we must invalidate the bans */
2910     mode_ban_invalidate(state->chptr);
2911 }
2912
2913 /*
2914  * Helper function to process client changes
2915  */
2916 static void
2917 mode_parse_client(struct ParseState *state, int *flag_p)
2918 {
2919   char *t_str;
2920   char *colon;
2921   struct Client *acptr;
2922   struct Membership *member;
2923   int oplevel = MAXOPLEVEL + 1;
2924   int req_oplevel;
2925   int i;
2926
2927   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2928     return;
2929
2930   if (state->parc <= 0) /* return if not enough args */
2931     return;
2932
2933   t_str = state->parv[state->args_used++]; /* grab arg */
2934   state->parc--;
2935   state->max_args--;
2936
2937   /* If they're not an oper, they can't change modes */
2938   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2939     send_notoper(state);
2940     return;
2941   }
2942
2943   if (MyUser(state->sptr)) {
2944     colon = strchr(t_str, ':');
2945     if (colon != NULL) {
2946       *colon++ = '\0';
2947       req_oplevel = atoi(colon);
2948       if (!(state->flags & MODE_PARSE_FORCE)
2949           && state->member
2950           && (req_oplevel < OpLevel(state->member)
2951               || (req_oplevel == OpLevel(state->member)
2952                   && OpLevel(state->member) < MAXOPLEVEL)
2953               || req_oplevel > MAXOPLEVEL))
2954         send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2955                    t_str, state->chptr->chname,
2956                    OpLevel(state->member), req_oplevel, "op",
2957                    OpLevel(state->member) == req_oplevel ? "the same" : "a higher");
2958       else if (req_oplevel <= MAXOPLEVEL)
2959         oplevel = req_oplevel;
2960     }
2961     /* find client we're manipulating */
2962     acptr = find_chasing(state->sptr, t_str, NULL);
2963   } else {
2964     if (t_str[5] == ':') {
2965       t_str[5] = '\0';
2966       oplevel = atoi(t_str + 6);
2967     }
2968     acptr = findNUser(t_str);
2969   }
2970
2971   if (!acptr)
2972     return; /* find_chasing() already reported an error to the user */
2973
2974   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2975     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2976                                        state->cli_change[i].flag & flag_p[0]))
2977       break; /* found a slot */
2978
2979   /* If we are going to bounce this deop, mark the correct oplevel. */
2980   if (state->flags & MODE_PARSE_BOUNCE
2981       && state->dir == MODE_DEL
2982       && flag_p[0] == MODE_CHANOP
2983       && (member = find_member_link(state->chptr, acptr)))
2984       oplevel = OpLevel(member);
2985
2986   /* Store what we're doing to them */
2987   state->cli_change[i].flag = state->dir | flag_p[0];
2988   state->cli_change[i].oplevel = oplevel;
2989   state->cli_change[i].client = acptr;
2990 }
2991
2992 /*
2993  * Helper function to process the changed client list
2994  */
2995 static void
2996 mode_process_clients(struct ParseState *state)
2997 {
2998   int i;
2999   struct Membership *member;
3000
3001   for (i = 0; state->cli_change[i].flag; i++) {
3002     assert(0 != state->cli_change[i].client);
3003
3004     /* look up member link */
3005     if (!(member = find_member_link(state->chptr,
3006                                     state->cli_change[i].client)) ||
3007         (MyUser(state->sptr) && IsZombie(member))) {
3008       if (MyUser(state->sptr))
3009         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
3010                    cli_name(state->cli_change[i].client),
3011                    state->chptr->chname);
3012       continue;
3013     }
3014
3015     if ((state->cli_change[i].flag & MODE_ADD &&
3016          (state->cli_change[i].flag & member->status)) ||
3017         (state->cli_change[i].flag & MODE_DEL &&
3018          !(state->cli_change[i].flag & member->status)))
3019       continue; /* no change made, don't do anything */
3020
3021     /* see if the deop is allowed */
3022     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
3023         (MODE_DEL | MODE_CHANOP)) {
3024       /* prevent +k users from being deopped */
3025       if (IsChannelService(state->cli_change[i].client)) {
3026         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
3027           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
3028                                state->chptr,
3029                                (IsServer(state->sptr) ? cli_name(state->sptr) :
3030                                 cli_name((cli_user(state->sptr))->server)));
3031
3032         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
3033           send_reply(state->sptr, ERR_ISCHANSERVICE,
3034                      cli_name(state->cli_change[i].client),
3035                      state->chptr->chname);
3036           continue;
3037         }
3038       }
3039
3040       /* check deop for local user */
3041       if (MyUser(state->sptr)) {
3042
3043         /* don't allow local opers to be deopped on local channels */
3044         if (state->cli_change[i].client != state->sptr &&
3045             IsLocalChannel(state->chptr->chname) &&
3046             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3047           send_reply(state->sptr, ERR_ISOPERLCHAN,
3048                      cli_name(state->cli_change[i].client),
3049                      state->chptr->chname);
3050           continue;
3051         }
3052
3053         /* Forbid deopping other members with an oplevel less than
3054          * one's own level, and other members with an oplevel the same
3055          * as one's own unless both are at MAXOPLEVEL. */
3056         if (state->sptr != state->cli_change[i].client
3057             && state->member
3058             && ((OpLevel(member) < OpLevel(state->member))
3059                 || (OpLevel(member) == OpLevel(state->member)
3060                     && OpLevel(member) < MAXOPLEVEL))) {
3061             int equal = (OpLevel(member) == OpLevel(state->member));
3062             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3063                        cli_name(state->cli_change[i].client),
3064                        state->chptr->chname,
3065                        OpLevel(state->member), OpLevel(member),
3066                        "deop", equal ? "the same" : "a higher");
3067           continue;
3068         }
3069       }
3070     }
3071
3072     /* set op-level of member being opped */
3073     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3074         (MODE_ADD | MODE_CHANOP)) {
3075       /* If a valid oplevel was specified, use it.
3076        * Otherwise, if being opped by an outsider, get MAXOPLEVEL.
3077        * Otherwise, if not an apass channel, or state->member has
3078        *   MAXOPLEVEL, get oplevel MAXOPLEVEL.
3079        * Otherwise, get state->member's oplevel+1.
3080        */
3081       if (state->cli_change[i].oplevel <= MAXOPLEVEL)
3082         SetOpLevel(member, state->cli_change[i].oplevel);
3083       else if (!state->member)
3084         SetOpLevel(member, MAXOPLEVEL);
3085       else if (!state->chptr->mode.apass[0] || OpLevel(state->member) == MAXOPLEVEL)
3086         SetOpLevel(member, MAXOPLEVEL);
3087       else
3088         SetOpLevel(member, OpLevel(state->member) + 1);
3089     }
3090
3091     /* actually effect the change */
3092     if (state->flags & MODE_PARSE_SET) {
3093       if (state->cli_change[i].flag & MODE_ADD) {
3094         if (IsDelayedJoin(member))
3095           RevealDelayedJoin(member);
3096         member->status |= (state->cli_change[i].flag &
3097                            (MODE_CHANOP | MODE_VOICE));
3098         if (state->cli_change[i].flag & MODE_CHANOP)
3099           ClearDeopped(member);
3100       } else
3101         member->status &= ~(state->cli_change[i].flag &
3102                             (MODE_CHANOP | MODE_VOICE));
3103     }
3104
3105     /* accumulate the change */
3106     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3107                         state->cli_change[i].client,
3108                         state->cli_change[i].oplevel);
3109   } /* for (i = 0; state->cli_change[i].flags; i++) */
3110 }
3111
3112 /*
3113  * Helper function to process the simple modes
3114  */
3115 static void
3116 mode_parse_mode(struct ParseState *state, int *flag_p)
3117 {
3118   /* If they're not an oper, they can't change modes */
3119   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3120     send_notoper(state);
3121     return;
3122   }
3123
3124   if (!state->mbuf)
3125     return;
3126
3127   if (state->dir == MODE_ADD) {
3128     state->add |= flag_p[0];
3129     state->del &= ~flag_p[0];
3130
3131     if (flag_p[0] & MODE_SECRET) {
3132       state->add &= ~MODE_PRIVATE;
3133       state->del |= MODE_PRIVATE;
3134     } else if (flag_p[0] & MODE_PRIVATE) {
3135       state->add &= ~MODE_SECRET;
3136       state->del |= MODE_SECRET;
3137     }
3138     if (flag_p[0] & MODE_DELJOINS) {
3139       state->add &= ~MODE_WASDELJOINS;
3140       state->del |= MODE_WASDELJOINS;
3141     }
3142   } else {
3143     state->add &= ~flag_p[0];
3144     state->del |= flag_p[0];
3145   }
3146
3147   assert(0 == (state->add & state->del));
3148   assert((MODE_SECRET | MODE_PRIVATE) !=
3149          (state->add & (MODE_SECRET | MODE_PRIVATE)));
3150 }
3151
3152 /*
3153  * This routine is intended to parse MODE or OPMODE commands and effect the
3154  * changes (or just build the bounce buffer).  We pass the starting offset
3155  * as a 
3156  */
3157 int
3158 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3159            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3160            struct Membership* member)
3161 {
3162   static int chan_flags[] = {
3163     MODE_CHANOP,        'o',
3164     MODE_VOICE,         'v',
3165     MODE_PRIVATE,       'p',
3166     MODE_SECRET,        's',
3167     MODE_MODERATED,     'm',
3168     MODE_TOPICLIMIT,    't',
3169     MODE_INVITEONLY,    'i',
3170     MODE_NOPRIVMSGS,    'n',
3171     MODE_KEY,           'k',
3172     MODE_APASS,         'A',
3173     MODE_UPASS,         'U',
3174     MODE_BAN,           'b',
3175     MODE_LIMIT,         'l',
3176     MODE_REGONLY,       'r',
3177     MODE_DELJOINS,      'D',
3178     MODE_ADD,           '+',
3179     MODE_DEL,           '-',
3180     0x0, 0x0
3181   };
3182   int i;
3183   int *flag_p;
3184   unsigned int t_mode;
3185   char *modestr;
3186   struct ParseState state;
3187
3188   assert(0 != cptr);
3189   assert(0 != sptr);
3190   assert(0 != chptr);
3191   assert(0 != parc);
3192   assert(0 != parv);
3193
3194   state.mbuf = mbuf;
3195   state.cptr = cptr;
3196   state.sptr = sptr;
3197   state.chptr = chptr;
3198   state.member = member;
3199   state.parc = parc;
3200   state.parv = parv;
3201   state.flags = flags;
3202   state.dir = MODE_ADD;
3203   state.done = 0;
3204   state.add = 0;
3205   state.del = 0;
3206   state.args_used = 0;
3207   state.max_args = MAXMODEPARAMS;
3208   state.numbans = 0;
3209
3210   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3211     state.banlist[i].next = 0;
3212     state.banlist[i].who[0] = '\0';
3213     state.banlist[i].when = 0;
3214     state.banlist[i].flags = 0;
3215     state.cli_change[i].flag = 0;
3216     state.cli_change[i].client = 0;
3217   }
3218
3219   modestr = state.parv[state.args_used++];
3220   state.parc--;
3221
3222   while (*modestr) {
3223     for (; *modestr; modestr++) {
3224       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3225         if (flag_p[1] == *modestr)
3226           break;
3227
3228       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3229         if (MyUser(state.sptr))
3230           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3231         continue;
3232       }
3233
3234       switch (*modestr) {
3235       case '+': /* switch direction to MODE_ADD */
3236       case '-': /* switch direction to MODE_DEL */
3237         state.dir = flag_p[0];
3238         break;
3239
3240       case 'l': /* deal with limits */
3241         mode_parse_limit(&state, flag_p);
3242         break;
3243
3244       case 'k': /* deal with keys */
3245         mode_parse_key(&state, flag_p);
3246         break;
3247
3248       case 'A': /* deal with Admin passes */
3249         if (IsServer(cptr) || feature_bool(FEAT_OPLEVELS))
3250         mode_parse_apass(&state, flag_p);
3251         break;
3252
3253       case 'U': /* deal with user passes */
3254         if (IsServer(cptr) || feature_bool(FEAT_OPLEVELS))
3255         mode_parse_upass(&state, flag_p);
3256         break;
3257
3258       case 'b': /* deal with bans */
3259         mode_parse_ban(&state, flag_p);
3260         break;
3261
3262       case 'o': /* deal with ops/voice */
3263       case 'v':
3264         mode_parse_client(&state, flag_p);
3265         break;
3266
3267       default: /* deal with other modes */
3268         mode_parse_mode(&state, flag_p);
3269         break;
3270       } /* switch (*modestr) */
3271     } /* for (; *modestr; modestr++) */
3272
3273     if (state.flags & MODE_PARSE_BURST)
3274       break; /* don't interpret any more arguments */
3275
3276     if (state.parc > 0) { /* process next argument in string */
3277       modestr = state.parv[state.args_used++];
3278       state.parc--;
3279
3280       /* is it a TS? */
3281       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3282         time_t recv_ts;
3283
3284         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3285           break;                     /* we're then going to bounce the mode! */
3286
3287         recv_ts = atoi(modestr);
3288
3289         if (recv_ts && recv_ts < state.chptr->creationtime)
3290           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3291
3292         break; /* break out of while loop */
3293       } else if (state.flags & MODE_PARSE_STRICT ||
3294                  (MyUser(state.sptr) && state.max_args <= 0)) {
3295         state.parc++; /* we didn't actually gobble the argument */
3296         state.args_used--;
3297         break; /* break out of while loop */
3298       }
3299     }
3300   } /* while (*modestr) */
3301
3302   /*
3303    * the rest of the function finishes building resultant MODEs; if the
3304    * origin isn't a member or an oper, skip it.
3305    */
3306   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3307     return state.args_used; /* tell our parent how many args we gobbled */
3308
3309   t_mode = state.chptr->mode.mode;
3310
3311   if (state.del & t_mode) { /* delete any modes to be deleted... */
3312     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3313
3314     t_mode &= ~state.del;
3315   }
3316   if (state.add & ~t_mode) { /* add any modes to be added... */
3317     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3318
3319     t_mode |= state.add;
3320   }
3321
3322   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3323     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3324         !(t_mode & MODE_INVITEONLY))
3325       mode_invite_clear(state.chptr);
3326
3327     state.chptr->mode.mode = t_mode;
3328   }
3329
3330   if (state.flags & MODE_PARSE_WIPEOUT) {
3331     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3332       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3333                         state.chptr->mode.limit);
3334     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3335       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3336                           state.chptr->mode.key, 0);
3337     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3338       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3339                           state.chptr->mode.upass, 0);
3340     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3341       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3342                           state.chptr->mode.apass, 0);
3343   }
3344
3345   if (state.done & DONE_BANCLEAN) /* process bans */
3346     mode_process_bans(&state);
3347
3348   /* process client changes */
3349   if (state.cli_change[0].flag)
3350     mode_process_clients(&state);
3351
3352   return state.args_used; /* tell our parent how many args we gobbled */
3353 }
3354
3355 /*
3356  * Initialize a join buffer
3357  */
3358 void
3359 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3360              struct Client *connect, unsigned int type, char *comment,
3361              time_t create)
3362 {
3363   int i;
3364
3365   assert(0 != jbuf);
3366   assert(0 != source);
3367   assert(0 != connect);
3368
3369   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3370   jbuf->jb_connect = connect;
3371   jbuf->jb_type = type;
3372   jbuf->jb_comment = comment;
3373   jbuf->jb_create = create;
3374   jbuf->jb_count = 0;
3375   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3376                        type == JOINBUF_TYPE_PART ||
3377                        type == JOINBUF_TYPE_PARTALL) ?
3378                       STARTJOINLEN : STARTCREATELEN) +
3379                      (comment ? strlen(comment) + 2 : 0));
3380
3381   for (i = 0; i < MAXJOINARGS; i++)
3382     jbuf->jb_channels[i] = 0;
3383 }
3384
3385 /*
3386  * Add a channel to the join buffer
3387  */
3388 void
3389 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3390 {
3391   unsigned int len;
3392   int is_local;
3393
3394   assert(0 != jbuf);
3395
3396   if (!chan) {
3397     sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3398     return;
3399   }
3400
3401   is_local = IsLocalChannel(chan->chname);
3402
3403   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3404       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3405     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3406     if (IsUserParting(member))
3407       return;
3408     SetUserParting(member);
3409
3410     /* Send notification to channel */
3411     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3412       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3413                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3414                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3415     else if (MyUser(jbuf->jb_source))
3416       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3417                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3418                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3419     /* XXX: Shouldn't we send a PART here anyway? */
3420     /* to users on the channel?  Why?  From their POV, the user isn't on
3421      * the channel anymore anyway.  We don't send to servers until below,
3422      * when we gang all the channel parts together.  Note that this is
3423      * exactly the same logic, albeit somewhat more concise, as was in
3424      * the original m_part.c */
3425
3426     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3427         is_local) /* got to remove user here */
3428       remove_user_from_channel(jbuf->jb_source, chan);
3429   } else {
3430     int oplevel = !chan->mode.apass[0] ? MAXOPLEVEL
3431         : (flags & CHFL_CHANNEL_MANAGER) ? 0
3432         : 1;
3433     /* Add user to channel */
3434     if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3435       add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, oplevel);
3436     else
3437       add_user_to_channel(chan, jbuf->jb_source, flags, oplevel);
3438
3439     /* send JOIN notification to all servers (CREATE is sent later). */
3440     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3441       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3442                             "%H %Tu", chan, chan->creationtime);
3443
3444     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3445       /* Send the notification to the channel */
3446       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3447
3448       /* send an op, too, if needed */
3449       if (flags & CHFL_CHANOP && (oplevel < MAXOPLEVEL || !MyUser(jbuf->jb_source)))
3450         sendcmdto_channel_butserv_butone((chan->mode.apass[0] ? &his : jbuf->jb_source),
3451                                          CMD_MODE, chan, NULL, 0, "%H +o %C",
3452                                          chan, jbuf->jb_source);
3453     } else if (MyUser(jbuf->jb_source))
3454       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3455   }
3456
3457   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3458       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3459     return; /* don't send to remote */
3460
3461   /* figure out if channel name will cause buffer to be overflowed */
3462   len = chan ? strlen(chan->chname) + 1 : 2;
3463   if (jbuf->jb_strlen + len > BUFSIZE)
3464     joinbuf_flush(jbuf);
3465
3466   /* add channel to list of channels to send and update counts */
3467   jbuf->jb_channels[jbuf->jb_count++] = chan;
3468   jbuf->jb_strlen += len;
3469
3470   /* if we've used up all slots, flush */
3471   if (jbuf->jb_count >= MAXJOINARGS)
3472     joinbuf_flush(jbuf);
3473 }
3474
3475 /*
3476  * Flush the channel list to remote servers
3477  */
3478 int
3479 joinbuf_flush(struct JoinBuf *jbuf)
3480 {
3481   char chanlist[BUFSIZE];
3482   int chanlist_i = 0;
3483   int i;
3484
3485   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3486       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3487     return 0; /* no joins to process */
3488
3489   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3490     build_string(chanlist, &chanlist_i,
3491                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3492                  i == 0 ? '\0' : ',');
3493     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3494       /* Remove user from channel */
3495       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3496
3497     jbuf->jb_channels[i] = 0; /* mark slot empty */
3498   }
3499
3500   jbuf->jb_count = 0; /* reset base counters */
3501   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3502                       STARTJOINLEN : STARTCREATELEN) +
3503                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3504
3505   /* and send the appropriate command */
3506   switch (jbuf->jb_type) {
3507   case JOINBUF_TYPE_CREATE:
3508     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3509                           "%s %Tu", chanlist, jbuf->jb_create);
3510     break;
3511
3512   case JOINBUF_TYPE_PART:
3513     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3514                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3515                           jbuf->jb_comment);
3516     break;
3517   }
3518
3519   return 0;
3520 }
3521
3522 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3523 int IsInvited(struct Client* cptr, const void* chptr)
3524 {
3525   struct SLink *lp;
3526
3527   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3528     if (lp->value.chptr == chptr)
3529       return 1;
3530   return 0;
3531 }
3532
3533 /* RevealDelayedJoin: sends a join for a hidden user */
3534
3535 void RevealDelayedJoin(struct Membership *member)
3536 {
3537   ClearDelayedJoin(member);
3538   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3539                                    member->channel);
3540   CheckDelayedJoins(member->channel);
3541 }
3542
3543 /* CheckDelayedJoins: checks and clear +d if necessary */
3544
3545 void CheckDelayedJoins(struct Channel *chan)
3546 {
3547   struct Membership *memb2;
3548
3549   if (chan->mode.mode & MODE_WASDELJOINS) {
3550     for (memb2=chan->members;memb2;memb2=memb2->next_member)
3551       if (IsDelayedJoin(memb2))
3552         break;
3553
3554     if (!memb2) {
3555       /* clear +d */
3556       chan->mode.mode &= ~MODE_WASDELJOINS;
3557       sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan, NULL, 0,
3558                                        "%H -d", chan);
3559     }
3560   }
3561 }