ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/ircnet.C
Revision: 1.5
Committed: Wed Sep 5 11:23:14 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.4: +3 -3 lines
Log Message:
removed GPLed code and put license back to BSD

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