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