Author: Ghostwolf <foxxe@trms.com>
[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             zombie = 0;
410   int             sendcreate = 0;
411   unsigned int    flags = 0;
412   size_t          jlen = 0;
413   size_t          mlen = 0;
414   size_t*         buflen;
415   char*           p = NULL;
416   char*           bufptr;
417
418   /*
419    * Doesn't make sense having a server join a channel, and besides
420    * the server cores.
421    */
422   if (IsServer(sptr))
423     return 0;
424
425   if (parc < 2 || *parv[1] == '\0')
426     return need_more_params(sptr, "JOIN");
427
428   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
429                                    parv[2] needs to be NULL for the call to
430                                    m_names below -Kev */
431   parv[2] = p = NULL;
432
433   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
434   /*
435    *  Rebuild list of channels joined to be the actual result of the
436    *  JOIN.  Note that "JOIN 0" is the destructive problem.
437    */
438   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
439   {
440     size_t len;
441     if (IsLocalChannel(name))
442       continue;
443
444     if (!IsChannelName(name))
445     {
446       sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
447       continue;
448     }
449
450     chptr = get_channel(sptr, name, CGT_CREATE);
451     if (chptr && (member = find_member_link(chptr, sptr)))
452     {
453       if (!IsZombie(member))
454         continue;
455
456       /* If they are a zombie, make them really part
457        * and rejoin
458        */       
459       zombie = 1;
460       flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
461       remove_user_from_channel(sptr, chptr);
462       chptr = get_channel(sptr, name, CGT_CREATE);
463       
464     }
465     
466     name = chptr->chname;
467     
468     if (!chptr->creationtime) /* A remote JOIN created this channel ? */
469       chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
470       
471     if (parc > 2)
472     {
473       if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
474         chptr->creationtime = atoi(keysOrTS);
475       else
476         parc = 2;             /* Don't pass it on */
477     }
478     
479     if (!zombie)
480     {
481       if (sptr->flags & FLAGS_TS8)
482         flags |= CHFL_SERVOPOK;
483     }
484     
485     /*
486      * Complete user entry to the new channel (if any)
487      */
488     add_user_to_channel(chptr, sptr, flags);
489
490     /*
491      * Notify all other users on the new channel
492      */
493     sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
494
495     /* Select proper buffer; mbuf for creation, jbuf otherwise */
496
497     if (*name == '&')
498       continue;                 /* Head off local channels at the pass */
499
500     bufptr = (sendcreate == 0) ? jbuf : mbuf;
501     buflen = (sendcreate == 0) ? &jlen : &mlen;
502     len = strlen(name);
503     
504     if (*buflen < BUFSIZE - len - 2)
505     {
506       if (*bufptr)
507       {
508         strcat(bufptr, ",");    /* Add to join buf */
509         *buflen += 1;
510       }
511       strncat(bufptr, name, BUFSIZE - *buflen - 1);
512       *buflen += len;
513     }
514     sendcreate = 0;             /* Reset sendcreate */
515   }
516
517   if (*jbuf)                    /* Propgate joins to P10 servers */
518     sendto_serv_butone(cptr, 
519         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
520   if (*mbuf)                    /* and now creation events */
521     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
522         NumNick(sptr), mbuf, TStime());
523
524   return 0;
525 }
526
527
528 #if 0
529 /*
530  * m_join
531  *
532  * parv[0] = sender prefix
533  * parv[1] = channel
534  * parv[2] = channel keys (client), or channel TS (server)
535  */
536 int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
537 {
538   static char     jbuf[BUFSIZE];
539   static char     mbuf[BUFSIZE];
540   struct Membership* member;
541   struct Channel* chptr;
542   char*           name;
543   char*           keysOrTS = NULL;
544   int             i = 0;
545   int             zombie = 0;
546   int             sendcreate = 0;
547   unsigned int    flags = 0;
548   size_t          jlen = 0;
549   size_t          mlen = 0;
550   size_t*         buflen;
551   char*           p = NULL;
552   char*           bufptr;
553
554   /*
555    * Doesn't make sense having a server join a channel, and besides
556    * the server cores.
557    */
558   if (IsServer(sptr))
559     return 0;
560
561   if (parc < 2 || *parv[1] == '\0')
562     return need_more_params(sptr, "JOIN");
563
564   for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
565     if (*p == '0'
566         && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
567     {
568       /* If it's a single "0", remember the place; we will start parsing
569          the channels after the last 0 in the line -Kev */
570       parv[1] = p;
571       if (!*(p + 1))
572         break;
573       p++;
574     }
575     else
576     {                           /* Step through to the next comma or until the
577                                    end of the line, in an attempt to save CPU
578                                    -Kev */
579       while (*p != ',' && *p != '\0')
580         p++;
581       if (!*p)
582         break;
583     }
584
585   keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
586                                    parv[2] needs to be NULL for the call to
587                                    m_names below -Kev */
588   parv[2] = p = NULL;
589
590   *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
591   /*
592    *  Rebuild list of channels joined to be the actual result of the
593    *  JOIN.  Note that "JOIN 0" is the destructive problem.
594    */
595   for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
596   {
597     size_t len;
598     if (MyConnect(sptr))
599       clean_channelname(name);
600     else if (IsLocalChannel(name))
601       continue;
602     if (*name == '0' && *(name + 1) == '\0')
603     {
604       /* Remove the user from all his channels -Kev */
605       while ((member = sptr->user->channel))
606       {
607         chptr = member->channel;
608         if (!IsZombie(member))
609           sendto_channel_butserv(chptr, sptr, PartFmt2,
610               parv[0], chptr->chname, "Left all channels");
611         remove_user_from_channel(sptr, chptr);
612       }
613       /* Just in case */
614       *mbuf = *jbuf = '\0';
615       mlen = jlen = 0;
616     }
617     else
618     {                           /* not a /join 0, so treat it as
619                                    a /join #channel -Kev */
620       if (!IsChannelName(name))
621       {
622         if (MyUser(sptr))
623           sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
624         continue;
625       }
626
627       if (MyConnect(sptr))
628       {
629 #ifdef BADCHAN
630         struct Gline *gline;
631
632         if ((gline = gline_find(name, GLINE_BADCHAN)) &&
633             GlineIsActive(gline) && !IsAnOper(sptr))
634         {
635           sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
636           continue;
637         }
638 #endif
639         /*
640          * Local client is first to enter previously nonexistant
641          * channel so make them (rightfully) the Channel Operator.
642          * This looks kind of ugly because we try to avoid calling the strlen()
643          */
644         if (ChannelExists(name))
645         {
646           flags = CHFL_DEOPPED;
647           sendcreate = 0;
648         }
649         else if (strlen(name) > CHANNELLEN)
650         {
651           *(name + CHANNELLEN) = '\0';
652           if (ChannelExists(name))
653           {
654             flags = CHFL_DEOPPED;
655             sendcreate = 0;
656           }
657           else
658           {
659             flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
660             sendcreate = 1;
661           }
662         }
663         else
664         {
665           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
666           sendcreate = 1;
667         }
668
669 #ifdef OPER_NO_CHAN_LIMIT
670         /*
671          * Opers are allowed to join any number of channels
672          */
673         if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
674 #else
675         if (sptr->user->joined >= MAXCHANNELSPERUSER)
676 #endif
677         {
678           chptr = get_channel(sptr, name, CGT_NO_CREATE);
679           sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
680                      me.name, parv[0], chptr ? chptr->chname : name);
681           /*
682            * Can't return, else he won't get on ANY channels!
683            * Break out of the for loop instead.  -Kev
684            */
685           break;
686         }
687       }
688       chptr = get_channel(sptr, name, CGT_CREATE);
689       if (chptr && (member = find_member_link(chptr, sptr)))
690       {
691         if (IsZombie(member))
692         {
693           zombie = 1;
694           flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
695           remove_user_from_channel(sptr, chptr);
696           chptr = get_channel(sptr, name, CGT_CREATE);
697         }
698         else
699           continue;
700       }
701       name = chptr->chname;
702       if (!chptr->creationtime) /* A remote JOIN created this channel ? */
703         chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
704       if (parc > 2)
705       {
706         if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
707           chptr->creationtime = atoi(keysOrTS);
708         else
709           parc = 2;             /* Don't pass it on */
710       }
711       if (!zombie)
712       {
713         if (!MyConnect(sptr))
714           flags = CHFL_DEOPPED;
715         if (sptr->flags & FLAGS_TS8)
716           flags |= CHFL_SERVOPOK;
717       }
718       if (MyConnect(sptr))
719       {
720         int created = chptr->users == 0;
721         if (check_target_limit(sptr, chptr, chptr->chname, created))
722         {
723           if (created)          /* Did we create the channel? */
724             sub1_from_channel(chptr);   /* Remove it again! */
725           continue;
726         }
727         if ((i = can_join(sptr, chptr, keysOrTS)))
728         {
729           sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
730 #ifdef OPER_WALK_THROUGH_LMODES
731           if (i > MAGIC_OPER_OVERRIDE)
732           {
733             switch(i - MAGIC_OPER_OVERRIDE)
734             {
735             case ERR_CHANNELISFULL: i = 'l'; break;
736             case ERR_INVITEONLYCHAN: i = 'i'; break;
737             case ERR_BANNEDFROMCHAN: i = 'b'; break;
738             case ERR_BADCHANNELKEY: i = 'k'; break;
739             }
740             sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
741           }
742           else
743             continue;     
744 #else     
745           continue;
746 #endif
747         }
748       }
749       /*
750        * Complete user entry to the new channel (if any)
751        */
752       add_user_to_channel(chptr, sptr, flags);
753
754       /*
755        * Notify all other users on the new channel
756        */
757       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
758
759       if (MyUser(sptr))
760       {
761         del_invite(sptr, chptr);
762         if (chptr->topic[0] != '\0')
763         {
764           sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
765               parv[0], name, chptr->topic);
766           sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
767               chptr->topic_nick, chptr->topic_time);
768         }
769         parv[1] = name;
770         m_names(cptr, sptr, 2, parv);
771       }
772     }
773
774     /* Select proper buffer; mbuf for creation, jbuf otherwise */
775
776     if (*name == '&')
777       continue;                 /* Head off local channels at the pass */
778
779     bufptr = (sendcreate == 0) ? jbuf : mbuf;
780     buflen = (sendcreate == 0) ? &jlen : &mlen;
781     len = strlen(name);
782     if (*buflen < BUFSIZE - len - 2)
783     {
784       if (*bufptr)
785       {
786         strcat(bufptr, ",");    /* Add to join buf */
787         *buflen += 1;
788       }
789       strncat(bufptr, name, BUFSIZE - *buflen - 1);
790       *buflen += len;
791     }
792     sendcreate = 0;             /* Reset sendcreate */
793   }
794
795   if (*jbuf)                    /* Propgate joins to P10 servers */
796     sendto_serv_butone(cptr, 
797         parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
798   if (*mbuf)                    /* and now creation events */
799     sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
800         NumNick(sptr), mbuf, TStime());
801
802   if (MyUser(sptr))
803   {                             /* shouldn't ever set TS for remote JOIN's */
804     if (*jbuf)
805     {                           /* check for channels that need TS's */
806       p = NULL;
807       for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
808       {
809         chptr = get_channel(sptr, name, CGT_NO_CREATE);
810         if (chptr && chptr->mode.mode & MODE_SENDTS)
811         {                       /* send a TS? */
812           sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
813               chptr->chname, chptr->creationtime);      /* ok, send TS */
814           chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
815         }
816       }
817     }
818   }
819   return 0;
820 }
821 #endif /* 0 */