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