a3a761706c77cd7da76cd0f63d6138d39427b77a
[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) || (SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
1317         continue;
1318       if (chptr->users > args->min_users && chptr->users < args->max_users &&
1319           chptr->creationtime > args->min_time &&
1320           chptr->creationtime < args->max_time &&
1321           (!args->topic_limits || (*chptr->topic &&
1322           chptr->topic_time > args->min_topic_time &&
1323           chptr->topic_time < args->max_topic_time)))
1324       {
1325         if (ShowChannel(cptr,chptr))
1326           send_reply(cptr, RPL_LIST, chptr->chname, chptr->users,
1327                      chptr->topic);
1328         chptr = chptr->next;
1329         break;
1330       }
1331     }
1332     if (!chptr)
1333     {
1334       MyFree(cli_listing(cptr));
1335       cli_listing(cptr) = NULL;
1336       send_reply(cptr, RPL_LISTEND);
1337       break;
1338     }
1339   }
1340   if (chptr)
1341   {
1342     (cli_listing(cptr))->chptr = chptr;
1343     chptr->mode.mode |= MODE_LISTED;
1344   }
1345
1346   update_write(cptr);
1347 }
1348
1349 /*
1350  * Consider:
1351  *
1352  *                     client
1353  *                       |
1354  *                       c
1355  *                       |
1356  *     X --a--> A --b--> B --d--> D
1357  *                       |
1358  *                      who
1359  *
1360  * Where `who' is being KICK-ed by a "KICK" message received by server 'A'
1361  * via 'a', or on server 'B' via either 'b' or 'c', or on server D via 'd'.
1362  *
1363  * a) On server A : set CHFL_ZOMBIE for `who' (lp) and pass on the KICK.
1364  *    Remove the user immedeately when no users are left on the channel.
1365  * b) On server B : remove the user (who/lp) from the channel, send a
1366  *    PART upstream (to A) and pass on the KICK.
1367  * c) KICKed by `client'; On server B : remove the user (who/lp) from the
1368  *    channel, and pass on the KICK.
1369  * d) On server D : remove the user (who/lp) from the channel, and pass on
1370  *    the KICK.
1371  *
1372  * Note:
1373  * - Setting the ZOMBIE flag never hurts, we either remove the
1374  *   client after that or we don't.
1375  * - The KICK message was already passed on, as should be in all cases.
1376  * - `who' is removed in all cases except case a) when users are left.
1377  * - A PART is only sent upstream in case b).
1378  *
1379  * 2 aug 97:
1380  *
1381  *              6
1382  *              |
1383  *  1 --- 2 --- 3 --- 4 --- 5
1384  *        |           |
1385  *      kicker       who
1386  *
1387  * We also need to turn 'who' into a zombie on servers 1 and 6,
1388  * because a KICK from 'who' (kicking someone else in that direction)
1389  * can arrive there afterwards - which should not be bounced itself.
1390  * Therefore case a) also applies for servers 1 and 6.
1391  *
1392  * --Run
1393  */
1394 void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
1395                  struct Client* sptr, struct Channel* chptr)
1396 {
1397   assert(0 != member);
1398   assert(0 != who);
1399   assert(0 != cptr);
1400   assert(0 != chptr);
1401
1402   /* Default for case a): */
1403   SetZombie(member);
1404
1405   /* Case b) or c) ?: */
1406   if (MyUser(who))      /* server 4 */
1407   {
1408     if (IsServer(cptr)) /* Case b) ? */
1409       sendcmdto_one(who, CMD_PART, cptr, "%H", chptr);
1410     remove_user_from_channel(who, chptr);
1411     return;
1412   }
1413   if (cli_from(who) == cptr)        /* True on servers 1, 5 and 6 */
1414   {
1415     struct Client *acptr = IsServer(sptr) ? sptr : (cli_user(sptr))->server;
1416     for (; acptr != &me; acptr = (cli_serv(acptr))->up)
1417       if (acptr == (cli_user(who))->server)   /* Case d) (server 5) */
1418       {
1419         remove_user_from_channel(who, chptr);
1420         return;
1421       }
1422   }
1423
1424   /* Case a) (servers 1, 2, 3 and 6) */
1425   if (channel_all_zombies(chptr))
1426     remove_user_from_channel(who, chptr);
1427
1428   /* XXX Can't actually call Debug here; if the channel is all zombies,
1429    * chptr will no longer exist when we get here.
1430   Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
1431   */
1432 }
1433
1434 int number_of_zombies(struct Channel *chptr)
1435 {
1436   struct Membership* member;
1437   int                count = 0;
1438
1439   assert(0 != chptr);
1440   for (member = chptr->members; member; member = member->next_member) {
1441     if (IsZombie(member))
1442       ++count;
1443   }
1444   return count;
1445 }
1446
1447 /*
1448  * This helper function builds an argument string in strptr, consisting
1449  * of the original string, a space, and str1 and str2 concatenated (if,
1450  * of course, str2 is not NULL)
1451  */
1452 static void
1453 build_string(char *strptr, int *strptr_i, char *str1, char *str2, char c)
1454 {
1455   if (c)
1456     strptr[(*strptr_i)++] = c;
1457
1458   while (*str1)
1459     strptr[(*strptr_i)++] = *(str1++);
1460
1461   if (str2)
1462     while (*str2)
1463       strptr[(*strptr_i)++] = *(str2++);
1464
1465   strptr[(*strptr_i)] = '\0';
1466 }
1467
1468 /*
1469  * This is the workhorse of our ModeBuf suite; this actually generates the
1470  * output MODE commands, HACK notices, or whatever.  It's pretty complicated.
1471  */
1472 static int
1473 modebuf_flush_int(struct ModeBuf *mbuf, int all)
1474 {
1475   /* we only need the flags that don't take args right now */
1476   static int flags[] = {
1477 /*  MODE_CHANOP,        'o', */
1478 /*  MODE_VOICE,         'v', */
1479     MODE_PRIVATE,       'p',
1480     MODE_SECRET,        's',
1481     MODE_MODERATED,     'm',
1482     MODE_TOPICLIMIT,    't',
1483     MODE_INVITEONLY,    'i',
1484     MODE_NOPRIVMSGS,    'n',
1485     MODE_REGONLY,       'r',
1486 /*  MODE_KEY,           'k', */
1487 /*  MODE_BAN,           'b', */
1488 /*  MODE_LIMIT,         'l', */
1489 /*  MODE_APASS,         'A', */
1490 /*  MODE_UPASS,         'u', */
1491     0x0, 0x0
1492   };
1493   int i;
1494   int *flag_p;
1495
1496   struct Client *app_source; /* where the MODE appears to come from */
1497
1498   char addbuf[20]; /* accumulates +psmtin, etc. */
1499   int addbuf_i = 0;
1500   char rembuf[20]; /* accumulates -psmtin, etc. */
1501   int rembuf_i = 0;
1502   char *bufptr; /* we make use of indirection to simplify the code */
1503   int *bufptr_i;
1504
1505   char addstr[BUFSIZE]; /* accumulates MODE parameters to add */
1506   int addstr_i;
1507   char remstr[BUFSIZE]; /* accumulates MODE parameters to remove */
1508   int remstr_i;
1509   char *strptr; /* more indirection to simplify the code */
1510   int *strptr_i;
1511
1512   int totalbuflen = BUFSIZE - 200; /* fuzz factor -- don't overrun buffer! */
1513   int tmp;
1514
1515   char limitbuf[20]; /* convert limits to strings */
1516
1517   unsigned int limitdel = MODE_LIMIT;
1518
1519   assert(0 != mbuf);
1520
1521   /* If the ModeBuf is empty, we have nothing to do */
1522   if (mbuf->mb_add == 0 && mbuf->mb_rem == 0 && mbuf->mb_count == 0)
1523     return 0;
1524
1525   /* Ok, if we were given the OPMODE flag, hide the source if its a user */
1526   if (mbuf->mb_dest & MODEBUF_DEST_OPMODE && !IsServer(mbuf->mb_source))
1527     app_source = &me;
1528   else
1529     app_source = mbuf->mb_source;
1530
1531   /*
1532    * Account for user we're bouncing; we have to get it in on the first
1533    * bounced MODE, or we could have problems
1534    */
1535   if (mbuf->mb_dest & MODEBUF_DEST_DEOP)
1536     totalbuflen -= 6; /* numeric nick == 5, plus one space */
1537
1538   /* Calculate the simple flags */
1539   for (flag_p = flags; flag_p[0]; flag_p += 2) {
1540     if (*flag_p & mbuf->mb_add)
1541       addbuf[addbuf_i++] = flag_p[1];
1542     else if (*flag_p & mbuf->mb_rem)
1543       rembuf[rembuf_i++] = flag_p[1];
1544   }
1545
1546   /* Now go through the modes with arguments... */
1547   for (i = 0; i < mbuf->mb_count; i++) {
1548     if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1549       bufptr = addbuf;
1550       bufptr_i = &addbuf_i;
1551     } else {
1552       bufptr = rembuf;
1553       bufptr_i = &rembuf_i;
1554     }
1555
1556     if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) {
1557       tmp = strlen(cli_name(MB_CLIENT(mbuf, i)));
1558
1559       if ((totalbuflen - IRCD_MAX(5, tmp)) <= 0) /* don't overflow buffer */
1560         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1561       else {
1562         bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v';
1563         totalbuflen -= IRCD_MAX(5, tmp) + 1;
1564       }
1565     } else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS)) {
1566       tmp = strlen(MB_STRING(mbuf, i));
1567
1568       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1569         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1570       else {
1571         char mode_char;
1572         switch(MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1573         {
1574           case MODE_APASS:
1575             mode_char = 'A';
1576             break;
1577           case MODE_UPASS:
1578             mode_char = 'u';
1579             break;
1580           case MODE_KEY:
1581             mode_char = 'k';
1582             break;
1583           default:
1584             mode_char = 'b';
1585             break;
1586         }
1587         bufptr[(*bufptr_i)++] = mode_char;
1588         totalbuflen -= tmp + 1;
1589       }
1590     } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) {
1591       /* if it's a limit, we also format the number */
1592       ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1593
1594       tmp = strlen(limitbuf);
1595
1596       if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */
1597         MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */
1598       else {
1599         bufptr[(*bufptr_i)++] = 'l';
1600         totalbuflen -= tmp + 1;
1601       }
1602     }
1603   }
1604
1605   /* terminate the mode strings */
1606   addbuf[addbuf_i] = '\0';
1607   rembuf[rembuf_i] = '\0';
1608
1609   /* If we're building a user visible MODE or HACK... */
1610   if (mbuf->mb_dest & (MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK2 |
1611                        MODEBUF_DEST_HACK3   | MODEBUF_DEST_HACK4 |
1612                        MODEBUF_DEST_LOG)) {
1613     /* Set up the parameter strings */
1614     addstr[0] = '\0';
1615     addstr_i = 0;
1616     remstr[0] = '\0';
1617     remstr_i = 0;
1618
1619     for (i = 0; i < mbuf->mb_count; i++) {
1620       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1621         continue;
1622
1623       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1624         strptr = addstr;
1625         strptr_i = &addstr_i;
1626       } else {
1627         strptr = remstr;
1628         strptr_i = &remstr_i;
1629       }
1630
1631       /* deal with clients... */
1632       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1633         build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' ');
1634
1635       /* deal with strings... */
1636       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN))
1637         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1638
1639       /* deal with invisible passwords */
1640       else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS))
1641         build_string(strptr, strptr_i, "*", 0, ' ');
1642
1643       /*
1644        * deal with limit; note we cannot include the limit parameter if we're
1645        * removing it
1646        */
1647       else if ((MB_TYPE(mbuf, i) & (MODE_ADD | MODE_LIMIT)) ==
1648                (MODE_ADD | MODE_LIMIT))
1649         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1650     }
1651
1652     /* send the messages off to their destination */
1653     if (mbuf->mb_dest & MODEBUF_DEST_HACK2)
1654       sendto_opmask_butone(0, SNO_HACK2, "HACK(2): %s MODE %s %s%s%s%s%s%s "
1655                            "[%Tu]",
1656 #ifdef HEAD_IN_SAND_SNOTICES
1657                            cli_name(mbuf->mb_source),
1658 #else
1659                            cli_name(app_source),
1660 #endif
1661                            mbuf->mb_channel->chname,
1662                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1663                            addbuf, remstr, addstr,
1664                            mbuf->mb_channel->creationtime);
1665
1666     if (mbuf->mb_dest & MODEBUF_DEST_HACK3)
1667       sendto_opmask_butone(0, SNO_HACK3, "BOUNCE or HACK(3): %s MODE %s "
1668                            "%s%s%s%s%s%s [%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, rembuf_i ? "-" : "",
1675                            rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr,
1676                            mbuf->mb_channel->creationtime);
1677
1678     if (mbuf->mb_dest & MODEBUF_DEST_HACK4)
1679       sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s "
1680                            "[%Tu]",
1681 #ifdef HEAD_IN_SAND_SNOTICES
1682                            cli_name(mbuf->mb_source),
1683 #else
1684                            cli_name(app_source),
1685 #endif
1686                            mbuf->mb_channel->chname,
1687                            rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1688                            addbuf, remstr, addstr,
1689                            mbuf->mb_channel->creationtime);
1690
1691     if (mbuf->mb_dest & MODEBUF_DEST_LOG)
1692       log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE,
1693                 "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source,
1694                 mbuf->mb_channel, rembuf_i ? "-" : "", rembuf,
1695                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1696
1697     if (mbuf->mb_dest & MODEBUF_DEST_CHANNEL)
1698       sendcmdto_channel_butserv_butone(app_source, CMD_MODE, mbuf->mb_channel, NULL,
1699                                 "%H %s%s%s%s%s%s", mbuf->mb_channel,
1700                                 rembuf_i ? "-" : "", rembuf,
1701                                 addbuf_i ? "+" : "", addbuf, remstr, addstr);
1702   }
1703
1704   /* Now are we supposed to propagate to other servers? */
1705   if (mbuf->mb_dest & MODEBUF_DEST_SERVER) {
1706     /* set up parameter string */
1707     addstr[0] = '\0';
1708     addstr_i = 0;
1709     remstr[0] = '\0';
1710     remstr_i = 0;
1711
1712     /*
1713      * limit is supressed if we're removing it; we have to figure out which
1714      * direction is the direction for it to be removed, though...
1715      */
1716     limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD;
1717
1718     for (i = 0; i < mbuf->mb_count; i++) {
1719       if (MB_TYPE(mbuf, i) & MODE_SAVE)
1720         continue;
1721
1722       if (MB_TYPE(mbuf, i) & MODE_ADD) { /* adding or removing? */
1723         strptr = addstr;
1724         strptr_i = &addstr_i;
1725       } else {
1726         strptr = remstr;
1727         strptr_i = &remstr_i;
1728       }
1729
1730       /* deal with modes that take clients */
1731       if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE))
1732         build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' ');
1733
1734       /* deal with modes that take strings */
1735       else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS))
1736         build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' ');
1737
1738       /*
1739        * deal with the limit.  Logic here is complicated; if HACK2 is set,
1740        * we're bouncing the mode, so sense is reversed, and we have to
1741        * include the original limit if it looks like it's being removed
1742        */
1743       else if ((MB_TYPE(mbuf, i) & limitdel) == limitdel)
1744         build_string(strptr, strptr_i, limitbuf, 0, ' ');
1745     }
1746
1747     /* we were told to deop the source */
1748     if (mbuf->mb_dest & MODEBUF_DEST_DEOP) {
1749       addbuf[addbuf_i++] = 'o'; /* remember, sense is reversed */
1750       addbuf[addbuf_i] = '\0'; /* terminate the string... */
1751       build_string(addstr, &addstr_i, NumNick(mbuf->mb_source), ' ');
1752
1753       /* mark that we've done this, so we don't do it again */
1754       mbuf->mb_dest &= ~MODEBUF_DEST_DEOP;
1755     }
1756
1757     if (mbuf->mb_dest & MODEBUF_DEST_OPMODE) {
1758       /* If OPMODE was set, we're propagating the mode as an OPMODE message */
1759       sendcmdto_serv_butone(mbuf->mb_source, CMD_OPMODE, mbuf->mb_connect,
1760                             "%H %s%s%s%s%s%s", mbuf->mb_channel,
1761                             rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1762                             addbuf, remstr, addstr);
1763     } else if (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) {
1764       /*
1765        * If HACK2 was set, we're bouncing; we send the MODE back to the
1766        * connection we got it from with the senses reversed and a TS of 0;
1767        * origin is us
1768        */
1769       sendcmdto_one(&me, CMD_MODE, mbuf->mb_connect, "%H %s%s%s%s%s%s %Tu",
1770                     mbuf->mb_channel, addbuf_i ? "-" : "", addbuf,
1771                     rembuf_i ? "+" : "", rembuf, addstr, remstr,
1772                     mbuf->mb_channel->creationtime);
1773     } else {
1774       /*
1775        * We're propagating a normal MODE command to the rest of the network;
1776        * we send the actual channel TS unless this is a HACK3 or a HACK4
1777        */
1778       if (IsServer(mbuf->mb_source))
1779         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1780                               "%H %s%s%s%s%s%s %Tu", mbuf->mb_channel,
1781                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1782                               addbuf, remstr, addstr,
1783                               (mbuf->mb_dest & MODEBUF_DEST_HACK4) ? 0 :
1784                               mbuf->mb_channel->creationtime);
1785       else
1786         sendcmdto_serv_butone(mbuf->mb_source, CMD_MODE, mbuf->mb_connect,
1787                               "%H %s%s%s%s%s%s", mbuf->mb_channel,
1788                               rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "",
1789                               addbuf, remstr, addstr);
1790     }
1791   }
1792
1793   /* We've drained the ModeBuf... */
1794   mbuf->mb_add = 0;
1795   mbuf->mb_rem = 0;
1796   mbuf->mb_count = 0;
1797
1798   /* reinitialize the mode-with-arg slots */
1799   for (i = 0; i < MAXMODEPARAMS; i++) {
1800     /* If we saved any, pack them down */
1801     if (MB_TYPE(mbuf, i) & MODE_SAVE) {
1802       mbuf->mb_modeargs[mbuf->mb_count] = mbuf->mb_modeargs[i];
1803       MB_TYPE(mbuf, mbuf->mb_count) &= ~MODE_SAVE; /* don't save anymore */
1804
1805       if (mbuf->mb_count++ == i) /* don't overwrite our hard work */
1806         continue;
1807     } else if (MB_TYPE(mbuf, i) & MODE_FREE)
1808       MyFree(MB_STRING(mbuf, i)); /* free string if needed */
1809
1810     MB_TYPE(mbuf, i) = 0;
1811     MB_UINT(mbuf, i) = 0;
1812   }
1813
1814   /* If we're supposed to flush it all, do so--all hail tail recursion */
1815   if (all && mbuf->mb_count)
1816     return modebuf_flush_int(mbuf, 1);
1817
1818   return 0;
1819 }
1820
1821 /*
1822  * This routine just initializes a ModeBuf structure with the information
1823  * needed and the options given.
1824  */
1825 void
1826 modebuf_init(struct ModeBuf *mbuf, struct Client *source,
1827              struct Client *connect, struct Channel *chan, unsigned int dest)
1828 {
1829   int i;
1830
1831   assert(0 != mbuf);
1832   assert(0 != source);
1833   assert(0 != chan);
1834   assert(0 != dest);
1835
1836   mbuf->mb_add = 0;
1837   mbuf->mb_rem = 0;
1838   mbuf->mb_source = source;
1839   mbuf->mb_connect = connect;
1840   mbuf->mb_channel = chan;
1841   mbuf->mb_dest = dest;
1842   mbuf->mb_count = 0;
1843
1844   /* clear each mode-with-parameter slot */
1845   for (i = 0; i < MAXMODEPARAMS; i++) {
1846     MB_TYPE(mbuf, i) = 0;
1847     MB_UINT(mbuf, i) = 0;
1848   }
1849 }
1850
1851 /*
1852  * This routine simply adds modes to be added or deleted; do a binary OR
1853  * with either MODE_ADD or MODE_DEL
1854  */
1855 void
1856 modebuf_mode(struct ModeBuf *mbuf, unsigned int mode)
1857 {
1858   assert(0 != mbuf);
1859   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1860
1861   mode &= (MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | MODE_MODERATED |
1862            MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY);
1863
1864   if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */
1865     return;
1866
1867   if (mode & MODE_ADD) {
1868     mbuf->mb_rem &= ~mode;
1869     mbuf->mb_add |= mode;
1870   } else {
1871     mbuf->mb_add &= ~mode;
1872     mbuf->mb_rem |= mode;
1873   }
1874 }
1875
1876 /*
1877  * This routine adds a mode to be added or deleted that takes a unsigned
1878  * int parameter; mode may *only* be the relevant mode flag ORed with one
1879  * of MODE_ADD or MODE_DEL
1880  */
1881 void
1882 modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint)
1883 {
1884   assert(0 != mbuf);
1885   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1886
1887   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1888   MB_UINT(mbuf, mbuf->mb_count) = uint;
1889
1890   /* when we've reached the maximal count, flush the buffer */
1891   if (++mbuf->mb_count >=
1892       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1893     modebuf_flush_int(mbuf, 0);
1894 }
1895
1896 /*
1897  * This routine adds a mode to be added or deleted that takes a string
1898  * parameter; mode may *only* be the relevant mode flag ORed with one of
1899  * MODE_ADD or MODE_DEL
1900  */
1901 void
1902 modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, char *string,
1903                     int free)
1904 {
1905   assert(0 != mbuf);
1906   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1907
1908   MB_TYPE(mbuf, mbuf->mb_count) = mode | (free ? MODE_FREE : 0);
1909   MB_STRING(mbuf, mbuf->mb_count) = string;
1910
1911   /* when we've reached the maximal count, flush the buffer */
1912   if (++mbuf->mb_count >=
1913       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1914     modebuf_flush_int(mbuf, 0);
1915 }
1916
1917 /*
1918  * This routine adds a mode to be added or deleted that takes a client
1919  * parameter; mode may *only* be the relevant mode flag ORed with one of
1920  * MODE_ADD or MODE_DEL
1921  */
1922 void
1923 modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode,
1924                     struct Client *client)
1925 {
1926   assert(0 != mbuf);
1927   assert(0 != (mode & (MODE_ADD | MODE_DEL)));
1928
1929   MB_TYPE(mbuf, mbuf->mb_count) = mode;
1930   MB_CLIENT(mbuf, mbuf->mb_count) = client;
1931
1932   /* when we've reached the maximal count, flush the buffer */
1933   if (++mbuf->mb_count >=
1934       (MAXMODEPARAMS - (mbuf->mb_dest & MODEBUF_DEST_DEOP ? 1 : 0)))
1935     modebuf_flush_int(mbuf, 0);
1936 }
1937
1938 /*
1939  * This is the exported binding for modebuf_flush()
1940  */
1941 int
1942 modebuf_flush(struct ModeBuf *mbuf)
1943 {
1944   return modebuf_flush_int(mbuf, 1);
1945 }
1946
1947 /*
1948  * This extracts the simple modes contained in mbuf
1949  */
1950 void
1951 modebuf_extract(struct ModeBuf *mbuf, char *buf)
1952 {
1953   static int flags[] = {
1954 /*  MODE_CHANOP,        'o', */
1955 /*  MODE_VOICE,         'v', */
1956     MODE_PRIVATE,       'p',
1957     MODE_SECRET,        's',
1958     MODE_MODERATED,     'm',
1959     MODE_TOPICLIMIT,    't',
1960     MODE_INVITEONLY,    'i',
1961     MODE_NOPRIVMSGS,    'n',
1962     MODE_KEY,           'k',
1963     MODE_APASS,         'A',
1964     MODE_UPASS,         'u',
1965 /*  MODE_BAN,           'b', */
1966     MODE_LIMIT,         'l',
1967     MODE_REGONLY,       'r',
1968     0x0, 0x0
1969   };
1970   unsigned int add;
1971   int i, bufpos = 0, len;
1972   int *flag_p;
1973   char *key = 0, limitbuf[20];
1974   char *apass, *upass;
1975
1976   assert(0 != mbuf);
1977   assert(0 != buf);
1978
1979   buf[0] = '\0';
1980
1981   add = mbuf->mb_add;
1982
1983   for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */
1984     if (MB_TYPE(mbuf, i) & MODE_ADD) {
1985       add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS);
1986
1987       if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */
1988         key = MB_STRING(mbuf, i);
1989       else if (MB_TYPE(mbuf, i) & MODE_LIMIT)
1990         ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i));
1991       else if (MB_TYPE(mbuf, i) & MODE_UPASS)
1992         upass = MB_STRING(mbuf, i);
1993       else if (MB_TYPE(mbuf, i) & MODE_APASS)
1994         apass = MB_STRING(mbuf, i);
1995     }
1996   }
1997
1998   if (!add)
1999     return;
2000
2001   buf[bufpos++] = '+'; /* start building buffer */
2002
2003   for (flag_p = flags; flag_p[0]; flag_p += 2)
2004     if (*flag_p & add)
2005       buf[bufpos++] = flag_p[1];
2006
2007   for (i = 0, len = bufpos; i < len; i++) {
2008     if (buf[i] == 'k')
2009       build_string(buf, &bufpos, key, 0, ' ');
2010     else if (buf[i] == 'l')
2011       build_string(buf, &bufpos, limitbuf, 0, ' ');
2012     else if (buf[i] == 'u')
2013       build_string(buf, &bufpos, upass, 0, ' ');
2014     else if (buf[i] == 'A')
2015       build_string(buf, &bufpos, apass, 0, ' ');
2016   }
2017
2018   buf[bufpos] = '\0';
2019
2020   return;
2021 }
2022
2023 /*
2024  * Simple function to invalidate bans
2025  */
2026 void
2027 mode_ban_invalidate(struct Channel *chan)
2028 {
2029   struct Membership *member;
2030
2031   for (member = chan->members; member; member = member->next_member)
2032     ClearBanValid(member);
2033 }
2034
2035 /*
2036  * Simple function to drop invite structures
2037  */
2038 void
2039 mode_invite_clear(struct Channel *chan)
2040 {
2041   while (chan->invites)
2042     del_invite(chan->invites->value.cptr, chan);
2043 }
2044
2045 /* What we've done for mode_parse so far... */
2046 #define DONE_LIMIT      0x01    /* We've set the limit */
2047 #define DONE_KEY        0x02    /* We've set the key */
2048 #define DONE_BANLIST    0x04    /* We've sent the ban list */
2049 #define DONE_NOTOPER    0x08    /* We've sent a "Not oper" error */
2050 #define DONE_BANCLEAN   0x10    /* We've cleaned bans... */
2051 #define DONE_UPASS      0x20    /* We've set user pass */
2052 #define DONE_APASS      0x40    /* We've set admin pass */
2053
2054 struct ParseState {
2055   struct ModeBuf *mbuf;
2056   struct Client *cptr;
2057   struct Client *sptr;
2058   struct Channel *chptr;
2059   struct Membership *member;
2060   int parc;
2061   char **parv;
2062   unsigned int flags;
2063   unsigned int dir;
2064   unsigned int done;
2065   unsigned int add;
2066   unsigned int del;
2067   int args_used;
2068   int max_args;
2069   int numbans;
2070   struct SLink banlist[MAXPARA];
2071   struct {
2072     unsigned int flag;
2073     struct Client *client;
2074   } cli_change[MAXPARA];
2075 };
2076
2077 /*
2078  * Here's a helper function to deal with sending along "Not oper" or
2079  * "Not member" messages
2080  */
2081 static void
2082 send_notoper(struct ParseState *state)
2083 {
2084   if (state->done & DONE_NOTOPER)
2085     return;
2086
2087   send_reply(state->sptr, (state->flags & MODE_PARSE_NOTOPER) ?
2088              ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL, state->chptr->chname);
2089
2090   state->done |= DONE_NOTOPER;
2091 }
2092
2093 /*
2094  * Helper function to convert limits
2095  */
2096 static void
2097 mode_parse_limit(struct ParseState *state, int *flag_p)
2098 {
2099   unsigned int t_limit;
2100
2101   if (state->dir == MODE_ADD) { /* convert arg only if adding limit */
2102     if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
2103       return;
2104
2105     if (state->parc <= 0) { /* warn if not enough args */
2106       if (MyUser(state->sptr))
2107         need_more_params(state->sptr, "MODE +l");
2108       return;
2109     }
2110
2111     t_limit = strtoul(state->parv[state->args_used++], 0, 10); /* grab arg */
2112     state->parc--;
2113     state->max_args--;
2114
2115     if (!(state->flags & MODE_PARSE_WIPEOUT) &&
2116         (!t_limit || t_limit == state->chptr->mode.limit))
2117       return;
2118   } else
2119     t_limit = state->chptr->mode.limit;
2120
2121   /* If they're not an oper, they can't change modes */
2122   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2123     send_notoper(state);
2124     return;
2125   }
2126
2127   if (state->done & DONE_LIMIT) /* allow limit to be set only once */
2128     return;
2129   state->done |= DONE_LIMIT;
2130
2131   if (!state->mbuf)
2132     return;
2133
2134   modebuf_mode_uint(state->mbuf, state->dir | flag_p[0], t_limit);
2135
2136   if (state->flags & MODE_PARSE_SET) { /* set the limit */
2137     if (state->dir & MODE_ADD) {
2138       state->chptr->mode.mode |= flag_p[0];
2139       state->chptr->mode.limit = t_limit;
2140     } else {
2141       state->chptr->mode.mode &= ~flag_p[0];
2142       state->chptr->mode.limit = 0;
2143     }
2144   }
2145 }
2146
2147 /*
2148  * Helper function to convert keys
2149  */
2150 static void
2151 mode_parse_key(struct ParseState *state, int *flag_p)
2152 {
2153   char *t_str, *s;
2154   int t_len;
2155
2156   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2157     return;
2158
2159   if (state->parc <= 0) { /* warn if not enough args */
2160     if (MyUser(state->sptr))
2161       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2162                        "MODE -k");
2163     return;
2164   }
2165
2166   t_str = state->parv[state->args_used++]; /* grab arg */
2167   state->parc--;
2168   state->max_args--;
2169
2170   /* If they're not an oper, they can't change modes */
2171   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2172     send_notoper(state);
2173     return;
2174   }
2175
2176   if (state->done & DONE_KEY) /* allow key to be set only once */
2177     return;
2178   state->done |= DONE_KEY;
2179
2180   t_len = KEYLEN + 1;
2181
2182   /* clean up the key string */
2183   s = t_str;
2184   while (*++s > ' ' && *s != ':' && --t_len)
2185     ;
2186   *s = '\0';
2187
2188   if (!*t_str) { /* warn if empty */
2189     if (MyUser(state->sptr))
2190       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +k" :
2191                        "MODE -k");
2192     return;
2193   }
2194
2195   if (!state->mbuf)
2196     return;
2197
2198   /* can't add a key if one is set, nor can one remove the wrong key */
2199   if (!(state->flags & MODE_PARSE_FORCE))
2200     if ((state->dir == MODE_ADD && *state->chptr->mode.key) ||
2201         (state->dir == MODE_DEL &&
2202          ircd_strcmp(state->chptr->mode.key, t_str))) {
2203       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2204       return;
2205     }
2206
2207   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2208       !ircd_strcmp(state->chptr->mode.key, t_str))
2209     return; /* no key change */
2210
2211   if (state->flags & MODE_PARSE_BOUNCE) {
2212     if (*state->chptr->mode.key) /* reset old key */
2213       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2214                           state->chptr->mode.key, 0);
2215     else /* remove new bogus key */
2216       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2217   } else /* send new key */
2218     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2219
2220   if (state->flags & MODE_PARSE_SET) {
2221     if (state->dir == MODE_ADD) /* set the new key */
2222       ircd_strncpy(state->chptr->mode.key, t_str, KEYLEN);
2223     else /* remove the old key */
2224       *state->chptr->mode.key = '\0';
2225   }
2226 }
2227
2228 /*
2229  * Helper function to convert user passes
2230  */
2231 static void
2232 mode_parse_upass(struct ParseState *state, int *flag_p)
2233 {
2234   char *t_str, *s;
2235   int t_len;
2236
2237   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2238     return;
2239
2240   if (state->parc <= 0) { /* warn if not enough args */
2241     if (MyUser(state->sptr))
2242       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2243                        "MODE -u");
2244     return;
2245   }
2246
2247   t_str = state->parv[state->args_used++]; /* grab arg */
2248   state->parc--;
2249   state->max_args--;
2250
2251   /* If they're not an oper, they can't change modes */
2252   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2253     send_notoper(state);
2254     return;
2255   }
2256
2257   /* If they are not the channel manager, they are not allowed to change it */
2258   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2259     if (*state->chptr->mode.apass) {
2260       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2261           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2262     } else {
2263       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2264           "Re-create the channel.  The channel must be *empty* for",
2265           TStime() - state->chptr->creationtime >= 171000 ? "48 contigious hours" : "a minute or two",
2266           "before it can be recreated.");
2267     }
2268     return;
2269   }
2270  
2271   if (state->done & DONE_UPASS) /* allow upass to be set only once */
2272     return;
2273   state->done |= DONE_UPASS;
2274
2275   t_len = PASSLEN + 1;
2276
2277   /* clean up the upass string */
2278   s = t_str;
2279   while (*++s > ' ' && *s != ':' && --t_len)
2280     ;
2281   *s = '\0';
2282
2283   if (!*t_str) { /* warn if empty */
2284     if (MyUser(state->sptr))
2285       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" :
2286                        "MODE -u");
2287     return;
2288   }
2289
2290   if (!state->mbuf)
2291     return;
2292
2293   if (!(state->flags & MODE_PARSE_FORCE))
2294     /* can't add the upass while apass is not set */
2295     if (state->dir == MODE_ADD && !*state->chptr->mode.apass) {
2296       send_reply(state->sptr, ERR_UPASSNOTSET, state->chptr->chname, state->chptr->chname);
2297       return;
2298     }
2299     /* can't add a upass if one is set, nor can one remove the wrong upass */
2300     if ((state->dir == MODE_ADD && *state->chptr->mode.upass) ||
2301         (state->dir == MODE_DEL &&
2302          ircd_strcmp(state->chptr->mode.upass, t_str))) {
2303       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2304       return;
2305     }
2306
2307   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2308       !ircd_strcmp(state->chptr->mode.upass, t_str))
2309     return; /* no upass change */
2310
2311   if (state->flags & MODE_PARSE_BOUNCE) {
2312     if (*state->chptr->mode.upass) /* reset old upass */
2313       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2314                           state->chptr->mode.upass, 0);
2315     else /* remove new bogus upass */
2316       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2317   } else /* send new upass */
2318     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2319
2320   if (state->flags & MODE_PARSE_SET) {
2321     if (state->dir == MODE_ADD) /* set the new upass */
2322       ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN);
2323     else /* remove the old upass */
2324       *state->chptr->mode.upass = '\0';
2325   }
2326 }
2327
2328 /*
2329  * Helper function to convert admin passes
2330  */
2331 static void
2332 mode_parse_apass(struct ParseState *state, int *flag_p)
2333 {
2334   char *t_str, *s;
2335   int t_len;
2336
2337   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2338     return;
2339
2340   if (state->parc <= 0) { /* warn if not enough args */
2341     if (MyUser(state->sptr))
2342       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2343                        "MODE -A");
2344     return;
2345   }
2346
2347   t_str = state->parv[state->args_used++]; /* grab arg */
2348   state->parc--;
2349   state->max_args--;
2350
2351   /* If they're not an oper, they can't change modes */
2352   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2353     send_notoper(state);
2354     return;
2355   }
2356
2357   /* Don't allow to change the Apass if the channel is older than 48 hours. */
2358   if (TStime() - state->chptr->creationtime >= 172800 && !IsAnOper(state->sptr)) {
2359     send_reply(state->sptr, ERR_CHANSECURED, state->chptr->chname);
2360     return;
2361   }
2362
2363   /* If they are not the channel manager, they are not allowed to change it */
2364   if (MyUser(state->sptr) && !IsChannelManager(state->member)) {
2365     if (*state->chptr->mode.apass) {
2366       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2367           "Use /JOIN", state->chptr->chname, "<AdminPass>.");
2368     } else {
2369       send_reply(state->sptr, ERR_NOTMANAGER, state->chptr->chname,
2370           "Re-create the channel.  The channel must be *empty* for",
2371           "at least a whole minute", "before it can be recreated.");
2372     }
2373     return;
2374   }
2375  
2376   if (state->done & DONE_APASS) /* allow apass to be set only once */
2377     return;
2378   state->done |= DONE_APASS;
2379
2380   t_len = PASSLEN + 1;
2381
2382   /* clean up the apass string */
2383   s = t_str;
2384   while (*++s > ' ' && *s != ':' && --t_len)
2385     ;
2386   *s = '\0';
2387
2388   if (!*t_str) { /* warn if empty */
2389     if (MyUser(state->sptr))
2390       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" :
2391                        "MODE -A");
2392     return;
2393   }
2394
2395   if (!state->mbuf)
2396     return;
2397
2398   if (!(state->flags & MODE_PARSE_FORCE)) {
2399     /* can't remove the apass while upass is still set */
2400     if (state->dir == MODE_DEL && *state->chptr->mode.upass) {
2401       send_reply(state->sptr, ERR_UPASSSET, state->chptr->chname, state->chptr->chname);
2402       return;
2403     }
2404     /* can't add an apass if one is set, nor can one remove the wrong apass */
2405     if ((state->dir == MODE_ADD && *state->chptr->mode.apass) ||
2406         (state->dir == MODE_DEL && ircd_strcmp(state->chptr->mode.apass, t_str))) {
2407       send_reply(state->sptr, ERR_KEYSET, state->chptr->chname);
2408       return;
2409     }
2410   }
2411
2412   if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
2413       !ircd_strcmp(state->chptr->mode.apass, t_str))
2414     return; /* no apass change */
2415
2416   if (state->flags & MODE_PARSE_BOUNCE) {
2417     if (*state->chptr->mode.apass) /* reset old apass */
2418       modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0],
2419                           state->chptr->mode.apass, 0);
2420     else /* remove new bogus apass */
2421       modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
2422   } else /* send new apass */
2423     modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
2424
2425   if (state->flags & MODE_PARSE_SET) {
2426     if (state->dir == MODE_ADD) { /* set the new apass */
2427       /* Make it VERY clear to the user that this is a one-time password */
2428       ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN);
2429       if (MyUser(state->sptr)) {
2430         send_reply(state->sptr, RPL_APASSWARN,
2431             "Channel Admin password (+A) set to '", state->chptr->mode.apass, "'. ",
2432             "Are you SURE you want to use this as Admin password? ",
2433             "You will NOT be able to change this password anymore once the channel is more than 48 hours old!");
2434         send_reply(state->sptr, RPL_APASSWARN,
2435             "Use \"/MODE ", state->chptr->chname, " -A ", state->chptr->mode.apass,
2436             "\" to remove the password and then immediatly set a new one. "
2437             "IMPORTANT: YOU CANNOT RECOVER THIS PASSWORD, EVER; "
2438             "WRITE THE PASSWORD DOWN (don't store this rescue password on disk)! "
2439             "Now set the channel user password (+u).");
2440       }
2441     } else { /* remove the old apass */
2442       *state->chptr->mode.apass = '\0';
2443       if (MyUser(state->sptr))
2444         send_reply(state->sptr, RPL_APASSWARN,
2445             "WARNING: You removed the channel Admin password MODE (+A). ",
2446             "If you would disconnect or leave the channel without setting a new password then you will ",
2447             "not be able to set it again and lose ownership of this channel! ",
2448             "SET A NEW PASSWORD NOW!", "");
2449     }
2450   }
2451 }
2452
2453 /*
2454  * Helper function to convert bans
2455  */
2456 static void
2457 mode_parse_ban(struct ParseState *state, int *flag_p)
2458 {
2459   char *t_str, *s;
2460   struct SLink *ban, *newban = 0;
2461
2462   if (state->parc <= 0) { /* Not enough args, send ban list */
2463     if (MyUser(state->sptr) && !(state->done & DONE_BANLIST)) {
2464       send_ban_list(state->sptr, state->chptr);
2465       state->done |= DONE_BANLIST;
2466     }
2467
2468     return;
2469   }
2470
2471   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2472     return;
2473
2474   t_str = state->parv[state->args_used++]; /* grab arg */
2475   state->parc--;
2476   state->max_args--;
2477
2478   /* If they're not an oper, they can't change modes */
2479   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2480     send_notoper(state);
2481     return;
2482   }
2483
2484   if ((s = strchr(t_str, ' ')))
2485     *s = '\0';
2486
2487   if (!*t_str || *t_str == ':') { /* warn if empty */
2488     if (MyUser(state->sptr))
2489       need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +b" :
2490                        "MODE -b");
2491     return;
2492   }
2493
2494   t_str = collapse(pretty_mask(t_str));
2495
2496   /* remember the ban for the moment... */
2497   if (state->dir == MODE_ADD) {
2498     newban = state->banlist + (state->numbans++);
2499     newban->next = 0;
2500
2501     DupString(newban->value.ban.banstr, t_str);
2502     newban->value.ban.who = cli_name(state->sptr);
2503     newban->value.ban.when = TStime();
2504
2505     newban->flags = CHFL_BAN | MODE_ADD;
2506
2507     if ((s = strrchr(t_str, '@')) && check_if_ipmask(s + 1))
2508       newban->flags |= CHFL_BAN_IPMASK;
2509   }
2510
2511   if (!state->chptr->banlist) {
2512     state->chptr->banlist = newban; /* add our ban with its flags */
2513     state->done |= DONE_BANCLEAN;
2514     return;
2515   }
2516
2517   /* Go through all bans */
2518   for (ban = state->chptr->banlist; ban; ban = ban->next) {
2519     /* first, clean the ban flags up a bit */
2520     if (!(state->done & DONE_BANCLEAN))
2521       /* Note: We're overloading *lots* of bits here; be careful! */
2522       ban->flags &= ~(MODE_ADD | MODE_DEL | CHFL_BAN_OVERLAPPED);
2523
2524     /* Bit meanings:
2525      *
2526      * MODE_ADD            - Ban was added; if we're bouncing modes,
2527      *                       then we'll remove it below; otherwise,
2528      *                       we'll have to allocate a real ban
2529      *
2530      * MODE_DEL            - Ban was marked for deletion; if we're
2531      *                       bouncing modes, we'll have to re-add it,
2532      *                       otherwise, we'll have to remove it
2533      *
2534      * CHFL_BAN_OVERLAPPED - The ban we added turns out to overlap
2535      *                       with a ban already set; if we're
2536      *                       bouncing modes, we'll have to bounce
2537      *                       this one; otherwise, we'll just ignore
2538      *                       it when we process added bans
2539      */
2540
2541     if (state->dir == MODE_DEL && !ircd_strcmp(ban->value.ban.banstr, t_str)) {
2542       ban->flags |= MODE_DEL; /* delete one ban */
2543
2544       if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2545         break;
2546     } else if (state->dir == MODE_ADD) {
2547       /* if the ban already exists, don't worry about it */
2548       if (!ircd_strcmp(ban->value.ban.banstr, t_str)) {
2549         newban->flags &= ~MODE_ADD; /* don't add ban at all */
2550         MyFree(newban->value.ban.banstr); /* stopper a leak */
2551         state->numbans--; /* deallocate last ban */
2552         if (state->done & DONE_BANCLEAN) /* If we're cleaning, finish */
2553           break;
2554       } else if (!mmatch(ban->value.ban.banstr, t_str)) {
2555         if (!(ban->flags & MODE_DEL))
2556           newban->flags |= CHFL_BAN_OVERLAPPED; /* our ban overlaps */
2557       } else if (!mmatch(t_str, ban->value.ban.banstr))
2558         ban->flags |= MODE_DEL; /* mark ban for deletion: overlapping */
2559
2560       if (!ban->next && (newban->flags & MODE_ADD)) {
2561         ban->next = newban; /* add our ban with its flags */
2562         break; /* get out of loop */
2563       }
2564     }
2565   }
2566   state->done |= DONE_BANCLEAN;
2567 }
2568
2569 /*
2570  * This is the bottom half of the ban processor
2571  */
2572 static void
2573 mode_process_bans(struct ParseState *state)
2574 {
2575   struct SLink *ban, *newban, *prevban, *nextban;
2576   int count = 0;
2577   int len = 0;
2578   int banlen;
2579   int changed = 0;
2580
2581   for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) {
2582     count++;
2583     banlen = strlen(ban->value.ban.banstr);
2584     len += banlen;
2585     nextban = ban->next;
2586
2587     if ((ban->flags & (MODE_DEL | MODE_ADD)) == (MODE_DEL | MODE_ADD)) {
2588       if (prevban)
2589         prevban->next = 0; /* Break the list; ban isn't a real ban */
2590       else
2591         state->chptr->banlist = 0;
2592
2593       count--;
2594       len -= banlen;
2595
2596       MyFree(ban->value.ban.banstr);
2597
2598       continue;
2599     } else if (ban->flags & MODE_DEL) { /* Deleted a ban? */
2600       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
2601                           ban->value.ban.banstr,
2602                           state->flags & MODE_PARSE_SET);
2603
2604       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
2605         if (prevban) /* clip it out of the list... */
2606           prevban->next = ban->next;
2607         else
2608           state->chptr->banlist = ban->next;
2609
2610         count--;
2611         len -= banlen;
2612
2613         MyFree(ban->value.ban.who);
2614         free_link(ban);
2615
2616         changed++;
2617         continue; /* next ban; keep prevban like it is */
2618       } else
2619         ban->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* unset other flags */
2620     } else if (ban->flags & MODE_ADD) { /* adding a ban? */
2621       if (prevban)
2622         prevban->next = 0; /* Break the list; ban isn't a real ban */
2623       else
2624         state->chptr->banlist = 0;
2625
2626       /* If we're supposed to ignore it, do so. */
2627       if (ban->flags & CHFL_BAN_OVERLAPPED &&
2628           !(state->flags & MODE_PARSE_BOUNCE)) {
2629         count--;
2630         len -= banlen;
2631
2632         MyFree(ban->value.ban.banstr);
2633       } else {
2634         if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
2635             (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
2636              count >= feature_int(FEAT_MAXBANS))) {
2637           send_reply(state->sptr, ERR_BANLISTFULL, state->chptr->chname,
2638                      ban->value.ban.banstr);
2639           count--;
2640           len -= banlen;
2641
2642           MyFree(ban->value.ban.banstr);
2643         } else {
2644           /* add the ban to the buffer */
2645           modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
2646                               ban->value.ban.banstr,
2647                               !(state->flags & MODE_PARSE_SET));
2648
2649           if (state->flags & MODE_PARSE_SET) { /* create a new ban */
2650             newban = make_link();
2651             newban->value.ban.banstr = ban->value.ban.banstr;
2652             DupString(newban->value.ban.who, ban->value.ban.who);
2653             newban->value.ban.when = ban->value.ban.when;
2654             newban->flags = ban->flags & (CHFL_BAN | CHFL_BAN_IPMASK);
2655
2656             newban->next = state->chptr->banlist; /* and link it in */
2657             state->chptr->banlist = newban;
2658
2659             changed++;
2660           }
2661         }
2662       }
2663     }
2664
2665     prevban = ban;
2666   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
2667
2668   if (changed) /* if we changed the ban list, we must invalidate the bans */
2669     mode_ban_invalidate(state->chptr);
2670 }
2671
2672 /*
2673  * Helper function to process client changes
2674  */
2675 static void
2676 mode_parse_client(struct ParseState *state, int *flag_p)
2677 {
2678   char *t_str;
2679   struct Client *acptr;
2680   int i;
2681
2682   if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */
2683     return;
2684
2685   if (state->parc <= 0) /* return if not enough args */
2686     return;
2687
2688   t_str = state->parv[state->args_used++]; /* grab arg */
2689   state->parc--;
2690   state->max_args--;
2691
2692   /* If they're not an oper, they can't change modes */
2693   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2694     send_notoper(state);
2695     return;
2696   }
2697
2698   if (MyUser(state->sptr)) /* find client we're manipulating */
2699     acptr = find_chasing(state->sptr, t_str, NULL);
2700   else
2701     acptr = findNUser(t_str);
2702
2703   if (!acptr)
2704     return; /* find_chasing() already reported an error to the user */
2705
2706   for (i = 0; i < MAXPARA; i++) /* find an element to stick them in */
2707     if (!state->cli_change[i].flag || (state->cli_change[i].client == acptr &&
2708                                        state->cli_change[i].flag & flag_p[0]))
2709       break; /* found a slot */
2710
2711   /* Store what we're doing to them */
2712   state->cli_change[i].flag = state->dir | flag_p[0];
2713   state->cli_change[i].client = acptr;
2714 }
2715
2716 /*
2717  * Helper function to process the changed client list
2718  */
2719 static void
2720 mode_process_clients(struct ParseState *state)
2721 {
2722   int i;
2723   struct Membership *member;
2724
2725   for (i = 0; state->cli_change[i].flag; i++) {
2726     assert(0 != state->cli_change[i].client);
2727
2728     /* look up member link */
2729     if (!(member = find_member_link(state->chptr,
2730                                     state->cli_change[i].client)) ||
2731         (MyUser(state->sptr) && IsZombie(member))) {
2732       if (MyUser(state->sptr))
2733         send_reply(state->sptr, ERR_USERNOTINCHANNEL,
2734                    cli_name(state->cli_change[i].client),
2735                    state->chptr->chname);
2736       continue;
2737     }
2738
2739     if ((state->cli_change[i].flag & MODE_ADD &&
2740          (state->cli_change[i].flag & member->status)) ||
2741         (state->cli_change[i].flag & MODE_DEL &&
2742          !(state->cli_change[i].flag & member->status)))
2743       continue; /* no change made, don't do anything */
2744
2745     /* see if the deop is allowed */
2746     if ((state->cli_change[i].flag & (MODE_DEL | MODE_CHANOP)) ==
2747         (MODE_DEL | MODE_CHANOP)) {
2748       /* prevent +k users from being deopped */
2749       if (IsChannelService(state->cli_change[i].client)) {
2750         if (state->flags & MODE_PARSE_FORCE) /* it was forced */
2751           sendto_opmask_butone(0, SNO_HACK4, "Deop of +k user on %H by %s",
2752                                state->chptr,
2753                                (IsServer(state->sptr) ? cli_name(state->sptr) :
2754                                 cli_name((cli_user(state->sptr))->server)));
2755
2756         else if (MyUser(state->sptr) && state->flags & MODE_PARSE_SET) {
2757           send_reply(state->sptr, ERR_ISCHANSERVICE,
2758                      cli_name(state->cli_change[i].client),
2759                      state->chptr->chname);
2760           continue;
2761         }
2762       }
2763
2764       /* check deop for local user */
2765       if (MyUser(state->sptr)) {
2766
2767         /* don't allow local opers to be deopped on local channels */
2768         if (state->cli_change[i].client != state->sptr &&
2769             IsLocalChannel(state->chptr->chname) &&
2770             HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) {
2771           send_reply(state->sptr, ERR_ISOPERLCHAN,
2772                      cli_name(state->cli_change[i].client),
2773                      state->chptr->chname);
2774           continue;
2775         }
2776
2777         /* don't allow to deop members with an op level that is <= our own level */
2778         if (state->sptr != state->cli_change[i].client          /* but allow to deop oneself */
2779                 && state->member
2780                 && OpLevel(member) <= OpLevel(state->member)) {
2781             int equal = (OpLevel(member) == OpLevel(state->member));
2782             send_reply(state->sptr, ERR_NOTLOWEROPLEVEL,
2783                        cli_name(state->cli_change[i].client),
2784                        state->chptr->chname,
2785                        OpLevel(state->member), OpLevel(member),
2786                        "deop", equal ? "the same" : "a higher");
2787           continue;
2788         }
2789       }
2790     }
2791
2792     /* set op-level of member being opped */
2793     if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) ==
2794         (MODE_ADD | MODE_CHANOP)) {
2795       /* If on a channel with upass set, someone with level x gives ops to someone else,
2796          then that person gets level x-1.  On other channels, where upass is not set,
2797          the level stays the same. */
2798       int level_increment = *state->chptr->mode.upass ? 1 : 0;
2799       /* Someone being opped by a server gets op-level 0 */
2800       int old_level = (state->member == NULL) ? -level_increment : OpLevel(state->member);
2801       SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + level_increment));
2802     }
2803
2804     /* accumulate the change */
2805     modebuf_mode_client(state->mbuf, state->cli_change[i].flag,
2806                         state->cli_change[i].client);
2807
2808     /* actually effect the change */
2809     if (state->flags & MODE_PARSE_SET) {
2810       if (state->cli_change[i].flag & MODE_ADD) {
2811         member->status |= (state->cli_change[i].flag &
2812                            (MODE_CHANOP | MODE_VOICE));
2813         if (state->cli_change[i].flag & MODE_CHANOP)
2814           ClearDeopped(member);
2815       } else
2816         member->status &= ~(state->cli_change[i].flag &
2817                             (MODE_CHANOP | MODE_VOICE));
2818     }
2819   } /* for (i = 0; state->cli_change[i].flags; i++) */
2820 }
2821
2822 /*
2823  * Helper function to process the simple modes
2824  */
2825 static void
2826 mode_parse_mode(struct ParseState *state, int *flag_p)
2827 {
2828   /* If they're not an oper, they can't change modes */
2829   if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
2830     send_notoper(state);
2831     return;
2832   }
2833
2834   if (!state->mbuf)
2835     return;
2836
2837   if (state->dir == MODE_ADD) {
2838     state->add |= flag_p[0];
2839     state->del &= ~flag_p[0];
2840
2841     if (flag_p[0] & MODE_SECRET) {
2842       state->add &= ~MODE_PRIVATE;
2843       state->del |= MODE_PRIVATE;
2844     } else if (flag_p[0] & MODE_PRIVATE) {
2845       state->add &= ~MODE_SECRET;
2846       state->del |= MODE_SECRET;
2847     }
2848   } else {
2849     state->add &= ~flag_p[0];
2850     state->del |= flag_p[0];
2851   }
2852
2853   assert(0 == (state->add & state->del));
2854   assert((MODE_SECRET | MODE_PRIVATE) !=
2855          (state->add & (MODE_SECRET | MODE_PRIVATE)));
2856 }
2857
2858 /*
2859  * This routine is intended to parse MODE or OPMODE commands and effect the
2860  * changes (or just build the bounce buffer).  We pass the starting offset
2861  * as a 
2862  */
2863 int
2864 mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
2865            struct Channel *chptr, int parc, char *parv[], unsigned int flags,
2866            struct Membership* member)
2867 {
2868   static int chan_flags[] = {
2869     MODE_CHANOP,        'o',
2870     MODE_VOICE,         'v',
2871     MODE_PRIVATE,       'p',
2872     MODE_SECRET,        's',
2873     MODE_MODERATED,     'm',
2874     MODE_TOPICLIMIT,    't',
2875     MODE_INVITEONLY,    'i',
2876     MODE_NOPRIVMSGS,    'n',
2877     MODE_KEY,           'k',
2878     MODE_APASS,         'A',
2879     MODE_UPASS,         'u',
2880     MODE_BAN,           'b',
2881     MODE_LIMIT,         'l',
2882     MODE_REGONLY,       'r',
2883     MODE_ADD,           '+',
2884     MODE_DEL,           '-',
2885     0x0, 0x0
2886   };
2887   int i;
2888   int *flag_p;
2889   unsigned int t_mode;
2890   char *modestr;
2891   struct ParseState state;
2892
2893   assert(0 != cptr);
2894   assert(0 != sptr);
2895   assert(0 != chptr);
2896   assert(0 != parc);
2897   assert(0 != parv);
2898
2899   state.mbuf = mbuf;
2900   state.cptr = cptr;
2901   state.sptr = sptr;
2902   state.chptr = chptr;
2903   state.member = member;
2904   state.parc = parc;
2905   state.parv = parv;
2906   state.flags = flags;
2907   state.dir = MODE_ADD;
2908   state.done = 0;
2909   state.add = 0;
2910   state.del = 0;
2911   state.args_used = 0;
2912   state.max_args = MAXMODEPARAMS;
2913   state.numbans = 0;
2914
2915   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
2916     state.banlist[i].next = 0;
2917     state.banlist[i].value.ban.banstr = 0;
2918     state.banlist[i].value.ban.who = 0;
2919     state.banlist[i].value.ban.when = 0;
2920     state.banlist[i].flags = 0;
2921     state.cli_change[i].flag = 0;
2922     state.cli_change[i].client = 0;
2923   }
2924
2925   modestr = state.parv[state.args_used++];
2926   state.parc--;
2927
2928   while (*modestr) {
2929     for (; *modestr; modestr++) {
2930       for (flag_p = chan_flags; flag_p[0]; flag_p += 2) /* look up flag */
2931         if (flag_p[1] == *modestr)
2932           break;
2933
2934       if (!flag_p[0]) { /* didn't find it?  complain and continue */
2935         if (MyUser(state.sptr))
2936           send_reply(state.sptr, ERR_UNKNOWNMODE, *modestr);
2937         continue;
2938       }
2939
2940       switch (*modestr) {
2941       case '+': /* switch direction to MODE_ADD */
2942       case '-': /* switch direction to MODE_DEL */
2943         state.dir = flag_p[0];
2944         break;
2945
2946       case 'l': /* deal with limits */
2947         mode_parse_limit(&state, flag_p);
2948         break;
2949
2950       case 'k': /* deal with keys */
2951         mode_parse_key(&state, flag_p);
2952         break;
2953
2954       case 'A': /* deal with Admin passes */
2955         mode_parse_apass(&state, flag_p);
2956         break;
2957
2958       case 'u': /* deal with user passes */
2959         mode_parse_upass(&state, flag_p);
2960         break;
2961
2962       case 'b': /* deal with bans */
2963         mode_parse_ban(&state, flag_p);
2964         break;
2965
2966       case 'o': /* deal with ops/voice */
2967       case 'v':
2968         mode_parse_client(&state, flag_p);
2969         break;
2970
2971       default: /* deal with other modes */
2972         mode_parse_mode(&state, flag_p);
2973         break;
2974       } /* switch (*modestr) */
2975     } /* for (; *modestr; modestr++) */
2976
2977     if (state.flags & MODE_PARSE_BURST)
2978       break; /* don't interpret any more arguments */
2979
2980     if (state.parc > 0) { /* process next argument in string */
2981       modestr = state.parv[state.args_used++];
2982       state.parc--;
2983
2984       /* is it a TS? */
2985       if (IsServer(state.sptr) && !state.parc && IsDigit(*modestr)) {
2986         time_t recv_ts;
2987
2988         if (!(state.flags & MODE_PARSE_SET))      /* don't set earlier TS if */
2989           break;                     /* we're then going to bounce the mode! */
2990
2991         recv_ts = atoi(modestr);
2992
2993         if (recv_ts && recv_ts < state.chptr->creationtime)
2994           state.chptr->creationtime = recv_ts; /* respect earlier TS */
2995
2996         break; /* break out of while loop */
2997       } else if (state.flags & MODE_PARSE_STRICT ||
2998                  (MyUser(state.sptr) && state.max_args <= 0)) {
2999         state.parc++; /* we didn't actually gobble the argument */
3000         state.args_used--;
3001         break; /* break out of while loop */
3002       }
3003     }
3004   } /* while (*modestr) */
3005
3006   /*
3007    * the rest of the function finishes building resultant MODEs; if the
3008    * origin isn't a member or an oper, skip it.
3009    */
3010   if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER))
3011     return state.args_used; /* tell our parent how many args we gobbled */
3012
3013   t_mode = state.chptr->mode.mode;
3014
3015   if (state.del & t_mode) { /* delete any modes to be deleted... */
3016     modebuf_mode(state.mbuf, MODE_DEL | (state.del & t_mode));
3017
3018     t_mode &= ~state.del;
3019   }
3020   if (state.add & ~t_mode) { /* add any modes to be added... */
3021     modebuf_mode(state.mbuf, MODE_ADD | (state.add & ~t_mode));
3022
3023     t_mode |= state.add;
3024   }
3025
3026   if (state.flags & MODE_PARSE_SET) { /* set the channel modes */
3027     if ((state.chptr->mode.mode & MODE_INVITEONLY) &&
3028         !(t_mode & MODE_INVITEONLY))
3029       mode_invite_clear(state.chptr);
3030
3031     state.chptr->mode.mode = t_mode;
3032   }
3033
3034   if (state.flags & MODE_PARSE_WIPEOUT) {
3035     if (state.chptr->mode.limit && !(state.done & DONE_LIMIT))
3036       modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT,
3037                         state.chptr->mode.limit);
3038     if (*state.chptr->mode.key && !(state.done & DONE_KEY))
3039       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY,
3040                           state.chptr->mode.key, 0);
3041     if (*state.chptr->mode.upass && !(state.done & DONE_UPASS))
3042       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS,
3043                           state.chptr->mode.upass, 0);
3044     if (*state.chptr->mode.apass && !(state.done & DONE_APASS))
3045       modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS,
3046                           state.chptr->mode.apass, 0);
3047   }
3048
3049   if (state.done & DONE_BANCLEAN) /* process bans */
3050     mode_process_bans(&state);
3051
3052   /* process client changes */
3053   if (state.cli_change[0].flag)
3054     mode_process_clients(&state);
3055
3056   return state.args_used; /* tell our parent how many args we gobbled */
3057 }
3058
3059 /*
3060  * Initialize a join buffer
3061  */
3062 void
3063 joinbuf_init(struct JoinBuf *jbuf, struct Client *source,
3064              struct Client *connect, unsigned int type, char *comment,
3065              time_t create)
3066 {
3067   int i;
3068
3069   assert(0 != jbuf);
3070   assert(0 != source);
3071   assert(0 != connect);
3072
3073   jbuf->jb_source = source; /* just initialize struct JoinBuf */
3074   jbuf->jb_connect = connect;
3075   jbuf->jb_type = type;
3076   jbuf->jb_comment = comment;
3077   jbuf->jb_create = create;
3078   jbuf->jb_count = 0;
3079   jbuf->jb_strlen = (((type == JOINBUF_TYPE_JOIN ||
3080                        type == JOINBUF_TYPE_PART ||
3081                        type == JOINBUF_TYPE_PARTALL) ?
3082                       STARTJOINLEN : STARTCREATELEN) +
3083                      (comment ? strlen(comment) + 2 : 0));
3084
3085   for (i = 0; i < MAXJOINARGS; i++)
3086     jbuf->jb_channels[i] = 0;
3087 }
3088
3089 /*
3090  * Add a channel to the join buffer
3091  */
3092 void
3093 joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags)
3094 {
3095   unsigned int len;
3096
3097   assert(0 != jbuf);
3098
3099   if (!chan) {
3100     if (jbuf->jb_type == JOINBUF_TYPE_JOIN)
3101       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect, "0");
3102
3103     return;
3104   }
3105
3106   if (jbuf->jb_type == JOINBUF_TYPE_PART ||
3107       jbuf->jb_type == JOINBUF_TYPE_PARTALL) {
3108     /* Send notification to channel */
3109     if (!(flags & CHFL_ZOMBIE))
3110       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL,
3111                                 (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3112                                 ":%H" : "%H :%s", chan, jbuf->jb_comment);
3113     else if (MyUser(jbuf->jb_source))
3114       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
3115                     (flags & CHFL_BANNED || !jbuf->jb_comment) ?
3116                     ":%H" : "%H :%s", chan, jbuf->jb_comment);
3117     /* XXX: Shouldn't we send a PART here anyway? */
3118     /* to users on the channel?  Why?  From their POV, the user isn't on
3119      * the channel anymore anyway.  We don't send to servers until below,
3120      * when we gang all the channel parts together.  Note that this is
3121      * exactly the same logic, albeit somewhat more concise, as was in
3122      * the original m_part.c */
3123
3124     if (jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3125         IsLocalChannel(chan->chname)) /* got to remove user here */
3126       remove_user_from_channel(jbuf->jb_source, chan);
3127   } else {
3128     /* Add user to channel */
3129     add_user_to_channel(chan, jbuf->jb_source, flags, 0);
3130
3131     /* send notification to all servers */
3132     if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname))
3133       sendcmdto_serv_butone(jbuf->jb_source, CMD_JOIN, jbuf->jb_connect,
3134                             "%H %Tu", chan, chan->creationtime);
3135
3136     /* Send the notification to the channel */
3137     sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_JOIN, chan, NULL, ":%H", chan);
3138
3139     /* send an op, too, if needed */
3140     if (!MyUser(jbuf->jb_source) && jbuf->jb_type == JOINBUF_TYPE_CREATE &&
3141         !IsModelessChannel(chan->chname))
3142       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_MODE, chan, NULL, "%H +o %C",
3143                                 chan, jbuf->jb_source);
3144   }
3145
3146   if (jbuf->jb_type == JOINBUF_TYPE_PARTALL || IsLocalChannel(chan->chname))
3147     return; /* don't send to remote */
3148
3149   /* figure out if channel name will cause buffer to be overflowed */
3150   len = chan ? strlen(chan->chname) + 1 : 2;
3151   if (jbuf->jb_strlen + len > BUFSIZE)
3152     joinbuf_flush(jbuf);
3153
3154   /* add channel to list of channels to send and update counts */
3155   jbuf->jb_channels[jbuf->jb_count++] = chan;
3156   jbuf->jb_strlen += len;
3157
3158   /* if we've used up all slots, flush */
3159   if (jbuf->jb_count >= MAXJOINARGS)
3160     joinbuf_flush(jbuf);
3161 }
3162
3163 /*
3164  * Flush the channel list to remote servers
3165  */
3166 int
3167 joinbuf_flush(struct JoinBuf *jbuf)
3168 {
3169   char chanlist[BUFSIZE];
3170   int chanlist_i = 0;
3171   int i;
3172
3173   if (!jbuf->jb_count || jbuf->jb_type == JOINBUF_TYPE_PARTALL ||
3174       jbuf->jb_type == JOINBUF_TYPE_JOIN)
3175     return 0; /* no joins to process */
3176
3177   for (i = 0; i < jbuf->jb_count; i++) { /* build channel list */
3178     build_string(chanlist, &chanlist_i,
3179                  jbuf->jb_channels[i] ? jbuf->jb_channels[i]->chname : "0", 0,
3180                  i == 0 ? '\0' : ',');
3181     if (JOINBUF_TYPE_PART == jbuf->jb_type)
3182       /* Remove user from channel */
3183       remove_user_from_channel(jbuf->jb_source, jbuf->jb_channels[i]);
3184
3185     jbuf->jb_channels[i] = 0; /* mark slot empty */
3186   }
3187
3188   jbuf->jb_count = 0; /* reset base counters */
3189   jbuf->jb_strlen = ((jbuf->jb_type == JOINBUF_TYPE_PART ?
3190                       STARTJOINLEN : STARTCREATELEN) +
3191                      (jbuf->jb_comment ? strlen(jbuf->jb_comment) + 2 : 0));
3192
3193   /* and send the appropriate command */
3194   switch (jbuf->jb_type) {
3195   case JOINBUF_TYPE_CREATE:
3196     sendcmdto_serv_butone(jbuf->jb_source, CMD_CREATE, jbuf->jb_connect,
3197                           "%s %Tu", chanlist, jbuf->jb_create);
3198     break;
3199
3200   case JOINBUF_TYPE_PART:
3201     sendcmdto_serv_butone(jbuf->jb_source, CMD_PART, jbuf->jb_connect,
3202                           jbuf->jb_comment ? "%s :%s" : "%s", chanlist,
3203                           jbuf->jb_comment);
3204     break;
3205   }
3206
3207   return 0;
3208 }