ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/bircd.C
Revision: 1.6
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +3 -2 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

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