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