ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/core/m_join.c
Revision: 741
Committed: Sun Jul 23 13:49:20 2006 UTC (19 years, 1 month ago) by adx
Content type: text/x-csrc
File size: 19901 byte(s)
Log Message:
+ removed s_conf.h and superseded parts of s_conf.c

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

Properties

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