ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/ultimate3.C
Revision: 1.3
Committed: Sat Jul 21 13:23:21 2007 UTC (19 years, 3 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +2 -2 lines
Log Message:
- added rcsid to some files
- more documentation tweaks
- made most protocol commands local to phandler.C
- added ircd metadata (inspircd only for now)
- added inspircd swhois support

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 Ultimate3 ircd.
7     *
8 pippijn 1.3 * $Id: ultimate3.C,v 1.2 2007-07-21 01:29:10 pippijn Exp $
9 pippijn 1.1 */
10    
11     #include "atheme.h"
12     #include <account/mynick.h>
13     #include "uplink.h"
14     #include "pmodule.h"
15     #include "protocol/ultimate3.h"
16    
17 pippijn 1.3 static char const rcsid[] = "$Id$";
18 pippijn 1.1
19     struct ultimate3_listeners : callback::has_listeners
20     {
21     };
22    
23     ultimate3_listeners listeners;
24    
25     DECLARE_MODULE_V1 ("protocol/ultimate3", true, _modinit, NULL, rcsid, "The Ermyth Team <http://ermyth.schmorp.de>");
26    
27     /* *INDENT-OFF* */
28    
29     ircd_t ultimate3 = {
30     "UltimateIRCd 3.0.*", /* 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     false, /* 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, /* Oper-only cmodes */
40     0, /* Integer flag for owner channel flag. */
41     CMODE_PROTECT, /* Integer flag for protect channel flag. */
42     CMODE_HALFOP, /* Integer flag for halfops. */
43     "+", /* Mode we set for owner. */
44     "+a", /* Mode we set for protect. */
45     "+h", /* Mode we set for halfops. */
46     PROTOCOL_ULTIMATE3, /* Protocol type */
47     0, /* Permanent cmodes */
48     "be", /* Ban-like cmodes */
49     'e', /* Except mchar */
50     0, /* Invex mchar */
51     0 /* Flags */
52     };
53    
54     cmode_t ultimate3_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     { 'M', CMODE_MODREG },
62     { 'R', CMODE_REGONLY },
63     { 'O', CMODE_OPERONLY },
64     { '\0', 0 }
65     };
66    
67     extmode ultimate3_ignore_mode_list[] = {
68     { '\0', 0 }
69     };
70    
71     cmode_t ultimate3_status_mode_list[] = {
72     { 'a', CMODE_PROTECT },
73     { 'o', CMODE_OP },
74     { 'h', CMODE_HALFOP },
75     { 'v', CMODE_VOICE },
76     { '\0', 0 }
77     };
78    
79     cmode_t ultimate3_prefix_mode_list[] = {
80     { '!', CMODE_PROTECT },
81     { '@', CMODE_OP },
82     { '%', CMODE_HALFOP },
83     { '+', CMODE_VOICE },
84     { '\0', 0 }
85     };
86    
87     /* *INDENT-ON* */
88    
89     /* login to our uplink */
90     static unsigned int
91     ultimate3_server_login (void)
92     {
93     int ret;
94    
95     ret = sts ("PASS %s :TS", curr_uplink->pass);
96     if (ret == 1)
97     return 1;
98    
99     me.bursting = true;
100    
101     sts ("CAPAB TS5 NOQUIT SSJ5 BURST TSMODE NICKIP CLIENT");
102     sts ("SERVER %s 1 :%s", me.name, me.desc);
103     sts ("SVINFO 5 3 0 :%ld", NOW);
104    
105     services_init ();
106    
107     return 0;
108     }
109    
110     /* introduce a client */
111     static void
112     ultimate3_introduce_nick (user_t *u)
113     {
114     sts ("CLIENT %s 1 %ld +%sS + %s %s * %s 0 0 :%s", u->nick, u->ts, "io", u->user, u->host, me.name, u->gecos);
115     }
116    
117     /* invite a user to a channel */
118     static void
119     ultimate3_invite_sts (user_t *sender, user_t *target, channel_t *channel)
120     {
121     sts (":%s INVITE %s %s", sender->nick, target->nick, channel->name);
122     }
123    
124     static void
125     ultimate3_quit_sts (user_t *u, const char *reason)
126     {
127     if (!me.connected)
128     return;
129    
130     sts (":%s QUIT :%s", u->nick, reason);
131     }
132    
133     /* WALLOPS wrapper */
134     static void
135     ultimate3_wallops_sts (const char *text)
136     {
137     sts (":%s GLOBOPS :%s", chansvs.nick, text);
138     }
139    
140     /* join a channel */
141     static void
142     ultimate3_join_sts (channel_t *c, user_t *u, bool isnew, char *modes)
143     {
144     if (isnew)
145     sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, modes, u->nick);
146     else
147     sts (":%s SJOIN %ld %s + :@%s", me.name, c->ts, c->name, u->nick);
148     }
149    
150     /* kicks a user from a channel */
151     static void
152     ultimate3_kick (char *from, char *channel, char *to, char *reason)
153     {
154     channel_t *chan = channel_find (channel);
155     user_t *user = user_find (to);
156    
157     if (!chan || !user)
158     return;
159    
160     sts (":%s KICK %s %s :%s", from, channel, to, reason);
161    
162     chanuser_delete (chan, user);
163     }
164    
165     /* PRIVMSG wrapper */
166     static void
167     ultimate3_msg (const char *from, const char *target, const char *fmt, ...)
168     {
169     va_list ap;
170     char buf[BUFSIZE];
171    
172     va_start (ap, fmt);
173     vsnprintf (buf, BUFSIZE, fmt, ap);
174     va_end (ap);
175    
176     sts (":%s PRIVMSG %s :%s", from, target, buf);
177     }
178    
179     /* NOTICE wrapper */
180     static void
181     ultimate3_notice_user_sts (user_t *from, user_t *target, const char *text)
182     {
183     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->nick, text);
184     }
185    
186     static void
187     ultimate3_notice_global_sts (user_t *from, const char *mask, const char *text)
188     {
189     node_t *n;
190     tld_t *tld;
191    
192     if (!strcmp (mask, "*"))
193     {
194     LIST_FOREACH (n, tldlist.head)
195     {
196     tld = static_cast<tld_t *> (n->data);
197     sts (":%s NOTICE %s*%s :%s", from ? from->nick : me.name, ircd->tldprefix, tld->name, text);
198     }
199     }
200     else
201     sts (":%s NOTICE %s%s :%s", from ? from->nick : me.name, ircd->tldprefix, mask, text);
202     }
203    
204     static void
205     ultimate3_notice_channel_sts (user_t *from, channel_t *target, const char *text)
206     {
207     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->name, text);
208     }
209    
210     static void
211     ultimate3_numeric_sts (char *from, int numeric, char *target, char *fmt, ...)
212     {
213     va_list ap;
214     char buf[BUFSIZE];
215    
216     va_start (ap, fmt);
217     vsnprintf (buf, BUFSIZE, fmt, ap);
218     va_end (ap);
219    
220     sts (":%s %d %s %s", from, numeric, target, buf);
221     }
222    
223     /* KILL wrapper */
224     static void
225     ultimate3_skill (char *from, char *nick, char *fmt, ...)
226     {
227     va_list ap;
228     char buf[BUFSIZE];
229    
230     va_start (ap, fmt);
231     vsnprintf (buf, BUFSIZE, fmt, ap);
232     va_end (ap);
233    
234     sts (":%s KILL %s :%s!%s!%s (%s)", from, nick, from, from, from, buf);
235     }
236    
237     /* PART wrapper */
238     static void
239     ultimate3_part_sts (channel_t *c, user_t *u)
240     {
241     sts (":%s PART %s", u->nick, c->name);
242     }
243    
244     /* server-to-server KLINE wrapper */
245     static void
246     ultimate3_kline_sts (char *server, char *user, char *host, long duration, char *reason)
247     {
248     if (!me.connected)
249     return;
250    
251     sts (":%s AKILL %s %s %ld %s %ld :%s", me.name, host, user, duration, opersvs.nick, time (NULL), reason);
252     }
253    
254     /* server-to-server UNKLINE wrapper */
255     static void
256     ultimate3_unkline_sts (char *server, char *user, char *host)
257     {
258     if (!me.connected)
259     return;
260    
261     sts (":%s RAKILL %s %s", me.name, host, user);
262     }
263    
264     /* topic wrapper */
265     static void
266     ultimate3_topic_sts (channel_t *c, const char *setter, time_t ts, time_t prevts, const char *topic)
267     {
268     if (!me.connected || !c)
269     return;
270    
271     sts (":%s TOPIC %s %s %ld :%s", chansvs.nick, c->name, setter, ts, topic);
272     }
273    
274     /* mode wrapper */
275     static void
276     ultimate3_mode_sts (char *sender, channel_t *target, char *modes)
277     {
278     if (!me.connected)
279     return;
280    
281     sts (":%s MODE %s %ld %s", sender, target->name, target->ts, modes);
282     }
283    
284     /* ping wrapper */
285     static void
286     ultimate3_ping_sts (void)
287     {
288     if (!me.connected)
289     return;
290    
291     sts ("PING :%s", me.name);
292     }
293    
294     /* protocol-specific stuff to do on login */
295     static void
296     ultimate3_on_login (char *origin, char *user, char *wantedhost)
297     {
298     user_t *u = user_find (origin);
299    
300     if (!me.connected || u == NULL)
301     return;
302    
303     /* Can only do this for nickserv, and can only record identified
304     * state if logged in to correct nick, sorry -- jilles
305     */
306     if (should_reg_umode (u))
307     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, origin, time (NULL));
308     }
309    
310     /* protocol-specific stuff to do on login */
311     static bool
312     ultimate3_on_logout (char *origin, char *user, char *wantedhost)
313     {
314     if (!me.connected)
315     return false;
316    
317     if (!nicksvs.no_nick_ownership)
318     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, origin, time (NULL));
319    
320     return false;
321     }
322    
323     static void
324     ultimate3_jupe (const char *server, const char *reason)
325     {
326     server_t *s;
327    
328     if (!me.connected)
329     return;
330    
331     sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
332     s = server_find (server);
333     /* If the server is not directly connected to our uplink, we
334     * need to wait for its uplink to process the SQUIT :(
335     * -- jilles */
336     if (s != NULL && s->uplink != NULL && s->uplink->uplink != me.me)
337     s->flags |= SF_JUPE_PENDING;
338     else
339     sts (":%s SERVER %s 2 :%s", me.name, server, reason);
340     }
341    
342     static void
343     ultimate3_sethost_sts (char *source, char *target, char *host)
344     {
345     if (!me.connected)
346     return;
347    
348     notice (source, target, "Setting your host to \2%s\2.", host);
349     sts (":%s SVSMODE %s +x", source, target);
350     sts (":%s SETHOST %s :%s", me.name, target, host);
351     }
352    
353     static void
354     m_topic (sourceinfo_t *si, int parc, char *parv[])
355     {
356     channel_t *c = channel_find (parv[0]);
357    
358     if (!c)
359     return;
360    
361     /* Our uplink is trying to change the topic during burst,
362     * and we have already set a topic. Assume our change won.
363     * -- jilles */
364     if (si->s != NULL && si->s->uplink == me.me && !(si->s->flags & SF_EOB) && c->topic != NULL)
365     return;
366    
367     handle_topic_from (si, c, parv[1], atol (parv[2]), parv[3]);
368     }
369    
370     static void
371     m_ping (sourceinfo_t *si, int parc, char *parv[])
372     {
373     /* reply to PING's */
374     sts (":%s PONG %s %s", me.name, me.name, parv[0]);
375     }
376    
377     static void
378     m_pong (sourceinfo_t *si, int parc, char *parv[])
379     {
380     server_t *s;
381    
382     /* someone replied to our PING */
383     if (!parv[0])
384     return;
385     s = server_find (parv[0]);
386     if (s == NULL)
387     return;
388     handle_eob (s);
389    
390     if (irccasecmp (me.actual, parv[0]))
391     return;
392    
393     me.uplinkpong = NOW;
394    
395     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
396     if (me.bursting)
397     {
398     #ifdef HAVE_GETTIMEOFDAY
399     e_time (burstime, &burstime);
400    
401     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
402    
403     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
404     #else
405     slog (LG_INFO, "m_pong(): finished synching with uplink");
406     wallops ("Finished synching to network.");
407     #endif
408    
409     me.bursting = false;
410     }
411     }
412    
413     static void
414     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
415     {
416     if (parc != 2)
417     return;
418    
419     handle_message (si, parv[0], false, parv[1]);
420     }
421    
422     static void
423     m_notice (sourceinfo_t *si, int parc, char *parv[])
424     {
425     if (parc != 2)
426     return;
427    
428     handle_message (si, parv[0], true, parv[1]);
429     }
430    
431     static void
432     m_sjoin (sourceinfo_t *si, int parc, char *parv[])
433     {
434     /*
435     * -> :proteus.malkier.net SJOIN 1073516550 #shrike +tn :@sycobuny @+rakaur
436     * also:
437     * -> :nenolod_ SJOIN 1117334567 #chat
438     */
439    
440     channel_t *c;
441     unsigned int userc;
442     char *userv[256];
443     unsigned int i;
444     time_t ts;
445    
446     if (parc >= 4 && si->s != NULL)
447     {
448     /* :origin SJOIN ts chan modestr [key or limits] :users */
449     c = channel_find (parv[1]);
450     ts = atol (parv[0]);
451    
452     if (!c)
453     {
454     slog (LG_DEBUG, "m_sjoin(): new channel: %s", parv[1]);
455     c = channel_add (parv[1], ts, si->s);
456     }
457    
458     if (ts < c->ts)
459     {
460     chanuser_t *cu;
461     node_t *n;
462    
463     /*
464     * the TS changed. a TS change requires the following things
465     * to be done to the channel: reset all modes to nothing, remove
466     * all status modes on known users on the channel (including ours),
467     * and set the new TS.
468     */
469    
470     clear_simple_modes (c);
471    
472     LIST_FOREACH (n, c->members.head)
473     {
474     cu = (chanuser_t *) n->data;
475     if (cu->user->server == me.me)
476     {
477     /* it's a service, reop */
478     sts (":%s PART %s :Reop", cu->user->nick, c->name);
479     sts (":%s SJOIN %ld %s + :@%s", me.name, ts, c->name, cu->user->nick);
480     cu->modes = CMODE_OP;
481     }
482     else
483     cu->modes = 0;
484     }
485    
486     slog (LG_DEBUG, "m_sjoin(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
487    
488     c->ts = ts;
489     hook_call_event ("channel_tschange", c);
490     }
491    
492     channel_mode (NULL, c, parc - 3, parv + 2);
493    
494     userc = sjtoken (parv[parc - 1], ' ', userv);
495    
496     for (i = 0; i < userc; i++)
497     chanuser_add (c, userv[i]);
498    
499     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
500     channel_delete (c);
501     }
502     else if (parc >= 2 && si->su != NULL)
503     {
504     c = channel_find (parv[1]);
505     ts = atol (parv[0]);
506    
507     if (c == NULL || ts < c->ts)
508     {
509     /* just request a resynch, this will include
510     * the user joining -- jilles */
511     slog (LG_DEBUG, "m_sjoin(): requesting resynch for %s", parv[1]);
512     sts ("RESYNCH %s", parv[1]);
513     return;
514     }
515    
516     chanuser_add (c, CLIENT_NAME (si->su));
517     }
518     else
519     {
520     slog (LG_DEBUG, "m_sjoin(): invalid source/parameters: origin %s parc %d", si->su != NULL ? si->su->nick : (si->s != NULL ? si->s->name : "<none>"), parc);
521     }
522     }
523    
524     static void
525     m_part (sourceinfo_t *si, int parc, char *parv[])
526     {
527     int chanc;
528     char *chanv[256];
529     int i;
530    
531     chanc = sjtoken (parv[0], ',', chanv);
532     for (i = 0; i < chanc; i++)
533     {
534     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
535    
536     chanuser_delete (channel_find (chanv[i]), si->su);
537     }
538     }
539    
540     static void
541     m_nick (sourceinfo_t *si, int parc, char *parv[])
542     {
543     server_t *s;
544     user_t *u;
545     char *ipbuf;
546     struct in_addr addr;
547     bool realchange;
548    
549     if (parc == 12)
550     {
551     s = server_find (parv[8]);
552     if (!s)
553     {
554     slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
555     return;
556     }
557    
558     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
559    
560     addr.s_addr = htonl (strtoul (parv[10], NULL, 0));
561     ipbuf = inet_ntoa (addr);
562     u = user_add (parv[0], parv[5], parv[6], parv[7], ipbuf, NULL, parv[11], s, atoi (parv[2]));
563    
564     /* user modes */
565     user_mode (u, parv[3]);
566     /* Oper Mode */
567     user_mode (u, parv[4]);
568    
569     /*
570     * Ok, we have the user ready to go.
571     * Here's the deal -- if the user's SVID is before
572     * the start time, and not 0, then check to see
573     * if it's a registered account or not.
574     *
575     * If it IS registered, deal with that accordingly,
576     * via handle_burstlogin(). --nenolod
577     */
578     /* Changed to just check umode +r for now -- jilles */
579     #if 0
580     /* We can't be sure if this is safe, so disable it for now.
581     * (If ircd unsets +r on nick changes, it is safe.)
582     * If you know this is safe or want to port over the
583     * svsid stuff from unreal.c, you're welcome -- jilles */
584     if (strchr (parv[3], 'r'))
585     handle_burstlogin (u, NULL);
586     #endif
587    
588     handle_nickchange (u);
589     }
590    
591     /* if it's only 2 then it's a nickname change */
592     else if (parc == 2)
593     {
594     if (!si->su)
595     {
596     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
597     return;
598     }
599    
600     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
601    
602     realchange = irccasecmp (si->su->nick, parv[0]);
603    
604     user_changenick (si->su, parv[0], atoi (parv[1]));
605    
606     /* fix up +r if necessary -- jilles */
607     if (realchange && should_reg_umode (si->su))
608     /* changed nick to registered one, reset +r */
609     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, parv[0], time (NULL));
610    
611     handle_nickchange (si->su);
612     }
613     else
614     {
615     int i;
616    
617     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
618    
619     for (i = 0; i < parc; i++)
620     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
621     }
622     }
623    
624     static void
625     m_quit (sourceinfo_t *si, int parc, char *parv[])
626     {
627     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
628    
629     /* user_delete() takes care of removing channels and so forth */
630     user_delete (si->su);
631     }
632    
633     static void
634     m_mode (sourceinfo_t *si, int parc, char *parv[])
635     {
636     if (*parv[0] == '#')
637     channel_mode (NULL, channel_find (parv[0]), parc - 2, &parv[2]);
638     else
639     user_mode (user_find (parv[0]), parv[1]);
640     }
641    
642     static void
643     m_kick (sourceinfo_t *si, int parc, char *parv[])
644     {
645     user_t *u = user_find (parv[1]);
646     channel_t *c = channel_find (parv[0]);
647    
648     /* -> :rakaur KICK #shrike rintaun :test */
649     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
650    
651     if (!u)
652     {
653     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
654     return;
655     }
656    
657     if (!c)
658     {
659     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
660     return;
661     }
662    
663     if (!chanuser_find (c, u))
664     {
665     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
666     return;
667     }
668    
669     chanuser_delete (c, u);
670    
671     /* if they kicked us, let's rejoin */
672     if (is_internal_client (u))
673     {
674     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
675     join (parv[0], u->nick);
676     }
677     }
678    
679     static void
680     m_chghost (sourceinfo_t *si, int parc, char *parv[])
681     {
682     user_t *u = user_find (parv[0]);
683    
684     if (!u)
685     return;
686    
687     strlcpy (u->vhost, parv[1], HOSTLEN);
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     server_delete (parv[0]);
701     }
702    
703     static void
704     m_server (sourceinfo_t *si, int parc, char *parv[])
705     {
706     server_t *s;
707    
708     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
709     s = handle_server (si, parv[0], NULL, atoi (parv[1]), parv[2]);
710    
711     if (s != NULL && s->uplink != me.me)
712     {
713     /* elicit PONG for EOB detection; pinging uplink is
714     * already done elsewhere -- jilles
715     */
716     sts (":%s PING %s %s", me.name, me.name, s->name);
717     }
718     }
719    
720     static void
721     m_stats (sourceinfo_t *si, int parc, char *parv[])
722     {
723     handle_stats (si->su, parv[0][0]);
724     }
725    
726     static void
727     m_admin (sourceinfo_t *si, int parc, char *parv[])
728     {
729     handle_admin (si->su);
730     }
731    
732     static void
733     m_version (sourceinfo_t *si, int parc, char *parv[])
734     {
735     handle_version (si->su);
736     }
737    
738     static void
739     m_info (sourceinfo_t *si, int parc, char *parv[])
740     {
741     handle_info (si->su);
742     }
743    
744     static void
745     m_whois (sourceinfo_t *si, int parc, char *parv[])
746     {
747     handle_whois (si->su, parv[1]);
748     }
749    
750     static void
751     m_trace (sourceinfo_t *si, int parc, char *parv[])
752     {
753     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
754     }
755    
756     static void
757     m_away (sourceinfo_t *si, int parc, char *parv[])
758     {
759     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
760     }
761    
762     static void
763     m_join (sourceinfo_t *si, int parc, char *parv[])
764     {
765     chanuser_t *cu;
766     node_t *n, *tn;
767    
768     /* JOIN 0 is really a part from all channels */
769     if (parv[0][0] == '0')
770     {
771     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
772     {
773     cu = (chanuser_t *) n->data;
774     chanuser_delete (cu->chan, si->su);
775     }
776     }
777     }
778    
779     static void
780     m_pass (sourceinfo_t *si, int parc, char *parv[])
781     {
782     if (strcmp (curr_uplink->pass, parv[0]))
783     {
784     slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
785     runflags |= RF_SHUTDOWN;
786     }
787     }
788    
789     static void
790     m_error (sourceinfo_t *si, int parc, char *parv[])
791     {
792     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
793     }
794    
795     static void
796     nick_group (hook_user_req_t * hdata)
797     {
798     user_t *u;
799    
800     u = hdata->si->su != NULL && !irccasecmp (hdata->si->su->nick, hdata->mn->nick) ? hdata->si->su : user_find_named (hdata->mn->nick);
801     if (u != NULL && should_reg_umode (u))
802     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, u->nick, time (NULL));
803     }
804    
805     static void
806     nick_ungroup (hook_user_req_t * hdata)
807     {
808     user_t *u;
809    
810     u = hdata->si->su != NULL && !irccasecmp (hdata->si->su->nick, hdata->mn->nick) ? hdata->si->su : user_find_named (hdata->mn->nick);
811     if (u != NULL && !nicksvs.no_nick_ownership)
812     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, u->nick, time (NULL));
813     }
814    
815     void
816     _modinit (module_t *m)
817     {
818     /* Symbol relocation voodoo. */
819     server_login = &ultimate3_server_login;
820     introduce_nick = &ultimate3_introduce_nick;
821     quit_sts = &ultimate3_quit_sts;
822     wallops_sts = &ultimate3_wallops_sts;
823     join_sts = &ultimate3_join_sts;
824     kick = &ultimate3_kick;
825     msg = &ultimate3_msg;
826     notice_user_sts = &ultimate3_notice_user_sts;
827     notice_global_sts = &ultimate3_notice_global_sts;
828     notice_channel_sts = &ultimate3_notice_channel_sts;
829     numeric_sts = &ultimate3_numeric_sts;
830     skill = &ultimate3_skill;
831     part_sts = &ultimate3_part_sts;
832     kline_sts = &ultimate3_kline_sts;
833     unkline_sts = &ultimate3_unkline_sts;
834     topic_sts = &ultimate3_topic_sts;
835     mode_sts = &ultimate3_mode_sts;
836     ping_sts = &ultimate3_ping_sts;
837     ircd_on_login = &ultimate3_on_login;
838     ircd_on_logout = &ultimate3_on_logout;
839     jupe = &ultimate3_jupe;
840     sethost_sts = &ultimate3_sethost_sts;
841     invite_sts = &ultimate3_invite_sts;
842    
843     mode_list = ultimate3_mode_list;
844     ignore_mode_list = ultimate3_ignore_mode_list;
845     status_mode_list = ultimate3_status_mode_list;
846     prefix_mode_list = ultimate3_prefix_mode_list;
847    
848     ircd = &ultimate3;
849    
850     pcommand_add ("PING", m_ping, 1, MSRC_USER | MSRC_SERVER);
851     pcommand_add ("PONG", m_pong, 1, MSRC_SERVER);
852     pcommand_add ("PRIVMSG", m_privmsg, 2, MSRC_USER);
853     pcommand_add ("NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER);
854     pcommand_add ("SJOIN", m_sjoin, 2, MSRC_USER | MSRC_SERVER);
855     pcommand_add ("PART", m_part, 1, MSRC_USER);
856     pcommand_add ("NICK", m_nick, 2, MSRC_USER | MSRC_SERVER);
857     pcommand_add ("CLIENT", m_nick, 2, MSRC_USER | MSRC_SERVER);
858     pcommand_add ("QUIT", m_quit, 1, MSRC_USER);
859     pcommand_add ("MODE", m_mode, 2, MSRC_USER | MSRC_SERVER);
860     pcommand_add ("KICK", m_kick, 2, MSRC_USER | MSRC_SERVER);
861     pcommand_add ("KILL", m_kill, 1, MSRC_USER | MSRC_SERVER);
862     pcommand_add ("SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER);
863     pcommand_add ("SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER);
864     pcommand_add ("STATS", m_stats, 2, MSRC_USER);
865     pcommand_add ("ADMIN", m_admin, 1, MSRC_USER);
866     pcommand_add ("VERSION", m_version, 1, MSRC_USER);
867     pcommand_add ("INFO", m_info, 1, MSRC_USER);
868     pcommand_add ("WHOIS", m_whois, 2, MSRC_USER);
869     pcommand_add ("TRACE", m_trace, 1, MSRC_USER);
870     pcommand_add ("AWAY", m_away, 0, MSRC_USER);
871     pcommand_add ("JOIN", m_join, 1, MSRC_USER);
872     pcommand_add ("PASS", m_pass, 1, MSRC_UNREG);
873     pcommand_add ("ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER);
874     pcommand_add ("TOPIC", m_topic, 4, MSRC_USER | MSRC_SERVER);
875     pcommand_add ("CHGHOST", m_chghost, 2, MSRC_USER | MSRC_SERVER);
876    
877     hook_add_event ("nick_group");
878     hook_add_hook ("nick_group", (void (*)(void *)) nick_group);
879     hook_add_event ("nick_ungroup");
880     hook_add_hook ("nick_ungroup", (void (*)(void *)) nick_ungroup);
881    
882     m->mflags = MODTYPE_CORE;
883    
884     pmodule_loaded = true;
885     }
886    
887     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
888     * vim:ts=8
889     * vim:sw=8
890     * vim:noexpandtab
891     */