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: 3186
Committed: Thu Mar 20 18:09:34 2014 UTC (10 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 18143 byte(s)
Log Message:
- Get rid of the ID() macro

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

Properties

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