ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/ptlink.C
Revision: 1.6
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +3 -2 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

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