ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/shadowircd.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: +6 -2 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

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