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