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