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