ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/ratbox.C
Revision: 1.2
Committed: Sat Jul 21 01:29:10 2007 UTC (19 years, 3 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.1: +2 -2 lines
Log Message:
- moved to new documentation system
- fixed small build error

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * Copyright © 2003-2004 E. Will et al.
3     * Copyright © 2005-2006 Atheme Development Group
4 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
5 pippijn 1.1 *
6     * This file contains protocol support for ratbox-based ircd.
7     *
8 pippijn 1.2 * $Id: ratbox.C,v 1.1 2007-07-19 08:24:55 pippijn Exp $
9 pippijn 1.1 */
10    
11     #include "atheme.h"
12     #include <account/myuser.h>
13     #include "uplink.h"
14     #include "pmodule.h"
15     #include "protocol/ratbox.h"
16    
17     static char const rcsid[] = "$Id";
18    
19     struct ratbox_listeners : callback::has_listeners
20     {
21     };
22    
23     ratbox_listeners listeners;
24    
25     DECLARE_MODULE_V1 ("protocol/ratbox", true, _modinit, NULL, rcsid, "The Ermyth Team <http://ermyth.schmorp.de>");
26    
27     /* *INDENT-OFF* */
28    
29     ircd_t Ratbox = {
30     "Ratbox (1.0 or later)", /* IRCd name */
31     "$$", /* TLD Prefix, used by Global. */
32     true, /* Whether or not we use IRCNet/TS6 UID */
33     false, /* Whether or not we use RCOMMAND */
34     false, /* Whether or not we support channel owners. */
35     false, /* Whether or not we support channel protection. */
36     false, /* Whether or not we support halfops. */
37     false, /* Whether or not we use P10 */
38     false, /* Whether or not we use vHosts. */
39     0, /* Oper-only cmodes */
40     0, /* Integer flag for owner channel flag. */
41     0, /* Integer flag for protect channel flag. */
42     0, /* Integer flag for halfops. */
43     "+", /* Mode we set for owner. */
44     "+", /* Mode we set for protect. */
45     "+", /* Mode we set for halfops. */
46     PROTOCOL_RATBOX, /* Protocol type */
47     0, /* Permanent cmodes */
48     "beI", /* Ban-like cmodes */
49     'e', /* Except mchar */
50     'I', /* Invex mchar */
51     IRCD_CIDR_BANS /* Flags */
52     };
53    
54     cmode_t ratbox_mode_list[] = {
55     { 'i', CMODE_INVITE },
56     { 'm', CMODE_MOD },
57     { 'n', CMODE_NOEXT },
58     { 'p', CMODE_PRIV },
59     { 's', CMODE_SEC },
60     { 't', CMODE_TOPIC },
61     { '\0', 0 }
62     };
63    
64     extmode ratbox_ignore_mode_list[] = {
65     { '\0', 0 }
66     };
67    
68     cmode_t ratbox_status_mode_list[] = {
69     { 'o', CMODE_OP },
70     { 'v', CMODE_VOICE },
71     { '\0', 0 }
72     };
73    
74     cmode_t ratbox_prefix_mode_list[] = {
75     { '@', CMODE_OP },
76     { '+', CMODE_VOICE },
77     { '\0', 0 }
78     };
79    
80     static bool use_rserv_support = false;
81     static bool use_tb = false;
82     static bool use_rsfnc = false;
83    
84     static void server_eob(server_t *s);
85    
86     static char ts6sid[3 + 1] = "";
87    
88     /* *INDENT-ON* */
89    
90     /* login to our uplink */
91     static unsigned int
92     ratbox_server_login (void)
93     {
94     int ret = 1;
95    
96     if (!me.numeric)
97     {
98     ircd->uses_uid = false;
99     ret = sts ("PASS %s :TS", curr_uplink->pass);
100     }
101     else if (strlen (me.numeric) == 3 && isdigit (*me.numeric))
102     {
103     ircd->uses_uid = true;
104     ret = sts ("PASS %s TS 6 :%s", curr_uplink->pass, me.numeric);
105     }
106     else
107     {
108     slog (LG_ERROR, "Invalid numeric (SID) %s", me.numeric);
109     }
110     if (ret == 1)
111     return 1;
112    
113     me.bursting = true;
114    
115     sts ("CAPAB :QS EX IE KLN UNKLN ENCAP TB SERVICES");
116     sts ("SERVER %s 1 :%s", me.name, me.desc);
117     sts ("SVINFO %d 3 0 :%ld", ircd->uses_uid ? 6 : 5, NOW);
118    
119     return 0;
120     }
121    
122     /* introduce a client */
123     static void
124     ratbox_introduce_nick (user_t *u)
125     {
126     if (ircd->uses_uid)
127     sts (":%s UID %s 1 %ld +%s%s%s %s %s 0 %s :%s", me.numeric, u->nick, u->ts, "io", chansvs.fantasy ? "" : "D", use_rserv_support ? "S" : "", u->user, u->host, u->uid, u->gecos);
128     else
129     sts ("NICK %s 1 %ld +%s%s%s %s %s %s :%s", u->nick, u->ts, "io", chansvs.fantasy ? "" : "D", use_rserv_support ? "S" : "", u->user, u->host, me.name, u->gecos);
130     }
131    
132     /* invite a user to a channel */
133     static void
134     ratbox_invite_sts (user_t *sender, user_t *target, channel_t *channel)
135     {
136     /* some older TSora ircds require the sender to be
137     * on the channel, but hyb7/ratbox don't
138     * let's just assume it's not necessary -- jilles */
139     sts (":%s INVITE %s %s", CLIENT_NAME (sender), CLIENT_NAME (target), channel->name);
140     }
141    
142     static void
143     ratbox_quit_sts (user_t *u, const char *reason)
144     {
145     if (!me.connected)
146     return;
147    
148     sts (":%s QUIT :%s", CLIENT_NAME (u), reason);
149     }
150    
151     /* WALLOPS wrapper */
152     static void
153     ratbox_wallops_sts (const char *text)
154     {
155     sts (":%s WALLOPS :%s", ME, text);
156     }
157    
158     /* join a channel */
159     static void
160     ratbox_join_sts (channel_t *c, user_t *u, bool isnew, char *modes)
161     {
162     if (isnew)
163     sts (":%s SJOIN %ld %s %s :@%s", ME, c->ts, c->name, modes, CLIENT_NAME (u));
164     else
165     sts (":%s SJOIN %ld %s + :@%s", ME, c->ts, c->name, CLIENT_NAME (u));
166     }
167    
168     static void
169     ratbox_chan_lowerts (channel_t *c, user_t *u)
170     {
171     slog (LG_DEBUG, "ratbox_chan_lowerts(): lowering TS for %s to %ld", c->name, (long) c->ts);
172     sts (":%s SJOIN %ld %s %s :@%s", ME, c->ts, c->name, channel_modes (c, true), CLIENT_NAME (u));
173     if (ircd->uses_uid)
174     chanban_clear (c);
175     }
176    
177     /* kicks a user from a channel */
178     static void
179     ratbox_kick (char *from, char *channel, char *to, char *reason)
180     {
181     channel_t *chan = channel_find (channel);
182     user_t *user = user_find (to);
183     user_t *from_p = user_find (from);
184    
185     if (!chan || !user)
186     return;
187    
188     if (chan->ts != 0 || chanuser_find (chan, from_p))
189     sts (":%s KICK %s %s :%s", CLIENT_NAME (from_p), channel, CLIENT_NAME (user), reason);
190     else
191     sts (":%s KICK %s %s :%s", ME, channel, CLIENT_NAME (user), reason);
192    
193     chanuser_delete (chan, user);
194     }
195    
196     /* PRIVMSG wrapper */
197     static void
198     ratbox_msg (const char *from, const char *target, const char *fmt, ...)
199     {
200     va_list ap;
201     char buf[BUFSIZE];
202     user_t *u = user_find (from);
203     user_t *t = user_find (target);
204    
205     if (!u)
206     return;
207    
208     va_start (ap, fmt);
209     vsnprintf (buf, BUFSIZE, fmt, ap);
210     va_end (ap);
211    
212     /* If this is to a channel, it's the snoop channel so chanserv
213     * is on it -- jilles
214     *
215     * Well, now it's operserv, but yes it's safe to assume that
216     * the source would be able to send to whatever target it is
217     * sending to. --nenolod
218     */
219     sts (":%s PRIVMSG %s :%s", CLIENT_NAME (u), t ? CLIENT_NAME (t) : target, buf);
220     }
221    
222     /* NOTICE wrapper */
223     static void
224     ratbox_notice_user_sts (user_t *from, user_t *target, const char *text)
225     {
226     sts (":%s NOTICE %s :%s", from ? CLIENT_NAME (from) : ME, CLIENT_NAME (target), text);
227     }
228    
229     static void
230     ratbox_notice_global_sts (user_t *from, const char *mask, const char *text)
231     {
232     node_t *n;
233     tld_t *tld;
234    
235     if (!strcmp (mask, "*"))
236     {
237     LIST_FOREACH (n, tldlist.head)
238     {
239     tld = static_cast<tld_t *> (n->data);
240     sts (":%s NOTICE %s*%s :%s", from ? CLIENT_NAME (from) : ME, ircd->tldprefix, tld->name, text);
241     }
242     }
243     else
244     sts (":%s NOTICE %s%s :%s", from ? CLIENT_NAME (from) : ME, ircd->tldprefix, mask, text);
245     }
246    
247     static void
248     ratbox_notice_channel_sts (user_t *from, channel_t *target, const char *text)
249     {
250     if (from == NULL || chanuser_find (target, from))
251     sts (":%s NOTICE %s :%s", from ? CLIENT_NAME (from) : ME, target->name, text);
252     else
253     /* not on channel, let's send it from the server
254     * hyb6 won't accept this, oh well, they'll have to
255     * enable join_chans -- jilles */
256     sts (":%s NOTICE %s :[%s:%s] %s", ME, target->name, from->nick, target->name, text);
257     }
258    
259     static void
260     ratbox_wallchops (user_t *sender, channel_t *channel, const char *message)
261     {
262     if (chanuser_find (channel, sender))
263     sts (":%s NOTICE @%s :%s", CLIENT_NAME (sender), channel->name, message);
264     else /* do not join for this, everyone would see -- jilles */
265     generic_wallchops (sender, channel, message);
266     }
267    
268     /* numeric wrapper */
269     static void
270     ratbox_numeric_sts (char *from, int numeric, char *target, char *fmt, ...)
271     {
272     va_list ap;
273     char buf[BUFSIZE];
274     user_t *t = user_find (target);
275    
276     va_start (ap, fmt);
277     vsnprintf (buf, BUFSIZE, fmt, ap);
278     va_end (ap);
279    
280     sts (":%s %d %s %s", ME, numeric, CLIENT_NAME (t), buf);
281     }
282    
283     /* KILL wrapper */
284     static void
285     ratbox_skill (char *from, char *nick, char *fmt, ...)
286     {
287     va_list ap;
288     char buf[BUFSIZE];
289     user_t *killer = user_find (from);
290     user_t *victim = user_find (nick);
291    
292     va_start (ap, fmt);
293     vsnprintf (buf, BUFSIZE, fmt, ap);
294     va_end (ap);
295    
296     sts (":%s KILL %s :%s!%s!%s (%s)", killer ? CLIENT_NAME (killer) : ME, victim ? CLIENT_NAME (victim) : nick, from, from, from, buf);
297     }
298    
299     /* PART wrapper */
300     static void
301     ratbox_part_sts (channel_t *c, user_t *u)
302     {
303     sts (":%s PART %s", CLIENT_NAME (u), c->name);
304     }
305    
306     /* server-to-server KLINE wrapper */
307     static void
308     ratbox_kline_sts (char *server, char *user, char *host, long duration, char *reason)
309     {
310     if (!me.connected)
311     return;
312    
313     sts (":%s KLINE %s %ld %s %s :%s", CLIENT_NAME (opersvs.me->me), server, duration, user, host, reason);
314     }
315    
316     /* server-to-server UNKLINE wrapper */
317     static void
318     ratbox_unkline_sts (char *server, char *user, char *host)
319     {
320     if (!me.connected)
321     return;
322    
323     sts (":%s UNKLINE %s %s %s", CLIENT_NAME (opersvs.me->me), server, user, host);
324     }
325    
326     /* topic wrapper */
327     static void
328     ratbox_topic_sts (channel_t *c, const char *setter, time_t ts, time_t prevts, const char *topic)
329     {
330     int joined = 0;
331    
332     if (!me.connected || !c)
333     return;
334    
335     /* If possible, try to use TB
336     * Note that because TOPIC does not contain topicTS, it may be
337     * off a few seconds on other servers, hence the 60 seconds here.
338     * -- jilles */
339     if (use_tb && *topic != '\0')
340     {
341     /* Restoring old topic */
342     if (ts < prevts || prevts == 0)
343     {
344     if (prevts != 0 && ts + 60 > prevts)
345     ts = prevts - 60;
346     sts (":%s TB %s %ld %s :%s", ME, c->name, ts, setter, topic);
347     c->topicts = ts;
348     return;
349     }
350     /* Tweaking a topic */
351     else if (ts == prevts)
352     {
353     ts -= 60;
354     sts (":%s TB %s %ld %s :%s", ME, c->name, ts, setter, topic);
355     c->topicts = ts;
356     return;
357     }
358     }
359     /* We have to be on channel to change topic.
360     * We cannot nicely change topic from the server:
361     * :server.name TOPIC doesn't propagate and TB requires
362     * us to specify an older topicts.
363     * -- jilles
364     */
365     if (!chanuser_find (c, chansvs.me->me))
366     {
367     sts (":%s SJOIN %ld %s + :@%s", ME, c->ts, c->name, CLIENT_NAME (chansvs.me->me));
368     joined = 1;
369     }
370     sts (":%s TOPIC %s :%s", CLIENT_NAME (chansvs.me->me), c->name, topic);
371     if (joined)
372     sts (":%s PART %s :Topic set", CLIENT_NAME (chansvs.me->me), c->name);
373     c->topicts = NOW;
374     }
375    
376     /* mode wrapper */
377     static void
378     ratbox_mode_sts (char *sender, channel_t *target, char *modes)
379     {
380     user_t *u = user_find (sender);
381    
382     if (!me.connected || !u)
383     return;
384    
385     if (ircd->uses_uid)
386     sts (":%s TMODE %ld %s %s", CLIENT_NAME (u), target->ts, target->name, modes);
387     else
388     sts (":%s MODE %s %s", CLIENT_NAME (u), target->name, modes);
389     }
390    
391     /* ping wrapper */
392     static void
393     ratbox_ping_sts (void)
394     {
395     if (!me.connected)
396     return;
397    
398     sts ("PING :%s", me.name);
399     }
400    
401     /* protocol-specific stuff to do on login */
402     static void
403     ratbox_on_login (char *origin, char *user, char *wantedhost)
404     {
405     user_t *u = user_find (origin);
406    
407     if (!me.connected || !use_rserv_support || !u)
408     return;
409    
410     sts (":%s ENCAP * SU %s %s", ME, CLIENT_NAME (u), user);
411     }
412    
413     /* protocol-specific stuff to do on login */
414     static bool
415     ratbox_on_logout (char *origin, char *user, char *wantedhost)
416     {
417     user_t *u = user_find (origin);
418    
419     if (!me.connected || !use_rserv_support || !u)
420     return false;
421    
422     sts (":%s ENCAP * SU %s", ME, CLIENT_NAME (u));
423     return false;
424     }
425    
426     static void
427     ratbox_jupe (const char *server, const char *reason)
428     {
429     if (!me.connected)
430     return;
431    
432     server_delete (server);
433     sts (":%s SQUIT %s :%s", CLIENT_NAME (opersvs.me->me), server, reason);
434     sts (":%s SERVER %s 2 :(H) %s", me.name, server, reason);
435     }
436    
437     static void
438     ratbox_fnc_sts (user_t *source, user_t *u, char *newnick, int type)
439     {
440     if (use_rsfnc)
441     /* XXX assumes whole net has it -- jilles */
442     sts (":%s ENCAP %s RSFNC %s %s %lu %lu", ME, u->server->name, CLIENT_NAME (u), newnick, (unsigned long) (NOW - 60), (unsigned long) u->ts);
443     else
444     generic_fnc_sts (source, u, newnick, type);
445     }
446    
447     static void
448     ratbox_holdnick_sts (user_t *source, int duration, const char *nick, myuser_t *account)
449     {
450     if (duration == 0)
451     return; /* can't do this safely */
452     sts (":%s ENCAP * RESV %d %s 0 :Reserved by %s for nickname owner (%s)", CLIENT_NAME (source), duration > 300 ? 300 : duration, nick, source->nick, account != NULL ? account->name : nick);
453     }
454    
455     static void
456     m_topic (sourceinfo_t *si, int parc, char *parv[])
457     {
458     channel_t *c = channel_find (parv[0]);
459    
460     if (c == NULL)
461     return;
462    
463     handle_topic_from (si, c, si->su->nick, NOW, parv[1]);
464     }
465    
466     static void
467     m_tb (sourceinfo_t *si, int parc, char *parv[])
468     {
469     channel_t *c = channel_find (parv[0]);
470     time_t ts = atol (parv[1]);
471    
472     if (c == NULL)
473     return;
474    
475     if (c->topic != NULL && c->topicts <= ts)
476     {
477     slog (LG_DEBUG, "m_tb(): ignoring newer topic on %s", c->name);
478     return;
479     }
480    
481     handle_topic_from (si, c, parc > 3 ? parv[2] : si->s->name, ts, parv[parc - 1]);
482     }
483    
484     static void
485     m_ping (sourceinfo_t *si, int parc, char *parv[])
486     {
487     /* reply to PING's */
488     sts (":%s PONG %s %s", ME, me.name, parv[0]);
489     }
490    
491     static void
492     m_pong (sourceinfo_t *si, int parc, char *parv[])
493     {
494     server_t *s;
495    
496     /* someone replied to our PING */
497     if (!parv[0])
498     return;
499     s = server_find (parv[0]);
500     if (s == NULL)
501     return;
502     handle_eob (s);
503    
504     if (irccasecmp (me.actual, parv[0]))
505     return;
506    
507     me.uplinkpong = NOW;
508    
509     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
510     if (me.bursting)
511     {
512     #ifdef HAVE_GETTIMEOFDAY
513     e_time (burstime, &burstime);
514    
515     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
516    
517     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
518     #else
519     slog (LG_INFO, "m_pong(): finished synching with uplink");
520     wallops ("Finished synching to network.");
521     #endif
522    
523     me.bursting = false;
524     }
525     }
526    
527     static void
528     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
529     {
530     if (parc != 2)
531     return;
532    
533     handle_message (si, parv[0], false, parv[1]);
534     }
535    
536     static void
537     m_notice (sourceinfo_t *si, int parc, char *parv[])
538     {
539     if (parc != 2)
540     return;
541    
542     handle_message (si, parv[0], true, parv[1]);
543     }
544    
545     static void
546     m_sjoin (sourceinfo_t *si, int parc, char *parv[])
547     {
548     /* -> :proteus.malkier.net SJOIN 1073516550 #shrike +tn :@sycobuny @+rakaur */
549    
550     channel_t *c;
551     bool keep_new_modes = true;
552     unsigned int userc;
553     char *userv[256];
554     unsigned int i;
555     time_t ts;
556     char *p;
557    
558     /* :origin SJOIN ts chan modestr [key or limits] :users */
559     c = channel_find (parv[1]);
560     ts = atol (parv[0]);
561    
562     if (!c)
563     {
564     slog (LG_DEBUG, "m_sjoin(): new channel: %s", parv[1]);
565     c = channel_add (parv[1], ts, si->s);
566     }
567    
568     if (ts == 0 || c->ts == 0)
569     {
570     if (c->ts != 0)
571     slog (LG_INFO, "m_sjoin(): server %s changing TS on %s from %ld to 0", si->s->name, c->name, (long) c->ts);
572     c->ts = 0;
573     hook_call_event ("channel_tschange", c);
574     }
575     else if (ts < c->ts)
576     {
577     chanuser_t *cu;
578     node_t *n;
579    
580     /* the TS changed. a TS change requires the following things
581     * to be done to the channel: reset all modes to nothing, remove
582     * all status modes on known users on the channel (including ours),
583     * and set the new TS.
584     *
585     * if the source does TS6, also remove all bans
586     * note that JOIN does not do this
587     */
588    
589     clear_simple_modes (c);
590     if (si->s->sid != NULL)
591     chanban_clear (c);
592    
593     LIST_FOREACH (n, c->members.head)
594     {
595     cu = (chanuser_t *) n->data;
596     if (cu->user->server == me.me)
597     {
598     /* it's a service, reop */
599     sts (":%s PART %s :Reop", CLIENT_NAME (cu->user), c->name);
600     sts (":%s SJOIN %ld %s + :@%s", ME, ts, c->name, CLIENT_NAME (cu->user));
601     cu->modes = CMODE_OP;
602     }
603     else
604     cu->modes = 0;
605     }
606    
607     slog (LG_DEBUG, "m_sjoin(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
608    
609     c->ts = ts;
610     hook_call_event ("channel_tschange", c);
611     }
612     else if (ts > c->ts)
613     keep_new_modes = false;
614    
615     if (keep_new_modes)
616     channel_mode (NULL, c, parc - 3, parv + 2);
617    
618     userc = sjtoken (parv[parc - 1], ' ', userv);
619    
620     if (keep_new_modes)
621     for (i = 0; i < userc; i++)
622     chanuser_add (c, userv[i]);
623     else
624     for (i = 0; i < userc; i++)
625     {
626     p = userv[i];
627     while (*p == '@' || *p == '%' || *p == '+')
628     p++;
629     /* XXX for TS5 we should mark them deopped
630     * if they were opped and drop modes from them
631     * -- jilles */
632     chanuser_add (c, p);
633     }
634    
635     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
636     channel_delete (c);
637     }
638    
639     static void
640     m_join (sourceinfo_t *si, int parc, char *parv[])
641     {
642     /* -> :1JJAAAAAB JOIN 1127474195 #test +tn */
643     bool keep_new_modes = true;
644     node_t *n, *tn;
645     channel_t *c;
646     chanuser_t *cu;
647     time_t ts;
648    
649     /* JOIN 0 is really a part from all channels */
650     /* be sure to allow joins to TS 0 channels -- jilles */
651     if (parv[0][0] == '0' && parc <= 2)
652     {
653     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
654     {
655     cu = (chanuser_t *) n->data;
656     chanuser_delete (cu->chan, si->su);
657     }
658     return;
659     }
660    
661     /* :user JOIN ts chan modestr [key or limits] */
662     c = channel_find (parv[1]);
663     ts = atol (parv[0]);
664    
665     if (!c)
666     {
667     slog (LG_DEBUG, "m_join(): new channel: %s", parv[1]);
668     c = channel_add (parv[1], ts, si->su->server);
669     }
670    
671     if (ts == 0 || c->ts == 0)
672     {
673     if (c->ts != 0)
674     slog (LG_INFO, "m_join(): server %s changing TS on %s from %ld to 0", si->su->server->name, c->name, (long) c->ts);
675     c->ts = 0;
676     hook_call_event ("channel_tschange", c);
677     }
678     else if (ts < c->ts)
679     {
680     /* the TS changed. a TS change requires the following things
681     * to be done to the channel: reset all modes to nothing, remove
682     * all status modes on known users on the channel (including ours),
683     * and set the new TS.
684     */
685     clear_simple_modes (c);
686    
687     LIST_FOREACH (n, c->members.head)
688     {
689     cu = (chanuser_t *) n->data;
690     if (cu->user->server == me.me)
691     {
692     /* it's a service, reop */
693     sts (":%s PART %s :Reop", CLIENT_NAME (cu->user), c->name);
694     sts (":%s SJOIN %ld %s + :@%s", ME, ts, c->name, CLIENT_NAME (cu->user));
695     cu->modes = CMODE_OP;
696     }
697     else
698     cu->modes = 0;
699     }
700     slog (LG_DEBUG, "m_join(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
701     c->ts = ts;
702     hook_call_event ("channel_tschange", c);
703     }
704     else if (ts > c->ts)
705     keep_new_modes = false;
706    
707     if (keep_new_modes)
708     channel_mode (NULL, c, parc - 2, parv + 2);
709    
710     chanuser_add (c, CLIENT_NAME (si->su));
711     }
712    
713     static void
714     m_bmask (sourceinfo_t *si, int parc, char *parv[])
715     {
716     unsigned int ac, i;
717     char *av[256];
718     channel_t *c = channel_find (parv[1]);
719     int type;
720    
721     /* :1JJ BMASK 1127474361 #services b :*!*@*evil* *!*eviluser1@* */
722     if (!c)
723     {
724     slog (LG_DEBUG, "m_bmask(): got bmask for unknown channel");
725     return;
726     }
727    
728     if (atol (parv[0]) > c->ts)
729     return;
730    
731     type = *parv[2];
732     if (!strchr (ircd->ban_like_modes, type))
733     {
734     slog (LG_DEBUG, "m_bmask(): got unknown type '%c'", type);
735     return;
736     }
737    
738     ac = sjtoken (parv[parc - 1], ' ', av);
739    
740     for (i = 0; i < ac; i++)
741     chanban_add (c, av[i], type);
742     }
743    
744     static void
745     m_part (sourceinfo_t *si, int parc, char *parv[])
746     {
747     int chanc;
748     char *chanv[256];
749     int i;
750    
751     chanc = sjtoken (parv[0], ',', chanv);
752     for (i = 0; i < chanc; i++)
753     {
754     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
755    
756     chanuser_delete (channel_find (chanv[i]), si->su);
757     }
758     }
759    
760     static void
761     m_nick (sourceinfo_t *si, int parc, char *parv[])
762     {
763     server_t *s;
764     user_t *u;
765    
766     /* got the right number of args for an introduction? */
767     if (parc == 8)
768     {
769     s = server_find (parv[6]);
770     if (!s)
771     {
772     slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
773     return;
774     }
775    
776     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
777    
778     u = user_add (parv[0], parv[4], parv[5], NULL, NULL, NULL, parv[7], s, atoi (parv[2]));
779    
780     user_mode (u, parv[3]);
781    
782     /* If server is not yet EOB we will do this later.
783     * This avoids useless "please identify" -- jilles */
784     if (s->flags & SF_EOB)
785     handle_nickchange (user_find (parv[0]));
786     }
787    
788     /* if it's only 2 then it's a nickname change */
789     else if (parc == 2)
790     {
791     if (!si->su)
792     {
793     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
794     return;
795     }
796    
797     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
798    
799     user_changenick (si->su, parv[0], atoi (parv[1]));
800    
801     /* It could happen that our PING arrived late and the
802     * server didn't acknowledge EOB yet even though it is
803     * EOB; don't send double notices in that case -- jilles */
804     if (si->su->server->flags & SF_EOB)
805     handle_nickchange (si->su);
806     }
807     else
808     {
809     int i;
810     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
811    
812     for (i = 0; i < parc; i++)
813     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
814     }
815     }
816    
817     static void
818     m_uid (sourceinfo_t *si, int parc, char *parv[])
819     {
820     server_t *s;
821     user_t *u;
822    
823     /* got the right number of args for an introduction? */
824     if (parc == 9)
825     {
826     s = si->s;
827     slog (LG_DEBUG, "m_uid(): new user on `%s': %s", s->name, parv[0]);
828    
829     u = user_add (parv[0], parv[4], parv[5], NULL, parv[6], parv[7], parv[8], s, atoi (parv[2]));
830    
831     user_mode (u, parv[3]);
832    
833     /* If server is not yet EOB we will do this later.
834     * This avoids useless "please identify" -- jilles
835     */
836     if (s->flags & SF_EOB)
837     handle_nickchange (user_find (parv[0]));
838     }
839     else
840     {
841     int i;
842     slog (LG_DEBUG, "m_uid(): got UID with wrong number of params");
843    
844     for (i = 0; i < parc; i++)
845     slog (LG_DEBUG, "m_uid(): parv[%d] = %s", i, parv[i]);
846     }
847     }
848    
849     static void
850     m_quit (sourceinfo_t *si, int parc, char *parv[])
851     {
852     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
853    
854     /* user_delete() takes care of removing channels and so forth */
855     user_delete (si->su);
856     }
857    
858     static void
859     m_mode (sourceinfo_t *si, int parc, char *parv[])
860     {
861     if (*parv[0] == '#')
862     channel_mode (NULL, channel_find (parv[0]), parc - 1, &parv[1]);
863     else
864     user_mode (user_find (parv[0]), parv[1]);
865     }
866    
867     static void
868     m_tmode (sourceinfo_t *si, int parc, char *parv[])
869     {
870     channel_t *c;
871    
872     /* -> :1JJAAAAAB TMODE 1127511579 #new +o 2JJAAAAAB */
873     c = channel_find (parv[1]);
874     if (c == NULL)
875     {
876     slog (LG_DEBUG, "m_tmode(): nonexistent channel %s", parv[1]);
877     return;
878     }
879    
880     if (atol (parv[0]) > c->ts)
881     return;
882    
883     channel_mode (NULL, c, parc - 2, &parv[2]);
884     }
885    
886     static void
887     m_kick (sourceinfo_t *si, int parc, char *parv[])
888     {
889     user_t *u = user_find (parv[1]);
890     channel_t *c = channel_find (parv[0]);
891    
892     /* -> :rakaur KICK #shrike rintaun :test */
893     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
894    
895     if (!u)
896     {
897     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
898     return;
899     }
900    
901     if (!c)
902     {
903     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
904     return;
905     }
906    
907     if (!chanuser_find (c, u))
908     {
909     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
910     return;
911     }
912    
913     chanuser_delete (c, u);
914    
915     /* if they kicked us, let's rejoin */
916     if (is_internal_client (u))
917     {
918     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
919     join (parv[0], u->nick);
920     }
921     }
922    
923     static void
924     m_kill (sourceinfo_t *si, int parc, char *parv[])
925     {
926     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
927     }
928    
929     static void
930     m_squit (sourceinfo_t *si, int parc, char *parv[])
931     {
932     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
933     server_delete (parv[0]);
934     }
935    
936     static void
937     m_server (sourceinfo_t *si, int parc, char *parv[])
938     {
939     server_t *s;
940    
941     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
942     s = handle_server (si, parv[0], si->s || !ircd->uses_uid ? NULL : ts6sid, atoi (parv[1]), parv[2]);
943    
944     if (s != NULL && s->uplink != me.me)
945     {
946     /* elicit PONG for EOB detection; pinging uplink is
947     * already done elsewhere -- jilles
948     */
949     sts (":%s PING %s %s", ME, me.name, s->name);
950     }
951     }
952    
953     static void
954     m_sid (sourceinfo_t *si, int parc, char *parv[])
955     {
956     /* -> :1JJ SID file. 2 00F :telnet server */
957     server_t *s;
958    
959     slog (LG_DEBUG, "m_sid(): new server: %s", parv[0]);
960     s = handle_server (si, parv[0], parv[2], atoi (parv[1]), parv[3]);
961    
962     if (s != NULL && s->uplink != me.me)
963     {
964     /* elicit PONG for EOB detection; pinging uplink is
965     * already done elsewhere -- jilles
966     */
967     sts (":%s PING %s %s", ME, me.name, s->sid);
968     }
969     }
970    
971     static void
972     m_stats (sourceinfo_t *si, int parc, char *parv[])
973     {
974     handle_stats (si->su, parv[0][0]);
975     }
976    
977     static void
978     m_admin (sourceinfo_t *si, int parc, char *parv[])
979     {
980     handle_admin (si->su);
981     }
982    
983     static void
984     m_version (sourceinfo_t *si, int parc, char *parv[])
985     {
986     handle_version (si->su);
987     }
988    
989     static void
990     m_info (sourceinfo_t *si, int parc, char *parv[])
991     {
992     handle_info (si->su);
993     }
994    
995     static void
996     m_whois (sourceinfo_t *si, int parc, char *parv[])
997     {
998     handle_whois (si->su, parv[1]);
999     }
1000    
1001     static void
1002     m_trace (sourceinfo_t *si, int parc, char *parv[])
1003     {
1004     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
1005     }
1006    
1007     static void
1008     m_away (sourceinfo_t *si, int parc, char *parv[])
1009     {
1010     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
1011     }
1012    
1013     static void
1014     m_pass (sourceinfo_t *si, int parc, char *parv[])
1015     {
1016     /* TS5: PASS mypassword :TS
1017     * TS6: PASS mypassword TS 6 :sid */
1018     if (strcmp (curr_uplink->pass, parv[0]))
1019     {
1020     slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
1021     runflags |= RF_SHUTDOWN;
1022     }
1023    
1024     if (ircd->uses_uid && parc > 3 && atoi (parv[2]) >= 6)
1025     strlcpy (ts6sid, parv[3], sizeof (ts6sid));
1026     else
1027     {
1028     if (ircd->uses_uid)
1029     {
1030     slog (LG_INFO, "m_pass(): uplink does not support TS6, falling back to TS5");
1031     ircd->uses_uid = false;
1032     }
1033     ts6sid[0] = '\0';
1034     }
1035     }
1036    
1037     static void
1038     m_error (sourceinfo_t *si, int parc, char *parv[])
1039     {
1040     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
1041     }
1042    
1043     static void
1044     m_encap (sourceinfo_t *si, int parc, char *parv[])
1045     {
1046     user_t *u;
1047    
1048     if (match (parv[0], me.name))
1049     return;
1050     if (!irccasecmp (parv[1], "LOGIN"))
1051     {
1052     /* :jilles ENCAP * LOGIN jilles */
1053     if (!use_rserv_support)
1054     return;
1055     if (parc < 3)
1056     return;
1057     u = si->su;
1058     if (u == NULL)
1059     return;
1060     if (u->server->flags & SF_EOB)
1061     {
1062     slog (LG_DEBUG, "m_encap(): %s sent ENCAP LOGIN for user %s outside burst", u->server->name, si->su->nick);
1063     return;
1064     }
1065     handle_burstlogin (u, parv[2]);
1066     }
1067     }
1068    
1069     static void
1070     m_capab (sourceinfo_t *si, int parc, char *parv[])
1071     {
1072     char *p;
1073    
1074     use_rserv_support = false;
1075     use_tb = false;
1076     use_rsfnc = false;
1077     for (p = strtok (parv[0], " "); p != NULL; p = strtok (NULL, " "))
1078     {
1079     if (!irccasecmp (p, "SERVICES"))
1080     {
1081     slog (LG_DEBUG, "m_capab(): uplink has rserv extensions, enabling support.");
1082     use_rserv_support = true;
1083     }
1084     if (!irccasecmp (p, "TB"))
1085     {
1086     slog (LG_DEBUG, "m_capab(): uplink does topic bursting, using if appropriate.");
1087     use_tb = true;
1088     }
1089     if (!irccasecmp (p, "RSFNC"))
1090     {
1091     slog (LG_DEBUG, "m_capab(): uplink does RSFNC, assuming whole net has it.");
1092     use_rsfnc = true;
1093     }
1094     }
1095    
1096     /* Now we know whether or not we should enable services support,
1097     * so burst the clients.
1098     * --nenolod
1099     */
1100     services_init ();
1101     }
1102    
1103     static void
1104     m_motd (sourceinfo_t *si, int parc, char *parv[])
1105     {
1106     handle_motd (si->su);
1107     }
1108    
1109     /* Server ended their burst: warn all their users if necessary -- jilles */
1110     static void
1111     server_eob (server_t *s)
1112     {
1113     node_t *n;
1114    
1115     LIST_FOREACH (n, s->userlist.head)
1116     {
1117     handle_nickchange ((user_t *) n->data);
1118     }
1119     }
1120    
1121     void
1122     _modinit (module_t *m)
1123     {
1124     /* Symbol relocation voodoo. */
1125     server_login = &ratbox_server_login;
1126     introduce_nick = &ratbox_introduce_nick;
1127     quit_sts = &ratbox_quit_sts;
1128     wallops_sts = &ratbox_wallops_sts;
1129     join_sts = &ratbox_join_sts;
1130     chan_lowerts = &ratbox_chan_lowerts;
1131     kick = &ratbox_kick;
1132     msg = &ratbox_msg;
1133     notice_user_sts = &ratbox_notice_user_sts;
1134     notice_global_sts = &ratbox_notice_global_sts;
1135     notice_channel_sts = &ratbox_notice_channel_sts;
1136     wallchops = &ratbox_wallchops;
1137     numeric_sts = &ratbox_numeric_sts;
1138     skill = &ratbox_skill;
1139     part_sts = &ratbox_part_sts;
1140     kline_sts = &ratbox_kline_sts;
1141     unkline_sts = &ratbox_unkline_sts;
1142     topic_sts = &ratbox_topic_sts;
1143     mode_sts = &ratbox_mode_sts;
1144     ping_sts = &ratbox_ping_sts;
1145     ircd_on_login = &ratbox_on_login;
1146     ircd_on_logout = &ratbox_on_logout;
1147     jupe = &ratbox_jupe;
1148     fnc_sts = &ratbox_fnc_sts;
1149     invite_sts = &ratbox_invite_sts;
1150     holdnick_sts = &ratbox_holdnick_sts;
1151    
1152     mode_list = ratbox_mode_list;
1153     ignore_mode_list = ratbox_ignore_mode_list;
1154     status_mode_list = ratbox_status_mode_list;
1155     prefix_mode_list = ratbox_prefix_mode_list;
1156    
1157     ircd = &Ratbox;
1158    
1159     pcommand_add ("PING", m_ping, 1, MSRC_USER | MSRC_SERVER);
1160     pcommand_add ("PONG", m_pong, 1, MSRC_SERVER);
1161     pcommand_add ("PRIVMSG", m_privmsg, 2, MSRC_USER);
1162     pcommand_add ("NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER);
1163     pcommand_add ("SJOIN", m_sjoin, 4, MSRC_SERVER);
1164     pcommand_add ("PART", m_part, 1, MSRC_USER);
1165     pcommand_add ("NICK", m_nick, 2, MSRC_USER | MSRC_SERVER);
1166     pcommand_add ("QUIT", m_quit, 1, MSRC_USER);
1167     pcommand_add ("MODE", m_mode, 2, MSRC_USER | MSRC_SERVER);
1168     pcommand_add ("KICK", m_kick, 2, MSRC_USER | MSRC_SERVER);
1169     pcommand_add ("KILL", m_kill, 1, MSRC_USER | MSRC_SERVER);
1170     pcommand_add ("SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER);
1171     pcommand_add ("SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER);
1172     pcommand_add ("STATS", m_stats, 2, MSRC_USER);
1173     pcommand_add ("ADMIN", m_admin, 1, MSRC_USER);
1174     pcommand_add ("VERSION", m_version, 1, MSRC_USER);
1175     pcommand_add ("INFO", m_info, 1, MSRC_USER);
1176     pcommand_add ("WHOIS", m_whois, 2, MSRC_USER);
1177     pcommand_add ("TRACE", m_trace, 1, MSRC_USER);
1178     pcommand_add ("AWAY", m_away, 0, MSRC_USER);
1179     pcommand_add ("JOIN", m_join, 1, MSRC_USER);
1180     pcommand_add ("PASS", m_pass, 1, MSRC_UNREG);
1181     pcommand_add ("ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER);
1182     pcommand_add ("TOPIC", m_topic, 2, MSRC_USER);
1183     pcommand_add ("TB", m_tb, 3, MSRC_SERVER);
1184     pcommand_add ("ENCAP", m_encap, 2, MSRC_USER | MSRC_SERVER);
1185     pcommand_add ("CAPAB", m_capab, 1, MSRC_UNREG);
1186     pcommand_add ("UID", m_uid, 9, MSRC_SERVER);
1187     pcommand_add ("BMASK", m_bmask, 4, MSRC_SERVER);
1188     pcommand_add ("TMODE", m_tmode, 3, MSRC_USER | MSRC_SERVER);
1189     pcommand_add ("SID", m_sid, 4, MSRC_SERVER);
1190     pcommand_add ("MOTD", m_motd, 1, MSRC_USER);
1191    
1192     hook_add_event ("server_eob");
1193     hook_add_hook ("server_eob", (void (*)(void *)) server_eob);
1194    
1195     m->mflags = MODTYPE_CORE;
1196    
1197     pmodule_loaded = true;
1198     }
1199    
1200     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
1201     * vim:ts=8
1202     * vim:sw=8
1203     * vim:noexpandtab
1204     */