ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/dreamforge.C
Revision: 1.8
Committed: Sat Sep 22 14:27:28 2007 UTC (16 years, 8 months 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

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