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