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

File Contents

# User Rev Content
1 pippijn 1.7 /**
2     * dreamforge.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.7 * $Id: dreamforge.C,v 1.6 2007-09-09 20:05:52 pippijn Exp $
14 pippijn 1.1 */
15    
16     #include "atheme.h"
17 pippijn 1.6 #include "servers.h"
18 pippijn 1.1 #include <account/mynick.h>
19     #include "uplink.h"
20     #include "pmodule.h"
21     #include "protocol/dreamforge.h"
22    
23 pippijn 1.7 static char const rcsid[] = "$Id: dreamforge.C,v 1.6 2007-09-09 20:05:52 pippijn Exp $";
24 pippijn 1.1
25     /* *INDENT-OFF* */
26    
27 pippijn 1.4 namespace protocol
28 pippijn 1.1 {
29 pippijn 1.4 static ircd_t DreamForge = {
30     "DreamForge 4.6.7 and later", /* IRCd name */
31     "$", /* TLD Prefix, used by Global. */
32     false, /* Whether or not we use IRCNet/TS6 UID */
33     false, /* Whether or not we use RCOMMAND */
34     false, /* Whether or not we support channel owners. */
35     false, /* Whether or not we support channel protection. */
36     false, /* Whether or not we support halfops. */
37     false, /* Whether or not we use P10 */
38     false, /* Whether or not we use vHosts. */
39     0, /* Oper-only cmodes */
40     0, /* Integer flag for owner channel flag. */
41     0, /* Integer flag for protect channel flag. */
42     0, /* Integer flag for halfops. */
43     "+", /* Mode we set for owner. */
44     "+", /* Mode we set for protect. */
45     "+", /* Mode we set for halfops. */
46     PROTOCOL_DREAMFORGE, /* Protocol type */
47     0, /* Permanent cmodes */
48     "b", /* Ban-like cmodes */
49     0, /* Except mchar */
50     0, /* Invex mchar */
51     0 /* Flags */
52     };
53    
54     struct dreamforge_handler : handler
55     {
56     dreamforge_handler ();
57     virtual ~dreamforge_handler ();
58    
59     virtual unsigned int server_login (void);
60     virtual void introduce_nick (user_t *u);
61     virtual void invite_sts (user_t *source, user_t *target, channel_t *channel);
62     virtual void quit_sts (user_t *u, char const * const reason);
63     virtual void wallops_sts (char const * const text);
64     virtual void join_sts (channel_t *c, user_t *u, bool isnew, char const * const modes);
65     virtual void kick (char const * const from, char const * const channel, char const * const to, char const * const reason);
66     virtual void privmsg (char const * const from, char const * const target, char const * const fmt, ...);
67     virtual void notice_user_sts (user_t *from, user_t *target, char const * const text);
68     virtual void notice_global_sts (user_t *from, char const * const mask, char const * const text);
69     virtual void notice_channel_sts (user_t *from, channel_t *target, char const * const text);
70     virtual void numeric_sts (char const * const from, int numeric, char const * const target, char const * const fmt, ...);
71     virtual void skill (char const * const from, char const * const nick, char const * const fmt, ...);
72     virtual void part_sts (channel_t *c, user_t *u);
73     virtual void kline_sts (char const * const server, char const * const user, char const * const host, long duration, char const * const reason);
74     virtual void unkline_sts (char const * const server, char const * const user, char const * const host);
75     virtual void topic_sts (channel_t *c, char const * const setter, time_t ts, time_t prevts, char const * const topic);
76     virtual void mode_sts (char const * const sender, channel_t *target, char const * const modes);
77     virtual void ping_sts (void);
78     virtual void ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost);
79     virtual bool ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost);
80     virtual void jupe (char const * const server, char const * const reason);
81     };
82    
83     static cmode_t dreamforge_mode_list[] = {
84     { 'i', CMODE_INVITE },
85     { 'm', CMODE_MOD },
86     { 'n', CMODE_NOEXT },
87     { 'p', CMODE_PRIV },
88     { 's', CMODE_SEC },
89     { 't', CMODE_TOPIC },
90     { 'c', CMODE_NOCOLOR },
91     { 'R', CMODE_REGONLY },
92     { '\0', 0 }
93     };
94    
95 pippijn 1.5 static extmode_t dreamforge_ignore_mode_list[] = {
96 pippijn 1.4 { '\0', 0 }
97     };
98    
99     static cmode_t dreamforge_status_mode_list[] = {
100     { 'o', CMODE_OP },
101     { 'v', CMODE_VOICE },
102     { '\0', 0 }
103     };
104    
105     static cmode_t dreamforge_prefix_mode_list[] = {
106     { '@', CMODE_OP },
107     { '+', CMODE_VOICE },
108     { '\0', 0 }
109     };
110    
111     /* *INDENT-ON* */
112    
113     /* login to our uplink */
114     unsigned int
115     dreamforge_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     sts ("PROTOCTL NOQUIT WATCH=128 SAFELIST");
126     sts ("SERVER %s 1 :%s", me.name, me.desc);
127    
128     services_init ();
129    
130     return 0;
131     }
132    
133     /* introduce a client */
134     void
135     dreamforge_handler::introduce_nick (user_t *u)
136     {
137     sts ("NICK %s 1 %ld %s %s %s 0 :%s", u->nick, u->ts, u->user, u->host, me.name, u->gecos);
138     sts (":%s MODE %s +%s", u->nick, u->nick, "io");
139     }
140    
141     /* invite a user to a channel */
142     void
143     dreamforge_handler::invite_sts (user_t *sender, user_t *target, channel_t *channel)
144     {
145     sts (":%s INVITE %s %s", sender->nick, target->nick, channel->name);
146     }
147    
148     void
149     dreamforge_handler::quit_sts (user_t *u, char const * const reason)
150     {
151     if (!me.connected)
152     return;
153    
154     sts (":%s QUIT :%s", u->nick, reason);
155     }
156    
157     /* WALLOPS wrapper */
158     void
159     dreamforge_handler::wallops_sts (char const * const text)
160     {
161     sts (":%s GLOBOPS :%s", me.name, text);
162     }
163    
164     /* join a channel */
165     void
166     dreamforge_handler::join_sts (channel_t *c, user_t *u, bool isnew, char const * const modes)
167     {
168     if (isnew)
169     {
170     sts (":%s JOIN %s", u->nick, c->name);
171     if (modes[0] && modes[1])
172     sts (":%s MODE %s %s", u->nick, c->name, modes);
173     }
174     else
175     {
176     sts (":%s JOIN %s", u->nick, c->name);
177     }
178     sts (":%s MODE %s +o %s %ld", u->nick, c->name, u->nick, c->ts);
179     }
180    
181     /* kicks a user from a channel */
182     void
183     dreamforge_handler::kick (char const * const from, char const * const channel, char const * const to, char const * const reason)
184     {
185     channel_t *chan = channel_find (channel);
186     user_t *user = user_find (to);
187    
188     if (!chan || !user)
189     return;
190    
191     sts (":%s KICK %s %s :%s", from, channel, to, reason);
192    
193     chanuser_delete (chan, user);
194     }
195    
196     /* PRIVMSG wrapper */
197     void
198     dreamforge_handler::privmsg (char const * const from, char const * const target, char const * const fmt, ...)
199     {
200     va_list ap;
201     char buf[BUFSIZE];
202    
203     va_start (ap, fmt);
204     vsnprintf (buf, BUFSIZE, fmt, ap);
205     va_end (ap);
206    
207     sts (":%s PRIVMSG %s :%s", from, target, buf);
208     }
209    
210     /* NOTICE wrapper */
211     void
212     dreamforge_handler::notice_user_sts (user_t *from, user_t *target, char const * const text)
213     {
214     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->nick, text);
215     }
216    
217     void
218     dreamforge_handler::notice_global_sts (user_t *from, char const * const mask, char const * const text)
219     {
220     node_t *n;
221     tld_t *tld;
222    
223     if (!strcmp (mask, "*"))
224     {
225     LIST_FOREACH (n, tldlist.head)
226     {
227     tld = static_cast<tld_t *> (n->data);
228     sts (":%s NOTICE %s*%s :%s", from ? from->nick : me.name, ircd->tldprefix, tld->name, text);
229     }
230     }
231     else
232     sts (":%s NOTICE %s%s :%s", from ? from->nick : me.name, ircd->tldprefix, mask, text);
233     }
234    
235     void
236     dreamforge_handler::notice_channel_sts (user_t *from, channel_t *target, char const * const text)
237     {
238     sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->name, text);
239     }
240    
241     void
242     dreamforge_handler::numeric_sts (char const * const from, int numeric, char const * const target, char const * const fmt, ...)
243     {
244     va_list ap;
245     char buf[BUFSIZE];
246    
247     va_start (ap, fmt);
248     vsnprintf (buf, BUFSIZE, fmt, ap);
249     va_end (ap);
250    
251     sts (":%s %d %s %s", from, numeric, target, buf);
252     }
253    
254     /* KILL wrapper */
255     void
256     dreamforge_handler::skill (char const * const from, char const * const nick, char const * const fmt, ...)
257     {
258     va_list ap;
259     char buf[BUFSIZE];
260    
261     va_start (ap, fmt);
262     vsnprintf (buf, BUFSIZE, fmt, ap);
263     va_end (ap);
264    
265     sts (":%s KILL %s :%s!%s!%s (%s)", from, nick, from, from, from, buf);
266     }
267    
268     /* PART wrapper */
269     void
270     dreamforge_handler::part_sts (channel_t *c, user_t *u)
271     {
272     sts (":%s PART %s", u->nick, c->name);
273     }
274    
275     /* server-to-server KLINE wrapper */
276     void
277     dreamforge_handler::kline_sts (char const * const server, char const * const user, char const * const host, long duration, char const * const reason)
278     {
279     if (!me.connected)
280     return;
281    
282     sts (":%s AKILL %s %s %ld %s %ld :%s", me.name, host, user, duration, opersvs.nick, NOW, reason);
283     }
284    
285     /* server-to-server UNKLINE wrapper */
286     void
287     dreamforge_handler::unkline_sts (char const * const server, char const * const user, char const * const host)
288     {
289     if (!me.connected)
290     return;
291    
292     sts (":%s RAKILL %s %s", me.name, host, user);
293     }
294    
295     /* topic wrapper */
296     void
297     dreamforge_handler::topic_sts (channel_t *c, char const * const setter, time_t ts, time_t prevts, char const * const topic)
298     {
299     if (!me.connected)
300     return;
301    
302     if (ts < prevts || prevts == 0)
303     sts (":%s TOPIC %s %s %ld :%s", chansvs.nick, c->name, setter, ts, topic);
304     else if (prevts > 1)
305     {
306     ts = prevts - 1;
307     sts (":%s TOPIC %s %s %ld :%s", chansvs.nick, c->name, "topictime.wrong", ts, topic);
308     c->topicts = ts;
309     }
310     else
311     {
312     notice (chansvs.nick, c->name, "Unable to change topic to: %s", topic);
313     c->topicts = 1;
314     }
315     }
316    
317     /* mode wrapper */
318     void
319     dreamforge_handler::mode_sts (char const * const sender, channel_t *target, char const * const modes)
320     {
321     if (!me.connected)
322     return;
323    
324     sts (":%s MODE %s %s", sender, target->name, modes);
325     }
326    
327     /* ping wrapper */
328     void
329     dreamforge_handler::ping_sts (void)
330     {
331     if (!me.connected)
332     return;
333    
334     sts ("PING :%s", me.name);
335     }
336    
337     /* protocol-specific stuff to do on login */
338     void
339     dreamforge_handler::ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost)
340     {
341     user_t *u = user_find (origin);
342    
343     if (!me.connected || u == NULL)
344     return;
345    
346     /* Can only do this for nickserv, and can only record identified
347     * state if logged in to correct nick, sorry -- jilles
348     */
349     if (should_reg_umode (u))
350     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, origin, NOW);
351     }
352    
353     /* protocol-specific stuff to do on login */
354     bool
355     dreamforge_handler::ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost)
356     {
357     if (!me.connected)
358     return false;
359    
360     if (!nicksvs.no_nick_ownership)
361     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, origin, NOW);
362    
363 pippijn 1.1 return false;
364 pippijn 1.4 }
365    
366     void
367     dreamforge_handler::jupe (char const * const server, char const * const reason)
368     {
369     if (!me.connected)
370     return;
371    
372     server_delete (server);
373     sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
374     sts (":%s SERVER %s 2 :%s", me.name, server, reason);
375     }
376    
377     static void
378     m_topic (sourceinfo_t *si, int parc, char *parv[])
379     {
380     channel_t *c = channel_find (parv[0]);
381    
382     if (!c)
383     return;
384    
385     handle_topic_from (si, c, parv[1], atol (parv[2]), parv[3]);
386     }
387    
388     static void
389     m_ping (sourceinfo_t *si, int parc, char *parv[])
390     {
391     /* reply to PING's */
392     sts (":%s PONG %s %s", me.name, me.name, parv[0]);
393     }
394    
395     static void
396     m_pong (sourceinfo_t *si, int parc, char *parv[])
397     {
398     server_t *s;
399    
400     /* someone replied to our PING */
401     if (!parv[0])
402     return;
403     s = server_find (parv[0]);
404     if (s == NULL)
405 pippijn 1.1 return;
406 pippijn 1.4 handle_eob (s);
407    
408     if (irccasecmp (me.actual, parv[0]))
409 pippijn 1.1 return;
410 pippijn 1.4
411     me.uplinkpong = NOW;
412    
413     /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
414     if (me.bursting)
415     {
416     #ifdef HAVE_GETTIMEOFDAY
417     e_time (burstime, &burstime);
418    
419     slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
420    
421     wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
422     #else
423     slog (LG_INFO, "m_pong(): finished synching with uplink");
424     wallops ("Finished synching to network.");
425     #endif
426    
427     me.bursting = false;
428     }
429     }
430    
431     static void
432     m_privmsg (sourceinfo_t *si, int parc, char *parv[])
433     {
434     if (parc != 2)
435 pippijn 1.1 return;
436 pippijn 1.4
437     handle_message (si, parv[0], false, parv[1]);
438     }
439    
440     static void
441     m_notice (sourceinfo_t *si, int parc, char *parv[])
442     {
443     if (parc != 2)
444 pippijn 1.1 return;
445 pippijn 1.4
446     handle_message (si, parv[0], true, parv[1]);
447     }
448    
449     static void
450     m_part (sourceinfo_t *si, int parc, char *parv[])
451     {
452     int chanc;
453     char *chanv[256];
454     int i;
455    
456     chanc = sjtoken (parv[0], ',', chanv);
457     for (i = 0; i < chanc; i++)
458     {
459     slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
460    
461     chanuser_delete (channel_find (chanv[i]), si->su);
462     }
463     }
464    
465     static void
466     m_nick (sourceinfo_t *si, int parc, char *parv[])
467     {
468     server_t *s;
469     bool realchange;
470    
471     if (parc == 8)
472     {
473     s = server_find (parv[5]);
474     if (!s)
475     {
476     slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
477     return;
478     }
479    
480     slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
481    
482     user_add (parv[0], parv[3], parv[4], NULL, NULL, NULL, parv[7], s, atoi (parv[2]));
483    
484     /* Note: cannot rely on umode +r to see if they're identified
485     * -- jilles */
486    
487     handle_nickchange (user_find (parv[0]));
488     }
489    
490     /* if it's only 2 then it's a nickname change */
491     else if (parc == 2)
492     {
493     if (!si->su)
494     {
495     slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
496     return;
497     }
498    
499     slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
500    
501     realchange = irccasecmp (si->su->nick, parv[0]);
502    
503     user_changenick (si->su, parv[0], atoi (parv[1]));
504    
505     /* fix up +r if necessary -- jilles */
506     if (realchange && !nicksvs.no_nick_ownership)
507     {
508     if (should_reg_umode (si->su))
509     /* changed nick to registered one, reset +r */
510     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, parv[0], NOW);
511     else
512     /* changed from registered nick, remove +r */
513     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, parv[0], NOW);
514     }
515    
516     handle_nickchange (si->su);
517     }
518     else
519     {
520     int i;
521     slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
522    
523     for (i = 0; i < parc; i++)
524     slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
525     }
526     }
527    
528     static void
529     m_quit (sourceinfo_t *si, int parc, char *parv[])
530     {
531     if (si->su->server == me.me)
532     {
533     slog (LG_DEBUG, "m_quit(): not destroying own user %s (fake direction)", si->su->nick);
534     return;
535     }
536     slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
537    
538     /* user_delete() takes care of removing channels and so forth */
539     user_delete (si->su);
540     }
541    
542     static void
543     m_mode (sourceinfo_t *si, int parc, char *parv[])
544     {
545     if (*parv[0] == '#')
546     channel_mode (NULL, channel_find (parv[0]), parc - 1, &parv[1]);
547     else
548     user_mode (user_find (parv[0]), parv[1]);
549     }
550    
551     static void
552     m_kick (sourceinfo_t *si, int parc, char *parv[])
553     {
554     user_t *u = user_find (parv[1]);
555     channel_t *c = channel_find (parv[0]);
556    
557     /* -> :rakaur KICK #shrike rintaun :test */
558     slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
559    
560     if (!u)
561     {
562     slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
563     return;
564     }
565    
566     if (!c)
567     {
568     slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
569     return;
570     }
571    
572     if (!chanuser_find (c, u))
573     {
574     slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
575     return;
576     }
577    
578     chanuser_delete (c, u);
579    
580     /* if they kicked us, let's rejoin */
581     if (is_internal_client (u))
582     {
583     slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
584     join (parv[0], u->nick);
585     }
586     }
587    
588     static void
589     m_kill (sourceinfo_t *si, int parc, char *parv[])
590     {
591     handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
592     }
593    
594     static void
595     m_squit (sourceinfo_t *si, int parc, char *parv[])
596     {
597     slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
598     server_delete (parv[0]);
599     }
600    
601     static void
602     m_server (sourceinfo_t *si, int parc, char *parv[])
603     {
604     server_t *s;
605    
606     slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
607     s = handle_server (si, parv[0], NULL, atoi (parv[1]), parv[2]);
608    
609     if (s != NULL && s->uplink != me.me)
610     {
611     /* elicit PONG for EOB detection; pinging uplink is
612     * already done elsewhere -- jilles
613     */
614     sts (":%s PING %s %s", me.name, me.name, s->name);
615     }
616     }
617    
618     static void
619     m_stats (sourceinfo_t *si, int parc, char *parv[])
620     {
621     handle_stats (si->su, parv[0][0]);
622     }
623    
624     static void
625     m_admin (sourceinfo_t *si, int parc, char *parv[])
626     {
627     handle_admin (si->su);
628     }
629    
630     static void
631     m_version (sourceinfo_t *si, int parc, char *parv[])
632     {
633     handle_version (si->su);
634     }
635    
636     static void
637     m_info (sourceinfo_t *si, int parc, char *parv[])
638     {
639     handle_info (si->su);
640     }
641    
642     static void
643     m_whois (sourceinfo_t *si, int parc, char *parv[])
644     {
645     handle_whois (si->su, parv[1]);
646     }
647    
648     static void
649     m_trace (sourceinfo_t *si, int parc, char *parv[])
650     {
651     handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
652     }
653    
654     static void
655     m_away (sourceinfo_t *si, int parc, char *parv[])
656     {
657     handle_away (si->su, parc >= 1 ? parv[0] : NULL);
658     }
659    
660     static void
661     m_join (sourceinfo_t *si, int parc, char *parv[])
662     {
663     chanuser_t *cu;
664     node_t *n, *tn;
665     int chanc;
666     char *chanv[256];
667     int i;
668    
669     /* JOIN 0 is really a part from all channels */
670     if (parv[0][0] == '0')
671     {
672     LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
673     {
674     cu = (chanuser_t *) n->data;
675     chanuser_delete (cu->chan, si->su);
676     }
677     }
678     else
679     {
680     chanc = sjtoken (parv[0], ',', chanv);
681     for (i = 0; i < chanc; i++)
682     {
683     channel_t *c = channel_find (chanv[i]);
684    
685     if (!c)
686     {
687     slog (LG_DEBUG, "m_join(): new channel: %s", parv[0]);
688     c = channel_add (chanv[i], NOW, si->su->server);
689     /* Tell the core to check mode locks now,
690     * otherwise it may only happen after the next
691     * mode change.
692     * DreamForge does not allow any redundant modes
693     * so this will not look ugly. -- jilles */
694     /* If this is in a burst, a MODE with the
695     * simple modes will follow so we can skip
696     * this. -- jilles */
697     if (!me.bursting)
698     channel_mode (NULL, c, "+");
699     }
700     chanuser_add (c, si->su->nick);
701     }
702     }
703     }
704    
705     static void
706     m_pass (sourceinfo_t *si, int parc, char *parv[])
707     {
708     if (strcmp (curr_uplink->pass, parv[0]))
709     {
710     slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
711     runflags |= RF_SHUTDOWN;
712     }
713     }
714    
715     static void
716     m_error (sourceinfo_t *si, int parc, char *parv[])
717     {
718     slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
719     }
720    
721     static void
722     m_motd (sourceinfo_t *si, int parc, char *parv[])
723     {
724     handle_motd (si->su);
725     }
726    
727     static void
728     nick_group (mynick_t *mn, myuser_t *mu, sourceinfo_t *si)
729     {
730     user_t *u;
731    
732     if (si->su != NULL && !irccasecmp (si->su->nick, mn->nick))
733     u = si->su;
734     else
735     u = user_find_named (mn->nick);
736    
737     if (u != NULL && should_reg_umode (u))
738     sts (":%s SVSMODE %s +rd %ld", nicksvs.nick, u->nick, NOW);
739     }
740    
741     static void
742     nick_ungroup (mynick_t *mn, myuser_t *mu, sourceinfo_t *si)
743     {
744     user_t *u;
745    
746     if (si->su != NULL && !irccasecmp (si->su->nick, mn->nick))
747     u = si->su;
748     else
749     u = user_find_named (mn->nick);
750    
751     if (u != NULL && !nicksvs.no_nick_ownership)
752     sts (":%s SVSMODE %s -r+d %ld", nicksvs.nick, u->nick, NOW);
753     }
754    
755     static pcommand_t const pcommands[] = {
756     { "PING", m_ping, 1, MSRC_USER | MSRC_SERVER },
757     { "PONG", m_pong, 1, MSRC_SERVER },
758     { "PRIVMSG", m_privmsg, 2, MSRC_USER },
759     { "NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER },
760     { "PART", m_part, 1, MSRC_USER },
761     { "NICK", m_nick, 2, MSRC_USER | MSRC_SERVER },
762     { "QUIT", m_quit, 1, MSRC_USER },
763     { "MODE", m_mode, 2, MSRC_USER | MSRC_SERVER },
764     { "KICK", m_kick, 2, MSRC_USER | MSRC_SERVER },
765     { "KILL", m_kill, 1, MSRC_USER | MSRC_SERVER },
766     { "SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER },
767     { "SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER },
768     { "STATS", m_stats, 2, MSRC_USER },
769     { "ADMIN", m_admin, 1, MSRC_USER },
770     { "VERSION", m_version, 1, MSRC_USER },
771     { "INFO", m_info, 1, MSRC_USER },
772     { "WHOIS", m_whois, 2, MSRC_USER },
773     { "TRACE", m_trace, 1, MSRC_USER },
774     { "AWAY", m_away, 0, MSRC_USER },
775     { "JOIN", m_join, 1, MSRC_USER },
776     { "PASS", m_pass, 1, MSRC_UNREG },
777     { "ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER },
778     { "TOPIC", m_topic, 4, MSRC_USER | MSRC_SERVER },
779     { "MOTD", m_motd, 1, MSRC_USER },
780     };
781    
782     dreamforge_handler::dreamforge_handler ()
783     {
784     mode_list = dreamforge_mode_list;
785     ignore_mode_list = dreamforge_ignore_mode_list;
786     status_mode_list = dreamforge_status_mode_list;
787     prefix_mode_list = dreamforge_prefix_mode_list;
788    
789     ircd = &DreamForge;
790    
791     pcommand_add (&pcommands);
792    
793     mynick_t::callback.group.attach (nick_group);
794     mynick_t::callback.ungroup.attach (nick_ungroup);
795     }
796    
797     dreamforge_handler::~dreamforge_handler ()
798     {
799     mode_list = NULL;
800     ignore_mode_list = NULL;
801     status_mode_list = NULL;
802     prefix_mode_list = NULL;
803    
804     ircd = NULL;
805    
806     mynick_t::callback.group.detach (nick_group);
807     mynick_t::callback.ungroup.detach (nick_ungroup);
808    
809     pcommand_delete (&pcommands);
810     }
811     } // namespace protocol
812    
813     #define FACREG_TYPE protocol::dreamforge_handler
814     #define FACREG_TYPE_NAME "dreamforge"
815     #define FACREG_INTERFACE_TYPE protocol::handler
816     #include <ermyth/factory_reg.h>