2004-05-09 Michael Poole <mdpoole@troilus.org>
[ircu2.10.12-pk.git] / ircd / channel.c
1 /*
2  * IRC - Internet Relay Chat, ircd/channel.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Co Center
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 1, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $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 or moderated)
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) &&
724             (is_banned(cptr, member->channel, member) ||
725              (member->channel->mode.mode & MODE_MODERATED)))
726         return member->channel->chname;
727     }
728   }
729   return 0;
730 }
731
732
733 /*
734  * write the "simple" list of channel modes for channel chptr onto buffer mbuf
735  * with the parameters in pbuf.
736  */
737 void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen,
738                           struct Channel *chptr, struct Membership *member)
739 {
740   int previous_parameter = 0;
741
742   assert(0 != mbuf);
743   assert(0 != pbuf);
744   assert(0 != chptr);
745
746   *mbuf++ = '+';
747   if (chptr->mode.mode & MODE_SECRET)
748     *mbuf++ = 's';
749   else if (chptr->mode.mode & MODE_PRIVATE)
750     *mbuf++ = 'p';
751   if (chptr->mode.mode & MODE_MODERATED)
752     *mbuf++ = 'm';
753   if (chptr->mode.mode & MODE_TOPICLIMIT)
754     *mbuf++ = 't';
755   if (chptr->mode.mode & MODE_INVITEONLY)
756     *mbuf++ = 'i';
757   if (chptr->mode.mode & MODE_NOPRIVMSGS)
758     *mbuf++ = 'n';
759   if (chptr->mode.mode & MODE_REGONLY)
760     *mbuf++ = 'r';
761   if (chptr->mode.limit) {
762     *mbuf++ = 'l';
763     ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit);
764     previous_parameter = 1;
765   }
766
767   if (*chptr->mode.key) {
768     *mbuf++ = 'k';
769     if (previous_parameter)
770       strcat(pbuf, " ");
771     if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
772       strcat(pbuf, chptr->mode.key);
773     } else
774       strcat(pbuf, "*");
775     previous_parameter = 1;
776   }
777   if (*chptr->mode.apass) {
778     *mbuf++ = 'A';
779     if (previous_parameter)
780       strcat(pbuf, " ");
781     if (IsServer(cptr)) {
782       strcat(pbuf, chptr->mode.apass);
783     } else
784       strcat(pbuf, "*");
785     previous_parameter = 1;
786   }
787   if (*chptr->mode.upass) {
788     *mbuf++ = 'u';
789     if (previous_parameter)
790       strcat(pbuf, " ");
791     if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0)) {
792       strcat(pbuf, chptr->mode.upass);
793     } else
794       strcat(pbuf, "*");
795   }
796   *mbuf = '\0';
797 }
798
799 int compare_member_oplevel(const void *mp1, const void *mp2)
800 {
801   struct Membership const* member1 = *(struct Membership const**)mp1;
802   struct Membership const* member2 = *(struct Membership const**)mp2;
803   if (member1->oplevel == member2->oplevel)
804     return 0;
805   return (member1->oplevel < member2->oplevel) ? -1 : 1;
806 }
807
808 /*
809  * send "cptr" a full list of the modes for channel chptr.
810  */
811 void send_channel_modes(struct Client *cptr, struct Channel *chptr)
812 {
813   /* The order in which modes are generated is now mandatory */
814   static unsigned int current_flags[4] =
815       { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE };
816   int                first = 1;
817   int                full  = 1;
818   int                flag_cnt = 0;
819   int                new_mode = 0;
820   size_t             len;
821   struct Membership* member;
822   struct SLink*      lp2;
823   char modebuf[MODEBUFLEN];
824   char parabuf[MODEBUFLEN];
825   struct MsgBuf *mb;
826   int                 number_of_ops = 0;
827   int                 opped_members_index = 0;
828   struct Membership** opped_members = NULL;
829   int                 last_oplevel = 0;
830
831   assert(0 != cptr);
832   assert(0 != chptr); 
833
834   if (IsLocalChannel(chptr->chname))
835     return;
836
837   member = chptr->members;
838   lp2 = chptr->banlist;
839
840   *modebuf = *parabuf = '\0';
841   channel_modes(cptr, modebuf, parabuf, sizeof(parabuf), chptr, 0);
842
843   for (first = 1; full; first = 0)      /* Loop for multiple messages */
844   {
845     full = 0;                   /* Assume by default we get it
846                                  all in one message */
847
848     /* (Continued) prefix: "<Y> B <channel> <TS>" */
849     /* is there any better way we can do this? */
850     mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr,
851                    chptr->creationtime);
852
853     if (first && modebuf[1])    /* Add simple modes (Aiklmnpstu)
854                                  if first message */
855     {
856       /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
857       msgq_append(&me, mb, " %s", modebuf);
858
859       if (*parabuf)
860         msgq_append(&me, mb, " %s", parabuf);
861     }
862
863     /*
864      * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
865      *
866      * First find all opless members.
867      * Run 2 times over all members, to group the members with
868      * and without voice together.
869      * Then run 2 times over all opped members (which are ordered
870      * by op-level) to also group voice and non-voice together.
871      */
872     for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt)
873     {
874       while (member)
875       {
876         if (flag_cnt < 2 && IsChanOp(member))
877         {
878           /*
879            * The first loop (to find all non-voice/op), we count the ops.
880            * The second loop (to find all voiced non-ops), store the ops
881            * in a dynamic array.
882            */
883           if (flag_cnt == 0)
884             ++number_of_ops;
885           else
886             opped_members[opped_members_index++] = member;
887         }
888         /* Only handle the members with the flags that we are interested in. */
889         if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt])
890         {
891           if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS)
892             /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */
893           {
894             full = 1;           /* Make sure we continue after
895                                    sending it so far */
896             /* Ensure the new BURST line contains the current
897              * ":mode", except when there is no mode yet. */
898             new_mode = (flag_cnt > 0) ? 1 : 0;
899             break;              /* Do not add this member to this message */
900           }
901           msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user);
902           first = 0;              /* From now on, use commas to add new nicks */
903
904           /*
905            * Do we have a nick with a new mode ?
906            * Or are we starting a new BURST line?
907            */
908           if (new_mode)
909           {
910             /*
911              * This means we are at the _first_ member that has only
912              * voice, or the first member that has only ops, or the
913              * first member that has voice and ops (so we get here
914              * at most three times, plus once for every start of
915              * a continued BURST line where only these modes is current.
916              * In the two cases where the current mode includes ops,
917              * we need to add the _absolute_ value of the oplevel to the mode.
918              */
919             char tbuf[3 + MAXOPLEVELDIGITS] = ":";
920             int loc = 1;
921
922             if (HasVoice(member))       /* flag_cnt == 1 or 3 */
923               tbuf[loc++] = 'v';
924             if (IsChanOp(member))       /* flag_cnt == 2 or 3 */
925             {
926               /* append the absolute value of the oplevel */
927               loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel);
928               last_oplevel = member->oplevel;
929             }
930             tbuf[loc] = '\0';
931             msgq_append(&me, mb, tbuf);
932             new_mode = 0;
933           }
934           else if (flag_cnt > 1 && last_oplevel != member->oplevel)
935           {
936             /*
937              * This can't be the first member of a (continued) BURST
938              * message because then either flag_cnt == 0 or new_mode == 1
939              * Now we need to append the incremental value of the oplevel.
940              */
941             char tbuf[2 + MAXOPLEVELDIGITS];
942             ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel);
943             last_oplevel = member->oplevel;
944             msgq_append(&me, mb, tbuf);
945           }
946         }
947         /* Go to the next `member'. */
948         if (flag_cnt < 2)
949           member = member->next_member;
950         else
951           member = opped_members[++opped_members_index];
952       }
953       if (full)
954         break;
955
956       /* Point `member' at the start of the list again. */
957       if (flag_cnt == 0)
958       {
959         member = chptr->members;
960         /* Now, after one loop, we know the number of ops and can
961          * allocate the dynamic array with pointer to the ops. */
962         opped_members = (struct Membership**)
963           MyMalloc((number_of_ops + 1) * sizeof(struct Membership*));
964         opped_members[number_of_ops] = NULL;    /* Needed for loop termination */
965       }
966       else
967       {
968         /* At the end of the second loop, sort the opped members with
969          * increasing op-level, so that we will output them in the
970          * correct order (and all op-level increments stay positive) */
971         if (flag_cnt == 1)
972           qsort(opped_members, number_of_ops,
973                 sizeof(struct Membership*), compare_member_oplevel);
974         /* The third and fourth loop run only over the opped members. */
975         member = opped_members[(opped_members_index = 0)];
976       }
977
978     } /* loop over 0,+v,+o,+ov */
979
980     if (!full)
981     {
982       /* Attach all bans, space seperated " :%ban ban ..." */
983       for (first = 2; lp2; lp2 = lp2->next)
984       {
985         len = strlen(lp2->value.ban.banstr);
986         if (msgq_bufleft(mb) < len + 1 + first)
987           /* The +1 stands for the added ' '.
988            * The +first stands for the added ":%".
989            */
990         {
991           full = 1;
992           break;
993         }
994         msgq_append(&me, mb, " %s%s", first ? ":%" : "",
995                     lp2->value.ban.banstr);
996         first = 0;
997       }
998     }
999
1000     send_buffer(cptr, mb, 0);  /* Send this message */
1001     msgq_clean(mb);
1002   }                             /* Continue when there was something
1003                                  that didn't fit (full==1) */
1004   if (opped_members)
1005     MyFree(opped_members);
1006 }
1007
1008 /*
1009  * pretty_mask
1010  *
1011  * by Carlo Wood (Run), 05 Oct 1998.
1012  *
1013  * Canonify a mask.
1014  *
1015  * When the nick is longer then NICKLEN, it is cut off (its an error of course).
1016  * When the user name or host name are too long (USERLEN and HOSTLEN
1017  * respectively) then they are cut off at the start with a '*'.
1018  *
1019  * The following transformations are made:
1020  *
1021  * 1)   xxx             -> nick!*@*
1022  * 2)   xxx.xxx         -> *!*@host
1023  * 3)   xxx!yyy         -> nick!user@*
1024  * 4)   xxx@yyy         -> *!user@host
1025  * 5)   xxx!yyy@zzz     -> nick!user@host
1026  */
1027 char *pretty_mask(char *mask)
1028 {
1029   static char star[2] = { '*', 0 };
1030   static char retmask[NUH_BUFSIZE];
1031   char *last_dot = NULL;
1032   char *ptr;
1033
1034   /* Case 1: default */
1035   char *nick = mask;
1036   char *user = star;
1037   char *host = star;
1038
1039   /* Do a _single_ pass through the characters of the mask: */
1040   for (ptr = mask; *ptr; ++ptr)
1041   {
1042     if (*ptr == '!')
1043     {
1044       /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
1045       user = ++ptr;
1046       host = star;
1047     }
1048     else if (*ptr == '@')
1049     {
1050       /* Case 4: Found last '@' (without finding a '!' yet) */
1051       nick = star;
1052       user = mask;
1053       host = ++ptr;
1054     }
1055     else if (*ptr == '.')
1056     {
1057       /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
1058       last_dot = ptr;
1059       continue;
1060     }
1061     else
1062       continue;
1063     for (; *ptr; ++ptr)
1064     {
1065       if (*ptr == '@')
1066       {
1067         /* Case 4 or 5: Found last '@' */
1068         host = ptr + 1;
1069       }
1070     }
1071     break;
1072   }
1073   if (user == star && last_dot)
1074   {
1075     /* Case 2: */
1076     nick = star;
1077     user = star;
1078     host = mask;
1079   }
1080   /* Check lengths */
1081   if (nick != star)
1082   {
1083     char *nick_end = (user != star) ? user - 1 : ptr;
1084     if (nick_end - nick > NICKLEN)
1085       nick[NICKLEN] = 0;
1086     *nick_end = 0;
1087   }
1088   if (user != star)
1089   {
1090     char *user_end = (host != star) ? host - 1 : ptr;
1091     if (user_end - user > USERLEN)
1092     {
1093       user = user_end - USERLEN;
1094       *user = '*';
1095     }
1096     *user_end = 0;
1097   }
1098   if (host != star && ptr - host > HOSTLEN)
1099   {
1100     host = ptr - HOSTLEN;
1101     *host = '*';
1102   }
1103   return make_nick_user_host(retmask, nick, user, host);
1104 }
1105
1106 static void send_ban_list(struct Client* cptr, struct Channel* chptr)
1107 {
1108   struct SLink* lp;
1109
1110   assert(0 != cptr);
1111   assert(0 != chptr);
1112
1113   for (lp = chptr->banlist; lp; lp = lp->next)
1114     send_reply(cptr, RPL_BANLIST, chptr->chname, lp->value.ban.banstr,
1115                lp->value.ban.who, lp->value.ban.when);
1116
1117   send_reply(cptr, RPL_ENDOFBANLIST, chptr->chname);
1118 }
1119
1120 /* We are now treating the <key> part of /join <channel list> <key> as a key
1121  * ring; that is, we try one key against the actual channel key, and if that
1122  * doesn't work, we try the next one, and so on. -Kev -Texaco
1123  * Returns: 0 on match, 1 otherwise
1124  * This version contributed by SeKs <intru@info.polymtl.ca>
1125  */
1126 static int compall(char *key, char *keyring)
1127 {
1128   char *p1;
1129
1130 top:
1131   p1 = key;                     /* point to the key... */
1132   while (*p1 && *p1 == *keyring)
1133   {                             /* step through the key and ring until they
1134                                    don't match... */
1135     p1++;
1136     keyring++;
1137   }
1138
1139   if (!*p1 && (!*keyring || *keyring == ','))
1140     /* ok, if we're at the end of the and also at the end of one of the keys
1141        in the keyring, we have a match */
1142     return 0;
1143
1144   if (!*keyring)                /* if we're at the end of the key ring, there
1145                                    weren't any matches, so we return 1 */
1146     return 1;
1147
1148   /* Not at the end of the key ring, so step
1149      through to the next key in the ring: */
1150   while (*keyring && *(keyring++) != ',');
1151
1152   goto top;                     /* and check it against the key */
1153 }
1154
1155 int can_join(struct Client *sptr, struct Channel *chptr, char *key)
1156 {
1157   struct SLink *lp;
1158   int overrideJoin = 0;  
1159   
1160   /*
1161    * Now a banned user CAN join if invited -- Nemesi
1162    * Now a user CAN escape channel limit if invited -- bfriendly
1163    * Now a user CAN escape anything if invited -- Isomer
1164    */
1165
1166   for (lp = (cli_user(sptr))->invited; lp; lp = lp->next)
1167     if (lp->value.chptr == chptr)
1168       return 0;
1169   
1170   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
1171      a HACK(4) notice will be sent if he would not have been supposed
1172      to join normally. */ 
1173   if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) &&
1174       !BadPtr(key) && compall("OVERRIDE",chptr->mode.key) != 0 &&
1175       compall("OVERRIDE",key) == 0)
1176     overrideJoin = MAGIC_OPER_OVERRIDE;
1177
1178   if (chptr->mode.mode & MODE_INVITEONLY)
1179         return overrideJoin + ERR_INVITEONLYCHAN;
1180         
1181   if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
1182         return overrideJoin + ERR_CHANNELISFULL;
1183
1184   if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr))
1185         return overrideJoin + ERR_NEEDREGGEDNICK;
1186         
1187   if (is_banned(sptr, chptr, NULL))
1188         return overrideJoin + ERR_BANNEDFROMCHAN;
1189   
1190   /*
1191    * now using compall (above) to test against a whole key ring -Kev
1192    */
1193   if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
1194     return overrideJoin + ERR_BADCHANNELKEY;
1195
1196   if (overrideJoin)     
1197         return ERR_DONTCHEAT;
1198         
1199   return 0;
1200 }
1201
1202 /*
1203  * Remove bells and commas from channel name
1204  */
1205 void clean_channelname(char *cn)
1206 {
1207   int i;
1208
1209   for (i = 0; cn[i]; i++) {
1210     if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
1211       cn[i] = '\0';
1212       return;
1213     }
1214     if (IsChannelLower(cn[i])) {
1215       cn[i] = ToLower(cn[i]);
1216 #ifndef FIXME
1217       /*
1218        * Remove for .08+
1219        * toupper(0xd0)
1220        */
1221       if ((unsigned char)(cn[i]) == 0xd0)
1222         cn[i] = (char) 0xf0;
1223 #endif
1224     }
1225   }
1226 }
1227
1228 /*
1229  *  Get Channel block for i (and allocate a new channel
1230  *  block, if it didn't exists before).
1231  */
1232 struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
1233 {
1234   struct Channel *chptr;
1235   int len;
1236
1237   if (EmptyString(chname))
1238     return NULL;
1239
1240   len = strlen(chname);
1241   if (MyUser(cptr) && len > CHANNELLEN)
1242   {
1243     len = CHANNELLEN;
1244     *(chname + CHANNELLEN) = '\0';
1245   }
1246   if ((chptr = FindChannel(chname)))
1247     return (chptr);
1248   if (flag == CGT_CREATE)
1249   {
1250     chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
1251     assert(0 != chptr);
1252     ++UserStats.channels;
1253     memset(chptr, 0, sizeof(struct Channel));
1254     strcpy(chptr->chname, chname);
1255     if (GlobalChannelList)
1256       GlobalChannelList->prev = chptr;
1257     chptr->prev = NULL;
1258     chptr->next = GlobalChannelList;
1259     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
1260     GlobalChannelList = chptr;
1261     hAddChannel(chptr);
1262   }
1263   return chptr;
1264 }
1265
1266 void add_invite(struct Client *cptr, struct Channel *chptr)
1267 {
1268   struct SLink *inv, **tmp;
1269
1270   del_invite(cptr, chptr);
1271   /*
1272    * Delete last link in chain if the list is max length
1273    */
1274   assert(list_length((cli_user(cptr))->invited) == (cli_user(cptr))->invites);
1275   if ((cli_user(cptr))->invites >= feature_int(FEAT_MAXCHANNELSPERUSER))
1276     del_invite(cptr, (cli_user(cptr))->invited->value.chptr);
1277   /*
1278    * Add client to channel invite list
1279    */
1280   inv = make_link();
1281   inv->value.cptr = cptr;
1282   inv->next = chptr->invites;
1283   chptr->invites = inv;
1284   /*
1285    * Add channel to the end of the client invite list
1286    */
1287   for (tmp = &((cli_user(cptr))->invited); *tmp; tmp = &((*tmp)->next));
1288   inv = make_link();
1289   inv->value.chptr = chptr;
1290   inv->next = NULL;
1291   (*tmp) = inv;
1292   (cli_user(cptr))->invites++;
1293 }
1294
1295 /*
1296  * Delete Invite block from channel invite list and client invite list
1297  */
1298 void del_invite(struct Client *cptr, struct Channel *chptr)
1299 {
1300   struct SLink **inv, *tmp;
1301
1302   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
1303     if (tmp->value.cptr == cptr)
1304     {
1305       *inv = tmp->next;
1306       free_link(tmp);
1307       tmp = 0;
1308       (cli_user(cptr))->invites--;
1309       break;
1310     }
1311
1312   for (inv = &((cli_user(cptr))->invited); (tmp = *inv); inv = &tmp->next)
1313     if (tmp->value.chptr == chptr)
1314     {
1315       *inv = tmp->next;
1316       free_link(tmp);
1317       tmp = 0;
1318       break;
1319     }
1320 }
1321
1322 /* List and skip all channels that are listen */
1323 void list_next_channels(struct Client *cptr, int nr)
1324 {
1325   struct ListingArgs *args = cli_listing(cptr);
1326   struct Channel *chptr = args->chptr;
1327   chptr->mode.mode &= ~MODE_LISTED;
1328   while (is_listed(chptr) || --nr >= 0)
1329   {
1330     for (; chptr; chptr = chptr->next)
1331     {
1332       if (!cli_user(cptr) || (!(HasPriv(cptr, PRIV_LIST_CHAN) && IsAnOper(cptr)) && 
1333           SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1334         continue;
1335       if (chptr->users > args->min_users && chptr->users < args->max_users &&
1336           chptr->creationtime > args->min_time &&
1337           chptr->creationtime < args->max_time &&
1338           (!args->topic_limits || (*chptr->topic &&
1339           chptr->topic_time > args->min_topic_time &&
1340           chptr->topic_time < args->max_topic_time)))
1341       {
1342         if (ShowChannel(cptr,chptr))
1343           send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1344                      chptr->topic);
1345         chptr = chptr->next;
1346         break;
1347       }
1348     }
1349     if (!chptr)
1350     {
1351       MyFree(cli_listing(cptr));
1352       cli_listing(cptr) = NULL;
1353       send_reply(cptr, RPL_LISTEND);
1354       break;
1355     }
1356   }
1357   if (chptr)
1358   {
1359     (cli_listing(cptr))->chptr = chptr;
1360     chptr->mode.mode |= MODE_LISTED;
1361   }
1362
1363   update_write(cptr);
1364 }
1365
1366 /*
1367  * Consider:
1368  *
1369  *                     client
1370  *                       |
1371  *                       c
1372  *                       |
1373  *     X --a--> A --b--> B --d--> D
1374  *                       |
1375  *                      who
1376  *
1377  * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1378  * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1379  *
1380  * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1381  *    Remove the user immediately when no users are left on the channel.
1382  * b) On server B : remove the user (who/lp) from the channel, send a
1383  *    PART upstream (to A) and pass on the KICK.
1384  * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1385  *    channel, and pass on the KICK.
1386  * d) On server D : remove the user (who/lp) from the channel, and pass on
1387  *    the KICK.
1388  *
1389  * Note:
1390  * - Setting the ZOMBIE flag never hurts, we either remove the
1391  *   client after that or we don't.
1392  * - The KICK message was already passed on, as should be in all cases.
1393  * - `who' is removed in all cases except case a) when users are left.
1394  * - A PART is only sent upstream in case b).
1395  *
1396  * 2 aug 97:
1397  *
1398  *              6
1399  *              |
1400  *  1 --- 2 --- 3 --- 4 --- 5
1401  *        |           |
1402  *      kicker       who
1403  *
1404  * We also need to turn 'who' into a zombie on servers 1 and 6,
1405  * because a KICK from 'who' (kicking someone else in that direction)
1406  * can arrive there afterwards - which should not be bounced itself.
1407  * Therefore case a) also applies for servers 1 and 6.
1408  *
1409  * --Run
1410  */
1411 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1412                  struct Client* sptr, struct Channel* chptr)
1413 {
1414   assert(0 != member);
1415   assert(0 != who);
1416   assert(0 != cptr);
1417   assert(0 != chptr);
1418
1419   /* Default for case a): */
1420   SetZombie(member);
1421
1422   /* Case b) or c) ?: */
1423   if (MyUser(who))      /* server 4 */
1424   {
1425     if (IsServer(cptr)) /* Case b) ? */
1426       sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1427     remove_user_from_channel(who, chptr);
1428     return;
1429   }
1430   if (cli_from(who) == cptr)        /* True on servers 1, 5 and 6 */
1431   {
1432     struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1433     for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1434       if (acptr == (cli_user(who))->server)   /* Case d) (server 5) */
1435       {
1436         remove_user_from_channel(who, chptr);
1437         return;
1438       }
1439   }
1440
1441   /* Case a) (servers 1, 2, 3 and 6) */
1442   if (channel_all_zombies(chptr))
1443     remove_user_from_channel(who, chptr);
1444
1445   /* XXX Can't actually call Debug here; if the channel is all zombies,
1446    * chptr will no longer exist when we get here.
1447   Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1448   */
1449 }
1450
1451 int number_of_zombies(struct Channel *chptr)
1452 {
1453   struct Membership* member;
1454   int                count = 0;
1455
1456   assert(0 != chptr);
1457   for (member = chptr->members; member; member = member->next_member) {
1458     if (IsZombie(member))
1459       ++count;
1460   }
1461   return count;
1462 }
1463
1464 /*
1465  * This helper function builds an argument string in strptr, consisting
1466  * of the original string, a space, and str1 and str2 concatenated (if,
1467  * of course, str2 is not NULL)
1468  */
1469 static void
1470 build_string(char *strptr, int *strptr_i, const char *str1,
1471              const char *str2, char c)
1472 {
1473   if (c)
1474     strptr[(*strptr_i)++] = c;
1475
1476   while (*str1)
1477     strptr[(*strptr_i)++] = *(str1++);
1478
1479   if (str2)
1480     while (*str2)
1481       strptr[(*strptr_i)++] = *(str2++);
1482
1483   strptr[(*strptr_i)] = '\0';
1484 }
1485
1486 /*
1487  * This is the workhorse of our ModeBuf suite; this actually generates the
1488  * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
1489  */
1490 static int
1491 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1492 {
1493   /* we only need the flags that don't take args right now */
1494   static int flags[] = {
1495 /*  MODE_CHANOP,        'o', */
1496 /*  MODE_VOICE,         'v', */
1497     MODE_PRIVATE,       'p',
1498     MODE_SECRET,        's',
1499     MODE_MODERATED,     'm',
1500     MODE_TOPICLIMIT,    't',
1501     MODE_INVITEONLY,    'i',
1502     MODE_NOPRIVMSGS,    'n',
1503     MODE_REGONLY,       'r',
1504 /*  MODE_KEY,           'k', */
1505 /*  MODE_BAN,           'b', */
1506 /*  MODE_LIMIT,         'l', */
1507 /*  MODE_APASS,         'A', */
1508 /*  MODE_UPASS,         'u', */
1509     0x0, 0x0
1510   };
1511   int i;
1512   int *flag_p;
1513
1514   struct Client *app_source; /* where the MODE appears to come from */
1515
1516   char addbuf[20]; /* accumulates +psmtin, etc. */
1517   int addbuf_i = 0;
1518   char rembuf[20]; /* accumulates -psmtin, etc. */
1519   int rembuf_i = 0;
1520   char *bufptr; /* we make use of indirection to simplify the code */
1521   int *bufptr_i;
1522
1523   char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1524   int addstr_i;
1525   char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1526   int remstr_i;
1527   char *strptr; /* more indirection to simplify the code */
1528   int *strptr_i;
1529
1530   int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1531   int tmp;
1532
1533   char limitbuf[20]; /* convert limits to strings */
1534
1535   unsigned int limitdel = MODE_LIMIT;
1536
1537   assert(0 != mbuf);
1538
1539   /* If the ModeBuf is empty, we have nothing to do */
1540   if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1541     return 0;
1542
1543   /* Ok, if we were given the OPMODE flag, or its a server, hide the source.
1544    */
1545   if (mbuf->mb_dest & MODEBUF_DEST_OPMODE || IsServer(mbuf->mb_source))
1546     app_source = &me;
1547   else
1548     app_source = mbuf->mb_source;
1549
1550   /*
1551    * Account for user we're bouncing; we have to get it in on the first
1552    * bounced MODE, or we could have problems
1553    */
1554   if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1555     totalbuflen -= 6; /* numeric nick == 5, plus one space */
1556
1557   /* Calculate the simple flags */
1558   for (flag_p = flags; flag_p[0]; flag_p += 2) {
1559     if (*flag_p & mbuf->mb_add)
1560       addbuf[addbuf_i++] = flag_p[1];
1561     else if (*flag_p & mbuf->mb_rem)
1562       rembuf[rembuf_i++] = flag_p[1];
1563   }
1564
1565   /* Now go through the modes with arguments... */
1566   for (i = 0; i < mbuf->mb_count; i++) {
1567     if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1568       bufptr = addbuf;
1569       bufptr_i = &addbuf_i;
1570     } else {
1571       bufptr = rembuf;
1572       bufptr_i = &rembuf_i;
1573     }
1574
1575     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1576       tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1577
1578       if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1579         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1580       else {
1581         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1582         totalbuflen -= IRCD_MAX(5, tmp) + 1;
1583       }
1584     } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS)) {
1585       tmp = strlen(MB_STRING(mbuf, i));
1586
1587       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1588         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1589       else {
1590         char mode_char;
1591         switch(MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS))
1592         {
1593           case MODE_APASS:
1594             mode_char = 'A';
1595             break;
1596           case MODE_UPASS:
1597             mode_char = 'u';
1598             break;
1599           default:
1600             mode_char = 'b';
1601             break;
1602         }
1603         bufptr[(*bufptr_i)++] = mode_char;
1604         totalbuflen -= tmp + 1;
1605       }
1606     } else if (MB_TYPE(mbuf, i) & MODE_KEY) {
1607       tmp = (mbuf->mb_dest & MODEBUF_DEST_NOKEY ? 1 :
1608              strlen(MB_STRING(mbuf, i)));
1609
1610       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1611         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1612       else {
1613         bufptr[(*bufptr_i)++] = 'k';
1614         totalbuflen -= tmp + 1;
1615       }
1616     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1617       /* if it's a limit, we also format the number */
1618       ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1619
1620       tmp = strlen(limitbuf);
1621
1622       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1623         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1624       else {
1625         bufptr[(*bufptr_i)++] = 'l';
1626         totalbuflen -= tmp + 1;
1627       }
1628     }
1629   }
1630
1631   /* terminate the mode strings */
1632   addbuf[addbuf_i] = '\0';
1633   rembuf[rembuf_i] = '\0';
1634
1635   /* If we're building a user visible MODE or HACK... */
1636   if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1637                        MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
1638                        MODEBUF_DEST_LOG)) {
1639     /* Set up the parameter strings */
1640     addstr[0] = '\0';
1641     addstr_i = 0;
1642     remstr[0] = '\0';
1643     remstr_i = 0;
1644
1645     for (i = 0; i < mbuf->mb_count; i++) {
1646       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1647         continue;
1648
1649       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1650         strptr = addstr;
1651         strptr_i = &addstr_i;
1652       } else {
1653         strptr = remstr;
1654         strptr_i = &remstr_i;
1655       }
1656
1657       /* deal with clients... */
1658       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1659         build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1660
1661       /* deal with bans... */
1662       else if (MB_TYPE(mbuf, i) & MODE_BAN)
1663         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1664
1665       /* deal with keys... */
1666       else if (MB_TYPE(mbuf, i) & MODE_KEY)
1667         build_string(strptr, strptr_i, mbuf->mb_dest & MODEBUF_DEST_NOKEY ?
1668                      "*" : MB_STRING(mbuf, i), 0, ' ');
1669
1670       /* deal with invisible passwords */
1671       else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1672         build_string(strptr, strptr_i, "*", 0, ' ');
1673
1674       /*
1675        * deal with limit; note we cannot include the limit parameter if we're
1676        * removing it
1677        */
1678       else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1679                (MODE_ADD | MODE_LIMIT))
1680         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1681     }
1682
1683     /* send the messages off to their destination */
1684     if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1685       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1686                            "[%Tu]",
1687                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ?
1688                                     mbuf->mb_source : app_source),
1689                            mbuf->mb_channel->chname,
1690                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1691                            addbuf, remstr, addstr,
1692                            mbuf->mb_channel->creationtime);
1693
1694     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1695       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1696                            "%s%s%s%s%s%s [%Tu]",
1697                            cli_name(feature_bool(FEAT_HIS_SNOTICES) ? 
1698                                     mbuf->mb_source : app_source),
1699                            mbuf->mb_channel->chname, rembuf_i ? "-" : "",
1700                            rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1701                            mbuf->mb_channel->creationtime);
1702
1703     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1704       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1705                            "[%Tu]",
1706 #ifdef HEAD_IN_SAND_SNOTICES
1707                            cli_name(mbuf->mb_source),
1708 #else
1709                            cli_name(app_source),
1710 #endif
1711                            mbuf->mb_channel->chname,
1712                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1713                            addbuf, remstr, addstr,
1714                            mbuf->mb_channel->creationtime);
1715
1716     if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1717       log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1718                 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1719                 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1720                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1721
1722     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1723       sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1724                                 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1725                                 rembuf_i ? "-" : "", rembuf,
1726                                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1727   }
1728
1729   /* Now are we supposed to propagate to other servers? */
1730   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1731     /* set up parameter string */
1732     addstr[0] = '\0';
1733     addstr_i = 0;
1734     remstr[0] = '\0';
1735     remstr_i = 0;
1736
1737     /*
1738      * limit is supressed if we're removing it; we have to figure out which
1739      * direction is the direction for it to be removed, though...
1740      */
1741     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1742
1743     for (i = 0; i < mbuf->mb_count; i++) {
1744       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1745         continue;
1746
1747       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1748         strptr = addstr;
1749         strptr_i = &addstr_i;
1750       } else {
1751         strptr = remstr;
1752         strptr_i = &remstr_i;
1753       }
1754
1755       /* deal with modes that take clients */
1756       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1757         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1758
1759       /* deal with modes that take strings */
1760       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1761         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1762
1763       /*
1764        * deal with the limit.  Logic here is complicated; if HACK2 is set,
1765        * we're bouncing the mode, so sense is reversed, and we have to
1766        * include the original limit if it looks like it's being removed
1767        */
1768       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1769         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1770     }
1771
1772     /* we were told to deop the source */
1773     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1774       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1775       addbuf[addbuf_i] = '\0'; /* terminate the string... */
1776       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1777
1778       /* mark that we've done this, so we don't do it again */
1779       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1780     }
1781
1782     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1783       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1784       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1785                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
1786                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1787                             addbuf, remstr, addstr);
1788     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1789       /*
1790        * If HACK2 was set, we're bouncing; we send the MODE back to the
1791        * connection we got it from with the senses reversed and a TS of 0;
1792        * origin is us
1793        */
1794       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1795                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1796                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
1797                     mbuf->mb_channel->creationtime);
1798     } else {
1799       /*
1800        * We're propagating a normal MODE command to the rest of the network;
1801        * we send the actual channel TS unless this is a HACK3 or a HACK4
1802        */
1803       if (IsServer(mbuf->mb_source))
1804         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1805                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1806                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1807                               addbuf, remstr, addstr,
1808                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1809                               mbuf->mb_channel->creationtime);
1810       else
1811         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1812                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
1813                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1814                               addbuf, remstr, addstr);
1815     }
1816   }
1817
1818   /* We've drained the ModeBuf... */
1819   mbuf->mb_add = 0;
1820   mbuf->mb_rem = 0;
1821   mbuf->mb_count = 0;
1822
1823   /* reinitialize the mode-with-arg slots */
1824   for (i = 0; i < MAXMODEPARAMS; i++) {
1825     /* If we saved any, pack them down */
1826     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1827       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1828       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1829
1830       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1831         continue;
1832     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1833       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1834
1835     MB_TYPE(mbuf, i) = 0;
1836     MB_UINT(mbuf, i) = 0;
1837   }
1838
1839   /* If we're supposed to flush it all, do so--all hail tail recursion */
1840   if (all && mbuf->mb_count)
1841     return modebuf_flush_int(mbuf, 1);
1842
1843   return 0;
1844 }
1845
1846 /*
1847  * This routine just initializes a ModeBuf structure with the information
1848  * needed and the options given.
1849  */
1850 void
1851 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1852              struct Client *connect, struct Channel *chan, unsigned int dest)
1853 {
1854   int i;
1855
1856   assert(0 != mbuf);
1857   assert(0 != source);
1858   assert(0 != chan);
1859   assert(0 != dest);
1860
1861   if (IsLocalChannel(chan->chname)) dest &= ~MODEBUF_DEST_SERVER;
1862
1863   mbuf->mb_add = 0;
1864   mbuf->mb_rem = 0;
1865   mbuf->mb_source = source;
1866   mbuf->mb_connect = connect;
1867   mbuf->mb_channel = chan;
1868   mbuf->mb_dest = dest;
1869   mbuf->mb_count = 0;
1870
1871   /* clear each mode-with-parameter slot */
1872   for (i = 0; i < MAXMODEPARAMS; i++) {
1873     MB_TYPE(mbuf, i) = 0;
1874     MB_UINT(mbuf, i) = 0;
1875   }
1876 }
1877
1878 /*
1879  * This routine simply adds modes to be added or deleted; do a binary OR
1880  * with either MODE_ADD or MODE_DEL
1881  */
1882 void
1883 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1884 {
1885   assert(0 != mbuf);
1886   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1887
1888   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1889            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1890
1891   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1892     return;
1893
1894   if (mode & MODE_ADD) {
1895     mbuf->mb_rem &= ~mode;
1896     mbuf->mb_add |= mode;
1897   } else {
1898     mbuf->mb_add &= ~mode;
1899     mbuf->mb_rem |= mode;
1900   }
1901 }
1902
1903 /*
1904  * This routine adds a mode to be added or deleted that takes a unsigned
1905  * int parameter; mode may *only* be the relevant mode flag ORed with one
1906  * of MODE_ADD or MODE_DEL
1907  */
1908 void
1909 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1910 {
1911   assert(0 != mbuf);
1912   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1913
1914   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1915   MB_UINT(mbuf, mbuf->mb_count) = uint;
1916
1917   /* when we've reached the maximal count, flush the buffer */
1918   if (++mbuf->mb_count >=
1919       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1920     modebuf_flush_int(mbuf, 0);
1921 }
1922
1923 /*
1924  * This routine adds a mode to be added or deleted that takes a string
1925  * parameter; mode may *only* be the relevant mode flag ORed with one of
1926  * MODE_ADD or MODE_DEL
1927  */
1928 void
1929 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1930                     int free)
1931 {
1932   assert(0 != mbuf);
1933   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1934
1935   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1936   MB_STRING(mbuf, mbuf->mb_count) = string;
1937
1938   /* when we've reached the maximal count, flush the buffer */
1939   if (++mbuf->mb_count >=
1940       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1941     modebuf_flush_int(mbuf, 0);
1942 }
1943
1944 /*
1945  * This routine adds a mode to be added or deleted that takes a client
1946  * parameter; mode may *only* be the relevant mode flag ORed with one of
1947  * MODE_ADD or MODE_DEL
1948  */
1949 void
1950 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1951                     struct Client *client)
1952 {
1953   assert(0 != mbuf);
1954   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1955
1956   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1957   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1958
1959   /* when we've reached the maximal count, flush the buffer */
1960   if (++mbuf->mb_count >=
1961       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1962     modebuf_flush_int(mbuf, 0);
1963 }
1964
1965 /*
1966  * This is the exported binding for modebuf_flush()
1967  */
1968 int
1969 modebuf_flush(struct ModeBuf *mbuf)
1970 {
1971   return modebuf_flush_int(mbuf, 1);
1972 }
1973
1974 /*
1975  * This extracts the simple modes contained in mbuf
1976  */
1977 void
1978 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1979 {
1980   static int flags[] = {
1981 /*  MODE_CHANOP,        'o', */
1982 /*  MODE_VOICE,         'v', */
1983     MODE_PRIVATE,       'p',
1984     MODE_SECRET,        's',
1985     MODE_MODERATED,     'm',
1986     MODE_TOPICLIMIT,    't',
1987     MODE_INVITEONLY,    'i',
1988     MODE_NOPRIVMSGS,    'n',
1989     MODE_KEY,           'k',
1990     MODE_APASS,         'A',
1991     MODE_UPASS,         'u',
1992 /*  MODE_BAN,           'b', */
1993     MODE_LIMIT,         'l',
1994     MODE_REGONLY,       'r',
1995     0x0, 0x0
1996   };
1997   unsigned int add;
1998   int i, bufpos = 0, len;
1999   int *flag_p;
2000   char *key = 0, limitbuf[20];
2001   char *apass = 0, *upass = 0;
2002
2003   assert(0 != mbuf);
2004   assert(0 != buf);
2005
2006   buf[0] = '\0';
2007
2008   add = mbuf->mb_add;
2009
2010   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
2011     if (MB_TYPE(mbuf, i) & MODE_ADD) {
2012       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
2013
2014       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
2015         key = MB_STRING(mbuf, i);
2016       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
2017         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
2018       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
2019         upass = MB_STRING(mbuf, i);
2020       else if (MB_TYPE(mbuf, i) & MODE_APASS)
2021         apass = MB_STRING(mbuf, i);
2022     }
2023   }
2024
2025   if (!add)
2026     return;
2027
2028   buf[bufpos++] = '+'; /* start building buffer */
2029
2030   for (flag_p = flags; flag_p[0]; flag_p += 2)
2031     if (*flag_p & add)
2032       buf[bufpos++] = flag_p[1];
2033
2034   for (i = 0, len = bufpos; i < len; i++) {
2035     if (buf[i] == 'k')
2036       build_string(buf, &bufpos, key, 0, ' ');
2037     else if (buf[i] == 'l')
2038       build_string(buf, &bufpos, limitbuf, 0, ' ');
2039     else if (buf[i] == 'u')
2040       build_string(buf, &bufpos, upass, 0, ' ');
2041     else if (buf[i] == 'A')
2042       build_string(buf, &bufpos, apass, 0, ' ');
2043   }
2044
2045   buf[bufpos] = '\0';
2046
2047   return;
2048 }
2049
2050 /*
2051  * Simple function to invalidate bans
2052  */
2053 void
2054 mode_ban_invalidate(struct Channel *chan)
2055 {
2056   struct Membership *member;
2057
2058   for (member = chan->members; member; member = member->next_member)
2059     ClearBanValid(member);
2060 }
2061
2062 /*
2063  * Simple function to drop invite structures
2064  */
2065 void
2066 mode_invite_clear(struct Channel *chan)
2067 {
2068   while (chan->invites)
2069     del_invite(chan->invites->value.cptr, chan);
2070 }
2071
2072 /* What we've done for mode_parse so far... */
2073 #define DONE_LIMIT      0x01    /* We've set the limit */
2074 #define DONE_KEY        0x02    /* We've set the key */
2075 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2076 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2077 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2078 #define DONE_UPASS      0x20    /* We've set user pass */
2079 #define DONE_APASS      0x40    /* We've set admin pass */
2080
2081 struct ParseState {
2082   struct ModeBuf *mbuf;
2083   struct Client *cptr;
2084   struct Client *sptr;
2085   struct Channel *chptr;
2086   struct Membership *member;
2087   int parc;
2088   char **parv;
2089   unsigned int flags;
2090   unsigned int dir;
2091   unsigned int done;
2092   unsigned int add;
2093   unsigned int del;
2094   int args_used;
2095   int max_args;
2096   int numbans;
2097   struct SLink banlist[MAXPARA];
2098   struct {
2099     unsigned int flag;
2100     struct Client *client;
2101   } cli_change[MAXPARA];
2102 };
2103
2104 /*
2105  * Here's a helper function to deal with sending along "Not oper" or
2106  * "Not member" messages
2107  */
2108 static void
2109 send_notoper(struct ParseState *state)
2110 {
2111   if (state->done & DONE_NOTOPER)
2112     return;
2113
2114   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2115              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2116
2117   state->done |= DONE_NOTOPER;
2118 }
2119
2120 /*
2121  * Helper function to convert limits
2122  */
2123 static void
2124 mode_parse_limit(struct ParseState *state, int *flag_p)
2125 {
2126   unsigned int t_limit;
2127
2128   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2129     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2130       return;
2131
2132     if (state->parc <= 0) { /* warn if not enough args */
2133       if (MyUser(state->sptr))
2134         need_more_params(state->sptr, "MODE +l");
2135       return;
2136     }
2137
2138     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2139     state->parc--;
2140     state->max_args--;
2141
2142     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2143         (!t_limit || t_limit == state->chptr->mode.limit))
2144       return;
2145   } else
2146     t_limit = state->chptr->mode.limit;
2147
2148   /* If they're not an oper, they can't change modes */
2149   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2150     send_notoper(state);
2151     return;
2152   }
2153
2154   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2155     return;
2156   state->done |= DONE_LIMIT;
2157
2158   if (!state->mbuf)
2159     return;
2160
2161   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2162
2163   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2164     if (state->dir & MODE_ADD) {
2165       state->chptr->mode.mode |= flag_p[0];
2166       state->chptr->mode.limit = t_limit;
2167     } else {
2168       state->chptr->mode.mode &= ~flag_p[0];
2169       state->chptr->mode.limit = 0;
2170     }
2171   }
2172 }
2173
2174 /*
2175  * Helper function to convert keys
2176  */
2177 static void
2178 mode_parse_key(struct ParseState *state, int *flag_p)
2179 {
2180   char *t_str, *s;
2181   int t_len;
2182
2183   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2184     return;
2185
2186   if (state->parc <= 0) { /* warn if not enough args */
2187     if (MyUser(state->sptr))
2188       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2189                        "MODE -k");
2190     return;
2191   }
2192
2193   t_str = state->parv[state->args_used++]; /* grab arg */
2194   state->parc--;
2195   state->max_args--;
2196
2197   /* If they're not an oper, they can't change modes */
2198   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2199     send_notoper(state);
2200     return;
2201   }
2202
2203   if (state->done & DONE_KEY) /* allow key to be set only once */
2204     return;
2205   state->done |= DONE_KEY;
2206
2207   t_len = KEYLEN;
2208
2209   /* clean up the key string */
2210   s = t_str;
2211   while (*++s > ' ' && *s != ':' && --t_len)
2212     ;
2213   *s = '\0';
2214
2215   if (!*t_str) { /* warn if empty */
2216     if (MyUser(state->sptr))
2217       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2218                        "MODE -k");
2219     return;
2220   }
2221
2222   if (!state->mbuf)
2223     return;
2224
2225   /* can't add a key if one is set, nor can one remove the wrong key */
2226   if (!(state->flags & MODE_PARSE_FORCE))
2227     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2228         (state->dir == MODE_DEL &&
2229          ircd_strcmp(state->chptr->mode.key, t_str))) {
2230       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2231       return;
2232     }
2233
2234   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2235       !ircd_strcmp(state->chptr->mode.key, t_str))
2236     return; /* no key change */
2237
2238   if (state->flags & MODE_PARSE_BOUNCE) {
2239     if (*state->chptr->mode.key) /* reset old key */
2240       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2241                           state->chptr->mode.key, 0);
2242     else /* remove new bogus key */
2243       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2244   } else /* send new key */
2245     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2246
2247   if (state->flags & MODE_PARSE_SET) {
2248     if (state->dir == MODE_ADD) /* set the new key */
2249       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2250     else /* remove the old key */
2251       *state->chptr->mode.key = '\0';
2252   }
2253 }
2254
2255 /*
2256  * Helper function to convert user passes
2257  */
2258 static void
2259 mode_parse_upass(struct ParseState *state, int *flag_p)
2260 {
2261   char *t_str, *s;
2262   int t_len;
2263
2264   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2265     return;
2266
2267   if (state->parc <= 0) { /* warn if not enough args */
2268     if (MyUser(state->sptr))
2269       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2270                        "MODE -u");
2271     return;
2272   }
2273
2274   t_str = state->parv[state->args_used++]; /* grab arg */
2275   state->parc--;
2276   state->max_args--;
2277
2278   /* If they're not an oper, they can't change modes */
2279   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2280     send_notoper(state);
2281     return;
2282   }
2283
2284   /* If they are not the channel manager, they are not allowed to change it */
2285   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2286     if (*state->chptr->mode.apass) {
2287       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2288           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2289     } else {
2290       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2291           "Re-create the channel.  The channel must be *empty* for",
2292           TStime() - state->chptr->creationtime >= 171000 ? "48 contiguous hours" : "a minute or two",
2293           "before it can be recreated.");
2294     }
2295     return;
2296   }
2297  
2298   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2299     return;
2300   state->done |= DONE_UPASS;
2301
2302   t_len = PASSLEN + 1;
2303
2304   /* clean up the upass string */
2305   s = t_str;
2306   while (*++s > ' ' && *s != ':' && --t_len)
2307     ;
2308   *s = '\0';
2309
2310   if (!*t_str) { /* warn if empty */
2311     if (MyUser(state->sptr))
2312       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2313                        "MODE -u");
2314     return;
2315   }
2316
2317   if (!state->mbuf)
2318     return;
2319
2320   if (!(state->flags & MODE_PARSE_FORCE))
2321     /* can't add the upass while apass is not set */
2322     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2323       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2324       return;
2325     }
2326     /* can't add a upass if one is set, nor can one remove the wrong upass */
2327     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2328         (state->dir == MODE_DEL &&
2329          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2330       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2331       return;
2332     }
2333
2334   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2335       !ircd_strcmp(state->chptr->mode.upass, t_str))
2336     return; /* no upass change */
2337
2338   if (state->flags & MODE_PARSE_BOUNCE) {
2339     if (*state->chptr->mode.upass) /* reset old upass */
2340       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2341                           state->chptr->mode.upass, 0);
2342     else /* remove new bogus upass */
2343       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2344   } else /* send new upass */
2345     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2346
2347   if (state->flags & MODE_PARSE_SET) {
2348     if (state->dir == MODE_ADD) /* set the new upass */
2349       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2350     else /* remove the old upass */
2351       *state->chptr->mode.upass = '\0';
2352   }
2353 }
2354
2355 /*
2356  * Helper function to convert admin passes
2357  */
2358 static void
2359 mode_parse_apass(struct ParseState *state, int *flag_p)
2360 {
2361   char *t_str, *s;
2362   int t_len;
2363
2364   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2365     return;
2366
2367   if (state->parc <= 0) { /* warn if not enough args */
2368     if (MyUser(state->sptr))
2369       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2370                        "MODE -A");
2371     return;
2372   }
2373
2374   t_str = state->parv[state->args_used++]; /* grab arg */
2375   state->parc--;
2376   state->max_args--;
2377
2378   /* If they're not an oper, they can't change modes */
2379   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2380     send_notoper(state);
2381     return;
2382   }
2383
2384   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2385   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2386     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2387     return;
2388   }
2389
2390   /* If they are not the channel manager, they are not allowed to change it */
2391   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2392     if (*state->chptr->mode.apass) {
2393       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2394           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2395     } else {
2396       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2397           "Re-create the channel.  The channel must be *empty* for",
2398           "at least a whole minute", "before it can be recreated.");
2399     }
2400     return;
2401   }
2402  
2403   if (state->done & DONE_APASS) /* allow apass to be set only once */
2404     return;
2405   state->done |= DONE_APASS;
2406
2407   t_len = PASSLEN + 1;
2408
2409   /* clean up the apass string */
2410   s = t_str;
2411   while (*++s > ' ' && *s != ':' && --t_len)
2412     ;
2413   *s = '\0';
2414
2415   if (!*t_str) { /* warn if empty */
2416     if (MyUser(state->sptr))
2417       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2418                        "MODE -A");
2419     return;
2420   }
2421
2422   if (!state->mbuf)
2423     return;
2424
2425   if (!(state->flags & MODE_PARSE_FORCE)) {
2426     /* can't remove the apass while upass is still set */
2427     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2428       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2429       return;
2430     }
2431     /* can't add an apass if one is set, nor can one remove the wrong apass */
2432     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2433         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2434       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2435       return;
2436     }
2437   }
2438
2439   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2440       !ircd_strcmp(state->chptr->mode.apass, t_str))
2441     return; /* no apass change */
2442
2443   if (state->flags & MODE_PARSE_BOUNCE) {
2444     if (*state->chptr->mode.apass) /* reset old apass */
2445       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2446                           state->chptr->mode.apass, 0);
2447     else /* remove new bogus apass */
2448       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2449   } else /* send new apass */
2450     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2451
2452   if (state->flags & MODE_PARSE_SET) {
2453     if (state->dir == MODE_ADD) { /* set the new apass */
2454       /* Make it VERY clear to the user that this is a one-time password */
2455       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2456       if (MyUser(state->sptr)) {
2457         send_reply(state->sptr, RPL_APASSWARN,
2458             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2459             "Are you SURE you want to use this as Admin password? ",
2460             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2461         send_reply(state->sptr, RPL_APASSWARN,
2462             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2463             "\" to remove the password and then immediately set a new one. "
2464             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2465             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2466             "Now set the channel user password (+u).");
2467       }
2468     } else { /* remove the old apass */
2469       *state->chptr->mode.apass = '\0';
2470       if (MyUser(state->sptr))
2471         send_reply(state->sptr, RPL_APASSWARN,
2472             "WARNING: You removed the channel Admin password MODE (+A). ",
2473             "If you would disconnect or leave the channel without setting a new password then you will ",
2474             "not be able to set it again and lose ownership of this channel! ",
2475             "SET A NEW PASSWORD NOW!", "");
2476     }
2477   }
2478 }
2479
2480 /*
2481  * Helper function to convert bans
2482  */
2483 static void
2484 mode_parse_ban(struct ParseState *state, int *flag_p)
2485 {
2486   char *t_str, *s;
2487   struct SLink *ban, *newban = 0;
2488
2489   if (state->parc <= 0) { /* Not enough args, send ban list */
2490     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2491       send_ban_list(state->sptr, state->chptr);
2492       state->done |= DONE_BANLIST;
2493     }
2494
2495     return;
2496   }
2497
2498   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2499     return;
2500
2501   t_str = state->parv[state->args_used++]; /* grab arg */
2502   state->parc--;
2503   state->max_args--;
2504
2505   /* If they're not an oper, they can't change modes */
2506   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2507     send_notoper(state);
2508     return;
2509   }
2510
2511   if ((s = strchr(t_str, ' ')))
2512     *s = '\0';
2513
2514   if (!*t_str || *t_str == ':') { /* warn if empty */
2515     if (MyUser(state->sptr))
2516       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2517                        "MODE -b");
2518     return;
2519   }
2520
2521   t_str = collapse(pretty_mask(t_str));
2522
2523   /* remember the ban for the moment... */
2524   if (state->dir == MODE_ADD) {
2525     newban = state->banlist + (state->numbans++);
2526     newban->next = 0;
2527
2528     DupString(newban->value.ban.banstr, t_str);
2529     newban->value.ban.who = cli_name(state->sptr);
2530     newban->value.ban.when = TStime();
2531
2532     newban->flags = CHFL_BAN | MODE_ADD;
2533
2534     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2535       newban->flags |= CHFL_BAN_IPMASK;
2536   }
2537
2538   if (!state->chptr->banlist) {
2539     state->chptr->banlist = newban; /* add our ban with its flags */
2540     state->done |= DONE_BANCLEAN;
2541     return;
2542   }
2543
2544   /* Go through all bans */
2545   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2546     /* first, clean the ban flags up a bit */
2547     if (!(state->done & DONE_BANCLEAN))
2548       /* Note: We're overloading *lots* of bits here; be careful! */
2549       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2550
2551     /* Bit meanings:
2552      *
2553      * MODE_ADD            - Ban was added; if we're bouncing modes,
2554      *                       then we'll remove it below; otherwise,
2555      *                       we'll have to allocate a real ban
2556      *
2557      * MODE_DEL            - Ban was marked for deletion; if we're
2558      *                       bouncing modes, we'll have to re-add it,
2559      *                       otherwise, we'll have to remove it
2560      *
2561      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2562      *                       with a ban already set; if we're
2563      *                       bouncing modes, we'll have to bounce
2564      *                       this one; otherwise, we'll just ignore
2565      *                       it when we process added bans
2566      */
2567
2568     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2569       ban->flags |= MODE_DEL; /* delete one ban */
2570
2571       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2572         break;
2573     } else if (state->dir == MODE_ADD) {
2574       /* if the ban already exists, don't worry about it */
2575       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2576         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2577         MyFree(newban->value.ban.banstr); /* stopper a leak */
2578         state->numbans--; /* deallocate last ban */
2579         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2580           break;
2581       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2582         if (!(ban->flags & MODE_DEL))
2583           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2584       } else if (!mmatch(t_str, ban->value.ban.banstr))
2585         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2586
2587       if (!ban->next && (newban->flags & MODE_ADD))
2588       {
2589         ban->next = newban; /* add our ban with its flags */
2590         break; /* get out of loop */
2591       }
2592     }
2593   }
2594   state->done |= DONE_BANCLEAN;
2595 }
2596
2597 /*
2598  * This is the bottom half of the ban processor
2599  */
2600 static void
2601 mode_process_bans(struct ParseState *state)
2602 {
2603   struct SLink *ban, *newban, *prevban, *nextban;
2604   int count = 0;
2605   int len = 0;
2606   int banlen;
2607   int changed = 0;
2608
2609   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2610     count++;
2611     banlen = strlen(ban->value.ban.banstr);
2612     len += banlen;
2613     nextban = ban->next;
2614
2615     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2616       if (prevban)
2617         prevban->next = 0; /* Break the list; ban isn't a real ban */
2618       else
2619         state->chptr->banlist = 0;
2620
2621       count--;
2622       len -= banlen;
2623
2624       MyFree(ban->value.ban.banstr);
2625
2626       continue;
2627     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2628       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2629                           ban->value.ban.banstr,
2630                           state->flags & MODE_PARSE_SET);
2631
2632       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2633         if (prevban) /* clip it out of the list... */
2634           prevban->next = ban->next;
2635         else
2636           state->chptr->banlist = ban->next;
2637
2638         count--;
2639         len -= banlen;
2640
2641         MyFree(ban->value.ban.who);
2642         free_link(ban);
2643
2644         changed++;
2645         continue; /* next ban; keep prevban like it is */
2646       } else
2647         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2648     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2649       if (prevban)
2650         prevban->next = 0; /* Break the list; ban isn't a real ban */
2651       else
2652         state->chptr->banlist = 0;
2653
2654       /* If we're supposed to ignore it, do so. */
2655       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2656           !(state->flags & MODE_PARSE_BOUNCE)) {
2657         count--;
2658         len -= banlen;
2659
2660         MyFree(ban->value.ban.banstr);
2661       } else {
2662         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2663             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2664              count > feature_int(FEAT_MAXBANS))) {
2665           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2666                      ban->value.ban.banstr);
2667           count--;
2668           len -= banlen;
2669
2670           MyFree(ban->value.ban.banstr);
2671         } else {
2672           /* add the ban to the buffer */
2673           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2674                               ban->value.ban.banstr,
2675                               !(state->flags & MODE_PARSE_SET));
2676
2677           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2678             newban = make_link();
2679             newban->value.ban.banstr = ban->value.ban.banstr;
2680             DupString(newban->value.ban.who, ban->value.ban.who);
2681             newban->value.ban.when = ban->value.ban.when;
2682             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2683
2684             newban->next = state->chptr->banlist; /* and link it in */
2685             state->chptr->banlist = newban;
2686
2687             changed++;
2688           }
2689         }
2690       }
2691     }
2692
2693     prevban = ban;
2694   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2695
2696   if (changed) /* if we changed the ban list, we must invalidate the bans */
2697     mode_ban_invalidate(state->chptr);
2698 }
2699
2700 /*
2701  * Helper function to process client changes
2702  */
2703 static void
2704 mode_parse_client(struct ParseState *state, int *flag_p)
2705 {
2706   char *t_str;
2707   struct Client *acptr;
2708   int i;
2709
2710   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2711     return;
2712
2713   if (state->parc <= 0) /* return if not enough args */
2714     return;
2715
2716   t_str = state->parv[state->args_used++]; /* grab arg */
2717   state->parc--;
2718   state->max_args--;
2719
2720   /* If they're not an oper, they can't change modes */
2721   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2722     send_notoper(state);
2723     return;
2724   }
2725
2726   if (MyUser(state->sptr)) /* find client we're manipulating */
2727     acptr = find_chasing(state->sptr, t_str, NULL);
2728   else
2729     acptr = findNUser(t_str);
2730
2731   if (!acptr)
2732     return; /* find_chasing() already reported an error to the user */
2733
2734   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2735     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2736                                        state->cli_change[i].flag & flag_p[0]))
2737       break; /* found a slot */
2738
2739   /* Store what we're doing to them */
2740   state->cli_change[i].flag = state->dir | flag_p[0];
2741   state->cli_change[i].client = acptr;
2742 }
2743
2744 /*
2745  * Helper function to process the changed client list
2746  */
2747 static void
2748 mode_process_clients(struct ParseState *state)
2749 {
2750   int i;
2751   struct Membership *member;
2752
2753   for (i = 0; state->cli_change[i].flag; i++) {
2754     assert(0 != state->cli_change[i].client);
2755
2756     /* look up member link */
2757     if (!(member = find_member_link(state->chptr,
2758                                     state->cli_change[i].client)) ||
2759         (MyUser(state->sptr) && IsZombie(member))) {
2760       if (MyUser(state->sptr))
2761         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2762                    cli_name(state->cli_change[i].client),
2763                    state->chptr->chname);
2764       continue;
2765     }
2766
2767     if ((state->cli_change[i].flag & MODE_ADD &&
2768          (state->cli_change[i].flag & member->status)) ||
2769         (state->cli_change[i].flag & MODE_DEL &&
2770          !(state->cli_change[i].flag & member->status)))
2771       continue; /* no change made, don't do anything */
2772
2773     /* see if the deop is allowed */
2774     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2775         (MODE_DEL | MODE_CHANOP)) {
2776       /* prevent +k users from being deopped */
2777       if (IsChannelService(state->cli_change[i].client)) {
2778         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2779           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2780                                state->chptr,
2781                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2782                                 cli_name((cli_user(state->sptr))->server)));
2783
2784         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2785           send_reply(state->sptr, ERR_ISCHANSERVICE,
2786                      cli_name(state->cli_change[i].client),
2787                      state->chptr->chname);
2788           continue;
2789         }
2790       }
2791
2792       /* check deop for local user */
2793       if (MyUser(state->sptr)) {
2794
2795         /* don't allow local opers to be deopped on local channels */
2796         if (MyUser(state->sptr) &&
2797             state->cli_change[i].client != state->sptr &&
2798             IsLocalChannel(state->chptr->chname) &&
2799             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2800           send_reply(state->sptr, ERR_ISOPERLCHAN,
2801                      cli_name(state->cli_change[i].client),
2802                      state->chptr->chname);
2803           continue;
2804         }
2805
2806         if (feature_bool(FEAT_OPLEVELS)) {
2807         /* don't allow to deop members with an op level that is <= our own level */
2808         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2809                 && state->member
2810                 && OpLevel(member) <= OpLevel(state->member)) {
2811             int equal = (OpLevel(member) == OpLevel(state->member));
2812             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2813                        cli_name(state->cli_change[i].client),
2814                        state->chptr->chname,
2815                        OpLevel(state->member), OpLevel(member),
2816                        "deop", equal ? "the same" : "a higher");
2817           continue;
2818         }
2819       }
2820     }
2821     }
2822
2823     /* set op-level of member being opped */
2824     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2825         (MODE_ADD | MODE_CHANOP)) {
2826       /* If on a channel with upass set, someone with level x gives ops to someone else,
2827          then that person gets level x-1.  On other channels, where upass is not set,
2828          the level stays the same. */
2829       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2830       /* Someone being opped by a server gets op-level 0 */
2831       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2832       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2833     }
2834
2835     /* accumulate the change */
2836     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2837                         state->cli_change[i].client);
2838
2839     /* actually effect the change */
2840     if (state->flags & MODE_PARSE_SET) {
2841       if (state->cli_change[i].flag & MODE_ADD) {
2842         member->status |= (state->cli_change[i].flag &
2843                            (MODE_CHANOP | MODE_VOICE));
2844         if (state->cli_change[i].flag & MODE_CHANOP)
2845           ClearDeopped(member);
2846       } else
2847         member->status &= ~(state->cli_change[i].flag &
2848                             (MODE_CHANOP | MODE_VOICE));
2849     }
2850   } /* for (i = 0; state->cli_change[i].flags; i++) */
2851 }
2852
2853 /*
2854  * Helper function to process the simple modes
2855  */
2856 static void
2857 mode_parse_mode(struct ParseState *state, int *flag_p)
2858 {
2859   /* If they're not an oper, they can't change modes */
2860   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2861     send_notoper(state);
2862     return;
2863   }
2864
2865   if (!state->mbuf)
2866     return;
2867
2868   if (state->dir == MODE_ADD) {
2869     state->add |= flag_p[0];
2870     state->del &= ~flag_p[0];
2871
2872     if (flag_p[0] & MODE_SECRET) {
2873       state->add &= ~MODE_PRIVATE;
2874       state->del |= MODE_PRIVATE;
2875     } else if (flag_p[0] & MODE_PRIVATE) {
2876       state->add &= ~MODE_SECRET;
2877       state->del |= MODE_SECRET;
2878     }
2879   } else {
2880     state->add &= ~flag_p[0];
2881     state->del |= flag_p[0];
2882   }
2883
2884   assert(0 == (state->add & state->del));
2885   assert((MODE_SECRET | MODE_PRIVATE) !=
2886          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2887 }
2888
2889 /*
2890  * This routine is intended to parse MODE or OPMODE commands and effect the
2891  * changes (or just build the bounce buffer).  We pass the starting offset
2892  * as a 
2893  */
2894 int
2895 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2896            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2897            struct Membership* member)
2898 {
2899   static int chan_flags[] = {
2900     MODE_CHANOP,        'o',
2901     MODE_VOICE,         'v',
2902     MODE_PRIVATE,       'p',
2903     MODE_SECRET,        's',
2904     MODE_MODERATED,     'm',
2905     MODE_TOPICLIMIT,    't',
2906     MODE_INVITEONLY,    'i',
2907     MODE_NOPRIVMSGS,    'n',
2908     MODE_KEY,           'k',
2909     MODE_APASS,         'A',
2910     MODE_UPASS,         'u',
2911     MODE_BAN,           'b',
2912     MODE_LIMIT,         'l',
2913     MODE_REGONLY,       'r',
2914     MODE_ADD,           '+',
2915     MODE_DEL,           '-',
2916     0x0, 0x0
2917   };
2918   int i;
2919   int *flag_p;
2920   unsigned int t_mode;
2921   char *modestr;
2922   struct ParseState state;
2923
2924   assert(0 != cptr);
2925   assert(0 != sptr);
2926   assert(0 != chptr);
2927   assert(0 != parc);
2928   assert(0 != parv);
2929
2930   state.mbuf = mbuf;
2931   state.cptr = cptr;
2932   state.sptr = sptr;
2933   state.chptr = chptr;
2934   state.member = member;
2935   state.parc = parc;
2936   state.parv = parv;
2937   state.flags = flags;
2938   state.dir = MODE_ADD;
2939   state.done = 0;
2940   state.add = 0;
2941   state.del = 0;
2942   state.args_used = 0;
2943   state.max_args = MAXMODEPARAMS;
2944   state.numbans = 0;
2945
2946   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2947     state.banlist[i].next = 0;
2948     state.banlist[i].value.ban.banstr = 0;
2949     state.banlist[i].value.ban.who = 0;
2950     state.banlist[i].value.ban.when = 0;
2951     state.banlist[i].flags = 0;
2952     state.cli_change[i].flag = 0;
2953     state.cli_change[i].client = 0;
2954   }
2955
2956   modestr = state.parv[state.args_used++];
2957   state.parc--;
2958
2959   while (*modestr) {
2960     for (; *modestr; modestr++) {
2961       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2962         if (flag_p[1] == *modestr)
2963           break;
2964
2965       if (!flag_p[0]) { /* didn't find it?  complain and continue */
2966         if (MyUser(state.sptr))
2967           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2968         continue;
2969       }
2970
2971       switch (*modestr) {
2972       case '+': /* switch direction to MODE_ADD */
2973       case '-': /* switch direction to MODE_DEL */
2974         state.dir = flag_p[0];
2975         break;
2976
2977       case 'l': /* deal with limits */
2978         mode_parse_limit(&state, flag_p);
2979         break;
2980
2981       case 'k': /* deal with keys */
2982         mode_parse_key(&state, flag_p);
2983         break;
2984
2985       case 'A': /* deal with Admin passes */
2986         if (feature_bool(FEAT_OPLEVELS))
2987         mode_parse_apass(&state, flag_p);
2988         break;
2989
2990       case 'u': /* deal with user passes */
2991         if (feature_bool(FEAT_OPLEVELS))
2992         mode_parse_upass(&state, flag_p);
2993         break;
2994
2995       case 'b': /* deal with bans */
2996         mode_parse_ban(&state, flag_p);
2997         break;
2998
2999       case 'o': /* deal with ops/voice */
3000       case 'v':
3001         mode_parse_client(&state, flag_p);
3002         break;
3003
3004       default: /* deal with other modes */
3005         mode_parse_mode(&state, flag_p);
3006         break;
3007       } /* switch (*modestr) */
3008     } /* for (; *modestr; modestr++) */
3009
3010     if (state.flags & MODE_PARSE_BURST)
3011       break; /* don't interpret any more arguments */
3012
3013     if (state.parc > 0) { /* process next argument in string */
3014       modestr = state.parv[state.args_used++];
3015       state.parc--;
3016
3017       /* is it a TS? */
3018       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
3019         time_t recv_ts;
3020
3021         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
3022           break;                     /* we're then going to bounce the mode! */
3023
3024         recv_ts = atoi(modestr);
3025
3026         if (recv_ts && recv_ts < state.chptr->creationtime)
3027           state.chptr->creationtime = recv_ts; /* respect earlier TS */
3028
3029         break; /* break out of while loop */
3030       } else if (state.flags & MODE_PARSE_STRICT ||
3031                  (MyUser(state.sptr) && state.max_args <= 0)) {
3032         state.parc++; /* we didn't actually gobble the argument */
3033         state.args_used--;
3034         break; /* break out of while loop */
3035       }
3036     }
3037   } /* while (*modestr) */
3038
3039   /*
3040    * the rest of the function finishes building resultant MODEs; if the
3041    * origin isn't a member or an oper, skip it.
3042    */
3043   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3044     return state.args_used; /* tell our parent how many args we gobbled */
3045
3046   t_mode = state.chptr->mode.mode;
3047
3048   if (state.del & t_mode) { /* delete any modes to be deleted... */
3049     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3050
3051     t_mode &= ~state.del;
3052   }
3053   if (state.add & ~t_mode) { /* add any modes to be added... */
3054     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3055
3056     t_mode |= state.add;
3057   }
3058
3059   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3060     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3061         !(t_mode & MODE_INVITEONLY))
3062       mode_invite_clear(state.chptr);
3063
3064     state.chptr->mode.mode = t_mode;
3065   }
3066
3067   if (state.flags & MODE_PARSE_WIPEOUT) {
3068     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3069       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3070                         state.chptr->mode.limit);
3071     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3072       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3073                           state.chptr->mode.key, 0);
3074     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3075       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3076                           state.chptr->mode.upass, 0);
3077     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3078       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3079                           state.chptr->mode.apass, 0);
3080   }
3081
3082   if (state.done & DONE_BANCLEAN) /* process bans */
3083     mode_process_bans(&state);
3084
3085   /* process client changes */
3086   if (state.cli_change[0].flag)
3087     mode_process_clients(&state);
3088
3089   return state.args_used; /* tell our parent how many args we gobbled */
3090 }
3091
3092 /*
3093  * Initialize a join buffer
3094  */
3095 void
3096 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3097              struct Client *connect, unsigned int type, char *comment,
3098              time_t create)
3099 {
3100   int i;
3101
3102   assert(0 != jbuf);
3103   assert(0 != source);
3104   assert(0 != connect);
3105
3106   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3107   jbuf->jb_connect = connect;
3108   jbuf->jb_type = type;
3109   jbuf->jb_comment = comment;
3110   jbuf->jb_create = create;
3111   jbuf->jb_count = 0;
3112   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3113                        type == JOINBUF_TYPE_PART ||
3114                        type == JOINBUF_TYPE_PARTALL) ?
3115                       STARTJOINLEN : STARTCREATELEN) +
3116                      (comment ? strlen(comment) + 2 : 0));
3117
3118   for (i = 0; i < MAXJOINARGS; i++)
3119     jbuf->jb_channels[i] = 0;
3120 }
3121
3122 /*
3123  * Add a channel to the join buffer
3124  */
3125 void
3126 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3127 {
3128   unsigned int len;
3129   int is_local;
3130
3131   assert(0 != jbuf);
3132
3133   if (!chan) {
3134     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3135       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3136
3137     return;
3138   }
3139
3140   is_local = IsLocalChannel(chan->chname);
3141
3142   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3143       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3144     struct Membership *member = find_member_link(chan, jbuf->jb_source);
3145     if (IsUserParting(member))
3146       return;
3147     SetUserParting(member);
3148
3149     /* Send notification to channel */
3150     if (!(flags & CHFL_ZOMBIE))
3151       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3152                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3153                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3154     else if (MyUser(jbuf->jb_source))
3155       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3156                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3157                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3158     /* XXX: Shouldn't we send a PART here anyway? */
3159     /* to users on the channel?  Why?  From their POV, the user isn't on
3160      * the channel anymore anyway.  We don't send to servers until below,
3161      * when we gang all the channel parts together.  Note that this is
3162      * exactly the same logic, albeit somewhat more concise, as was in
3163      * the original m_part.c */
3164
3165     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3166         is_local) /* got to remove user here */
3167       remove_user_from_channel(jbuf->jb_source, chan);
3168   } else {
3169     /* Add user to channel */
3170     add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3171
3172     /* send notification to all servers */
3173     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !is_local)
3174       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3175                             "%H %Tu", chan, chan->creationtime);
3176
3177     /* Send the notification to the channel */
3178     sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3179
3180     /* send an op, too, if needed */
3181     if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE)
3182       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3183                                 chan, jbuf->jb_source);
3184   }
3185
3186   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3187       jbuf->jb_type == JOINBUF_TYPE_JOIN || is_local)
3188     return; /* don't send to remote */
3189
3190   /* figure out if channel name will cause buffer to be overflowed */
3191   len = chan ? strlen(chan->chname) + 1 : 2;
3192   if (jbuf->jb_strlen + len > BUFSIZE)
3193     joinbuf_flush(jbuf);
3194
3195   /* add channel to list of channels to send and update counts */
3196   jbuf->jb_channels[jbuf->jb_count++] = chan;
3197   jbuf->jb_strlen += len;
3198
3199   /* if we've used up all slots, flush */
3200   if (jbuf->jb_count >= MAXJOINARGS)
3201     joinbuf_flush(jbuf);
3202 }
3203
3204 /*
3205  * Flush the channel list to remote servers
3206  */
3207 int
3208 joinbuf_flush(struct JoinBuf *jbuf)
3209 {
3210   char chanlist[BUFSIZE];
3211   int chanlist_i = 0;
3212   int i;
3213
3214   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3215       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3216     return 0; /* no joins to process */
3217
3218   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3219     build_string(chanlist, &chanlist_i,
3220                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3221                  i == 0 ? '\0' : ',');
3222     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3223       /* Remove user from channel */
3224       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3225
3226     jbuf->jb_channels[i] = 0; /* mark slot empty */
3227   }
3228
3229   jbuf->jb_count = 0; /* reset base counters */
3230   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3231                       STARTJOINLEN : STARTCREATELEN) +
3232                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3233
3234   /* and send the appropriate command */
3235   switch (jbuf->jb_type) {
3236   case JOINBUF_TYPE_CREATE:
3237     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3238                           "%s %Tu", chanlist, jbuf->jb_create);
3239     break;
3240
3241   case JOINBUF_TYPE_PART:
3242     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3243                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3244                           jbuf->jb_comment);
3245     break;
3246   }
3247
3248   return 0;
3249 }
3250
3251 /* Returns TRUE (1) if client is invited, FALSE (0) if not */
3252 int IsInvited(struct Client* cptr, const void* chptr)
3253 {
3254   struct SLink *lp;
3255
3256   for (lp = (cli_user(cptr))->invited; lp; lp = lp->next)
3257     if (lp->value.chptr == chptr)
3258       return 1;
3259   return 0;
3260 }