ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/solidircd.C
Revision: 1.3
Committed: Sat Jul 21 13:23:21 2007 UTC (19 years, 2 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 © 2005-2006 Atheme Development Group
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 solidircd.
6     *
7 pippijn 1.3 * $Id: solidircd.C,v 1.2 2007-07-21 01:29:10 pippijn Exp $
8 pippijn 1.1 */
9    
10     #include "atheme.h"
11     #include <account/mynick.h>
12     #include <account/myuser.h>
13     #include "uplink.h"
14     #include "pmodule.h"
15     #include "protocol/solidircd.h"
16    
17 pippijn 1.3 static char const rcsid[] = "$Id$";
18 pippijn 1.1
19     struct solidircd_listeners : callback::has_listeners
20     {
21     };
22    
23     solidircd_listeners listeners;
24    
25     DECLARE_MODULE_V1 ("protocol/solidircd", true, _modinit, NULL, rcsid, "The Ermyth Team <http://ermyth.schmorp.de>");
26    
27     /* *INDENT-OFF* */
28    
29     ircd_t Solidircd = {
30     "solid-ircd 3.4.x", /* 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     false, /* Whether or not we support channel protection. */
36     true, /* Whether or not we support halfops. */
37     false, /* Whether or not we use P10 */
38     false, /* Whether or not we use vHosts. */
39     CMODE_OPERONLY, /* Oper-only cmodes */
40     0, /* Integer flag for owner channel flag. */
41     0, /* Integer flag for protect channel flag. */
42     CMODE_HALFOP, /* Integer flag for halfops. */
43     "+", /* Mode we set for owner. */
44     "+", /* Mode we set for protect. */
45     "+h", /* Mode we set for halfops. */
46     PROTOCOL_SOLIDIRCD, /* Protocol type */
47     0, /* Permanent cmodes */
48     "beI", /* Ban-like cmodes */
49     'e', /* Except mchar */
50     'I', /* Invex mchar */
51     0 /* Flags */
52     };
53    
54     cmode_t solidircd_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_NOCTRL },
62     { 'M', CMODE_MODREG },
63     { 'R', CMODE_REGONLY },
64     { 'O', CMODE_OPERONLY },
65     { 'S', CMODE_SSL }, /* SSL users only */
66     { 'N', CMODE_NONICK }, /* No Nick Changes */
67     { 'D', CMODE_RSL }, /* Only Resolved Clients */
68     { '\0', 0 }
69     };
70    
71     static bool check_jointhrottle(const char *, channel_t *, mychan_t *, user_t *, myuser_t *);
72    
73     extmode solidircd_ignore_mode_list[] = {
74     { 'j', check_jointhrottle },
75     { '\0', 0 }
76     };
77    
78     cmode_t solidircd_status_mode_list[] = {
79     { 'o', CMODE_OP },
80     { 'h', CMODE_HALFOP },
81     { 'v', CMODE_VOICE },
82     { '\0', 0 }
83     };
84    
85     cmode_t solidircd_prefix_mode_list[] = {
86     { '@', CMODE_OP },
87     { '%', CMODE_HALFOP },
88     { '+', CMODE_VOICE },
89     { '\0', 0 }
90     };
91    
92     /* *INDENT-ON* */
93    
94     static bool
95     check_jointhrottle (const char *value, channel_t *c, mychan_t *mc, user_t *u, myuser_t *mu)
96     {
97     const char *p, *arg2;
98     int num, timeslice, v;
99    
100     if (!strcmp (value, "0") && u == NULL && mu == NULL)
101     return true;
102     p = value, arg2 = NULL;
103     while (*p != '\0')
104     {
105     if (*p == ':')
106     {
107     if (arg2 != NULL)
108     return false;
109     arg2 = p + 1;
110     }
111     else if (!isdigit (*p))
112     return false;
113     p++;
114     }
115     if (arg2 == NULL)
116     return false;
117     if (p - arg2 > 3 || arg2 - value - 1 > 3)
118     return false;
119     num = atoi (value);
120     timeslice = atoi (arg2);
121     if (num <= 0 || num > 127 || timeslice <= 0 || timeslice > 127)
122     return false;
123     if (u != NULL || mu != NULL)
124     {
125     /* the following are the same restrictions bahamut
126     * applies to local clients
127     */
128     if (num < 2 || num > 20 || timeslice > 60)
129     return false;
130     v = (timeslice - 1) / 8 + 1;
131     if (num < v)
132     return false;
133     v = num / 2;
134     if (timeslice < v)
135     return false;
136     }
137     return true;
138     }
139    
140     /* login to our uplink */
141     static unsigned int
142     solidircd_server_login (void)
143     {
144     int ret;
145    
146     ret = sts ("PASS %s :TS", curr_uplink->pass);
147     if (ret == 1)
148     return 1;
149    
150     me.bursting = true;
151    
152     sts ("CAPAB SSJOIN NOQUIT BURST ZIP NICKIP TSMODE");
153     sts ("SERVER %s 1 :%s", me.name, me.desc);
154     sts ("SVINFO 5 3 0 :%ld", NOW);
155    
156     services_init ();
157    
158     return 0;
159     }
160    
161     /* introduce a client */
162     static void
163     solidircd_introduce_nick (user_t *u)
164     {
165     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);
166     }
167    
168     /* invite a user to a channel */
169     static void
170     solidircd_invite_sts (user_t *sender, user_t *target, channel_t *channel)
171     {
172     sts (":%s INVITE %s %s", sender->nick, target->nick, channel->name);
173     }
174    
175     static void
176     solidircd_quit_sts (user_t *u, const char *reason)
177     {
178     if (!me.connected)
179     return;
180    
181     sts (":%s QUIT :%s", u->nick, reason);
182     }
183    
184     /* WALLOPS wrapper */
185     static void
186     solidircd_wallops_sts (const char *text)
187     {
188     sts (":%s GLOBOPS :%s", me.name, text);
189     }
190    
191     /* join a channel */
192     static void
193     solidircd_join_sts (channel_t *c, user_t *u, bool isnew, char *modes)
194     {
195     if (isnew)
196     sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, modes, u->nick);
197     else
198     sts (":%s SJOIN %ld %s + :@%s", me.name, c->ts, c->name, u->nick);
199     }
200    
201     static void
202     solidircd_chan_lowerts (channel_t *c, user_t *u)
203     {
204     slog (LG_DEBUG, "solidircd_chan_lowerts(): lowering TS for %s to %ld", c->name, (long) c->ts);
205     sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, channel_modes (c, true), u->nick);
206     chanban_clear (c);
207     /*handle_topic(c, "", 0, ""); */
208     /* Don't destroy keeptopic info, I'll admit this is ugly -- jilles */
209     if (c->topic != NULL)
210     free (c->topic);
211     if (c->topic_setter != NULL)
212     free (c->topic_setter);
213     c->topic = c->topic_setter = NULL;
214     c->topicts = 0;
215     }
216    
217     /* kicks a user from a channel */
218     static void
219     solidircd_kick (char *from, char *channel, char *to, char *reason)
220     {
221     channel_t *chan = channel_find (channel);
222     user_t *user = user_find (to);
223    
224     if (!chan || !user)
225     return;
226    
227     sts (":%s KICK %s %s :%s", from, channel, to, reason);
228    
229     chanuser_delete (chan, user);
230     }
231    
232     /* PRIVMSG wrapper */
233     static void
234     solidircd_msg (const char *from, const char *target, const char *fmt, ...)
235     {
236     va_list ap;
237     char buf[BUFSIZE];
238    
239     va_start (ap, fmt);
240     vsnprintf (buf, BUFSIZE, fmt, ap);
241     va_end (ap);
242    
243     sts (":%s PRIVMSG %s :%s", from, target, buf);
244     }
245    
246     /* NOTICE wrapper */
247     static void
248     solidircd_notice_user_sts (user_t *from, user_t *target, const char *text)
249     {
250     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->nick, text);
251     }
252    
253     static void
254     solidircd_notice_global_sts (user_t *from, const char *mask, const char *text)
255     {
256     node_t *n;
257     tld_t *tld;
258    
259     if (!strcmp (mask, "*"))
260     {
261     LIST_FOREACH (n, tldlist.head)
262     {
263     tld = static_cast<tld_t *> (n->data);
264     sts (":%s NOTICE %s*%s :%s", from ? from->nick : me.name, ircd->tldprefix, tld->name, text);
265     }
266     }
267     else
268     sts (":%s NOTICE %s%s :%s", from ? from->nick : me.name, ircd->tldprefix, mask, text);
269     }
270    
271     static void
272     solidircd_notice_channel_sts (user_t *from, channel_t *target, const char *text)
273     {
274     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->name, text);
275     }
276    
277     static void
278     solidircd_wallchops (user_t *sender, channel_t *channel, const char *message)
279     {
280     sts (":%s NOTICE @%s :%s", sender->nick, channel->name, message);
281     }
282    
283     static void
284     solidircd_numeric_sts (char *from, int numeric, char *target, char *fmt, ...)
285     {
286     va_list ap;
287     char buf[BUFSIZE];
288    
289     va_start (ap, fmt);
290     vsnprintf (buf, BUFSIZE, fmt, ap);
291     va_end (ap);
292    
293     sts (":%s %d %s %s", from, numeric, target, buf);
294     }
295    
296     /* KILL wrapper */
297     static void
298     solidircd_skill (char *from, char *nick, char *fmt, ...)
299     {
300     va_list ap;
301     char buf[BUFSIZE];
302    
303     va_start (ap, fmt);
304     vsnprintf (buf, BUFSIZE, fmt, ap);
305     va_end (ap);
306    
307     sts (":%s KILL %s :%s!%s!%s (%s)", from, nick, from, from, from, buf);
308     }
309    
310     /* PART wrapper */
311     static void
312     solidircd_part_sts (channel_t *c, user_t *u)
313     {
314     sts (":%s PART %s", u->nick, c->name);
315     }
316    
317     /* server-to-server KLINE wrapper */
318     static void
319     solidircd_kline_sts (char *server, char *user, char *host, long duration, char *reason)
320     {
321     if (!me.connected)
322     return;
323    
324     sts (":%s AKILL %s %s %ld %s %ld :%s", me.name, host, user, duration, opersvs.nick, time (NULL), reason);
325     }
326    
327     /* server-to-server UNKLINE wrapper */
328     static void
329     solidircd_unkline_sts (char *server, char *user, char *host)
330     {
331     if (!me.connected)
332     return;
333    
334     sts (":%s RAKILL %s %s", me.name, host, user);
335     }
336    
337     /* topic wrapper */
338     static void
339     solidircd_topic_sts (channel_t *c, const char *setter, time_t ts, time_t prevts, const char *topic)
340     {
341     if (!me.connected || !c)
342     return;
343    
344     sts (":%s TOPIC %s %s %ld :%s", chansvs.nick, c->name, setter, ts, topic);
345     }
346    
347     /* mode wrapper */
348     static void
349     solidircd_mode_sts (char *sender, channel_t *target, char *modes)
350     {
351     if (!me.connected)
352     return;
353    
354     sts (":%s MODE %s %ld %s", sender, target->name, target->ts, modes);
355     }
356    
357     /* ping wrapper */
358     static void
359     solidircd_ping_sts (void)
360     {
361     if (!me.connected)
362     return;
363    
364     sts ("PING :%s", me.name);
365     }
366    
367     /* protocol-specific stuff to do on login */
368     static void
369     solidircd_on_login (char *origin, char *user, char *wantedhost)
370     {
371     user_t *u = user_find (origin);
372    
373     if (!me.connected || u == NULL)
374     return;
375    
376     /* Can only do this for nickserv, and can only record identified
377     * state if logged in to correct nick, sorry -- jilles
378     */
379     if (should_reg_umode (u))
380     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, origin, time (NULL));
381     }
382    
383     /* protocol-specific stuff to do on login */
384     static bool
385     solidircd_on_logout (char *origin, char *user, char *wantedhost)
386     {
387     if (!me.connected)
388     return false;
389    
390     if (!nicksvs.no_nick_ownership)
391     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, origin, time (NULL));
392     return false;
393     }
394    
395     static void
396     solidircd_jupe (const char *server, const char *reason)
397     {
398     server_t *s;
399    
400     if (!me.connected)
401     return;
402    
403     sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
404     s = server_find (server);
405     /* If the server is not directly connected to our uplink, we
406     * need to wait for its uplink to process the SQUIT :(
407     * -- jilles */
408     if (s != NULL && s->uplink != NULL && s->uplink->uplink != me.me)
409     s->flags |= SF_JUPE_PENDING;
410     else
411     sts (":%s SERVER %s 2 :%s", me.name, server, reason);
412     }
413    
414    
415     static void
416     solidircd_sethost_sts (char *source, char *target, char *host)
417     {
418     if (!me.connected)
419     return;
420    
421     notice (source, target, "Setting your host to \2%s\2.", host);
422     sts (":%s SVSMODE %s +v", source, target);
423     sts (":%s SVHOST %s :%s", me.name, target, host);
424     }
425    
426     static void
427     solidircd_fnc_sts (user_t *source, user_t *u, char *newnick, int type)
428     {
429     sts (":%s SVSNICK %s %s %lu", source->nick, u->nick, newnick, (unsigned long) (NOW - 60));
430     }
431    
432     static void
433     solidircd_holdnick_sts (user_t *source, int duration, const char *nick, myuser_t *account)
434     {
435     sts (":%s SVSHOLD %s %d :Reserved by %s for nickname owner (%s)", source->nick, nick, duration, source->nick, account != NULL ? account->name : nick);
436     }
437    
438     static void
439     m_topic (sourceinfo_t *si, int parc, char *parv[])
440     {
441     channel_t *c = channel_find (parv[0]);
442    
443     if (!c)
444     return;
445    
446     /* Our uplink is trying to change the topic during burst,
447     * and we have already set a topic. Assume our change won.
448     * -- jilles */
449     if (si->s != NULL && si->s->uplink == me.me && !(si->s->flags & SF_EOB) && c->topic != NULL)
450     return;
451    
452     handle_topic_from (si, c, parv[1], atol (parv[2]), parv[3]);
453     }
454    
455     static void
456     m_ping (sourceinfo_t *si, int parc, char *parv[])
457     {
458     /* reply to PING's */
459     sts (":%s PONG %s %s", me.name, me.name, parv[0]);
460     }
461    
462     static void
463     m_pong (sourceinfo_t *si, int parc, char *parv[])
464     {
465     server_t *s;
466    
467     /* someone replied to our PING */
468     if (!parv[0])
469     return;
470     s = server_find (parv[0]);
471     if (s == NULL)
472     return;
473     /* Postpone EOB for our uplink until topic burst is also done */
474     if (s->uplink != me.me)
475     handle_eob (s);
476    
477     if (irccasecmp (me.actual, parv[0]))
478     return;
479    
480     me.uplinkpong = NOW;
481    
482     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
483     }
484    
485     static void
486     m_burst (sourceinfo_t *si, int parc, char *parv[])
487     {
488     server_t *s;
489    
490     /* Ignore "BURST" at start of burst */
491     if (parc != 1)
492     return;
493    
494     s = server_find (me.actual);
495     if (s != NULL)
496     handle_eob (s);
497    
498     if (me.bursting)
499     {
500     #ifdef HAVE_GETTIMEOFDAY
501     e_time (burstime, &burstime);
502    
503     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
504    
505     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
506     #else
507     slog (LG_INFO, "m_pong(): finished synching with uplink");
508     wallops ("Finished synching to network.");
509     #endif
510    
511     me.bursting = false;
512     }
513     }
514    
515     static void
516     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
517     {
518     if (parc != 2)
519     return;
520    
521     handle_message (si, parv[0], false, parv[1]);
522     }
523    
524     static void
525     m_notice (sourceinfo_t *si, int parc, char *parv[])
526     {
527     if (parc != 2)
528     return;
529    
530     handle_message (si, parv[0], true, parv[1]);
531     }
532    
533     static void
534     m_sjoin (sourceinfo_t *si, int parc, char *parv[])
535     {
536     /*
537     * -> :proteus.malkier.net SJOIN 1073516550 #shrike +tn :@sycobuny @+rakaur
538     * also:
539     * -> :nenolod_ SJOIN 1117334567 #chat
540     */
541    
542     channel_t *c;
543     bool keep_new_modes = true;
544     unsigned int userc;
545     char *userv[256];
546     unsigned int i;
547     time_t ts;
548     char *p;
549    
550     if (parc >= 4 && si->s != NULL)
551     {
552     /* :origin SJOIN ts chan modestr [key or limits] :users */
553     c = channel_find (parv[1]);
554     ts = atol (parv[0]);
555    
556     if (!c)
557     {
558     slog (LG_DEBUG, "m_sjoin(): new channel: %s", parv[1]);
559     c = channel_add (parv[1], ts, si->s);
560     }
561    
562     if (ts == 0 || c->ts == 0)
563     {
564     if (c->ts != 0)
565     slog (LG_INFO, "m_sjoin(): server %s changing TS on %s from %ld to 0", si->s->name, c->name, (long) c->ts);
566     c->ts = 0;
567     hook_call_event ("channel_tschange", c);
568     }
569     else if (ts < c->ts)
570     {
571     chanuser_t *cu;
572     node_t *n;
573    
574     /* the TS changed. a TS change requires the following things
575     * to be done to the channel: reset all modes to nothing, remove
576     * all status modes on known users on the channel (including ours),
577     * and set the new TS.
578     * also clear all bans and the topic
579     */
580    
581     clear_simple_modes (c);
582     chanban_clear (c);
583     handle_topic_from (si, c, "", 0, "");
584    
585     LIST_FOREACH (n, c->members.head)
586     {
587     cu = (chanuser_t *) n->data;
588     if (cu->user->server == me.me)
589     {
590     /* it's a service, reop */
591     sts (":%s PART %s :Reop", cu->user->nick, c->name);
592     sts (":%s SJOIN %ld %s + :@%s", me.name, ts, c->name, cu->user->nick);
593     cu->modes = CMODE_OP;
594     }
595     else
596     cu->modes = 0;
597     }
598    
599     slog (LG_DEBUG, "m_sjoin(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
600    
601     c->ts = ts;
602     hook_call_event ("channel_tschange", c);
603     }
604     else if (ts > c->ts)
605     keep_new_modes = false;
606    
607     if (keep_new_modes)
608     channel_mode (NULL, c, parc - 3, parv + 2);
609    
610     userc = sjtoken (parv[parc - 1], ' ', userv);
611    
612     if (keep_new_modes)
613     for (i = 0; i < userc; i++)
614     chanuser_add (c, userv[i]);
615     else
616     for (i = 0; i < userc; i++)
617     {
618     p = userv[i];
619     while (*p == '@' || *p == '%' || *p == '+')
620     p++;
621     chanuser_add (c, p);
622     }
623    
624     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
625     channel_delete (c);
626     }
627     else if (parc >= 2 && si->su != NULL)
628     {
629     c = channel_find (parv[1]);
630     ts = atol (parv[0]);
631    
632     if (c == NULL || ts < c->ts)
633     {
634     /* just request a resynch, this will include
635     * the user joining -- jilles */
636     slog (LG_DEBUG, "m_sjoin(): requesting resynch for %s", parv[1]);
637     sts ("RESYNCH %s", parv[1]);
638     return;
639     }
640    
641     chanuser_add (c, CLIENT_NAME (si->su));
642     }
643     else
644     {
645     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);
646     }
647     }
648    
649     static void
650     m_part (sourceinfo_t *si, int parc, char *parv[])
651     {
652     int chanc;
653     char *chanv[256];
654     int i;
655    
656     chanc = sjtoken (parv[0], ',', chanv);
657     for (i = 0; i < chanc; i++)
658     {
659     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
660    
661     chanuser_delete (channel_find (chanv[i]), si->su);
662     }
663     }
664    
665     static void
666     m_nick (sourceinfo_t *si, int parc, char *parv[])
667     {
668     server_t *s;
669     user_t *u;
670     struct in_addr ip;
671     char ipstring[64];
672     bool realchange;
673    
674     /* -> NICK jilles 1 1136143909 +oi ~jilles 192.168.1.5 jaguar.test 0 3232235781 :Jilles Tjoelker */
675     if (parc == 10)
676     {
677     s = server_find (parv[6]);
678     if (!s)
679     {
680     slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
681     return;
682     }
683    
684     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
685    
686     ip.s_addr = ntohl (strtoul (parv[8], NULL, 10));
687     ipstring[0] = '\0';
688     if (!inet_ntop (AF_INET, &ip, ipstring, sizeof ipstring))
689     ipstring[0] = '\0';
690     u = user_add (parv[0], parv[4], parv[5], NULL, ipstring, NULL, parv[9], s, atoi (parv[2]));
691    
692     user_mode (u, parv[3]);
693    
694     /* Ok, we have the user ready to go.
695     * Here's the deal -- if the user's SVID is before
696     * the start time, and not 0, then check to see
697     * if it's a registered account or not.
698     *
699     * If it IS registered, deal with that accordingly,
700     * via handle_burstlogin(). --nenolod
701     */
702     /* Changed to just check umode +r for now -- jilles */
703     /* This is ok because this ircd clears +r on nick changes
704     * -- jilles */
705     if (strchr (parv[3], 'r'))
706     handle_burstlogin (u, NULL);
707    
708     handle_nickchange (u);
709     }
710    
711     /* if it's only 2 then it's a nickname change */
712     else if (parc == 2)
713     {
714     if (!si->su)
715     {
716     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
717     return;
718     }
719    
720     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
721    
722     realchange = irccasecmp (si->su->nick, parv[0]);
723    
724     user_changenick (si->su, parv[0], atoi (parv[1]));
725    
726     /* fix up +r if necessary -- jilles */
727     if (realchange && should_reg_umode (si->su))
728     /* changed nick to registered one, reset +r */
729     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, parv[0], time (NULL));
730    
731     handle_nickchange (si->su);
732     }
733     else
734     {
735     int i;
736     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
737    
738     for (i = 0; i < parc; i++)
739     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
740     }
741     }
742    
743     static void
744     m_quit (sourceinfo_t *si, int parc, char *parv[])
745     {
746     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
747    
748     /* user_delete() takes care of removing channels and so forth */
749     user_delete (si->su);
750     }
751    
752     static void
753     m_mode (sourceinfo_t *si, int parc, char *parv[])
754     {
755     channel_t *c;
756    
757     if (*parv[0] == '#')
758     {
759     c = channel_find (parv[0]);
760     if (c == NULL)
761     {
762     slog (LG_DEBUG, "m_mode(): unknown channel %s", parv[0]);
763     return;
764     }
765     if (atol (parv[1]) > c->ts)
766     return;
767     channel_mode (NULL, channel_find (parv[0]), parc - 2, &parv[2]);
768     }
769     else
770     user_mode (user_find (parv[0]), parv[1]);
771     }
772    
773     static void
774     m_kick (sourceinfo_t *si, int parc, char *parv[])
775     {
776     user_t *u = user_find (parv[1]);
777     channel_t *c = channel_find (parv[0]);
778    
779     /* -> :rakaur KICK #shrike rintaun :test */
780     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
781    
782     if (!u)
783     {
784     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
785     return;
786     }
787    
788     if (!c)
789     {
790     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
791     return;
792     }
793    
794     if (!chanuser_find (c, u))
795     {
796     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
797     return;
798     }
799    
800     chanuser_delete (c, u);
801    
802     /* if they kicked us, let's rejoin */
803     if (is_internal_client (u))
804     {
805     slog (LG_DEBUG, "m_kick(): i got kicked from `%s'; rejoining", parv[0]);
806     join (parv[0], u->nick);
807     }
808     }
809    
810     static void
811     m_kill (sourceinfo_t *si, int parc, char *parv[])
812     {
813     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
814     }
815    
816     static void
817     m_squit (sourceinfo_t *si, int parc, char *parv[])
818     {
819     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
820     server_delete (parv[0]);
821     }
822    
823     static void
824     m_server (sourceinfo_t *si, int parc, char *parv[])
825     {
826     server_t *s;
827    
828     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
829     s = handle_server (si, parv[0], NULL, atoi (parv[1]), parv[2]);
830    
831     if (s != NULL && s->uplink != me.me)
832     {
833     /* elicit PONG for EOB detection; pinging uplink is
834     * already done elsewhere -- jilles
835     */
836     sts (":%s PING %s %s", me.name, me.name, s->name);
837     }
838     }
839    
840     static void
841     m_stats (sourceinfo_t *si, int parc, char *parv[])
842     {
843     handle_stats (si->su, parv[0][0]);
844     }
845    
846     static void
847     m_admin (sourceinfo_t *si, int parc, char *parv[])
848     {
849     handle_admin (si->su);
850     }
851    
852     static void
853     m_version (sourceinfo_t *si, int parc, char *parv[])
854     {
855     handle_version (si->su);
856     }
857    
858     static void
859     m_info (sourceinfo_t *si, int parc, char *parv[])
860     {
861     handle_info (si->su);
862     }
863    
864     static void
865     m_whois (sourceinfo_t *si, int parc, char *parv[])
866     {
867     handle_whois (si->su, parv[1]);
868     }
869    
870     static void
871     m_trace (sourceinfo_t *si, int parc, char *parv[])
872     {
873     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
874     }
875    
876     static void
877     m_away (sourceinfo_t *si, int parc, char *parv[])
878     {
879     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
880     }
881    
882     static void
883     m_join (sourceinfo_t *si, int parc, char *parv[])
884     {
885     chanuser_t *cu;
886     node_t *n, *tn;
887    
888     /* JOIN 0 is really a part from all channels */
889     if (parv[0][0] == '0')
890     {
891     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
892     {
893     cu = (chanuser_t *) n->data;
894     chanuser_delete (cu->chan, si->su);
895     }
896     }
897     }
898    
899     static void
900     m_pass (sourceinfo_t *si, int parc, char *parv[])
901     {
902     if (strcmp (curr_uplink->pass, parv[0]))
903     {
904     slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
905     runflags |= RF_SHUTDOWN;
906     }
907     }
908    
909     static void
910     m_error (sourceinfo_t *si, int parc, char *parv[])
911     {
912     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
913     }
914    
915     static void
916     m_motd (sourceinfo_t *si, int parc, char *parv[])
917     {
918     handle_motd (si->su);
919     }
920    
921     static void
922     m_svhost (sourceinfo_t *si, int parc, char *parv[])
923     {
924     user_t *u;
925    
926     u = user_find (parv[0]);
927     if (u == NULL)
928     return;
929     strlcpy (u->vhost, parv[1], HOSTLEN);
930     }
931    
932     static void
933     nick_group (hook_user_req_t * hdata)
934     {
935     user_t *u;
936    
937     u = hdata->si->su != NULL && !irccasecmp (hdata->si->su->nick, hdata->mn->nick) ? hdata->si->su : user_find_named (hdata->mn->nick);
938     if (u != NULL && should_reg_umode (u))
939     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, u->nick, time (NULL));
940     }
941    
942     static void
943     nick_ungroup (hook_user_req_t * hdata)
944     {
945     user_t *u;
946    
947     u = hdata->si->su != NULL && !irccasecmp (hdata->si->su->nick, hdata->mn->nick) ? hdata->si->su : user_find_named (hdata->mn->nick);
948     if (u != NULL && !nicksvs.no_nick_ownership)
949     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, u->nick, time (NULL));
950     }
951    
952     void
953     _modinit (module_t *m)
954     {
955     /* Symbol relocation voodoo. */
956     server_login = &solidircd_server_login;
957     introduce_nick = &solidircd_introduce_nick;
958     quit_sts = &solidircd_quit_sts;
959     wallops_sts = &solidircd_wallops_sts;
960     join_sts = &solidircd_join_sts;
961     chan_lowerts = &solidircd_chan_lowerts;
962     kick = &solidircd_kick;
963     msg = &solidircd_msg;
964     notice_user_sts = &solidircd_notice_user_sts;
965     notice_global_sts = &solidircd_notice_global_sts;
966     notice_channel_sts = &solidircd_notice_channel_sts;
967     wallchops = &solidircd_wallchops;
968     numeric_sts = &solidircd_numeric_sts;
969     skill = &solidircd_skill;
970     part_sts = &solidircd_part_sts;
971     kline_sts = &solidircd_kline_sts;
972     unkline_sts = &solidircd_unkline_sts;
973     topic_sts = &solidircd_topic_sts;
974     mode_sts = &solidircd_mode_sts;
975     ping_sts = &solidircd_ping_sts;
976     ircd_on_login = &solidircd_on_login;
977     ircd_on_logout = &solidircd_on_logout;
978     jupe = &solidircd_jupe;
979     sethost_sts = &solidircd_sethost_sts;
980     fnc_sts = &solidircd_fnc_sts;
981     invite_sts = &solidircd_invite_sts;
982     holdnick_sts = &solidircd_holdnick_sts;
983    
984     mode_list = solidircd_mode_list;
985     ignore_mode_list = solidircd_ignore_mode_list;
986     status_mode_list = solidircd_status_mode_list;
987     prefix_mode_list = solidircd_prefix_mode_list;
988    
989     ircd = &Solidircd;
990    
991     pcommand_add ("PING", m_ping, 1, MSRC_USER | MSRC_SERVER);
992     pcommand_add ("PONG", m_pong, 1, MSRC_SERVER);
993     pcommand_add ("PRIVMSG", m_privmsg, 2, MSRC_USER);
994     pcommand_add ("NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER);
995     pcommand_add ("SJOIN", m_sjoin, 2, MSRC_USER | MSRC_SERVER);
996     pcommand_add ("PART", m_part, 1, MSRC_USER);
997     pcommand_add ("NICK", m_nick, 2, MSRC_USER | MSRC_SERVER);
998     pcommand_add ("QUIT", m_quit, 1, MSRC_USER);
999     pcommand_add ("MODE", m_mode, 2, MSRC_USER | MSRC_SERVER);
1000     pcommand_add ("KICK", m_kick, 2, MSRC_USER | MSRC_SERVER);
1001     pcommand_add ("KILL", m_kill, 1, MSRC_USER | MSRC_SERVER);
1002     pcommand_add ("SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER);
1003     pcommand_add ("SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER);
1004     pcommand_add ("STATS", m_stats, 2, MSRC_USER);
1005     pcommand_add ("ADMIN", m_admin, 1, MSRC_USER);
1006     pcommand_add ("VERSION", m_version, 1, MSRC_USER);
1007     pcommand_add ("INFO", m_info, 1, MSRC_USER);
1008     pcommand_add ("WHOIS", m_whois, 2, MSRC_USER);
1009     pcommand_add ("TRACE", m_trace, 1, MSRC_USER);
1010     pcommand_add ("AWAY", m_away, 0, MSRC_USER);
1011     pcommand_add ("JOIN", m_join, 1, MSRC_USER);
1012     pcommand_add ("PASS", m_pass, 1, MSRC_UNREG);
1013     pcommand_add ("ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER);
1014     pcommand_add ("TOPIC", m_topic, 4, MSRC_USER | MSRC_SERVER);
1015     pcommand_add ("MOTD", m_motd, 1, MSRC_USER);
1016     pcommand_add ("BURST", m_burst, 0, MSRC_SERVER);
1017     pcommand_add ("SVHOST", m_svhost, 2, MSRC_USER | MSRC_SERVER);
1018    
1019     hook_add_event ("nick_group");
1020     hook_add_hook ("nick_group", (void (*)(void *)) nick_group);
1021     hook_add_event ("nick_ungroup");
1022     hook_add_hook ("nick_ungroup", (void (*)(void *)) nick_ungroup);
1023    
1024     m->mflags = MODTYPE_CORE;
1025    
1026     pmodule_loaded = true;
1027     }
1028    
1029     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
1030     * vim:ts=8
1031     * vim:sw=8
1032     * vim:noexpandtab
1033     */