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

File Contents

# Content
1 /* PTlink 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 "version.h"
16 #include "modules/operserv/operserv.h"
17 #include "modules/operserv/maskdata.h"
18 #include "modules/nickserv/nickserv.h"
19 #include "modules/chanserv/chanserv.h"
20
21 #include "banexcept.c"
22 #include "sjoin.c"
23 #include "svsnick.c"
24
25 /*************************************************************************/
26
27 /* "Nick" to use to indicate Services-set GLINEs */
28 #define GLINE_WHO "<ircservices>"
29
30
31 static Module *module_operserv;
32
33 static char *NetworkDomain = NULL;
34
35 static int32 usermode_admin = 0; /* +aANT */
36 static int32 usermode_hiding = 0; /* +S */
37 static int32 chanmode_admins_only = 0; /* +A */
38
39 /*************************************************************************/
40 /***************** Local interface to external routines ******************/
41 /*************************************************************************/
42
43 static typeof(is_services_admin) *p_is_services_admin = NULL;
44
45 static int local_is_services_admin(User *u)
46 {
47 return p_is_services_admin && (*p_is_services_admin)(u);
48 }
49 #define is_services_admin local_is_services_admin
50
51 /*************************************************************************/
52 /************************** User/channel modes ***************************/
53 /*************************************************************************/
54
55 struct modedata_init {
56 uint8 mode;
57 ModeData data;
58 };
59
60 #define MI_ADMIN 0x01000000 /* Usermode given to admins */
61 #define MI_HIDING 0x02000000 /* Usermode for hiding users */
62 #define MI_ADMINS_ONLY 0x01000000 /* Chanmode for admin-only channels */
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 {'N', {0x00000100,0,0,0,MI_ADMIN}},
72 /* Network admin */
73 {'T', {0x00000200,0,0,0,MI_ADMIN}},
74 /* Technical admin */
75 /* Flags in this range are used by Unreal */
76 {'S', {0x00002000,0,0,0,MI_HIDING}},
77 /* Stealth mode (hides joins etc) */
78 {'B', {0x00004000}}, /* Is a bot ("deaf" in Unreal) */
79 {'R', {0x00008000}}, /* Allow PRIVMSGs from +r clients only */
80 {'p', {0x00010000}}, /* Private (don't show channels in /whois) */
81 {'v', {0x00020000}}, /* Don't allow DCCs */
82 };
83
84 static const struct modedata_init new_chanmodes[] = {
85 {'R', {0x00000100,0,0,0,MI_REGNICKS_ONLY}},
86 /* Only identified users can join */
87 {'r', {0x00000200,0,0,0,MI_REGISTERED}},
88 /* Set for all registered channels */
89 {'c', {0x00000400,0,0}}, /* No ANSI colors in channel */
90 {'O', {0x00000800,0,0,0,MI_OPERS_ONLY}},
91 /* Only opers can join channel */
92 {'A', {0x00001000,0,0,0,MI_OPERS_ONLY|MI_ADMINS_ONLY}},
93 /* Only admins can join channel */
94 {'c', {0x00100000,0,0}}, /* Strip colors */
95 {'d', {0x00800000,0,0}}, /* No flooding */
96 {'S', {0x04000000,0,0}}, /* No spam */
97 {'q', {0x08000000,0,0}}, /* No quits */
98 {'K', {0x10000000,0,0}}, /* Send knock message on failed join */
99 {'e', {0x80000000,1,1,0,MI_MULTIPLE}},
100 /* Ban exceptions */
101 };
102
103 static const struct modedata_init new_chanusermodes[] = {
104 {'a', {0x00000010,1,1,'.'}}, /* Channel owner */
105 };
106
107 static void init_modes(void)
108 {
109 int i;
110
111 for (i = 0; i < lenof(new_usermodes); i++) {
112 usermodes[new_usermodes[i].mode] = new_usermodes[i].data;
113 if (new_usermodes[i].data.info & MI_ADMIN)
114 usermode_admin |= new_usermodes[i].data.flag;
115 if (new_usermodes[i].data.info & MI_HIDING)
116 usermode_hiding |= new_usermodes[i].data.flag;
117 }
118 for (i = 0; i < lenof(new_chanmodes); i++) {
119 chanmodes[new_chanmodes[i].mode] = new_chanmodes[i].data;
120 if (new_chanmodes[i].data.info & MI_ADMINS_ONLY)
121 chanmode_admins_only |= new_chanmodes[i].data.flag;
122 }
123 for (i = 0; i < lenof(new_chanusermodes); i++)
124 chanusermodes[new_chanusermodes[i].mode] = new_chanusermodes[i].data;
125
126 mode_setup();
127 };
128
129 /*************************************************************************/
130 /************************* IRC message receiving *************************/
131 /*************************************************************************/
132
133 static void m_nick(char *source, int ac, char **av)
134 {
135 char *newav[11];
136
137 if (*source) {
138 /* Old user changing nicks. */
139 if (ac != 2) {
140 module_log_debug(1, "NICK message: wrong number of parameters"
141 " (%d) for source `%s'", ac, source);
142 } else {
143 do_nick(source, ac, av);
144 }
145 return;
146 }
147
148 /* New user. */
149 if (ac != 9) {
150 module_log_debug(1, "NICK message: wrong number of parameters (%d)"
151 " for new user", ac);
152 return;
153 }
154 newav[ 0] = av[0]; /* Nick */
155 newav[ 1] = av[1]; /* Hop count */
156 newav[ 2] = av[2]; /* Timestamp */
157 newav[ 3] = av[4]; /* Username */
158 newav[ 4] = av[5]; /* Hostname */
159 newav[ 5] = av[7]; /* Server */
160 newav[ 6] = av[8]; /* Real name */
161 newav[ 7] = NULL; /* Services stamp */
162 newav[ 8] = NULL; /* IP address */
163 newav[ 9] = av[3]; /* Modes */
164 newav[10] = av[6]; /* User area (fake hostname) */
165 do_nick(source, 11, newav);
166 }
167
168 /*************************************************************************/
169
170 static void m_capab(char *source, int ac, char **av)
171 {
172 char *s;
173 int got_PTS4 = 0;
174 int got_QS = 0;
175 int got_EX = 0;
176
177 if (ac < 1) {
178 module_log("received CAPAB with no parameters--broken ircd?");
179 } else {
180 for (s = strtok(av[0]," "); s; s = strtok(NULL," ")) {
181 if (stricmp(s, "PTS4") == 0)
182 got_PTS4 = 1;
183 else if (stricmp(s, "QS") == 0)
184 got_QS = 1;
185 else if (stricmp(s, "EX") == 0)
186 got_EX = 1;
187 }
188 }
189 if (!got_PTS4 || !got_QS || !got_EX) {
190 module_log("CAPAB: capabilities missing:%s%s%s",
191 got_PTS4 ? "" : " PTS4",
192 got_QS ? "" : " QS",
193 got_EX ? "" : " EX");
194 send_error("Need PTS4/QS/EX capabilities");
195 strbcpy(quitmsg, "Remote server doesn't support all of PTS4/QS/EX");
196 quitting = 1;
197 }
198 }
199
200 /*************************************************************************/
201
202 static void m_svinfo(char *source, int ac, char **av)
203 {
204 if (ac < 2) {
205 module_log("received SVINFO with <2 parameters--broken ircd?");
206 send_error("Invalid SVINFO received (at least 2 parameters needed)");
207 quitting = 1;
208 } else {
209 if (atoi(av[1]) > 6 || atoi(av[0]) < 6) {
210 send_error("Need protocol version 6 support");
211 strbcpy(quitmsg,
212 "Remote server doesn't support protocol version 6");
213 quitting = 1;
214 }
215 }
216 }
217
218 /*************************************************************************/
219
220 static void m_sjoin(char *source, int ac, char **av)
221 {
222 if (ac < 4) {
223 module_log("SJOIN: expected >=4 params, got %d (broken ircd?)", ac);
224 return;
225 }
226 do_sjoin(source, ac, av);
227 }
228
229 /*************************************************************************/
230
231 static void m_newmask(char *source, int ac, char **av)
232 {
233 char *newuser, *newhost;
234 User *u;
235
236 if (ac < 1) {
237 module_log("NEWUSER: parameters missing--broken ircd?");
238 return;
239 }
240 if (!(u = get_user(source))) {
241 module_log("got NEWUSER from nonexistent user %s", source);
242 return;
243 }
244 newuser = av[0];
245 newhost = strchr(newuser, '@');
246 if (newhost)
247 *newhost++ = 0;
248 else
249 newhost = "";
250 free(u->username);
251 u->username = sstrdup(newuser);
252 free(u->host);
253 u->host = sstrdup(newhost);
254 }
255
256 /*************************************************************************/
257
258 /* GLINE/SGLINE/SQLINE handling: cancel any Services-set lines from remote
259 * servers (see comments in unreal.c/m_tkl() for details).
260 */
261
262 static void m_gline(char *source, int ac, char **av)
263 {
264 typeof(get_maskdata) *p_get_maskdata = NULL;
265 typeof(put_maskdata) *p_put_maskdata = NULL;
266
267 if (ac < 3 || strcmp(av[2], GLINE_WHO) != 0)
268 return;
269 if (!(p_get_maskdata = get_module_symbol(NULL, "get_maskdata")))
270 return;
271 if (!(p_put_maskdata = get_module_symbol(NULL, "put_maskdata")))
272 return;
273 if ((*p_put_maskdata)((*p_get_maskdata)(MD_AKILL, av[0])))
274 return;
275 send_cmd(ServerName, "UNGLINE :%s", av[0]);
276 }
277
278 static void m_sgline(char *source, int ac, char **av)
279 {
280 typeof(get_maskdata) *p_get_maskdata = NULL;
281 typeof(put_maskdata) *p_put_maskdata = NULL;
282 int masklen;
283
284 if (ac < 3)
285 return;
286 masklen = atoi(av[1]);
287 if (masklen < strlen(av[2]))
288 av[2][masklen] = 0;
289 if (!(p_get_maskdata = get_module_symbol(NULL, "get_maskdata")))
290 return;
291 if (!(p_put_maskdata = get_module_symbol(NULL, "put_maskdata")))
292 return;
293 if ((*p_put_maskdata)((*p_get_maskdata)(MD_SGLINE, av[2])))
294 return;
295 send_cmd(ServerName, "UNSGLINE :%s", av[2]);
296 }
297
298 static void m_sqline(char *source, int ac, char **av)
299 {
300 typeof(get_maskdata) *p_get_maskdata = NULL;
301 typeof(put_maskdata) *p_put_maskdata = NULL;
302
303 if (ac < 1)
304 return;
305 if (!(p_get_maskdata = get_module_symbol(NULL, "get_maskdata")))
306 return;
307 if (!(p_put_maskdata = get_module_symbol(NULL, "put_maskdata")))
308 return;
309 if ((*p_put_maskdata)((*p_get_maskdata)(MD_SQLINE, av[0])))
310 return;
311 send_cmd(ServerName, "UNSQLINE :%s", av[0]);
312 }
313
314 /*************************************************************************/
315
316 static Message ptlink_messages[] = {
317 { "CAPAB", m_capab },
318 { "GLINE", m_gline },
319 { "GLOBOPS", NULL },
320 { "GNOTICE", NULL },
321 { "GOPER", NULL },
322 { "NEWMASK", m_newmask },
323 { "NICK", m_nick },
324 { "SILENCE", NULL },
325 { "SJOIN", m_sjoin },
326 { "SGLINE", m_sgline },
327 { "SQLINE", m_sqline },
328 { "SVINFO", m_svinfo },
329 { "SVLINE", NULL },
330 { "UNGLINE", NULL },
331 { "UNSGLINE", NULL },
332 { "UNSQLINE", NULL },
333 { "UNSVLINE", NULL },
334 { "UNZOMBIE", NULL },
335 { "ZOMBIE", NULL },
336 { NULL }
337 };
338
339 /*************************************************************************/
340 /************************** IRC message sending **************************/
341 /*************************************************************************/
342
343 /* Send a NICK command for a new user. */
344
345 static void do_send_nick(const char *nick, const char *user, const char *host,
346 const char *server, const char *name,
347 const char *modes)
348 {
349 /* NICK <nick> <hops> <TS> <umode> <user> <host> <fakehost> <server>
350 * :<ircname> */
351 send_cmd(NULL, "NICK %s 1 %ld +%s %s %s %s %s 0 :%s", nick,
352 (long)time(NULL), modes, user, host, host, server, name);
353 }
354
355 /*************************************************************************/
356
357 /* Send a NICK command to change an existing user's nick. */
358
359 static void do_send_nickchange(const char *nick, const char *newnick)
360 {
361 send_cmd(nick, "NICK %s %ld", newnick, (long)time(NULL));
362 }
363
364 /*************************************************************************/
365
366 /* Send a command to change a user's "real name". */
367
368 static void do_send_namechange(const char *nick, const char *newname)
369 {
370 /* Not supported by this protocol. */
371 }
372
373 /*************************************************************************/
374
375 /* Send a SERVER command, and anything else needed at the beginning of the
376 * connection.
377 */
378
379 static void do_send_server(void)
380 {
381 Module *mod;
382 int32 maxusercnt = 0;
383
384 send_cmd(NULL, "PASS %s :TS", RemotePassword);
385 send_cmd(NULL, "CAPAB :PTS4 QS EX");
386 send_cmd(NULL, "SERVER %s 1 ircservices-%s :%s", ServerName,
387 version_number, ServerDesc);
388 send_cmd(NULL, "SVINFO 6 6");
389 if ((mod = find_module("operserv/main")) != NULL) {
390 typeof(get_operserv_data) *p_get_operserv_data;
391 p_get_operserv_data = get_module_symbol(mod, "get_operserv_data");
392 if (p_get_operserv_data)
393 p_get_operserv_data(OSDATA_MAXUSERCNT, &maxusercnt);
394 }
395 send_cmd(NULL, "SVSINFO %ld %d", (long)start_time, maxusercnt);
396 }
397
398 /*************************************************************************/
399
400 /* Send a SERVER command for a remote (juped) server. */
401
402 static void do_send_server_remote(const char *server, const char *reason)
403 {
404 send_cmd(NULL, "SERVER %s 2 :%s", server, reason);
405 }
406
407 /*************************************************************************/
408
409 /* Send a WALLOPS (really a GLOBOPS). */
410
411 static void do_wallops(const char *source, const char *fmt, ...)
412 {
413 va_list args;
414 char buf[BUFSIZE];
415
416 va_start(args, fmt);
417 vsnprintf(buf, sizeof(buf), fmt, args);
418 va_end(args);
419 send_cmd(source ? source : ServerName, "GLOBOPS :%s", buf);
420 }
421
422 /*************************************************************************/
423
424 /* Send a NOTICE to all users on the network. */
425
426 static void do_notice_all(const char *source, const char *fmt, ...)
427 {
428 va_list args;
429 char msgbuf[BUFSIZE];
430
431 va_start(args, fmt);
432 vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
433 va_end(args);
434 if (NetworkDomain) {
435 send_cmd(source, "NOTICE $*.%s :%s", NetworkDomain, msgbuf);
436 } else {
437 /* Go through all common top-level domains. If you have others,
438 * add them here. */
439 send_cmd(source, "NOTICE $*.com :%s", msgbuf);
440 send_cmd(source, "NOTICE $*.net :%s", msgbuf);
441 send_cmd(source, "NOTICE $*.org :%s", msgbuf);
442 send_cmd(source, "NOTICE $*.edu :%s", msgbuf);
443 }
444 }
445
446 /*************************************************************************/
447
448 /* Send a command which modifies channel status. */
449
450 static void do_send_channel_cmd(const char *source, const char *fmt, ...)
451 {
452 va_list args;
453
454 va_start(args, fmt);
455 vsend_cmd(ServerName, fmt, args);
456 va_end(args);
457 }
458
459 /*************************************************************************/
460 /******************************* Callbacks *******************************/
461 /*************************************************************************/
462
463 static int do_user_create(User *user, int ac, char **av)
464 {
465 user->fakehost = sstrdup(av[9]);
466 return 0;
467 }
468
469 /*************************************************************************/
470
471 static int do_user_mode(User *user, int modechar, int add, char **av)
472 {
473 switch (modechar) {
474 case 'o':
475 if (add) {
476 user->mode |= UMODE_o;
477 if (add && user_identified(user) && is_services_admin(user))
478 send_cmd(ServerName, "SVSMODE %s +a", user->nick);
479 user->mode &= ~UMODE_o;
480 }
481 return 0;
482
483 case 'r':
484 if (user_identified(user)) {
485 if (!add)
486 send_cmd(ServerName, "SVSMODE %s +r", user->nick);
487 } else {
488 if (add)
489 send_cmd(ServerName, "SVSMODE %s -r", user->nick);
490 }
491 return 1;
492
493 case 'a':
494 if (is_oper(user)) {
495 if (is_services_admin(user)) {
496 if (!add)
497 send_cmd(ServerName, "SVSMODE %s +a", user->nick);
498 } else {
499 if (add)
500 send_cmd(ServerName, "SVSMODE %s -a", user->nick);
501 }
502 return 1;
503 }
504 }
505 return 0;
506 }
507
508 /*************************************************************************/
509
510 static int do_nick_identified(User *u, int old_status)
511 {
512 if (is_oper(u) && is_services_admin(u))
513 send_cmd(ServerName, "SVSMODE %s +a", u->nick);
514 return 0;
515 }
516
517 /*************************************************************************/
518
519 static int do_set_topic(const char *source, Channel *c, const char *topic,
520 const char *setter, time_t t)
521 {
522 if (setter)
523 return 0;
524 c->topic_time = t;
525 send_cmd(source, "TOPIC %s %s %ld :%s", c->name, c->topic_setter,
526 (long)c->topic_time, c->topic ? c->topic : "");
527 return 1;
528 }
529
530 /*************************************************************************/
531
532 static int do_check_chan_user_modes(const char *source, User *user,
533 Channel *c, int32 modes)
534 {
535 /* Don't do anything to hiding users */
536 return ((user->mode & usermode_hiding) ? 1 : 0);
537 }
538
539 /*************************************************************************/
540
541 static int do_check_kick(User *user, const char *chan, ChannelInfo *ci,
542 char **mask_ret, const char **reason_ret)
543 {
544 Channel *c = get_channel(chan);
545
546 /* Don't let plain opers into +A (admin only) channels */
547 if ((((c?c->mode:0) | (ci?ci->mlock.on:0)) & chanmode_admins_only)
548 && !(user->mode & usermode_admin)
549 ) {
550 *mask_ret = create_mask(user, 1);
551 *reason_ret = getstring(user->ngi, CHAN_NOT_ALLOWED_TO_JOIN);
552 return 1;
553 }
554 return 0;
555 }
556
557 /*************************************************************************/
558
559 static int do_send_akill(const char *username, const char *host,
560 time_t expires, const char *who, const char *reason)
561 {
562 time_t now = time(NULL);
563
564 send_cmd(ServerName, "GLINE %s@%s %ld %s :%s", username, host,
565 (long)((expires && expires > now) ? expires - now : 0),
566 GLINE_WHO, reason);
567 return 1;
568 }
569
570 /*************************************************************************/
571
572 static int do_cancel_akill(const char *username, const char *host)
573 {
574 send_cmd(ServerName, "UNGLINE %s@%s", username, host);
575 return 1;
576 }
577
578 /*************************************************************************/
579
580 static int do_send_sgline(const char *mask, time_t expires, const char *who,
581 const char *reason)
582 {
583 send_cmd(ServerName, "SGLINE %d :%s:%s", (int)strlen(mask), mask, reason);
584 return 1;
585 }
586
587 static int do_send_sqline(const char *mask, time_t expires, const char *who,
588 const char *reason)
589 {
590 send_cmd(ServerName, "SQLINE %s :%s", mask, reason);
591 return 1;
592 }
593
594 /*************************************************************************/
595
596 static int do_cancel_sgline(const char *mask)
597 {
598 send_cmd(ServerName, "UNSGLINE :%s", mask);
599 return 1;
600 }
601
602 static int do_cancel_sqline(const char *mask)
603 {
604 send_cmd(ServerName, "UNSQLINE %s", mask);
605 return 1;
606 }
607
608 /*************************************************************************/
609 /***************************** Module stuff ******************************/
610 /*************************************************************************/
611
612 ConfigDirective module_config[] = {
613 { "NetworkDomain", { { CD_STRING, 0, &NetworkDomain } } },
614 SJOIN_CONFIG,
615 { NULL }
616 };
617
618 /*************************************************************************/
619
620 static int do_load_module(Module *mod, const char *modname)
621 {
622 if (strcmp(modname, "operserv/main") == 0) {
623 module_operserv = mod;
624 p_is_services_admin = get_module_symbol(mod, "is_services_admin");
625 if (!p_is_services_admin) {
626 module_log("warning: unable to look up symbol `is_services_admin'"
627 " in module `operserv/main'");
628 }
629 } else if (strcmp(modname, "operserv/akill") == 0) {
630 if (!add_callback(mod, "send_akill", do_send_akill))
631 module_log("Unable to add send_akill callback");
632 if (!add_callback(mod, "cancel_akill", do_cancel_akill))
633 module_log("Unable to add cancel_akill callback");
634 } else if (strcmp(modname, "operserv/sline") == 0) {
635 if (!add_callback(mod, "send_sgline", do_send_sgline))
636 module_log("Unable to add send_sgline callback");
637 if (!add_callback(mod, "send_sqline", do_send_sqline))
638 module_log("Unable to add send_sqline callback");
639 if (!add_callback(mod, "cancel_sgline", do_cancel_sgline))
640 module_log("Unable to add cancel_sgline callback");
641 if (!add_callback(mod, "cancel_sqline", do_cancel_sqline))
642 module_log("Unable to add cancel_sqline callback");
643 } else if (strcmp(modname, "nickserv/main") == 0) {
644 if (!add_callback(mod, "identified", do_nick_identified))
645 module_log("Unable to add NickServ identified callback");
646 } else if (strcmp(modname, "chanserv/main") == 0) {
647 if (!add_callback(mod, "check_chan_user_modes",
648 do_check_chan_user_modes))
649 module_log("Unable to add ChanServ check_chan_user_modes"
650 " callback");
651 if (!add_callback(mod, "check_kick", do_check_kick))
652 module_log("Unable to add ChanServ check_kick callback");
653 }
654 return 0;
655 }
656
657 /*************************************************************************/
658
659 static int do_unload_module(Module *mod)
660 {
661 if (mod == module_operserv) {
662 module_operserv = NULL;
663 p_is_services_admin = NULL;
664 }
665 return 0;
666 }
667
668 /*************************************************************************/
669
670 int init_module(void)
671 {
672 unsigned char c;
673
674
675 protocol_name = "PTlink";
676 protocol_version = "6.x";
677 protocol_features = PF_BANEXCEPT | PF_NOQUIT;
678 protocol_nickmax = 20;
679
680 if (!register_messages(ptlink_messages)) {
681 module_log("Unable to register messages");
682 exit_module(1);
683 return 0;
684 }
685
686 if (!add_callback(NULL, "load module", do_load_module)
687 || !add_callback(NULL, "unload module", do_unload_module)
688 || !add_callback(NULL, "user create", do_user_create)
689 || !add_callback(NULL, "user MODE", do_user_mode)
690 || !add_callback(NULL, "set topic", do_set_topic)
691 ) {
692 module_log("Unable to add callbacks");
693 exit_module(1);
694 return 0;
695 }
696
697 if (!init_banexcept() || !init_sjoin() || !init_svsnick("SVSNICK")) {
698 exit_module(1);
699 return 0;
700 }
701
702 init_modes();
703
704 irc_lowertable['['] = '[';
705 irc_lowertable['\\'] = '\\';
706 irc_lowertable[']'] = ']';
707 /* Note that PTlink extended character sets are not supported */
708 valid_nick_table['\\'] = 0;
709 for (c = 0; c < 32; c++)
710 valid_chan_table[c] = 0;
711 valid_chan_table['\\'] = 0;
712 valid_chan_table[160] = 0;
713
714 send_nick = do_send_nick;
715 send_nickchange = do_send_nickchange;
716 send_namechange = do_send_namechange;
717 send_server = do_send_server;
718 send_server_remote = do_send_server_remote;
719 wallops = do_wallops;
720 notice_all = do_notice_all;
721 send_channel_cmd = do_send_channel_cmd;
722 pseudoclient_modes = "";
723 enforcer_modes = "";
724 pseudoclient_oper = 0;
725
726 mapstring(OPER_BOUNCY_MODES, OPER_BOUNCY_MODES_U_LINE);
727
728 return 1;
729 }
730
731 /*************************************************************************/
732
733 int exit_module(int shutdown)
734 {
735 if (!shutdown) {
736 /* Do not allow removal */
737 return 0;
738 }
739
740 exit_svsnick();
741 exit_sjoin();
742 exit_banexcept();
743 remove_callback(NULL, "set topic", do_set_topic);
744 remove_callback(NULL, "user MODE", do_user_mode);
745 remove_callback(NULL, "user create", do_user_create);
746 remove_callback(NULL, "unload module", do_unload_module);
747 remove_callback(NULL, "load module", do_load_module);
748 unregister_messages(ptlink_messages);
749 return 1;
750 }
751
752 /*************************************************************************/
753
754 /*
755 * Local variables:
756 * c-file-style: "stroustrup"
757 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
758 * indent-tabs-mode: nil
759 * End:
760 *
761 * vim: expandtab shiftwidth=4:
762 */