ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/ratbox.C
Revision: 1.6
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +3 -2 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

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