ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/ultimate3.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 * ultimate3.C: This file contains protocol support for Ultimate3 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: ultimate3.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/ultimate3.h"
26
27 static char const rcsid[] = "$Id: ultimate3.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 ultimate3 = {
34 "UltimateIRCd 3.0.*", /* 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 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, /* Oper-only cmodes */
44 0, /* Integer flag for owner channel flag. */
45 CMODE_PROTECT, /* Integer flag for protect channel flag. */
46 CMODE_HALFOP, /* Integer flag for halfops. */
47 "+", /* Mode we set for owner. */
48 "+a", /* Mode we set for protect. */
49 "+h", /* Mode we set for halfops. */
50 PROTOCOL_ULTIMATE3, /* Protocol type */
51 0, /* Permanent cmodes */
52 "be", /* Ban-like cmodes */
53 'e', /* Except mchar */
54 0, /* Invex mchar */
55 0 /* Flags */
56 };
57
58 struct ultimate3_handler : handler
59 {
60 ultimate3_handler ();
61 virtual ~ultimate3_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 virtual void sethost_sts (char const * const source, char const * const target, char const * const host);
86 };
87
88 static cmode_t ultimate3_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 { 'M', CMODE_MODREG },
96 { 'R', CMODE_REGONLY },
97 { 'O', CMODE_OPERONLY },
98 { '\0', 0 }
99 };
100
101 static extmode_t ultimate3_ignore_mode_list[] = {
102 { '\0', 0 }
103 };
104
105 static cmode_t ultimate3_status_mode_list[] = {
106 { 'a', CMODE_PROTECT },
107 { 'o', CMODE_OP },
108 { 'h', CMODE_HALFOP },
109 { 'v', CMODE_VOICE },
110 { '\0', 0 }
111 };
112
113 static cmode_t ultimate3_prefix_mode_list[] = {
114 { '!', CMODE_PROTECT },
115 { '@', CMODE_OP },
116 { '%', CMODE_HALFOP },
117 { '+', CMODE_VOICE },
118 { '\0', 0 }
119 };
120
121 /* *INDENT-ON* */
122
123 /* login to our uplink */
124 unsigned int
125 ultimate3_handler::server_login (void)
126 {
127 int ret;
128
129 ret = sts ("PASS %s :TS", curr_uplink->pass);
130 if (ret == 1)
131 return 1;
132
133 me.bursting = true;
134
135 sts ("CAPAB TS5 NOQUIT SSJ5 BURST TSMODE NICKIP CLIENT");
136 sts ("SERVER %s 1 :%s", me.name, me.desc);
137 sts ("SVINFO 5 3 0 :%ld", NOW);
138
139 services_init ();
140
141 return 0;
142 }
143
144 /* introduce a client */
145 void
146 ultimate3_handler::introduce_nick (user_t *u)
147 {
148 sts ("CLIENT %s 1 %ld +%sS + %s %s * %s 0 0 :%s", u->nick, u->ts, "io", u->user, u->host, me.name, u->gecos);
149 }
150
151 /* invite a user to a channel */
152 void
153 ultimate3_handler::invite_sts (user_t *sender, user_t *target, channel_t *channel)
154 {
155 sts (":%s INVITE %s %s", sender->nick, target->nick, channel->name);
156 }
157
158 void
159 ultimate3_handler::quit_sts (user_t *u, char const * const reason)
160 {
161 if (!me.connected)
162 return;
163
164 sts (":%s QUIT :%s", u->nick, reason);
165 }
166
167 /* WALLOPS wrapper */
168 void
169 ultimate3_handler::wallops_sts (char const * const text)
170 {
171 sts (":%s GLOBOPS :%s", chansvs.nick, text);
172 }
173
174 /* join a channel */
175 void
176 ultimate3_handler::join_sts (channel_t *c, user_t *u, bool isnew, char const * const modes)
177 {
178 if (isnew)
179 sts (":%s SJOIN %ld %s %s :@%s", me.name, c->ts, c->name, modes, u->nick);
180 else
181 sts (":%s SJOIN %ld %s + :@%s", me.name, c->ts, c->name, u->nick);
182 }
183
184 /* kicks a user from a channel */
185 void
186 ultimate3_handler::kick (char const * const from, char const * const channel, char const * const to, char const * const reason)
187 {
188 channel_t *chan = channel_find (channel);
189 user_t *user = user_find (to);
190
191 if (!chan || !user)
192 return;
193
194 sts (":%s KICK %s %s :%s", from, channel, to, reason);
195
196 chanuser_delete (chan, user);
197 }
198
199 /* PRIVMSG wrapper */
200 void
201 ultimate3_handler::privmsg (char const * const from, char const * const target, char const * const fmt, ...)
202 {
203 va_list ap;
204 char buf[BUFSIZE];
205
206 va_start (ap, fmt);
207 vsnprintf (buf, BUFSIZE, fmt, ap);
208 va_end (ap);
209
210 sts (":%s PRIVMSG %s :%s", from, target, buf);
211 }
212
213 /* NOTICE wrapper */
214 void
215 ultimate3_handler::notice_user_sts (user_t *from, user_t *target, char const * const text)
216 {
217 sts (":%s NOTICE %s :%s", from ? from->nick : me.name, target->nick, text);
218 }
219
220 void
221 ultimate3_handler::notice_global_sts (user_t *from, char const * const mask, char const * const text)
222 {
223 if (!strcmp (mask, "*"))
224 foreach (tld_t *tld, tld_t::list)
225 sts (":%s NOTICE %s*%s :%s", from ? from->nick : me.name, ircd->tldprefix, tld->name, text);
226 else
227 sts (":%s NOTICE %s%s :%s", from ? from->nick : me.name, ircd->tldprefix, mask, text);
228 }
229
230 void
231 ultimate3_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 ultimate3_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 ultimate3_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 ultimate3_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 ultimate3_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 ultimate3_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 ultimate3_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 || !c)
295 return;
296
297 sts (":%s TOPIC %s %s %ld :%s", chansvs.nick, c->name, setter, ts, topic);
298 }
299
300 /* mode wrapper */
301 void
302 ultimate3_handler::mode_sts (char const * const sender, channel_t *target, char const * const modes)
303 {
304 if (!me.connected)
305 return;
306
307 sts (":%s MODE %s %ld %s", sender, target->name, target->ts, modes);
308 }
309
310 /* ping wrapper */
311 void
312 ultimate3_handler::ping_sts (void)
313 {
314 if (!me.connected)
315 return;
316
317 sts ("PING :%s", me.name);
318 }
319
320 /* protocol-specific stuff to do on login */
321 void
322 ultimate3_handler::ircd_on_login (char const * const origin, char const * const user, char const * const wantedhost)
323 {
324 user_t *u = user_find (origin);
325
326 if (!me.connected || u == NULL)
327 return;
328
329 /* Can only do this for nickserv, and can only record identified
330 * state if logged in to correct nick, sorry -- jilles
331 */
332 if (should_reg_umode (u))
333 sts (":%s SVSMODE %s +rd %ld", me.name, origin, NOW);
334 }
335
336 /* protocol-specific stuff to do on login */
337 bool
338 ultimate3_handler::ircd_on_logout (char const * const origin, char const * const user, char const * const wantedhost)
339 {
340 if (!me.connected)
341 return false;
342
343 if (!nicksvs.no_nick_ownership)
344 sts (":%s SVSMODE %s -r+d %ld", me.name, origin, NOW);
345
346 return false;
347 }
348
349 void
350 ultimate3_handler::jupe (char const * const server, char const * const reason)
351 {
352 server_t *s;
353
354 if (!me.connected)
355 return;
356
357 sts (":%s SQUIT %s :%s", opersvs.nick, server, reason);
358 s = server_find (server);
359 /* If the server is not directly connected to our uplink, we
360 * need to wait for its uplink to process the SQUIT :(
361 * -- jilles */
362 if (s != NULL && s->uplink != NULL && s->uplink->uplink != me.me)
363 s->flags |= SF_JUPE_PENDING;
364 else
365 sts (":%s SERVER %s 2 :%s", me.name, server, reason);
366 }
367
368 void
369 ultimate3_handler::sethost_sts (char const * const source, char const * const target, char const * const host)
370 {
371 if (!me.connected)
372 return;
373
374 notice (source, target, "Setting your host to \2%s\2.", host);
375 sts (":%s SVSMODE %s +x", source, target);
376 sts (":%s SETHOST %s :%s", me.name, target, host);
377 }
378
379 static void
380 m_topic (sourceinfo_t *si, int parc, char *parv[])
381 {
382 channel_t *c = channel_find (parv[0]);
383
384 if (!c)
385 return;
386
387 /* Our uplink is trying to change the topic during burst,
388 * and we have already set a topic. Assume our change won.
389 * -- jilles */
390 if (si->s != NULL && si->s->uplink == me.me && !(si->s->flags & SF_EOB) && c->topic != NULL)
391 return;
392
393 handle_topic_from (si, c, parv[1], atol (parv[2]), parv[3]);
394 }
395
396 static void
397 m_ping (sourceinfo_t *si, int parc, char *parv[])
398 {
399 /* reply to PING's */
400 sts (":%s PONG %s %s", me.name, me.name, parv[0]);
401 }
402
403 static void
404 m_pong (sourceinfo_t *si, int parc, char *parv[])
405 {
406 server_t *s;
407
408 /* someone replied to our PING */
409 if (!parv[0])
410 return;
411 s = server_find (parv[0]);
412 if (s == NULL)
413 return;
414 handle_eob (s);
415
416 if (irccasecmp (me.actual, parv[0]))
417 return;
418
419 me.uplinkpong = NOW;
420
421 /* -> :test.projectxero.net PONG test.projectxero.net :shrike.malkier.net */
422 if (me.bursting)
423 {
424 #ifdef HAVE_GETTIMEOFDAY
425 e_time (burstime, &burstime);
426
427 slog (LG_INFO, "m_pong(): finished synching with uplink (%d %s)", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
428
429 wallops ("Finished synching to network in %d %s.", (tv2ms (&burstime) > 1000) ? (tv2ms (&burstime) / 1000) : tv2ms (&burstime), (tv2ms (&burstime) > 1000) ? "s" : "ms");
430 #else
431 slog (LG_INFO, "m_pong(): finished synching with uplink");
432 wallops ("Finished synching to network.");
433 #endif
434
435 me.bursting = false;
436 }
437 }
438
439 static void
440 m_privmsg (sourceinfo_t *si, int parc, char *parv[])
441 {
442 if (parc != 2)
443 return;
444
445 handle_message (si, parv[0], false, parv[1]);
446 }
447
448 static void
449 m_notice (sourceinfo_t *si, int parc, char *parv[])
450 {
451 if (parc != 2)
452 return;
453
454 handle_message (si, parv[0], true, parv[1]);
455 }
456
457 static void
458 m_sjoin (sourceinfo_t *si, int parc, char *parv[])
459 {
460 /*
461 * -> :proteus.malkier.net SJOIN 1073516550 #shrike +tn :@sycobuny @+rakaur
462 * also:
463 * -> :nenolod_ SJOIN 1117334567 #chat
464 */
465
466 channel_t *c;
467 unsigned int userc;
468 char *userv[256];
469 unsigned int i;
470 time_t ts;
471
472 if (parc >= 4 && si->s != NULL)
473 {
474 /* :origin SJOIN ts chan modestr [key or limits] :users */
475 c = channel_find (parv[1]);
476 ts = atol (parv[0]);
477
478 if (!c)
479 {
480 slog (LG_DEBUG, "m_sjoin(): new channel: %s", parv[1]);
481 c = channel_add (parv[1], ts, si->s);
482 }
483
484 if (ts < c->ts)
485 {
486 chanuser_t *cu;
487 node_t *n;
488
489 /*
490 * the TS changed. a TS change requires the following things
491 * to be done to the channel: reset all modes to nothing, remove
492 * all status modes on known users on the channel (including ours),
493 * and set the new TS.
494 */
495
496 clear_simple_modes (c);
497
498 LIST_FOREACH (n, c->members.head)
499 {
500 cu = (chanuser_t *) n->data;
501 if (cu->user->server == me.me)
502 {
503 /* it's a service, reop */
504 sts (":%s PART %s :Reop", cu->user->nick, c->name);
505 sts (":%s SJOIN %ld %s + :@%s", me.name, ts, c->name, cu->user->nick);
506 cu->modes = CMODE_OP;
507 }
508 else
509 cu->modes = 0;
510 }
511
512 slog (LG_DEBUG, "m_sjoin(): TS changed for %s (%ld -> %ld)", c->name, c->ts, ts);
513
514 c->ts = ts;
515 c->callback.tschange (c);
516 }
517
518 channel_mode (NULL, c, parc - 3, parv + 2);
519
520 userc = sjtoken (parv[parc - 1], ' ', userv);
521
522 for (i = 0; i < userc; i++)
523 chanuser_add (c, userv[i]);
524
525 if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
526 channel_delete (c);
527 }
528 else if (parc >= 2 && si->su != NULL)
529 {
530 c = channel_find (parv[1]);
531 ts = atol (parv[0]);
532
533 if (c == NULL || ts < c->ts)
534 {
535 /* just request a resynch, this will include
536 * the user joining -- jilles */
537 slog (LG_DEBUG, "m_sjoin(): requesting resynch for %s", parv[1]);
538 sts ("RESYNCH %s", parv[1]);
539 return;
540 }
541
542 chanuser_add (c, CLIENT_NAME (si->su));
543 }
544 else
545 {
546 slog (LG_DEBUG, "m_sjoin(): invalid source/parameters: origin %s parc %d", si->su != NULL ? si->su->nick : (si->s != NULL ? si->s->name : "<none>"), parc);
547 }
548 }
549
550 static void
551 m_part (sourceinfo_t *si, int parc, char *parv[])
552 {
553 int chanc;
554 char *chanv[256];
555 int i;
556
557 chanc = sjtoken (parv[0], ',', chanv);
558 for (i = 0; i < chanc; i++)
559 {
560 slog (LG_DEBUG, "m_part(): user left channel: %s -> %s", si->su->nick, chanv[i]);
561
562 chanuser_delete (channel_find (chanv[i]), si->su);
563 }
564 }
565
566 static void
567 m_nick (sourceinfo_t *si, int parc, char *parv[])
568 {
569 server_t *s;
570 user_t *u;
571 char *ipbuf;
572 struct in_addr addr;
573 bool realchange;
574
575 if (parc == 12)
576 {
577 s = server_find (parv[8]);
578 if (!s)
579 {
580 slog (LG_DEBUG, "m_nick(): new user on nonexistant server: %s", parv[6]);
581 return;
582 }
583
584 slog (LG_DEBUG, "m_nick(): new user on `%s': %s", s->name, parv[0]);
585
586 addr.s_addr = htonl (strtoul (parv[10], NULL, 0));
587 ipbuf = inet_ntoa (addr);
588 u = user_add (parv[0], parv[5], parv[6], parv[7], ipbuf, NULL, parv[11], s, atoi (parv[2]));
589
590 /* user modes */
591 user_mode (u, parv[3]);
592 /* Oper Mode */
593 user_mode (u, parv[4]);
594
595 /*
596 * Ok, we have the user ready to go.
597 * Here's the deal -- if the user's SVID is before
598 * the start time, and not 0, then check to see
599 * if it's a registered account or not.
600 *
601 * If it IS registered, deal with that accordingly,
602 * via handle_burstlogin(). --nenolod
603 */
604 /* Changed to just check umode +r for now -- jilles */
605 #if 0
606 /* We can't be sure if this is safe, so disable it for now.
607 * (If ircd unsets +r on nick changes, it is safe.)
608 * If you know this is safe or want to port over the
609 * svsid stuff from unreal.c, you're welcome -- jilles */
610 if (strchr (parv[3], 'r'))
611 handle_burstlogin (u, NULL);
612 #endif
613
614 handle_nickchange (u);
615 }
616
617 /* if it's only 2 then it's a nickname change */
618 else if (parc == 2)
619 {
620 if (!si->su)
621 {
622 slog (LG_DEBUG, "m_nick(): server trying to change nick: %s", si->s != NULL ? si->s->name : "<none>");
623 return;
624 }
625
626 slog (LG_DEBUG, "m_nick(): nickname change from `%s': %s", si->su->nick, parv[0]);
627
628 realchange = irccasecmp (si->su->nick, parv[0]);
629
630 user_changenick (si->su, parv[0], atoi (parv[1]));
631
632 /* fix up +r if necessary -- jilles */
633 if (realchange && should_reg_umode (si->su))
634 /* changed nick to registered one, reset +r */
635 sts (":%s SVSMODE %s +rd %ld", me.name, parv[0], NOW);
636
637 handle_nickchange (si->su);
638 }
639 else
640 {
641 int i;
642
643 slog (LG_DEBUG, "m_nick(): got NICK with wrong number of params");
644
645 for (i = 0; i < parc; i++)
646 slog (LG_DEBUG, "m_nick(): parv[%d] = %s", i, parv[i]);
647 }
648 }
649
650 static void
651 m_quit (sourceinfo_t *si, int parc, char *parv[])
652 {
653 slog (LG_DEBUG, "m_quit(): user leaving: %s", si->su->nick);
654
655 /* user_delete() takes care of removing channels and so forth */
656 user_delete (si->su);
657 }
658
659 static void
660 m_mode (sourceinfo_t *si, int parc, char *parv[])
661 {
662 if (*parv[0] == '#')
663 channel_mode (NULL, channel_find (parv[0]), parc - 2, &parv[2]);
664 else
665 user_mode (user_find (parv[0]), parv[1]);
666 }
667
668 static void
669 m_kick (sourceinfo_t *si, int parc, char *parv[])
670 {
671 user_t *u = user_find (parv[1]);
672 channel_t *c = channel_find (parv[0]);
673
674 /* -> :rakaur KICK #shrike rintaun :test */
675 slog (LG_DEBUG, "m_kick(): user was kicked: %s -> %s", parv[1], parv[0]);
676
677 if (!u)
678 {
679 slog (LG_DEBUG, "m_kick(): got kick for nonexistant user %s", parv[1]);
680 return;
681 }
682
683 if (!c)
684 {
685 slog (LG_DEBUG, "m_kick(): got kick in nonexistant channel: %s", parv[0]);
686 return;
687 }
688
689 if (!chanuser_find (c, u))
690 {
691 slog (LG_DEBUG, "m_kick(): got kick for %s not in %s", u->nick, c->name);
692 return;
693 }
694
695 chanuser_delete (c, u);
696
697 /* if they kicked us, let's rejoin */
698 if (is_internal_client (u))
699 {
700 slog (LG_DEBUG, "m_kick(): %s got kicked from %s; rejoining", u->nick, parv[0]);
701 join (parv[0], u->nick);
702 }
703 }
704
705 static void
706 m_chghost (sourceinfo_t *si, int parc, char *parv[])
707 {
708 user_t *u = user_find (parv[0]);
709
710 if (!u)
711 return;
712
713 strlcpy (u->vhost, parv[1], HOSTLEN);
714 }
715
716 static void
717 m_kill (sourceinfo_t *si, int parc, char *parv[])
718 {
719 handle_kill (si, parv[0], parc > 1 ? parv[1] : "<No reason given>");
720 }
721
722 static void
723 m_squit (sourceinfo_t *si, int parc, char *parv[])
724 {
725 slog (LG_DEBUG, "m_squit(): server leaving: %s from %s", parv[0], parv[1]);
726 server_delete (parv[0]);
727 }
728
729 static void
730 m_server (sourceinfo_t *si, int parc, char *parv[])
731 {
732 server_t *s;
733
734 slog (LG_DEBUG, "m_server(): new server: %s", parv[0]);
735 s = handle_server (si, parv[0], NULL, atoi (parv[1]), parv[2]);
736
737 if (s != NULL && s->uplink != me.me)
738 {
739 /* elicit PONG for EOB detection; pinging uplink is
740 * already done elsewhere -- jilles
741 */
742 sts (":%s PING %s %s", me.name, me.name, s->name);
743 }
744 }
745
746 static void
747 m_stats (sourceinfo_t *si, int parc, char *parv[])
748 {
749 handle_stats (si->su, parv[0][0]);
750 }
751
752 static void
753 m_admin (sourceinfo_t *si, int parc, char *parv[])
754 {
755 handle_admin (si->su);
756 }
757
758 static void
759 m_version (sourceinfo_t *si, int parc, char *parv[])
760 {
761 handle_version (si->su);
762 }
763
764 static void
765 m_info (sourceinfo_t *si, int parc, char *parv[])
766 {
767 handle_info (si->su);
768 }
769
770 static void
771 m_whois (sourceinfo_t *si, int parc, char *parv[])
772 {
773 handle_whois (si->su, parv[1]);
774 }
775
776 static void
777 m_trace (sourceinfo_t *si, int parc, char *parv[])
778 {
779 handle_trace (si->su, parv[0], parc >= 2 ? parv[1] : NULL);
780 }
781
782 static void
783 m_away (sourceinfo_t *si, int parc, char *parv[])
784 {
785 handle_away (si->su, parc >= 1 ? parv[0] : NULL);
786 }
787
788 static void
789 m_join (sourceinfo_t *si, int parc, char *parv[])
790 {
791 chanuser_t *cu;
792 node_t *n, *tn;
793
794 /* JOIN 0 is really a part from all channels */
795 if (parv[0][0] == '0')
796 {
797 LIST_FOREACH_SAFE (n, tn, si->su->channels.head)
798 {
799 cu = (chanuser_t *) n->data;
800 chanuser_delete (cu->chan, si->su);
801 }
802 }
803 }
804
805 static void
806 m_pass (sourceinfo_t *si, int parc, char *parv[])
807 {
808 if (strcmp (curr_uplink->pass, parv[0]))
809 {
810 slog (LG_INFO, "m_pass(): password mismatch from uplink; aborting");
811 runflags |= RF_SHUTDOWN;
812 }
813 }
814
815 static void
816 m_error (sourceinfo_t *si, int parc, char *parv[])
817 {
818 slog (LG_INFO, "m_error(): error from server: %s", parv[0]);
819 }
820
821 static void
822 nick_group (mynick_t *mn, myuser_t *mu, sourceinfo_t *si)
823 {
824 user_t *u;
825
826 if (si->su != NULL && !irccasecmp (si->su->nick, mn->nick))
827 u = si->su;
828 else
829 u = user_find_named (mn->nick);
830
831 if (u != NULL && should_reg_umode (u))
832 sts (":%s SVSMODE %s +rd %ld", me.name, u->nick, NOW);
833 }
834
835 static void
836 nick_ungroup (mynick_t *mn, myuser_t *mu, sourceinfo_t *si)
837 {
838 user_t *u;
839
840 if (si->su != NULL && !irccasecmp (si->su->nick, mn->nick))
841 u = si->su;
842 else
843 u = user_find_named (mn->nick);
844
845 if (u != NULL && !nicksvs.no_nick_ownership)
846 sts (":%s SVSMODE %s -r+d %ld", me.name, u->nick, NOW);
847 }
848
849 static pcommand_t const pcommands[] = {
850 { "PING", m_ping, 1, MSRC_USER | MSRC_SERVER },
851 { "PONG", m_pong, 1, MSRC_SERVER },
852 { "PRIVMSG", m_privmsg, 2, MSRC_USER },
853 { "NOTICE", m_notice, 2, MSRC_UNREG | MSRC_USER | MSRC_SERVER },
854 { "SJOIN", m_sjoin, 2, MSRC_USER | MSRC_SERVER },
855 { "PART", m_part, 1, MSRC_USER },
856 { "NICK", m_nick, 2, MSRC_USER | MSRC_SERVER },
857 { "CLIENT", m_nick, 2, MSRC_USER | MSRC_SERVER },
858 { "QUIT", m_quit, 1, MSRC_USER },
859 { "MODE", m_mode, 2, MSRC_USER | MSRC_SERVER },
860 { "KICK", m_kick, 2, MSRC_USER | MSRC_SERVER },
861 { "KILL", m_kill, 1, MSRC_USER | MSRC_SERVER },
862 { "SQUIT", m_squit, 1, MSRC_USER | MSRC_SERVER },
863 { "SERVER", m_server, 3, MSRC_UNREG | MSRC_SERVER },
864 { "STATS", m_stats, 2, MSRC_USER },
865 { "ADMIN", m_admin, 1, MSRC_USER },
866 { "VERSION", m_version, 1, MSRC_USER },
867 { "INFO", m_info, 1, MSRC_USER },
868 { "WHOIS", m_whois, 2, MSRC_USER },
869 { "TRACE", m_trace, 1, MSRC_USER },
870 { "AWAY", m_away, 0, MSRC_USER },
871 { "JOIN", m_join, 1, MSRC_USER },
872 { "PASS", m_pass, 1, MSRC_UNREG },
873 { "ERROR", m_error, 1, MSRC_UNREG | MSRC_SERVER },
874 { "TOPIC", m_topic, 4, MSRC_USER | MSRC_SERVER },
875 { "CHGHOST", m_chghost, 2, MSRC_USER | MSRC_SERVER },
876 };
877
878 ultimate3_handler::ultimate3_handler ()
879 {
880 mode_list = ultimate3_mode_list;
881 ignore_mode_list = ultimate3_ignore_mode_list;
882 status_mode_list = ultimate3_status_mode_list;
883 prefix_mode_list = ultimate3_prefix_mode_list;
884
885 ircd = &ultimate3;
886
887 pcommand_add (&pcommands);
888
889 mynick_t::callback.group.attach (nick_group);
890 mynick_t::callback.ungroup.attach (nick_ungroup);
891 }
892
893 ultimate3_handler::~ultimate3_handler ()
894 {
895 mode_list = NULL;
896 ignore_mode_list = NULL;
897 status_mode_list = NULL;
898 prefix_mode_list = NULL;
899
900 ircd = NULL;
901
902 mynick_t::callback.group.detach (nick_group);
903 mynick_t::callback.ungroup.detach (nick_ungroup);
904
905 pcommand_delete (&pcommands);
906 }
907 } // namespace protocol
908
909 #define FACREG_TYPE protocol::ultimate3_handler
910 #define FACREG_TYPE_NAME "ultimate3"
911 #define FACREG_INTERFACE_TYPE protocol::handler
912 #include <ermyth/factory_reg.h>