Author: Kev <klmitch@mit.edu>
[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   if (parc < 2 || *parv[1] == '\0')
135     return need_more_params(sptr, "JOIN");
136
137   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
138     if (*p == '0'
139         && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
140     {
141       /* If it's a single "0", remember the place; we will start parsing
142          the channels after the last 0 in the line -Kev */
143       parv[1] = p;
144       if (!*(p + 1))
145         break;
146       p++;
147     }
148     else
149     {                           /* Step through to the next comma or until the
150                                    end of the line, in an attempt to save CPU
151                                    -Kev */
152       while (*p != ',' && *p != '\0')
153         p++;
154       if (!*p)
155         break;
156     }
157
158   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
159                                    parv[2] needs to be NULL for the call to
160                                    m_names below -Kev */
161   parv[2] = p = NULL;
162
163   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
164   /*
165    *  Rebuild list of channels joined to be the actual result of the
166    *  JOIN.  Note that "JOIN 0" is the destructive problem.
167    */
168   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
169   {
170     size_t len;
171     if (MyConnect(sptr))
172       clean_channelname(name);
173     else if (IsLocalChannel(name))
174       continue;
175     if (*name == '0' && *(name + 1) == '\0')
176     {
177       /* Remove the user from all his channels -Kev */
178       while ((member = sptr->user->channel))
179       {
180         chptr = member->channel;
181         if (!IsZombie(member))
182           sendto_channel_butserv(chptr, sptr, PartFmt2,
183               parv[0], chptr->chname, "Left all channels");
184         remove_user_from_channel(sptr, chptr);
185       }
186       /* Just in case */
187       *mbuf = *jbuf = '\0';
188       mlen = jlen = 0;
189     }
190     else
191     {                           /* not a /join 0, so treat it as
192                                    a /join #channel -Kev */
193       if (!IsChannelName(name))
194       {
195         if (MyUser(sptr))
196           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
197         continue;
198       }
199
200       if (MyConnect(sptr))
201       {
202 #ifdef BADCHAN
203         struct Gline *gline;
204
205         if ((gline = gline_find(name, GLINE_BADCHAN)) &&
206             GlineIsActive(gline) && !IsAnOper(sptr))
207         {
208           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
209           continue;
210         }
211 #endif
212         /*
213          * Local client is first to enter previously nonexistant
214          * channel so make them (rightfully) the Channel Operator.
215          * This looks kind of ugly because we try to avoid calling the strlen()
216          */
217         if (ChannelExists(name))
218         {
219           flags = CHFL_DEOPPED;
220           sendcreate = 0;
221         }
222         else if (strlen(name) > CHANNELLEN)
223         {
224           *(name + CHANNELLEN) = '\0';
225           if (ChannelExists(name))
226           {
227             flags = CHFL_DEOPPED;
228             sendcreate = 0;
229           }
230           else
231           {
232             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
233             sendcreate = 1;
234           }
235         }
236         else
237         {
238           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
239           sendcreate = 1;
240         }
241
242 #ifdef OPER_NO_CHAN_LIMIT
243         /*
244          * Opers are allowed to join any number of channels
245          */
246         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
247 #else
248         if (sptr->user->joined >= MAXCHANNELSPERUSER)
249 #endif
250         {
251           chptr = get_channel(sptr, name, CGT_NO_CREATE);
252           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
253                      me.name, parv[0], chptr ? chptr->chname : name);
254           /*
255            * Can't return, else he won't get on ANY channels!
256            * Break out of the for loop instead.  -Kev
257            */
258           break;
259         }
260       }
261       chptr = get_channel(sptr, name, CGT_CREATE);
262       if (chptr && (member = find_member_link(chptr, sptr)))
263       {
264         if (IsZombie(member))
265         {
266           zombie = 1;
267           flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
268           remove_user_from_channel(sptr, chptr);
269           chptr = get_channel(sptr, name, CGT_CREATE);
270         }
271         else
272           continue;
273       }
274       name = chptr->chname;
275       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
276         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
277       if (parc > 2)
278       {
279         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
280           chptr->creationtime = atoi(keysOrTS);
281         else
282           parc = 2;             /* Don't pass it on */
283       }
284       if (!zombie)
285       {
286         if (!MyConnect(sptr))
287           flags = CHFL_DEOPPED;
288         if (sptr->flags & FLAGS_TS8)
289           flags |= CHFL_SERVOPOK;
290       }
291       if (MyConnect(sptr))
292       {
293         int created = chptr->users == 0;
294         if (check_target_limit(sptr, chptr, chptr->chname, created))
295         {
296           if (created)          /* Did we create the channel? */
297             sub1_from_channel(chptr);   /* Remove it again! */
298           continue;
299         }
300         if ((i = can_join(sptr, chptr, keysOrTS)))
301         {
302 #ifdef OPER_WALK_THROUGH_LMODES
303           if (i > MAGIC_OPER_OVERRIDE)
304           {
305             switch(i - MAGIC_OPER_OVERRIDE)
306             {
307             case ERR_CHANNELISFULL: i = 'l'; break;
308             case ERR_INVITEONLYCHAN: i = 'i'; break;
309             case ERR_BANNEDFROMCHAN: i = 'b'; break;
310             case ERR_BADCHANNELKEY: i = 'k'; break;
311             }
312             sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
313           }
314           else
315           {
316             sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
317             continue;
318           }
319 #else     
320           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
321           continue;
322 #endif
323         }
324       }
325       /*
326        * Complete user entry to the new channel (if any)
327        */
328       add_user_to_channel(chptr, sptr, flags);
329
330       /*
331        * Notify all other users on the new channel
332        */
333       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
334
335       if (MyUser(sptr))
336       {
337         del_invite(sptr, chptr);
338         if (chptr->topic[0] != '\0')
339         {
340           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
341               parv[0], name, chptr->topic);
342           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
343               chptr->topic_nick, chptr->topic_time);
344         }
345         parv[1] = name;
346         m_names(cptr, sptr, 2, parv);
347       }
348     }
349
350     /* Select proper buffer; mbuf for creation, jbuf otherwise */
351
352     if (*name == '&')
353       continue;                 /* Head off local channels at the pass */
354
355     bufptr = (sendcreate == 0) ? jbuf : mbuf;
356     buflen = (sendcreate == 0) ? &jlen : &mlen;
357     len = strlen(name);
358     if (*buflen < BUFSIZE - len - 2)
359     {
360       if (*bufptr)
361       {
362         strcat(bufptr, ",");    /* Add to join buf */
363         *buflen += 1;
364       }
365       strncat(bufptr, name, BUFSIZE - *buflen - 1);
366       *buflen += len;
367     }
368     sendcreate = 0;             /* Reset sendcreate */
369   }
370
371   if (*jbuf)                    /* Propgate joins to P10 servers */
372     sendto_serv_butone(cptr, 
373         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
374   if (*mbuf)                    /* and now creation events */
375     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
376         NumNick(sptr), mbuf, TStime());
377
378   if (MyUser(sptr))
379   {                             /* shouldn't ever set TS for remote JOIN's */
380     if (*jbuf)
381     {                           /* check for channels that need TS's */
382       p = NULL;
383       for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
384       {
385         chptr = get_channel(sptr, name, CGT_NO_CREATE);
386         if (chptr && chptr->mode.mode & MODE_SENDTS)
387         {                       /* send a TS? */
388           sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
389               chptr->chname, chptr->creationtime);      /* ok, send TS */
390           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
391         }
392       }
393     }
394   }
395   return 0;
396 }
397
398 /*
399  * ms_join - server message handler
400  */
401 int ms_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
402 {
403   static char     jbuf[BUFSIZE];
404   static char     mbuf[BUFSIZE];
405   struct Membership* member;
406   struct Channel* chptr;
407   char*           name;
408   char*           keysOrTS = NULL;
409   int             i = 0;
410   int             zombie = 0;
411   int             sendcreate = 0;
412   unsigned int    flags = 0;
413   size_t          jlen = 0;
414   size_t          mlen = 0;
415   size_t*         buflen;
416   char*           p = NULL;
417   char*           bufptr;
418
419   /*
420    * Doesn't make sense having a server join a channel, and besides
421    * the server cores.
422    */
423   if (IsServer(sptr))
424     return 0;
425
426   if (parc < 2 || *parv[1] == '\0')
427     return need_more_params(sptr, "JOIN");
428
429   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
430                                    parv[2] needs to be NULL for the call to
431                                    m_names below -Kev */
432   parv[2] = p = NULL;
433
434   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
435   /*
436    *  Rebuild list of channels joined to be the actual result of the
437    *  JOIN.  Note that "JOIN 0" is the destructive problem.
438    */
439   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
440   {
441     size_t len;
442     if (IsLocalChannel(name))
443       continue;
444
445     if (!IsChannelName(name))
446     {
447       sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
448       continue;
449     }
450
451     chptr = get_channel(sptr, name, CGT_CREATE);
452     if (chptr && (member = find_member_link(chptr, sptr)))
453     {
454       if (!IsZombie(member))
455         continue;
456
457       /* If they are a zombie, make them really part
458        * and rejoin
459        */       
460       zombie = 1;
461       flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
462       remove_user_from_channel(sptr, chptr);
463       chptr = get_channel(sptr, name, CGT_CREATE);
464       
465     }
466     
467     name = chptr->chname;
468     
469     if (!chptr->creationtime) /* A remote JOIN created this channel ? */
470       chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
471       
472     if (parc > 2)
473     {
474       if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
475         chptr->creationtime = atoi(keysOrTS);
476       else
477         parc = 2;             /* Don't pass it on */
478     }
479     
480     if (!zombie)
481     {
482       if (sptr->flags & FLAGS_TS8)
483         flags |= CHFL_SERVOPOK;
484     }
485     
486     /*
487      * Complete user entry to the new channel (if any)
488      */
489     add_user_to_channel(chptr, sptr, flags);
490
491     /*
492      * Notify all other users on the new channel
493      */
494     sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
495
496     /* Select proper buffer; mbuf for creation, jbuf otherwise */
497
498     if (*name == '&')
499       continue;                 /* Head off local channels at the pass */
500
501     bufptr = (sendcreate == 0) ? jbuf : mbuf;
502     buflen = (sendcreate == 0) ? &jlen : &mlen;
503     len = strlen(name);
504     
505     if (*buflen < BUFSIZE - len - 2)
506     {
507       if (*bufptr)
508       {
509         strcat(bufptr, ",");    /* Add to join buf */
510         *buflen += 1;
511       }
512       strncat(bufptr, name, BUFSIZE - *buflen - 1);
513       *buflen += len;
514     }
515     sendcreate = 0;             /* Reset sendcreate */
516   }
517
518   if (*jbuf)                    /* Propgate joins to P10 servers */
519     sendto_serv_butone(cptr, 
520         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
521   if (*mbuf)                    /* and now creation events */
522     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
523         NumNick(sptr), mbuf, TStime());
524
525   return 0;
526 }
527
528
529 #if 0
530 /*
531  * m_join
532  *
533  * parv[0] = sender prefix
534  * parv[1] = channel
535  * parv[2] = channel keys (client), or channel TS (server)
536  */
537 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
538 {
539   static char     jbuf[BUFSIZE];
540   static char     mbuf[BUFSIZE];
541   struct Membership* member;
542   struct Channel* chptr;
543   char*           name;
544   char*           keysOrTS = NULL;
545   int             i = 0;
546   int             zombie = 0;
547   int             sendcreate = 0;
548   unsigned int    flags = 0;
549   size_t          jlen = 0;
550   size_t          mlen = 0;
551   size_t*         buflen;
552   char*           p = NULL;
553   char*           bufptr;
554
555   /*
556    * Doesn't make sense having a server join a channel, and besides
557    * the server cores.
558    */
559   if (IsServer(sptr))
560     return 0;
561
562   if (parc < 2 || *parv[1] == '\0')
563     return need_more_params(sptr, "JOIN");
564
565   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
566     if (*p == '0'
567         && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
568     {
569       /* If it's a single "0", remember the place; we will start parsing
570          the channels after the last 0 in the line -Kev */
571       parv[1] = p;
572       if (!*(p + 1))
573         break;
574       p++;
575     }
576     else
577     {                           /* Step through to the next comma or until the
578                                    end of the line, in an attempt to save CPU
579                                    -Kev */
580       while (*p != ',' && *p != '\0')
581         p++;
582       if (!*p)
583         break;
584     }
585
586   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
587                                    parv[2] needs to be NULL for the call to
588                                    m_names below -Kev */
589   parv[2] = p = NULL;
590
591   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
592   /*
593    *  Rebuild list of channels joined to be the actual result of the
594    *  JOIN.  Note that "JOIN 0" is the destructive problem.
595    */
596   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
597   {
598     size_t len;
599     if (MyConnect(sptr))
600       clean_channelname(name);
601     else if (IsLocalChannel(name))
602       continue;
603     if (*name == '0' && *(name + 1) == '\0')
604     {
605       /* Remove the user from all his channels -Kev */
606       while ((member = sptr->user->channel))
607       {
608         chptr = member->channel;
609         if (!IsZombie(member))
610           sendto_channel_butserv(chptr, sptr, PartFmt2,
611               parv[0], chptr->chname, "Left all channels");
612         remove_user_from_channel(sptr, chptr);
613       }
614       /* Just in case */
615       *mbuf = *jbuf = '\0';
616       mlen = jlen = 0;
617     }
618     else
619     {                           /* not a /join 0, so treat it as
620                                    a /join #channel -Kev */
621       if (!IsChannelName(name))
622       {
623         if (MyUser(sptr))
624           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
625         continue;
626       }
627
628       if (MyConnect(sptr))
629       {
630 #ifdef BADCHAN
631         struct Gline *gline;
632
633         if ((gline = gline_find(name, GLINE_BADCHAN)) &&
634             GlineIsActive(gline) && !IsAnOper(sptr))
635         {
636           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
637           continue;
638         }
639 #endif
640         /*
641          * Local client is first to enter previously nonexistant
642          * channel so make them (rightfully) the Channel Operator.
643          * This looks kind of ugly because we try to avoid calling the strlen()
644          */
645         if (ChannelExists(name))
646         {
647           flags = CHFL_DEOPPED;
648           sendcreate = 0;
649         }
650         else if (strlen(name) > CHANNELLEN)
651         {
652           *(name + CHANNELLEN) = '\0';
653           if (ChannelExists(name))
654           {
655             flags = CHFL_DEOPPED;
656             sendcreate = 0;
657           }
658           else
659           {
660             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
661             sendcreate = 1;
662           }
663         }
664         else
665         {
666           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
667           sendcreate = 1;
668         }
669
670 #ifdef OPER_NO_CHAN_LIMIT
671         /*
672          * Opers are allowed to join any number of channels
673          */
674         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
675 #else
676         if (sptr->user->joined >= MAXCHANNELSPERUSER)
677 #endif
678         {
679           chptr = get_channel(sptr, name, CGT_NO_CREATE);
680           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
681                      me.name, parv[0], chptr ? chptr->chname : name);
682           /*
683            * Can't return, else he won't get on ANY channels!
684            * Break out of the for loop instead.  -Kev
685            */
686           break;
687         }
688       }
689       chptr = get_channel(sptr, name, CGT_CREATE);
690       if (chptr && (member = find_member_link(chptr, sptr)))
691       {
692         if (IsZombie(member))
693         {
694           zombie = 1;
695           flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
696           remove_user_from_channel(sptr, chptr);
697           chptr = get_channel(sptr, name, CGT_CREATE);
698         }
699         else
700           continue;
701       }
702       name = chptr->chname;
703       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
704         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
705       if (parc > 2)
706       {
707         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
708           chptr->creationtime = atoi(keysOrTS);
709         else
710           parc = 2;             /* Don't pass it on */
711       }
712       if (!zombie)
713       {
714         if (!MyConnect(sptr))
715           flags = CHFL_DEOPPED;
716         if (sptr->flags & FLAGS_TS8)
717           flags |= CHFL_SERVOPOK;
718       }
719       if (MyConnect(sptr))
720       {
721         int created = chptr->users == 0;
722         if (check_target_limit(sptr, chptr, chptr->chname, created))
723         {
724           if (created)          /* Did we create the channel? */
725             sub1_from_channel(chptr);   /* Remove it again! */
726           continue;
727         }
728         if ((i = can_join(sptr, chptr, keysOrTS)))
729         {
730           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
731 #ifdef OPER_WALK_THROUGH_LMODES
732           if (i > MAGIC_OPER_OVERRIDE)
733           {
734             switch(i - MAGIC_OPER_OVERRIDE)
735             {
736             case ERR_CHANNELISFULL: i = 'l'; break;
737             case ERR_INVITEONLYCHAN: i = 'i'; break;
738             case ERR_BANNEDFROMCHAN: i = 'b'; break;
739             case ERR_BADCHANNELKEY: i = 'k'; break;
740             }
741             sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
742           }
743           else
744             continue;     
745 #else     
746           continue;
747 #endif
748         }
749       }
750       /*
751        * Complete user entry to the new channel (if any)
752        */
753       add_user_to_channel(chptr, sptr, flags);
754
755       /*
756        * Notify all other users on the new channel
757        */
758       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
759
760       if (MyUser(sptr))
761       {
762         del_invite(sptr, chptr);
763         if (chptr->topic[0] != '\0')
764         {
765           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
766               parv[0], name, chptr->topic);
767           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
768               chptr->topic_nick, chptr->topic_time);
769         }
770         parv[1] = name;
771         m_names(cptr, sptr, 2, parv);
772       }
773     }
774
775     /* Select proper buffer; mbuf for creation, jbuf otherwise */
776
777     if (*name == '&')
778       continue;                 /* Head off local channels at the pass */
779
780     bufptr = (sendcreate == 0) ? jbuf : mbuf;
781     buflen = (sendcreate == 0) ? &jlen : &mlen;
782     len = strlen(name);
783     if (*buflen < BUFSIZE - len - 2)
784     {
785       if (*bufptr)
786       {
787         strcat(bufptr, ",");    /* Add to join buf */
788         *buflen += 1;
789       }
790       strncat(bufptr, name, BUFSIZE - *buflen - 1);
791       *buflen += len;
792     }
793     sendcreate = 0;             /* Reset sendcreate */
794   }
795
796   if (*jbuf)                    /* Propgate joins to P10 servers */
797     sendto_serv_butone(cptr, 
798         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
799   if (*mbuf)                    /* and now creation events */
800     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
801         NumNick(sptr), mbuf, TStime());
802
803   if (MyUser(sptr))
804   {                             /* shouldn't ever set TS for remote JOIN's */
805     if (*jbuf)
806     {                           /* check for channels that need TS's */
807       p = NULL;
808       for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
809       {
810         chptr = get_channel(sptr, name, CGT_NO_CREATE);
811         if (chptr && chptr->mode.mode & MODE_SENDTS)
812         {                       /* send a TS? */
813           sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
814               chptr->chname, chptr->creationtime);      /* ok, send TS */
815           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
816         }
817       }
818     }
819   }
820   return 0;
821 }
822 #endif /* 0 */