ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/shadowircd.C
Revision: 1.1
Committed: Thu Jul 19 08:24:55 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Log Message:
initial import. the most important changes since Atheme are:
- fixed many memory leaks
- fixed many bugs
- converted to C++ and use more STL containers
- added a (not very enhanced yet) perl module
- greatly improved XML-RPC speed
- added a JSON-RPC module with code from json-cpp
- added a valgrind memcheck module to operserv
- added a more object oriented base64 implementation
- added a specialised unit test framework
- improved stability
- use gettimeofday() if available
- reworked adding/removing commands
- MemoServ IGNORE DEL can now remove indices

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * Copyright © 2003-2004 E. Will et al.
3     * Copyright © 2005-2006 Atheme Development Group
4     * Rights to this code are documented in doc/LICENSE.
5     *
6     * This file contains protocol support for shadowircd-based ircd.
7     *
8     * $Id: shadowircd.c 8301 2007-05-20 13:22:15Z jilles $
9     */
10    
11     #include "atheme.h"
12     #include <account/mynick.h>
13     #include "uplink.h"
14     #include "pmodule.h"
15     #include "protocol/shadowircd.h"
16    
17     static char const rcsid[] = "$Id";
18    
19     struct shadowircd_listeners : callback::has_listeners
20     {
21     };
22    
23     shadowircd_listeners listeners;
24    
25     DECLARE_MODULE_V1 ("protocol/shadowircd", true, _modinit, NULL, rcsid, "The Ermyth Team <http://ermyth.schmorp.de>");
26    
27     /* *INDENT-OFF* */
28    
29     ircd_t ShadowIRCd = {
30     "ShadowIRCd 3.3/3.6 family", /* IRCd name */
31     "$$", /* TLD Prefix, used by Global. */
32     false, /* Whether or not we use IRCNet/TS6 UID */
33     false, /* Whether or not we use RCOMMAND */
34     true, /* Whether or not we support channel owners. */
35     true, /* Whether or not we support channel protection. */
36     true, /* Whether or not we support halfops. */
37     false, /* Whether or not we use P10 */
38     true, /* Whether or not we use vHosts. */
39     CMODE_OPERONLY | CMODE_PERM, /* Oper-only cmodes */
40     CMODE_PROTECT, /* Integer flag for owner channel flag. */
41     CMODE_PROTECT, /* Integer flag for protect channel flag. */
42     CMODE_HALFOP, /* Integer flag for halfops. */
43     "+u", /* Mode we set for owner. */
44     "+u", /* Mode we set for protect. */
45     "+h", /* Mode we set for halfops. */
46     PROTOCOL_SHADOWIRCD, /* Protocol type */
47     CMODE_PERM, /* Permanent cmodes */
48     "beIqd", /* Ban-like cmodes */
49     'e', /* Except mchar */
50     'I', /* Invex mchar */
51     0 /* Flags */
52     };
53    
54     cmode_t shadowircd_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     { 'c', CMODE_NOCOLOR },
62     { 'M', CMODE_MODREG },
63     { 'E', CMODE_REGONLY },
64     { 'O', CMODE_OPERONLY },
65     { 'P', CMODE_PEACE },
66     { 'R', CMODE_PERM },
67     { 'S', CMODE_STRIP },
68     { 'K', CMODE_NOKNOCK },
69     { 'N', CMODE_STICKY },
70     { '\0', 0 }
71     };
72    
73     extmode shadowircd_ignore_mode_list[] = {
74     { '\0', 0 }
75     };
76    
77     cmode_t shadowircd_status_mode_list[] = {
78     { 'u', CMODE_PROTECT },
79     { 'o', CMODE_OP },
80     { 'h', CMODE_HALFOP },
81     { 'v', CMODE_VOICE },
82     { '\0', 0 }
83     };
84    
85     cmode_t shadowircd_prefix_mode_list[] = {
86     { '!', CMODE_PROTECT },
87     { '@', CMODE_OP },
88     { '%', CMODE_HALFOP },
89     { '+', CMODE_VOICE },
90     { '\0', 0 }
91     };
92    
93     /* *INDENT-ON* */
94    
95     /* login to our uplink */
96     static unsigned int
97     shadowircd_server_login (void)
98     {
99     int ret;
100    
101     ret = sts ("PASS %s :TS", curr_uplink->pass);
102     if (ret == 1)
103     return 1;
104    
105     me.bursting = true;
106    
107     sts ("CAPAB :QS EX IE KLN UNKLN ENCAP SERVICES");
108     sts ("SERVER %s 1 :%s", me.name, me.desc);
109     sts ("SVINFO 5 3 0 :%ld", NOW);
110    
111     return 0;
112     }
113    
114     /* introduce a client */
115     static void
116     shadowircd_introduce_nick (user_t *u)
117     {
118     sts ("NICK %s 1 %ld +%sS %s %s %s :%s", u->nick, u->ts, "io", u->user, u->host, me.name, u->gecos);
119     }
120    
121     /* invite a user to a channel */
122     static void
123     shadowircd_invite_sts (user_t *sender, user_t *target, channel_t *channel)
124     {
125     sts (":%s INVITE %s %s", sender->nick, target->nick, channel->name);
126     }
127    
128     static void
129     shadowircd_quit_sts (user_t *u, const char *reason)
130     {
131     if (!me.connected)
132     return;
133    
134     sts (":%s QUIT :%s", u->nick, reason);
135     }
136    
137     /* WALLOPS wrapper */
138     static void
139     shadowircd_wallops_sts (const char *text)
140     {
141     sts (":%s WALLOPS :%s", chansvs.nick, text);
142     }
143    
144     /* join a channel */
145     static void
146     shadowircd_join_sts (channel_t *c, user_t *u, bool isnew, char *modes)
147     {
148     if (isnew)
149     sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, modes, u->nick);
150     else
151     sts (":%s SJOIN %ld %s + :@%s", me.name, c->ts, c->name, u->nick);
152     }
153    
154     /* kicks a user from a channel */
155     static void
156     shadowircd_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    
161     if (!chan || !user)
162     return;
163    
164     sts (":%s KICK %s %s :%s", from, channel, to, reason);
165    
166     chanuser_delete (chan, user);
167     }
168    
169     /* PRIVMSG wrapper */
170     static void
171     shadowircd_msg (const char *from, const char *target, const char *fmt, ...)
172     {
173     va_list ap;
174     char buf[BUFSIZE];
175    
176     va_start (ap, fmt);
177     vsnprintf (buf, BUFSIZE, fmt, ap);
178     va_end (ap);
179    
180     sts (":%s PRIVMSG %s :%s", from, target, buf);
181     }
182    
183     /* NOTICE wrapper */
184     static void
185     shadowircd_notice_user_sts (user_t *from, user_t *target, const char *text)
186     {
187     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->nick, text);
188     }
189    
190     static void
191     shadowircd_notice_global_sts (user_t *from, const char *mask, const char *text)
192     {
193     sts (":%s NOTICE %s%s :%s", from ? from->nick : me.name, ircd->tldprefix, mask, text);
194     }
195    
196     static void
197     shadowircd_notice_channel_sts (user_t *from, channel_t *target, const char *text)
198     {
199     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->name, text);
200     }
201    
202     static void
203     shadowircd_wallchops (user_t *sender, channel_t *channel, const char *message)
204     {
205     if (chanuser_find (channel, sender))
206     sts (":%s NOTICE @%s :%s", CLIENT_NAME (sender), channel->name, message);
207     else /* do not join for this, everyone would see -- jilles */
208     generic_wallchops (sender, channel, message);
209     }
210    
211     /* numeric wrapper */
212     static void
213     shadowircd_numeric_sts (char *from, int numeric, char *target, char *fmt, ...)
214     {
215     va_list ap;
216     char buf[BUFSIZE];
217    
218     va_start (ap, fmt);
219     vsnprintf (buf, BUFSIZE, fmt, ap);
220     va_end (ap);
221    
222     sts (":%s %d %s %s", from, numeric, target, buf);
223     }
224    
225     /* KILL wrapper */
226     static void
227     shadowircd_skill (char *from, char *nick, char *fmt, ...)
228     {
229     va_list ap;
230     char buf[BUFSIZE];
231    
232     va_start (ap, fmt);
233     vsnprintf (buf, BUFSIZE, fmt, ap);
234     va_end (ap);
235    
236     sts (":%s KILL %s :%s!%s!%s (%s)", from, nick, from, from, from, buf);
237     }
238    
239     /* PART wrapper */
240     static void
241     shadowircd_part_sts (channel_t *c, user_t *u)
242     {
243     sts (":%s PART %s", u->nick, c->name);
244     }
245    
246     /* server-to-server KLINE wrapper */
247     static void
248     shadowircd_kline_sts (char *server, char *user, char *host, long duration, char *reason)
249     {
250     if (!me.connected)
251     return;
252    
253     sts (":%s KLINE %s %ld %s %s :%s", me.name, server, duration, user, host, reason);
254     }
255    
256     /* server-to-server UNKLINE wrapper */
257     static void
258     shadowircd_unkline_sts (char *server, char *user, char *host)
259     {
260     if (!me.connected)
261     return;
262    
263     sts (":%s UNKLINE %s %s %s", opersvs.nick, server, user, host);
264     }
265    
266     /* topic wrapper */
267     static void
268     shadowircd_topic_sts (channel_t *c, const char *setter, time_t ts, time_t prevts, const char *topic)
269     {
270     if (!me.connected || !c)
271     return;
272    
273     sts (":%s TOPIC %s :%s", chansvs.nick, c->name, topic);
274     }
275    
276     /* mode wrapper */
277     static void
278     shadowircd_mode_sts (char *sender, channel_t *target, char *modes)
279     {
280     if (!me.connected)
281     return;
282    
283     sts (":%s MODE %s %s", sender, target->name, modes);
284     }
285    
286     /* ping wrapper */
287     static void
288     shadowircd_ping_sts (void)
289     {
290     if (!me.connected)
291     return;
292    
293     sts ("PING :%s", me.name);
294     }
295    
296     /* protocol-specific stuff to do on login */
297     static void
298     shadowircd_on_login (char *origin, char *user, char *wantedhost)
299     {
300     user_t *u = user_find (origin);
301    
302     if (!me.connected || u == NULL)
303     return;
304    
305     /* Can only do this for nickserv, and can only record identified
306     * state if logged in to correct nick, sorry -- jilles
307     */
308     if (should_reg_umode (u))
309     sts (":%s MODE %s +e", me.name, origin);
310     }
311    
312     /* protocol-specific stuff to do on login */
313     static bool
314     shadowircd_on_logout (char *origin, char *user, char *wantedhost)
315     {
316     if (!me.connected)
317     return false;
318    
319     if (!nicksvs.no_nick_ownership)
320     sts (":%s MODE %s -e", me.name, origin);
321    
322     return false;
323     }
324    
325     static void
326     shadowircd_jupe (const char *server, const char *reason)
327     {
328     if (!me.connected)
329     return;
330    
331     server_delete (server);
332     sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
333     sts (":%s SERVER %s 2 :%s", me.name, server, reason);
334     }
335    
336     static void
337     m_topic (sourceinfo_t *si, int parc, char *parv[])
338     {
339     channel_t *c = channel_find (parv[0]);
340    
341     if (c == NULL)
342     return;
343    
344     handle_topic_from (si, c, si->su->nick, NOW, parv[1]);
345     }
346    
347     static void
348     m_ping (sourceinfo_t *si, int parc, char *parv[])
349     {
350     /* reply to PING's */
351     sts (":%s PONG %s %s", me.name, me.name, parv[0]);
352     }
353    
354     static void
355     m_pong (sourceinfo_t *si, int parc, char *parv[])
356     {
357     server_t *s;
358    
359     /* someone replied to our PING */
360     if (!parv[0])
361     return;
362     s = server_find (parv[0]);
363     if (s == NULL)
364     return;
365     handle_eob (s);
366    
367     if (irccasecmp (me.actual, parv[0]))
368     return;
369    
370     me.uplinkpong = NOW;
371    
372     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
373     if (me.bursting)
374     {
375     #ifdef HAVE_GETTIMEOFDAY
376     e_time (burstime, &burstime);
377    
378     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
379    
380     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
381     #else
382     slog (LG_INFO, "m_pong(): finished synching with uplink");
383     wallops ("Finished synching to network.");
384     #endif
385    
386     me.bursting = false;
387     }
388     }
389    
390     static void
391     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
392     {
393     if (parc != 2)
394     return;
395    
396     handle_message (si, parv[0], false, parv[1]);
397     }
398    
399     static void
400     m_notice (sourceinfo_t *si, int parc, char *parv[])
401     {
402     if (parc != 2)
403     return;
404    
405     handle_message (si, parv[0], true, parv[1]);
406     }
407    
408     static void
409     m_sjoin (sourceinfo_t *si, int parc, char *parv[])
410     {
411     /* -> :proteus.malkier.net SJOIN 1073516550 #shrike +tn :@sycobuny @+rakaur */
412    
413     channel_t *c;
414     unsigned int userc;
415     char *userv[256];
416     unsigned int i;
417     time_t ts;
418    
419     /* :origin SJOIN ts chan modestr [key or limits] :users */
420     c = channel_find (parv[1]);
421     ts = atol (parv[0]);
422    
423     if (!c)
424     {
425     slog (LG_DEBUG, "m_sjoin(): new channel: %s", parv[1]);
426     c = channel_add (parv[1], ts, si->s);
427     }
428    
429     if (ts < c->ts)
430     {
431     chanuser_t *cu;
432     node_t *n;
433    
434     /* the TS changed. a TS change requires the following things
435     * to be done to the channel: reset all modes to nothing, remove
436     * all status modes on known users on the channel (including ours),
437     * and set the new TS.
438     */
439    
440     clear_simple_modes (c);
441    
442     LIST_FOREACH (n, c->members.head)
443     {
444     cu = (chanuser_t *) n->data;
445     cu->modes = 0;
446     }
447    
448     slog (LG_DEBUG, "m_sjoin(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
449    
450     c->ts = ts;
451     hook_call_event ("channel_tschange", c);
452     }
453    
454     channel_mode (NULL, c, parc - 3, parv + 2);
455    
456     userc = sjtoken (parv[parc - 1], ' ', userv);
457    
458     for (i = 0; i < userc; i++)
459     chanuser_add (c, userv[i]);
460    
461     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
462     channel_delete (c);
463     }
464    
465     static void
466     m_part (sourceinfo_t *si, int parc, char *parv[])
467     {
468     int chanc;
469     char *chanv[256];
470     int i;
471    
472     chanc = sjtoken (parv[0], ',', chanv);
473     for (i = 0; i < chanc; i++)
474     {
475     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
476    
477     chanuser_delete (channel_find (chanv[i]), si->su);
478     }
479     }
480    
481     static void
482     m_nick (sourceinfo_t *si, int parc, char *parv[])
483     {
484     server_t *s;
485     user_t *u;
486    
487     /* got the right number of args for an introduction? */
488     if (parc == 8)
489     {
490     s = server_find (parv[6]);
491     if (!s)
492     {
493     slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
494     return;
495     }
496    
497     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
498    
499     u = user_add (parv[0], parv[4], parv[5], NULL, NULL, NULL, parv[7], s, atoi (parv[2]));
500    
501     user_mode (u, parv[3]);
502    
503     handle_nickchange (u);
504     }
505    
506     /* if it's only 2 then it's a nickname change */
507     else if (parc == 2)
508     {
509     if (!si->su)
510     {
511     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
512     return;
513     }
514    
515     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
516    
517     user_changenick (si->su, parv[0], atoi (parv[1]));
518    
519     handle_nickchange (si->su);
520     }
521     else
522     {
523     int i;
524     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
525    
526     for (i = 0; i < parc; i++)
527     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
528     }
529     }
530    
531     static void
532     m_quit (sourceinfo_t *si, int parc, char *parv[])
533     {
534     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
535    
536     /* user_delete() takes care of removing channels and so forth */
537     user_delete (si->su);
538     }
539    
540     static void
541     m_mode (sourceinfo_t *si, int parc, char *parv[])
542     {
543     if (*parv[0] == '#')
544     channel_mode (NULL, channel_find (parv[0]), parc - 1, &parv[1]);
545     else
546     user_mode (user_find (parv[0]), parv[1]);
547     }
548    
549     static void
550     m_kick (sourceinfo_t *si, int parc, char *parv[])
551     {
552     user_t *u = user_find (parv[1]);
553     channel_t *c = channel_find (parv[0]);
554    
555     /* -> :rakaur KICK #shrike rintaun :test */
556     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
557    
558     if (!u)
559     {
560     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
561     return;
562     }
563    
564     if (!c)
565     {
566     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
567     return;
568     }
569    
570     if (!chanuser_find (c, u))
571     {
572     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
573     return;
574     }
575    
576     chanuser_delete (c, u);
577    
578     /* if they kicked us, let's rejoin */
579     if (is_internal_client (u))
580     {
581     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
582     join (parv[0], u->nick);
583     }
584     }
585    
586     static void
587     m_kill (sourceinfo_t *si, int parc, char *parv[])
588     {
589     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
590     }
591    
592     static void
593     m_squit (sourceinfo_t *si, int parc, char *parv[])
594     {
595     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
596     server_delete (parv[0]);
597     }
598    
599     static void
600     m_server (sourceinfo_t *si, int parc, char *parv[])
601     {
602     server_t *s;
603    
604     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
605     s = handle_server (si, parv[0], NULL, atoi (parv[1]), parv[2]);
606    
607     if (s != NULL && s->uplink != me.me)
608     {
609     /* elicit PONG for EOB detection; pinging uplink is
610     * already done elsewhere -- jilles
611     */
612     sts (":%s PING %s %s", me.name, me.name, s->name);
613     }
614     }
615    
616     static void
617     m_stats (sourceinfo_t *si, int parc, char *parv[])
618     {
619     handle_stats (si->su, parv[0][0]);
620     }
621    
622     static void
623     m_admin (sourceinfo_t *si, int parc, char *parv[])
624     {
625     handle_admin (si->su);
626     }
627    
628     static void
629     m_version (sourceinfo_t *si, int parc, char *parv[])
630     {
631     handle_version (si->su);
632     }
633    
634     static void
635     m_info (sourceinfo_t *si, int parc, char *parv[])
636     {
637     handle_info (si->su);
638     }
639    
640     static void
641     m_whois (sourceinfo_t *si, int parc, char *parv[])
642     {
643     handle_whois (si->su, parv[1]);
644     }
645    
646     static void
647     m_trace (sourceinfo_t *si, int parc, char *parv[])
648     {
649     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
650     }
651    
652     static void
653     m_away (sourceinfo_t *si, int parc, char *parv[])
654     {
655     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
656     }
657    
658     static void
659     m_join (sourceinfo_t *si, int parc, char *parv[])
660     {
661     chanuser_t *cu;
662     node_t *n, *tn;
663    
664     /* JOIN 0 is really a part from all channels */
665     if (parv[0][0] == '0')
666     {
667     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
668     {
669     cu = (chanuser_t *) n->data;
670     chanuser_delete (cu->chan, si->su);
671     }
672     }
673     }
674    
675     static void
676     m_pass (sourceinfo_t *si, int parc, char *parv[])
677     {
678     if (strcmp (curr_uplink->pass, parv[0]))
679     {
680     slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
681     runflags |= RF_SHUTDOWN;
682     }
683     }
684    
685     static void
686     m_error (sourceinfo_t *si, int parc, char *parv[])
687     {
688     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
689     }
690    
691     static void
692     m_capab (sourceinfo_t *si, int parc, char *parv[])
693     {
694     services_init ();
695     }
696    
697     /* :shadowircd36.qa.atheme.org SVSCLOAK nenolod moogles.are.fun */
698     static void
699     m_svscloak (sourceinfo_t *si, int parc, char *parv[])
700     {
701     user_t *u = user_find (parv[0]);
702    
703     if (!u)
704     return;
705    
706     strlcpy (u->vhost, parv[1], HOSTLEN);
707     }
708    
709     static void
710     m_motd (sourceinfo_t *si, int parc, char *parv[])
711     {
712     handle_motd (si->su);
713     }
714    
715     static void
716     nick_group (hook_user_req_t * hdata)
717     {
718     user_t *u;
719    
720     u = hdata->si->su != NULL && !irccasecmp (hdata->si->su->nick, hdata->mn->nick) ? hdata->si->su : user_find_named (hdata->mn->nick);
721     if (u != NULL && should_reg_umode (u))
722     sts (":%s MODE %s +e", me.name, u->nick);
723     }
724    
725     static void
726     nick_ungroup (hook_user_req_t * hdata)
727     {
728     user_t *u;
729    
730     u = hdata->si->su != NULL && !irccasecmp (hdata->si->su->nick, hdata->mn->nick) ? hdata->si->su : user_find_named (hdata->mn->nick);
731     if (u != NULL && !nicksvs.no_nick_ownership)
732     sts (":%s MODE %s -e", me.name, u->nick);
733     }
734    
735     void
736     _modinit (module_t *m)
737     {
738     /* Symbol relocation voodoo. */
739     server_login = &shadowircd_server_login;
740     introduce_nick = &shadowircd_introduce_nick;
741     quit_sts = &shadowircd_quit_sts;
742     wallops_sts = &shadowircd_wallops_sts;
743     join_sts = &shadowircd_join_sts;
744     kick = &shadowircd_kick;
745     msg = &shadowircd_msg;
746     notice_user_sts = &shadowircd_notice_user_sts;
747     notice_global_sts = &shadowircd_notice_global_sts;
748     notice_channel_sts = &shadowircd_notice_channel_sts;
749     wallchops = &shadowircd_wallchops;
750     numeric_sts = &shadowircd_numeric_sts;
751     skill = &shadowircd_skill;
752     part_sts = &shadowircd_part_sts;
753     kline_sts = &shadowircd_kline_sts;
754     unkline_sts = &shadowircd_unkline_sts;
755     topic_sts = &shadowircd_topic_sts;
756     mode_sts = &shadowircd_mode_sts;
757     ping_sts = &shadowircd_ping_sts;
758     ircd_on_login = &shadowircd_on_login;
759     ircd_on_logout = &shadowircd_on_logout;
760     jupe = &shadowircd_jupe;
761     invite_sts = &shadowircd_invite_sts;
762    
763     mode_list = shadowircd_mode_list;
764     ignore_mode_list = shadowircd_ignore_mode_list;
765     status_mode_list = shadowircd_status_mode_list;
766     prefix_mode_list = shadowircd_prefix_mode_list;
767    
768     ircd = &ShadowIRCd;
769    
770     pcommand_add ("PING", m_ping, 1, MSRC_USER | MSRC_SERVER);
771     pcommand_add ("PONG", m_pong, 1, MSRC_SERVER);
772     pcommand_add ("PRIVMSG", m_privmsg, 2, MSRC_USER);
773     pcommand_add ("NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER);
774     pcommand_add ("SJOIN", m_sjoin, 2, MSRC_USER | MSRC_SERVER);
775     pcommand_add ("PART", m_part, 1, MSRC_USER);
776     pcommand_add ("NICK", m_nick, 2, MSRC_USER | MSRC_SERVER);
777     pcommand_add ("QUIT", m_quit, 1, MSRC_USER);
778     pcommand_add ("MODE", m_mode, 2, MSRC_USER | MSRC_SERVER);
779     pcommand_add ("KICK", m_kick, 2, MSRC_USER | MSRC_SERVER);
780     pcommand_add ("KILL", m_kill, 1, MSRC_USER | MSRC_SERVER);
781     pcommand_add ("SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER);
782     pcommand_add ("SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER);
783     pcommand_add ("STATS", m_stats, 2, MSRC_USER);
784     pcommand_add ("ADMIN", m_admin, 1, MSRC_USER);
785     pcommand_add ("VERSION", m_version, 1, MSRC_USER);
786     pcommand_add ("INFO", m_info, 1, MSRC_USER);
787     pcommand_add ("WHOIS", m_whois, 2, MSRC_USER);
788     pcommand_add ("TRACE", m_trace, 1, MSRC_USER);
789     pcommand_add ("AWAY", m_away, 0, MSRC_USER);
790     pcommand_add ("JOIN", m_join, 1, MSRC_USER);
791     pcommand_add ("PASS", m_pass, 1, MSRC_UNREG);
792     pcommand_add ("ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER);
793     pcommand_add ("TOPIC", m_topic, 2, MSRC_USER);
794     pcommand_add ("CAPAB", m_capab, 1, MSRC_UNREG);
795     pcommand_add ("SVSCLOAK", m_svscloak, 2, MSRC_USER | MSRC_SERVER);
796     pcommand_add ("MOTD", m_motd, 1, MSRC_USER);
797    
798     hook_add_event ("nick_group");
799     hook_add_hook ("nick_group", (void (*)(void *)) nick_group);
800     hook_add_event ("nick_ungroup");
801     hook_add_hook ("nick_ungroup", (void (*)(void *)) nick_ungroup);
802    
803     m->mflags = MODTYPE_CORE;
804    
805     pmodule_loaded = true;
806     }
807    
808     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
809     * vim:ts=8
810     * vim:sw=8
811     * vim:noexpandtab
812     */