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