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: 3162
Committed: Sat Mar 15 19:43:39 2014 UTC (10 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 18175 byte(s)
Log Message:
- ms_join(), ms_sjoin(): made some server notices more descriptive

File Contents

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

Properties

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