ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/modules/protocol/bahamut.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 32708 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Bahamut protocol module for IRC Services.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #include "services.h"
11 #include "modules.h"
12 #include "conffile.h"
13 #include "language.h"
14 #include "messages.h"
15 #include "modules/operserv/operserv.h"
16 #include "modules/operserv/maskdata.h"
17 #include "modules/nickserv/nickserv.h"
18 #include "modules/chanserv/chanserv.h"
19
20 #define BAHAMUT_HACK /* For SJOIN; see comments in sjoin.c */
21 #include "banexcept.c"
22 #include "invitemask.c"
23 #include "sjoin.c"
24 #include "svsnick.c"
25
26 /*************************************************************************/
27
28 static Module *module_operserv;
29 static Module *module_chanserv;
30
31 static char *NetworkDomain = NULL;
32
33 static int32 usermode_secure = 0; /* +S */
34 static int32 chanmode_secure_only = 0; /* +S */
35
36 /*************************************************************************/
37 /***************** Local interface to external routines ******************/
38 /*************************************************************************/
39
40 static typeof(is_services_admin) *p_is_services_admin = NULL;
41
42 static int local_is_services_admin(User *u)
43 {
44 return p_is_services_admin && (*p_is_services_admin)(u);
45 }
46 #define is_services_admin local_is_services_admin
47
48 static char **p_s_ChanServ = &ServerName;
49 #define s_ChanServ (*p_s_ChanServ)
50
51 /*************************************************************************/
52 /************************** User/channel modes ***************************/
53 /*************************************************************************/
54
55 #define MI_SECURE 0x01000000 /* Usermode for users on secure conn's */
56 #define MI_SECURE_ONLY 0x01000000 /* Chanmode for secure-user-only chans */
57
58 struct modedata_init {
59 uint8 mode;
60 ModeData data;
61 };
62
63 static const struct modedata_init new_usermodes[] = {
64 {'g', {0x00000008}}, /* Receive globops */
65 {'h', {0x00000010}}, /* Helpop */
66 {'r', {0x00000020,0,0,0,MI_REGISTERED}},
67 /* Registered nick */
68 {'a', {0x00000040}}, /* Services admin */
69 {'A', {0x00000080}}, /* Server admin */
70 {'S', {0x00000100,0,0,0,MI_SECURE}},
71 /* Using secure connection */
72 };
73
74 static const struct modedata_init new_chanmodes[] = {
75 {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}},
76 /* Only identified users can join */
77 {'r', {0x00000200,0,0,0,MI_REGISTERED}},
78 /* Set for all registered channels */
79 {'c', {0x00000400,0,0}}, /* No ANSI colors in channel */
80 {'O', {0x00000800,0,0,0,MI_OPERS_ONLY}},
81 /* Only opers can join channel */
82 {'M', {0x02000000,0,0}}, /* Moderated to unregged nicks */
83 {'j', {0x04000000,1,0}}, /* /join rate limit */
84 {'S', {0x08000000,0,0,0,MI_SECURE_ONLY}},
85 /* Only secure (+S) users allowed */
86 {'e', {0x80000000,1,1,0,MI_MULTIPLE}},
87 /* Ban exceptions */
88 {'I', {0x80000000,1,1,0,MI_MULTIPLE}},
89 /* INVITE hosts */
90 };
91
92 static const struct modedata_init new_chanusermodes[] = {
93 };
94
95 static void init_modes(void)
96 {
97 int i;
98
99 for (i = 0; i < lenof(new_usermodes); i++) {
100 usermodes[new_usermodes[i].mode] = new_usermodes[i].data;
101 if (new_usermodes[i].data.info & MI_SECURE)
102 usermode_secure |= new_usermodes[i].data.flag;
103 }
104 for (i = 0; i < lenof(new_chanmodes); i++) {
105 chanmodes[new_chanmodes[i].mode] = new_chanmodes[i].data;
106 if (new_chanmodes[i].data.info & MI_SECURE_ONLY)
107 chanmode_secure_only |= new_chanmodes[i].data.flag;
108 }
109 for (i = 0; i < lenof(new_chanusermodes); i++)
110 chanusermodes[new_chanusermodes[i].mode] = new_chanusermodes[i].data;
111
112 mode_setup();
113 };
114
115 /*************************************************************************/
116 /************************* IRC message receiving *************************/
117 /*************************************************************************/
118
119 static void m_nick(char *source, int ac, char **av)
120 {
121 char ipbuf[16], *s;
122 uint32 ip;
123
124 if (*source) {
125 /* Old user changing nicks. */
126 if (ac != 2) {
127 module_log_debug(1, "NICK message: wrong number of parameters"
128 " (%d) for source `%s'", ac, source);
129 } else {
130 do_nick(source, ac, av);
131 }
132 return;
133 }
134
135 /* New user. */
136
137 if (ac != 10) {
138 module_log_debug(1, "NICK message: wrong number of parameters (%d)"
139 " for new user", ac);
140 return;
141 }
142
143 /* Move modes to the end, like do_nick() wants */
144 s = av[3];
145 memmove(&av[3], &av[4], sizeof(char *) * (ac-4));
146 av[9] = s;
147
148 /* Convert IP address from 32 bit integer to string format */
149 ip = strtoul(av[7], &s, 10);
150 if (*s) {
151 wallops(NULL,
152 "\2WARNING\2: invalid IP address `%s' for new nick %s",
153 av[7], av[0]);
154 module_log("WARNING: invalid IP address `%s' for new nick %s",
155 av[7], av[0]);
156 s = NULL;
157 } else if (!ip && find_module("operserv/sline")) {
158 static int warned_no_nickip = 0;
159 if (!warned_no_nickip) {
160 wallops(NULL, "\2WARNING\2: missing IP address for new nick %s",
161 av[0]);
162 warned_no_nickip = 1;
163 }
164 module_log("WARNING: missing IP address for new nick %s", av[0]);
165 s = strcpy(ipbuf, "0.0.0.0");
166 } else {
167 uint8 rawip[4];
168 rawip[0] = ip>>24;
169 rawip[1] = ip>>16;
170 rawip[2] = ip>>8;
171 rawip[3] = ip;
172 s = unpack_ip(rawip);
173 if (!s || strlen(s) > sizeof(ipbuf)-1) {
174 /* super duper paranoia */
175 module_log("WARNING: unpack_ip() returned overlong or null"
176 " string: %s", s ? s : "(null)");
177 s = NULL;
178 } else {
179 strcpy(ipbuf, s); /* safe: we checked length above */
180 s = ipbuf;
181 }
182 }
183
184 /* Rearrange parameters for do_nick() (IP address is in `s') */
185 av[7] = av[6];
186 av[6] = av[8];
187 av[8] = s;
188
189 do_nick(source, ac, av);
190 }
191
192 /*************************************************************************/
193
194 static void m_capab(char *source, int ac, char **av)
195 {
196 int i;
197
198 for (i = 0; i < ac; i++) {
199 if (stricmp(av[i], "NOQUIT") == 0)
200 protocol_features |= PF_NOQUIT;
201 }
202 }
203
204 /*************************************************************************/
205
206 static void m_sjoin(char *source, int ac, char **av)
207 {
208 if (ac == 3 || ac < 2) {
209 module_log_debug(1, "SJOIN: expected 2 or >=4 params, got %d", ac);
210 return;
211 }
212 do_sjoin(source, ac, av);
213 }
214
215 /*************************************************************************/
216
217 /* SVSMODE message handler. */
218
219 static void m_svsmode(char *source, int ac, char **av)
220 {
221 if (*av[0] == '#') {
222 if (ac >= 3 && strcmp(av[1],"-b") == 0) {
223 Channel *c = get_channel(av[0]);
224 User *u = get_user(av[2]);
225 if (c && u)
226 clear_channel(c, CLEAR_BANS, u);
227 } else {
228 module_log("Invalid SVSMODE from %s for channel %s: %s",
229 source, av[0], merge_args(ac-1,av+1));
230 }
231 } else if (*av[0] == '&') {
232 module_log("SVSMODE from %s for invalid target (channel %s): %s",
233 source, av[0], merge_args(ac-1,av+1));
234 } else {
235 if (ac < 2)
236 return;
237 if (ac >= 3 && (*av[2] == '+' || *av[2] == '-')) {
238 /* Move the timestamp to the end */
239 char *ts = av[1];
240 memmove(av+1, av+2, sizeof(char *) * (ac-2));
241 av[ac-1] = ts;
242 }
243 do_umode(source, ac, av);
244 }
245 }
246
247 /*************************************************************************/
248
249 /* SGLINE/SQLINE message handlers. These remove any SGLINE/SQLINE received
250 * which does not exist in Services' databases, to avoid servers which were
251 * split during an UNSGLINE/UNSQLINE re-propogating the mask across the
252 * network. See m_tkl() in unreal.c for details.
253 */
254
255 static void do_sgqline(char *source, int ac, char **av, int type)
256 {
257 typeof(get_maskdata) *p_get_maskdata = NULL;
258 typeof(put_maskdata) *p_put_maskdata = NULL;
259 char *mask;
260
261 if (ac != 2)
262 return;
263 if (type == MD_SGLINE) {
264 int masklen = strtol(av[0], NULL, 10);
265 mask = av[1];
266 if (masklen <= 0)
267 return;
268 mask[masklen] = 0;
269 } else { /* MD_SQLINE */
270 mask = av[0];
271 }
272 if (!(p_get_maskdata = get_module_symbol(NULL, "get_maskdata")))
273 return;
274 if (!(p_put_maskdata = get_module_symbol(NULL, "put_maskdata")))
275 return;
276 if ((*p_put_maskdata)((*p_get_maskdata)(type, mask)))
277 return;
278 send_cmd(ServerName, "UNS%cLINE :%s", type==MD_SGLINE ? 'G' : 'Q', mask);
279 }
280
281 static void m_sgline(char *source, int ac, char **av) {
282 do_sgqline(source, ac, av, MD_SGLINE);
283 }
284
285 static void m_sqline(char *source, int ac, char **av) {
286 do_sgqline(source, ac, av, MD_SQLINE);
287 }
288
289 /*************************************************************************/
290
291 /* Abbreviated message handlers.
292 * We do not allow Bahamut to run in SERVICESHUB mode because it cuts out
293 * both the topic burst (causing temporary desynch) and AWAY messages
294 * (causing MemoServ unaway checking to break).
295 */
296
297 #ifdef ALLOW_BAHAMUT_SERVICESHUB /* not defined anywhere */
298
299 static void expand_to_privmsg(char *source, const char *cmdname,
300 const char *targetsym, char *msg)
301 {
302 char **targetnick = NULL;
303
304 if (targetsym)
305 targetnick = get_module_symbol(NULL, targetsym);
306 if (targetnick) {
307 Message *m = find_message("PRIVMSG");
308 if (m) {
309 char *av[2];
310 av[0] = *targetnick;
311 av[1] = msg;
312 m->func(source, 2, av);
313 } else {
314 module_log("expand_to_privmsg(): BUG: PRIVMSG message entry not"
315 " found");
316 send_cmd(ServerName, "421 %s %s :Internal error", source, msg);
317 }
318 } else {
319 /* We don't know what command/nick the user originally used, so
320 * this is about the best we can do... */
321 send_cmd(ServerName, "421 %s %s :Command not available", source, msg);
322 }
323 }
324
325 static void m_ns(char *source, int ac, char **av) {
326 expand_to_privmsg(source, "NS", "s_NickServ", av[0]); }
327 static void m_cs(char *source, int ac, char **av) {
328 expand_to_privmsg(source, "CS", "s_ChanServ", av[0]); }
329 static void m_ms(char *source, int ac, char **av) {
330 expand_to_privmsg(source, "MS", "s_MemoServ", av[0]); }
331 static void m_rs(char *source, int ac, char **av) {
332 expand_to_privmsg(source, "RS", NULL /*"s_RootServ"*/, av[0]); }
333 static void m_os(char *source, int ac, char **av) {
334 expand_to_privmsg(source, "OS", "s_OperServ", av[0]); }
335 static void m_ss(char *source, int ac, char **av) {
336 expand_to_privmsg(source, "SS", "s_StatServ", av[0]); }
337 static void m_hs(char *source, int ac, char **av) {
338 expand_to_privmsg(source, "HS", "s_HelpServ", av[0]); }
339
340 #else
341
342 static void no_serviceshub(char *source, int ac, char **av)
343 {
344 fatal("IRC Services will not function correctly when Bahamut is"
345 " configured as a SERVICESHUB. Please reconfigure Bahamut as a"
346 " regular hub and restart Services.");
347 }
348
349 #define m_ns no_serviceshub
350 #define m_cs no_serviceshub
351 #define m_ms no_serviceshub
352 #define m_rs no_serviceshub
353 #define m_os no_serviceshub
354 #define m_ss no_serviceshub
355 #define m_hs no_serviceshub
356
357 #endif
358
359 /*************************************************************************/
360
361 /* SQUIT handler, for remote SQUITs (SQUITs from remote clients for juped
362 * servers). This has to be implemented as a "receive message" callback
363 * because we can't layer message functions on top of each other. */
364
365 static void do_bahamut_squit(char *source, int ac, char **av)
366 {
367 Server *server;
368
369 if (ac < 1) /* also checked in do_receive_message, but for completeness */
370 return;
371 server = get_server(av[0]);
372 if (!server) {
373 send_cmd(ServerName, "402 %s %s :No such server", source, av[0]);
374 } else if (!server->fake || server == get_server(ServerName)) {
375 /* We should never see an SQUIT for ourselves, since the remote
376 * server will disconnect us instead, but just in case... */
377 send_cmd(ServerName, "402 %s %s :Not a juped server", source, av[0]);
378 } else {
379 do_squit(source, ac, av);
380 send_cmd(NULL, "SQUIT %s :%s", av[0], av[1] ? av[1] : "");
381 }
382 }
383
384 static int do_receive_message(char *source, char *cmd, int ac, char **av)
385 {
386 if (irc_stricmp(cmd,"SQUIT") != 0)
387 return 0;
388 if (!source || !*source || ac < 1 || irc_stricmp(source,av[0]) == 0)
389 return 0;
390 do_bahamut_squit(source, ac, av);
391 return 1;
392 }
393
394 /*************************************************************************/
395
396 static Message bahamut_messages[] = {
397 { "AKILL", NULL },
398 { "CAPAB", m_capab },
399 { "CS", m_cs },
400 { "GLOBOPS", NULL },
401 { "GNOTICE", NULL },
402 { "GOPER", NULL },
403 { "HS", m_hs },
404 { "LOCKLUSERS",NULL },
405 { "MS", m_ms },
406 { "NICK", m_nick },
407 { "NS", m_ns },
408 { "OS", m_os },
409 { "RAKILL", NULL },
410 { "RS", m_rs },
411 { "SGLINE", m_sgline },
412 { "SILENCE", NULL },
413 { "SJOIN", m_sjoin },
414 { "SQLINE", m_sqline },
415 { "SS", m_ss },
416 { "SVINFO", NULL },
417 { "SVSMODE", m_svsmode },
418 { "UNSGLINE", NULL },
419 { "UNSQLINE", NULL },
420 { NULL }
421 };
422
423 /*************************************************************************/
424 /************************** IRC message sending **************************/
425 /*************************************************************************/
426
427 /* Send a NICK command for a new user. */
428
429 static void do_send_nick(const char *nick, const char *user, const char *host,
430 const char *server, const char *name,
431 const char *modes)
432 {
433 /* NICK <nick> <hops> <TS> <umode> <user> <host> <server> <svsid> <ip>
434 * :<ircname> */
435 send_cmd(NULL, "NICK %s 1 %ld +%s %s %s %s 0 0 :%s", nick,
436 (long)time(NULL), modes, user, host, server, name);
437 }
438
439 /*************************************************************************/
440
441 /* Send a NICK command to change an existing user's nick. */
442
443 static void do_send_nickchange(const char *nick, const char *newnick)
444 {
445 send_cmd(nick, "NICK %s %ld", newnick, (long)time(NULL));
446 }
447
448 /*************************************************************************/
449
450 /* Send a command to change a user's "real name". */
451
452 static void do_send_namechange(const char *nick, const char *newname)
453 {
454 /* Not supported by this protocol. */
455 }
456
457 /*************************************************************************/
458
459 /* Send a SERVER command, and anything else needed at the beginning of the
460 * connection.
461 */
462
463 static void do_send_server(void)
464 {
465 send_cmd(NULL, "PASS %s :TS", RemotePassword);
466 send_cmd(NULL, "CAPAB TS3 SSJOIN NICKIP NOQUIT TSMODE UNCONNECT");
467 send_cmd(NULL, "SERVER %s 1 :%s", ServerName, ServerDesc);
468 send_cmd(NULL, "SVINFO 3 3 0 :%ld", (long)time(NULL));
469 }
470
471 /*************************************************************************/
472
473 /* Send a SERVER command for a remote (juped) server. */
474
475 static void do_send_server_remote(const char *server, const char *reason)
476 {
477 send_cmd(NULL, "SERVER %s 2 :%s", server, reason);
478 }
479
480 /*************************************************************************/
481
482 /* Send a WALLOPS (really a GLOBOPS). */
483
484 static void do_wallops(const char *source, const char *fmt, ...)
485 {
486 va_list args;
487 char buf[BUFSIZE];
488
489 va_start(args, fmt);
490 vsnprintf(buf, sizeof(buf), fmt, args);
491 va_end(args);
492 send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
493 }
494
495 /*************************************************************************/
496
497 /* Send a NOTICE to all users on the network. */
498
499 static void do_notice_all(const char *source, const char *fmt, ...)
500 {
501 va_list args;
502 char msgbuf[BUFSIZE];
503
504 va_start(args, fmt);
505 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
506 va_end(args);
507 if (NetworkDomain) {
508 send_cmd(source, "NOTICE $*.%s :%s", NetworkDomain, msgbuf);
509 } else {
510 /* Go through all common top-level domains. If you have others,
511 * add them here. */
512 send_cmd(source, "NOTICE $*.com :%s", msgbuf);
513 send_cmd(source, "NOTICE $*.net :%s", msgbuf);
514 send_cmd(source, "NOTICE $*.org :%s", msgbuf);
515 send_cmd(source, "NOTICE $*.edu :%s", msgbuf);
516 }
517 }
518
519 /*************************************************************************/
520
521 /* Send a command which modifies channel status. */
522
523 static void do_send_channel_cmd(const char *source, const char *fmt, ...)
524 {
525 va_list args;
526
527 va_start(args, fmt);
528 vsend_cmd(source, fmt, args);
529 va_end(args);
530 }
531
532 /*************************************************************************/
533 /******************************* Callbacks *******************************/
534 /*************************************************************************/
535
536 static int do_user_servicestamp_change(User *user)
537 {
538 send_cmd(ServerName, "SVSMODE %s +d %u", user->nick, user->servicestamp);
539 return 0;
540 }
541
542 /*************************************************************************/
543
544 static int do_user_mode(User *user, int modechar, int add, char **av)
545 {
546 switch (modechar) {
547
548 case 'd':
549 module_log("MODE tried to change services stamp for %s", user->nick);
550 send_cmd(ServerName, "SVSMODE %s +d %u", user->nick,
551 user->servicestamp);
552 return 0;
553
554 case 'o':
555 if (add) {
556 user->mode |= UMODE_o;
557 if (add && user_identified(user) && is_services_admin(user))
558 send_cmd(ServerName, "SVSMODE %s +a", user->nick);
559 user->mode &= ~UMODE_o;
560 }
561 return 0;
562
563 case 'r':
564 if (user_identified(user)) {
565 if (!add)
566 send_cmd(ServerName, "SVSMODE %s +r", user->nick);
567 } else {
568 if (add)
569 send_cmd(ServerName, "SVSMODE %s -r", user->nick);
570 }
571 return 1;
572
573 case 'a':
574 if (is_oper(user)) {
575 if (is_services_admin(user)) {
576 if (!add)
577 send_cmd(ServerName, "SVSMODE %s +a", user->nick);
578 } else {
579 if (add)
580 send_cmd(ServerName, "SVSMODE %s -a", user->nick);
581 }
582 return 1;
583 }
584
585 } /* switch (mode) */
586
587 return 0;
588 }
589
590 /*************************************************************************/
591
592 static int do_channel_mode(const char *source, Channel *channel,
593 int modechar, int add, char **av)
594 {
595 int32 flag = mode_char_to_flag(modechar, MODE_CHANNEL);
596
597 switch (modechar) {
598 case 'j':
599 if (add) {
600 int ok = 0;
601 char *s;
602 int joinrate1 = strtol(av[0], &s, 0);
603 if (*s == ':') {
604 int joinrate2 = strtol(s+1, &s, 0);
605 if (!*s) {
606 if (joinrate1 && joinrate2) {
607 channel->mode |= flag;
608 channel->joinrate1 = joinrate1;
609 channel->joinrate2 = joinrate2;
610 } else {
611 channel->mode &= ~flag;
612 channel->joinrate1 = 0;
613 channel->joinrate2 = 0;
614 ok = 1;
615 }
616 ok = 1;
617 }
618 } else if (joinrate1 == 0) {
619 channel->mode &= ~flag;
620 channel->joinrate1 = 0;
621 channel->joinrate2 = 0;
622 ok = 1;
623 }
624 if (!ok) {
625 module_log("warning: invalid MODE +j %s for %s", av[0],
626 channel->name);
627 }
628 } else {
629 channel->mode &= ~flag;
630 channel->joinrate1 = 0;
631 channel->joinrate2 = 0;
632 }
633 return 1;
634 } /* switch (modechar) */
635 return 0;
636 }
637
638 /*************************************************************************/
639
640 static int do_nick_identified(User *u, int old_status)
641 {
642 if (is_oper(u) && is_services_admin(u))
643 send_cmd(ServerName, "SVSMODE %s +a", u->nick);
644 return 0;
645 }
646
647 /*************************************************************************/
648
649 static int do_set_topic(const char *source, Channel *c, const char *topic,
650 const char *setter, time_t t)
651 {
652 if (setter)
653 return 0;
654 c->topic_time = t;
655 send_cmd(source, "TOPIC %s %s %ld :%s", c->name, c->topic_setter,
656 (long)c->topic_time, c->topic ? c->topic : "");
657 return 1;
658 }
659
660 /*************************************************************************/
661
662 static int do_check_modes(Channel *c, ChannelInfo *ci, int add, int32 flag)
663 {
664 if (add) {
665 switch (mode_flag_to_char(flag, MODE_CHANNEL)) {
666 case 'j':
667 if (sgn(ci->mlock.joinrate1) != sgn(ci->mlock.joinrate2)) {
668 module_log("warning: removing +j from channel %s mode lock"
669 " (invalid parameter: %d:%d)", ci->name,
670 ci->mlock.joinrate1, ci->mlock.joinrate2);
671 ci->mlock.on &= ~mode_char_to_flag('j', MODE_CHANNEL);
672 ci->mlock.joinrate1 = ci->mlock.joinrate2 = 0;
673 } else if (ci->mlock.joinrate1 < 0) {
674 if (c->joinrate1 || c->joinrate2)
675 set_cmode(s_ChanServ, c, "-j");
676 } else {
677 if (c->joinrate1 != ci->mlock.joinrate1
678 || c->joinrate2 != ci->mlock.joinrate2
679 ) {
680 char buf[BUFSIZE];
681 snprintf(buf, sizeof(buf), "%d:%d",
682 ci->mlock.joinrate1, ci->mlock.joinrate2);
683 set_cmode(s_ChanServ, c, "+j", buf);
684 }
685 }
686 return 1;
687 }
688 }
689 return 0;
690 }
691
692 /*************************************************************************/
693
694 /*
695 * Callback for ChanServ channel entrance checking; we enforce the
696 * secure-only (+S) channel mode here.
697 */
698
699 static int do_check_kick(User *user, const char *chan, ChannelInfo *ci,
700 char **mask_ret, const char **reason_ret)
701 {
702 /* Retrieve the channel's Channel record, if present */
703 Channel *c = get_channel(chan);
704
705 /* Don't let users not on secure connections (-S) into +S channels */
706 if ((((c?c->mode:0) | (ci?ci->mlock.on:0)) & chanmode_secure_only)
707 && !(user->mode & usermode_secure)
708 ) {
709 *mask_ret = create_mask(user, 1);
710 *reason_ret = getstring(user->ngi, CHAN_NOT_ALLOWED_TO_JOIN);
711 return 1;
712 }
713
714 /* Let other processing continue as usual */
715 return 0;
716 }
717
718 /*************************************************************************/
719
720 static int do_set_mlock(User *u, ChannelInfo *ci, int mode, int add, char **av)
721 {
722 if (!mode) {
723 /* Final check of new mode lock--nothing to do */
724 return 0;
725 }
726
727 /* Single mode set/clear */
728
729 if (add) {
730
731 switch (mode) {
732 case 'j': {
733 int ok = 0;
734 char *s;
735 ci->mlock.joinrate1 = strtol(av[0], &s, 0);
736 if (ci->mlock.joinrate1 > 0 && *s == ':') {
737 ci->mlock.joinrate2 = strtol(s+1, &s, 0);
738 if (ci->mlock.joinrate2 > 0 && !*s)
739 ok = 1;
740 }
741 if (!ok) {
742 notice_lang(s_ChanServ, u, CHAN_SET_MLOCK_BAD_PARAM, mode);
743 return 1;
744 }
745 break;
746 } /* case 'j' */
747 } /* switch (mode) */
748
749 } else { /* !add -> lock off */
750
751 switch (mode) {
752 case 'j':
753 ci->mlock.joinrate1 = ci->mlock.joinrate2 = -1;
754 break;
755 } /* switch (mode) */
756
757 } /* if (add) */
758
759 return 0;
760 }
761
762 /*************************************************************************/
763
764 static int do_send_akill(const char *username, const char *host,
765 time_t expires, const char *who, const char *reason)
766 {
767 time_t now = time(NULL);
768
769 /* Bahamut 1.8.0 has a "feature" which converts an expiration delay of
770 * zero (supposedly "unlimited") into a delay of one week. Therefore,
771 * we have a "feature" which sends an unlimited expiration time as
772 * many years in the future. */
773 time_t length = ((expires && expires > now) ? expires - now : 0);
774 if (length == 0 && now < 0x7FFFFFFF)
775 length = 0x7FFFFFFF - now;
776
777 send_cmd(ServerName, "AKILL %s %s %ld %s %ld :%s", host, username,
778 (long)length, who ? who : "<unknown>", (long)now, reason);
779 return 1;
780 }
781
782 /*************************************************************************/
783
784 static int do_cancel_akill(const char *username, const char *host)
785 {
786 send_cmd(ServerName, "RAKILL %s %s", host, username);
787 return 1;
788 }
789
790 /*************************************************************************/
791
792 static int do_send_sgline(const char *mask, time_t expires, const char *who,
793 const char *reason)
794 {
795 send_cmd(ServerName, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
796 return 1;
797 }
798
799 static int do_send_sqline(const char *mask, time_t expires, const char *who,
800 const char *reason)
801 {
802 send_cmd(ServerName, "SQLINE %s :%s", mask, reason);
803 return 1;
804 }
805
806 static int do_send_szline(const char *mask, time_t expires, const char *who,
807 const char *reason)
808 {
809 return do_send_akill("*", mask, expires, who, reason);
810 }
811
812 /*************************************************************************/
813
814 static int do_cancel_sgline(const char *mask)
815 {
816 send_cmd(ServerName, "UNSGLINE :%s", mask);
817 return 1;
818 }
819
820 static int do_cancel_sqline(const char *mask)
821 {
822 send_cmd(ServerName, "UNSQLINE %s", mask);
823 return 1;
824 }
825
826 static int do_cancel_szline(const char *mask)
827 {
828 return do_cancel_akill("*", mask);
829 return 1;
830 }
831
832 /*************************************************************************/
833 /***************************** Module stuff ******************************/
834 /*************************************************************************/
835
836 ConfigDirective module_config[] = {
837 { "NetworkDomain", { { CD_STRING, 0, &NetworkDomain } } },
838 SJOIN_CONFIG,
839 { NULL }
840 };
841
842 /*************************************************************************/
843
844 static int do_load_module(Module *mod, const char *modname)
845 {
846 if (strcmp(modname, "operserv/main") == 0) {
847 module_operserv = mod;
848 p_is_services_admin = get_module_symbol(mod, "is_services_admin");
849 if (!p_is_services_admin) {
850 module_log("warning: unable to look up symbol `is_services_admin'"
851 " in module `operserv/main'");
852 }
853 } else if (strcmp(modname, "operserv/akill") == 0) {
854 if (!add_callback(mod, "send_akill", do_send_akill))
855 module_log("Unable to add send_akill callback");
856 if (!add_callback(mod, "cancel_akill", do_cancel_akill))
857 module_log("Unable to add cancel_akill callback");
858 } else if (strcmp(modname, "operserv/sline") == 0) {
859 if (!add_callback(mod, "send_sgline", do_send_sgline))
860 module_log("Unable to add send_sgline callback");
861 if (!add_callback(mod, "send_sqline", do_send_sqline))
862 module_log("Unable to add send_sqline callback");
863 if (!add_callback(mod, "send_szline", do_send_szline))
864 module_log("Unable to add send_szline callback");
865 if (!add_callback(mod, "cancel_sgline", do_cancel_sgline))
866 module_log("Unable to add cancel_sgline callback");
867 if (!add_callback(mod, "cancel_sqline", do_cancel_sqline))
868 module_log("Unable to add cancel_sqline callback");
869 if (!add_callback(mod, "cancel_szline", do_cancel_szline))
870 module_log("Unable to add cancel_szline callback");
871 } else if (strcmp(modname, "nickserv/main") == 0) {
872 if (!add_callback(mod, "identified", do_nick_identified))
873 module_log("Unable to add NickServ identified callback");
874 } else if (strcmp(modname, "chanserv/main") == 0) {
875 module_chanserv = mod;
876 p_s_ChanServ = get_module_symbol(mod, "s_ChanServ");
877 if (!p_s_ChanServ)
878 p_s_ChanServ = &ServerName;
879 if (!add_callback(mod, "check_modes", do_check_modes))
880 module_log("Unable to add ChanServ check_modes callback");
881 if (!add_callback(mod, "check_kick", do_check_kick))
882 module_log("Unable to add ChanServ check_kick callback");
883 if (!add_callback(mod, "SET MLOCK", do_set_mlock))
884 module_log("Unable to add ChanServ SET MLOCK callback");
885 }
886 return 0;
887 }
888
889 /*************************************************************************/
890
891 static int do_unload_module(Module *mod)
892 {
893 if (mod == module_operserv) {
894 module_operserv = NULL;
895 p_is_services_admin = NULL;
896 } else if (mod == module_chanserv) {
897 module_chanserv = NULL;
898 p_s_ChanServ = &ServerName;
899 }
900 return 0;
901 }
902
903 /*************************************************************************/
904
905 int init_module(void)
906 {
907 unsigned char c;
908
909
910 protocol_name = "Bahamut";
911 protocol_version = "1.8.0+";
912 protocol_features = PF_SZLINE | PF_MODETS_FIRST;
913 protocol_nickmax = 30;
914
915 if (!register_messages(bahamut_messages)) {
916 module_log("Unable to register messages");
917 exit_module(1);
918 return 0;
919 }
920
921 if (!add_callback(NULL, "load module", do_load_module)
922 || !add_callback(NULL, "unload module", do_unload_module)
923 || !add_callback(NULL, "receive message", do_receive_message)
924 || !add_callback(NULL, "user servicestamp change",
925 do_user_servicestamp_change)
926 || !add_callback(NULL, "channel MODE", do_channel_mode)
927 || !add_callback(NULL, "user MODE", do_user_mode)
928 || !add_callback(NULL, "set topic", do_set_topic)
929 ) {
930 module_log("Unable to add callbacks");
931 exit_module(1);
932 return 0;
933 }
934
935 if (!init_banexcept()
936 || !init_invitemask()
937 || !init_sjoin()
938 || !init_svsnick("SVSNICK")
939 ) {
940 exit_module(1);
941 return 0;
942 }
943
944 init_modes();
945
946 irc_lowertable['['] = '[';
947 irc_lowertable['\\'] = '\\';
948 irc_lowertable[']'] = ']';
949 for (c = 0; c < 32; c++)
950 valid_chan_table[c] = 0;
951 valid_chan_table[160] = 0;
952
953 send_nick = do_send_nick;
954 send_nickchange = do_send_nickchange;
955 send_namechange = do_send_namechange;
956 send_server = do_send_server;
957 send_server_remote = do_send_server_remote;
958 wallops = do_wallops;
959 notice_all = do_notice_all;
960 send_channel_cmd = do_send_channel_cmd;
961 pseudoclient_modes = "";
962 enforcer_modes = "";
963 pseudoclient_oper = 0;
964
965 mapstring(OPER_BOUNCY_MODES, OPER_BOUNCY_MODES_U_LINE);
966
967 return 1;
968 }
969
970 /*************************************************************************/
971
972 int exit_module(int shutdown)
973 {
974 if (!shutdown) {
975 /* Do not allow removal */
976 return 0;
977 }
978
979 exit_svsnick();
980 exit_sjoin();
981 exit_invitemask();
982 exit_banexcept();
983 remove_callback(NULL, "set topic", do_set_topic);
984 remove_callback(NULL, "user MODE", do_user_mode);
985 remove_callback(NULL, "channel MODE", do_channel_mode);
986 remove_callback(NULL, "user servicestamp change",
987 do_user_servicestamp_change);
988 remove_callback(NULL, "receive message", do_receive_message);
989 remove_callback(NULL, "unload module", do_unload_module);
990 remove_callback(NULL, "load module", do_load_module);
991 unregister_messages(bahamut_messages);
992 return 1;
993 }
994
995 /*************************************************************************/
996
997 /*
998 * Local variables:
999 * c-file-style: "stroustrup"
1000 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
1001 * indent-tabs-mode: nil
1002 * End:
1003 *
1004 * vim: expandtab shiftwidth=4:
1005 */