ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/ircnet.C
Revision: 1.6
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years, 1 month 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 © 2005-2006 William Pitcock, et al.
3 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
4 pippijn 1.1 *
5     * This file contains protocol support for IRCnet ircd's.
6     * Derived mainly from the documentation (or lack thereof)
7     * in my protocol bridge.
8     *
9 pippijn 1.6 * $Id: ircnet.C,v 1.5 2007-09-05 11:23:14 pippijn Exp $
10 pippijn 1.1 */
11    
12     #include "atheme.h"
13 pippijn 1.6 #include "servers.h"
14 pippijn 1.1 #include "uplink.h"
15     #include "pmodule.h"
16     #include "protocol/ircnet.h"
17    
18 pippijn 1.6 static char const rcsid[] = "$Id: ircnet.C,v 1.5 2007-09-05 11:23:14 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 IRCNet = {
25     "ircd 2.11.1p1 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_IRCNET, /* Protocol type */
42     0, /* Permanent cmodes */
43     "beIR", /* Ban-like cmodes */
44     'e', /* Except mchar */
45     'I', /* Invex mchar */
46     IRCD_CIDR_BANS /* Flags */
47     };
48    
49     struct ircnet_handler : handler
50     {
51     ircnet_handler ();
52     virtual ~ircnet_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 kick (char const * const from, char const * const channel, char const * const to, char const * const reason);
61     virtual void privmsg (char const * const from, char const * const target, char const * const fmt, ...);
62     virtual void notice_user_sts (user_t *from, user_t *target, char const * const text);
63     virtual void notice_global_sts (user_t *from, char const * const mask, char const * const text);
64     virtual void notice_channel_sts (user_t *from, channel_t *target, char const * const text);
65     virtual void numeric_sts (char const * const from, int numeric, char const * const target, char const * const fmt, ...);
66     virtual void skill (char const * const from, char const * const nick, char const * const fmt, ...);
67     virtual void part_sts (channel_t *c, user_t *u);
68     virtual void kline_sts (char const * const server, char const * const user, char const * const host, long duration, char const * const reason);
69     virtual void unkline_sts (char const * const server, char const * const user, char const * const host);
70     virtual void topic_sts (channel_t *c, char const * const setter, time_t ts, time_t prevts, char const * const topic);
71     virtual void mode_sts (char const * const sender, channel_t *target, char const * const modes);
72     virtual void ping_sts (void);
73     virtual void ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost);
74     virtual bool ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost);
75     virtual void jupe (char const * const server, char const * const reason);
76     };
77    
78     static cmode_t ircnet_mode_list[] = {
79     { 'i', CMODE_INVITE },
80     { 'm', CMODE_MOD },
81     { 'n', CMODE_NOEXT },
82     { 'p', CMODE_PRIV },
83     { 's', CMODE_SEC },
84     { 't', CMODE_TOPIC },
85     { '\0', 0 }
86     };
87    
88 pippijn 1.5 static extmode_t ircnet_ignore_mode_list[] = {
89 pippijn 1.4 { '\0', 0 }
90     };
91    
92     static cmode_t ircnet_status_mode_list[] = {
93     { 'o', CMODE_OP },
94     { 'v', CMODE_VOICE },
95     { '\0', 0 }
96     };
97    
98     static cmode_t ircnet_prefix_mode_list[] = {
99     { '@', CMODE_OP },
100     { '+', CMODE_VOICE },
101     { '\0', 0 }
102     };
103    
104     /* *INDENT-ON* */
105    
106     /* login to our uplink */
107     unsigned int
108     ircnet_handler::server_login (void)
109     {
110     int ret;
111    
112     ret = sts ("PASS %s 0211010000 IRC|aDEFiIJMuw P", curr_uplink->pass);
113     if (ret == 1)
114     return 1;
115    
116     me.bursting = true;
117    
118     sts ("SERVER %s 1 %s :%s", me.name, me.numeric, me.desc);
119    
120     services_init ();
121    
122     sts (":%s EOB", me.numeric);
123    
124     return 0;
125     }
126    
127     /* introduce a client */
128     void
129     ircnet_handler::introduce_nick (user_t *u)
130     {
131     sts (":%s UNICK %s %s %s %s 0.0.0.0 +%s :%s", me.numeric, u->nick, u->uid, u->user, u->host, "io", u->gecos);
132     }
133    
134     /* invite a user to a channel */
135     void
136     ircnet_handler::invite_sts (user_t *sender, user_t *target, channel_t *channel)
137     {
138     int joined = 0;
139    
140     /* Need to join to invite -- jilles */
141     if (!chanuser_find (channel, sender))
142     {
143     sts (":%s NJOIN %s :@%s", ME, channel->name, CLIENT_NAME (sender));
144     joined = 1;
145     }
146     /* ircnet's UID implementation is incomplete, in many places,
147     * like this one, it does not accept UIDs -- jilles */
148     sts (":%s INVITE %s %s", CLIENT_NAME (sender), target->nick, channel->name);
149     if (joined)
150     sts (":%s PART %s :Invited %s", CLIENT_NAME (sender), channel->name, target->nick);
151     }
152    
153     void
154     ircnet_handler::quit_sts (user_t *u, char const * const reason)
155     {
156     if (!me.connected)
157     return;
158    
159     sts (":%s QUIT :%s", u->nick, reason);
160     }
161    
162     /* WALLOPS wrapper */
163     void
164     ircnet_handler::wallops_sts (char const * const text)
165     {
166     sts (":%s WALLOPS :%s", me.name, text);
167     }
168    
169     /* join a channel */
170     void
171     ircnet_handler::join_sts (channel_t *c, user_t *u, bool isnew, char const * const modes)
172     {
173     sts (":%s NJOIN %s :@%s", me.numeric, c->name, u->uid);
174     if (isnew && modes[0] && modes[1])
175     sts (":%s MODE %s %s", me.numeric, c->name, modes);
176     }
177    
178     /* kicks a user from a channel */
179     void
180     ircnet_handler::kick (char const * const from, char const * const channel, char const * const to, char const * const reason)
181     {
182     channel_t *chan = channel_find (channel);
183     user_t *user = user_find (to);
184     user_t *from_p = user_find (from);
185    
186     if (!chan || !user)
187     return;
188    
189     /* sigh server kicks will generate snotes
190     * but let's avoid joining N times for N kicks */
191     sts (":%s KICK %s %s :%s", from_p != NULL && chanuser_find (chan, from_p) ? CLIENT_NAME (from_p) : ME, channel, CLIENT_NAME (user), reason);
192    
193     chanuser_delete (chan, user);
194     }
195    
196     /* PRIVMSG wrapper */
197     void
198     ircnet_handler::privmsg (char const * const from, char const * const target, char const * const fmt, ...)
199     {
200     va_list ap;
201     char buf[BUFSIZE];
202    
203     va_start (ap, fmt);
204     vsnprintf (buf, BUFSIZE, fmt, ap);
205     va_end (ap);
206    
207     sts (":%s PRIVMSG %s :%s", from, target, buf);
208     }
209    
210     /* NOTICE wrapper */
211     void
212     ircnet_handler::notice_user_sts (user_t *from, user_t *target, char const * const text)
213     {
214     sts (":%s NOTICE %s :%s", from ? CLIENT_NAME (from) : ME, CLIENT_NAME (target), text);
215     }
216    
217     void
218     ircnet_handler::notice_global_sts (user_t *from, char const * const mask, char const * const text)
219     {
220     node_t *n;
221     tld_t *tld;
222    
223     if (!strcmp (mask, "*"))
224     {
225     LIST_FOREACH (n, tldlist.head)
226     {
227     tld = static_cast<tld_t *> (n->data);
228     sts (":%s NOTICE %s*%s :%s", from ? CLIENT_NAME (from) : ME, ircd->tldprefix, tld->name, text);
229     }
230     }
231     else
232     sts (":%s NOTICE %s%s :%s", from ? CLIENT_NAME (from) : ME, ircd->tldprefix, mask, text);
233     }
234    
235     void
236     ircnet_handler::notice_channel_sts (user_t *from, channel_t *target, char const * const text)
237     {
238     if (from == NULL || chanuser_find (target, from))
239     sts (":%s NOTICE %s :%s", from ? CLIENT_NAME (from) : ME, target->name, text);
240     else
241     sts (":%s NOTICE %s :[%s:%s] %s", ME, target->name, from->nick, target->name, text);
242     }
243    
244     /* numeric wrapper */
245     void
246     ircnet_handler::numeric_sts (char const * const from, int numeric, char const * const target, char const * const fmt, ...)
247     {
248     va_list ap;
249     char buf[BUFSIZE];
250    
251     va_start (ap, fmt);
252     vsnprintf (buf, BUFSIZE, fmt, ap);
253     va_end (ap);
254    
255     sts (":%s %d %s %s", from, numeric, target, buf);
256     }
257    
258     /* KILL wrapper */
259     void
260     ircnet_handler::skill (char const * const from, char const * const nick, char const * const fmt, ...)
261     {
262     va_list ap;
263     char buf[BUFSIZE];
264    
265     va_start (ap, fmt);
266     vsnprintf (buf, BUFSIZE, fmt, ap);
267     va_end (ap);
268    
269     sts (":%s KILL %s :%s!%s!%s (%s)", from, nick, from, from, from, buf);
270     }
271    
272     /* PART wrapper */
273     void
274     ircnet_handler::part_sts (channel_t *c, user_t *u)
275     {
276     sts (":%s PART %s", u->nick, c->name);
277     }
278    
279     /* server-to-server KLINE wrapper */
280     void
281     ircnet_handler::kline_sts (char const * const server, char const * const user, char const * const host, long duration, char const * const reason)
282     {
283     if (!me.connected)
284     return;
285    
286     /* this won't propagate!
287     * you'll need some bot/service on each server to do that */
288     if (irccasecmp (server, me.actual) && cnt.server > 2)
289     wallops ("Missed a tkline");
290     sts (":%s TKLINE %lds %s@%s :%s", opersvs.nick, duration, user, host, reason);
291     }
292    
293     /* server-to-server UNKLINE wrapper */
294     void
295     ircnet_handler::unkline_sts (char const * const server, char const * const user, char const * const host)
296     {
297     if (!me.connected)
298     return;
299    
300     if (irccasecmp (server, me.actual) && cnt.server > 2)
301     wallops ("Missed an untkline");
302     sts (":%s UNTKLINE %s@%s", opersvs.nick, user, host);
303     }
304    
305     /* topic wrapper */
306     void
307     ircnet_handler::topic_sts (channel_t *c, char const * const setter, time_t ts, time_t prevts, char const * const topic)
308     {
309     int joined = 0;
310    
311     if (!me.connected || !c)
312     return;
313    
314     /* Need to join to set topic -- jilles */
315     if (!chanuser_find (c, chansvs.me->me))
316     {
317     sts (":%s NJOIN %s :@%s", ME, c->name, CLIENT_NAME (chansvs.me->me));
318     joined = 1;
319     }
320     sts (":%s TOPIC %s :%s", CLIENT_NAME (chansvs.me->me), c->name, topic);
321     if (joined)
322     sts (":%s PART %s :Topic set", CLIENT_NAME (chansvs.me->me), c->name);
323     }
324    
325     /* mode wrapper */
326     void
327     ircnet_handler::mode_sts (char const * const sender, channel_t *target, char const * const modes)
328     {
329     user_t *u;
330    
331     if (!me.connected)
332     return;
333    
334     u = user_find (sender);
335    
336     /* send it from the server if that service isn't on channel
337     * -- jilles */
338     sts (":%s MODE %s %s", chanuser_find (target, u) ? CLIENT_NAME (u) : ME, target->name, modes);
339     }
340    
341     /* ping wrapper */
342     void
343     ircnet_handler::ping_sts (void)
344     {
345     if (!me.connected)
346     return;
347    
348     sts ("PING :%s", me.name);
349     }
350    
351     /* protocol-specific stuff to do on login */
352     void
353     ircnet_handler::ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost)
354     {
355     /* nothing to do on ratbox */
356     return;
357     }
358    
359     /* protocol-specific stuff to do on login */
360     bool
361     ircnet_handler::ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost)
362     {
363     /* nothing to do on ratbox */
364     return false;
365     }
366    
367     void
368     ircnet_handler::jupe (char const * const server, char const * const reason)
369     {
370     static char sid[4 + 1];
371     int i;
372     server_t *s;
373    
374     if (!me.connected)
375     return;
376    
377     sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
378     s = server_find (server);
379     /* We need to wait for the SQUIT to be processed -- jilles */
380     if (s != NULL)
381     {
382     s->flags |= SF_JUPE_PENDING;
383     return;
384     }
385    
386     /* dirty dirty make up some sid */
387     if (sid[0] == '\0')
388     strlcpy (sid, me.numeric, sizeof sid);
389     do
390     {
391     i = 3;
392     for (;;)
393     {
394     if (sid[i] == 'Z')
395     {
396     sid[i] = '0';
397     i--;
398     /* eek, no more sids */
399     if (i < 0)
400     return;
401     continue;
402     }
403     else if (sid[i] == '9')
404     sid[i] = 'A';
405     else
406     sid[i]++;
407     break;
408     }
409     }
410     while (server_find (sid));
411    
412     sts (":%s SERVER %s 2 %s 0211010000 :%s", me.name, server, sid, reason);
413     }
414    
415     static void
416     m_topic (sourceinfo_t *si, int parc, char *parv[])
417     {
418     channel_t *c = channel_find (parv[0]);
419    
420     if (!c)
421     return;
422    
423     handle_topic_from (si, c, si->su->nick, NOW, parv[1]);
424     }
425    
426     static void
427     m_ping (sourceinfo_t *si, int parc, char *parv[])
428     {
429     /* reply to PING's */
430     sts (":%s PONG %s %s", me.name, me.name, parv[0]);
431     }
432    
433     static void
434     m_pong (sourceinfo_t *si, int parc, char *parv[])
435     {
436     /* someone replied to our PING */
437     if ((!parv[0]) || (strcasecmp (me.actual, parv[0])))
438 pippijn 1.1 return;
439 pippijn 1.4
440     me.uplinkpong = NOW;
441    
442     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
443     }
444    
445     static void
446     m_eob (sourceinfo_t *si, int parc, char *parv[])
447     {
448     server_t *serv;
449     char sidbuf[4 + 1], *p;
450    
451     handle_eob (si->s);
452     if (parc >= 1)
453     {
454     sidbuf[4] = '\0';
455     p = parv[0];
456     while (p[0] && p[1] && p[2] && p[3])
457     {
458     memcpy (sidbuf, p, 4);
459     serv = server_find (sidbuf);
460     handle_eob (serv);
461     if (p[4] != ',')
462     break;
463     p += 5;
464     }
465     }
466    
467     if (me.bursting)
468     {
469     sts (":%s EOBACK", me.numeric);
470     #ifdef HAVE_GETTIMEOFDAY
471     e_time (burstime, &burstime);
472    
473     slog (LG_INFO, "m_eob(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
474    
475     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
476     #else
477     slog (LG_INFO, "m_eob(): finished synching with uplink");
478     wallops ("Finished synching to network.");
479     #endif
480    
481     me.bursting = false;
482     }
483     }
484    
485     static void
486     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
487     {
488     if (parc != 2)
489 pippijn 1.1 return;
490 pippijn 1.4
491     handle_message (si, parv[0], false, parv[1]);
492     }
493    
494     static void
495     m_notice (sourceinfo_t *si, int parc, char *parv[])
496     {
497     if (parc != 2)
498 pippijn 1.1 return;
499 pippijn 1.4
500     handle_message (si, parv[0], true, parv[1]);
501     }
502    
503     static void
504     m_njoin (sourceinfo_t *si, int parc, char *parv[])
505     {
506     channel_t *c;
507     unsigned int userc;
508     char *userv[256];
509     unsigned int i;
510    
511     c = channel_find (parv[0]);
512    
513     if (!c)
514     {
515     slog (LG_DEBUG, "m_njoin(): new channel: %s", parv[0]);
516     /* Give channels created during burst an older "TS"
517     * so they won't be deopped -- jilles */
518     c = channel_add (parv[0], si->s->flags & SF_EOB ? NOW : NOW - 601, si->s);
519     /* if !/+ channel, we don't want to do anything with it */
520     if (c == NULL)
521     return;
522     /* Check mode locks */
523     channel_mode (NULL, c, "+");
524     }
525    
526     userc = sjtoken (parv[parc - 1], ',', userv);
527    
528     for (i = 0; i < userc; i++)
529     chanuser_add (c, userv[i]);
530    
531     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
532     channel_delete (c);
533     }
534    
535     static void
536     m_part (sourceinfo_t *si, int parc, char *parv[])
537     {
538     int chanc;
539     char *chanv[256];
540     int i;
541    
542     chanc = sjtoken (parv[0], ',', chanv);
543     for (i = 0; i < chanc; i++)
544     {
545     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
546    
547     chanuser_delete (channel_find (chanv[i]), si->su);
548     }
549     }
550    
551     static void
552     m_nick (sourceinfo_t *si, int parc, char *parv[])
553     {
554     user_t *u;
555    
556     /* got the right number of args for an introduction? */
557     if (parc == 7)
558     {
559     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", si->s->name, parv[0]);
560    
561     u = user_add (parv[0], parv[2], parv[3], NULL, parv[4], parv[1], parv[6], si->s, 0);
562    
563     user_mode (u, parv[5]);
564     if (strchr (parv[5], 'a'))
565     handle_away (u, "Gone");
566    
567     handle_nickchange (u);
568     }
569    
570     /* if it's only 1 then it's a nickname change */
571     else if (parc == 1)
572     {
573     if (!si->su)
574     {
575     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
576     return;
577     }
578    
579     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
580    
581     user_changenick (si->su, parv[0], 0);
582    
583     handle_nickchange (si->su);
584     }
585     else
586     {
587     int i;
588     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
589    
590     for (i = 0; i < parc; i++)
591     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
592     }
593     }
594    
595     static void
596     m_save (sourceinfo_t *si, int parc, char *parv[])
597     {
598     user_t *u;
599    
600     u = user_find (parv[0]);
601     if (u == NULL)
602 pippijn 1.1 return;
603 pippijn 1.4 if (!strcmp (u->nick, u->uid))
604     {
605     slog (LG_DEBUG, "m_save(): ignoring noop SAVE message for %s", u->nick);
606     return;
607     }
608     if (is_internal_client (u))
609     {
610     slog (LG_INFO, "m_save(): service %s got hit, changing back", u->nick);
611     sts (":%s NICK %s", u->uid, u->nick);
612     /* XXX services wars */
613     }
614     else
615     {
616     slog (LG_DEBUG, "m_save(): nickname change for `%s': %s", u->nick, u->uid);
617    
618     user_changenick (u, u->uid, 0);
619    
620     handle_nickchange (u);
621     }
622     }
623    
624     static void
625     m_quit (sourceinfo_t *si, int parc, char *parv[])
626     {
627     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
628    
629     /* user_delete() takes care of removing channels and so forth */
630     user_delete (si->su);
631     }
632    
633     static void
634     m_mode (sourceinfo_t *si, int parc, char *parv[])
635     {
636     /* The following is hackish, but it works, because user MODE
637     * is not used in bursts and users are not allowed to change away
638     * status using MODE.
639     * -- jilles */
640     if (*parv[0] == '#')
641     channel_mode (NULL, channel_find (parv[0]), parc - 1, &parv[1]);
642     else if (!strcmp (parv[1], "-a"))
643     handle_away (user_find (parv[0]), NULL);
644     else if (!strcmp (parv[1], "+a"))
645     handle_away (user_find (parv[0]), "Gone");
646     else
647     user_mode (user_find (parv[0]), parv[1]);
648     }
649    
650     static void
651     m_kick (sourceinfo_t *si, int parc, char *parv[])
652     {
653     user_t *u = user_find (parv[1]);
654     channel_t *c = channel_find (parv[0]);
655    
656     /* -> :rakaur KICK #shrike rintaun :test */
657     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
658    
659     if (!u)
660     {
661     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
662     return;
663     }
664    
665     if (!c)
666     {
667     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
668     return;
669     }
670    
671     if (!chanuser_find (c, u))
672     {
673     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
674     return;
675     }
676    
677     chanuser_delete (c, u);
678    
679     /* if they kicked us, let's rejoin */
680     if (is_internal_client (u))
681     {
682     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
683     join (parv[0], u->nick);
684     }
685     }
686    
687     static void
688     m_kill (sourceinfo_t *si, int parc, char *parv[])
689     {
690     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
691     }
692    
693     static void
694     m_squit (sourceinfo_t *si, int parc, char *parv[])
695     {
696     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
697     if (server_find (parv[0]))
698     server_delete (parv[0]);
699     else if (si->su != NULL)
700     {
701     /* XXX we don't have a list of jupes, so let's just
702     * assume it is one if we don't know it */
703     slog (LG_INFO, "m_squit(): accepting SQUIT for jupe %s from %s", parv[0], si->su->nick);
704     sts (":%s WALLOPS :Received SQUIT %s from %s (%s)", me.numeric, parv[0], si->su->nick, parv[1]);
705     sts (":%s SQUIT %s :%s", me.numeric, parv[0], parv[1]);
706     }
707     }
708    
709     static void
710     m_server (sourceinfo_t *si, int parc, char *parv[])
711     {
712     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
713     handle_server (si, parv[0], parv[2], atoi (parv[1]), parv[parc - 1]);
714     }
715    
716     static void
717     m_stats (sourceinfo_t *si, int parc, char *parv[])
718     {
719     handle_stats (si->su, parv[0][0]);
720     }
721    
722     static void
723     m_admin (sourceinfo_t *si, int parc, char *parv[])
724     {
725     handle_admin (si->su);
726     }
727    
728     static void
729     m_version (sourceinfo_t *si, int parc, char *parv[])
730     {
731     handle_version (si->su);
732     }
733    
734     static void
735     m_info (sourceinfo_t *si, int parc, char *parv[])
736     {
737     handle_info (si->su);
738     }
739    
740     static void
741     m_whois (sourceinfo_t *si, int parc, char *parv[])
742     {
743     handle_whois (si->su, parv[1]);
744     }
745    
746     static void
747     m_trace (sourceinfo_t *si, int parc, char *parv[])
748     {
749     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
750     }
751    
752     static void
753     m_join (sourceinfo_t *si, int parc, char *parv[])
754     {
755     chanuser_t *cu;
756     node_t *n, *tn;
757    
758     /* JOIN 0 is really a part from all channels */
759     if (parv[0][0] == '0')
760     {
761     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
762     {
763     cu = (chanuser_t *) n->data;
764     chanuser_delete (cu->chan, si->su);
765     }
766     }
767     }
768    
769     static void
770     m_pass (sourceinfo_t *si, int parc, char *parv[])
771     {
772     if (strcmp (curr_uplink->pass, parv[0]))
773 pippijn 1.1 {
774 pippijn 1.4 slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
775     runflags |= RF_SHUTDOWN;
776 pippijn 1.1 }
777 pippijn 1.4 }
778    
779     static void
780     m_error (sourceinfo_t *si, int parc, char *parv[])
781     {
782     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
783     }
784    
785     static void
786     m_motd (sourceinfo_t *si, int parc, char *parv[])
787     {
788     handle_motd (si->su);
789     }
790    
791     static pcommand_t const pcommands[] = {
792     { "PING", m_ping, 1, MSRC_USER | MSRC_SERVER },
793     { "PONG", m_pong, 1, MSRC_SERVER },
794     { "EOB", m_eob, 0, MSRC_SERVER },
795     { "PRIVMSG", m_privmsg, 2, MSRC_USER },
796     { "NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER },
797     { "NJOIN", m_njoin, 2, MSRC_SERVER },
798     { "PART", m_part, 1, MSRC_USER },
799     { "NICK", m_nick, 1, MSRC_USER },
800     { "UNICK", m_nick, 7, MSRC_SERVER },
801     { "SAVE", m_save, 1, MSRC_SERVER },
802     { "QUIT", m_quit, 1, MSRC_USER },
803     { "MODE", m_mode, 2, MSRC_USER | MSRC_SERVER },
804     { "KICK", m_kick, 2, MSRC_USER | MSRC_SERVER },
805     { "KILL", m_kill, 1, MSRC_USER | MSRC_SERVER },
806     { "SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER },
807     { "SERVER", m_server, 4, MSRC_UNREG | MSRC_SERVER },
808     { "STATS", m_stats, 2, MSRC_USER },
809     { "ADMIN", m_admin, 1, MSRC_USER },
810     { "VERSION", m_version, 1, MSRC_USER },
811     { "INFO", m_info, 1, MSRC_USER },
812     { "WHOIS", m_whois, 2, MSRC_USER },
813     { "TRACE", m_trace, 1, MSRC_USER },
814     { "JOIN", m_join, 1, MSRC_USER },
815     { "PASS", m_pass, 1, MSRC_UNREG },
816     { "ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER },
817     { "TOPIC", m_topic, 2, MSRC_USER },
818     { "MOTD", m_motd, 1, MSRC_USER },
819     };
820    
821     ircnet_handler::ircnet_handler ()
822     {
823     mode_list = ircnet_mode_list;
824     ignore_mode_list = ircnet_ignore_mode_list;
825     status_mode_list = ircnet_status_mode_list;
826     prefix_mode_list = ircnet_prefix_mode_list;
827    
828     ircd = &IRCNet;
829    
830     pcommand_add (&pcommands);
831     }
832    
833     ircnet_handler::~ircnet_handler ()
834     {
835     mode_list = NULL;
836     ignore_mode_list = NULL;
837     status_mode_list = NULL;
838     prefix_mode_list = NULL;
839    
840     ircd = NULL;
841    
842     pcommand_delete (&pcommands);
843     }
844     } // namespace protocol
845    
846     #define FACREG_TYPE protocol::ircnet_handler
847     #define FACREG_TYPE_NAME "ircnet"
848     #define FACREG_INTERFACE_TYPE protocol::handler
849     #include <ermyth/factory_reg.h>