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