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

File Contents

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