/[cvs]/eggdrop1.9/src/tcl.c
ViewVC logotype

Contents of /eggdrop1.9/src/tcl.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.100 - (show annotations) (download) (as text)
Tue Feb 25 06:52:19 2003 UTC (16 years, 4 months ago) by stdarg
Branch: MAIN
CVS Tags: HEAD
Changes since 1.99: +1 -1 lines
File MIME type: text/x-chdr
FILE REMOVED
* Well, I think Tcl is finally removed from the core (except for detection/configuration).

1 /*
2 * tcl.c --
3 *
4 * the code for every command eggdrop adds to Tcl
5 * Tcl initialization
6 * getting and setting Tcl/eggdrop variables
7 */
8 /*
9 * Copyright (C) 1997 Robey Pointer
10 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Eggheads Development Team
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #ifndef lint
28 static const char rcsid[] = "$Id: tcl.c,v 1.99 2003/02/18 10:37:18 stdarg Exp $";
29 #endif
30
31 #include <stdlib.h> /* getenv() */
32 #include <locale.h> /* setlocale() */
33 #include "main.h"
34 #include "logfile.h"
35 #include "misc.h"
36 #include "chanprog.h" /* masktype */
37
38 /* Used for read/write to internal strings */
39 typedef struct {
40 char *str; /* Pointer to actual string in eggdrop */
41 int max; /* max length (negative: read-only var
42 when protect is on) (0: read-only ALWAYS) */
43 int flags; /* 1 = directory */
44 } strinfo;
45
46 typedef struct {
47 int *var;
48 int ro;
49 } intinfo;
50
51
52 extern time_t online_since;
53
54 extern int flood_telnet_thr, flood_telnet_time, learn_users, default_flags,
55 conmask, firewallport, notify_users_at, ignore_time,
56 reserved_port_min, reserved_port_max, die_on_sighup, die_on_sigterm,
57 dcc_total, raw_log, identtimeout, egg_numver, userfile_perm,
58 default_uflags, strict_host;
59
60 extern char botuser[], motdfile[], admin[], userfile[], firewall[], helpdir[],
61 notify_new[], myip[], moddir[], tempdir[], owner[], network[],
62 myname[], bannerfile[], egg_version[], natip[], configfile[],
63 textdir[], myip6[], pid_file[];
64
65 extern struct dcc_t *dcc;
66
67 int protect_readonly = 0; /* turn on/off readonly protection */
68 char whois_fields[1025] = ""; /* fields to display in a .whois */
69 Tcl_Interp *interp; /* eggdrop always uses the same interpreter */
70 int use_invites = 0;
71 int use_exempts = 0;
72 int force_expire = 0;
73 int copy_to_tmp = 0;
74 int quiet_reject = 1;
75 int par_telnet_flood = 1;
76 int handlen = HANDLEN;
77
78 /* Prototypes for tcl */
79 Tcl_Interp *Tcl_CreateInterp();
80
81
82 static void myname_change(char *new)
83 {
84 if (strcasecmp(myname, new)) {
85 if (myname[0])
86 putlog(LOG_MISC, "*", "* IDENTITY CHANGE: %s -> %s", myname, new);
87 strcpy(myname, new);
88 }
89 }
90
91
92 /*
93 * Vars, traces, misc
94 */
95
96 /* Used for read/write to integer couplets */
97 typedef struct {
98 int *left; /* left side of couplet */
99 int *right; /* right side */
100 } coupletinfo;
101
102 /* Read/write integer couplets (int1:int2) */
103 static char *tcl_eggcouplet(ClientData cdata, Tcl_Interp *irp, char *name1,
104 char *name2, int flags)
105 {
106 char *s, s1[41];
107 coupletinfo *cp = (coupletinfo *) cdata;
108
109 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
110 snprintf(s1, sizeof s1, "%d:%d", *(cp->left), *(cp->right));
111 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
112 if (flags & TCL_TRACE_UNSETS)
113 Tcl_TraceVar(interp, name1,
114 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
115 tcl_eggcouplet, cdata);
116 } else { /* writes */
117 s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
118 if (s != NULL) {
119 int nr1, nr2;
120
121 if (strlen(s) > 40)
122 s[40] = 0;
123 sscanf(s, "%d%*c%d", &nr1, &nr2);
124 *(cp->left) = nr1;
125 *(cp->right) = nr2;
126 }
127 }
128 return NULL;
129 }
130
131 /* Read or write normal integer.
132 */
133 static char *tcl_eggint(ClientData cdata, Tcl_Interp *irp, char *name1,
134 char *name2, int flags)
135 {
136 char *s, s1[40];
137 long l;
138 intinfo *ii = (intinfo *) cdata;
139
140 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
141 /* Special cases */
142 if ((int *) ii->var == &conmask)
143 strcpy(s1, masktype(conmask));
144 else if ((int *) ii->var == &default_flags) {
145 struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
146 fr.global = default_flags;
147 fr.udef_global = default_uflags;
148 build_flags(s1, &fr, 0);
149 } else if ((int *) ii->var == &userfile_perm) {
150 snprintf(s1, sizeof s1, "0%o", userfile_perm);
151 } else
152 snprintf(s1, sizeof s1, "%d", *(int *) ii->var);
153 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
154 if (flags & TCL_TRACE_UNSETS)
155 Tcl_TraceVar(interp, name1,
156 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
157 tcl_eggint, cdata);
158 return NULL;
159 } else { /* Writes */
160 s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
161 if (s != NULL) {
162 if ((int *) ii->var == &conmask) {
163 if (s[0])
164 conmask = logmodes(s);
165 else
166 conmask = 0x7fffffff;
167 } else if ((int *) ii->var == &default_flags) {
168 struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
169
170 break_down_flags(s, &fr, 0);
171 default_flags = sanity_check(fr.global); /* drummer */
172 default_uflags = fr.udef_global;
173 } else if ((ii->ro == 2) || ((ii->ro == 1) && protect_readonly)) {
174 return "read-only variable";
175 } else {
176 if (Tcl_ExprLong(interp, s, &l) == TCL_ERROR)
177 return interp->result;
178 else
179 *(ii->var) = (int) l;
180 }
181 }
182 return NULL;
183 }
184 }
185
186 /* Read/write normal string variable
187 */
188 static char *tcl_eggstr(ClientData cdata, Tcl_Interp *irp, char *name1,
189 char *name2, int flags)
190 {
191 char *s;
192 strinfo *st = (strinfo *) cdata;
193
194 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
195 if ((st->str == firewall) && (firewall[0])) {
196 char s1[127];
197
198 snprintf(s1, sizeof s1, "%s:%d", firewall, firewallport);
199 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
200 } else
201 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
202 if (flags & TCL_TRACE_UNSETS) {
203 Tcl_TraceVar(interp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
204 TCL_TRACE_UNSETS, tcl_eggstr, cdata);
205 if ((st->max <= 0) && (protect_readonly || (st->max == 0)))
206 return "read-only variable"; /* it won't return the error... */
207 }
208 return NULL;
209 } else { /* writes */
210 if ((st->max <= 0) && (protect_readonly || (st->max == 0))) {
211 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
212 return "read-only variable";
213 }
214 s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
215 if (s != NULL) {
216 if (strlen(s) > abs(st->max))
217 s[abs(st->max)] = 0;
218 if (st->str == myname)
219 myname_change(s);
220 else if (st->str == firewall) {
221 splitc(firewall, s, ':');
222 if (!firewall[0])
223 strcpy(firewall, s);
224 else
225 firewallport = atoi(s);
226 } else
227 strcpy(st->str, s);
228 if ((st->flags) && (s[0])) {
229 if (st->str[strlen(st->str) - 1] != '/')
230 strcat(st->str, "/");
231 }
232 }
233 return NULL;
234 }
235 }
236
237 /* Add/remove tcl commands
238 */
239 void add_tcl_commands(tcl_cmds *tab)
240 {
241 int i;
242
243 for (i = 0; tab[i].name; i++)
244 Tcl_CreateCommand(interp, tab[i].name, tab[i].func, NULL, NULL);
245 }
246
247 void rem_tcl_commands(tcl_cmds *tab)
248 {
249 int i;
250
251 for (i = 0; tab[i].name; i++)
252 Tcl_DeleteCommand(interp, tab[i].name);
253 }
254
255 /* Strings */
256 static tcl_strings def_tcl_strings[] =
257 {
258 {"myname", myname, HANDLEN, 0},
259 {"userfile", userfile, 120, STR_PROTECT},
260 {"motd", motdfile, 120, STR_PROTECT},
261 {"admin", admin, 120, 0},
262 {"help_path", helpdir, 120, STR_DIR | STR_PROTECT},
263 {"temp_path", tempdir, 120, STR_DIR | STR_PROTECT},
264 {"text_path", textdir, 120, STR_DIR | STR_PROTECT},
265 {"mod_path", moddir, 120, STR_DIR | STR_PROTECT},
266 {"notify_newusers", notify_new, 120, 0},
267 {"owner", owner, 120, STR_PROTECT},
268 {"my_ip", myip, 120, 0},
269 {"my_ip6", myip6, 120, 0},
270 {"network", network, 40, 0},
271 {"whois_fields", whois_fields, 1024, 0},
272 {"nat_ip", natip, 120, 0},
273 {"username", botuser, 10, 0},
274 {"version", egg_version, 0, 0},
275 {"firewall", firewall, 120, 0},
276 /* confvar patch by aaronwl */
277 {"config", configfile, 0, 0},
278 {"telnet_banner", bannerfile, 120, STR_PROTECT},
279 {"pidfile", pid_file, 120, STR_PROTECT},
280 {NULL, NULL, 0, 0}
281 };
282
283 /* Ints */
284 static tcl_ints def_tcl_ints[] =
285 {
286 {"ignore_time", &ignore_time, 0},
287 {"handlen", &handlen, 2},
288 {"hourly_updates", &notify_users_at, 0},
289 {"learn_users", &learn_users, 0},
290 {"uptime", (int *) &online_since, 2},
291 {"console", &conmask, 0},
292 {"default_flags", &default_flags, 0},
293 {"numversion", &egg_numver, 2},
294 {"die_on_sighup", &die_on_sighup, 1},
295 {"die_on_sigterm", &die_on_sigterm, 1},
296 {"raw_log", &raw_log, 1},
297 {"use_exempts", &use_exempts, 0},
298 {"use_invites", &use_invites, 0},
299 {"force_expire", &force_expire, 0},
300 {"strict_host", &strict_host, 0},
301 {"userfile_perm", &userfile_perm, 0},
302 {"copy-to-tmp", &copy_to_tmp, 0},
303 {"quiet-reject", &quiet_reject, 0},
304 {NULL, NULL, 0}
305 };
306
307 static tcl_coups def_tcl_coups[] =
308 {
309 {"telnet_flood", &flood_telnet_thr, &flood_telnet_time},
310 {"reserved_portrange", &reserved_port_min, &reserved_port_max},
311 {NULL, NULL, NULL}
312 };
313
314 /* Set up Tcl variables that will hook into eggdrop internal vars via
315 * trace callbacks.
316 */
317 static void init_traces()
318 {
319 add_tcl_coups(def_tcl_coups);
320 add_tcl_strings(def_tcl_strings);
321 add_tcl_ints(def_tcl_ints);
322 }
323
324 void kill_tcl()
325 {
326 rem_tcl_coups(def_tcl_coups);
327 rem_tcl_strings(def_tcl_strings);
328 rem_tcl_ints(def_tcl_ints);
329 Tcl_DeleteInterp(interp);
330 }
331
332 extern tcl_cmds tcldcc_cmds[];
333
334 /* Not going through Tcl's crazy main() system (what on earth was he
335 * smoking?!) so we gotta initialize the Tcl interpreter
336 */
337 void init_tcl(int argc, char **argv)
338 {
339 #ifndef HAVE_PRE7_5_TCL
340 int j;
341 char pver[1024] = "";
342 #endif
343
344 /* This must be done *BEFORE* Tcl_SetSystemEncoding(),
345 * or Tcl_SetSystemEncoding() will cause a segfault.
346 */
347 #ifndef HAVE_PRE7_5_TCL
348 /* This is used for 'info nameofexecutable'.
349 * The filename in argv[0] must exist in a directory listed in
350 * the environment variable PATH for it to register anything.
351 */
352 Tcl_FindExecutable(argv[0]);
353 #endif
354
355 /* Initialize the interpreter */
356 interp = Tcl_CreateInterp();
357
358 #ifdef DEBUG
359 /* Initialize Tcl's memory debugging if we want it */
360 Tcl_InitMemory(interp);
361 #endif
362
363 /* Set Tcl variable tcl_interactive to 0 */
364 Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
365
366 /* Setup script library facility */
367 Tcl_Init(interp);
368
369 #ifndef HAVE_PRE7_5_TCL
370 /* Add eggdrop to Tcl's package list */
371 for (j = 0; j <= strlen(egg_version); j++) {
372 if ((egg_version[j] == ' ') || (egg_version[j] == '+'))
373 break;
374 pver[strlen(pver)] = egg_version[j];
375 }
376 Tcl_PkgProvide(interp, "eggdrop", pver);
377 #endif
378
379 /* Initialize traces */
380 init_traces();
381 }
382
383 void do_tcl(char *whatzit, char *script)
384 {
385 int code;
386
387 code = Tcl_Eval(interp, script);
388 if (code != TCL_OK) {
389 putlog(LOG_MISC, "*", "TCL error in script for '%s':", whatzit);
390 putlog(LOG_MISC, "*", "%s", interp->result);
391 }
392 }
393
394 /* Interpret tcl file fname.
395 *
396 * returns: 1 - if everything was okay
397 */
398 int readtclprog(char *fname)
399 {
400 if (!file_readable(fname))
401 return 0;
402
403 if (Tcl_EvalFile(interp, fname) != TCL_OK) {
404 putlog(LOG_MISC, "*", "TCL error in file '%s':", fname);
405 putlog(LOG_MISC, "*", "%s",
406 Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
407 return 0;
408 }
409
410 /* Refresh internal variables */
411 return 1;
412 }
413
414 void add_tcl_strings(tcl_strings *list)
415 {
416 int i;
417 strinfo *st;
418 int tmp;
419
420 for (i = 0; list[i].name; i++) {
421 st = (strinfo *) malloc(sizeof(strinfo));
422 st->max = list[i].length - (list[i].flags & STR_DIR);
423 if (list[i].flags & STR_PROTECT)
424 st->max = -st->max;
425 st->str = list[i].buf;
426 st->flags = (list[i].flags & STR_DIR);
427 tmp = protect_readonly;
428 protect_readonly = 0;
429 tcl_eggstr((ClientData) st, interp, list[i].name, NULL, TCL_TRACE_WRITES);
430 protect_readonly = tmp;
431 tcl_eggstr((ClientData) st, interp, list[i].name, NULL, TCL_TRACE_READS);
432 Tcl_TraceVar(interp, list[i].name, TCL_TRACE_READS | TCL_TRACE_WRITES |
433 TCL_TRACE_UNSETS, tcl_eggstr, (ClientData) st);
434 }
435 }
436
437 void rem_tcl_strings(tcl_strings *list)
438 {
439 int i;
440 strinfo *st;
441
442 for (i = 0; list[i].name; i++) {
443 st = (strinfo *) Tcl_VarTraceInfo(interp, list[i].name,
444 TCL_TRACE_READS |
445 TCL_TRACE_WRITES |
446 TCL_TRACE_UNSETS,
447 tcl_eggstr, NULL);
448 Tcl_UntraceVar(interp, list[i].name,
449 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
450 tcl_eggstr, st);
451 if (st != NULL)
452 free(st);
453 }
454 }
455
456 void add_tcl_ints(tcl_ints *list)
457 {
458 int i, tmp;
459 intinfo *ii;
460
461 for (i = 0; list[i].name; i++) {
462 ii = malloc(sizeof(intinfo));
463 ii->var = list[i].val;
464 ii->ro = list[i].readonly;
465 tmp = protect_readonly;
466 protect_readonly = 0;
467 tcl_eggint((ClientData) ii, interp, list[i].name, NULL, TCL_TRACE_WRITES);
468 protect_readonly = tmp;
469 tcl_eggint((ClientData) ii, interp, list[i].name, NULL, TCL_TRACE_READS);
470 Tcl_TraceVar(interp, list[i].name,
471 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
472 tcl_eggint, (ClientData) ii);
473 }
474
475 }
476
477 void rem_tcl_ints(tcl_ints *list)
478 {
479 int i;
480 intinfo *ii;
481
482 for (i = 0; list[i].name; i++) {
483 ii = (intinfo *) Tcl_VarTraceInfo(interp, list[i].name,
484 TCL_TRACE_READS |
485 TCL_TRACE_WRITES |
486 TCL_TRACE_UNSETS,
487 tcl_eggint, NULL);
488 Tcl_UntraceVar(interp, list[i].name,
489 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
490 tcl_eggint, (ClientData) ii);
491 if (ii)
492 free(ii);
493 }
494 }
495
496 /* Allocate couplet space for tracing couplets
497 */
498 void add_tcl_coups(tcl_coups *list)
499 {
500 coupletinfo *cp;
501 int i;
502
503 for (i = 0; list[i].name; i++) {
504 cp = (coupletinfo *) malloc(sizeof(coupletinfo));
505 cp->left = list[i].lptr;
506 cp->right = list[i].rptr;
507 tcl_eggcouplet((ClientData) cp, interp, list[i].name, NULL,
508 TCL_TRACE_WRITES);
509 tcl_eggcouplet((ClientData) cp, interp, list[i].name, NULL,
510 TCL_TRACE_READS);
511 Tcl_TraceVar(interp, list[i].name,
512 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
513 tcl_eggcouplet, (ClientData) cp);
514 }
515 }
516
517 void rem_tcl_coups(tcl_coups * list)
518 {
519 coupletinfo *cp;
520 int i;
521
522 for (i = 0; list[i].name; i++) {
523 cp = (coupletinfo *) Tcl_VarTraceInfo(interp, list[i].name,
524 TCL_TRACE_READS |
525 TCL_TRACE_WRITES |
526 TCL_TRACE_UNSETS,
527 tcl_eggcouplet, NULL);
528 Tcl_UntraceVar(interp, list[i].name,
529 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
530 tcl_eggcouplet, (ClientData) cp);
531 free(cp);
532 }
533 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23