ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/ircnet.C
Revision: 1.7
Committed: Sun Sep 16 18:54:44 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +10 -7 lines
Log Message:
#defines to enum

File Contents

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