ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/undernet.C
Revision: 1.4
Committed: Tue Aug 28 17:08:11 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.3: +1125 -1113 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

File Contents

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