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

File Contents

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