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