Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / m_join.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_join.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "channel.h"
91 #include "client.h"
92 #include "gline.h"
93 #include "hash.h"
94 #include "ircd.h"
95 #include "ircd_chattr.h"
96 #include "ircd_reply.h"
97 #include "ircd_string.h"
98 #include "msg.h"
99 #include "numeric.h"
100 #include "numnicks.h"
101 #include "s_user.h"
102 #include "send.h"
103
104 #include <assert.h>
105 #include <stdlib.h>
106 #include <string.h>
107
108 #if !defined(XXX_BOGUS_TEMP_HACK)
109 #include "handlers.h"      /* m_names */
110 #endif
111
112 /*
113  * m_join - generic message handler
114  */
115 int m_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
116 {
117   static char     jbuf[BUFSIZE];
118   static char     mbuf[BUFSIZE];
119   struct Membership* member;
120   struct Channel* chptr;
121   char*           name;
122   char*           keysOrTS = NULL;
123   int             i = 0;
124   int             zombie = 0;
125   int             sendcreate = 0;
126   unsigned int    flags = 0;
127   size_t          jlen = 0;
128   size_t          mlen = 0;
129   size_t*         buflen;
130   char*           p = NULL;
131   char*           bufptr;
132
133   /*
134    * Doesn't make sense having a server join a channel, and besides
135    * the server cores.
136    */
137   if (IsServer(sptr))
138     return 0;
139
140   if (parc < 2 || *parv[1] == '\0')
141     return need_more_params(sptr, "JOIN");
142
143   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
144     if (*p == '0'
145         && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
146     {
147       /* If it's a single "0", remember the place; we will start parsing
148          the channels after the last 0 in the line -Kev */
149       parv[1] = p;
150       if (!*(p + 1))
151         break;
152       p++;
153     }
154     else
155     {                           /* Step through to the next comma or until the
156                                    end of the line, in an attempt to save CPU
157                                    -Kev */
158       while (*p != ',' && *p != '\0')
159         p++;
160       if (!*p)
161         break;
162     }
163
164   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
165                                    parv[2] needs to be NULL for the call to
166                                    m_names below -Kev */
167   parv[2] = p = NULL;
168
169   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
170   /*
171    *  Rebuild list of channels joined to be the actual result of the
172    *  JOIN.  Note that "JOIN 0" is the destructive problem.
173    */
174   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
175   {
176     size_t len;
177     if (MyConnect(sptr))
178       clean_channelname(name);
179     else if (IsLocalChannel(name))
180       continue;
181     if (*name == '0' && *(name + 1) == '\0')
182     {
183       /* Remove the user from all his channels -Kev */
184       while ((member = sptr->user->channel))
185       {
186         chptr = member->channel;
187         if (!IsZombie(member))
188           sendto_channel_butserv(chptr, sptr, PartFmt2,
189               parv[0], chptr->chname, "Left all channels");
190         remove_user_from_channel(sptr, chptr);
191       }
192       /* Just in case */
193       *mbuf = *jbuf = '\0';
194       mlen = jlen = 0;
195     }
196     else
197     {                           /* not a /join 0, so treat it as
198                                    a /join #channel -Kev */
199       if (!IsChannelName(name))
200       {
201         if (MyUser(sptr))
202           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
203         continue;
204       }
205
206       if (MyConnect(sptr))
207       {
208 #ifdef BADCHAN
209         if (bad_channel(name) && !IsAnOper(sptr))
210         {
211           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
212           continue;
213         }
214 #endif
215         /*
216          * Local client is first to enter previously nonexistant
217          * channel so make them (rightfully) the Channel Operator.
218          * This looks kind of ugly because we try to avoid calling the strlen()
219          */
220         if (ChannelExists(name))
221         {
222           flags = CHFL_DEOPPED;
223           sendcreate = 0;
224         }
225         else if (strlen(name) > CHANNELLEN)
226         {
227           *(name + CHANNELLEN) = '\0';
228           if (ChannelExists(name))
229           {
230             flags = CHFL_DEOPPED;
231             sendcreate = 0;
232           }
233           else
234           {
235             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
236             sendcreate = 1;
237           }
238         }
239         else
240         {
241           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
242           sendcreate = 1;
243         }
244
245 #ifdef OPER_NO_CHAN_LIMIT
246         /*
247          * Opers are allowed to join any number of channels
248          */
249         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
250 #else
251         if (sptr->user->joined >= MAXCHANNELSPERUSER)
252 #endif
253         {
254           chptr = get_channel(sptr, name, CGT_NO_CREATE);
255           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
256                      me.name, parv[0], chptr ? chptr->chname : name);
257           /*
258            * Can't return, else he won't get on ANY channels!
259            * Break out of the for loop instead.  -Kev
260            */
261           break;
262         }
263       }
264       chptr = get_channel(sptr, name, CGT_CREATE);
265       if (chptr && (member = find_member_link(chptr, sptr)))
266       {
267         if (IsZombie(member))
268         {
269           zombie = 1;
270           flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
271           remove_user_from_channel(sptr, chptr);
272           chptr = get_channel(sptr, name, CGT_CREATE);
273         }
274         else
275           continue;
276       }
277       name = chptr->chname;
278       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
279         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
280       if (parc > 2)
281       {
282         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
283           chptr->creationtime = atoi(keysOrTS);
284         else
285           parc = 2;             /* Don't pass it on */
286       }
287       if (!zombie)
288       {
289         if (!MyConnect(sptr))
290           flags = CHFL_DEOPPED;
291         if (sptr->flags & FLAGS_TS8)
292           flags |= CHFL_SERVOPOK;
293       }
294       if (MyConnect(sptr))
295       {
296         int created = chptr->users == 0;
297         if (check_target_limit(sptr, chptr, chptr->chname, created))
298         {
299           if (created)          /* Did we create the channel? */
300             sub1_from_channel(chptr);   /* Remove it again! */
301           continue;
302         }
303         if ((i = can_join(sptr, chptr, keysOrTS)))
304         {
305 #ifdef OPER_WALK_THROUGH_LMODES
306           if (i > MAGIC_OPER_OVERRIDE)
307           {
308             switch(i - MAGIC_OPER_OVERRIDE)
309             {
310             case ERR_CHANNELISFULL: i = 'l'; break;
311             case ERR_INVITEONLYCHAN: i = 'i'; break;
312             case ERR_BANNEDFROMCHAN: i = 'b'; break;
313             case ERR_BADCHANNELKEY: i = 'k'; break;
314             }
315             sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
316           }
317           else
318           {
319             sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
320             continue;
321           }
322 #else     
323           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
324           continue;
325 #endif
326         }
327       }
328       /*
329        * Complete user entry to the new channel (if any)
330        */
331       add_user_to_channel(chptr, sptr, flags);
332
333       /*
334        * Notify all other users on the new channel
335        */
336       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
337
338       if (MyUser(sptr))
339       {
340         del_invite(sptr, chptr);
341         if (chptr->topic[0] != '\0')
342         {
343           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
344               parv[0], name, chptr->topic);
345           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
346               chptr->topic_nick, chptr->topic_time);
347         }
348         parv[1] = name;
349         m_names(cptr, sptr, 2, parv);
350       }
351     }
352
353     /* Select proper buffer; mbuf for creation, jbuf otherwise */
354
355     if (*name == '&')
356       continue;                 /* Head off local channels at the pass */
357
358     bufptr = (sendcreate == 0) ? jbuf : mbuf;
359     buflen = (sendcreate == 0) ? &jlen : &mlen;
360     len = strlen(name);
361     if (*buflen < BUFSIZE - len - 2)
362     {
363       if (*bufptr)
364       {
365         strcat(bufptr, ",");    /* Add to join buf */
366         *buflen += 1;
367       }
368       strncat(bufptr, name, BUFSIZE - *buflen - 1);
369       *buflen += len;
370     }
371     sendcreate = 0;             /* Reset sendcreate */
372   }
373
374   if (*jbuf)                    /* Propgate joins to P10 servers */
375     sendto_serv_butone(cptr, 
376         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
377   if (*mbuf)                    /* and now creation events */
378     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
379         NumNick(sptr), mbuf, TStime());
380
381   if (MyUser(sptr))
382   {                             /* shouldn't ever set TS for remote JOIN's */
383     if (*jbuf)
384     {                           /* check for channels that need TS's */
385       p = NULL;
386       for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
387       {
388         chptr = get_channel(sptr, name, CGT_NO_CREATE);
389         if (chptr && chptr->mode.mode & MODE_SENDTS)
390         {                       /* send a TS? */
391           sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
392               chptr->chname, chptr->creationtime);      /* ok, send TS */
393           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
394         }
395       }
396     }
397   }
398   return 0;
399 }
400
401 /*
402  * ms_join - server message handler
403  */
404 int ms_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
405 {
406   static char     jbuf[BUFSIZE];
407   static char     mbuf[BUFSIZE];
408   struct Membership* member;
409   struct Channel* chptr;
410   char*           name;
411   char*           keysOrTS = NULL;
412   int             i = 0;
413   int             zombie = 0;
414   int             sendcreate = 0;
415   unsigned int    flags = 0;
416   size_t          jlen = 0;
417   size_t          mlen = 0;
418   size_t*         buflen;
419   char*           p = NULL;
420   char*           bufptr;
421
422   /*
423    * Doesn't make sense having a server join a channel, and besides
424    * the server cores.
425    */
426   if (IsServer(sptr))
427     return 0;
428
429   if (parc < 2 || *parv[1] == '\0')
430     return need_more_params(sptr, "JOIN");
431
432   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
433     if (*p == '0'
434         && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
435     {
436       /* If it's a single "0", remember the place; we will start parsing
437          the channels after the last 0 in the line -Kev */
438       parv[1] = p;
439       if (!*(p + 1))
440         break;
441       p++;
442     }
443     else
444     {                           /* Step through to the next comma or until the
445                                    end of the line, in an attempt to save CPU
446                                    -Kev */
447       while (*p != ',' && *p != '\0')
448         p++;
449       if (!*p)
450         break;
451     }
452
453   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
454                                    parv[2] needs to be NULL for the call to
455                                    m_names below -Kev */
456   parv[2] = p = NULL;
457
458   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
459   /*
460    *  Rebuild list of channels joined to be the actual result of the
461    *  JOIN.  Note that "JOIN 0" is the destructive problem.
462    */
463   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
464   {
465     size_t len;
466     if (MyConnect(sptr))
467       clean_channelname(name);
468     else if (IsLocalChannel(name))
469       continue;
470     if (*name == '0' && *(name + 1) == '\0')
471     {
472       /* Remove the user from all his channels -Kev */
473       while ((member = sptr->user->channel))
474       {
475         chptr = member->channel;
476         if (!IsZombie(member))
477           sendto_channel_butserv(chptr, sptr, PartFmt2,
478               parv[0], chptr->chname, "Left all channels");
479         remove_user_from_channel(sptr, chptr);
480       }
481       /* Just in case */
482       *mbuf = *jbuf = '\0';
483       mlen = jlen = 0;
484     }
485     else
486     {                           /* not a /join 0, so treat it as
487                                    a /join #channel -Kev */
488       if (!IsChannelName(name))
489       {
490         if (MyUser(sptr))
491           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
492         continue;
493       }
494
495       if (MyConnect(sptr))
496       {
497 #ifdef BADCHAN
498         if (bad_channel(name) && !IsAnOper(sptr))
499         {
500           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
501           continue;
502         }
503 #endif
504         /*
505          * Local client is first to enter previously nonexistant
506          * channel so make them (rightfully) the Channel Operator.
507          * This looks kind of ugly because we try to avoid calling the strlen()
508          */
509         if (ChannelExists(name))
510         {
511           flags = CHFL_DEOPPED;
512           sendcreate = 0;
513         }
514         else if (strlen(name) > CHANNELLEN)
515         {
516           *(name + CHANNELLEN) = '\0';
517           if (ChannelExists(name))
518           {
519             flags = CHFL_DEOPPED;
520             sendcreate = 0;
521           }
522           else
523           {
524             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
525             sendcreate = 1;
526           }
527         }
528         else
529         {
530           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
531           sendcreate = 1;
532         }
533
534 #ifdef OPER_NO_CHAN_LIMIT
535         /*
536          * Opers are allowed to join any number of channels
537          */
538         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
539 #else
540         if (sptr->user->joined >= MAXCHANNELSPERUSER)
541 #endif
542         {
543           chptr = get_channel(sptr, name, CGT_NO_CREATE);
544           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
545                      me.name, parv[0], chptr ? chptr->chname : name);
546           /*
547            * Can't return, else he won't get on ANY channels!
548            * Break out of the for loop instead.  -Kev
549            */
550           break;
551         }
552       }
553       chptr = get_channel(sptr, name, CGT_CREATE);
554       if (chptr && (member = find_member_link(chptr, sptr)))
555       {
556         if (IsZombie(member))
557         {
558           zombie = 1;
559           flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
560           remove_user_from_channel(sptr, chptr);
561           chptr = get_channel(sptr, name, CGT_CREATE);
562         }
563         else
564           continue;
565       }
566       name = chptr->chname;
567       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
568         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
569       if (parc > 2)
570       {
571         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
572           chptr->creationtime = atoi(keysOrTS);
573         else
574           parc = 2;             /* Don't pass it on */
575       }
576       if (!zombie)
577       {
578         if (!MyConnect(sptr))
579           flags = CHFL_DEOPPED;
580         if (sptr->flags & FLAGS_TS8)
581           flags |= CHFL_SERVOPOK;
582       }
583       if (MyConnect(sptr))
584       {
585         int created = chptr->users == 0;
586         if (check_target_limit(sptr, chptr, chptr->chname, created))
587         {
588           if (created)          /* Did we create the channel? */
589             sub1_from_channel(chptr);   /* Remove it again! */
590           continue;
591         }
592         if ((i = can_join(sptr, chptr, keysOrTS)))
593         {
594           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
595           continue;
596         }
597       }
598       /*
599        * Complete user entry to the new channel (if any)
600        */
601       add_user_to_channel(chptr, sptr, flags);
602
603       /*
604        * Notify all other users on the new channel
605        */
606       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
607
608       if (MyUser(sptr))
609       {
610         del_invite(sptr, chptr);
611         if (chptr->topic[0] != '\0')
612         {
613           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
614               parv[0], name, chptr->topic);
615           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
616               chptr->topic_nick, chptr->topic_time);
617         }
618         parv[1] = name;
619         m_names(cptr, sptr, 2, parv);
620       }
621     }
622
623     /* Select proper buffer; mbuf for creation, jbuf otherwise */
624
625     if (*name == '&')
626       continue;                 /* Head off local channels at the pass */
627
628     bufptr = (sendcreate == 0) ? jbuf : mbuf;
629     buflen = (sendcreate == 0) ? &jlen : &mlen;
630     len = strlen(name);
631     if (*buflen < BUFSIZE - len - 2)
632     {
633       if (*bufptr)
634       {
635         strcat(bufptr, ",");    /* Add to join buf */
636         *buflen += 1;
637       }
638       strncat(bufptr, name, BUFSIZE - *buflen - 1);
639       *buflen += len;
640     }
641     sendcreate = 0;             /* Reset sendcreate */
642   }
643
644   if (*jbuf)                    /* Propgate joins to P10 servers */
645     sendto_serv_butone(cptr, 
646         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
647   if (*mbuf)                    /* and now creation events */
648     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
649         NumNick(sptr), mbuf, TStime());
650
651   if (MyUser(sptr))
652   {                             /* shouldn't ever set TS for remote JOIN's */
653     if (*jbuf)
654     {                           /* check for channels that need TS's */
655       p = NULL;
656       for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
657       {
658         chptr = get_channel(sptr, name, CGT_NO_CREATE);
659         if (chptr && chptr->mode.mode & MODE_SENDTS)
660         {                       /* send a TS? */
661           sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
662               chptr->chname, chptr->creationtime);      /* ok, send TS */
663           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
664         }
665       }
666     }
667   }
668   return 0;
669 }
670
671
672 #if 0
673 /*
674  * m_join
675  *
676  * parv[0] = sender prefix
677  * parv[1] = channel
678  * parv[2] = channel keys (client), or channel TS (server)
679  */
680 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
681 {
682   static char     jbuf[BUFSIZE];
683   static char     mbuf[BUFSIZE];
684   struct Membership* member;
685   struct Channel* chptr;
686   char*           name;
687   char*           keysOrTS = NULL;
688   int             i = 0;
689   int             zombie = 0;
690   int             sendcreate = 0;
691   unsigned int    flags = 0;
692   size_t          jlen = 0;
693   size_t          mlen = 0;
694   size_t*         buflen;
695   char*           p = NULL;
696   char*           bufptr;
697
698   /*
699    * Doesn't make sense having a server join a channel, and besides
700    * the server cores.
701    */
702   if (IsServer(sptr))
703     return 0;
704
705   if (parc < 2 || *parv[1] == '\0')
706     return need_more_params(sptr, "JOIN");
707
708   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
709     if (*p == '0'
710         && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
711     {
712       /* If it's a single "0", remember the place; we will start parsing
713          the channels after the last 0 in the line -Kev */
714       parv[1] = p;
715       if (!*(p + 1))
716         break;
717       p++;
718     }
719     else
720     {                           /* Step through to the next comma or until the
721                                    end of the line, in an attempt to save CPU
722                                    -Kev */
723       while (*p != ',' && *p != '\0')
724         p++;
725       if (!*p)
726         break;
727     }
728
729   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
730                                    parv[2] needs to be NULL for the call to
731                                    m_names below -Kev */
732   parv[2] = p = NULL;
733
734   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
735   /*
736    *  Rebuild list of channels joined to be the actual result of the
737    *  JOIN.  Note that "JOIN 0" is the destructive problem.
738    */
739   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
740   {
741     size_t len;
742     if (MyConnect(sptr))
743       clean_channelname(name);
744     else if (IsLocalChannel(name))
745       continue;
746     if (*name == '0' && *(name + 1) == '\0')
747     {
748       /* Remove the user from all his channels -Kev */
749       while ((member = sptr->user->channel))
750       {
751         chptr = member->channel;
752         if (!IsZombie(member))
753           sendto_channel_butserv(chptr, sptr, PartFmt2,
754               parv[0], chptr->chname, "Left all channels");
755         remove_user_from_channel(sptr, chptr);
756       }
757       /* Just in case */
758       *mbuf = *jbuf = '\0';
759       mlen = jlen = 0;
760     }
761     else
762     {                           /* not a /join 0, so treat it as
763                                    a /join #channel -Kev */
764       if (!IsChannelName(name))
765       {
766         if (MyUser(sptr))
767           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
768         continue;
769       }
770
771       if (MyConnect(sptr))
772       {
773 #ifdef BADCHAN
774         if (bad_channel(name) && !IsAnOper(sptr))
775         {
776           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
777           continue;
778         }
779 #endif
780         /*
781          * Local client is first to enter previously nonexistant
782          * channel so make them (rightfully) the Channel Operator.
783          * This looks kind of ugly because we try to avoid calling the strlen()
784          */
785         if (ChannelExists(name))
786         {
787           flags = CHFL_DEOPPED;
788           sendcreate = 0;
789         }
790         else if (strlen(name) > CHANNELLEN)
791         {
792           *(name + CHANNELLEN) = '\0';
793           if (ChannelExists(name))
794           {
795             flags = CHFL_DEOPPED;
796             sendcreate = 0;
797           }
798           else
799           {
800             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
801             sendcreate = 1;
802           }
803         }
804         else
805         {
806           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
807           sendcreate = 1;
808         }
809
810 #ifdef OPER_NO_CHAN_LIMIT
811         /*
812          * Opers are allowed to join any number of channels
813          */
814         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
815 #else
816         if (sptr->user->joined >= MAXCHANNELSPERUSER)
817 #endif
818         {
819           chptr = get_channel(sptr, name, CGT_NO_CREATE);
820           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
821                      me.name, parv[0], chptr ? chptr->chname : name);
822           /*
823            * Can't return, else he won't get on ANY channels!
824            * Break out of the for loop instead.  -Kev
825            */
826           break;
827         }
828       }
829       chptr = get_channel(sptr, name, CGT_CREATE);
830       if (chptr && (member = find_member_link(chptr, sptr)))
831       {
832         if (IsZombie(member))
833         {
834           zombie = 1;
835           flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
836           remove_user_from_channel(sptr, chptr);
837           chptr = get_channel(sptr, name, CGT_CREATE);
838         }
839         else
840           continue;
841       }
842       name = chptr->chname;
843       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
844         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
845       if (parc > 2)
846       {
847         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
848           chptr->creationtime = atoi(keysOrTS);
849         else
850           parc = 2;             /* Don't pass it on */
851       }
852       if (!zombie)
853       {
854         if (!MyConnect(sptr))
855           flags = CHFL_DEOPPED;
856         if (sptr->flags & FLAGS_TS8)
857           flags |= CHFL_SERVOPOK;
858       }
859       if (MyConnect(sptr))
860       {
861         int created = chptr->users == 0;
862         if (check_target_limit(sptr, chptr, chptr->chname, created))
863         {
864           if (created)          /* Did we create the channel? */
865             sub1_from_channel(chptr);   /* Remove it again! */
866           continue;
867         }
868         if ((i = can_join(sptr, chptr, keysOrTS)))
869         {
870           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
871 #ifdef OPER_WALK_THROUGH_LMODES
872           if (i > MAGIC_OPER_OVERRIDE)
873           {
874             switch(i - MAGIC_OPER_OVERRIDE)
875             {
876             case ERR_CHANNELISFULL: i = 'l'; break;
877             case ERR_INVITEONLYCHAN: i = 'i'; break;
878             case ERR_BANNEDFROMCHAN: i = 'b'; break;
879             case ERR_BADCHANNELKEY: i = 'k'; break;
880             }
881             sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
882           }
883           else
884             continue;     
885 #else     
886           continue;
887 #endif
888         }
889       }
890       /*
891        * Complete user entry to the new channel (if any)
892        */
893       add_user_to_channel(chptr, sptr, flags);
894
895       /*
896        * Notify all other users on the new channel
897        */
898       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
899
900       if (MyUser(sptr))
901       {
902         del_invite(sptr, chptr);
903         if (chptr->topic[0] != '\0')
904         {
905           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
906               parv[0], name, chptr->topic);
907           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
908               chptr->topic_nick, chptr->topic_time);
909         }
910         parv[1] = name;
911         m_names(cptr, sptr, 2, parv);
912       }
913     }
914
915     /* Select proper buffer; mbuf for creation, jbuf otherwise */
916
917     if (*name == '&')
918       continue;                 /* Head off local channels at the pass */
919
920     bufptr = (sendcreate == 0) ? jbuf : mbuf;
921     buflen = (sendcreate == 0) ? &jlen : &mlen;
922     len = strlen(name);
923     if (*buflen < BUFSIZE - len - 2)
924     {
925       if (*bufptr)
926       {
927         strcat(bufptr, ",");    /* Add to join buf */
928         *buflen += 1;
929       }
930       strncat(bufptr, name, BUFSIZE - *buflen - 1);
931       *buflen += len;
932     }
933     sendcreate = 0;             /* Reset sendcreate */
934   }
935
936   if (*jbuf)                    /* Propgate joins to P10 servers */
937     sendto_serv_butone(cptr, 
938         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
939   if (*mbuf)                    /* and now creation events */
940     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
941         NumNick(sptr), mbuf, TStime());
942
943   if (MyUser(sptr))
944   {                             /* shouldn't ever set TS for remote JOIN's */
945     if (*jbuf)
946     {                           /* check for channels that need TS's */
947       p = NULL;
948       for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
949       {
950         chptr = get_channel(sptr, name, CGT_NO_CREATE);
951         if (chptr && chptr->mode.mode & MODE_SENDTS)
952         {                       /* send a TS? */
953           sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
954               chptr->chname, chptr->creationtime);      /* ok, send TS */
955           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
956         }
957       }
958     }
959   }
960   return 0;
961 }
962 #endif /* 0 */