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: 1832
Committed: Fri Apr 19 19:16:09 2013 UTC (10 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 19199 byte(s)
Log Message:
- Made all numeric defines use the actual string instead of the numeric value
  which allows to use gcc's printf format attribute
- Remove current message locale implementation

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

Properties

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