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: 1751
Committed: Wed Jan 16 18:30:52 2013 UTC (11 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 19280 byte(s)
Log Message:
- Forward-port -r1750 [IMPORTANT: nick and topic lengths are now configurable
  via ircd.conf. A max_nick_length, as well as a max_topic_length configuration
  option can now be found in the serverinfo{} block]
- OpenSSL 0.9.8s and higher is now required in order to enable ssl support

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

Properties

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