1 |
/* |
2 |
* tcl.c -- handles: |
3 |
* the code for every command eggdrop adds to Tcl |
4 |
* Tcl initialization |
5 |
* getting and setting Tcl/eggdrop variables |
6 |
* |
7 |
* dprintf'ized, 4feb1996 |
8 |
*/ |
9 |
/* |
10 |
* This file is part of the eggdrop source code |
11 |
* copyright (c) 1997 Robey Pointer |
12 |
* and is distributed according to the GNU general public license. |
13 |
* For full details, read the top of 'main.c' or the file called |
14 |
* COPYING that was distributed with this code. |
15 |
*/ |
16 |
|
17 |
#include "main.h" |
18 |
|
19 |
/* used for read/write to internal strings */ |
20 |
typedef struct { |
21 |
char *str; /* pointer to actual string in eggdrop */ |
22 |
int max; /* max length (negative: read-only var when protect is on) */ |
23 |
/* (0: read-only ALWAYS) */ |
24 |
int flags; /* 1 = directory */ |
25 |
} strinfo; |
26 |
|
27 |
typedef struct { |
28 |
int *var; |
29 |
int ro; |
30 |
} intinfo; |
31 |
|
32 |
int protect_readonly = 0; /* turn on/off readonly protection */ |
33 |
char whois_fields[121] = ""; /* fields to display in a .whois */ |
34 |
Tcl_Interp *interp; /* eggdrop always uses the same interpreter */ |
35 |
|
36 |
extern int backgrd, flood_telnet_thr, flood_telnet_time; |
37 |
extern int shtime, share_greet, require_p, keep_all_logs; |
38 |
extern int use_stderr, allow_new_telnets, stealth_telnets, use_telnet_banner; |
39 |
extern int default_flags, conmask, switch_logfiles_at, connect_timeout; |
40 |
extern int firewallport, reserved_port, notify_users_at; |
41 |
extern int flood_thr, ignore_time; |
42 |
extern char origbotname[], botuser[], motdfile[], admin[], userfile[], |
43 |
firewall[], helpdir[], notify_new[], hostname[], myip[], moddir[], |
44 |
tempdir[], owner[], network[], botnetnick[], bannerfile[]; |
45 |
extern int die_on_sighup, die_on_sigterm, max_logs, max_logsize, enable_simul; |
46 |
extern int dcc_total, debug_output, identtimeout, protect_telnet; |
47 |
extern int egg_numver, share_unlinks, dcc_sanitycheck, sort_users; |
48 |
extern struct dcc_t *dcc; |
49 |
extern char egg_version[]; |
50 |
extern tcl_timer_t *timer, *utimer; |
51 |
extern time_t online_since; |
52 |
extern log_t *logs; |
53 |
extern int tands; |
54 |
extern int resolve_timeout; |
55 |
extern char natip[]; |
56 |
extern int default_uflags; /* drummer */ |
57 |
|
58 |
/* confvar patch by aaronwl */ |
59 |
extern char configfile[]; |
60 |
int dcc_flood_thr = 3; |
61 |
int debug_tcl = 0; |
62 |
int use_silence = 0; |
63 |
int use_invites = 0; /* Jason/drummer */ |
64 |
int use_exempts = 0; /* Jason/drummer */ |
65 |
int force_expire = 0; /* Rufus */ |
66 |
int remote_boots = 2; |
67 |
int allow_dk_cmds = 1; |
68 |
int must_be_owner = 1; |
69 |
int max_dcc = 20; /* needs at least 4 or 5 just to get started |
70 |
* 20 should be enough */ |
71 |
int min_dcc_port = 1024; /* dcc-portrange, min port - dw/guppy */ |
72 |
int max_dcc_port = 65535; /* dcc-portrange, max port - dw/guppy */ |
73 |
int quick_logs = 0; /* quick write logs? |
74 |
* flush em every min instead of every 5 */ |
75 |
int par_telnet_flood = 1; /* trigger telnet flood for +f ppl? - dw */ |
76 |
|
77 |
/* prototypes for tcl */ |
78 |
Tcl_Interp *Tcl_CreateInterp(); |
79 |
int strtot = 0; |
80 |
|
81 |
int expmem_tcl() |
82 |
{ |
83 |
int i, tot = 0; |
84 |
|
85 |
context; |
86 |
for (i = 0; i < max_logs; i++) |
87 |
if (logs[i].filename != NULL) { |
88 |
tot += strlen(logs[i].filename) + 1; |
89 |
tot += strlen(logs[i].chname) + 1; |
90 |
} |
91 |
return tot + strtot; |
92 |
} |
93 |
|
94 |
/***********************************************************************/ |
95 |
|
96 |
/* logfile [<modes> <channel> <filename>] */ |
97 |
static int tcl_logfile STDVAR |
98 |
{ |
99 |
int i; |
100 |
char s[151]; |
101 |
|
102 |
BADARGS(1, 4, " ?logModes channel logFile?"); |
103 |
if (argc == 1) { |
104 |
/* they just want a list of the logfiles and modes */ |
105 |
for (i = 0; i < max_logs; i++) |
106 |
if (logs[i].filename != NULL) { |
107 |
strcpy(s, masktype(logs[i].mask)); |
108 |
strcat(s, " "); |
109 |
strcat(s, logs[i].chname); |
110 |
strcat(s, " "); |
111 |
strcat(s, logs[i].filename); |
112 |
Tcl_AppendElement(interp, s); |
113 |
} |
114 |
return TCL_OK; |
115 |
} |
116 |
BADARGS(4, 4, " ?logModes channel logFile?"); |
117 |
for (i = 0; i < max_logs; i++) |
118 |
if ((logs[i].filename != NULL) && (!strcmp(logs[i].filename, argv[3]))) { |
119 |
logs[i].mask = logmodes(argv[1]); |
120 |
nfree(logs[i].chname); |
121 |
logs[i].chname = NULL; |
122 |
if (!logs[i].mask) { |
123 |
/* ending logfile */ |
124 |
nfree(logs[i].filename); |
125 |
logs[i].filename = NULL; |
126 |
if (logs[i].f != NULL) { |
127 |
fclose(logs[i].f); |
128 |
logs[i].f = NULL; |
129 |
} |
130 |
} else { |
131 |
logs[i].chname = (char *) nmalloc(strlen(argv[2]) + 1); |
132 |
strcpy(logs[i].chname, argv[2]); |
133 |
} |
134 |
Tcl_AppendResult(interp, argv[3], NULL); |
135 |
return TCL_OK; |
136 |
} |
137 |
for (i = 0; i < max_logs; i++) |
138 |
if (logs[i].filename == NULL) { |
139 |
logs[i].mask = logmodes(argv[1]); |
140 |
logs[i].filename = (char *) nmalloc(strlen(argv[3]) + 1); |
141 |
strcpy(logs[i].filename, argv[3]); |
142 |
logs[i].chname = (char *) nmalloc(strlen(argv[2]) + 1); |
143 |
strcpy(logs[i].chname, argv[2]); |
144 |
Tcl_AppendResult(interp, argv[3], NULL); |
145 |
return TCL_OK; |
146 |
} |
147 |
Tcl_AppendResult(interp, "reached max # of logfiles", NULL); |
148 |
return TCL_ERROR; |
149 |
} |
150 |
|
151 |
int findidx(int z) |
152 |
{ |
153 |
int j; |
154 |
|
155 |
for (j = 0; j < dcc_total; j++) |
156 |
if ((dcc[j].sock == z) && (dcc[j].type->flags & DCT_VALIDIDX)) |
157 |
return j; |
158 |
return -1; |
159 |
} |
160 |
|
161 |
static void botnet_change(char *new) |
162 |
{ |
163 |
if (strcasecmp(botnetnick, new) != 0) { |
164 |
/* trying to change bot's nickname */ |
165 |
if (tands > 0) { |
166 |
putlog(LOG_MISC, "*", "* Tried to change my botnet nick, but I'm still linked to a botnet."); |
167 |
putlog(LOG_MISC, "*", "* (Unlink and try again.)"); |
168 |
return; |
169 |
} else { |
170 |
if (botnetnick[0]) |
171 |
putlog(LOG_MISC, "*", "* IDENTITY CHANGE: %s -> %s", botnetnick, new); |
172 |
strcpy(botnetnick, new); |
173 |
} |
174 |
} |
175 |
} |
176 |
|
177 |
/**********************************************************************/ |
178 |
|
179 |
int init_dcc_max(), init_misc(); |
180 |
|
181 |
/* used for read/write to integer couplets */ |
182 |
typedef struct { |
183 |
int *left; /* left side of couplet */ |
184 |
int *right; /* right side */ |
185 |
} coupletinfo; |
186 |
|
187 |
/* read/write integer couplets (int1:int2) */ |
188 |
static char *tcl_eggcouplet(ClientData cdata, Tcl_Interp * irp, char *name1, |
189 |
char *name2, int flags) |
190 |
{ |
191 |
char *s, s1[41]; |
192 |
coupletinfo *cp = (coupletinfo *) cdata; |
193 |
|
194 |
if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) { |
195 |
sprintf(s1, "%d:%d", *(cp->left), *(cp->right)); |
196 |
Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY); |
197 |
if (flags & TCL_TRACE_UNSETS) |
198 |
Tcl_TraceVar(interp, name1, |
199 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
200 |
tcl_eggcouplet, cdata); |
201 |
} else { /* writes */ |
202 |
s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY); |
203 |
if (s != NULL) { |
204 |
int nr1, nr2; |
205 |
|
206 |
if (strlen(s) > 40) |
207 |
s[40] = 0; |
208 |
sscanf(s, "%d%*c%d", &nr1, &nr2); |
209 |
*(cp->left) = nr1; |
210 |
*(cp->right) = nr2; |
211 |
} |
212 |
} |
213 |
return NULL; |
214 |
} |
215 |
|
216 |
/* read/write normal integer */ |
217 |
static char *tcl_eggint(ClientData cdata, Tcl_Interp * irp, char *name1, |
218 |
char *name2, int flags) |
219 |
{ |
220 |
char *s, s1[40]; |
221 |
long l; |
222 |
intinfo *ii = (intinfo *) cdata; |
223 |
|
224 |
if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) { |
225 |
/* special cases */ |
226 |
if ((int *) ii->var == &conmask) |
227 |
strcpy(s1, masktype(conmask)); |
228 |
else if ((int *) ii->var == &default_flags) { |
229 |
struct flag_record fr = |
230 |
{FR_GLOBAL, 0, 0, 0, 0, 0}; |
231 |
fr.global = default_flags; |
232 |
fr.udef_global = default_uflags; |
233 |
build_flags(s1, &fr, 0); |
234 |
} else |
235 |
sprintf(s1, "%d", *(int *) ii->var); |
236 |
Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY); |
237 |
if (flags & TCL_TRACE_UNSETS) |
238 |
Tcl_TraceVar(interp, name1, |
239 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
240 |
tcl_eggint, cdata); |
241 |
return NULL; |
242 |
} else { /* writes */ |
243 |
s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY); |
244 |
if (s != NULL) { |
245 |
if ((int *) ii->var == &conmask) { |
246 |
if (s[0]) |
247 |
conmask = logmodes(s); |
248 |
else |
249 |
conmask = LOG_MODES | LOG_MISC | LOG_CMDS; |
250 |
} else if ((int *) ii->var == &default_flags) { |
251 |
struct flag_record fr = |
252 |
{FR_GLOBAL, 0, 0, 0, 0, 0}; |
253 |
|
254 |
break_down_flags(s, &fr, 0); |
255 |
default_flags = sanity_check(fr.global); /* drummer */ |
256 |
default_uflags = fr.udef_global; |
257 |
} else if ((ii->ro == 2) || ((ii->ro == 1) && protect_readonly)) { |
258 |
return "read-only variable"; |
259 |
} else { |
260 |
if (Tcl_ExprLong(interp, s, &l) == TCL_ERROR) |
261 |
return interp->result; |
262 |
if ((int *) ii->var == &max_dcc) { |
263 |
if (l < max_dcc) |
264 |
return "you can't DECREASE max-dcc"; |
265 |
max_dcc = l; |
266 |
init_dcc_max(); |
267 |
} else if ((int *) ii->var == &max_logs) { |
268 |
if (l < max_logs) |
269 |
return "you can't DECREASE max-logs"; |
270 |
max_logs = l; |
271 |
init_misc(); |
272 |
} else |
273 |
*(ii->var) = (int) l; |
274 |
} |
275 |
} |
276 |
return NULL; |
277 |
} |
278 |
} |
279 |
|
280 |
/* read/write normal string variable */ |
281 |
static char *tcl_eggstr(ClientData cdata, Tcl_Interp * irp, char *name1, |
282 |
char *name2, int flags) |
283 |
{ |
284 |
char *s; |
285 |
strinfo *st = (strinfo *) cdata; |
286 |
|
287 |
if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) { |
288 |
if ((st->str == firewall) && (firewall[0])) { |
289 |
char s1[161]; |
290 |
|
291 |
sprintf(s1, "%s:%d", firewall, firewallport); |
292 |
Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY); |
293 |
} else |
294 |
Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY); |
295 |
if (flags & TCL_TRACE_UNSETS) { |
296 |
Tcl_TraceVar(interp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES | |
297 |
TCL_TRACE_UNSETS, tcl_eggstr, cdata); |
298 |
if ((st->max <= 0) && (protect_readonly || (st->max == 0))) |
299 |
return "read-only variable"; /* it won't return the error... */ |
300 |
} |
301 |
return NULL; |
302 |
} else { /* writes */ |
303 |
if ((st->max <= 0) && (protect_readonly || (st->max == 0))) { |
304 |
Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY); |
305 |
return "read-only variable"; |
306 |
} |
307 |
s = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY); |
308 |
if (s != NULL) { |
309 |
if (strlen(s) > abs(st->max)) |
310 |
s[abs(st->max)] = 0; |
311 |
if (st->str == botnetnick) |
312 |
botnet_change(s); |
313 |
else if (st->str == firewall) { |
314 |
splitc(firewall, s, ':'); |
315 |
if (!firewall[0]) |
316 |
strcpy(firewall, s); |
317 |
else |
318 |
firewallport = atoi(s); |
319 |
} else |
320 |
strcpy(st->str, s); |
321 |
if ((st->flags) && (s[0])) { |
322 |
if (st->str[strlen(st->str) - 1] != '/') |
323 |
strcat(st->str, "/"); |
324 |
} |
325 |
} |
326 |
return NULL; |
327 |
} |
328 |
} |
329 |
|
330 |
/* add/remove tcl commands */ |
331 |
void add_tcl_commands(tcl_cmds * tab) |
332 |
{ |
333 |
int i; |
334 |
|
335 |
for (i = 0; tab[i].name; i++) |
336 |
Tcl_CreateCommand(interp, tab[i].name, tab[i].func, NULL, NULL); |
337 |
} |
338 |
|
339 |
void rem_tcl_commands(tcl_cmds * tab) |
340 |
{ |
341 |
int i; |
342 |
|
343 |
for (i = 0; tab[i].name; i++) |
344 |
Tcl_DeleteCommand(interp, tab[i].name); |
345 |
} |
346 |
|
347 |
static tcl_strings def_tcl_strings[] = |
348 |
{ |
349 |
{"botnet-nick", botnetnick, HANDLEN, 0}, |
350 |
{"userfile", userfile, 120, STR_PROTECT}, |
351 |
{"motd", motdfile, 120, STR_PROTECT}, |
352 |
{"admin", admin, 120, 0}, |
353 |
{"help-path", helpdir, 120, STR_DIR | STR_PROTECT}, |
354 |
{"temp-path", tempdir, 120, STR_DIR | STR_PROTECT}, |
355 |
#ifndef STATIC |
356 |
{"mod-path", moddir, 120, STR_DIR | STR_PROTECT}, |
357 |
#endif |
358 |
{"notify-newusers", notify_new, 120, 0}, |
359 |
{"owner", owner, 120, STR_PROTECT}, |
360 |
{"my-hostname", hostname, 120, 0}, |
361 |
{"my-ip", myip, 120, 0}, |
362 |
{"network", network, 40, 0}, |
363 |
{"whois-fields", whois_fields, 120, 0}, |
364 |
{"nat-ip", natip, 120, 0}, |
365 |
{"username", botuser, 10, 0}, |
366 |
{"version", egg_version, 0, 0}, |
367 |
{"firewall", firewall, 120, 0}, |
368 |
/* confvar patch by aaronwl */ |
369 |
{"config", configfile, 0, 0}, |
370 |
{"telnet-banner", bannerfile, 120, STR_PROTECT}, |
371 |
{0, 0, 0, 0} |
372 |
}; |
373 |
|
374 |
/* ints */ |
375 |
|
376 |
static tcl_ints def_tcl_ints[] = |
377 |
{ |
378 |
{"ignore-time", &ignore_time, 0}, |
379 |
{"dcc-flood-thr", &dcc_flood_thr, 0}, |
380 |
{"hourly-updates", ¬ify_users_at, 0}, |
381 |
{"switch-logfiles-at", &switch_logfiles_at, 0}, |
382 |
{"connect-timeout", &connect_timeout, 0}, |
383 |
{"reserved-port", &reserved_port, 0}, |
384 |
/* booleans (really just ints) */ |
385 |
{"require-p", &require_p, 0}, |
386 |
{"keep-all-logs", &keep_all_logs, 0}, |
387 |
{"open-telnets", &allow_new_telnets, 0}, |
388 |
{"stealth-telnets", &stealth_telnets, 0}, |
389 |
{"use-telnet-banner", &use_telnet_banner, 0}, |
390 |
{"uptime", (int *) &online_since, 2}, |
391 |
{"console", &conmask, 0}, |
392 |
{"default-flags", &default_flags, 0}, |
393 |
/* moved from eggdrop.h */ |
394 |
{"numversion", &egg_numver, 2}, |
395 |
{"debug-tcl", &debug_tcl, 1}, |
396 |
{"die-on-sighup", &die_on_sighup, 1}, |
397 |
{"die-on-sigterm", &die_on_sigterm, 1}, |
398 |
{"remote-boots", &remote_boots, 1}, |
399 |
{"max-dcc", &max_dcc, 0}, |
400 |
{"max-logs", &max_logs, 0}, |
401 |
{"max-logsize", &max_logsize, 0}, |
402 |
{"quick-logs", &quick_logs, 0}, |
403 |
{"enable-simul", &enable_simul, 1}, |
404 |
{"debug-output", &debug_output, 1}, |
405 |
{"protect-telnet", &protect_telnet, 0}, |
406 |
{"dcc-sanitycheck", &dcc_sanitycheck, 0}, |
407 |
{"sort-users", &sort_users, 0}, |
408 |
{"ident-timeout", &identtimeout, 0}, |
409 |
{"share-unlinks", &share_unlinks, 0}, |
410 |
{"log-time", &shtime, 0}, |
411 |
{"allow-dk-cmds", &allow_dk_cmds, 0}, |
412 |
{"resolve-timeout", &resolve_timeout, 0}, |
413 |
{"must-be-owner", &must_be_owner, 1}, |
414 |
{"use-silence", &use_silence, 0}, /* arthur2 */ |
415 |
{"paranoid-telnet-flood", &par_telnet_flood, 0}, |
416 |
{"use-exempts", &use_exempts, 0}, /* Jason/drummer */ |
417 |
{"use-invites", &use_invites, 0}, /* Jason/drummer */ |
418 |
{"force-expire", &force_expire, 0}, /* Rufus */ |
419 |
{0, 0, 0} /* arthur2 */ |
420 |
}; |
421 |
|
422 |
static tcl_coups def_tcl_coups[] = |
423 |
{ |
424 |
{"telnet-flood", &flood_telnet_thr, &flood_telnet_time}, |
425 |
{"dcc-portrange", &min_dcc_port, &max_dcc_port}, /* dw */ |
426 |
{0, 0, 0} |
427 |
}; |
428 |
|
429 |
/* set up Tcl variables that will hook into eggdrop internal vars via */ |
430 |
/* trace callbacks */ |
431 |
static void init_traces() |
432 |
{ |
433 |
add_tcl_coups(def_tcl_coups); |
434 |
add_tcl_strings(def_tcl_strings); |
435 |
add_tcl_ints(def_tcl_ints); |
436 |
} |
437 |
|
438 |
void kill_tcl() |
439 |
{ |
440 |
rem_tcl_coups(def_tcl_coups); |
441 |
rem_tcl_strings(def_tcl_strings); |
442 |
rem_tcl_ints(def_tcl_ints); |
443 |
kill_bind(); |
444 |
Tcl_DeleteInterp(interp); |
445 |
} |
446 |
|
447 |
extern tcl_cmds tcluser_cmds[], tcldcc_cmds[], tclmisc_cmds[]; |
448 |
|
449 |
/* not going through Tcl's crazy main() system (what on earth was he |
450 |
* smoking?!) so we gotta initialize the Tcl interpreter */ |
451 |
void init_tcl() |
452 |
{ |
453 |
char pver[25]; |
454 |
|
455 |
/* initialize the interpreter */ |
456 |
context; |
457 |
interp = Tcl_CreateInterp(); |
458 |
Tcl_Init(interp); |
459 |
init_bind(); |
460 |
init_traces(); |
461 |
/* add new commands */ |
462 |
/* isnt this much neater :) */ |
463 |
add_tcl_commands(tcluser_cmds); |
464 |
add_tcl_commands(tcldcc_cmds); |
465 |
add_tcl_commands(tclmisc_cmds); |
466 |
|
467 |
#define Q(A,B) Tcl_CreateCommand(interp,A,B,NULL,NULL) |
468 |
Q("logfile", tcl_logfile); |
469 |
sscanf(egg_version, "%s", pver); |
470 |
Tcl_PkgProvide(interp, "eggdrop", pver); |
471 |
} |
472 |
|
473 |
/**********************************************************************/ |
474 |
|
475 |
void do_tcl(char *whatzit, char *script) |
476 |
{ |
477 |
int code; |
478 |
FILE *f = 0; |
479 |
|
480 |
if (debug_tcl) { |
481 |
f = fopen("DEBUG.TCL", "a"); |
482 |
if (f != NULL) |
483 |
fprintf(f, "eval: %s\n", script); |
484 |
} |
485 |
set_tcl_vars(); |
486 |
context; |
487 |
code = Tcl_Eval(interp, script); |
488 |
if (debug_tcl && (f != NULL)) { |
489 |
fprintf(f, "done eval, result=%d\n", code); |
490 |
fclose(f); |
491 |
} |
492 |
if (code != TCL_OK) { |
493 |
putlog(LOG_MISC, "*", "Tcl error in script for '%s':", whatzit); |
494 |
putlog(LOG_MISC, "*", "%s", interp->result); |
495 |
} |
496 |
} |
497 |
|
498 |
/* read and interpret the configfile given */ |
499 |
/* return 1 if everything was okay */ |
500 |
int readtclprog(char *fname) |
501 |
{ |
502 |
int code; |
503 |
FILE *f; |
504 |
|
505 |
set_tcl_vars(); |
506 |
f = fopen(fname, "r"); |
507 |
if (f == NULL) |
508 |
return 0; |
509 |
fclose(f); |
510 |
if (debug_tcl) { |
511 |
f = fopen("DEBUG.TCL", "a"); |
512 |
if (f != NULL) { |
513 |
fprintf(f, "Sourcing file %s ...\n", fname); |
514 |
fclose(f); |
515 |
} |
516 |
} |
517 |
code = Tcl_EvalFile(interp, fname); |
518 |
if (code != TCL_OK) { |
519 |
if (use_stderr) { |
520 |
dprintf(DP_STDERR, "Tcl error in file '%s':\n", fname); |
521 |
dprintf(DP_STDERR, "%s\n", |
522 |
Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)); |
523 |
} else { |
524 |
putlog(LOG_MISC, "*", "Tcl error in file '%s':", fname); |
525 |
putlog(LOG_MISC, "*", "%s\n", |
526 |
Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)); |
527 |
} |
528 |
/* try to go on anyway (shrug) */ |
529 |
/* no dont it's to risky now */ |
530 |
return 0; |
531 |
} |
532 |
/* refresh internal variables */ |
533 |
return 1; |
534 |
} |
535 |
|
536 |
void add_tcl_strings(tcl_strings * list) |
537 |
{ |
538 |
int i; |
539 |
strinfo *st; |
540 |
|
541 |
for (i = 0; list[i].name; i++) { |
542 |
if (list[i].length > 0) { |
543 |
char *p = Tcl_GetVar(interp, list[i].name, TCL_GLOBAL_ONLY); |
544 |
|
545 |
if (p != NULL) { |
546 |
strncpy(list[i].buf, p, list[i].length); |
547 |
list[i].buf[list[i].length] = 0; |
548 |
if (list[i].flags & STR_DIR) { |
549 |
int x = strlen(list[i].buf); |
550 |
|
551 |
if ((x > 0) && (x < (list[i].length - 1)) && |
552 |
(list[i].buf[x - 1] != '/')) { |
553 |
list[i].buf[x++] = '/'; |
554 |
list[i].buf[x] = 0; |
555 |
} |
556 |
} |
557 |
} |
558 |
} |
559 |
st = (strinfo *) nmalloc(sizeof(strinfo)); |
560 |
strtot += sizeof(strinfo); |
561 |
st->max = list[i].length - (list[i].flags & STR_DIR); |
562 |
if (list[i].flags & STR_PROTECT) |
563 |
st->max = -st->max; |
564 |
st->str = list[i].buf; |
565 |
st->flags = (list[i].flags & STR_DIR); |
566 |
Tcl_TraceVar(interp, list[i].name, TCL_TRACE_READS | TCL_TRACE_WRITES | |
567 |
TCL_TRACE_UNSETS, tcl_eggstr, (ClientData) st); |
568 |
} |
569 |
} |
570 |
|
571 |
void rem_tcl_strings(tcl_strings * list) |
572 |
{ |
573 |
int i; |
574 |
strinfo *st; |
575 |
|
576 |
for (i = 0; list[i].name; i++) { |
577 |
st = (strinfo *) Tcl_VarTraceInfo(interp, list[i].name, |
578 |
TCL_TRACE_READS | |
579 |
TCL_TRACE_WRITES | |
580 |
TCL_TRACE_UNSETS, |
581 |
tcl_eggstr, NULL); |
582 |
Tcl_UntraceVar(interp, list[i].name, |
583 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
584 |
tcl_eggstr, st); |
585 |
if (st != NULL) { |
586 |
strtot -= sizeof(strinfo); |
587 |
nfree(st); |
588 |
} |
589 |
} |
590 |
} |
591 |
|
592 |
void add_tcl_ints(tcl_ints * list) |
593 |
{ |
594 |
int i; |
595 |
intinfo *ii; |
596 |
|
597 |
for (i = 0; list[i].name; i++) { |
598 |
char *p = Tcl_GetVar(interp, list[i].name, TCL_GLOBAL_ONLY); |
599 |
|
600 |
if (p != NULL) |
601 |
*(list[i].val) = atoi(p); |
602 |
ii = nmalloc(sizeof(intinfo)); |
603 |
strtot += sizeof(intinfo); |
604 |
ii->var = list[i].val; |
605 |
ii->ro = list[i].readonly; |
606 |
Tcl_TraceVar(interp, list[i].name, |
607 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
608 |
tcl_eggint, (ClientData) ii); |
609 |
} |
610 |
|
611 |
} |
612 |
|
613 |
void rem_tcl_ints(tcl_ints * list) |
614 |
{ |
615 |
int i; |
616 |
intinfo *ii; |
617 |
|
618 |
for (i = 0; list[i].name; i++) { |
619 |
ii = (intinfo *) Tcl_VarTraceInfo(interp, list[i].name, |
620 |
TCL_TRACE_READS | |
621 |
TCL_TRACE_WRITES | |
622 |
TCL_TRACE_UNSETS, |
623 |
tcl_eggint, NULL); |
624 |
Tcl_UntraceVar(interp, list[i].name, |
625 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
626 |
tcl_eggint, (ClientData) ii); |
627 |
if (ii) { |
628 |
strtot -= sizeof(intinfo); |
629 |
nfree(ii); |
630 |
} |
631 |
} |
632 |
} |
633 |
|
634 |
/* allocate couplet space for tracing couplets */ |
635 |
void add_tcl_coups(tcl_coups * list) |
636 |
{ |
637 |
coupletinfo *cp; |
638 |
int i; |
639 |
|
640 |
for (i = 0; list[i].name; i++) { |
641 |
cp = (coupletinfo *) nmalloc(sizeof(coupletinfo)); |
642 |
strtot += sizeof(coupletinfo); |
643 |
cp->left = list[i].lptr; |
644 |
cp->right = list[i].rptr; |
645 |
Tcl_TraceVar(interp, list[i].name, |
646 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
647 |
tcl_eggcouplet, (ClientData) cp); |
648 |
} |
649 |
} |
650 |
|
651 |
void rem_tcl_coups(tcl_coups * list) |
652 |
{ |
653 |
coupletinfo *cp; |
654 |
int i; |
655 |
|
656 |
for (i = 0; list[i].name; i++) { |
657 |
cp = (coupletinfo *) Tcl_VarTraceInfo(interp, list[i].name, |
658 |
TCL_TRACE_READS | |
659 |
TCL_TRACE_WRITES | |
660 |
TCL_TRACE_UNSETS, |
661 |
tcl_eggcouplet, NULL); |
662 |
strtot -= sizeof(coupletinfo); |
663 |
Tcl_UntraceVar(interp, list[i].name, |
664 |
TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, |
665 |
tcl_eggcouplet, (ClientData) cp); |
666 |
nfree(cp); |
667 |
} |
668 |
} |