1 /*
2 * IRC - Internet Relay Chat, src/modules/m_join.c
3 * (C) 2005 The UnrealIRCd Team
4 *
5 * See file AUTHORS in IRC package for additional names of
6 * the programmers.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 #include "config.h"
23 #include "struct.h"
24 #include "common.h"
25 #include "sys.h"
26 #include "numeric.h"
27 #include "msg.h"
28 #include "proto.h"
29 #include "channel.h"
30 #include <time.h>
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef _WIN32
36 #include <io.h>
37 #endif
38 #include <fcntl.h>
39 #include "h.h"
40 #ifdef STRIPBADWORDS
41 #include "badwords.h"
42 #endif
43 #ifdef _WIN32
44 #include "version.h"
45 #endif
46
47 /* Forward declarations */
48 DLLFUNC CMD_FUNC(m_join);
49 DLLFUNC void _join_channel(aChannel *chptr, aClient *cptr, aClient *sptr, int flags);
50 DLLFUNC CMD_FUNC(_do_join);
51 DLLFUNC int _can_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *key, char *link, char *parv[]);
52 static int extended_operoverride(aClient *sptr, aChannel *chptr, char *key, int mval, char mchar);
53 #define MAXBOUNCE 5 /** Most sensible */
54 #ifdef JOINTHROTTLE
55 static int isjthrottled(aClient *cptr, aChannel *chptr);
56 static void cmodej_increase_usercounter(aClient *cptr, aChannel *chptr);
57 #endif
58
59 /* Externs */
60 extern MODVAR int spamf_ugly_vchanoverride;
61 extern int find_invex(aChannel *chptr, aClient *sptr);
62
63 /* Local vars */
64 static int bouncedtimes = 0;
65
66 #define MSG_JOIN "JOIN"
67 #define TOK_JOIN "C"
68
69 ModuleHeader MOD_HEADER(m_join)
70 = {
71 "m_join",
72 "$Id$",
73 "command /join",
74 "3.2-b8-1",
75 NULL
76 };
77
MOD_TEST(m_join)78 DLLFUNC int MOD_TEST(m_join)(ModuleInfo *modinfo)
79 {
80 MARK_AS_OFFICIAL_MODULE(modinfo);
81 EfunctionAddVoid(modinfo->handle, EFUNC_JOIN_CHANNEL, _join_channel);
82 EfunctionAdd(modinfo->handle, EFUNC_DO_JOIN, _do_join);
83 EfunctionAdd(modinfo->handle, EFUNC_CAN_JOIN, _can_join);
84 return MOD_SUCCESS;
85 }
86
MOD_INIT(m_join)87 DLLFUNC int MOD_INIT(m_join)(ModuleInfo *modinfo)
88 {
89 CommandAdd(modinfo->handle, MSG_JOIN, TOK_JOIN, m_join, MAXPARA, M_USER);
90 MARK_AS_OFFICIAL_MODULE(modinfo);
91 return MOD_SUCCESS;
92 }
93
MOD_LOAD(m_join)94 DLLFUNC int MOD_LOAD(m_join)(int module_load)
95 {
96 return MOD_SUCCESS;
97 }
98
MOD_UNLOAD(m_join)99 DLLFUNC int MOD_UNLOAD(m_join)(int module_unload)
100 {
101 return MOD_SUCCESS;
102 }
103
104 /* This function adds as an extra (weird) operoverride.
105 * Currently it's only used if you try to operoverride for a +z channel,
106 * if you then do '/join #chan override' it will put the channel -z and allow you directly in.
107 * This is to avoid attackers from using 'race conditions' to prevent you from joining.
108 * PARAMETERS: sptr = the client, chptr = the channel, mval = mode value (eg MODE_ONLYSECURE),
109 * mchar = mode char (eg 'z')
110 * RETURNS: 1 if operoverride, 0 if not.
111 */
extended_operoverride(aClient * sptr,aChannel * chptr,char * key,int mval,char mchar)112 int extended_operoverride(aClient *sptr, aChannel *chptr, char *key, int mval, char mchar)
113 {
114 unsigned char invited = 0;
115 Link *lp;
116
117 if (!IsAnOper(sptr) || !OPCanOverride(sptr))
118 return 0;
119
120 for (lp = sptr->user->invited; lp; lp = lp->next)
121 if (lp->value.chptr == chptr)
122 {
123 invited = 1;
124 break;
125 }
126 if (invited)
127 {
128 if (key && !strcasecmp(key, "override"))
129 {
130 sendto_channelprefix_butone(NULL, &me, chptr, PREFIX_OP|PREFIX_ADMIN|PREFIX_OWNER,
131 ":%s NOTICE @%s :setting channel -%c due to OperOverride request from %s",
132 me.name, chptr->chname, mchar, sptr->name);
133 sendto_serv_butone(&me, ":%s MODE %s -%c 0", me.name, chptr->chname, mchar);
134 sendto_channel_butserv(chptr, &me, ":%s MODE %s -%c", me.name, chptr->chname, mchar);
135 chptr->mode.mode &= ~mval;
136 return 1;
137 }
138 }
139 return 0;
140 }
141
142
143 /* Now let _invited_ people join thru bans, +i and +l.
144 * Checking if an invite exist could be done only if a block exists,
145 * but I'm not too fancy of the complicated structure that'd cause,
146 * when optimization will hopefully take care of it. Most of the time
147 * a user won't have invites on him anyway. -Donwulff
148 */
149
_can_join(aClient * cptr,aClient * sptr,aChannel * chptr,char * key,char * link,char * parv[])150 DLLFUNC int _can_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *key, char *link, char *parv[])
151 {
152 Link *lp;
153 Ban *banned;
154
155 if ((chptr->mode.mode & MODE_ONLYSECURE) && !(sptr->umodes & UMODE_SECURE))
156 {
157 if (IsAnOper(sptr))
158 {
159 /* Yeah yeah.. duplicate code..
160 * Anyway: if the channel is +z we still allow an ircop to bypass it
161 * if they are invited.
162 */
163 for (lp = sptr->user->invited; lp; lp = lp->next)
164 if (lp->value.chptr == chptr)
165 return 0;
166 }
167 return (ERR_SECUREONLYCHAN);
168 }
169
170 if ((chptr->mode.mode & MODE_OPERONLY) && !IsAnOper(sptr))
171 return (ERR_OPERONLY);
172
173 if ((chptr->mode.mode & MODE_ADMONLY) && !IsSkoAdmin(sptr))
174 return (ERR_ADMONLY);
175
176 /* Admin, Coadmin, Netadmin, and SAdmin can still walk +b in +O */
177 banned = is_banned(sptr, chptr, BANCHK_JOIN);
178 if (banned && (chptr->mode.mode & MODE_OPERONLY) &&
179 IsAnOper(sptr) && !IsSkoAdmin(sptr) && !IsCoAdmin(sptr))
180 return (ERR_BANNEDFROMCHAN);
181
182 /* Only NetAdmin/SAdmin can walk +b in +A */
183 if (banned && (chptr->mode.mode & MODE_ADMONLY) &&
184 IsAnOper(sptr) && !IsNetAdmin(sptr) && !IsSAdmin(sptr))
185 return (ERR_BANNEDFROMCHAN);
186
187 for (lp = sptr->user->invited; lp; lp = lp->next)
188 if (lp->value.chptr == chptr)
189 return 0;
190
191 if ((chptr->mode.limit && chptr->users >= chptr->mode.limit))
192 {
193 if (chptr->mode.link)
194 {
195 if (*chptr->mode.link != '\0')
196 {
197 /* We are linked. */
198 sendto_one(sptr,
199 err_str(ERR_LINKCHANNEL), me.name,
200 sptr->name, chptr->chname,
201 chptr->mode.link);
202 parv[0] = sptr->name;
203 parv[1] = (chptr->mode.link);
204 do_join(cptr, sptr, 2, parv);
205 return -1;
206 }
207 }
208 /* We check this later return (ERR_CHANNELISFULL); */
209 }
210
211 if ((chptr->mode.mode & MODE_RGSTRONLY) && !IsLoggedIn(sptr))
212 return (ERR_NEEDREGGEDNICK);
213
214 if (*chptr->mode.key && (BadPtr(key) || strcmp(chptr->mode.key, key)))
215 return (ERR_BADCHANNELKEY);
216
217 if ((chptr->mode.mode & MODE_INVITEONLY) && !find_invex(chptr, sptr))
218 return (ERR_INVITEONLYCHAN);
219
220 if ((chptr->mode.limit && chptr->users >= chptr->mode.limit))
221 return (ERR_CHANNELISFULL);
222
223 if (banned)
224 return (ERR_BANNEDFROMCHAN);
225
226 #ifndef NO_OPEROVERRIDE
227 #ifdef OPEROVERRIDE_VERIFY
228 if (IsOper(sptr) && (chptr->mode.mode & MODE_SECRET ||
229 chptr->mode.mode & MODE_PRIVATE) && !is_autojoin_chan(chptr->chname))
230 return (ERR_OPERSPVERIFY);
231 #endif
232 #endif
233
234 #ifdef JOINTHROTTLE
235 if (!IsAnOper(cptr) &&
236 (chptr->mode.extmode & EXTMODE_JOINTHROTTLE) && isjthrottled(cptr, chptr))
237 return ERR_TOOMANYJOINS;
238 #endif
239
240 return 0;
241 }
242
243 #ifdef JOINTHROTTLE
isjthrottled(aClient * cptr,aChannel * chptr)244 static int isjthrottled(aClient *cptr, aChannel *chptr)
245 {
246 CmodeParam *m;
247 aJFlood *e;
248 int num=0, t=0;
249
250 if (!MyClient(cptr))
251 return 0;
252
253 for (m = chptr->mode.extmodeparam; m; m=m->next)
254 if (m->flag == 'j')
255 {
256 num = ((aModejEntry *)m)->num;
257 t = ((aModejEntry *)m)->t;
258 break;
259 }
260
261 if (!num || !t)
262 return 0;
263
264 /* Grab user<->chan entry.. */
265 for (e = cptr->user->jflood; e; e=e->next_u)
266 if (e->chptr == chptr)
267 break;
268
269 if (!e)
270 return 0; /* Not present, so cannot be throttled */
271
272 /* Ok... now the actual check:
273 * if ([timer valid] && [one more join would exceed num])
274 */
275 if (((TStime() - e->firstjoin) < t) && (e->numjoins == num))
276 return 1; /* Throttled */
277
278 return 0;
279 }
280
cmodej_increase_usercounter(aClient * cptr,aChannel * chptr)281 static void cmodej_increase_usercounter(aClient *cptr, aChannel *chptr)
282 {
283 CmodeParam *m;
284 aJFlood *e;
285 int num=0, t=0;
286
287 if (!MyClient(cptr))
288 return;
289
290 for (m = chptr->mode.extmodeparam; m; m=m->next)
291 if (m->flag == 'j')
292 {
293 num = ((aModejEntry *)m)->num;
294 t = ((aModejEntry *)m)->t;
295 break;
296 }
297
298 if (!num || !t)
299 return;
300
301 /* Grab user<->chan entry.. */
302 for (e = cptr->user->jflood; e; e=e->next_u)
303 if (e->chptr == chptr)
304 break;
305
306 if (!e)
307 {
308 /* Allocate one */
309 e = cmodej_addentry(cptr, chptr);
310 e->firstjoin = TStime();
311 e->numjoins = 1;
312 } else
313 if ((TStime() - e->firstjoin) < t) /* still valid? */
314 {
315 e->numjoins++;
316 } else {
317 /* reset :p */
318 e->firstjoin = TStime();
319 e->numjoins = 1;
320 }
321 }
322
323 #endif
324
325 /*
326 ** m_join
327 ** parv[0] = sender prefix
328 ** parv[1] = channel
329 ** parv[2] = channel password (key)
330 */
CMD_FUNC(m_join)331 DLLFUNC CMD_FUNC(m_join)
332 {
333 int r;
334
335 if (bouncedtimes)
336 sendto_realops("m_join: bouncedtimes=%d??? [please report at http://bugs.unrealircd.org/]", bouncedtimes);
337 bouncedtimes = 0;
338 if (IsServer(sptr))
339 return 0;
340 r = do_join(cptr, sptr, parc, parv);
341 bouncedtimes = 0;
342 return r;
343 }
344
345 /* Routine that actually makes a user join the channel
346 * this does no actual checking (banned, etc.) it just adds the user
347 */
_join_channel(aChannel * chptr,aClient * cptr,aClient * sptr,int flags)348 DLLFUNC void _join_channel(aChannel *chptr, aClient *cptr, aClient *sptr, int flags)
349 {
350 char *parv[] = { 0, 0 };
351 /*
352 ** Complete user entry to the new channel (if any)
353 */
354 add_user_to_channel(chptr, sptr, flags);
355 /*
356 ** notify all other users on the new channel
357 */
358 if (chptr->mode.mode & MODE_AUDITORIUM)
359 {
360 if (MyClient(sptr))
361 sendto_one(sptr, ":%s!%s@%s JOIN :%s",
362 sptr->name, sptr->user->username,
363 GetHost(sptr), chptr->chname);
364 sendto_chanops_butone(NULL, chptr, ":%s!%s@%s JOIN :%s",
365 sptr->name, sptr->user->username,
366 GetHost(sptr), chptr->chname);
367 }
368 else
369 sendto_channel_butserv(chptr, sptr,
370 ":%s JOIN :%s", sptr->name, chptr->chname);
371
372 sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3, sptr->name, MSG_JOIN,
373 TOK_JOIN, "%s", chptr->chname);
374
375 #ifdef JOIN_INSTEAD_OF_SJOIN_ON_REMOTEJOIN
376 if ((MyClient(sptr) && !(flags & CHFL_CHANOP)) || !MyClient(sptr))
377 sendto_serv_butone_token_opt(cptr, OPT_SJ3, sptr->name, MSG_JOIN,
378 TOK_JOIN, "%s", chptr->chname);
379 if (flags && !(flags & CHFL_DEOPPED))
380 {
381 #endif
382 /* I _know_ that the "@%s " look a bit wierd
383 with the space and all .. but its to get around
384 a SJOIN bug --stskeeps */
385 sendto_serv_butone_token_opt(cptr, OPT_SJ3|OPT_SJB64,
386 me.name, MSG_SJOIN, TOK_SJOIN,
387 "%B %s :%s%s ", (long)chptr->creationtime,
388 chptr->chname, chfl_to_sjoin_symbol(flags), sptr->name);
389 sendto_serv_butone_token_opt(cptr, OPT_SJ3|OPT_NOT_SJB64,
390 me.name, MSG_SJOIN, TOK_SJOIN,
391 "%li %s :%s%s ", chptr->creationtime,
392 chptr->chname, chfl_to_sjoin_symbol(flags), sptr->name);
393 #ifdef JOIN_INSTEAD_OF_SJOIN_ON_REMOTEJOIN
394 }
395 #endif
396
397 if (MyClient(sptr))
398 {
399 /*
400 ** Make a (temporal) creationtime, if someone joins
401 ** during a net.reconnect : between remote join and
402 ** the mode with TS. --Run
403 */
404 if (chptr->creationtime == 0)
405 {
406 chptr->creationtime = TStime();
407 sendto_serv_butone_token(cptr, me.name,
408 MSG_MODE, TOK_MODE, "%s + %lu",
409 chptr->chname, chptr->creationtime);
410 }
411 del_invite(sptr, chptr);
412 if (flags && !(flags & CHFL_DEOPPED))
413 {
414 #ifndef PREFIX_AQ
415 if ((flags & CHFL_CHANOWNER) || (flags & CHFL_CHANPROT))
416 {
417 /* +ao / +qo for when PREFIX_AQ is off */
418 sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3,
419 me.name,
420 MSG_MODE, TOK_MODE, "%s +o%c %s %s %lu",
421 chptr->chname, chfl_to_chanmode(flags), sptr->name, sptr->name,
422 chptr->creationtime);
423 } else {
424 #endif
425 /* +v/+h/+o (and +a/+q if PREFIX_AQ is on) */
426 sendto_serv_butone_token_opt(cptr, OPT_NOT_SJ3,
427 me.name,
428 MSG_MODE, TOK_MODE, "%s +%c %s %lu",
429 chptr->chname, chfl_to_chanmode(flags), sptr->name,
430 chptr->creationtime);
431 #ifndef PREFIX_AQ
432 }
433 #endif
434 }
435 if (chptr->topic)
436 {
437 sendto_one(sptr, rpl_str(RPL_TOPIC),
438 me.name, sptr->name, chptr->chname, chptr->topic);
439 sendto_one(sptr,
440 rpl_str(RPL_TOPICWHOTIME), me.name,
441 sptr->name, chptr->chname, chptr->topic_nick,
442 chptr->topic_time);
443 }
444 if (chptr->users == 1 && (MODES_ON_JOIN
445 #ifdef EXTCMODE
446 || iConf.modes_on_join.extmodes)
447 #endif
448 )
449 {
450 #ifdef EXTCMODE
451 int i;
452 chptr->mode.extmode = iConf.modes_on_join.extmodes;
453 /* Param fun */
454 for (i = 0; i <= Channelmode_highest; i++)
455 {
456 if (!Channelmode_Table[i].flag || !Channelmode_Table[i].paracount)
457 continue;
458 if (chptr->mode.extmode & Channelmode_Table[i].mode)
459 {
460 CmodeParam *p;
461 p = Channelmode_Table[i].put_param(NULL, iConf.modes_on_join.extparams[i]);
462 AddListItem(p, chptr->mode.extmodeparam);
463 }
464 }
465 #endif
466 chptr->mode.mode = MODES_ON_JOIN;
467 #ifdef NEWCHFLOODPROT
468 if (iConf.modes_on_join.floodprot.per)
469 {
470 chptr->mode.floodprot = MyMalloc(sizeof(ChanFloodProt));
471 memcpy(chptr->mode.floodprot, &iConf.modes_on_join.floodprot, sizeof(ChanFloodProt));
472 }
473 #else
474 chptr->mode.kmode = iConf.modes_on_join.kmode;
475 chptr->mode.per = iConf.modes_on_join.per;
476 chptr->mode.msgs = iConf.modes_on_join.msgs;
477 #endif
478 *modebuf = *parabuf = 0;
479 channel_modes(sptr, modebuf, parabuf, chptr);
480 /* This should probably be in the SJOIN stuff */
481 sendto_serv_butone_token(&me, me.name, MSG_MODE, TOK_MODE,
482 "%s %s %s %lu", chptr->chname, modebuf, parabuf,
483 chptr->creationtime);
484 sendto_one(sptr, ":%s MODE %s %s %s", me.name, chptr->chname, modebuf, parabuf);
485 }
486 parv[0] = sptr->name;
487 parv[1] = chptr->chname;
488 do_cmd(cptr, sptr, "NAMES", 2, parv);
489 RunHook4(HOOKTYPE_LOCAL_JOIN, cptr, sptr,chptr,parv);
490 } else {
491 RunHook4(HOOKTYPE_REMOTE_JOIN, cptr, sptr, chptr, parv); /* (rarely used) */
492 }
493
494 #ifdef NEWCHFLOODPROT
495 /* I'll explain this only once:
496 * 1. if channel is +f
497 * 2. local client OR synced server
498 * 3. then, increase floodcounter
499 * 4. if we reached the limit AND only if source was a local client.. do the action (+i).
500 * Nr 4 is done because otherwise you would have a noticeflood with 'joinflood detected'
501 * from all servers.
502 */
503 if (chptr->mode.floodprot && (MyClient(sptr) || sptr->srvptr->serv->flags.synced) &&
504 !IsULine(sptr) && do_chanflood(chptr->mode.floodprot, FLD_JOIN) && MyClient(sptr))
505 {
506 do_chanflood_action(chptr, FLD_JOIN, "join");
507 }
508 #endif
509 }
510
511 /** User request to join a channel.
512 * This routine can be called from both m_join or via do_join->can_join->do_join
513 * if the channel is 'linked' (chmode +L). We use a counter 'bouncedtimes' which
514 * is set to 0 in m_join, increased every time we enter this loop and decreased
515 * anytime we leave the loop. So be carefull ;p.
516 */
CMD_FUNC(_do_join)517 DLLFUNC CMD_FUNC(_do_join)
518 {
519 char jbuf[BUFSIZE];
520 Membership *lp;
521 aChannel *chptr;
522 char *name, *key = NULL, *link = NULL;
523 int i, flags = 0;
524 char *p = NULL, *p2 = NULL;
525
526 #define RET(x) { bouncedtimes--; return x; }
527
528 if (parc < 2 || *parv[1] == '\0')
529 {
530 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
531 me.name, parv[0], "JOIN");
532 return 0;
533 }
534 bouncedtimes++;
535 /* don't use 'return x;' but 'RET(x)' from here ;p */
536
537 if (bouncedtimes > MAXBOUNCE)
538 {
539 /* bounced too many times */
540 sendto_one(sptr,
541 ":%s %s %s :*** Couldn't join %s ! - Link setting was too bouncy",
542 me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", sptr->name, parv[1]);
543 RET(0)
544 }
545
546 *jbuf = '\0';
547 /*
548 ** Rebuild list of channels joined to be the actual result of the
549 ** JOIN. Note that "JOIN 0" is the destructive problem.
550 */
551 for (i = 0, name = strtoken(&p, parv[1], ","); name;
552 name = strtoken(&p, NULL, ","))
553 {
554 /* pathological case only on longest channel name.
555 ** If not dealt with here, causes desynced channel ops
556 ** since ChannelExists() doesn't see the same channel
557 ** as one being joined. cute bug. Oct 11 1997, Dianora/comstud
558 ** Copied from Dianora's "hybrid 5" ircd.
559 */
560
561 if (strlen(name) > CHANNELLEN) /* same thing is done in get_channel() */
562 name[CHANNELLEN] = '\0';
563
564 if (MyConnect(sptr))
565 clean_channelname(name);
566 if (check_channelmask(sptr, cptr, name) == -1)
567 continue;
568 if (*name == '0' && !atoi(name))
569 {
570 (void)strcpy(jbuf, "0");
571 i = 1;
572 continue;
573 }
574 else if (!IsChannelName(name))
575 {
576 if (MyClient(sptr))
577 sendto_one(sptr,
578 err_str(ERR_NOSUCHCHANNEL), me.name,
579 parv[0], name);
580 continue;
581 }
582 if (*jbuf)
583 (void)strlcat(jbuf, ",", sizeof jbuf);
584 (void)strlncat(jbuf, name, sizeof jbuf, sizeof(jbuf) - i - 1);
585 i += strlen(name) + 1;
586 }
587 /* This strcpy should be safe since jbuf contains the "filtered"
588 * result of parv[1] which should never be larger than the source.
589 */
590 (void)strcpy(parv[1], jbuf);
591
592 p = NULL;
593 if (parv[2])
594 key = strtoken(&p2, parv[2], ",");
595 parv[2] = NULL; /* for m_names call later, parv[parc] must == NULL */
596 for (name = strtoken(&p, jbuf, ","); name;
597 key = (key) ? strtoken(&p2, NULL, ",") : NULL,
598 name = strtoken(&p, NULL, ","))
599 {
600 /*
601 ** JOIN 0 sends out a part for all channels a user
602 ** has joined.
603 */
604 if (*name == '0' && !atoi(name))
605 {
606 while ((lp = sptr->user->channel))
607 {
608 chptr = lp->chptr;
609 sendto_channel_butserv(chptr, sptr,
610 PARTFMT2, parv[0], chptr->chname,
611 "Left all channels");
612 if (MyConnect(sptr))
613 RunHook4(HOOKTYPE_LOCAL_PART, cptr, sptr, chptr, "Left all channels");
614 remove_user_from_channel(sptr, chptr);
615 }
616 sendto_serv_butone_token(cptr, parv[0],
617 MSG_JOIN, TOK_JOIN, "0");
618 continue;
619 }
620
621 if (MyConnect(sptr))
622 {
623 /*
624 ** local client is first to enter previously nonexistant
625 ** channel so make them (rightfully) the Channel
626 ** Operator.
627 */
628 /* Where did this come from? Potvin ? --Stskeeps
629 flags = (ChannelExists(name)) ? CHFL_DEOPPED :
630 CHFL_CHANOWNER;
631
632 */
633
634 flags =
635 (ChannelExists(name)) ? CHFL_DEOPPED : LEVEL_ON_JOIN;
636
637 if (!IsAnOper(sptr)) /* opers can join unlimited chans */
638 if (sptr->user->joined >= MAXCHANNELSPERUSER)
639 {
640 sendto_one(sptr,
641 err_str
642 (ERR_TOOMANYCHANNELS),
643 me.name, parv[0], name);
644 RET(0)
645 }
646 /* RESTRICTCHAN */
647 if (conf_deny_channel)
648 {
649 if (!IsOper(sptr) && !IsULine(sptr))
650 {
651 ConfigItem_deny_channel *d;
652 if ((d = Find_channel_allowed(cptr, name)))
653 {
654 if (d->warn)
655 {
656 sendto_snomask(SNO_EYES, "*** %s tried to join forbidden channel %s",
657 get_client_name(sptr, 1), name);
658 }
659 if (d->reason)
660 sendto_one(sptr,
661 ":%s %s %s :*** Can not join %s: %s",
662 me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", sptr->name, name, d->reason);
663 if (d->redirect)
664 {
665 sendto_one(sptr,
666 ":%s %s %s :*** Redirecting you to %s",
667 me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", sptr->name, d->redirect);
668 parv[0] = sptr->name;
669 parv[1] = d->redirect;
670 do_join(cptr, sptr, 2, parv);
671 }
672 if (d->class) {
673 sendto_one(sptr,
674 ":%s %s %s :*** Can not join %s: Your class is not allowed",
675 me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE", sptr->name, name);
676 }
677 continue;
678 }
679 }
680 }
681 /* ugly set::spamfilter::virus-help-channel-deny hack.. */
682 if (SPAMFILTER_VIRUSCHANDENY && SPAMFILTER_VIRUSCHAN &&
683 !strcasecmp(name, SPAMFILTER_VIRUSCHAN) &&
684 !IsAnOper(sptr) && !spamf_ugly_vchanoverride)
685 {
686 int invited = 0;
687 Link *lp;
688 aChannel *chptr = find_channel(name, NULL);
689
690 if (chptr)
691 {
692 for (lp = sptr->user->invited; lp; lp = lp->next)
693 if (lp->value.chptr == chptr)
694 invited = 1;
695 }
696 if (!invited)
697 {
698 sendnotice(sptr, "*** Cannot join '%s' because it's the virus-help-channel which is "
699 "reserved for infected users only", name);
700 continue;
701 }
702 }
703 }
704
705 chptr = get_channel(sptr, name, CREATE);
706 if (chptr && (lp = find_membership_link(sptr->user->channel, chptr)))
707 continue;
708
709 if (!chptr)
710 continue;
711
712 i = HOOK_CONTINUE;
713 if (!MyConnect(sptr))
714 flags = CHFL_DEOPPED;
715 else
716 {
717 Hook *h;
718 for (h = Hooks[HOOKTYPE_PRE_LOCAL_JOIN]; h; h = h->next)
719 {
720 i = (*(h->func.intfunc))(sptr,chptr,parv);
721 if (i == HOOK_DENY || i == HOOK_ALLOW)
722 break;
723 }
724 /* Denied, get out now! */
725 if (i == HOOK_DENY)
726 {
727 /* Rejected... if we just created a new chan we should destroy it too. -- Syzop */
728 if (!chptr->users)
729 sub1_from_channel(chptr);
730 continue;
731 }
732 /* If they are allowed, don't check can_join */
733 if (i != HOOK_ALLOW &&
734 (i = can_join(cptr, sptr, chptr, key, link, parv)))
735 {
736 if (i != -1)
737 sendto_one(sptr, err_str(i),
738 me.name, parv[0], name);
739 continue;
740 }
741 #ifdef JOINTHROTTLE
742 cmodej_increase_usercounter(cptr, chptr);
743 #endif
744 }
745
746 join_channel(chptr, cptr, sptr, flags);
747 }
748 RET(0)
749 #undef RET
750 }
751