/[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 896 - (show annotations)
Sat Nov 3 08:54:09 2007 UTC (12 years, 1 month ago) by michael
File MIME type: text/x-chdr
File size: 18661 byte(s)
- Killed s_stats.c

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

Properties

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

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