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