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