ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/protocol/bahamut.C
Revision: 1.8
Committed: Sat Sep 22 14:27:28 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +8 -12 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# User Rev Content
1 pippijn 1.7 /**
2     * bahamut.C: This file contains protocol support for bahamut-based ircd.
3     *
4     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5     * Rights to this code are as documented in COPYING.
6     *
7     *
8     * Portions of this file were derived from sources bearing the following license:
9 pippijn 1.4 * Copyright © 2003-2004 E. Will et al.
10     * Copyright © 2005-2006 Atheme Development Group
11 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
12 pippijn 1.1 *
13 pippijn 1.8 * $Id: bahamut.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $
14 pippijn 1.1 */
15    
16 pippijn 1.8 #include <boost/foreach.hpp>
17    
18 pippijn 1.1 #include "atheme.h"
19 pippijn 1.8 #include <util/time.h>
20     #include <libermyth.h>
21 pippijn 1.6 #include "servers.h"
22 pippijn 1.1 #include <account/mynick.h>
23     #include <account/myuser.h>
24     #include "uplink.h"
25     #include "pmodule.h"
26     #include "protocol/bahamut.h"
27    
28 pippijn 1.8 static char const rcsid[] = "$Id: bahamut.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $";
29 pippijn 1.1
30     /* *INDENT-OFF* */
31    
32 pippijn 1.4 namespace protocol
33 pippijn 1.1 {
34 pippijn 1.4 static ircd_t Bahamut = {
35     "Bahamut 1.8.x", /* IRCd name */
36     "$", /* TLD Prefix, used by Global. */
37     false, /* Whether or not we use IRCNet/TS6 UID */
38     false, /* Whether or not we use RCOMMAND */
39     false, /* Whether or not we support channel owners. */
40     false, /* Whether or not we support channel protection. */
41     false, /* Whether or not we support halfops. */
42     false, /* Whether or not we use P10 */
43     false, /* Whether or not we use vHosts. */
44     CMODE_OPERONLY, /* Oper-only cmodes */
45     0, /* Integer flag for owner channel flag. */
46     0, /* Integer flag for protect channel flag. */
47     0, /* Integer flag for halfops. */
48     "+", /* Mode we set for owner. */
49     "+", /* Mode we set for protect. */
50     "+", /* Mode we set for halfops. */
51     PROTOCOL_BAHAMUT, /* Protocol type */
52     0, /* Permanent cmodes */
53     "beI", /* Ban-like cmodes */
54     'e', /* Except mchar */
55     'I', /* Invex mchar */
56     0 /* Flags */
57     };
58    
59     struct bahamut_handler : handler
60     {
61     bahamut_handler ();
62     virtual ~bahamut_handler ();
63    
64     virtual unsigned int server_login (void);
65     virtual void introduce_nick (user_t *u);
66     virtual void invite_sts (user_t *source, user_t *target, channel_t *channel);
67     virtual void quit_sts (user_t *u, char const * const reason);
68     virtual void wallops_sts (char const * const text);
69     virtual void join_sts (channel_t *c, user_t *u, bool isnew, char const * const modes);
70     virtual void chan_lowerts (channel_t *c, user_t *u);
71     virtual void kick (char const * const from, char const * const channel, char const * const to, char const * const reason);
72     virtual void privmsg (char const * const from, char const * const target, char const * const fmt, ...);
73     virtual void notice_user_sts (user_t *from, user_t *target, char const * const text);
74     virtual void notice_global_sts (user_t *from, char const * const mask, char const * const text);
75     virtual void notice_channel_sts (user_t *from, channel_t *target, char const * const text);
76     virtual void wallchops (user_t *sender, channel_t *channel, char const * const message);
77     virtual void numeric_sts (char const * const from, int numeric, char const * const target, char const * const fmt, ...);
78     virtual void skill (char const * const from, char const * const nick, char const * const fmt, ...);
79     virtual void part_sts (channel_t *c, user_t *u);
80     virtual void kline_sts (char const * const server, char const * const user, char const * const host, long duration, char const * const reason);
81     virtual void unkline_sts (char const * const server, char const * const user, char const * const host);
82     virtual void topic_sts (channel_t *c, char const * const setter, time_t ts, time_t prevts, char const * const topic);
83     virtual void mode_sts (char const * const sender, channel_t *target, char const * const modes);
84     virtual void ping_sts (void);
85     virtual void ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost);
86     virtual bool ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost);
87     virtual void jupe (char const * const server, char const * const reason);
88     virtual void fnc_sts (user_t *source, user_t *u, char const * const newnick, int type);
89     virtual void holdnick_sts (user_t *source, int duration, char const * const nick, myuser_t *account);
90     };
91    
92     static cmode_t bahamut_mode_list[] = {
93     { 'i', CMODE_INVITE },
94     { 'm', CMODE_MOD },
95     { 'n', CMODE_NOEXT },
96     { 'p', CMODE_PRIV },
97     { 's', CMODE_SEC },
98     { 't', CMODE_TOPIC },
99     { 'c', CMODE_NOCOLOR },
100     { 'M', CMODE_MODREG },
101     { 'R', CMODE_REGONLY },
102     { 'O', CMODE_OPERONLY },
103     { '\0', 0 }
104     };
105    
106     static bool check_jointhrottle(char const * const , channel_t *, mychan_t *, user_t *, myuser_t *);
107    
108 pippijn 1.5 static extmode_t bahamut_ignore_mode_list[] = {
109 pippijn 1.4 { 'j', check_jointhrottle },
110     { '\0', 0 }
111     };
112    
113     static cmode_t bahamut_status_mode_list[] = {
114     { 'o', CMODE_OP },
115     { 'v', CMODE_VOICE },
116     { '\0', 0 }
117     };
118    
119     static cmode_t bahamut_prefix_mode_list[] = {
120     { '@', CMODE_OP },
121     { '+', CMODE_VOICE },
122     { '\0', 0 }
123     };
124    
125     /* *INDENT-ON* */
126    
127     static bool
128     check_jointhrottle (char const * const value, channel_t *c, mychan_t *mc, user_t *u, myuser_t *mu)
129     {
130     char const *p = value;
131     char const *arg2 = NULL;
132     int num, timeslice, v;
133    
134     if (!strcmp (value, "0") && u == NULL && mu == NULL)
135     return true;
136     while (*p != '\0')
137     {
138     if (*p == ':')
139     {
140     if (arg2 != NULL)
141     return false;
142     arg2 = p + 1;
143     }
144     else if (!isdigit (*p))
145     return false;
146     p++;
147     }
148     if (arg2 == NULL)
149     return false;
150     if (p - arg2 > 3 || arg2 - value - 1 > 3)
151     return false;
152     num = atoi (value);
153     timeslice = atoi (arg2);
154     if (num <= 0 || num > 127 || timeslice <= 0 || timeslice > 127)
155     return false;
156     if (u != NULL || mu != NULL)
157     {
158     /* the following are the same restrictions bahamut
159     * applies to local clients
160     */
161     if (num < 2 || num > 20 || timeslice > 60)
162     return false;
163     v = (timeslice - 1) / 8 + 1;
164     if (num < v)
165     return false;
166     v = num / 2;
167     if (timeslice < v)
168     return false;
169     }
170 pippijn 1.1 return true;
171 pippijn 1.4 }
172    
173     /* login to our uplink */
174     unsigned int
175     bahamut_handler::server_login (void)
176     {
177     int ret;
178    
179     ret = sts ("PASS %s :TS", curr_uplink->pass);
180     if (ret == 1)
181     return 1;
182    
183     me.bursting = true;
184    
185     sts ("CAPAB SSJOIN NOQUIT BURST ZIP NICKIP TSMODE");
186     sts ("SERVER %s 1 :%s", me.name, me.desc);
187     sts ("SVINFO 5 3 0 :%ld", NOW);
188    
189     services_init ();
190    
191     return 0;
192     }
193    
194     /* introduce a client */
195     void
196     bahamut_handler::introduce_nick (user_t *u)
197     {
198     sts ("NICK %s 1 %ld +%s %s %s %s 0 0 :%s", u->nick, u->ts, "io", u->user, u->host, me.name, u->gecos);
199     }
200    
201     /* invite a user to a channel */
202     void
203     bahamut_handler::invite_sts (user_t *sender, user_t *target, channel_t *channel)
204     {
205     sts (":%s INVITE %s %s", sender->nick, target->nick, channel->name);
206     }
207    
208     void
209     bahamut_handler::quit_sts (user_t *u, char const * const reason)
210     {
211     if (!me.connected)
212     return;
213    
214     sts (":%s QUIT :%s", u->nick, reason);
215     }
216    
217     /* WALLOPS wrapper */
218     void
219     bahamut_handler::wallops_sts (char const * const text)
220     {
221     sts (":%s GLOBOPS :%s", me.name, text);
222     }
223    
224     /* join a channel */
225     void
226     bahamut_handler::join_sts (channel_t *c, user_t *u, bool isnew, char const * const modes)
227     {
228     if (isnew)
229     sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, modes, u->nick);
230     else
231     sts (":%s SJOIN %ld %s + :@%s", me.name, c->ts, c->name, u->nick);
232     }
233    
234     void
235     bahamut_handler::chan_lowerts (channel_t *c, user_t *u)
236     {
237     slog (LG_DEBUG, "bahamut_chan_lowerts(): lowering TS for %s to %ld", c->name, (long) c->ts);
238     sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, channel_modes (c, true), u->nick);
239     chanban_clear (c);
240     /*handle_topic(c, "", 0, ""); */
241     /* Don't destroy keeptopic info, I'll admit this is ugly -- jilles */
242     if (c->topic != NULL)
243     sfree (c->topic);
244     if (c->topic_setter != NULL)
245     sfree (c->topic_setter);
246     c->topic = c->topic_setter = NULL;
247     c->topicts = 0;
248     }
249    
250     /* kicks a user from a channel */
251     void
252     bahamut_handler::kick (char const * const from, char const * const channel, char const * const to, char const * const reason)
253     {
254     channel_t *chan = channel_find (channel);
255     user_t *user = user_find (to);
256    
257     if (!chan || !user)
258     return;
259    
260     sts (":%s KICK %s %s :%s", from, channel, to, reason);
261    
262     chanuser_delete (chan, user);
263     }
264    
265     /* PRIVMSG wrapper */
266     void
267     bahamut_handler::privmsg (char const * const from, char const * const target, char const * const fmt, ...)
268     {
269     va_list ap;
270     char buf[BUFSIZE];
271    
272     va_start (ap, fmt);
273     vsnprintf (buf, BUFSIZE, fmt, ap);
274     va_end (ap);
275    
276     sts (":%s PRIVMSG %s :%s", from, target, buf);
277     }
278    
279     /* NOTICE wrapper */
280     void
281     bahamut_handler::notice_user_sts (user_t *from, user_t *target, char const * const text)
282     {
283     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->nick, text);
284     }
285    
286     void
287     bahamut_handler::notice_global_sts (user_t *from, char const * const mask, char const * const text)
288     {
289     if (!strcmp (mask, "*"))
290 pippijn 1.8 foreach (tld_t *tld, tld_t::list)
291     sts (":%s NOTICE %s*%s :%s", from ? from->nick : me.name, ircd->tldprefix, tld->name, text);
292 pippijn 1.4 else
293     sts (":%s NOTICE %s%s :%s", from ? from->nick : me.name, ircd->tldprefix, mask, text);
294     }
295    
296     void
297     bahamut_handler::notice_channel_sts (user_t *from, channel_t *target, char const * const text)
298     {
299     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->name, text);
300     }
301    
302     void
303     bahamut_handler::wallchops (user_t *sender, channel_t *channel, char const * const message)
304     {
305     sts (":%s NOTICE @%s :%s", sender->nick, channel->name, message);
306     }
307    
308     void
309     bahamut_handler::numeric_sts (char const * const from, int numeric, char const * const target, char const * const fmt, ...)
310     {
311     va_list ap;
312     char buf[BUFSIZE];
313    
314     va_start (ap, fmt);
315     vsnprintf (buf, BUFSIZE, fmt, ap);
316     va_end (ap);
317    
318     sts (":%s %d %s %s", from, numeric, target, buf);
319     }
320    
321     /* KILL wrapper */
322     void
323     bahamut_handler::skill (char const * const from, char const * const nick, char const * const fmt, ...)
324     {
325     va_list ap;
326     char buf[BUFSIZE];
327    
328     va_start (ap, fmt);
329     vsnprintf (buf, BUFSIZE, fmt, ap);
330     va_end (ap);
331    
332     sts (":%s KILL %s :%s!%s!%s (%s)", from, nick, from, from, from, buf);
333     }
334    
335     /* PART wrapper */
336     void
337     bahamut_handler::part_sts (channel_t *c, user_t *u)
338     {
339     sts (":%s PART %s", u->nick, c->name);
340     }
341    
342     /* server-to-server KLINE wrapper */
343     void
344     bahamut_handler::kline_sts (char const * const server, char const * const user, char const * const host, long duration, char const * const reason)
345     {
346     if (!me.connected)
347     return;
348    
349     sts (":%s AKILL %s %s %ld %s %ld :%s", me.name, host, user, duration, opersvs.nick, NOW, reason);
350     }
351    
352     /* server-to-server UNKLINE wrapper */
353     void
354     bahamut_handler::unkline_sts (char const * const server, char const * const user, char const * const host)
355     {
356     if (!me.connected)
357     return;
358    
359     sts (":%s RAKILL %s %s", me.name, host, user);
360     }
361    
362     /* topic wrapper */
363     void
364     bahamut_handler::topic_sts (channel_t *c, char const * const setter, time_t ts, time_t prevts, char const * const topic)
365     {
366     if (!me.connected || !c)
367     return;
368    
369     sts (":%s TOPIC %s %s %ld :%s", chansvs.nick, c->name, setter, ts, topic);
370     }
371    
372     /* mode wrapper */
373     void
374     bahamut_handler::mode_sts (char const * const sender, channel_t *target, char const * const modes)
375     {
376     if (!me.connected)
377     return;
378    
379     sts (":%s MODE %s %ld %s", sender, target->name, target->ts, modes);
380     }
381    
382     /* ping wrapper */
383     void
384     bahamut_handler::ping_sts (void)
385     {
386     if (!me.connected)
387     return;
388    
389     sts ("PING :%s", me.name);
390     }
391    
392     /* protocol-specific stuff to do on login */
393     void
394     bahamut_handler::ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost)
395     {
396     user_t *u = user_find (origin);
397    
398     if (!me.connected || u == NULL)
399     return;
400    
401     /* Can only do this for nickserv, and can only record identified
402     * state if logged in to correct nick, sorry -- jilles
403     */
404     if (should_reg_umode (u))
405     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, origin, NOW);
406     }
407    
408     /* protocol-specific stuff to do on login */
409     bool
410     bahamut_handler::ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost)
411     {
412     if (!me.connected)
413     return false;
414    
415     if (!nicksvs.no_nick_ownership)
416     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, origin, NOW);
417 pippijn 1.1 return false;
418 pippijn 1.4 }
419    
420     void
421     bahamut_handler::jupe (char const * const server, char const * const reason)
422     {
423     server_t *s;
424    
425     if (!me.connected)
426     return;
427    
428     sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
429     s = server_find (server);
430     /* If the server is not directly connected to our uplink, we
431     * need to wait for its uplink to process the SQUIT :(
432     * -- jilles */
433     if (s != NULL && s->uplink != NULL && s->uplink->uplink != me.me)
434     s->flags |= SF_JUPE_PENDING;
435     else
436     sts (":%s SERVER %s 2 :%s", me.name, server, reason);
437     }
438    
439     void
440     bahamut_handler::fnc_sts (user_t *source, user_t *u, char const * const newnick, int type)
441     {
442     sts (":%s SVSNICK %s %s %lu", source->nick, u->nick, newnick, (unsigned long) (NOW - 60));
443     }
444    
445     void
446     bahamut_handler::holdnick_sts (user_t *source, int duration, char const * const nick, myuser_t *account)
447     {
448     sts (":%s SVSHOLD %s %d :Reserved by %s for nickname owner (%s)", source->nick, nick, duration, source->nick, account != NULL ? account->name : nick);
449     }
450    
451     static void
452     m_topic (sourceinfo_t *si, int parc, char *parv[])
453     {
454     channel_t *c = channel_find (parv[0]);
455    
456     if (!c)
457     return;
458    
459     /* Our uplink is trying to change the topic during burst,
460     * and we have already set a topic. Assume our change won.
461     * -- jilles */
462     if (si->s != NULL && si->s->uplink == me.me && !(si->s->flags & SF_EOB) && c->topic != NULL)
463     return;
464    
465     handle_topic_from (si, c, parv[1], atol (parv[2]), parv[3]);
466     }
467    
468     static void
469     m_ping (sourceinfo_t *si, int parc, char *parv[])
470     {
471     /* reply to PING's */
472     sts (":%s PONG %s %s", me.name, me.name, parv[0]);
473     }
474    
475     static void
476     m_pong (sourceinfo_t *si, int parc, char *parv[])
477     {
478     server_t *s;
479    
480     /* someone replied to our PING */
481     if (!parv[0])
482     return;
483     s = server_find (parv[0]);
484     if (s == NULL)
485     return;
486     /* Postpone EOB for our uplink until topic burst is also done */
487     if (s->uplink != me.me)
488     handle_eob (s);
489    
490     if (irccasecmp (me.actual, parv[0]))
491     return;
492    
493     me.uplinkpong = NOW;
494    
495     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
496     }
497    
498     static void
499     m_burst (sourceinfo_t *si, int parc, char *parv[])
500     {
501     server_t *s;
502    
503     /* Ignore "BURST" at start of burst */
504     if (parc != 1)
505 pippijn 1.1 return;
506 pippijn 1.4
507     s = server_find (me.actual);
508     if (s != NULL)
509     handle_eob (s);
510    
511     if (me.bursting)
512     {
513     #ifdef HAVE_GETTIMEOFDAY
514     e_time (burstime, &burstime);
515    
516     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
517    
518     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
519     #else
520     slog (LG_INFO, "m_pong(): finished synching with uplink");
521     wallops ("Finished synching to network.");
522     #endif
523    
524     me.bursting = false;
525     }
526     }
527    
528     static void
529     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
530     {
531     if (parc != 2)
532 pippijn 1.1 return;
533 pippijn 1.4
534     handle_message (si, parv[0], false, parv[1]);
535     }
536    
537     static void
538     m_notice (sourceinfo_t *si, int parc, char *parv[])
539     {
540     if (parc != 2)
541 pippijn 1.1 return;
542 pippijn 1.4
543     handle_message (si, parv[0], true, parv[1]);
544     }
545    
546     static void
547     m_sjoin (sourceinfo_t *si, int parc, char *parv[])
548     {
549     /*
550     * -> :proteus.malkier.net SJOIN 1073516550 #shrike +tn :@sycobuny @+rakaur
551     * also:
552     * -> :nenolod_ SJOIN 1117334567 #chat
553     */
554    
555     channel_t *c;
556     bool keep_new_modes = true;
557     unsigned int userc;
558     char *userv[256];
559     unsigned int i;
560     time_t ts;
561     char *p;
562    
563     if (parc >= 4 && si->s != NULL)
564     {
565     /* :origin SJOIN ts chan modestr [key or limits] :users */
566     c = channel_find (parv[1]);
567     ts = atol (parv[0]);
568    
569     if (!c)
570     {
571     slog (LG_DEBUG, "m_sjoin(): new channel: %s", parv[1]);
572     c = channel_add (parv[1], ts, si->s);
573     }
574    
575     if (ts == 0 || c->ts == 0)
576     {
577     if (c->ts != 0)
578     slog (LG_INFO, "m_sjoin(): server %s changing TS on %s from %ld to 0", si->s->name, c->name, (long) c->ts);
579     c->ts = 0;
580     c->callback.tschange (c);
581     }
582     else if (ts < c->ts)
583     {
584     chanuser_t *cu;
585     node_t *n;
586    
587     /* the TS changed. a TS change requires the following things
588     * to be done to the channel: reset all modes to nothing, remove
589     * all status modes on known users on the channel (including ours),
590     * and set the new TS.
591     * also clear all bans and the topic
592     */
593    
594     clear_simple_modes (c);
595     chanban_clear (c);
596     handle_topic_from (si, c, "", 0, "");
597    
598     LIST_FOREACH (n, c->members.head)
599     {
600     cu = (chanuser_t *) n->data;
601     if (cu->user->server == me.me)
602     {
603     /* it's a service, reop */
604     sts (":%s PART %s :Reop", cu->user->nick, c->name);
605     sts (":%s SJOIN %ld %s + :@%s", me.name, ts, c->name, cu->user->nick);
606     cu->modes = CMODE_OP;
607     }
608     else
609     cu->modes = 0;
610     }
611    
612     slog (LG_DEBUG, "m_sjoin(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
613    
614     c->ts = ts;
615     c->callback.tschange (c);
616     }
617     else if (ts > c->ts)
618     keep_new_modes = false;
619    
620     if (keep_new_modes)
621     channel_mode (NULL, c, parc - 3, parv + 2);
622    
623     userc = sjtoken (parv[parc - 1], ' ', userv);
624    
625     if (keep_new_modes)
626     for (i = 0; i < userc; i++)
627     chanuser_add (c, userv[i]);
628     else
629     for (i = 0; i < userc; i++)
630     {
631     p = userv[i];
632     while (*p == '@' || *p == '%' || *p == '+')
633     p++;
634     chanuser_add (c, p);
635     }
636    
637     if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
638     channel_delete (c);
639     }
640     else if (parc >= 2 && si->su != NULL)
641     {
642     c = channel_find (parv[1]);
643     ts = atol (parv[0]);
644    
645     if (c == NULL || ts < c->ts)
646     {
647     /* just request a resynch, this will include
648     * the user joining -- jilles */
649     slog (LG_DEBUG, "m_sjoin(): requesting resynch for %s", parv[1]);
650     sts ("RESYNCH %s", parv[1]);
651     return;
652     }
653    
654     chanuser_add (c, CLIENT_NAME (si->su));
655     }
656     else
657     {
658     slog (LG_DEBUG, "m_sjoin(): invalid source/parameters: origin %s parc %d", si->su != NULL ? si->su->nick : (si->s != NULL ? si->s->name : "<none>"), parc);
659     }
660     }
661    
662     static void
663     m_part (sourceinfo_t *si, int parc, char *parv[])
664     {
665     int chanc;
666     char *chanv[256];
667     int i;
668    
669     chanc = sjtoken (parv[0], ',', chanv);
670     for (i = 0; i < chanc; i++)
671     {
672     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
673    
674     chanuser_delete (channel_find (chanv[i]), si->su);
675     }
676     }
677    
678     static void
679     m_nick (sourceinfo_t *si, int parc, char *parv[])
680     {
681     server_t *s;
682     user_t *u;
683     struct in_addr ip;
684     char ipstring[64];
685     bool realchange;
686    
687     /* -> NICK jilles 1 1136143909 +oi ~jilles 192.168.1.5 jaguar.test 0 3232235781 :Jilles Tjoelker */
688     if (parc == 10)
689     {
690     s = server_find (parv[6]);
691     if (!s)
692     {
693     slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
694     return;
695     }
696    
697     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
698    
699     ip.s_addr = ntohl (strtoul (parv[8], NULL, 10));
700     ipstring[0] = '\0';
701     if (!inet_ntop (AF_INET, &ip, ipstring, sizeof ipstring))
702     ipstring[0] = '\0';
703     u = user_add (parv[0], parv[4], parv[5], NULL, ipstring, NULL, parv[9], s, atoi (parv[2]));
704    
705     user_mode (u, parv[3]);
706    
707     /* Ok, we have the user ready to go.
708     * Here's the deal -- if the user's SVID is before
709     * the start time, and not 0, then check to see
710     * if it's a registered account or not.
711     *
712     * If it IS registered, deal with that accordingly,
713     * via handle_burstlogin(). --nenolod
714     */
715     /* Changed to just check umode +r for now -- jilles */
716     /* This is ok because this ircd clears +r on nick changes
717     * -- jilles */
718     if (strchr (parv[3], 'r'))
719     handle_burstlogin (u, NULL);
720    
721     handle_nickchange (u);
722     }
723    
724     /* if it's only 2 then it's a nickname change */
725     else if (parc == 2)
726     {
727     if (!si->su)
728     {
729     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
730     return;
731     }
732    
733     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
734    
735     realchange = irccasecmp (si->su->nick, parv[0]);
736    
737     user_changenick (si->su, parv[0], atoi (parv[1]));
738    
739     /* fix up +r if necessary -- jilles */
740     if (realchange && should_reg_umode (si->su))
741     /* changed nick to registered one, reset +r */
742     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, parv[0], NOW);
743    
744     handle_nickchange (si->su);
745     }
746     else
747     {
748     int i;
749     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
750    
751     for (i = 0; i < parc; i++)
752     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
753     }
754     }
755    
756     static void
757     m_quit (sourceinfo_t *si, int parc, char *parv[])
758     {
759     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
760    
761     /* user_delete() takes care of removing channels and so forth */
762     user_delete (si->su);
763     }
764    
765     static void
766     m_mode (sourceinfo_t *si, int parc, char *parv[])
767     {
768     channel_t *c;
769    
770     if (*parv[0] == '#')
771     {
772     c = channel_find (parv[0]);
773     if (c == NULL)
774     {
775     slog (LG_DEBUG, "m_mode(): unknown channel %s", parv[0]);
776     return;
777     }
778     if (atol (parv[1]) > c->ts)
779     return;
780     channel_mode (NULL, channel_find (parv[0]), parc - 2, &parv[2]);
781     }
782     else
783     user_mode (user_find (parv[0]), parv[1]);
784     }
785    
786     static void
787     m_kick (sourceinfo_t *si, int parc, char *parv[])
788     {
789     user_t *u = user_find (parv[1]);
790     channel_t *c = channel_find (parv[0]);
791    
792     /* -> :rakaur KICK #shrike rintaun :test */
793     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
794    
795     if (!u)
796     {
797     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
798     return;
799     }
800    
801     if (!c)
802     {
803     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
804     return;
805     }
806    
807     if (!chanuser_find (c, u))
808     {
809     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
810     return;
811     }
812    
813     chanuser_delete (c, u);
814    
815     /* if they kicked us, let's rejoin */
816     if (is_internal_client (u))
817     {
818     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
819     join (parv[0], u->nick);
820     }
821     }
822    
823     static void
824     m_kill (sourceinfo_t *si, int parc, char *parv[])
825     {
826     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
827     }
828    
829     static void
830     m_squit (sourceinfo_t *si, int parc, char *parv[])
831     {
832     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
833     server_delete (parv[0]);
834     }
835    
836     static void
837     m_server (sourceinfo_t *si, int parc, char *parv[])
838     {
839     server_t *s;
840    
841     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
842     s = handle_server (si, parv[0], NULL, atoi (parv[1]), parv[2]);
843    
844     if (s != NULL && s->uplink != me.me)
845     {
846     /* elicit PONG for EOB detection; pinging uplink is
847     * already done elsewhere -- jilles
848     */
849     sts (":%s PING %s %s", me.name, me.name, s->name);
850     }
851     }
852    
853     static void
854     m_stats (sourceinfo_t *si, int parc, char *parv[])
855     {
856     handle_stats (si->su, parv[0][0]);
857     }
858    
859     static void
860     m_admin (sourceinfo_t *si, int parc, char *parv[])
861     {
862     handle_admin (si->su);
863     }
864    
865     static void
866     m_version (sourceinfo_t *si, int parc, char *parv[])
867     {
868     handle_version (si->su);
869     }
870    
871     static void
872     m_info (sourceinfo_t *si, int parc, char *parv[])
873     {
874     handle_info (si->su);
875     }
876    
877     static void
878     m_whois (sourceinfo_t *si, int parc, char *parv[])
879     {
880     handle_whois (si->su, parv[1]);
881     }
882    
883     static void
884     m_trace (sourceinfo_t *si, int parc, char *parv[])
885     {
886     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
887     }
888    
889     static void
890     m_away (sourceinfo_t *si, int parc, char *parv[])
891     {
892     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
893     }
894    
895     static void
896     m_join (sourceinfo_t *si, int parc, char *parv[])
897     {
898     chanuser_t *cu;
899     node_t *n, *tn;
900    
901     /* JOIN 0 is really a part from all channels */
902     if (parv[0][0] == '0')
903     {
904     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
905     {
906     cu = (chanuser_t *) n->data;
907     chanuser_delete (cu->chan, si->su);
908     }
909     }
910     }
911    
912     static void
913     m_pass (sourceinfo_t *si, int parc, char *parv[])
914     {
915     if (strcmp (curr_uplink->pass, parv[0]))
916 pippijn 1.1 {
917 pippijn 1.4 slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
918     runflags |= RF_SHUTDOWN;
919 pippijn 1.1 }
920 pippijn 1.4 }
921    
922     static void
923     m_error (sourceinfo_t *si, int parc, char *parv[])
924     {
925     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
926     }
927    
928     static void
929     m_motd (sourceinfo_t *si, int parc, char *parv[])
930     {
931     handle_motd (si->su);
932     }
933    
934     static void
935     nick_group (mynick_t *mn, myuser_t *mu, sourceinfo_t *si)
936     {
937     user_t *u;
938    
939     if (si->su != NULL && !irccasecmp (si->su->nick, mn->nick))
940     u = si->su;
941     else
942     u = user_find_named (mn->nick);
943    
944     if (u != NULL && should_reg_umode (u))
945     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, u->nick, NOW);
946     }
947    
948     static void
949     nick_ungroup (mynick_t *mn, myuser_t *mu, sourceinfo_t *si)
950     {
951     user_t *u;
952    
953     if (si->su != NULL && !irccasecmp (si->su->nick, mn->nick))
954     u = si->su;
955     else
956     u = user_find_named (mn->nick);
957    
958     if (u != NULL && !nicksvs.no_nick_ownership)
959     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, u->nick, NOW);
960     }
961    
962     static pcommand_t const pcommands[] = {
963     { "PING", m_ping, 1, MSRC_USER | MSRC_SERVER },
964     { "PONG", m_pong, 1, MSRC_SERVER },
965     { "PRIVMSG", m_privmsg, 2, MSRC_USER },
966     { "NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER },
967     { "SJOIN", m_sjoin, 2, MSRC_USER | MSRC_SERVER },
968     { "PART", m_part, 1, MSRC_USER },
969     { "NICK", m_nick, 2, MSRC_USER | MSRC_SERVER },
970     { "QUIT", m_quit, 1, MSRC_USER },
971     { "MODE", m_mode, 2, MSRC_USER | MSRC_SERVER },
972     { "KICK", m_kick, 2, MSRC_USER | MSRC_SERVER },
973     { "KILL", m_kill, 1, MSRC_USER | MSRC_SERVER },
974     { "SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER },
975     { "SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER },
976     { "STATS", m_stats, 2, MSRC_USER },
977     { "ADMIN", m_admin, 1, MSRC_USER },
978     { "VERSION", m_version, 1, MSRC_USER },
979     { "INFO", m_info, 1, MSRC_USER },
980     { "WHOIS", m_whois, 2, MSRC_USER },
981     { "TRACE", m_trace, 1, MSRC_USER },
982     { "AWAY", m_away, 0, MSRC_USER },
983     { "JOIN", m_join, 1, MSRC_USER },
984     { "PASS", m_pass, 1, MSRC_UNREG },
985     { "ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER },
986     { "TOPIC", m_topic, 4, MSRC_USER | MSRC_SERVER },
987     { "MOTD", m_motd, 1, MSRC_USER },
988     { "BURST", m_burst, 0, MSRC_SERVER },
989     };
990    
991     bahamut_handler::bahamut_handler ()
992     {
993     mode_list = bahamut_mode_list;
994     ignore_mode_list = bahamut_ignore_mode_list;
995     status_mode_list = bahamut_status_mode_list;
996     prefix_mode_list = bahamut_prefix_mode_list;
997    
998     ircd = &Bahamut;
999    
1000     pcommand_add (&pcommands);
1001    
1002     mynick_t::callback.group.attach (nick_group);
1003     mynick_t::callback.ungroup.attach (nick_ungroup);
1004     }
1005    
1006     bahamut_handler::~bahamut_handler ()
1007     {
1008     mode_list = NULL;
1009     ignore_mode_list = NULL;
1010     status_mode_list = NULL;
1011     prefix_mode_list = NULL;
1012    
1013     ircd = NULL;
1014    
1015     mynick_t::callback.group.detach (nick_group);
1016     mynick_t::callback.ungroup.detach (nick_ungroup);
1017    
1018     pcommand_delete (&pcommands);
1019     }
1020     } // namespace protocol
1021    
1022     #define FACREG_TYPE protocol::bahamut_handler
1023     #define FACREG_TYPE_NAME "bahamut"
1024     #define FACREG_INTERFACE_TYPE protocol::handler
1025     #include <ermyth/factory_reg.h>