ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_join.c
Revision: 3342
Committed: Fri Apr 18 13:37:41 2014 UTC (12 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 18561 byte(s)
Log Message:
- Cleaned up style & fixed comments

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