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