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