/[svn]/ircd-hybrid-7.2/modules/core/m_join.c
ViewVC logotype

Contents of /ircd-hybrid-7.2/modules/core/m_join.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 494 - (show annotations)
Wed Mar 1 16:26:31 2006 UTC (14 years, 5 months ago) by michael
File MIME type: text/x-chdr
File size: 19562 byte(s)
- Break the loop if a client has reached its channel limit

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

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28