ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/modules/protocol/solidircd.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: 30478 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

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