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: 1167
Committed: Thu Aug 11 20:13:38 2011 UTC (12 years, 7 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_join.c
File size: 18696 byte(s)
Log Message:
- Improve services support
- Add channelmode +r

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 "list.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 "numeric.h"
36 #include "send.h"
37 #include "s_serv.h"
38 #include "s_conf.h"
39 #include "msg.h"
40 #include "parse.h"
41 #include "modules.h"
42
43
44 static void m_join(struct Client *, struct Client *, int, char *[]);
45 static void ms_join(struct Client *, struct Client *, int, char *[]);
46 static void do_join_0(struct Client *, struct Client *);
47
48 static void set_final_mode(struct Mode *, struct Mode *);
49 static void remove_our_modes(struct Channel *, struct Client *);
50 static void remove_a_mode(struct Channel *, struct Client *, int, char);
51
52 static char modebuf[MODEBUFLEN];
53 static char parabuf[MODEBUFLEN];
54 static char sendbuf[MODEBUFLEN];
55 static char *mbuf;
56
57 struct Message join_msgtab = {
58 "JOIN", 0, 0, 2, 0, MFLG_SLOW, 0,
59 { m_unregistered, m_join, ms_join, m_ignore, m_join, m_ignore }
60 };
61
62 void
63 _modinit(void)
64 {
65 mod_add_cmd(&join_msgtab);
66 }
67
68 void
69 _moddeinit(void)
70 {
71 mod_del_cmd(&join_msgtab);
72 }
73
74 const char *_version = "$Revision$";
75
76 /* last0() stolen from ircu */
77 static char *
78 last0(struct Client *client_p, struct Client *source_p, char *chanlist)
79 {
80 char *p;
81 int join0 = 0;
82
83 for (p = chanlist; *p; ++p) /* find last "JOIN 0" */
84 {
85 if (*p == '0' && (*(p + 1) == ',' || *(p + 1) == '\0'))
86 {
87 if ((*p + 1) == ',')
88 ++p;
89
90 chanlist = p + 1;
91 join0 = 1;
92 }
93 else
94 {
95 while (*p != ',' && *p != '\0') /* skip past channel name */
96 ++p;
97
98 if (*p == '\0') /* hit the end */
99 break;
100 }
101 }
102
103 if (join0)
104 do_join_0(client_p, source_p);
105
106 return chanlist;
107 }
108
109 /* m_join()
110 * parv[0] = sender prefix
111 * parv[1] = channel
112 * parv[2] = channel password (key)
113 */
114 static void
115 m_join(struct Client *client_p, struct Client *source_p,
116 int parc, char *parv[])
117 {
118 char *p = NULL;
119 char *key_list = NULL;
120 char *chan_list = NULL;
121 char *chan = NULL;
122 struct Channel *chptr = NULL;
123 int i = 0;
124 unsigned int flags = 0;
125
126 if (EmptyString(parv[1]))
127 {
128 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
129 me.name, source_p->name, "JOIN");
130 return;
131 }
132
133 assert(client_p == source_p);
134
135 key_list = parv[2];
136 chan_list = last0(client_p, source_p, parv[1]);
137
138 for (chan = strtoken(&p, chan_list, ","); chan;
139 chan = strtoken(&p, NULL, ","))
140 {
141 char *key = NULL;
142
143 /* If we have any more keys, take the first for this channel. */
144 if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
145 *key_list++ = '\0';
146
147 /* Empty keys are the same as no keys. */
148 if (key && *key == '\0')
149 key = NULL;
150
151 if (!check_channel_name(chan, 1))
152 {
153 sendto_one(source_p, form_str(ERR_BADCHANNAME),
154 me.name, source_p->name, chan);
155 continue;
156 }
157
158 if (ConfigChannel.disable_local_channels && (*chan == '&'))
159 {
160 sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
161 me.name, source_p->name, chan);
162 continue;
163 }
164
165 if (!IsExemptResv(source_p) &&
166 !(IsOper(source_p) && ConfigFileEntry.oper_pass_resv) &&
167 (!hash_find_resv(chan) == ConfigChannel.restrict_channels))
168 {
169 sendto_one(source_p, form_str(ERR_BADCHANNAME),
170 me.name, source_p->name, chan);
171 sendto_realops_flags(UMODE_SPY, L_ALL,
172 "User %s (%s@%s) is attempting to join locally juped channel %s",
173 source_p->name, source_p->username, source_p->host, chan);
174 continue;
175 }
176
177 if ((dlink_list_length(&source_p->channel) >= ConfigChannel.max_chans_per_user) &&
178 (!IsOper(source_p) || (dlink_list_length(&source_p->channel) >=
179 ConfigChannel.max_chans_per_user * 3)))
180 {
181 sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
182 me.name, source_p->name, chan);
183 break;
184 }
185
186 if ((chptr = hash_find_channel(chan)) != NULL)
187 {
188 if (IsMember(source_p, chptr))
189 continue;
190
191 if (splitmode && !IsOper(source_p) && (*chan != '&') &&
192 ConfigChannel.no_join_on_split)
193 {
194 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
195 me.name, source_p->name, chan);
196 continue;
197 }
198
199 /*
200 * can_join checks for +i key, bans.
201 */
202 if ((i = can_join(source_p, chptr, key)))
203 {
204 sendto_one(source_p, form_str(i), me.name,
205 source_p->name, chptr->chname);
206 continue;
207 }
208
209 /*
210 * This should never be the case unless there is some sort of
211 * persistant channels.
212 */
213 if (dlink_list_length(&chptr->members) == 0)
214 flags = CHFL_CHANOP;
215 else
216 flags = 0;
217 }
218 else
219 {
220 if (splitmode && !IsOper(source_p) && (*chan != '&') &&
221 (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split))
222 {
223 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
224 me.name, source_p->name, chan);
225 continue;
226 }
227
228 flags = CHFL_CHANOP;
229 chptr = make_channel(chan);
230 }
231
232 if (!IsOper(source_p))
233 check_spambot_warning(source_p, chptr->chname);
234
235 add_user_to_channel(chptr, source_p, flags, 1);
236
237 /*
238 * Set timestamp if appropriate, and propagate
239 */
240 if (flags & CHFL_CHANOP)
241 {
242 chptr->channelts = CurrentTime;
243 chptr->mode.mode |= MODE_TOPICLIMIT;
244 chptr->mode.mode |= MODE_NOPRIVMSGS;
245
246 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
247 ":%s SJOIN %lu %s +nt :@%s",
248 me.id, (unsigned long)chptr->channelts,
249 chptr->chname, source_p->id);
250 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
251 ":%s SJOIN %lu %s +nt :@%s",
252 me.name, (unsigned long)chptr->channelts,
253 chptr->chname, source_p->name);
254 /*
255 * notify all other users on the new channel
256 */
257 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
258 source_p->name, source_p->username,
259 source_p->host, chptr->chname);
260 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s +nt",
261 me.name, chptr->chname);
262 }
263 else
264 {
265 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
266 ":%s JOIN %lu %s +",
267 source_p->id, (unsigned long)chptr->channelts,
268 chptr->chname);
269 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
270 ":%s SJOIN %lu %s + :%s",
271 me.name, (unsigned long)chptr->channelts,
272 chptr->chname, source_p->name);
273
274 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
275 source_p->name, source_p->username,
276 source_p->host, chptr->chname);
277 }
278
279 del_invite(chptr, source_p);
280
281 if (chptr->topic != NULL)
282 {
283 sendto_one(source_p, form_str(RPL_TOPIC), me.name,
284 source_p->name, chptr->chname, chptr->topic);
285
286 sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
287 me.name, source_p->name, chptr->chname,
288 chptr->topic_info, chptr->topic_time);
289 }
290
291 channel_member_names(source_p, chptr, 1);
292
293 source_p->localClient->last_join_time = CurrentTime;
294 }
295 }
296
297 /* ms_join()
298 *
299 * inputs - parv[0] = uid
300 * parv[1] = ts
301 * parv[2] = channel name
302 * parv[3] = modes (Deprecated)
303 * output - none
304 * side effects - handles remote JOIN's sent by servers. In TSora
305 * remote clients are joined using SJOIN, hence a
306 * JOIN sent by a server on behalf of a client is an error.
307 * here, the initial code is in to take an extra parameter
308 * and use it for the TimeStamp on a new channel.
309 */
310 static void
311 ms_join(struct Client *client_p, struct Client *source_p,
312 int parc, char *parv[])
313 {
314 time_t newts = 0;
315 time_t oldts = 0;
316 int keep_our_modes = 1;
317 int keep_new_modes = 1;
318 int isnew = 0;
319 const char *servername = NULL;
320 struct Channel *chptr = NULL;
321 struct Mode mode, *oldmode;
322
323 if (parc == 2 && !irccmp(parv[1], "0"))
324 {
325 do_join_0(client_p, source_p);
326 return;
327 }
328
329 if (parc < 4 || *parv[2] == '&')
330 return;
331
332 if (!check_channel_name(parv[2], 0))
333 {
334 sendto_realops_flags(UMODE_DEBUG, L_ALL,
335 "*** Too long or invalid channel name from %s: %s",
336 client_p->name, parv[2]);
337 return;
338 }
339
340 mbuf = modebuf;
341 mode.mode = mode.limit = 0;
342 mode.key[0] = '\0';
343
344 if ((chptr = hash_find_channel(parv[2])) == NULL)
345 {
346 isnew = 1;
347 chptr = make_channel(parv[2]);
348 }
349
350 newts = atol(parv[1]);
351 oldts = chptr->channelts;
352 oldmode = &chptr->mode;
353
354 if (ConfigFileEntry.ignore_bogus_ts)
355 {
356 if (newts < 800000000)
357 {
358 sendto_realops_flags(UMODE_DEBUG, L_ALL,
359 "*** Bogus TS %lu on %s ignored from %s",
360 (unsigned long)newts, chptr->chname,
361 client_p->name);
362
363 newts = (oldts == 0) ? 0 : 800000000;
364 }
365 }
366 else
367 {
368 if (!newts && !isnew && oldts)
369 {
370 sendto_channel_local(ALL_MEMBERS, 0, chptr,
371 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
372 me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
373 sendto_realops_flags(UMODE_ALL, L_ALL,
374 "Server %s changing TS on %s from %lu to 0",
375 source_p->name, chptr->chname, (unsigned long)oldts);
376 }
377 }
378
379 if (isnew)
380 chptr->channelts = newts;
381 else if (newts == 0 || oldts == 0)
382 chptr->channelts = 0;
383 else if (newts == oldts)
384 ;
385 else if (newts < oldts)
386 {
387 keep_our_modes = 0;
388 chptr->channelts = newts;
389 }
390 else
391 keep_new_modes = 0;
392
393 if (!keep_new_modes)
394 mode = *oldmode;
395 else if (keep_our_modes)
396 {
397 mode.mode |= oldmode->mode;
398 if (oldmode->limit > mode.limit)
399 mode.limit = oldmode->limit;
400 if (strcmp(mode.key, oldmode->key) < 0)
401 strcpy(mode.key, oldmode->key);
402 }
403
404 set_final_mode(&mode, oldmode);
405 chptr->mode = mode;
406
407 /* Lost the TS, other side wins, so remove modes on this side */
408 if (!keep_our_modes)
409 {
410 remove_our_modes(chptr, source_p);
411
412 if (chptr->topic)
413 {
414 set_channel_topic(chptr, NULL, NULL, 0);
415 chptr->topic_time = 0;
416 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :",
417 (IsHidden(source_p) ||
418 ConfigServerHide.hide_servers) ?
419 me.name : source_p->name, chptr->chname);
420 }
421
422 sendto_channel_local(ALL_MEMBERS, 0, chptr,
423 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
424 me.name, chptr->chname, chptr->chname,
425 (unsigned long)oldts, (unsigned long)newts);
426 }
427
428 if (*modebuf != '\0')
429 {
430 servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
431 me.name : source_p->name;
432
433 /* This _SHOULD_ be to ALL_MEMBERS
434 * It contains only +imnpstlk, etc */
435 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s %s",
436 servername, chptr->chname, modebuf, parabuf);
437 }
438
439 if (!IsMember(source_p, chptr))
440 {
441 add_user_to_channel(chptr, source_p, 0, 1);
442 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
443 source_p->name, source_p->username,
444 source_p->host, chptr->chname);
445 }
446
447 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
448 ":%s JOIN %lu %s +",
449 ID(source_p), (unsigned long)chptr->channelts, chptr->chname);
450 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
451 ":%s SJOIN %lu %s + :%s",
452 source_p->servptr->name, (unsigned long)chptr->channelts,
453 chptr->chname, source_p->name);
454 }
455
456 /* do_join_0()
457 *
458 * inputs - pointer to client doing join 0
459 * output - NONE
460 * side effects - Use has decided to join 0. This is legacy
461 * from the days when channels were numbers not names. *sigh*
462 * There is a bunch of evilness necessary here due to
463 * anti spambot code.
464 */
465 static void
466 do_join_0(struct Client *client_p, struct Client *source_p)
467 {
468 struct Channel *chptr = NULL;
469 dlink_node *ptr = NULL, *ptr_next = NULL;
470
471 if (source_p->channel.head && MyConnect(source_p) && !IsOper(source_p))
472 check_spambot_warning(source_p, NULL);
473
474 DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
475 {
476 chptr = ((struct Membership *)ptr->data)->chptr;
477
478 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
479 ":%s PART %s", ID(source_p), chptr->chname);
480 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
481 ":%s PART %s", source_p->name, chptr->chname);
482 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s",
483 source_p->name, source_p->username,
484 source_p->host, chptr->chname);
485
486 remove_user_from_channel(ptr->data);
487 }
488 }
489
490 /* set_final_mode()
491 *
492 * inputs - pointer to mode to setup
493 * - pointer to old mode
494 * output - NONE
495 * side effects -
496 */
497 static const struct mode_letter
498 {
499 unsigned int mode;
500 unsigned char letter;
501 } flags[] = {
502 { MODE_NOPRIVMSGS, 'n' },
503 { MODE_TOPICLIMIT, 't' },
504 { MODE_SECRET, 's' },
505 { MODE_MODERATED, 'm' },
506 { MODE_INVITEONLY, 'i' },
507 { MODE_PRIVATE, 'p' },
508 { MODE_REGISTERED, 'r' },
509 { MODE_OPERONLY, 'O' },
510 { MODE_SSLONLY, 'S' },
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