ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/nefarious.C
Revision: 1.7
Committed: Sun Sep 16 18:54:44 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +10 -7 lines
Log Message:
#defines to enum

File Contents

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