/[svn]/ircd-hybrid-7.2/modules/core/m_join.c
ViewVC logotype

Contents of /ircd-hybrid-7.2/modules/core/m_join.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 632 - (show annotations)
Thu Jun 1 10:53:00 2006 UTC (14 years, 10 months ago) by michael
File MIME type: text/x-chdr
File size: 19292 byte(s)
- Added channel::disable_fake_channels which disallows creation of channels
  that have ascii 2, 3, 31 and 160 in their names.
- Minor improvements and cleanups to channel name validation routines
  backported from 7.3

1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_join.c: Joins a channel.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "tools.h"
27 #include "handlers.h"
28 #include "channel.h"
29 #include "channel_mode.h"
30 #include "client.h"
31 #include "common.h" /* bleah */
32 #include "hash.h"
33 #include "irc_string.h"
34 #include "sprintf_irc.h"
35 #include "ircd.h"
36 #include "list.h"
37 #include "numeric.h"
38 #include "send.h"
39 #include "s_serv.h"
40 #include "s_conf.h"
41 #include "msg.h"
42 #include "parse.h"
43 #include "modules.h"
44
45
46 static void m_join(struct Client *, struct Client *, int, char **);
47 static void ms_join(struct Client *, struct Client *, int, char **);
48 static void do_join_0(struct Client *client_p, struct Client *source_p);
49
50 static void set_final_mode(struct Mode *, struct Mode *);
51 static void remove_our_modes(struct Channel *, struct Client *);
52 static void remove_a_mode(struct Channel *, struct Client *, int, char);
53
54 static char modebuf[MODEBUFLEN];
55 static char parabuf[MODEBUFLEN];
56 static char sendbuf[MODEBUFLEN];
57 static char *mbuf;
58
59 struct Message join_msgtab = {
60 "JOIN", 0, 0, 2, 0, MFLG_SLOW, 0,
61 {m_unregistered, m_join, ms_join, m_ignore, m_join, m_ignore}
62 };
63
64 #ifndef STATIC_MODULES
65 void
66 _modinit(void)
67 {
68 mod_add_cmd(&join_msgtab);
69 }
70
71 void
72 _moddeinit(void)
73 {
74 mod_del_cmd(&join_msgtab);
75 }
76
77 const char *_version = "$Revision$";
78 #endif
79
80 /* last0() stolen from ircu */
81 static char *
82 last0(struct Client *client_p, struct Client *source_p, char *chanlist)
83 {
84 char *p;
85 int join0 = 0;
86
87 for (p = chanlist; *p; ++p) /* find last "JOIN 0" */
88 {
89 if (*p == '0' && (*(p + 1) == ',' || *(p + 1) == '\0'))
90 {
91 if ((*p + 1) == ',')
92 ++p;
93
94 chanlist = p + 1;
95 join0 = 1;
96 }
97 else
98 {
99 while (*p != ',' && *p != '\0') /* skip past channel name */
100 ++p;
101
102 if (*p == '\0') /* hit the end */
103 break;
104 }
105 }
106
107 if (join0)
108 do_join_0(client_p, source_p);
109
110 return chanlist;
111 }
112
113 /* m_join()
114 * parv[0] = sender prefix
115 * parv[1] = channel
116 * parv[2] = channel password (key)
117 */
118 static void
119 m_join(struct Client *client_p, struct Client *source_p,
120 int parc, char *parv[])
121 {
122 char *p = NULL;
123 char *key_list = NULL;
124 char *chan_list = NULL;
125 char *chan = NULL;
126 struct Channel *chptr = NULL;
127 int i = 0;
128 unsigned int flags = 0;
129
130 if (EmptyString(parv[1]))
131 {
132 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
133 me.name, source_p->name, "JOIN");
134 return;
135 }
136
137 assert(client_p == source_p);
138
139 key_list = parv[2];
140 chan_list = last0(client_p, source_p, parv[1]);
141
142 for (chan = strtoken(&p, chan_list, ","); chan;
143 chan = strtoken(&p, NULL, ","))
144 {
145 char *key = NULL;
146
147 /* If we have any more keys, take the first for this channel. */
148 if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
149 *key_list++ = '\0';
150
151 /* Empty keys are the same as no keys. */
152 if (key && *key == '\0')
153 key = NULL;
154
155 if (!check_channel_name(chan, 1))
156 {
157 sendto_one(source_p, form_str(ERR_BADCHANNAME),
158 me.name, source_p->name, chan);
159 continue;
160 }
161
162 if (ConfigChannel.disable_local_channels && (*chan == '&'))
163 {
164 sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
165 me.name, source_p->name, chan);
166 continue;
167 }
168
169 if (!IsExemptResv(source_p) &&
170 !(IsOper(source_p) && ConfigFileEntry.oper_pass_resv) &&
171 (!hash_find_resv(chan) == ConfigChannel.restrict_channels))
172 {
173 sendto_one(source_p, form_str(ERR_BADCHANNAME),
174 me.name, source_p->name, chan);
175 sendto_realops_flags(UMODE_SPY, L_ALL,
176 "User %s (%s@%s) is attempting to join locally juped channel %s",
177 source_p->name, source_p->username, source_p->host, chan);
178 continue;
179 }
180
181 if ((dlink_list_length(&source_p->channel) >= ConfigChannel.max_chans_per_user) &&
182 (!IsOper(source_p) || (dlink_list_length(&source_p->channel) >=
183 ConfigChannel.max_chans_per_user * 3)))
184 {
185 sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
186 me.name, source_p->name, chan);
187 break;
188 }
189
190 if ((chptr = hash_find_channel(chan)) != NULL)
191 {
192 if (IsMember(source_p, chptr))
193 continue;
194
195 if (splitmode && !IsOper(source_p) && (*chan != '&') &&
196 ConfigChannel.no_join_on_split)
197 {
198 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
199 me.name, source_p->name, chan);
200 continue;
201 }
202
203 /*
204 * This should never be the case unless there is some sort of
205 * persistant channels.
206 */
207 if (dlink_list_length(&chptr->members) == 0)
208 flags = CHFL_CHANOP;
209 else
210 flags = 0;
211 }
212 else
213 {
214 if (splitmode && !IsOper(source_p) && (*chan != '&') &&
215 (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split))
216 {
217 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
218 me.name, source_p->name, chan);
219 continue;
220 }
221
222 flags = CHFL_CHANOP;
223 chptr = make_channel(chan);
224 }
225
226 if (!IsOper(source_p))
227 check_spambot_warning(source_p, chptr->chname);
228
229 /*
230 * can_join checks for +i key, bans.
231 */
232 if ((i = can_join(source_p, chptr, key)))
233 {
234 sendto_one(source_p, form_str(i), me.name,
235 source_p->name, chptr->chname);
236 continue;
237 }
238
239 add_user_to_channel(chptr, source_p, flags, YES);
240
241 /*
242 * Set timestamp if appropriate, and propagate
243 */
244 if (flags & CHFL_CHANOP)
245 {
246 chptr->channelts = CurrentTime;
247 chptr->mode.mode |= MODE_TOPICLIMIT;
248 chptr->mode.mode |= MODE_NOPRIVMSGS;
249
250 sendto_server(client_p, source_p, chptr, CAP_TS6, NOCAPS, LL_ICLIENT,
251 ":%s SJOIN %lu %s +nt :@%s",
252 me.id, (unsigned long)chptr->channelts,
253 chptr->chname, source_p->id);
254 sendto_server(client_p, source_p, chptr, NOCAPS, CAP_TS6, LL_ICLIENT,
255 ":%s SJOIN %lu %s +nt :@%s",
256 me.name, (unsigned long)chptr->channelts,
257 chptr->chname, source_p->name);
258 /*
259 * notify all other users on the new channel
260 */
261 sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN :%s",
262 source_p->name, source_p->username,
263 source_p->host, chptr->chname);
264 sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s MODE %s +nt",
265 me.name, chptr->chname);
266 }
267 else
268 {
269 sendto_server(client_p, source_p, chptr, CAP_TS6, NOCAPS, LL_ICLIENT,
270 ":%s JOIN %lu %s +",
271 source_p->id, (unsigned long)chptr->channelts,
272 chptr->chname);
273 sendto_server(client_p, source_p, chptr, NOCAPS, CAP_TS6, LL_ICLIENT,
274 ":%s SJOIN %lu %s + :%s",
275 me.name, (unsigned long)chptr->channelts,
276 chptr->chname, source_p->name);
277
278 sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN :%s",
279 source_p->name, source_p->username,
280 source_p->host, chptr->chname);
281 }
282
283 del_invite(chptr, source_p);
284
285 if (chptr->topic != NULL)
286 {
287 sendto_one(source_p, form_str(RPL_TOPIC), me.name,
288 source_p->name, chptr->chname, chptr->topic);
289
290 sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
291 me.name, source_p->name, chptr->chname,
292 chptr->topic_info, chptr->topic_time);
293 }
294
295 channel_member_names(source_p, chptr, 1);
296
297 source_p->localClient->last_join_time = CurrentTime;
298 }
299 }
300
301 /* ms_join()
302 *
303 * inputs - parv[0] = uid
304 * parv[1] = ts
305 * parv[2] = channel name
306 * parv[3] = modes
307 * output - none
308 * side effects - handles remote JOIN's sent by servers. In TSora
309 * remote clients are joined using SJOIN, hence a
310 * JOIN sent by a server on behalf of a client is an error.
311 * here, the initial code is in to take an extra parameter
312 * and use it for the TimeStamp on a new channel.
313 */
314 static void
315 ms_join(struct Client *client_p, struct Client *source_p,
316 int parc, char *parv[])
317 {
318 time_t newts = 0;
319 time_t oldts = 0;
320 int args = 0;
321 int keep_our_modes = 1;
322 int keep_new_modes = 1;
323 int isnew = 0;
324 const char *s = NULL;
325 const char *servername = NULL;
326 struct Channel *chptr = NULL;
327 struct Mode mode, *oldmode;
328
329 if (parc == 2 && !irccmp(parv[1], "0"))
330 {
331 do_join_0(client_p, source_p);
332 return;
333 }
334
335 if (parc < 4 || *parv[2] == '&')
336 return;
337
338 if (!check_channel_name(parv[2], 0))
339 {
340 sendto_realops_flags(UMODE_DEBUG, L_ALL,
341 "*** Too long or invalid channel name from %s: %s",
342 client_p->name, parv[2]);
343 return;
344 }
345
346 mbuf = modebuf;
347 mode.mode = mode.limit = 0;
348 mode.key[0] = '\0';
349
350 for (s = parv[3]; *s; ++s)
351 {
352 switch (*s)
353 {
354 case 't':
355 mode.mode |= MODE_TOPICLIMIT;
356 break;
357 case 'n':
358 mode.mode |= MODE_NOPRIVMSGS;
359 break;
360 case 's':
361 mode.mode |= MODE_SECRET;
362 break;
363 case 'm':
364 mode.mode |= MODE_MODERATED;
365 break;
366 case 'i':
367 mode.mode |= MODE_INVITEONLY;
368 break;
369 case 'p':
370 mode.mode |= MODE_PRIVATE;
371 break;
372 case 'k':
373 if (parc < 5 + args)
374 return;
375
376 strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
377 args++;
378 break;
379 case 'l':
380 if (parc < 5 + args)
381 return;
382
383 mode.limit = atoi(parv[4 + args]);
384 args++;
385 break;
386 }
387 }
388
389
390 if ((chptr = hash_find_channel(parv[2])) == NULL)
391 {
392 isnew = 1;
393 chptr = make_channel(parv[2]);
394 }
395
396 newts = atol(parv[1]);
397 oldts = chptr->channelts;
398 oldmode = &chptr->mode;
399
400 if (ConfigFileEntry.ignore_bogus_ts)
401 {
402 if (newts < 800000000)
403 {
404 sendto_realops_flags(UMODE_DEBUG, L_ALL,
405 "*** Bogus TS %lu on %s ignored from %s",
406 (unsigned long)newts, chptr->chname,
407 client_p->name);
408
409 newts = (oldts == 0) ? 0 : 800000000;
410 }
411 }
412 else
413 {
414 if (!newts && !isnew && oldts)
415 {
416 sendto_channel_local(ALL_MEMBERS, NO, chptr,
417 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
418 me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
419 sendto_realops_flags(UMODE_ALL, L_ALL,
420 "Server %s changing TS on %s from %lu to 0",
421 source_p->name, chptr->chname, (unsigned long)oldts);
422 }
423 }
424
425 if (isnew)
426 chptr->channelts = newts;
427 else if (newts == 0 || oldts == 0)
428 chptr->channelts = 0;
429 else if (newts == oldts)
430 ;
431 else if (newts < oldts)
432 {
433 keep_our_modes = NO;
434 chptr->channelts = newts;
435 }
436 else
437 keep_new_modes = NO;
438
439 if (!keep_new_modes)
440 mode = *oldmode;
441 else if (keep_our_modes)
442 {
443 mode.mode |= oldmode->mode;
444 if (oldmode->limit > mode.limit)
445 mode.limit = oldmode->limit;
446 if (strcmp(mode.key, oldmode->key) < 0)
447 strcpy(mode.key, oldmode->key);
448 }
449
450 set_final_mode(&mode, oldmode);
451 chptr->mode = mode;
452
453 /* Lost the TS, other side wins, so remove modes on this side */
454 if (!keep_our_modes)
455 {
456 remove_our_modes(chptr, source_p);
457 sendto_channel_local(ALL_MEMBERS, NO, chptr,
458 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
459 me.name, chptr->chname, chptr->chname,
460 (unsigned long)oldts, (unsigned long)newts);
461 }
462
463 if (*modebuf != '\0')
464 {
465 servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
466 me.name : source_p->name;
467
468 /* This _SHOULD_ be to ALL_MEMBERS
469 * It contains only +imnpstlk, etc */
470 sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s MODE %s %s %s",
471 servername, chptr->chname, modebuf, parabuf);
472 }
473
474 if (!IsMember(source_p, chptr))
475 {
476 add_user_to_channel(chptr, source_p, 0, YES);
477 sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s JOIN :%s",
478 source_p->name, source_p->username,
479 source_p->host, chptr->chname);
480 }
481
482 sendto_server(client_p, NULL, chptr, CAP_TS6, NOCAPS, NOFLAGS,
483 ":%s JOIN %lu %s +",
484 ID(source_p), (unsigned long)chptr->channelts, chptr->chname);
485 sendto_server(client_p, NULL, chptr, NOCAPS, CAP_TS6, NOFLAGS,
486 ":%s SJOIN %lu %s + :%s",
487 source_p->servptr->name, (unsigned long)chptr->channelts,
488 chptr->chname, source_p->name);
489 }
490
491 /* do_join_0()
492 *
493 * inputs - pointer to client doing join 0
494 * output - NONE
495 * side effects - Use has decided to join 0. This is legacy
496 * from the days when channels were numbers not names. *sigh*
497 * There is a bunch of evilness necessary here due to
498 * anti spambot code.
499 */
500 static void
501 do_join_0(struct Client *client_p, struct Client *source_p)
502 {
503 struct Channel *chptr = NULL;
504 dlink_node *ptr = NULL, *ptr_next = NULL;
505
506 if (source_p->channel.head && MyConnect(source_p) && !IsOper(source_p))
507 check_spambot_warning(source_p, NULL);
508
509 DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
510 {
511 chptr = ((struct Membership *)ptr->data)->chptr;
512
513 sendto_server(client_p, NULL, chptr, CAP_TS6, NOCAPS, NOFLAGS,
514 ":%s PART %s", ID(source_p), chptr->chname);
515 sendto_server(client_p, NULL, chptr, NOCAPS, CAP_TS6, NOFLAGS,
516 ":%s PART %s", source_p->name, chptr->chname);
517 sendto_channel_local(ALL_MEMBERS, NO, chptr, ":%s!%s@%s PART %s",
518 source_p->name, source_p->username,
519 source_p->host, chptr->chname);
520
521 remove_user_from_channel(ptr->data);
522 }
523 }
524
525 /* set_final_mode()
526 *
527 * inputs - pointer to mode to setup
528 * - pointer to old mode
529 * output - NONE
530 * side effects -
531 */
532 static const struct mode_letter
533 {
534 unsigned int mode;
535 unsigned char letter;
536 } flags[] = {
537 { MODE_NOPRIVMSGS, 'n' },
538 { MODE_TOPICLIMIT, 't' },
539 { MODE_SECRET, 's' },
540 { MODE_MODERATED, 'm' },
541 { MODE_INVITEONLY, 'i' },
542 { MODE_PRIVATE, 'p' },
543 { 0, '\0' }
544 };
545
546 static void
547 set_final_mode(struct Mode *mode, struct Mode *oldmode)
548 {
549 char *pbuf = parabuf;
550 int what = 0;
551 int len;
552 int i;
553
554 for (i = 0; flags[i].letter; i++)
555 {
556 if ((flags[i].mode & mode->mode) &&
557 !(flags[i].mode & oldmode->mode))
558 {
559 if (what != 1)
560 {
561 *mbuf++ = '+';
562 what = 1;
563 }
564 *mbuf++ = flags[i].letter;
565 }
566 }
567
568 for (i = 0; flags[i].letter; i++)
569 {
570 if ((flags[i].mode & oldmode->mode) &&
571 !(flags[i].mode & mode->mode))
572 {
573 if (what != -1)
574 {
575 *mbuf++ = '-';
576 what = -1;
577 }
578 *mbuf++ = flags[i].letter;
579 }
580 }
581
582 if (oldmode->limit != 0 && mode->limit == 0)
583 {
584 if (what != -1)
585 {
586 *mbuf++ = '-';
587 what = -1;
588 }
589 *mbuf++ = 'l';
590 }
591
592 if (oldmode->key[0] && !mode->key[0])
593 {
594 if (what != -1)
595 {
596 *mbuf++ = '-';
597 what = -1;
598 }
599 *mbuf++ = 'k';
600 len = ircsprintf(pbuf, "%s ", oldmode->key);
601 pbuf += len;
602 }
603
604 if (mode->limit != 0 && oldmode->limit != mode->limit)
605 {
606 if (what != 1)
607 {
608 *mbuf++ = '+';
609 what = 1;
610 }
611 *mbuf++ = 'l';
612 len = ircsprintf(pbuf, "%d ", mode->limit);
613 pbuf += len;
614 }
615
616 if (mode->key[0] && strcmp(oldmode->key, mode->key))
617 {
618 if (what != 1)
619 {
620 *mbuf++ = '+';
621 what = 1;
622 }
623 *mbuf++ = 'k';
624 len = ircsprintf(pbuf, "%s ", mode->key);
625 pbuf += len;
626 }
627 *mbuf = '\0';
628 }
629
630 /* remove_our_modes()
631 *
632 * inputs - pointer to channel to remove modes from
633 * - client pointer
634 * output - NONE
635 * side effects - Go through the local members, remove all their
636 * chanop modes etc., this side lost the TS.
637 */
638 static void
639 remove_our_modes(struct Channel *chptr, struct Client *source_p)
640 {
641 remove_a_mode(chptr, source_p, CHFL_CHANOP, 'o');
642 #ifdef HALFOPS
643 remove_a_mode(chptr, source_p, CHFL_HALFOP, 'h');
644 #endif
645 remove_a_mode(chptr, source_p, CHFL_VOICE, 'v');
646 }
647
648 /* remove_a_mode()
649 *
650 * inputs -
651 * output - NONE
652 * side effects - remove ONE mode from a channel
653 */
654 static void
655 remove_a_mode(struct Channel *chptr, struct Client *source_p,
656 int mask, char flag)
657 {
658 dlink_node *ptr;
659 struct Membership *ms;
660 char lmodebuf[MODEBUFLEN];
661 const char *lpara[MAXMODEPARAMS];
662 int count = 0;
663 int lcount;
664
665 mbuf = lmodebuf;
666 *mbuf++ = '-';
667
668 for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
669 lpara[lcount] = "";
670 sendbuf[0] = '\0';
671
672 DLINK_FOREACH(ptr, chptr->members.head)
673 {
674 ms = ptr->data;
675
676 if ((ms->flags & mask) == 0)
677 continue;
678
679 ms->flags &= ~mask;
680
681 lpara[count++] = ms->client_p->name;
682
683 *mbuf++ = flag;
684
685 if (count >= MAXMODEPARAMS)
686 {
687 for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
688 {
689 if (*lpara[lcount] == '\0')
690 break;
691
692 strlcat(sendbuf, " ", sizeof(sendbuf));
693 strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
694 lpara[lcount] = "";
695 }
696
697 *mbuf = '\0';
698 sendto_channel_local(ALL_MEMBERS, NO, chptr,
699 ":%s MODE %s %s%s",
700 (IsHidden(source_p) ||
701 ConfigServerHide.hide_servers) ?
702 me.name : source_p->name,
703 chptr->chname, lmodebuf, sendbuf);
704 mbuf = lmodebuf;
705 *mbuf++ = '-';
706 count = 0;
707 sendbuf[0] = '\0';
708 }
709 }
710
711 if (count != 0)
712 {
713 *mbuf = '\0';
714 for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
715 {
716 if (*lpara[lcount] == '\0')
717 break;
718
719 strlcat(sendbuf, " ", sizeof(sendbuf));
720 strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
721 }
722 sendto_channel_local(ALL_MEMBERS, NO, chptr,
723 ":%s MODE %s %s%s",
724 (IsHidden(source_p) || ConfigServerHide.hide_servers) ?
725 me.name : source_p->name,
726 chptr->chname, lmodebuf, sendbuf);
727 }
728 }
729

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28