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