/[svn]/ircd-hybrid/branches/8.0.x/modules/core/m_join.c
ViewVC logotype

Contents of /ircd-hybrid/branches/8.0.x/modules/core/m_join.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1685 - (show annotations)
Wed Dec 19 20:24:52 2012 UTC (7 years, 7 months ago) by michael
File MIME type: text/x-chdr
File size: 18364 byte(s)
- STATS q|Q now shows how many times a resv{} block has been matched.
  (Just like STATS x|X)

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

Properties

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

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