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