ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/protocol/officeirc.C
Revision: 1.5
Committed: Wed Sep 5 11:23:15 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.4: +3 -3 lines
Log Message:
removed GPLed code and put license back to BSD

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