ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/nefarious.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 © 2005-2006 William Pitcock, et al.
3     * Rights to this code are documented in doc/LICENSE.
4     *
5     * This file contains protocol support for P10 ircd's.
6     * Some sources used: Run's documentation, beware's description,
7     * raw data sent by nefarious.
8     *
9     * $Id: nefarious.c 8223 2007-05-05 12:58:06Z jilles $
10     */
11    
12     #include "atheme.h"
13     #include <account/myuser.h>
14     #include "uplink.h"
15     #include "pmodule.h"
16     #include "protocol/nefarious.h"
17    
18     static char const rcsid[] = "$Id";
19    
20     struct nefarious_listeners : callback::has_listeners
21     {
22     };
23    
24     nefarious_listeners listeners;
25    
26     DECLARE_MODULE_V1 ("protocol/nefarious", true, _modinit, NULL, rcsid, "The Ermyth Team <http://ermyth.schmorp.de>");
27    
28     /* *INDENT-OFF* */
29    
30     ircd_t Nefarious = {
31     "Nefarious IRCU 0.4.0 or later", /* IRCd name */
32     "$", /* TLD Prefix, used by Global. */
33     true, /* Whether or not we use IRCNet/TS6 UID */
34     false, /* Whether or not we use RCOMMAND */
35     false, /* Whether or not we support channel owners. */
36     false, /* Whether or not we support channel protection. */
37     true, /* Whether or not we support halfops. */
38     true, /* Whether or not we use P10 */
39     true, /* Whether or not we use vhosts. */
40     CMODE_PERM|CMODE_OPERONLY|CMODE_ADMONLY, /* Oper-only cmodes */
41     0, /* Integer flag for owner channel flag. */
42     0, /* Integer flag for protect channel flag. */
43     CMODE_HALFOP, /* Integer flag for halfops. */
44     "+", /* Mode we set for owner. */
45     "+", /* Mode we set for protect. */
46     "+", /* Mode we set for halfops. */
47     PROTOCOL_NEFARIOUS, /* Protocol type */
48     CMODE_PERM, /* Permanent cmodes */
49     "be", /* Ban-like cmodes */
50     'e', /* Except mchar */
51     'e', /* Invex mchar (+e also exempts from +i in Nefarious) */
52     IRCD_CIDR_BANS /* Flags */
53     };
54    
55     cmode_t nefarious_mode_list[] = {
56     { 'a', CMODE_ADMONLY },
57     { 'i', CMODE_INVITE },
58     { 'm', CMODE_MOD },
59     { 'n', CMODE_NOEXT },
60     { 'p', CMODE_PRIV },
61     { 'r', CMODE_REGONLY },
62     { 's', CMODE_SEC },
63     { 't', CMODE_TOPIC },
64     { 'z', CMODE_PERM },
65     { 'c', CMODE_NOCOLOR },
66     { 'C', CMODE_NOCTCP },
67     { 'D', CMODE_DELAYED },
68     { 'Q', CMODE_NOQUIT },
69     { 'N', CMODE_NONOTICE },
70     { 'M', CMODE_SOFTMOD },
71     { 'C', CMODE_NOCTCP },
72     { 'S', CMODE_STRIP },
73     { 'T', CMODE_NOAMSG },
74     { 'O', CMODE_OPERONLY },
75     { 'L', CMODE_SOFTPRIV },
76     { 'Z', CMODE_SSLONLY },
77     { '\0', 0 }
78     };
79    
80     extmode nefarious_ignore_mode_list[] = {
81     { '\0', 0 }
82     };
83    
84     cmode_t nefarious_status_mode_list[] = {
85     { 'o', CMODE_OP },
86     { 'h', CMODE_HALFOP },
87     { 'v', CMODE_VOICE },
88     { '\0', 0 }
89     };
90    
91     cmode_t nefarious_prefix_mode_list[] = {
92     { '@', CMODE_OP },
93     { '%', CMODE_HALFOP },
94     { '+', CMODE_VOICE },
95     { '\0', 0 }
96     };
97    
98     static void check_hidehost(user_t *u);
99    
100     /* *INDENT-ON* */
101    
102     /* login to our uplink */
103     static unsigned int
104     nefarious_server_login (void)
105     {
106     int ret;
107    
108     ret = sts ("PASS :%s", curr_uplink->pass);
109     if (ret == 1)
110     return 1;
111    
112     me.bursting = true;
113    
114     /* SERVER irc.undernet.org 1 933022556 947908144 J10 AA]]] :[127.0.0.1] A Undernet Server */
115     sts ("SERVER %s 1 %ld %ld J10 %s]]] +s :%s", me.name, me.start, NOW, me.numeric, me.desc);
116    
117     services_init ();
118    
119     sts ("%s EB", me.numeric);
120    
121     return 0;
122     }
123    
124     /* introduce a client */
125     static void
126     nefarious_introduce_nick (user_t *u)
127     {
128     sts ("%s N %s 1 %ld %s %s +%s%sk ]]]]]] %s :%s", me.numeric, u->nick, u->ts, u->user, u->host, "io", chansvs.fantasy ? "" : "d", u->uid, u->gecos);
129     }
130    
131     /* invite a user to a channel */
132     static void
133     nefarious_invite_sts (user_t *sender, user_t *target, channel_t *channel)
134     {
135     /* target is a nick, weird eh? -- jilles */
136     sts ("%s I %s %s", sender->uid, target->nick, channel->name);
137     }
138    
139     static void
140     nefarious_quit_sts (user_t *u, const char *reason)
141     {
142     if (!me.connected)
143     return;
144    
145     sts ("%s Q :%s", u->uid, reason);
146     }
147    
148     /* WALLOPS wrapper */
149     static void
150     nefarious_wallops_sts (const char *text)
151     {
152     sts ("%s WA :%s", me.numeric, text);
153     }
154    
155     /* join a channel */
156     static void
157     nefarious_join_sts (channel_t *c, user_t *u, bool isnew, char *modes)
158     {
159     /* If the channel doesn't exist, we need to create it. */
160     if (isnew)
161     {
162     sts ("%s C %s %ld", u->uid, c->name, c->ts);
163     if (modes[0] && modes[1])
164     sts ("%s M %s %s", u->uid, c->name, modes);
165     }
166     else
167     {
168     sts ("%s J %s %ld", u->uid, c->name, c->ts);
169     sts ("%s M %s +o %s", me.numeric, c->name, u->uid);
170     }
171     }
172    
173     /* kicks a user from a channel */
174     static void
175     nefarious_kick (char *from, char *channel, char *to, char *reason)
176     {
177     channel_t *chan = channel_find (channel);
178     user_t *fptr = user_find_named (from);
179     user_t *user = user_find_named (to);
180    
181     if (!chan || !user || !fptr)
182     return;
183    
184     sts ("%s K %s %s :%s", fptr->uid, channel, user->uid, reason);
185    
186     chanuser_delete (chan, user);
187     }
188    
189     /* PRIVMSG wrapper */
190     static void
191     nefarious_msg (const char *from, const char *target, const char *fmt, ...)
192     {
193     va_list ap;
194     user_t *u = user_find_named (from);
195     char buf[BUFSIZE];
196    
197     if (!u)
198     return;
199    
200     va_start (ap, fmt);
201     vsnprintf (buf, BUFSIZE, fmt, ap);
202     va_end (ap);
203    
204     sts ("%s P %s :%s", u->uid, target, buf);
205     }
206    
207     /* NOTICE wrapper */
208     static void
209     nefarious_notice_user_sts (user_t *from, user_t *target, const char *text)
210     {
211     sts ("%s O %s :%s", from ? from->uid : me.numeric, target->uid, text);
212     }
213    
214     static void
215     nefarious_notice_global_sts (user_t *from, const char *mask, const char *text)
216     {
217     node_t *n;
218     tld_t *tld;
219    
220     if (!strcmp (mask, "*"))
221     {
222     LIST_FOREACH (n, tldlist.head)
223     {
224     tld = static_cast<tld_t *> (n->data);
225     sts ("%s O %s*%s :%s", from ? from->uid : me.numeric, ircd->tldprefix, tld->name, text);
226     }
227     }
228     else
229     sts ("%s O %s%s :%s", from ? from->uid : me.numeric, ircd->tldprefix, mask, text);
230     }
231    
232     static void
233     nefarious_notice_channel_sts (user_t *from, channel_t *target, const char *text)
234     {
235     sts ("%s O %s :%s", from ? from->uid : me.numeric, target->name, text);
236     }
237    
238     static void
239     nefarious_wallchops (user_t *sender, channel_t *channel, const char *message)
240     {
241     sts ("%s WC %s :%s", sender->uid, channel->name, message);
242     }
243    
244     static void
245     nefarious_numeric_sts (char *from, int numeric, char *target, char *fmt, ...)
246     {
247     va_list ap;
248     char buf[BUFSIZE];
249     user_t *source_p, *target_p;
250    
251     source_p = user_find_named (from);
252     target_p = user_find_named (target);
253    
254     if (!target_p)
255     return;
256    
257     va_start (ap, fmt);
258     vsnprintf (buf, BUFSIZE, fmt, ap);
259     va_end (ap);
260    
261     sts ("%s %d %s %s", source_p ? source_p->uid : me.numeric, numeric, target_p->uid, buf);
262     }
263    
264     /* KILL wrapper */
265     static void
266     nefarious_skill (char *from, char *nick, char *fmt, ...)
267     {
268     va_list ap;
269     char buf[BUFSIZE];
270     user_t *fptr = user_find_named (from);
271     user_t *tptr = user_find_named (nick);
272    
273     if (!tptr)
274     return;
275    
276     va_start (ap, fmt);
277     vsnprintf (buf, BUFSIZE, fmt, ap);
278     va_end (ap);
279    
280     sts ("%s D %s :%s!%s!%s (%s)", fptr ? fptr->uid : me.numeric, tptr->uid, from, from, from, buf);
281     }
282    
283     /* PART wrapper */
284     static void
285     nefarious_part_sts (channel_t *c, user_t *u)
286     {
287     sts ("%s L %s", u->uid, c->name);
288     }
289    
290     /* server-to-server KLINE wrapper */
291     static void
292     nefarious_kline_sts (char *server, char *user, char *host, long duration, char *reason)
293     {
294     if (!me.connected)
295     return;
296    
297     /* hold permanent akills for four weeks -- jilles */
298     sts ("%s GL * +%s@%s %ld :%s", me.numeric, user, host, duration > 0 ? duration : 2419200, reason);
299     }
300    
301     /* server-to-server UNKLINE wrapper */
302     static void
303     nefarious_unkline_sts (char *server, char *user, char *host)
304     {
305     if (!me.connected)
306     return;
307    
308     sts ("%s GL * -%s@%s", me.numeric, user, host);
309     }
310    
311     /* topic wrapper */
312     static void
313     nefarious_topic_sts (channel_t *c, const char *setter, time_t ts, time_t prevts, const char *topic)
314     {
315     if (!me.connected || !c)
316     return;
317    
318     /* for nefarious, set topicsetter iff we can set the proper topicTS */
319     if (ts > prevts || prevts == 0)
320     sts ("%s T %s %s %ld %ld :%s", chansvs.me->me->uid, c->name, setter, c->ts, ts, topic);
321     else
322     {
323     ts = NOW;
324     if (ts < prevts)
325     ts = prevts + 1;
326     sts ("%s T %s %ld %ld :%s", chansvs.me->me->uid, c->name, c->ts, NOW, topic);
327     c->topicts = ts;
328     }
329     }
330    
331     /* mode wrapper */
332     static void
333     nefarious_mode_sts (char *sender, channel_t *target, char *modes)
334     {
335     user_t *fptr = user_find_named (sender);
336    
337     if (!fptr)
338     return;
339    
340     sts ("%s M %s %s", fptr->uid, target->name, modes);
341     }
342    
343     /* ping wrapper */
344     static void
345     nefarious_ping_sts (void)
346     {
347     if (!me.connected)
348     return;
349    
350     sts ("%s G !%ld %s %ld", me.numeric, NOW, me.name, NOW);
351     }
352    
353     /* protocol-specific stuff to do on login */
354     static void
355     nefarious_on_login (char *origin, char *user, char *wantedhost)
356     {
357     user_t *u = user_find_named (origin);
358    
359     if (!u)
360     return;
361    
362     sts ("%s AC %s R %s", me.numeric, u->uid, u->myuser->name);
363     check_hidehost (u);
364     }
365    
366     /* P10 does not support logout, so kill the user
367     * we can't keep track of which logins are stale and which aren't -- jilles
368     * Except we can in Nefarious --nenolod
369     */
370     static bool
371     nefarious_on_logout (char *origin, char *user, char *wantedhost)
372     {
373     user_t *u = user_find_named (origin);
374    
375     if (!me.connected)
376     return false;
377    
378     if (!u)
379     return false;
380    
381     sts ("%s AC %s U", me.numeric, u->uid);
382     if (u->flags & UF_HIDEHOSTREQ && me.hidehostsuffix != NULL && !strcmp (u->vhost + strlen (u->vhost) - strlen (me.hidehostsuffix), me.hidehostsuffix))
383     {
384     slog (LG_DEBUG, "nefarious_on_logout(): removing +x vhost for %s: %s -> %s", u->nick, u->vhost, u->host);
385     strlcpy (u->vhost, u->host, sizeof u->vhost);
386     }
387    
388     return false;
389     }
390    
391     static void
392     nefarious_jupe (const char *server, const char *reason)
393     {
394     server_t *s;
395    
396     if (!me.connected)
397     return;
398    
399     /* hold it for a day (arbitrary) -- jilles */
400     /* get rid of local deactivation too */
401     s = server_find (server);
402     if (s != NULL && s->uplink != NULL)
403     sts ("%s JU %s +%s %d %ld :%s", me.numeric, s->uplink->sid, server, 86400, NOW, reason);
404     sts ("%s JU * +%s %d %ld :%s", me.numeric, server, 86400, NOW, reason);
405     }
406    
407     static void
408     m_topic (sourceinfo_t *si, int parc, char *parv[])
409     {
410     channel_t *c = channel_find (parv[0]);
411     char *source;
412     time_t ts = 0;
413    
414     if (!c)
415     return;
416    
417     if (si->s != NULL)
418     source = si->s->name;
419     else
420     source = si->su->nick;
421    
422     if (parc > 2)
423     ts = atoi (parv[parc - 2]);
424     if (ts == 0)
425     ts = NOW;
426     else if (c->topic != NULL && ts < c->topicts)
427     return;
428     handle_topic_from (si, c, parc > 4 ? parv[parc - 4] : source, ts, parv[parc - 1]);
429     }
430    
431     /* AB G !1119920789.573932 services.atheme.org 1119920789.573932 */
432     static void
433     m_ping (sourceinfo_t *si, int parc, char *parv[])
434     {
435     /* reply to PING's */
436     sts ("%s Z %s %s %s", me.numeric, parv[0], parv[1], parv[2]);
437     }
438    
439     static void
440     m_pong (sourceinfo_t *si, int parc, char *parv[])
441     {
442     me.uplinkpong = NOW;
443    
444     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
445     if (me.bursting)
446     {
447     #ifdef HAVE_GETTIMEOFDAY
448     e_time (burstime, &burstime);
449    
450     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
451    
452     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
453     #else
454     slog (LG_INFO, "m_pong(): finished synching with uplink");
455     wallops ("Finished synching to network.");
456     #endif
457    
458     me.bursting = false;
459     }
460     }
461    
462     static void
463     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
464     {
465     if (parc != 2)
466     return;
467    
468     handle_message (si, parv[0], false, parv[1]);
469     }
470    
471     static void
472     m_notice (sourceinfo_t *si, int parc, char *parv[])
473     {
474     if (parc != 2)
475     return;
476    
477     handle_message (si, parv[0], true, parv[1]);
478     }
479    
480     static void
481     m_create (sourceinfo_t *si, int parc, char *parv[])
482     {
483     char buf[BUFSIZE];
484     int chanc;
485     char *chanv[256];
486     int i;
487    
488     chanc = sjtoken (parv[0], ',', chanv);
489    
490     for (i = 0; i < chanc; i++)
491     {
492     channel_t *c = channel_add (chanv[i], atoi (parv[1]), si->su->server);
493    
494     /* Tell the core to check mode locks now,
495     * otherwise it may only happen after the next
496     * mode change.
497     * P10 does not allow any redundant modes
498     * so this will not look ugly. -- jilles */
499     channel_mode_va (NULL, c, 1, "+");
500    
501     buf[0] = '@';
502     buf[1] = '\0';
503    
504     strlcat (buf, si->su->uid, BUFSIZE);
505    
506     chanuser_add (c, buf);
507     }
508     }
509    
510     static void
511     m_join (sourceinfo_t *si, int parc, char *parv[])
512     {
513     int chanc;
514     char *chanv[256];
515     int i;
516     node_t *n, *tn;
517     chanuser_t *cu;
518    
519     /* JOIN 0 is really a part from all channels */
520     if (!strcmp (parv[0], "0"))
521     {
522     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
523     {
524     cu = (chanuser_t *) n->data;
525     chanuser_delete (cu->chan, si->su);
526     }
527     return;
528     }
529     if (parc < 2)
530     return;
531    
532     chanc = sjtoken (parv[0], ',', chanv);
533    
534     for (i = 0; i < chanc; i++)
535     {
536     channel_t *c = channel_find (chanv[i]);
537    
538     if (!c)
539     {
540     c = channel_add (chanv[i], atoi (parv[1]), si->su->server);
541     channel_mode_va (NULL, c, 1, "+");
542     }
543    
544     chanuser_add (c, si->su->uid);
545     }
546     }
547    
548     static void
549     m_burst (sourceinfo_t *si, int parc, char *parv[])
550     {
551     channel_t *c;
552     unsigned int modec;
553     char *modev[16];
554     unsigned int userc;
555     char *userv[256];
556     unsigned int i;
557     int j;
558     char prefix[16];
559     char newnick[16 + NICKLEN];
560     char *p;
561     time_t ts;
562     int bantype;
563    
564     /* S BURST <channel> <ts> [parameters]
565     * parameters can be:
566     * +<simple mode>
567     * %<bans separated with spaces>
568     * <nicks>
569     */
570     ts = atoi (parv[1]);
571    
572     c = channel_find (parv[0]);
573    
574     if (c == NULL)
575     {
576     slog (LG_DEBUG, "m_burst(): new channel: %s", parv[0]);
577     c = channel_add (parv[0], ts, si->s);
578     }
579     else if (ts < c->ts)
580     {
581     chanuser_t *cu;
582     node_t *n;
583    
584     clear_simple_modes (c);
585     chanban_clear (c);
586     handle_topic_from (si, c, "", 0, "");
587     LIST_FOREACH (n, c->members.head)
588     {
589     cu = (chanuser_t *) n->data;
590     if (cu->user->server == me.me)
591     {
592     /* it's a service, reop */
593     sts ("%s M %s +o %s", me.numeric, c->name, CLIENT_NAME (cu->user));
594     cu->modes = CMODE_OP;
595     }
596     else
597     cu->modes = 0;
598     }
599    
600     slog (LG_DEBUG, "m_burst(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
601     c->ts = ts;
602     hook_call_event ("channel_tschange", c);
603     }
604     if (parc < 3 || parv[2][0] != '+')
605     {
606     /* Tell the core to check mode locks now,
607     * otherwise it may only happen after the next
608     * mode change. -- jilles */
609     channel_mode_va (NULL, c, 1, "+");
610     }
611    
612     bantype = 'b';
613     j = 2;
614     while (j < parc)
615     {
616     if (parv[j][0] == '+')
617     {
618     modec = 0;
619     modev[modec++] = parv[j++];
620     if (strchr (modev[0], 'k') && j < parc)
621     modev[modec++] = parv[j++];
622     if (strchr (modev[0], 'l') && j < parc)
623     modev[modec++] = parv[j++];
624     channel_mode (NULL, c, modec, modev);
625     }
626     else if (parv[j][0] == '%')
627     {
628     userc = sjtoken (parv[j++] + 1, ' ', userv);
629     for (i = 0; i < userc; i++)
630     if (!strcmp (userv[i], "~"))
631     /* A ban "~" means exceptions are
632     * following */
633     bantype = 'e';
634     else
635     chanban_add (c, userv[i], bantype);
636     }
637     else
638     {
639     userc = sjtoken (parv[j++], ',', userv);
640    
641     prefix[0] = '\0';
642     for (i = 0; i < userc; i++)
643     {
644     p = strchr (userv[i], ':');
645     if (p != NULL)
646     {
647     *p = '\0';
648     prefix[0] = '\0';
649     prefix[1] = '\0';
650     prefix[2] = '\0';
651     p++;
652     while (*p)
653     {
654     if (*p == 'o')
655     prefix[prefix[0] ? 1 : 0] = '@';
656     else if (*p == 'h')
657     prefix[prefix[0] ? 1 : 0] = '%';
658     else if (*p == 'v')
659     prefix[prefix[0] ? 1 : 0] = '+';
660     p++;
661     }
662     }
663     strlcpy (newnick, prefix, sizeof newnick);
664     strlcat (newnick, userv[i], sizeof newnick);
665     chanuser_add (c, newnick);
666     }
667     }
668     }
669    
670     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
671     channel_delete (c);
672     }
673    
674     static void
675     m_part (sourceinfo_t *si, int parc, char *parv[])
676     {
677     int chanc;
678     char *chanv[256];
679     int i;
680    
681     chanc = sjtoken (parv[0], ',', chanv);
682     for (i = 0; i < chanc; i++)
683     {
684     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
685    
686     chanuser_delete (channel_find (chanv[i]), si->su);
687     }
688     }
689    
690     static void
691     m_nick (sourceinfo_t *si, int parc, char *parv[])
692     {
693     user_t *u;
694     struct in_addr ip;
695     char ipstring[64];
696     char *p;
697     int i;
698    
699     /* got the right number of args for an introduction? */
700     if (parc >= 8)
701     {
702     /* -> AB N jilles 1 1137687480 jilles jaguar.test +oiwgrx jilles B]AAAB ABAAE :Jilles Tjoelker */
703     /* -> AB N test4 1 1137690148 jilles jaguar.test +iw B]AAAB ABAAG :Jilles Tjoelker */
704     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", si->s->name, parv[0]);
705    
706     ipstring[0] = '\0';
707     if (strlen (parv[parc - 3]) == 6)
708     {
709     ip.s_addr = ntohl (base64touint (parv[parc - 3]));
710     if (!inet_ntop (AF_INET, &ip, ipstring, sizeof ipstring))
711     ipstring[0] = '\0';
712     }
713     u = user_add (parv[0], parv[3], parv[4], NULL, ipstring, parv[parc - 2], parv[parc - 1], si->s, atoi (parv[2]));
714    
715     if (parv[5][0] == '+')
716     {
717     user_mode (u, parv[5]);
718     i = 1;
719     if (strchr (parv[5], 'r'))
720     {
721     handle_burstlogin (u, parv[5 + i]);
722     /* killed to force logout? */
723     if (user_find (parv[parc - 2]) == NULL)
724     return;
725     i++;
726     }
727     if (strchr (parv[5], 'h'))
728     {
729     p = strchr (parv[5 + i], '@');
730     if (p == NULL)
731     strlcpy (u->vhost, parv[5 + i], sizeof u->vhost);
732     else
733     {
734     strlcpy (u->vhost, p + 1, sizeof u->vhost);
735     strlcpy (u->user, parv[5 + i], sizeof u->user);
736     p = strchr (u->user, '@');
737     if (p != NULL)
738     *p = '\0';
739     }
740     i++;
741     }
742     if (strchr (parv[5], 'x'))
743     {
744     u->flags |= UF_HIDEHOSTREQ;
745     /* this must be after setting the account name */
746     check_hidehost (u);
747     }
748     }
749    
750     handle_nickchange (u);
751     }
752     /* if it's only 2 then it's a nickname change */
753     else if (parc == 2)
754     {
755     if (!si->su)
756     {
757     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
758     return;
759     }
760    
761     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
762    
763     user_changenick (si->su, parv[0], atoi (parv[1]));
764    
765     handle_nickchange (si->su);
766     }
767     else
768     {
769     slog (LG_DEBUG, "m_nick(): got NICK with wrong (%d) number of params", parc);
770    
771     for (i = 0; i < parc; i++)
772     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
773     }
774     }
775    
776     static void
777     m_quit (sourceinfo_t *si, int parc, char *parv[])
778     {
779     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
780    
781     /* user_delete() takes care of removing channels and so forth */
782     user_delete (si->su);
783     }
784    
785     static void
786     m_mode (sourceinfo_t *si, int parc, char *parv[])
787     {
788     user_t *u;
789     char *p;
790    
791     if (*parv[0] == '#')
792     channel_mode (NULL, channel_find (parv[0]), parc - 1, &parv[1]);
793     else
794     {
795     /* Yes this is a nick and not a UID -- jilles */
796     u = user_find_named (parv[0]);
797     if (u == NULL)
798     {
799     slog (LG_DEBUG, "m_mode(): user mode for unknown user %s", parv[0]);
800     return;
801     }
802     user_mode (u, parv[1]);
803     if (strchr (parv[1], 'x'))
804     {
805     u->flags |= UF_HIDEHOSTREQ;
806     check_hidehost (u);
807     }
808     if (strchr (parv[1], 'h'))
809     {
810     if (parc > 2)
811     {
812     /* assume +h */
813     p = strchr (parv[2], '@');
814     if (p == NULL)
815     strlcpy (u->vhost, parv[2], sizeof u->vhost);
816     else
817     {
818     strlcpy (u->vhost, p + 1, sizeof u->vhost);
819     strlcpy (u->user, parv[2], sizeof u->user);
820     p = strchr (u->user, '@');
821     if (p != NULL)
822     *p = '\0';
823     }
824     slog (LG_DEBUG, "m_mode(): user %s setting vhost %s@%s", u->nick, u->user, u->vhost);
825     }
826     else
827     {
828     /* must be -h */
829     /* XXX we don't know the original ident */
830     slog (LG_DEBUG, "m_mode(): user %s turning off vhost", u->nick);
831     strlcpy (u->vhost, u->host, sizeof u->vhost);
832     /* revert to +x vhost if applicable */
833     check_hidehost (u);
834     }
835     }
836     }
837     }
838    
839     static void
840     m_clearmode (sourceinfo_t *si, int parc, char *parv[])
841     {
842     channel_t *chan;
843     char *p, c;
844     node_t *n, *tn;
845     chanuser_t *cu;
846     int i;
847    
848     /* -> ABAAA CM # b */
849     /* Note: this is an IRCop command, do not enforce mode locks. */
850     chan = channel_find (parv[0]);
851     if (chan == NULL)
852     {
853     slog (LG_DEBUG, "m_clearmode(): unknown channel %s", parv[0]);
854     return;
855     }
856     p = parv[1];
857     while ((c = *p++))
858     {
859     if (c == 'b')
860     {
861     LIST_FOREACH_SAFE (n, tn, chan->bans.head)
862     {
863     if (((chanban_t *) n->data)->type == 'b')
864     chanban_delete (static_cast<chanban_t *> (n->data));
865     }
866     }
867     else if (c == 'e')
868     {
869     LIST_FOREACH_SAFE (n, tn, chan->bans.head)
870     {
871     if (((chanban_t *) n->data)->type == 'e')
872     chanban_delete (static_cast<chanban_t *> (n->data));
873     }
874     }
875     else if (c == 'k')
876     {
877     if (chan->key)
878     free (chan->key);
879     chan->key = NULL;
880     }
881     else if (c == 'l')
882     chan->limit = 0;
883     else if (c == 'o')
884     {
885     LIST_FOREACH (n, chan->members.head)
886     {
887     cu = (chanuser_t *) n->data;
888     if (cu->user->server == me.me)
889     {
890     /* it's a service, reop */
891     sts ("%s M %s +o %s", me.numeric, chan->name, cu->user->uid);
892     }
893     else
894     cu->modes &= ~CMODE_OP;
895     }
896     }
897     else if (c == 'h')
898     {
899     LIST_FOREACH (n, chan->members.head)
900     {
901     cu = (chanuser_t *) n->data;
902     cu->modes &= ~CMODE_HALFOP;
903     }
904     }
905     else if (c == 'v')
906     {
907     LIST_FOREACH (n, chan->members.head)
908     {
909     cu = (chanuser_t *) n->data;
910     cu->modes &= ~CMODE_VOICE;
911     }
912     }
913     else
914     for (i = 0; mode_list[i].mode != '\0'; i++)
915     {
916     if (c == mode_list[i].mode)
917     chan->modes &= ~mode_list[i].value;
918     }
919     }
920     }
921    
922     static void
923     m_kick (sourceinfo_t *si, int parc, char *parv[])
924     {
925     user_t *u = user_find (parv[1]);
926     channel_t *c = channel_find (parv[0]);
927    
928     /* -> :rakaur KICK #shrike rintaun :test */
929     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
930    
931     if (!u)
932     {
933     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
934     return;
935     }
936    
937     if (!c)
938     {
939     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
940     return;
941     }
942    
943     if (!chanuser_find (c, u))
944     {
945     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
946     return;
947     }
948    
949     chanuser_delete (c, u);
950    
951     /* if they kicked us, let's rejoin */
952     if (is_internal_client (u))
953     {
954     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
955     join (parv[0], u->nick);
956     }
957     }
958    
959     static void
960     m_kill (sourceinfo_t *si, int parc, char *parv[])
961     {
962     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
963     }
964    
965     static void
966     m_squit (sourceinfo_t *si, int parc, char *parv[])
967     {
968     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
969     server_delete (parv[0]);
970     }
971    
972     /* SERVER ircu.devel.atheme.org 1 1119902586 1119908830 J10 ABAP] + :lets lol */
973     static void
974     m_server (sourceinfo_t *si, int parc, char *parv[])
975     {
976     server_t *s;
977    
978     /* We dont care about the max connections. */
979     parv[5][2] = '\0';
980    
981     slog (LG_DEBUG, "m_server(): new server: %s, id %s, %s", parv[0], parv[5], parv[4][0] == 'P' ? "eob" : "bursting");
982     s = handle_server (si, parv[0], parv[5], atoi (parv[1]), parv[7]);
983    
984     /* SF_EOB may only be set when we have all users on the server.
985     * so store the fact that they are EOB in another flag.
986     * handle_eob() will set SF_EOB when the uplink has finished bursting.
987     * -- jilles */
988     if (s != NULL && parv[4][0] == 'P')
989     s->flags |= SF_EOB2;
990     }
991    
992     static void
993     m_stats (sourceinfo_t *si, int parc, char *parv[])
994     {
995     handle_stats (si->su, parv[0][0]);
996     }
997    
998     static void
999     m_admin (sourceinfo_t *si, int parc, char *parv[])
1000     {
1001     handle_admin (si->su);
1002     }
1003    
1004     static void
1005     m_version (sourceinfo_t *si, int parc, char *parv[])
1006     {
1007     handle_version (si->su);
1008     }
1009    
1010     static void
1011     m_info (sourceinfo_t *si, int parc, char *parv[])
1012     {
1013     handle_info (si->su);
1014     }
1015    
1016     static void
1017     m_motd (sourceinfo_t *si, int parc, char *parv[])
1018     {
1019     handle_motd (si->su);
1020     }
1021    
1022     static void
1023     m_whois (sourceinfo_t *si, int parc, char *parv[])
1024     {
1025     handle_whois (si->su, parv[1]);
1026     }
1027    
1028     static void
1029     m_trace (sourceinfo_t *si, int parc, char *parv[])
1030     {
1031     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
1032     }
1033    
1034     static void
1035     m_away (sourceinfo_t *si, int parc, char *parv[])
1036     {
1037     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
1038     }
1039    
1040     static void
1041     m_pass (sourceinfo_t *si, int parc, char *parv[])
1042     {
1043     if (strcmp (curr_uplink->pass, parv[0]))
1044     {
1045     slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
1046     runflags |= RF_SHUTDOWN;
1047     }
1048     }
1049    
1050     static void
1051     m_error (sourceinfo_t *si, int parc, char *parv[])
1052     {
1053     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
1054     }
1055    
1056     static void
1057     m_eos (sourceinfo_t *si, int parc, char *parv[])
1058     {
1059     handle_eob (si->s);
1060    
1061     /* acknowledge a local END_OF_BURST */
1062     if (si->s->uplink == me.me)
1063     sts ("%s EA", me.numeric);
1064     }
1065    
1066     static void
1067     check_hidehost (user_t *u)
1068     {
1069     static bool warned = false;
1070    
1071     /* do they qualify? */
1072     if (!(u->flags & UF_HIDEHOSTREQ) || u->myuser == NULL || (u->myuser->flags & MU_WAITAUTH))
1073     return;
1074     /* don't use this if they have some other kind of vhost */
1075     if (strcmp (u->host, u->vhost))
1076     {
1077     slog (LG_DEBUG, "check_hidehost(): +x overruled by other vhost for %s", u->nick);
1078     return;
1079     }
1080     if (me.hidehostsuffix == NULL)
1081     {
1082     if (!warned)
1083     {
1084     wallops ("Misconfiguration: serverinfo::hidehostsuffix not set");
1085     warned = true;
1086     }
1087     return;
1088     }
1089     snprintf (u->vhost, sizeof u->vhost, "%s.%s", u->myuser->name, me.hidehostsuffix);
1090     slog (LG_DEBUG, "check_hidehost(): %s -> %s", u->nick, u->vhost);
1091     }
1092    
1093     void
1094     _modinit (module_t *m)
1095     {
1096     /* Symbol relocation voodoo. */
1097     server_login = &nefarious_server_login;
1098     introduce_nick = &nefarious_introduce_nick;
1099     quit_sts = &nefarious_quit_sts;
1100     wallops_sts = &nefarious_wallops_sts;
1101     join_sts = &nefarious_join_sts;
1102     kick = &nefarious_kick;
1103     msg = &nefarious_msg;
1104     notice_user_sts = &nefarious_notice_user_sts;
1105     notice_global_sts = &nefarious_notice_global_sts;
1106     notice_channel_sts = &nefarious_notice_channel_sts;
1107     wallchops = &nefarious_wallchops;
1108     numeric_sts = &nefarious_numeric_sts;
1109     skill = &nefarious_skill;
1110     part_sts = &nefarious_part_sts;
1111     kline_sts = &nefarious_kline_sts;
1112     unkline_sts = &nefarious_unkline_sts;
1113     topic_sts = &nefarious_topic_sts;
1114     mode_sts = &nefarious_mode_sts;
1115     ping_sts = &nefarious_ping_sts;
1116     ircd_on_login = &nefarious_on_login;
1117     ircd_on_logout = &nefarious_on_logout;
1118     jupe = &nefarious_jupe;
1119     invite_sts = &nefarious_invite_sts;
1120    
1121     parse = &p10_parse;
1122    
1123     mode_list = nefarious_mode_list;
1124     ignore_mode_list = nefarious_ignore_mode_list;
1125     status_mode_list = nefarious_status_mode_list;
1126     prefix_mode_list = nefarious_prefix_mode_list;
1127    
1128     ircd = &Nefarious;
1129    
1130     pcommand_add ("G", m_ping, 1, MSRC_USER | MSRC_SERVER);
1131     pcommand_add ("Z", m_pong, 1, MSRC_SERVER);
1132     pcommand_add ("P", m_privmsg, 2, MSRC_USER);
1133     pcommand_add ("O", m_notice, 2, MSRC_USER | MSRC_SERVER);
1134     pcommand_add ("NOTICE", m_notice, 2, MSRC_UNREG);
1135     pcommand_add ("C", m_create, 1, MSRC_USER);
1136     pcommand_add ("J", m_join, 1, MSRC_USER);
1137     pcommand_add ("EB", m_eos, 0, MSRC_SERVER);
1138     pcommand_add ("B", m_burst, 2, MSRC_SERVER);
1139     pcommand_add ("L", m_part, 1, MSRC_USER);
1140     pcommand_add ("N", m_nick, 2, MSRC_USER | MSRC_SERVER);
1141     pcommand_add ("Q", m_quit, 1, MSRC_USER);
1142     pcommand_add ("M", m_mode, 2, MSRC_USER | MSRC_SERVER);
1143     pcommand_add ("OM", m_mode, 2, MSRC_USER); /* OPMODE, treat as MODE */
1144     pcommand_add ("CM", m_clearmode, 2, MSRC_USER);
1145     pcommand_add ("K", m_kick, 2, MSRC_USER | MSRC_SERVER);
1146     pcommand_add ("D", m_kill, 1, MSRC_USER | MSRC_SERVER);
1147     pcommand_add ("SQ", m_squit, 1, MSRC_USER | MSRC_SERVER);
1148     pcommand_add ("S", m_server, 8, MSRC_SERVER);
1149     pcommand_add ("SERVER", m_server, 8, MSRC_UNREG);
1150     pcommand_add ("R", m_stats, 2, MSRC_USER);
1151     pcommand_add ("AD", m_admin, 1, MSRC_USER);
1152     pcommand_add ("V", m_version, 1, MSRC_USER);
1153     pcommand_add ("F", m_info, 1, MSRC_USER);
1154     pcommand_add ("W", m_whois, 2, MSRC_USER);
1155     pcommand_add ("TR", m_trace, 1, MSRC_USER);
1156     pcommand_add ("A", m_away, 0, MSRC_USER);
1157     pcommand_add ("PASS", m_pass, 1, MSRC_UNREG);
1158     pcommand_add ("Y", m_error, 1, MSRC_UNREG | MSRC_SERVER);
1159     pcommand_add ("ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER);
1160     pcommand_add ("T", m_topic, 2, MSRC_USER | MSRC_SERVER);
1161     pcommand_add ("MO", m_motd, 1, MSRC_USER);
1162    
1163     m->mflags = MODTYPE_CORE;
1164    
1165     pmodule_loaded = true;
1166     }
1167    
1168     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
1169     * vim:ts=8
1170     * vim:sw=8
1171     * vim:noexpandtab
1172     */