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