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