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: 1011
Committed: Fri Sep 18 10:14:09 2009 UTC (14 years, 7 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/modules/core/m_join.c
File size: 18642 byte(s)
Log Message:
- move list manipulation routines from tools.c to list.c
- mem_frob() goes to memory.c
- sort out redundant/unneeded header includes

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

Properties

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