ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/core/m_join.c
Revision: 896
Committed: Sat Nov 3 08:54:09 2007 UTC (16 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/modules/core/m_join.c
File size: 18661 byte(s)
Log Message:
- Killed s_stats.c

File Contents

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
23 adx 30 */
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 michael 894 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 adx 30
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 michael 894 { m_unregistered, m_join, ms_join, m_ignore, m_join, m_ignore }
61 adx 30 };
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 knight 31 const char *_version = "$Revision$";
77 adx 30 #endif
78    
79 michael 488 /* 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 adx 30 /* 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 michael 488 char *p = NULL;
122     char *key_list = NULL;
123     char *chan_list = NULL;
124     char *chan = NULL;
125 adx 30 struct Channel *chptr = NULL;
126 michael 488 int i = 0;
127 adx 30 unsigned int flags = 0;
128    
129 michael 632 if (EmptyString(parv[1]))
130 adx 30 {
131     sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
132     me.name, source_p->name, "JOIN");
133     return;
134     }
135    
136 michael 487 assert(client_p == source_p);
137 adx 30
138 michael 488 key_list = parv[2];
139     chan_list = last0(client_p, source_p, parv[1]);
140 michael 487
141 michael 488 for (chan = strtoken(&p, chan_list, ","); chan;
142     chan = strtoken(&p, NULL, ","))
143 adx 30 {
144 michael 488 char *key = NULL;
145 adx 30
146 michael 488 /* 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 michael 632 if (!check_channel_name(chan, 1))
155 michael 488 {
156     sendto_one(source_p, form_str(ERR_BADCHANNAME),
157     me.name, source_p->name, chan);
158 adx 30 continue;
159 michael 488 }
160 adx 30
161 michael 488 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 michael 494 sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
185     me.name, source_p->name, chan);
186     break;
187 michael 488 }
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 michael 894 * 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 michael 488 * 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 michael 632 chptr = make_channel(chan);
233 michael 488 }
234    
235 adx 30 if (!IsOper(source_p))
236     check_spambot_warning(source_p, chptr->chname);
237    
238 michael 894 add_user_to_channel(chptr, source_p, flags, 1);
239 adx 30
240     /*
241 michael 488 * Set timestamp if appropriate, and propagate
242     */
243 adx 30 if (flags & CHFL_CHANOP)
244     {
245     chptr->channelts = CurrentTime;
246     chptr->mode.mode |= MODE_TOPICLIMIT;
247     chptr->mode.mode |= MODE_NOPRIVMSGS;
248    
249 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
250 adx 30 ":%s SJOIN %lu %s +nt :@%s",
251     me.id, (unsigned long)chptr->channelts,
252     chptr->chname, source_p->id);
253 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
254 adx 30 ":%s SJOIN %lu %s +nt :@%s",
255     me.name, (unsigned long)chptr->channelts,
256 michael 632 chptr->chname, source_p->name);
257 adx 30 /*
258     * notify all other users on the new channel
259     */
260 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
261 adx 30 source_p->name, source_p->username,
262     source_p->host, chptr->chname);
263 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s +nt",
264 adx 30 me.name, chptr->chname);
265     }
266     else
267     {
268 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
269 adx 30 ":%s JOIN %lu %s +",
270     source_p->id, (unsigned long)chptr->channelts,
271     chptr->chname);
272 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
273 adx 30 ":%s SJOIN %lu %s + :%s",
274     me.name, (unsigned long)chptr->channelts,
275     chptr->chname, source_p->name);
276    
277 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
278 adx 30 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 michael 487 source_p->localClient->last_join_time = CurrentTime;
297 adx 30 }
298     }
299    
300     /* ms_join()
301     *
302     * inputs - parv[0] = uid
303     * parv[1] = ts
304     * parv[2] = channel name
305 db 853 * parv[3] = modes (Deprecated)
306 adx 30 * 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 michael 632 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 adx 30
326 michael 632 if (parc == 2 && !irccmp(parv[1], "0"))
327 adx 30 {
328     do_join_0(client_p, source_p);
329     return;
330     }
331    
332 michael 632 if (parc < 4 || *parv[2] == '&')
333 adx 30 return;
334    
335 michael 632 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 adx 30 return;
341 michael 632 }
342 adx 30
343     mbuf = modebuf;
344     mode.mode = mode.limit = 0;
345     mode.key[0] = '\0';
346    
347 michael 632 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 adx 30 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 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
374 michael 873 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
375     me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
376 adx 30 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 michael 894 keep_our_modes = 0;
391 adx 30 chptr->channelts = newts;
392     }
393     else
394 michael 894 keep_new_modes = 0;
395 adx 30
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 michael 873
415     if (chptr->topic)
416     {
417     set_channel_topic(chptr, NULL, NULL, 0);
418     chptr->topic_time = 0;
419 michael 896 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :",
420 michael 873 (IsHidden(source_p) ||
421     ConfigServerHide.hide_servers) ?
422     me.name : source_p->name, chptr->chname);
423     }
424    
425 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
426 adx 30 ":%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 michael 896 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s %s",
439 adx 30 servername, chptr->chname, modebuf, parabuf);
440     }
441    
442     if (!IsMember(source_p, chptr))
443     {
444 michael 894 add_user_to_channel(chptr, source_p, 0, 1);
445     sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
446 adx 30 source_p->name, source_p->username,
447     source_p->host, chptr->chname);
448     }
449    
450 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
451 adx 30 ":%s JOIN %lu %s +",
452     ID(source_p), (unsigned long)chptr->channelts, chptr->chname);
453 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
454 adx 30 ":%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 michael 488 dlink_node *ptr = NULL, *ptr_next = NULL;
473 adx 30
474 michael 488 if (source_p->channel.head && MyConnect(source_p) && !IsOper(source_p))
475 adx 30 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 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
482 michael 488 ":%s PART %s", ID(source_p), chptr->chname);
483 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
484 michael 488 ":%s PART %s", source_p->name, chptr->chname);
485 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s",
486 michael 488 source_p->name, source_p->username,
487     source_p->host, chptr->chname);
488 adx 30
489 michael 488 remove_user_from_channel(ptr->data);
490 adx 30 }
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 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
667 adx 30 ":%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 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
691 adx 30 ":%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