Fix another SILENCE crash.
[ircu2.10.12-pk.git] / ircd / channel.c
1 /*
2  * IRC - Internet Relay Chat, ircd/channel.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Co Center
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 /** @file
21  * @brief Channel management and maintanance
22  * @version $Id$
23  */
24 #include "config.h"
25
26 #include "channel.h"
27 #include "client.h"
28 #include "destruct_event.h"
29 #include "hash.h"
30 #include "ircd.h"
31 #include "ircd_alloc.h"
32 #include "ircd_chattr.h"
33 #include "ircd_defs.h"
34 #include "ircd_features.h"
35 #include "ircd_log.h"
36 #include "ircd_reply.h"
37 #include "ircd_snprintf.h"
38 #include "ircd_string.h"
39 #include "list.h"
40 #include "match.h"
41 #include "msg.h"
42 #include "msgq.h"
43 #include "numeric.h"
44 #include "numnicks.h"
45 #include "querycmds.h"
46 #include "s_bsd.h"
47 #include "s_conf.h"
48 #include "s_debug.h"
49 #include "s_misc.h"
50 #include "s_user.h"
51 #include "send.h"
52 #include "struct.h"
53 #include "sys.h"
54 #include "whowas.h"
55
56 /* #include <assert.h> -- 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 represeting 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.mode & MODE_APASS))         /* 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 banlist 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 destory 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 priviledged 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.mode & MODE_APASS) != 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 seperated " 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 || !feat_oplevels)
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 (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 seperated " :%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 seperated 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 occured bitwised OR'd with MAGIC_OPER_OVERRIDE
1215  *          if the oper used the magic key, 0 if no error occured.
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 afterwards - 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 contatenate from.
1534  * @param str2          The second string to contatenate from.
1535  * @param c             Charactor to seperate 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 && !IsChannelService(state->sptr)) {
2440     send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2441                "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2442     return;
2443   }
2444
2445   /* If they are not the channel manager, they are not allowed to change it */
2446   if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2447     if (*state->chptr->mode.apass) {
2448       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2449           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2450     } else {
2451       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2452           "Re-create the channel.  The channel must be *empty* for",
2453           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2454           "before it can be recreated.");
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   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2496       !ircd_strcmp(state->chptr->mode.upass, t_str))
2497     return; /* no upass change */
2498
2499   if (state->flags & MODE_PARSE_BOUNCE) {
2500     if (*state->chptr->mode.upass) /* reset old upass */
2501       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2502                           state->chptr->mode.upass, 0);
2503     else /* remove new bogus upass */
2504       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2505   } else /* send new upass */
2506     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2507
2508   if (state->flags & MODE_PARSE_SET) {
2509     if (state->dir == MODE_ADD) /* set the new upass */
2510       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2511     else /* remove the old upass */
2512       *state->chptr->mode.upass = '\0';
2513   }
2514 }
2515
2516 /*
2517  * Helper function to convert admin passes
2518  */
2519 static void
2520 mode_parse_apass(struct ParseState *state, int *flag_p)
2521 {
2522   char *t_str, *s;
2523   int t_len;
2524
2525   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2526     return;
2527
2528   if (state->parc <= 0) { /* warn if not enough args */
2529     if (MyUser(state->sptr))
2530       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2531                        "MODE -A");
2532     return;
2533   }
2534
2535   t_str = state->parv[state->args_used++]; /* grab arg */
2536   state->parc--;
2537   state->max_args--;
2538
2539   /* If they're not an oper, they can't change modes */
2540   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2541     send_notoper(state);
2542     return;
2543   }
2544
2545   /* If a non-service user is trying to force it, refuse. */
2546   if (state->flags & MODE_PARSE_FORCE && !IsChannelService(state->sptr)) {
2547     send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2548                "Use /JOIN", state->chptr->chname, " <AdminPass>.");
2549     return;
2550   }
2551
2552   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2553   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2554     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2555     return;
2556   }
2557
2558   /* If they are not the channel manager, they are not allowed to change it */
2559   if (MyUser(state->sptr) && !(state->flags & MODE_PARSE_FORCE || IsChannelManager(state->member))) {
2560     if (*state->chptr->mode.apass) {
2561       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2562           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2563     } else {
2564       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2565           "Re-create the channel.  The channel must be *empty* for",
2566           "at least a whole minute", "before it can be recreated.");
2567     }
2568     return;
2569   }
2570  
2571   if (state->done & DONE_APASS) /* allow apass to be set only once */
2572     return;
2573   state->done |= DONE_APASS;
2574
2575   t_len = PASSLEN + 1;
2576
2577   /* clean up the apass string */
2578   s = t_str;
2579   while (*++s > ' ' && *s != ':' && --t_len)
2580     ;
2581   *s = '\0';
2582
2583   if (!*t_str) { /* warn if empty */
2584     if (MyUser(state->sptr))
2585       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2586                        "MODE -A");
2587     return;
2588   }
2589
2590   if (!state->mbuf)
2591     return;
2592
2593   if (!(state->flags & MODE_PARSE_FORCE)) {
2594     /* can't remove the apass while upass is still set */
2595     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2596       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2597       return;
2598     }
2599     /* can't add an apass if one is set, nor can one remove the wrong apass */
2600     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2601         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2602       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2603       return;
2604     }
2605   }
2606
2607   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2608       !ircd_strcmp(state->chptr->mode.apass, t_str))
2609     return; /* no apass change */
2610
2611   if (state->flags & MODE_PARSE_BOUNCE) {
2612     if (*state->chptr->mode.apass) /* reset old apass */
2613       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2614                           state->chptr->mode.apass, 0);
2615     else /* remove new bogus apass */
2616       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2617   } else /* send new apass */
2618     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2619
2620   if (state->flags & MODE_PARSE_SET) {
2621     if (state->dir == MODE_ADD) { /* set the new apass */
2622       /* Make it VERY clear to the user that this is a one-time password */
2623       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2624       if (MyUser(state->sptr)) {
2625         send_reply(state->sptr, RPL_APASSWARN,
2626             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2627             "Are you SURE you want to use this as Admin password? ",
2628             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2629         send_reply(state->sptr, RPL_APASSWARN,
2630             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2631             "\" to remove the password and then immediately set a new one. "
2632             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2633             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2634             "Now set the channel user password (+U).");
2635       }
2636     } else { /* remove the old apass */
2637       *state->chptr->mode.apass = '\0';
2638       if (MyUser(state->sptr))
2639         send_reply(state->sptr, RPL_APASSWARN,
2640             "WARNING: You removed the channel Admin password MODE (+A). ",
2641             "If you would disconnect or leave the channel without setting a new password then you will ",
2642             "not be able to set it again and lose ownership of this channel! ",
2643             "SET A NEW PASSWORD NOW!", "");
2644     }
2645   }
2646 }
2647
2648 /** Compare one ban's extent to another.
2649  * This works very similarly to mmatch() but it knows about CIDR masks
2650  * and ban exceptions.  If both bans are CIDR-based, compare their
2651  * address bits; otherwise, use mmatch().
2652  * @param[in] old_ban One ban.
2653  * @param[in] new_ban Another ban.
2654  * @return Zero if \a old_ban is a superset of \a new_ban, non-zero otherwise.
2655  */
2656 static int
2657 bmatch(struct Ban *old_ban, struct Ban *new_ban)
2658 {
2659   int res;
2660   assert(old_ban != NULL);
2661   assert(new_ban != NULL);
2662   /* A ban is never treated as a superset of an exception. */
2663   if (!(old_ban->flags & BAN_EXCEPTION)
2664       && (new_ban->flags & BAN_EXCEPTION))
2665     return 1;
2666   /* If either is not an address mask, match the text masks. */
2667   if ((old_ban->flags & new_ban->flags & BAN_IPMASK) == 0)
2668     return mmatch(old_ban->banstr, new_ban->banstr);
2669   /* If the old ban has a longer prefix than new, it cannot be a superset. */
2670   if (old_ban->addrbits > new_ban->addrbits)
2671     return 1;
2672   /* Compare the masks before the hostname part.  */
2673   old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '\0';
2674   res = mmatch(old_ban->banstr, new_ban->banstr);
2675   old_ban->banstr[old_ban->nu_len] = new_ban->banstr[new_ban->nu_len] = '@';
2676   if (res)
2677     return res;
2678   /* Compare the addresses. */
2679   return !ipmask_check(&new_ban->address, &old_ban->address, old_ban->addrbits);
2680 }
2681
2682 /** Add a ban from a ban list and mark bans that should be removed
2683  * because they overlap.
2684  *
2685  * There are three invariants for a ban list.  First, no ban may be
2686  * more specific than another ban.  Second, no exception may be more
2687  * specific than another exception.  Finally, no ban may be more
2688  * specific than any exception.
2689  *
2690  * @param[in,out] banlist Pointer to head of list.
2691  * @param[in] newban Ban (or exception) to add (or remove).
2692  * @return Zero if \a newban could be applied, non-zero if not.
2693  */
2694 int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
2695 {
2696   struct Ban *ban;
2697   size_t count = 0;
2698
2699   assert(newban->flags & (BAN_ADD|BAN_DEL));
2700   if (newban->flags & BAN_ADD) {
2701     size_t totlen = 0;
2702     /* If a less specific entry is found, fail.  */
2703     for (ban = *banlist; ban; ban = ban->next) {
2704       if (!bmatch(ban, newban)) {
2705         if (do_free)
2706           free_ban(newban);
2707         return 1;
2708       }
2709       if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
2710         count++;
2711         totlen += strlen(ban->banstr);
2712       }
2713     }
2714     /* Mark more specific entries and add this one to the end of the list. */
2715     while ((ban = *banlist) != NULL) {
2716       if (!bmatch(newban, ban)) {
2717         ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2718       }
2719       banlist = &ban->next;
2720     }
2721     *banlist = newban;
2722     return 0;
2723   } else if (newban->flags & BAN_DEL) {
2724     size_t remove_count = 0;
2725     /* Mark more specific entries. */
2726     for (ban = *banlist; ban; ban = ban->next) {
2727       if (!bmatch(newban, ban)) {
2728         ban->flags |= BAN_OVERLAPPED | BAN_DEL;
2729         remove_count++;
2730       }
2731     }
2732     if (remove_count)
2733         return 0;
2734     /* If no matches were found, fail. */
2735     if (do_free)
2736       free_ban(newban);
2737     else
2738       MyFree(newban->banstr);
2739     return 3;
2740   }
2741   if (do_free)
2742     free_ban(newban);
2743   return 4;
2744 }
2745
2746 /*
2747  * Helper function to convert bans
2748  */
2749 static void
2750 mode_parse_ban(struct ParseState *state, int *flag_p)
2751 {
2752   char *t_str, *s;
2753   struct Ban *ban, *newban;
2754
2755   if (state->parc <= 0) { /* Not enough args, send ban list */
2756     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2757       send_ban_list(state->sptr, state->chptr);
2758       state->done |= DONE_BANLIST;
2759     }
2760
2761     return;
2762   }
2763
2764   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2765     return;
2766
2767   t_str = state->parv[state->args_used++]; /* grab arg */
2768   state->parc--;
2769   state->max_args--;
2770
2771   /* If they're not an oper, they can't change modes */
2772   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2773     send_notoper(state);
2774     return;
2775   }
2776
2777   if ((s = strchr(t_str, ' ')))
2778     *s = '\0';
2779
2780   if (!*t_str || *t_str == ':') { /* warn if empty */
2781     if (MyUser(state->sptr))
2782       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2783                        "MODE -b");
2784     return;
2785   }
2786
2787   /* Clear all ADD/DEL/OVERLAPPED flags from ban list. */
2788   if (!(state->done & DONE_BANCLEAN)) {
2789     for (ban = state->chptr->banlist; ban; ban = ban->next)
2790       ban->flags &= ~(BAN_ADD | BAN_DEL | BAN_OVERLAPPED);
2791     state->done |= DONE_BANCLEAN;
2792   }
2793
2794   /* remember the ban for the moment... */
2795   newban = state->banlist + (state->numbans++);
2796   newban->next = 0;
2797   newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
2798       | (*flag_p == 'b' ? 0 : BAN_EXCEPTION);
2799   newban->banstr = NULL;
2800   set_ban_mask(newban, collapse(pretty_mask(t_str)));
2801   newban->who = cli_name(state->sptr);
2802   newban->when = TStime();
2803   apply_ban(&state->chptr->banlist, newban, 0);
2804 }
2805
2806 /*
2807  * This is the bottom half of the ban processor
2808  */
2809 static void
2810 mode_process_bans(struct ParseState *state)
2811 {
2812   struct Ban *ban, *newban, *prevban, *nextban;
2813   int count = 0;
2814   int len = 0;
2815   int banlen;
2816   int changed = 0;
2817
2818   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2819     count++;
2820     banlen = strlen(ban->banstr);
2821     len += banlen;
2822     nextban = ban->next;
2823
2824     if ((ban->flags & (BAN_DEL | BAN_ADD)) == (BAN_DEL | BAN_ADD)) {
2825       if (prevban)
2826         prevban->next = 0; /* Break the list; ban isn't a real ban */
2827       else
2828         state->chptr->banlist = 0;
2829
2830       count--;
2831       len -= banlen;
2832
2833       MyFree(ban->banstr);
2834
2835       continue;
2836     } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
2837       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2838                           ban->banstr, 1);
2839
2840       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2841         if (prevban) /* clip it out of the list... */
2842           prevban->next = ban->next;
2843         else
2844           state->chptr->banlist = ban->next;
2845
2846         count--;
2847         len -= banlen;
2848
2849         ban->banstr = NULL; /* modebuf_mode_string() gave ownership of
2850                              * the ban string to state->mbuf */
2851         free_ban(ban);
2852
2853         changed++;
2854         continue; /* next ban; keep prevban like it is */
2855       } else
2856         ban->flags &= BAN_IPMASK; /* unset other flags */
2857     } else if (ban->flags & BAN_ADD) { /* adding a ban? */
2858       if (prevban)
2859         prevban->next = 0; /* Break the list; ban isn't a real ban */
2860       else
2861         state->chptr->banlist = 0;
2862
2863       /* If we're supposed to ignore it, do so. */
2864       if (ban->flags & BAN_OVERLAPPED &&
2865           !(state->flags & MODE_PARSE_BOUNCE)) {
2866         count--;
2867         len -= banlen;
2868         MyFree(ban->banstr);
2869       } else {
2870         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2871             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2872              count > feature_int(FEAT_MAXBANS))) {
2873           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2874                      ban->banstr);
2875           count--;
2876           len -= banlen;
2877           MyFree(ban->banstr);
2878         } else {
2879           /* add the ban to the buffer */
2880           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2881                               ban->banstr, 1);
2882
2883           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2884             newban = make_ban(ban->banstr);
2885             DupString(newban->who, ban->who);
2886             newban->when = ban->when;
2887             newban->flags = ban->flags & BAN_IPMASK;
2888
2889             newban->next = state->chptr->banlist; /* and link it in */
2890             state->chptr->banlist = newban;
2891
2892             changed++;
2893           }
2894         }
2895       }
2896     }
2897
2898     prevban = ban;
2899   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2900
2901   if (changed) /* if we changed the ban list, we must invalidate the bans */
2902     mode_ban_invalidate(state->chptr);
2903 }
2904
2905 /*
2906  * Helper function to process client changes
2907  */
2908 static void
2909 mode_parse_client(struct ParseState *state, int *flag_p)
2910 {
2911   char *t_str;
2912   struct Client *acptr;
2913   int i;
2914
2915   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2916     return;
2917
2918   if (state->parc <= 0) /* return if not enough args */
2919     return;
2920
2921   t_str = state->parv[state->args_used++]; /* grab arg */
2922   state->parc--;
2923   state->max_args--;
2924
2925   /* If they're not an oper, they can't change modes */
2926   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2927     send_notoper(state);
2928     return;
2929   }
2930
2931   if (MyUser(state->sptr)) /* find client we're manipulating */
2932     acptr = find_chasing(state->sptr, t_str, NULL);
2933   else
2934     acptr = findNUser(t_str);
2935
2936   if (!acptr)
2937     return; /* find_chasing() already reported an error to the user */
2938
2939   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2940     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2941                                        state->cli_change[i].flag & flag_p[0]))
2942       break; /* found a slot */
2943
2944   /* Store what we're doing to them */
2945   state->cli_change[i].flag = state->dir | flag_p[0];
2946   state->cli_change[i].client = acptr;
2947 }
2948
2949 /*
2950  * Helper function to process the changed client list
2951  */
2952 static void
2953 mode_process_clients(struct ParseState *state)
2954 {
2955   int i;
2956   struct Membership *member;
2957
2958   for (i = 0; state->cli_change[i].flag; i++) {
2959     assert(0 != state->cli_change[i].client);
2960
2961     /* look up member link */
2962     if (!(member = find_member_link(state->chptr,
2963                                     state->cli_change[i].client)) ||
2964         (MyUser(state->sptr) && IsZombie(member))) {
2965       if (MyUser(state->sptr))
2966         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2967                    cli_name(state->cli_change[i].client),
2968                    state->chptr->chname);
2969       continue;
2970     }
2971
2972     if ((state->cli_change[i].flag & MODE_ADD &&
2973          (state->cli_change[i].flag & member->status)) ||
2974         (state->cli_change[i].flag & MODE_DEL &&
2975          !(state->cli_change[i].flag & member->status)))
2976       continue; /* no change made, don't do anything */
2977
2978     /* see if the deop is allowed */
2979     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2980         (MODE_DEL | MODE_CHANOP)) {
2981       /* prevent +k users from being deopped */
2982       if (IsChannelService(state->cli_change[i].client)) {
2983         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2984           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2985                                state->chptr,
2986                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2987                                 cli_name((cli_user(state->sptr))->server)));
2988
2989         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2990           send_reply(state->sptr, ERR_ISCHANSERVICE,
2991                      cli_name(state->cli_change[i].client),
2992                      state->chptr->chname);
2993           continue;
2994         }
2995       }
2996
2997       /* check deop for local user */
2998       if (MyUser(state->sptr)) {
2999
3000         /* don't allow local opers to be deopped on local channels */
3001         if (state->cli_change[i].client != state->sptr &&
3002             IsLocalChannel(state->chptr->chname) &&
3003             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
3004           send_reply(state->sptr, ERR_ISOPERLCHAN,
3005                      cli_name(state->cli_change[i].client),
3006                      state->chptr->chname);
3007           continue;
3008         }
3009
3010         if (feature_bool(FEAT_OPLEVELS)) {
3011         /* don't allow to deop members with an op level that is <= our own level */
3012         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
3013                 && state->member
3014                 && OpLevel(member) <= OpLevel(state->member)) {
3015             int equal = (OpLevel(member) == OpLevel(state->member));
3016             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
3017                        cli_name(state->cli_change[i].client),
3018                        state->chptr->chname,
3019                        OpLevel(state->member), OpLevel(member),
3020                        "deop", equal ? "the same" : "a higher");
3021           continue;
3022         }
3023       }
3024     }
3025     }
3026
3027     /* set op-level of member being opped */
3028     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
3029         (MODE_ADD | MODE_CHANOP)) {
3030       /* If on a channel with upass set, someone with level x gives ops to someone else,
3031          then that person gets level x-1.  On other channels, where upass is not set,
3032          the level stays the same. */
3033       int level_increment = *state->chptr->mode.upass ? 1 : 0;
3034       /* Someone being opped by a server gets op-level 0 */
3035       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
3036       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
3037     }
3038
3039     /* actually effect the change */
3040     if (state->flags & MODE_PARSE_SET) {
3041       if (state->cli_change[i].flag & MODE_ADD) {
3042         if (IsDelayedJoin(member))
3043           RevealDelayedJoin(member);
3044         member->status |= (state->cli_change[i].flag &
3045                            (MODE_CHANOP | MODE_VOICE));
3046         if (state->cli_change[i].flag & MODE_CHANOP)
3047           ClearDeopped(member);
3048       } else
3049         member->status &= ~(state->cli_change[i].flag &
3050                             (MODE_CHANOP | MODE_VOICE));
3051     }
3052
3053     /* accumulate the change */
3054     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
3055                         state->cli_change[i].client);
3056   } /* for (i = 0; state->cli_change[i].flags; i++) */
3057 }
3058
3059 /*
3060  * Helper function to process the simple modes
3061  */
3062 static void
3063 mode_parse_mode(struct ParseState *state, int *flag_p)
3064 {
3065   /* If they're not an oper, they can't change modes */
3066   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
3067     send_notoper(state);
3068     return;
3069   }
3070
3071   if (!state->mbuf)
3072     return;
3073
3074   if (state->dir == MODE_ADD) {
3075     state->add |= flag_p[0];
3076     state->del &= ~flag_p[0];
3077
3078     if (flag_p[0] & MODE_SECRET) {
3079       state->add &= ~MODE_PRIVATE;
3080       state->del |= MODE_PRIVATE;
3081     } else if (flag_p[0] & MODE_PRIVATE) {
3082       state->add &= ~MODE_SECRET;
3083       state->del |= MODE_SECRET;
3084     }
3085     if (flag_p[0] & MODE_DELJOINS) {
3086       state->add &= ~MODE_WASDELJOINS;
3087       state->del |= MODE_WASDELJOINS;
3088     }
3089   } else {
3090     state->add &= ~flag_p[0];
3091     state->del |= flag_p[0];
3092   }
3093
3094   assert(0 == (state->add & state->del));
3095   assert((MODE_SECRET | MODE_PRIVATE) !=
3096          (state->add & (MODE_SECRET | MODE_PRIVATE)));
3097 }
3098
3099 /*
3100  * This routine is intended to parse MODE or OPMODE commands and effect the
3101  * changes (or just build the bounce buffer).  We pass the starting offset
3102  * as a 
3103  */
3104 int
3105 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
3106            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
3107            struct Membership* member)
3108 {
3109   static int chan_flags[] = {
3110     MODE_CHANOP,        'o',
3111     MODE_VOICE,         'v',
3112     MODE_PRIVATE,       'p',
3113     MODE_SECRET,        's',
3114     MODE_MODERATED,     'm',
3115     MODE_TOPICLIMIT,    't',
3116     MODE_INVITEONLY,    'i',
3117     MODE_NOPRIVMSGS,    'n',
3118     MODE_KEY,           'k',
3119     MODE_APASS,         'A',
3120     MODE_UPASS,         'U',
3121     MODE_BAN,           'b',
3122     MODE_LIMIT,         'l',
3123     MODE_REGONLY,       'r',
3124     MODE_DELJOINS,      'D',
3125     MODE_ADD,           '+',
3126     MODE_DEL,           '-',
3127     0x0, 0x0
3128   };
3129   int i;
3130   int *flag_p;
3131   unsigned int t_mode;
3132   char *modestr;
3133   struct ParseState state;
3134
3135   assert(0 != cptr);
3136   assert(0 != sptr);
3137   assert(0 != chptr);
3138   assert(0 != parc);
3139   assert(0 != parv);
3140
3141   state.mbuf = mbuf;
3142   state.cptr = cptr;
3143   state.sptr = sptr;
3144   state.chptr = chptr;
3145   state.member = member;
3146   state.parc = parc;
3147   state.parv = parv;
3148   state.flags = flags;
3149   state.dir = MODE_ADD;
3150   state.done = 0;
3151   state.add = 0;
3152   state.del = 0;
3153   state.args_used = 0;
3154   state.max_args = MAXMODEPARAMS;
3155   state.numbans = 0;
3156
3157   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
3158     state.banlist[i].next = 0;
3159     state.banlist[i].who = 0;
3160     state.banlist[i].when = 0;
3161     state.banlist[i].flags = 0;
3162     state.cli_change[i].flag = 0;
3163     state.cli_change[i].client = 0;
3164   }
3165
3166   modestr = state.parv[state.args_used++];
3167   state.parc--;
3168
3169   while (*modestr) {
3170     for (; *modestr; modestr++) {
3171       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
3172         if (flag_p[1] == *modestr)
3173           break;
3174
3175       if (!flag_p[0]) { /* didn't find it?  complain and continue */
3176         if (MyUser(state.sptr))
3177           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
3178         continue;
3179       }
3180
3181       switch (*modestr) {
3182       case '+': /* switch direction to MODE_ADD */
3183       case '-': /* switch direction to MODE_DEL */
3184         state.dir = flag_p[0];
3185         break;
3186
3187       case 'l': /* deal with limits */
3188         mode_parse_limit(&state, flag_p);
3189         break;
3190
3191       case 'k': /* deal with keys */
3192         mode_parse_key(&state, flag_p);
3193         break;
3194
3195       case 'A': /* deal with Admin passes */
3196         if (feature_bool(FEAT_OPLEVELS))
3197         mode_parse_apass(&state, flag_p);
3198         break;
3199
3200       case 'U': /* deal with user passes */
3201         if (feature_bool(FEAT_OPLEVELS))
3202         mode_parse_upass(&state, flag_p);
3203         break;
3204
3205       case 'b': /* deal with bans */
3206         mode_parse_ban(&state, flag_p);
3207         break;
3208
3209       case 'o': /* deal with ops/voice */
3210       case 'v':
3211         mode_parse_client(&state, flag_p);
3212         break;
3213
3214       default: /* deal with other modes */
3215         mode_parse_mode(&state, flag_p);
3216         break;
3217       } /* switch (*modestr) */
3218     } /* for (; *modestr; modestr++) */
3219
3220     if (state.flags & MODE_PARSE_BURST)
3221       break; /* don't interpret any more arguments */
3222
3223     if (state.parc > 0) { /* process next argument in string */
3224       modestr = state.parv[state.args_used++];
3225       state.parc--;
3226
3227       /* is it a TS? */
3228       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3229         time_t recv_ts;
3230
3231         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3232           break;                     /* we're then going to bounce the mode! */
3233
3234         recv_ts = atoi(modestr);
3235
3236         if (recv_ts && recv_ts < state.chptr->creationtime)
3237           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3238
3239         break; /* break out of while loop */
3240       } else if (state.flags & MODE_PARSE_STRICT ||
3241                  (MyUser(state.sptr) && state.max_args <= 0)) {
3242         state.parc++; /* we didn't actually gobble the argument */
3243         state.args_used--;
3244         break; /* break out of while loop */
3245       }
3246     }
3247   } /* while (*modestr) */
3248
3249   /*
3250    * the rest of the function finishes building resultant MODEs; if the
3251    * origin isn't a member or an oper, skip it.
3252    */
3253   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3254     return state.args_used; /* tell our parent how many args we gobbled */
3255
3256   t_mode = state.chptr->mode.mode;
3257
3258   if (state.del & t_mode) { /* delete any modes to be deleted... */
3259     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3260
3261     t_mode &= ~state.del;
3262   }
3263   if (state.add & ~t_mode) { /* add any modes to be added... */
3264     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3265
3266     t_mode |= state.add;
3267   }
3268
3269   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3270     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3271         !(t_mode & MODE_INVITEONLY))
3272       mode_invite_clear(state.chptr);
3273
3274     state.chptr->mode.mode = t_mode;
3275   }
3276
3277   if (state.flags & MODE_PARSE_WIPEOUT) {
3278     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3279       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3280                         state.chptr->mode.limit);
3281     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3282       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3283                           state.chptr->mode.key, 0);
3284     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3285       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3286                           state.chptr->mode.upass, 0);
3287     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3288       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3289                           state.chptr->mode.apass, 0);
3290   }
3291
3292   if (state.done & DONE_BANCLEAN) /* process bans */
3293     mode_process_bans(&state);
3294
3295   /* process client changes */
3296   if (state.cli_change[0].flag)
3297     mode_process_clients(&state);
3298
3299   return state.args_used; /* tell our parent how many args we gobbled */
3300 }
3301
3302 /*
3303  * Initialize a join buffer
3304  */
3305 void
3306 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3307              struct Client *connect, unsigned int type, char *comment,
3308              time_t create)
3309 {
3310   int i;
3311
3312   assert(0 != jbuf);
3313   assert(0 != source);
3314   assert(0 != connect);
3315
3316   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3317   jbuf->jb_connect = connect;
3318   jbuf->jb_type = type;
3319   jbuf->jb_comment = comment;
3320   jbuf->jb_create = create;
3321   jbuf->jb_count = 0;
3322   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3323                        type == JOINBUF_TYPE_PART ||
3324                        type == JOINBUF_TYPE_PARTALL) ?
3325                       STARTJOINLEN : STARTCREATELEN) +
3326                      (comment ? strlen(comment) + 2 : 0));
3327
3328   for (i = 0; i < MAXJOINARGS; i++)
3329     jbuf->jb_channels[i] = 0;
3330 }
3331
3332 /*
3333  * Add a channel to the join buffer
3334  */
3335 void
3336 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3337 {
3338   unsigned int len;
3339   int is_local;
3340
3341   assert(0 != jbuf);
3342
3343   if (!chan) {
3344     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3345       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3346
3347     return;
3348   }
3349
3350   is_local = IsLocalChannel(chan->chname);
3351
3352   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3353       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3354     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3355     if (IsUserParting(member))
3356       return;
3357     SetUserParting(member);
3358
3359     /* Send notification to channel */
3360     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
3361       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
3362                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3363                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3364     else if (MyUser(jbuf->jb_source))
3365       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3366                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3367                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3368     /* XXX: Shouldn't we send a PART here anyway? */
3369     /* to users on the channel?  Why?  From their POV, the user isn't on
3370      * the channel anymore anyway.  We don't send to servers until below,
3371      * when we gang all the channel parts together.  Note that this is
3372      * exactly the same logic, albeit somewhat more concise, as was in
3373      * the original m_part.c */
3374
3375     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3376         is_local) /* got to remove user here */
3377       remove_user_from_channel(jbuf->jb_source, chan);
3378   } else {
3379     /* Add user to channel */
3380     if ((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))
3381       add_user_to_channel(chan, jbuf->jb_source, flags | CHFL_DELAYED, 0);
3382     else
3383       add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3384
3385     /* send notification to all servers */
3386     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3387       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3388                             "%H %Tu", chan, chan->creationtime);
3389
3390     if (!((chan->mode.mode & MODE_DELJOINS) && !(flags & CHFL_VOICED_OR_OPPED))) {
3391       /* Send the notification to the channel */
3392       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, 0, "%H", chan);
3393
3394       /* send an op, too, if needed */
3395       if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3396         sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, 0, "%H +o %C",
3397                                          chan, jbuf->jb_source);
3398     } else if (MyUser(jbuf->jb_source))
3399       sendcmdto_one(jbuf->jb_source, CMD_JOIN, jbuf->jb_source, ":%H", chan);
3400   }
3401
3402   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3403       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3404     return; /* don't send to remote */
3405
3406   /* figure out if channel name will cause buffer to be overflowed */
3407   len = chan ? strlen(chan->chname) + 1 : 2;
3408   if (jbuf->jb_strlen + len > BUFSIZE)
3409     joinbuf_flush(jbuf);
3410
3411   /* add channel to list of channels to send and update counts */
3412   jbuf->jb_channels[jbuf->jb_count++] = chan;
3413   jbuf->jb_strlen += len;
3414
3415   /* if we've used up all slots, flush */
3416   if (jbuf->jb_count >= MAXJOINARGS)
3417     joinbuf_flush(jbuf);
3418 }
3419
3420 /*
3421  * Flush the channel list to remote servers
3422  */
3423 int
3424 joinbuf_flush(struct JoinBuf *jbuf)
3425 {
3426   char chanlist[BUFSIZE];
3427   int chanlist_i = 0;
3428   int i;
3429
3430   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3431       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3432     return 0; /* no joins to process */
3433
3434   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3435     build_string(chanlist, &chanlist_i,
3436                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3437                  i == 0 ? '\0' : ',');
3438     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3439       /* Remove user from channel */
3440       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3441
3442     jbuf->jb_channels[i] = 0; /* mark slot empty */
3443   }
3444
3445   jbuf->jb_count = 0; /* reset base counters */
3446   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3447                       STARTJOINLEN : STARTCREATELEN) +
3448                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3449
3450   /* and send the appropriate command */
3451   switch (jbuf->jb_type) {
3452   case JOINBUF_TYPE_CREATE:
3453     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3454                           "%s %Tu", chanlist, jbuf->jb_create);
3455     break;
3456
3457   case JOINBUF_TYPE_PART:
3458     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3459                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3460                           jbuf->jb_comment);
3461     break;
3462   }
3463
3464   return 0;
3465 }
3466
3467 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3468 int IsInvited(struct Client* cptr, const void* chptr)
3469 {
3470   struct SLink *lp;
3471
3472   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3473     if (lp->value.chptr == chptr)
3474       return 1;
3475   return 0;
3476 }
3477
3478 /* RevealDelayedJoin: sends a join for a hidden user */
3479
3480 void RevealDelayedJoin(struct Membership *member) {
3481   ClearDelayedJoin(member);
3482   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
3483                                    member->channel);
3484   CheckDelayedJoins(member->channel);
3485 }
3486
3487 /* CheckDelayedJoins: checks and clear +d if necessary */
3488
3489 void CheckDelayedJoins(struct Channel *chan) {
3490   struct Membership *memb2;
3491   
3492   if (chan->mode.mode & MODE_WASDELJOINS) {
3493     for (memb2=chan->members;memb2;memb2=memb2->next_member)
3494       if (IsDelayedJoin(memb2))
3495         break;
3496     
3497     if (!memb2) {
3498       /* clear +d */
3499       chan->mode.mode &= ~MODE_WASDELJOINS;
3500       sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan, NULL, 0,
3501                                        "%H -d", chan);
3502     }
3503   }
3504 }