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: 1687
Committed: Wed Dec 19 20:47:44 2012 UTC (11 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 18383 byte(s)
Log Message:
- Forward-port -r1685 [STATS q|Q now shows how many times a resv{}
  block has been matched]

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

Properties

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