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