Author: beware (by Spike)
[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   if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1860
1861   mbuf->mb_add = 0;
1862   mbuf->mb_rem = 0;
1863   mbuf->mb_source = source;
1864   mbuf->mb_connect = connect;
1865   mbuf->mb_channel = chan;
1866   mbuf->mb_dest = dest;
1867   mbuf->mb_count = 0;
1868
1869   /* clear each mode-with-parameter slot */
1870   for (i = 0; i < MAXMODEPARAMS; i++) {
1871     MB_TYPE(mbuf, i) = 0;
1872     MB_UINT(mbuf, i) = 0;
1873   }
1874 }
1875
1876 /*
1877  * This routine simply adds modes to be added or deleted; do a binary OR
1878  * with either MODE_ADD or MODE_DEL
1879  */
1880 void
1881 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1882 {
1883   assert(0 != mbuf);
1884   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1885
1886   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1887            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1888
1889   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1890     return;
1891
1892   if (mode & MODE_ADD) {
1893     mbuf->mb_rem &= ~mode;
1894     mbuf->mb_add |= mode;
1895   } else {
1896     mbuf->mb_add &= ~mode;
1897     mbuf->mb_rem |= mode;
1898   }
1899 }
1900
1901 /*
1902  * This routine adds a mode to be added or deleted that takes a unsigned
1903  * int parameter; mode may *only* be the relevant mode flag ORed with one
1904  * of MODE_ADD or MODE_DEL
1905  */
1906 void
1907 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1908 {
1909   assert(0 != mbuf);
1910   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1911
1912   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1913   MB_UINT(mbuf, mbuf->mb_count) = uint;
1914
1915   /* when we've reached the maximal count, flush the buffer */
1916   if (++mbuf->mb_count >=
1917       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1918     modebuf_flush_int(mbuf, 0);
1919 }
1920
1921 /*
1922  * This routine adds a mode to be added or deleted that takes a string
1923  * parameter; mode may *only* be the relevant mode flag ORed with one of
1924  * MODE_ADD or MODE_DEL
1925  */
1926 void
1927 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1928                     int free)
1929 {
1930   assert(0 != mbuf);
1931   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1932
1933   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1934   MB_STRING(mbuf, mbuf->mb_count) = string;
1935
1936   /* when we've reached the maximal count, flush the buffer */
1937   if (++mbuf->mb_count >=
1938       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1939     modebuf_flush_int(mbuf, 0);
1940 }
1941
1942 /*
1943  * This routine adds a mode to be added or deleted that takes a client
1944  * parameter; mode may *only* be the relevant mode flag ORed with one of
1945  * MODE_ADD or MODE_DEL
1946  */
1947 void
1948 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1949                     struct Client *client)
1950 {
1951   assert(0 != mbuf);
1952   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1953
1954   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1955   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1956
1957   /* when we've reached the maximal count, flush the buffer */
1958   if (++mbuf->mb_count >=
1959       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1960     modebuf_flush_int(mbuf, 0);
1961 }
1962
1963 /*
1964  * This is the exported binding for modebuf_flush()
1965  */
1966 int
1967 modebuf_flush(struct ModeBuf *mbuf)
1968 {
1969   return modebuf_flush_int(mbuf, 1);
1970 }
1971
1972 /*
1973  * This extracts the simple modes contained in mbuf
1974  */
1975 void
1976 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1977 {
1978   static int flags[] = {
1979 /*  MODE_CHANOP,        'o', */
1980 /*  MODE_VOICE,         'v', */
1981     MODE_PRIVATE,       'p',
1982     MODE_SECRET,        's',
1983     MODE_MODERATED,     'm',
1984     MODE_TOPICLIMIT,    't',
1985     MODE_INVITEONLY,    'i',
1986     MODE_NOPRIVMSGS,    'n',
1987     MODE_KEY,           'k',
1988     MODE_APASS,         'A',
1989     MODE_UPASS,         'u',
1990 /*  MODE_BAN,           'b', */
1991     MODE_LIMIT,         'l',
1992     MODE_REGONLY,       'r',
1993     0x0, 0x0
1994   };
1995   unsigned int add;
1996   int i, bufpos = 0, len;
1997   int *flag_p;
1998   char *key = 0, limitbuf[20];
1999   char *apass = 0, *upass = 0;
2000
2001   assert(0 != mbuf);
2002   assert(0 != buf);
2003
2004   buf[0] = '\0';
2005
2006   add = mbuf->mb_add;
2007
2008   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2009     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2010       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2011
2012       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2013         key = MB_STRING(mbuf, i);
2014       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2015         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2016       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2017         upass = MB_STRING(mbuf, i);
2018       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2019         apass = MB_STRING(mbuf, i);
2020     }
2021   }
2022
2023   if (!add)
2024     return;
2025
2026   buf[bufpos++] = '+'; /* start building buffer */
2027
2028   for (flag_p = flags; flag_p[0]; flag_p += 2)
2029     if (*flag_p & add)
2030       buf[bufpos++] = flag_p[1];
2031
2032   for (i = 0, len = bufpos; i < len; i++) {
2033     if (buf[i] == 'k')
2034       build_string(buf, &bufpos, key, 0, ' ');
2035     else if (buf[i] == 'l')
2036       build_string(buf, &bufpos, limitbuf, 0, ' ');
2037     else if (buf[i] == 'u')
2038       build_string(buf, &bufpos, upass, 0, ' ');
2039     else if (buf[i] == 'A')
2040       build_string(buf, &bufpos, apass, 0, ' ');
2041   }
2042
2043   buf[bufpos] = '\0';
2044
2045   return;
2046 }
2047
2048 /*
2049  * Simple function to invalidate bans
2050  */
2051 void
2052 mode_ban_invalidate(struct Channel *chan)
2053 {
2054   struct Membership *member;
2055
2056   for (member = chan->members; member; member = member->next_member)
2057     ClearBanValid(member);
2058 }
2059
2060 /*
2061  * Simple function to drop invite structures
2062  */
2063 void
2064 mode_invite_clear(struct Channel *chan)
2065 {
2066   while (chan->invites)
2067     del_invite(chan->invites->value.cptr, chan);
2068 }
2069
2070 /* What we've done for mode_parse so far... */
2071 #define DONE_LIMIT      0x01    /* We've set the limit */
2072 #define DONE_KEY        0x02    /* We've set the key */
2073 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2074 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2075 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2076 #define DONE_UPASS      0x20    /* We've set user pass */
2077 #define DONE_APASS      0x40    /* We've set admin pass */
2078
2079 struct ParseState {
2080   struct ModeBuf *mbuf;
2081   struct Client *cptr;
2082   struct Client *sptr;
2083   struct Channel *chptr;
2084   struct Membership *member;
2085   int parc;
2086   char **parv;
2087   unsigned int flags;
2088   unsigned int dir;
2089   unsigned int done;
2090   unsigned int add;
2091   unsigned int del;
2092   int args_used;
2093   int max_args;
2094   int numbans;
2095   struct SLink banlist[MAXPARA];
2096   struct {
2097     unsigned int flag;
2098     struct Client *client;
2099   } cli_change[MAXPARA];
2100 };
2101
2102 /*
2103  * Here's a helper function to deal with sending along "Not oper" or
2104  * "Not member" messages
2105  */
2106 static void
2107 send_notoper(struct ParseState *state)
2108 {
2109   if (state->done & DONE_NOTOPER)
2110     return;
2111
2112   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2113              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2114
2115   state->done |= DONE_NOTOPER;
2116 }
2117
2118 /*
2119  * Helper function to convert limits
2120  */
2121 static void
2122 mode_parse_limit(struct ParseState *state, int *flag_p)
2123 {
2124   unsigned int t_limit;
2125
2126   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2127     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2128       return;
2129
2130     if (state->parc <= 0) { /* warn if not enough args */
2131       if (MyUser(state->sptr))
2132         need_more_params(state->sptr, "MODE +l");
2133       return;
2134     }
2135
2136     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2137     state->parc--;
2138     state->max_args--;
2139
2140     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2141         (!t_limit || t_limit == state->chptr->mode.limit))
2142       return;
2143   } else
2144     t_limit = state->chptr->mode.limit;
2145
2146   /* If they're not an oper, they can't change modes */
2147   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2148     send_notoper(state);
2149     return;
2150   }
2151
2152   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2153     return;
2154   state->done |= DONE_LIMIT;
2155
2156   if (!state->mbuf)
2157     return;
2158
2159   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2160
2161   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2162     if (state->dir & MODE_ADD) {
2163       state->chptr->mode.mode |= flag_p[0];
2164       state->chptr->mode.limit = t_limit;
2165     } else {
2166       state->chptr->mode.mode &= ~flag_p[0];
2167       state->chptr->mode.limit = 0;
2168     }
2169   }
2170 }
2171
2172 /*
2173  * Helper function to convert keys
2174  */
2175 static void
2176 mode_parse_key(struct ParseState *state, int *flag_p)
2177 {
2178   char *t_str, *s;
2179   int t_len;
2180
2181   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2182     return;
2183
2184   if (state->parc <= 0) { /* warn if not enough args */
2185     if (MyUser(state->sptr))
2186       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2187                        "MODE -k");
2188     return;
2189   }
2190
2191   t_str = state->parv[state->args_used++]; /* grab arg */
2192   state->parc--;
2193   state->max_args--;
2194
2195   /* If they're not an oper, they can't change modes */
2196   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2197     send_notoper(state);
2198     return;
2199   }
2200
2201   if (state->done & DONE_KEY) /* allow key to be set only once */
2202     return;
2203   state->done |= DONE_KEY;
2204
2205   t_len = KEYLEN;
2206
2207   /* clean up the key string */
2208   s = t_str;
2209   while (*++s > ' ' && *s != ':' && --t_len)
2210     ;
2211   *s = '\0';
2212
2213   if (!*t_str) { /* warn if empty */
2214     if (MyUser(state->sptr))
2215       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2216                        "MODE -k");
2217     return;
2218   }
2219
2220   if (!state->mbuf)
2221     return;
2222
2223   /* can't add a key if one is set, nor can one remove the wrong key */
2224   if (!(state->flags & MODE_PARSE_FORCE))
2225     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2226         (state->dir == MODE_DEL &&
2227          ircd_strcmp(state->chptr->mode.key, t_str))) {
2228       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2229       return;
2230     }
2231
2232   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2233       !ircd_strcmp(state->chptr->mode.key, t_str))
2234     return; /* no key change */
2235
2236   if (state->flags & MODE_PARSE_BOUNCE) {
2237     if (*state->chptr->mode.key) /* reset old key */
2238       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2239                           state->chptr->mode.key, 0);
2240     else /* remove new bogus key */
2241       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2242   } else /* send new key */
2243     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2244
2245   if (state->flags & MODE_PARSE_SET) {
2246     if (state->dir == MODE_ADD) /* set the new key */
2247       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2248     else /* remove the old key */
2249       *state->chptr->mode.key = '\0';
2250   }
2251 }
2252
2253 /*
2254  * Helper function to convert user passes
2255  */
2256 static void
2257 mode_parse_upass(struct ParseState *state, int *flag_p)
2258 {
2259   char *t_str, *s;
2260   int t_len;
2261
2262   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2263     return;
2264
2265   if (state->parc <= 0) { /* warn if not enough args */
2266     if (MyUser(state->sptr))
2267       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2268                        "MODE -u");
2269     return;
2270   }
2271
2272   t_str = state->parv[state->args_used++]; /* grab arg */
2273   state->parc--;
2274   state->max_args--;
2275
2276   /* If they're not an oper, they can't change modes */
2277   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2278     send_notoper(state);
2279     return;
2280   }
2281
2282   /* If they are not the channel manager, they are not allowed to change it */
2283   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2284     if (*state->chptr->mode.apass) {
2285       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2286           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2287     } else {
2288       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2289           "Re-create the channel.  The channel must be *empty* for",
2290           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2291           "before it can be recreated.");
2292     }
2293     return;
2294   }
2295  
2296   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2297     return;
2298   state->done |= DONE_UPASS;
2299
2300   t_len = PASSLEN + 1;
2301
2302   /* clean up the upass string */
2303   s = t_str;
2304   while (*++s > ' ' && *s != ':' && --t_len)
2305     ;
2306   *s = '\0';
2307
2308   if (!*t_str) { /* warn if empty */
2309     if (MyUser(state->sptr))
2310       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2311                        "MODE -u");
2312     return;
2313   }
2314
2315   if (!state->mbuf)
2316     return;
2317
2318   if (!(state->flags & MODE_PARSE_FORCE))
2319     /* can't add the upass while apass is not set */
2320     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2321       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2322       return;
2323     }
2324     /* can't add a upass if one is set, nor can one remove the wrong upass */
2325     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2326         (state->dir == MODE_DEL &&
2327          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2328       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2329       return;
2330     }
2331
2332   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2333       !ircd_strcmp(state->chptr->mode.upass, t_str))
2334     return; /* no upass change */
2335
2336   if (state->flags & MODE_PARSE_BOUNCE) {
2337     if (*state->chptr->mode.upass) /* reset old upass */
2338       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2339                           state->chptr->mode.upass, 0);
2340     else /* remove new bogus upass */
2341       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2342   } else /* send new upass */
2343     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2344
2345   if (state->flags & MODE_PARSE_SET) {
2346     if (state->dir == MODE_ADD) /* set the new upass */
2347       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2348     else /* remove the old upass */
2349       *state->chptr->mode.upass = '\0';
2350   }
2351 }
2352
2353 /*
2354  * Helper function to convert admin passes
2355  */
2356 static void
2357 mode_parse_apass(struct ParseState *state, int *flag_p)
2358 {
2359   char *t_str, *s;
2360   int t_len;
2361
2362   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2363     return;
2364
2365   if (state->parc <= 0) { /* warn if not enough args */
2366     if (MyUser(state->sptr))
2367       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2368                        "MODE -A");
2369     return;
2370   }
2371
2372   t_str = state->parv[state->args_used++]; /* grab arg */
2373   state->parc--;
2374   state->max_args--;
2375
2376   /* If they're not an oper, they can't change modes */
2377   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2378     send_notoper(state);
2379     return;
2380   }
2381
2382   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2383   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2384     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2385     return;
2386   }
2387
2388   /* If they are not the channel manager, they are not allowed to change it */
2389   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2390     if (*state->chptr->mode.apass) {
2391       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2392           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2393     } else {
2394       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2395           "Re-create the channel.  The channel must be *empty* for",
2396           "at least a whole minute", "before it can be recreated.");
2397     }
2398     return;
2399   }
2400  
2401   if (state->done & DONE_APASS) /* allow apass to be set only once */
2402     return;
2403   state->done |= DONE_APASS;
2404
2405   t_len = PASSLEN + 1;
2406
2407   /* clean up the apass string */
2408   s = t_str;
2409   while (*++s > ' ' && *s != ':' && --t_len)
2410     ;
2411   *s = '\0';
2412
2413   if (!*t_str) { /* warn if empty */
2414     if (MyUser(state->sptr))
2415       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2416                        "MODE -A");
2417     return;
2418   }
2419
2420   if (!state->mbuf)
2421     return;
2422
2423   if (!(state->flags & MODE_PARSE_FORCE)) {
2424     /* can't remove the apass while upass is still set */
2425     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2426       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2427       return;
2428     }
2429     /* can't add an apass if one is set, nor can one remove the wrong apass */
2430     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2431         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2432       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2433       return;
2434     }
2435   }
2436
2437   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2438       !ircd_strcmp(state->chptr->mode.apass, t_str))
2439     return; /* no apass change */
2440
2441   if (state->flags & MODE_PARSE_BOUNCE) {
2442     if (*state->chptr->mode.apass) /* reset old apass */
2443       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2444                           state->chptr->mode.apass, 0);
2445     else /* remove new bogus apass */
2446       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2447   } else /* send new apass */
2448     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2449
2450   if (state->flags & MODE_PARSE_SET) {
2451     if (state->dir == MODE_ADD) { /* set the new apass */
2452       /* Make it VERY clear to the user that this is a one-time password */
2453       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2454       if (MyUser(state->sptr)) {
2455         send_reply(state->sptr, RPL_APASSWARN,
2456             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2457             "Are you SURE you want to use this as Admin password? ",
2458             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2459         send_reply(state->sptr, RPL_APASSWARN,
2460             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2461             "\" to remove the password and then immediately set a new one. "
2462             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2463             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2464             "Now set the channel user password (+u).");
2465       }
2466     } else { /* remove the old apass */
2467       *state->chptr->mode.apass = '\0';
2468       if (MyUser(state->sptr))
2469         send_reply(state->sptr, RPL_APASSWARN,
2470             "WARNING: You removed the channel Admin password MODE (+A). ",
2471             "If you would disconnect or leave the channel without setting a new password then you will ",
2472             "not be able to set it again and lose ownership of this channel! ",
2473             "SET A NEW PASSWORD NOW!", "");
2474     }
2475   }
2476 }
2477
2478 /*
2479  * Helper function to convert bans
2480  */
2481 static void
2482 mode_parse_ban(struct ParseState *state, int *flag_p)
2483 {
2484   char *t_str, *s;
2485   struct SLink *ban, *newban = 0;
2486
2487   if (state->parc <= 0) { /* Not enough args, send ban list */
2488     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2489       send_ban_list(state->sptr, state->chptr);
2490       state->done |= DONE_BANLIST;
2491     }
2492
2493     return;
2494   }
2495
2496   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2497     return;
2498
2499   t_str = state->parv[state->args_used++]; /* grab arg */
2500   state->parc--;
2501   state->max_args--;
2502
2503   /* If they're not an oper, they can't change modes */
2504   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2505     send_notoper(state);
2506     return;
2507   }
2508
2509   if ((s = strchr(t_str, ' ')))
2510     *s = '\0';
2511
2512   if (!*t_str || *t_str == ':') { /* warn if empty */
2513     if (MyUser(state->sptr))
2514       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2515                        "MODE -b");
2516     return;
2517   }
2518
2519   t_str = collapse(pretty_mask(t_str));
2520
2521   /* remember the ban for the moment... */
2522   if (state->dir == MODE_ADD) {
2523     newban = state->banlist + (state->numbans++);
2524     newban->next = 0;
2525
2526     DupString(newban->value.ban.banstr, t_str);
2527     newban->value.ban.who = cli_name(state->sptr);
2528     newban->value.ban.when = TStime();
2529
2530     newban->flags = CHFL_BAN | MODE_ADD;
2531
2532     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2533       newban->flags |= CHFL_BAN_IPMASK;
2534   }
2535
2536   if (!state->chptr->banlist) {
2537     state->chptr->banlist = newban; /* add our ban with its flags */
2538     state->done |= DONE_BANCLEAN;
2539     return;
2540   }
2541
2542   /* Go through all bans */
2543   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2544     /* first, clean the ban flags up a bit */
2545     if (!(state->done & DONE_BANCLEAN))
2546       /* Note: We're overloading *lots* of bits here; be careful! */
2547       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2548
2549     /* Bit meanings:
2550      *
2551      * MODE_ADD            - Ban was added; if we're bouncing modes,
2552      *                       then we'll remove it below; otherwise,
2553      *                       we'll have to allocate a real ban
2554      *
2555      * MODE_DEL            - Ban was marked for deletion; if we're
2556      *                       bouncing modes, we'll have to re-add it,
2557      *                       otherwise, we'll have to remove it
2558      *
2559      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2560      *                       with a ban already set; if we're
2561      *                       bouncing modes, we'll have to bounce
2562      *                       this one; otherwise, we'll just ignore
2563      *                       it when we process added bans
2564      */
2565
2566     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2567       ban->flags |= MODE_DEL; /* delete one ban */
2568
2569       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2570         break;
2571     } else if (state->dir == MODE_ADD) {
2572       /* if the ban already exists, don't worry about it */
2573       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2574         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2575         MyFree(newban->value.ban.banstr); /* stopper a leak */
2576         state->numbans--; /* deallocate last ban */
2577         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2578           break;
2579       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2580         if (!(ban->flags & MODE_DEL))
2581           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2582       } else if (!mmatch(t_str, ban->value.ban.banstr))
2583         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2584
2585       if (!ban->next && (newban->flags & MODE_ADD))
2586       {
2587         ban->next = newban; /* add our ban with its flags */
2588         break; /* get out of loop */
2589       }
2590     }
2591   }
2592   state->done |= DONE_BANCLEAN;
2593 }
2594
2595 /*
2596  * This is the bottom half of the ban processor
2597  */
2598 static void
2599 mode_process_bans(struct ParseState *state)
2600 {
2601   struct SLink *ban, *newban, *prevban, *nextban;
2602   int count = 0;
2603   int len = 0;
2604   int banlen;
2605   int changed = 0;
2606
2607   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2608     count++;
2609     banlen = strlen(ban->value.ban.banstr);
2610     len += banlen;
2611     nextban = ban->next;
2612
2613     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2614       if (prevban)
2615         prevban->next = 0; /* Break the list; ban isn't a real ban */
2616       else
2617         state->chptr->banlist = 0;
2618
2619       count--;
2620       len -= banlen;
2621
2622       MyFree(ban->value.ban.banstr);
2623
2624       continue;
2625     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2626       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2627                           ban->value.ban.banstr,
2628                           state->flags & MODE_PARSE_SET);
2629
2630       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2631         if (prevban) /* clip it out of the list... */
2632           prevban->next = ban->next;
2633         else
2634           state->chptr->banlist = ban->next;
2635
2636         count--;
2637         len -= banlen;
2638
2639         MyFree(ban->value.ban.who);
2640         free_link(ban);
2641
2642         changed++;
2643         continue; /* next ban; keep prevban like it is */
2644       } else
2645         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2646     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2647       if (prevban)
2648         prevban->next = 0; /* Break the list; ban isn't a real ban */
2649       else
2650         state->chptr->banlist = 0;
2651
2652       /* If we're supposed to ignore it, do so. */
2653       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2654           !(state->flags & MODE_PARSE_BOUNCE)) {
2655         count--;
2656         len -= banlen;
2657
2658         MyFree(ban->value.ban.banstr);
2659       } else {
2660         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2661             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2662              count > feature_int(FEAT_MAXBANS))) {
2663           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2664                      ban->value.ban.banstr);
2665           count--;
2666           len -= banlen;
2667
2668           MyFree(ban->value.ban.banstr);
2669         } else {
2670           /* add the ban to the buffer */
2671           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2672                               ban->value.ban.banstr,
2673                               !(state->flags & MODE_PARSE_SET));
2674
2675           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2676             newban = make_link();
2677             newban->value.ban.banstr = ban->value.ban.banstr;
2678             DupString(newban->value.ban.who, ban->value.ban.who);
2679             newban->value.ban.when = ban->value.ban.when;
2680             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2681
2682             newban->next = state->chptr->banlist; /* and link it in */
2683             state->chptr->banlist = newban;
2684
2685             changed++;
2686           }
2687         }
2688       }
2689     }
2690
2691     prevban = ban;
2692   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2693
2694   if (changed) /* if we changed the ban list, we must invalidate the bans */
2695     mode_ban_invalidate(state->chptr);
2696 }
2697
2698 /*
2699  * Helper function to process client changes
2700  */
2701 static void
2702 mode_parse_client(struct ParseState *state, int *flag_p)
2703 {
2704   char *t_str;
2705   struct Client *acptr;
2706   int i;
2707
2708   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2709     return;
2710
2711   if (state->parc <= 0) /* return if not enough args */
2712     return;
2713
2714   t_str = state->parv[state->args_used++]; /* grab arg */
2715   state->parc--;
2716   state->max_args--;
2717
2718   /* If they're not an oper, they can't change modes */
2719   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2720     send_notoper(state);
2721     return;
2722   }
2723
2724   if (MyUser(state->sptr)) /* find client we're manipulating */
2725     acptr = find_chasing(state->sptr, t_str, NULL);
2726   else
2727     acptr = findNUser(t_str);
2728
2729   if (!acptr)
2730     return; /* find_chasing() already reported an error to the user */
2731
2732   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2733     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2734                                        state->cli_change[i].flag & flag_p[0]))
2735       break; /* found a slot */
2736
2737   /* Store what we're doing to them */
2738   state->cli_change[i].flag = state->dir | flag_p[0];
2739   state->cli_change[i].client = acptr;
2740 }
2741
2742 /*
2743  * Helper function to process the changed client list
2744  */
2745 static void
2746 mode_process_clients(struct ParseState *state)
2747 {
2748   int i;
2749   struct Membership *member;
2750
2751   for (i = 0; state->cli_change[i].flag; i++) {
2752     assert(0 != state->cli_change[i].client);
2753
2754     /* look up member link */
2755     if (!(member = find_member_link(state->chptr,
2756                                     state->cli_change[i].client)) ||
2757         (MyUser(state->sptr) && IsZombie(member))) {
2758       if (MyUser(state->sptr))
2759         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2760                    cli_name(state->cli_change[i].client),
2761                    state->chptr->chname);
2762       continue;
2763     }
2764
2765     if ((state->cli_change[i].flag & MODE_ADD &&
2766          (state->cli_change[i].flag & member->status)) ||
2767         (state->cli_change[i].flag & MODE_DEL &&
2768          !(state->cli_change[i].flag & member->status)))
2769       continue; /* no change made, don't do anything */
2770
2771     /* see if the deop is allowed */
2772     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2773         (MODE_DEL | MODE_CHANOP)) {
2774       /* prevent +k users from being deopped */
2775       if (IsChannelService(state->cli_change[i].client)) {
2776         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2777           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2778                                state->chptr,
2779                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2780                                 cli_name((cli_user(state->sptr))->server)));
2781
2782         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2783           send_reply(state->sptr, ERR_ISCHANSERVICE,
2784                      cli_name(state->cli_change[i].client),
2785                      state->chptr->chname);
2786           continue;
2787         }
2788       }
2789
2790       /* check deop for local user */
2791       if (MyUser(state->sptr)) {
2792
2793         /* don't allow local opers to be deopped on local channels */
2794         if (MyUser(state->sptr) &&
2795             state->cli_change[i].client != state->sptr &&
2796             IsLocalChannel(state->chptr->chname) &&
2797             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2798           send_reply(state->sptr, ERR_ISOPERLCHAN,
2799                      cli_name(state->cli_change[i].client),
2800                      state->chptr->chname);
2801           continue;
2802         }
2803
2804         if (feature_bool(FEAT_OPLEVELS)) {
2805         /* don't allow to deop members with an op level that is <= our own level */
2806         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2807                 && state->member
2808                 && OpLevel(member) <= OpLevel(state->member)) {
2809             int equal = (OpLevel(member) == OpLevel(state->member));
2810             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2811                        cli_name(state->cli_change[i].client),
2812                        state->chptr->chname,
2813                        OpLevel(state->member), OpLevel(member),
2814                        "deop", equal ? "the same" : "a higher");
2815           continue;
2816         }
2817       }
2818     }
2819     }
2820
2821     /* set op-level of member being opped */
2822     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2823         (MODE_ADD | MODE_CHANOP)) {
2824       /* If on a channel with upass set, someone with level x gives ops to someone else,
2825          then that person gets level x-1.  On other channels, where upass is not set,
2826          the level stays the same. */
2827       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2828       /* Someone being opped by a server gets op-level 0 */
2829       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2830       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2831     }
2832
2833     /* accumulate the change */
2834     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2835                         state->cli_change[i].client);
2836
2837     /* actually effect the change */
2838     if (state->flags & MODE_PARSE_SET) {
2839       if (state->cli_change[i].flag & MODE_ADD) {
2840         member->status |= (state->cli_change[i].flag &
2841                            (MODE_CHANOP | MODE_VOICE));
2842         if (state->cli_change[i].flag & MODE_CHANOP)
2843           ClearDeopped(member);
2844       } else
2845         member->status &= ~(state->cli_change[i].flag &
2846                             (MODE_CHANOP | MODE_VOICE));
2847     }
2848   } /* for (i = 0; state->cli_change[i].flags; i++) */
2849 }
2850
2851 /*
2852  * Helper function to process the simple modes
2853  */
2854 static void
2855 mode_parse_mode(struct ParseState *state, int *flag_p)
2856 {
2857   /* If they're not an oper, they can't change modes */
2858   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2859     send_notoper(state);
2860     return;
2861   }
2862
2863   if (!state->mbuf)
2864     return;
2865
2866   if (state->dir == MODE_ADD) {
2867     state->add |= flag_p[0];
2868     state->del &= ~flag_p[0];
2869
2870     if (flag_p[0] & MODE_SECRET) {
2871       state->add &= ~MODE_PRIVATE;
2872       state->del |= MODE_PRIVATE;
2873     } else if (flag_p[0] & MODE_PRIVATE) {
2874       state->add &= ~MODE_SECRET;
2875       state->del |= MODE_SECRET;
2876     }
2877   } else {
2878     state->add &= ~flag_p[0];
2879     state->del |= flag_p[0];
2880   }
2881
2882   assert(0 == (state->add & state->del));
2883   assert((MODE_SECRET | MODE_PRIVATE) !=
2884          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2885 }
2886
2887 /*
2888  * This routine is intended to parse MODE or OPMODE commands and effect the
2889  * changes (or just build the bounce buffer).  We pass the starting offset
2890  * as a 
2891  */
2892 int
2893 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2894            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2895            struct Membership* member)
2896 {
2897   static int chan_flags[] = {
2898     MODE_CHANOP,        'o',
2899     MODE_VOICE,         'v',
2900     MODE_PRIVATE,       'p',
2901     MODE_SECRET,        's',
2902     MODE_MODERATED,     'm',
2903     MODE_TOPICLIMIT,    't',
2904     MODE_INVITEONLY,    'i',
2905     MODE_NOPRIVMSGS,    'n',
2906     MODE_KEY,           'k',
2907     MODE_APASS,         'A',
2908     MODE_UPASS,         'u',
2909     MODE_BAN,           'b',
2910     MODE_LIMIT,         'l',
2911     MODE_REGONLY,       'r',
2912     MODE_ADD,           '+',
2913     MODE_DEL,           '-',
2914     0x0, 0x0
2915   };
2916   int i;
2917   int *flag_p;
2918   unsigned int t_mode;
2919   char *modestr;
2920   struct ParseState state;
2921
2922   assert(0 != cptr);
2923   assert(0 != sptr);
2924   assert(0 != chptr);
2925   assert(0 != parc);
2926   assert(0 != parv);
2927
2928   state.mbuf = mbuf;
2929   state.cptr = cptr;
2930   state.sptr = sptr;
2931   state.chptr = chptr;
2932   state.member = member;
2933   state.parc = parc;
2934   state.parv = parv;
2935   state.flags = flags;
2936   state.dir = MODE_ADD;
2937   state.done = 0;
2938   state.add = 0;
2939   state.del = 0;
2940   state.args_used = 0;
2941   state.max_args = MAXMODEPARAMS;
2942   state.numbans = 0;
2943
2944   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2945     state.banlist[i].next = 0;
2946     state.banlist[i].value.ban.banstr = 0;
2947     state.banlist[i].value.ban.who = 0;
2948     state.banlist[i].value.ban.when = 0;
2949     state.banlist[i].flags = 0;
2950     state.cli_change[i].flag = 0;
2951     state.cli_change[i].client = 0;
2952   }
2953
2954   modestr = state.parv[state.args_used++];
2955   state.parc--;
2956
2957   while (*modestr) {
2958     for (; *modestr; modestr++) {
2959       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2960         if (flag_p[1] == *modestr)
2961           break;
2962
2963       if (!flag_p[0]) { /* didn't find it?  complain and continue */
2964         if (MyUser(state.sptr))
2965           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2966         continue;
2967       }
2968
2969       switch (*modestr) {
2970       case '+': /* switch direction to MODE_ADD */
2971       case '-': /* switch direction to MODE_DEL */
2972         state.dir = flag_p[0];
2973         break;
2974
2975       case 'l': /* deal with limits */
2976         mode_parse_limit(&state, flag_p);
2977         break;
2978
2979       case 'k': /* deal with keys */
2980         mode_parse_key(&state, flag_p);
2981         break;
2982
2983       case 'A': /* deal with Admin passes */
2984         if (feature_bool(FEAT_OPLEVELS))
2985         mode_parse_apass(&state, flag_p);
2986         break;
2987
2988       case 'u': /* deal with user passes */
2989         if (feature_bool(FEAT_OPLEVELS))
2990         mode_parse_upass(&state, flag_p);
2991         break;
2992
2993       case 'b': /* deal with bans */
2994         mode_parse_ban(&state, flag_p);
2995         break;
2996
2997       case 'o': /* deal with ops/voice */
2998       case 'v':
2999         mode_parse_client(&state, flag_p);
3000         break;
3001
3002       default: /* deal with other modes */
3003         mode_parse_mode(&state, flag_p);
3004         break;
3005       } /* switch (*modestr) */
3006     } /* for (; *modestr; modestr++) */
3007
3008     if (state.flags & MODE_PARSE_BURST)
3009       break; /* don't interpret any more arguments */
3010
3011     if (state.parc > 0) { /* process next argument in string */
3012       modestr = state.parv[state.args_used++];
3013       state.parc--;
3014
3015       /* is it a TS? */
3016       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3017         time_t recv_ts;
3018
3019         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3020           break;                     /* we're then going to bounce the mode! */
3021
3022         recv_ts = atoi(modestr);
3023
3024         if (recv_ts && recv_ts < state.chptr->creationtime)
3025           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3026
3027         break; /* break out of while loop */
3028       } else if (state.flags & MODE_PARSE_STRICT ||
3029                  (MyUser(state.sptr) && state.max_args <= 0)) {
3030         state.parc++; /* we didn't actually gobble the argument */
3031         state.args_used--;
3032         break; /* break out of while loop */
3033       }
3034     }
3035   } /* while (*modestr) */
3036
3037   /*
3038    * the rest of the function finishes building resultant MODEs; if the
3039    * origin isn't a member or an oper, skip it.
3040    */
3041   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3042     return state.args_used; /* tell our parent how many args we gobbled */
3043
3044   t_mode = state.chptr->mode.mode;
3045
3046   if (state.del & t_mode) { /* delete any modes to be deleted... */
3047     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3048
3049     t_mode &= ~state.del;
3050   }
3051   if (state.add & ~t_mode) { /* add any modes to be added... */
3052     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3053
3054     t_mode |= state.add;
3055   }
3056
3057   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3058     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3059         !(t_mode & MODE_INVITEONLY))
3060       mode_invite_clear(state.chptr);
3061
3062     state.chptr->mode.mode = t_mode;
3063   }
3064
3065   if (state.flags & MODE_PARSE_WIPEOUT) {
3066     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3067       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3068                         state.chptr->mode.limit);
3069     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3070       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3071                           state.chptr->mode.key, 0);
3072     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3073       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3074                           state.chptr->mode.upass, 0);
3075     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3076       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3077                           state.chptr->mode.apass, 0);
3078   }
3079
3080   if (state.done & DONE_BANCLEAN) /* process bans */
3081     mode_process_bans(&state);
3082
3083   /* process client changes */
3084   if (state.cli_change[0].flag)
3085     mode_process_clients(&state);
3086
3087   return state.args_used; /* tell our parent how many args we gobbled */
3088 }
3089
3090 /*
3091  * Initialize a join buffer
3092  */
3093 void
3094 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3095              struct Client *connect, unsigned int type, char *comment,
3096              time_t create)
3097 {
3098   int i;
3099
3100   assert(0 != jbuf);
3101   assert(0 != source);
3102   assert(0 != connect);
3103
3104   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3105   jbuf->jb_connect = connect;
3106   jbuf->jb_type = type;
3107   jbuf->jb_comment = comment;
3108   jbuf->jb_create = create;
3109   jbuf->jb_count = 0;
3110   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3111                        type == JOINBUF_TYPE_PART ||
3112                        type == JOINBUF_TYPE_PARTALL) ?
3113                       STARTJOINLEN : STARTCREATELEN) +
3114                      (comment ? strlen(comment) + 2 : 0));
3115
3116   for (i = 0; i < MAXJOINARGS; i++)
3117     jbuf->jb_channels[i] = 0;
3118 }
3119
3120 /*
3121  * Add a channel to the join buffer
3122  */
3123 void
3124 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3125 {
3126   unsigned int len;
3127   int is_local;
3128
3129   assert(0 != jbuf);
3130
3131   if (!chan) {
3132     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3133       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3134
3135     return;
3136   }
3137
3138   is_local = IsLocalChannel(chan->chname);
3139
3140   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3141       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3142     /* Send notification to channel */
3143     if (!(flags & CHFL_ZOMBIE))
3144       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3145                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3146                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3147     else if (MyUser(jbuf->jb_source))
3148       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3149                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3150                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3151     /* XXX: Shouldn't we send a PART here anyway? */
3152     /* to users on the channel?  Why?  From their POV, the user isn't on
3153      * the channel anymore anyway.  We don't send to servers until below,
3154      * when we gang all the channel parts together.  Note that this is
3155      * exactly the same logic, albeit somewhat more concise, as was in
3156      * the original m_part.c */
3157
3158     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3159         is_local) /* got to remove user here */
3160       remove_user_from_channel(jbuf->jb_source, chan);
3161   } else {
3162     /* Add user to channel */
3163     add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3164
3165     /* send notification to all servers */
3166     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3167       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3168                             "%H %Tu", chan, chan->creationtime);
3169
3170     /* Send the notification to the channel */
3171     sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3172
3173     /* send an op, too, if needed */
3174     if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3175       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3176                                 chan, jbuf->jb_source);
3177   }
3178
3179   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3180       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3181     return; /* don't send to remote */
3182
3183   /* figure out if channel name will cause buffer to be overflowed */
3184   len = chan ? strlen(chan->chname) + 1 : 2;
3185   if (jbuf->jb_strlen + len > BUFSIZE)
3186     joinbuf_flush(jbuf);
3187
3188   /* add channel to list of channels to send and update counts */
3189   jbuf->jb_channels[jbuf->jb_count++] = chan;
3190   jbuf->jb_strlen += len;
3191
3192   /* if we've used up all slots, flush */
3193   if (jbuf->jb_count >= MAXJOINARGS)
3194     joinbuf_flush(jbuf);
3195 }
3196
3197 /*
3198  * Flush the channel list to remote servers
3199  */
3200 int
3201 joinbuf_flush(struct JoinBuf *jbuf)
3202 {
3203   char chanlist[BUFSIZE];
3204   int chanlist_i = 0;
3205   int i;
3206
3207   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3208       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3209     return 0; /* no joins to process */
3210
3211   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3212     build_string(chanlist, &chanlist_i,
3213                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3214                  i == 0 ? '\0' : ',');
3215     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3216       /* Remove user from channel */
3217       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3218
3219     jbuf->jb_channels[i] = 0; /* mark slot empty */
3220   }
3221
3222   jbuf->jb_count = 0; /* reset base counters */
3223   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3224                       STARTJOINLEN : STARTCREATELEN) +
3225                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3226
3227   /* and send the appropriate command */
3228   switch (jbuf->jb_type) {
3229   case JOINBUF_TYPE_CREATE:
3230     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3231                           "%s %Tu", chanlist, jbuf->jb_create);
3232     break;
3233
3234   case JOINBUF_TYPE_PART:
3235     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3236                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3237                           jbuf->jb_comment);
3238     break;
3239   }
3240
3241   return 0;
3242 }
3243
3244 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3245 int IsInvited(struct Client* cptr, const void* chptr)
3246 {
3247   struct SLink *lp;
3248
3249   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3250     if (lp->value.chptr == chptr)
3251       return 1;
3252   return 0;
3253 }