ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/core/m_join.c
Revision: 1309
Committed: Sun Mar 25 11:24:18 2012 UTC (12 years ago) by michael
Content type: text/x-csrc
File size: 18658 byte(s)
Log Message:
- renaming files:

  ircd_parser.y -> conf_parser.y
  ircd_lexer.l  -> conf_lexer.l
  s_conf.c      -> conf.c
  s_conf.h      -> conf.h
  s_log.c       -> log.c
  s_log.h       -> log.h

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

Properties

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