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