ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_join.c
Revision: 2663
Committed: Thu Dec 12 19:42:22 2013 UTC (10 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 19300 byte(s)
Log Message:
- m_join.c:m_join(): actually test conf->reason for being a NULL pointer

File Contents

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

Properties

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