00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdlib.h>
00029 #include <locale.h>
00030 #include "main.h"
00031
00032
00033 typedef struct {
00034 char *str;
00035 int max;
00036
00037 int flags;
00038 } strinfo;
00039
00040 typedef struct {
00041 int *var;
00042 int ro;
00043 } intinfo;
00044
00045
00046 extern time_t online_since;
00047
00048 extern char origbotname[], botuser[], motdfile[], admin[], userfile[],
00049 firewall[], helpdir[], notify_new[], hostname[], myip[], moddir[],
00050 tempdir[], owner[], network[], botnetnick[], bannerfile[],
00051 egg_version[], natip[], configfile[], logfile_suffix[], log_ts[],
00052 textdir[], pid_file[];
00053
00054 extern int flood_telnet_thr, flood_telnet_time, shtime, share_greet,
00055 require_p, keep_all_logs, allow_new_telnets, stealth_telnets,
00056 use_telnet_banner, default_flags, conmask, switch_logfiles_at,
00057 connect_timeout, firewallport, notify_users_at, flood_thr, tands,
00058 ignore_time, reserved_port_min, reserved_port_max, die_on_sighup,
00059 die_on_sigterm, max_logs, max_logsize, dcc_total, raw_log,
00060 identtimeout, dcc_sanitycheck, dupwait_timeout, egg_numver,
00061 share_unlinks, protect_telnet, sort_users, strict_host,
00062 resolve_timeout, default_uflags, userfile_perm, cidr_support;
00063
00064 extern struct dcc_t *dcc;
00065 extern tcl_timer_t *timer, *utimer;
00066
00067 Tcl_Interp *interp;
00068
00069 int protect_readonly = 0;
00070 char whois_fields[1025] = "";
00071
00072 int dcc_flood_thr = 3;
00073 int use_invites = 0;
00074 int use_exempts = 0;
00075 int force_expire = 0;
00076 int remote_boots = 2;
00077 int allow_dk_cmds = 1;
00078 int must_be_owner = 1;
00079 int quiet_reject = 1;
00080 int copy_to_tmp = 1;
00081 int max_socks = 100;
00082 int quick_logs = 0;
00083 int par_telnet_flood = 1;
00084 int quiet_save = 0;
00085 int strtot = 0;
00086 int handlen = HANDLEN;
00087 int utftot = 0;
00088 int clientdata_stuff = 0;
00089
00090
00091 int strict_servernames = 0, enable_simul = 1, use_console_r = 0,
00092 debug_output = 0;
00093
00094 #ifdef REPLACE_NOTIFIER
00095 tclevent_t *tclevents = NULL;
00096 #endif
00097
00098
00099 Tcl_Interp *Tcl_CreateInterp();
00100
00101 int expmem_tcl()
00102 {
00103 return strtot + utftot + clientdata_stuff;
00104 }
00105
00106 static void botnet_change(char *new)
00107 {
00108 if (egg_strcasecmp(botnetnick, new)) {
00109
00110 if (tands > 0) {
00111 putlog(LOG_MISC, "*", "* Tried to change my botnet nick, but I'm still "
00112 "linked to a botnet.");
00113 putlog(LOG_MISC, "*", "* (Unlink and try again.)");
00114 return;
00115 } else {
00116 if (botnetnick[0])
00117 putlog(LOG_MISC, "*", "* IDENTITY CHANGE: %s -> %s", botnetnick, new);
00118 strcpy(botnetnick, new);
00119 }
00120 }
00121 }
00122
00123
00124
00125
00126
00127
00128 int init_misc();
00129
00130
00131 typedef struct {
00132 int *left;
00133 int *right;
00134 } coupletinfo;
00135
00136
00137
00138
00139
00140
00141 static char *tcl_eggcouplet(ClientData cdata, Tcl_Interp *irp,
00142 EGG_CONST char *name1,
00143 EGG_CONST char *name2, int flags)
00144 {
00145 char *s, s1[41];
00146 coupletinfo *cp = (coupletinfo *) cdata;
00147
00148 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
00149 egg_snprintf(s1, sizeof s1, "%d:%d", *(cp->left), *(cp->right));
00150 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
00151 if (flags & TCL_TRACE_UNSETS)
00152 Tcl_TraceVar(interp, name1,
00153 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
00154 tcl_eggcouplet, cdata);
00155 } else {
00156 s = (char *) Tcl_GetVar2(interp, name1, name2, 0);
00157 if (s != NULL) {
00158 int nr1, nr2;
00159
00160 nr1 = nr2 = 0;
00161
00162 if (strlen(s) > 40)
00163 s[40] = 0;
00164
00165 sscanf(s, "%d%*c%d", &nr1, &nr2);
00166 *(cp->left) = nr1;
00167 *(cp->right) = nr2;
00168 }
00169 }
00170 return NULL;
00171 }
00172
00173
00174
00175 static char *tcl_eggint(ClientData cdata, Tcl_Interp *irp,
00176 EGG_CONST char *name1,
00177 EGG_CONST char *name2, int flags)
00178 {
00179 char *s, s1[40];
00180 long l;
00181 intinfo *ii = (intinfo *) cdata;
00182
00183 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
00184
00185 if ((int *) ii->var == &conmask)
00186 strcpy(s1, masktype(conmask));
00187 else if ((int *) ii->var == &default_flags) {
00188 struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
00189 fr.global = default_flags;
00190
00191 fr.udef_global = default_uflags;
00192 build_flags(s1, &fr, 0);
00193 } else if ((int *) ii->var == &userfile_perm) {
00194 egg_snprintf(s1, sizeof s1, "0%o", userfile_perm);
00195 } else
00196 egg_snprintf(s1, sizeof s1, "%d", *(int *) ii->var);
00197 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
00198 if (flags & TCL_TRACE_UNSETS)
00199 Tcl_TraceVar(interp, name1,
00200 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
00201 tcl_eggint, cdata);
00202 return NULL;
00203 } else {
00204 s = (char *) Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
00205 if (s != NULL) {
00206 if ((int *) ii->var == &conmask) {
00207 if (s[0])
00208 conmask = logmodes(s);
00209 else
00210 conmask = LOG_MODES | LOG_MISC | LOG_CMDS;
00211 } else if ((int *) ii->var == &default_flags) {
00212 struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
00213
00214 break_down_flags(s, &fr, 0);
00215 default_flags = sanity_check(fr.global);
00216
00217 default_uflags = fr.udef_global;
00218 } else if ((int *) ii->var == &userfile_perm) {
00219 int p = oatoi(s);
00220
00221 if (p <= 0)
00222 return "invalid userfile permissions";
00223 userfile_perm = p;
00224 } else if ((ii->ro == 2) || ((ii->ro == 1) && protect_readonly))
00225 return "read-only variable";
00226 else {
00227 if (Tcl_ExprLong(interp, s, &l) == TCL_ERROR)
00228 return "variable must have integer value";
00229 if ((int *) ii->var == &max_socks) {
00230 if (l < threaddata()->MAXSOCKS)
00231 return "you can't DECREASE max-socks below current usage";
00232 max_socks = l;
00233 } else if ((int *) ii->var == &max_logs) {
00234 if (l < max_logs)
00235 return "you can't DECREASE max-logs";
00236 max_logs = l;
00237 init_misc();
00238 } else
00239 *(ii->var) = (int) l;
00240 }
00241 }
00242 return NULL;
00243 }
00244 }
00245
00246
00247
00248 static char *tcl_eggstr(ClientData cdata, Tcl_Interp *irp,
00249 EGG_CONST char *name1,
00250 EGG_CONST char *name2, int flags)
00251 {
00252 char *s;
00253 strinfo *st = (strinfo *) cdata;
00254
00255 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
00256 if ((st->str == firewall) && (firewall[0])) {
00257 char s1[127];
00258
00259 egg_snprintf(s1, sizeof s1, "%s:%d", firewall, firewallport);
00260 Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
00261 } else
00262 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
00263 if (flags & TCL_TRACE_UNSETS) {
00264 Tcl_TraceVar(interp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
00265 TCL_TRACE_UNSETS, tcl_eggstr, cdata);
00266 if ((st->max <= 0) && (protect_readonly || (st->max == 0)))
00267 return "read-only variable";
00268 }
00269 return NULL;
00270 } else {
00271 if ((st->max <= 0) && (protect_readonly || (st->max == 0))) {
00272 Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
00273 return "read-only variable";
00274 }
00275 #ifdef USE_TCL_BYTE_ARRAYS
00276 # undef malloc
00277 # undef free
00278 {
00279 Tcl_Obj *obj;
00280 unsigned char *bytes;
00281 int len;
00282
00283 obj = Tcl_GetVar2Ex(interp, name1, name2, 0);
00284 if (!obj)
00285 return NULL;
00286 len = 0;
00287 bytes = Tcl_GetByteArrayFromObj(obj, &len);
00288 if (!bytes)
00289 return NULL;
00290 s = malloc(len + 1);
00291 egg_memcpy(s, bytes, len);
00292 s[len] = 0;
00293 }
00294 #else
00295 s = (char *) Tcl_GetVar2(interp, name1, name2, 0);
00296 #endif
00297 if (s != NULL) {
00298 if (strlen(s) > abs(st->max))
00299 s[abs(st->max)] = 0;
00300 if (st->str == botnetnick)
00301 botnet_change(s);
00302 else if (st->str == logfile_suffix)
00303 logsuffix_change(s);
00304 else if (st->str == firewall) {
00305 splitc(firewall, s, ':');
00306 if (!firewall[0])
00307 strcpy(firewall, s);
00308 else
00309 firewallport = atoi(s);
00310 } else
00311 strcpy(st->str, s);
00312 if ((st->flags) && (s[0])) {
00313 if (st->str[strlen(st->str) - 1] != '/')
00314 strcat(st->str, "/");
00315 }
00316 #ifdef USE_TCL_BYTE_ARRAYS
00317 free(s);
00318 #endif
00319 }
00320 return NULL;
00321 }
00322 }
00323
00324
00325
00326
00327 #ifdef USE_TCL_BYTE_ARRAYS
00328 static int utf_converter(ClientData cdata, Tcl_Interp *myinterp, int objc,
00329 Tcl_Obj *CONST objv[])
00330 {
00331 char **strings, *byteptr;
00332 int i, len, retval, diff;
00333 void **callback_data;
00334 Function func;
00335 ClientData cd;
00336
00337 objc += 5;
00338 strings = (char **) nmalloc(sizeof(char *) * objc);
00339 egg_memset(strings, 0, sizeof(char *) * objc);
00340 diff = utftot;
00341 utftot += sizeof(char *) * objc;
00342 objc -= 5;
00343 for (i = 0; i < objc; i++) {
00344 byteptr = (char *) Tcl_GetByteArrayFromObj(objv[i], &len);
00345 strings[i] = (char *) nmalloc(len + 1);
00346 utftot += len + 1;
00347 strncpy(strings[i], byteptr, len);
00348 strings[i][len] = 0;
00349 }
00350 callback_data = (void **) cdata;
00351 func = (Function) callback_data[0];
00352 cd = (ClientData) callback_data[1];
00353 diff -= utftot;
00354 retval = func(cd, myinterp, objc, strings);
00355 for (i = 0; i < objc; i++)
00356 nfree(strings[i]);
00357 nfree(strings);
00358 utftot += diff;
00359 return retval;
00360 }
00361
00362 void cmd_delete_callback(ClientData cdata)
00363 {
00364 nfree(cdata);
00365 clientdata_stuff -= sizeof(void *) * 2;
00366 }
00367 #endif
00368
00369 #ifdef USE_TCL_BYTE_ARRAYS
00370 void add_tcl_commands(tcl_cmds *table)
00371 {
00372 void **cdata;
00373
00374 while (table->name) {
00375 cdata = (void **) nmalloc(sizeof(void *) * 2);
00376 clientdata_stuff += sizeof(void *) * 2;
00377 cdata[0] = (void *)table->func;
00378 cdata[1] = NULL;
00379 Tcl_CreateObjCommand(interp, table->name, utf_converter, (ClientData) cdata,
00380 cmd_delete_callback);
00381 table++;
00382 }
00383 }
00384
00385 #else
00386
00387 void add_tcl_commands(tcl_cmds *table)
00388 {
00389 int i;
00390
00391 for (i = 0; table[i].name; i++)
00392 Tcl_CreateCommand(interp, table[i].name, table[i].func, NULL, NULL);
00393 }
00394 #endif
00395
00396 #ifdef USE_TCL_BYTE_ARRAYS
00397 void add_cd_tcl_cmds(cd_tcl_cmd *table)
00398 {
00399 void **cdata;
00400
00401 while (table->name) {
00402 cdata = nmalloc(sizeof(void *) * 2);
00403 clientdata_stuff += sizeof(void *) * 2;
00404 cdata[0] = (void *)table->callback;
00405 cdata[1] = table->cdata;
00406 Tcl_CreateObjCommand(interp, table->name, utf_converter, (ClientData) cdata,
00407 cmd_delete_callback);
00408 table++;
00409 }
00410 }
00411
00412 #else
00413
00414 void add_cd_tcl_cmds(cd_tcl_cmd *table)
00415 {
00416 while (table->name) {
00417 Tcl_CreateCommand(interp, table->name, table->callback,
00418 (ClientData) table->cdata, NULL);
00419 table++;
00420 }
00421 }
00422 #endif
00423
00424 void rem_tcl_commands(tcl_cmds *table)
00425 {
00426 int i;
00427
00428 for (i = 0; table[i].name; i++)
00429 Tcl_DeleteCommand(interp, table[i].name);
00430 }
00431
00432 void rem_cd_tcl_cmds(cd_tcl_cmd *table)
00433 {
00434 while (table->name) {
00435 Tcl_DeleteCommand(interp, table->name);
00436 table++;
00437 }
00438 }
00439
00440 #ifdef USE_TCL_OBJ
00441 void add_tcl_objcommands(tcl_cmds *table)
00442 {
00443 int i;
00444
00445 for (i = 0; table[i].name; i++)
00446 Tcl_CreateObjCommand(interp, table[i].name, table[i].func, (ClientData) 0,
00447 NULL);
00448 }
00449 #endif
00450
00451
00452 const char *tcl_resultstring()
00453 {
00454 const char *result;
00455 #ifdef USE_TCL_OBJ
00456 result = Tcl_GetStringResult(interp);
00457 #else
00458 result = interp->result;
00459 #endif
00460 return result;
00461 }
00462
00463 int tcl_resultempty() {
00464 const char *result;
00465 result = tcl_resultstring();
00466 return (result && result[0]) ? 0 : 1;
00467 }
00468
00469
00470 int tcl_resultint()
00471 {
00472 int result;
00473 #ifdef USE_TCL_OBJ
00474 if (Tcl_GetIntFromObj(NULL, Tcl_GetObjResult(interp), &result) != TCL_OK)
00475 #else
00476 if (Tcl_GetInt(NULL, interp->result, &result) != TCL_OK)
00477 #endif
00478 result = 0;
00479 return result;
00480 }
00481
00482 static tcl_strings def_tcl_strings[] = {
00483 {"botnet-nick", botnetnick, HANDLEN, 0},
00484 {"userfile", userfile, 120, STR_PROTECT},
00485 {"motd", motdfile, 120, STR_PROTECT},
00486 {"admin", admin, 120, 0},
00487 {"help-path", helpdir, 120, STR_DIR | STR_PROTECT},
00488 {"temp-path", tempdir, 120, STR_DIR | STR_PROTECT},
00489 {"text-path", textdir, 120, STR_DIR | STR_PROTECT},
00490 #ifndef STATIC
00491 {"mod-path", moddir, 120, STR_DIR | STR_PROTECT},
00492 #endif
00493 {"notify-newusers", notify_new, 120, 0},
00494 {"owner", owner, 120, STR_PROTECT},
00495 {"my-ip", myip, 120, 0},
00496 {"my-hostname", hostname, 120, 0},
00497 {"network", network, 40, 0},
00498 {"whois-fields", whois_fields, 1024, 0},
00499 {"nat-ip", natip, 120, 0},
00500 {"username", botuser, 10, 0},
00501 {"version", egg_version, 0, 0},
00502 {"firewall", firewall, 120, 0},
00503 {"config", configfile, 0, 0},
00504 {"telnet-banner", bannerfile, 120, STR_PROTECT},
00505 {"logfile-suffix", logfile_suffix, 20, 0},
00506 {"timestamp-format",log_ts, 32, 0},
00507 {"pidfile", pid_file, 120, STR_PROTECT},
00508 {NULL, NULL, 0, 0}
00509 };
00510
00511 static tcl_ints def_tcl_ints[] = {
00512 {"ignore-time", &ignore_time, 0},
00513 {"handlen", &handlen, 2},
00514 {"dcc-flood-thr", &dcc_flood_thr, 0},
00515 {"hourly-updates", ¬ify_users_at, 0},
00516 {"switch-logfiles-at", &switch_logfiles_at, 0},
00517 {"connect-timeout", &connect_timeout, 0},
00518 {"reserved-port", &reserved_port_min, 0},
00519 {"require-p", &require_p, 0},
00520 {"keep-all-logs", &keep_all_logs, 0},
00521 {"open-telnets", &allow_new_telnets, 0},
00522 {"stealth-telnets", &stealth_telnets, 0},
00523 {"use-telnet-banner", &use_telnet_banner, 0},
00524 {"uptime", (int *) &online_since, 2},
00525 {"console", &conmask, 0},
00526 {"default-flags", &default_flags, 0},
00527 {"numversion", &egg_numver, 2},
00528 {"die-on-sighup", &die_on_sighup, 1},
00529 {"die-on-sigterm", &die_on_sigterm, 1},
00530 {"remote-boots", &remote_boots, 1},
00531 {"max-socks", &max_socks, 0},
00532 {"max-logs", &max_logs, 0},
00533 {"max-logsize", &max_logsize, 0},
00534 {"quick-logs", &quick_logs, 0},
00535 {"raw-log", &raw_log, 1},
00536 {"protect-telnet", &protect_telnet, 0},
00537 {"dcc-sanitycheck", &dcc_sanitycheck, 0},
00538 {"sort-users", &sort_users, 0},
00539 {"ident-timeout", &identtimeout, 0},
00540 {"share-unlinks", &share_unlinks, 0},
00541 {"log-time", &shtime, 0},
00542 {"allow-dk-cmds", &allow_dk_cmds, 0},
00543 {"resolve-timeout", &resolve_timeout, 0},
00544 {"must-be-owner", &must_be_owner, 1},
00545 {"paranoid-telnet-flood", &par_telnet_flood, 0},
00546 {"use-exempts", &use_exempts, 0},
00547 {"use-invites", &use_invites, 0},
00548 {"quiet-save", &quiet_save, 0},
00549 {"force-expire", &force_expire, 0},
00550 {"dupwait-timeout", &dupwait_timeout, 0},
00551 {"strict-host", &strict_host, 0},
00552 {"userfile-perm", &userfile_perm, 0},
00553 {"copy-to-tmp", ©_to_tmp, 0},
00554 {"quiet-reject", &quiet_reject, 0},
00555 {"cidr-support", &cidr_support, 0},
00556 {"strict-servernames", &strict_servernames, 0},
00557 {"enable-simul", &enable_simul, 0},
00558 {"debug-output", &debug_output, 0},
00559 {"use-console-r", &use_console_r, 0},
00560 {NULL, NULL, 0}
00561 };
00562
00563 static tcl_coups def_tcl_coups[] = {
00564 {"telnet-flood", &flood_telnet_thr, &flood_telnet_time},
00565 {"reserved-portrange", &reserved_port_min, &reserved_port_max},
00566 {NULL, NULL, NULL}
00567 };
00568
00569
00570
00571
00572 static void init_traces()
00573 {
00574 add_tcl_coups(def_tcl_coups);
00575 add_tcl_strings(def_tcl_strings);
00576 add_tcl_ints(def_tcl_ints);
00577 }
00578
00579
00580
00581
00582 void bgtclcallback(char *context, char *script, int code,
00583 const char *result, int dofree) {
00584 #ifdef USE_TCL_ENCODING
00585 Tcl_DString dstr;
00586 #endif
00587
00588 if (code == TCL_ERROR) {
00589 #ifdef USE_TCL_ENCODING
00590
00591 Tcl_DStringInit(&dstr);
00592 Tcl_UtfToExternalDString(NULL, result, -1, &dstr);
00593 result = Tcl_DStringValue(&dstr);
00594 #endif
00595 putlog(LOG_MISC, "*", "Tcl error in script for '%s':", context);
00596 putlog(LOG_MISC, "*", "%s", result);
00597 #ifdef USE_TCL_ENCODING
00598 Tcl_DStringFree(&dstr);
00599 #endif
00600 }
00601 if (dofree) {
00602 nfree(context);
00603 nfree(script);
00604 }
00605 }
00606
00607
00608
00609
00610
00611
00612
00613 void do_tcl(char *context, char *script) {
00614 do_tcl_async(context, script, bgtclcallback);
00615 }
00616
00617
00618
00619
00620
00621
00622 void do_tcl_sync(char *context, char *script, tcleventcallback cb, int dofree) {
00623 int x;
00624
00625 x = Tcl_Eval(interp, script);
00626 cb(context, script, x, tcl_resultstring(), dofree);
00627 }
00628
00629 extern tcl_cmds tcluser_cmds[], tcldcc_cmds[], tclmisc_cmds[],
00630 tclmisc_objcmds[], tcldns_cmds[];
00631
00632 #ifdef REPLACE_NOTIFIER
00633
00634
00635
00636 void tickle_SetTimer (TCL_CONST86 Tcl_Time *timePtr)
00637 {
00638 struct threaddata *td = threaddata();
00639
00640 if (!timePtr || timePtr->sec > 1 || (timePtr->sec == 1 && timePtr->usec > 0)) {
00641 td->blocktime.tv_sec = 1;
00642 td->blocktime.tv_usec = 0;
00643 } else {
00644 td->blocktime.tv_sec = timePtr->sec;
00645 td->blocktime.tv_usec = timePtr->usec;
00646 }
00647 }
00648
00649 int tickle_WaitForEvent (TCL_CONST86 Tcl_Time *timePtr)
00650 {
00651 struct threaddata *td = threaddata();
00652
00653 tickle_SetTimer(timePtr);
00654 return (*td->mainloopfunc)(0);
00655 }
00656
00657 void tickle_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData cd)
00658 {
00659 alloctclsock(fd, mask, proc, cd);
00660 }
00661
00662 void tickle_DeleteFileHandler(int fd)
00663 {
00664 killtclsock(fd);
00665 }
00666
00667 void tickle_FinalizeNotifier(ClientData cd)
00668 {
00669 struct threaddata *td = threaddata();
00670 if (td->socklist)
00671 nfree(td->socklist);
00672 }
00673
00674 ClientData tickle_InitNotifier()
00675 {
00676 static int ismainthread = 1;
00677 init_threaddata(ismainthread);
00678 if (ismainthread)
00679 ismainthread = 0;
00680 return NULL;
00681 }
00682
00683 int tclthreadmainloop(int zero)
00684 {
00685 int i;
00686 i = sockread(NULL, NULL, threaddata()->socklist, threaddata()->MAXSOCKS, 1);
00687 return (i == -5);
00688 }
00689
00690 struct threaddata *threaddata()
00691 {
00692 static Tcl_ThreadDataKey tdkey;
00693 struct threaddata *td = Tcl_GetThreadData(&tdkey, sizeof(struct threaddata));
00694 return td;
00695 }
00696
00697
00698
00699
00700 void do_tcl_async(char *context, char *script, tcleventcallback callback) {
00701 tclevent_t *ev, *e = tclevents;
00702
00703 ev = nmalloc(sizeof(tclevent_t));
00704 ev->script = nstrdup(script);
00705 ev->context = nstrdup(context);
00706 ev->callback = callback;
00707 ev->next = NULL;
00708
00709 if (!e)
00710 tclevents = ev;
00711 else {
00712 while (e->next)
00713 e = e->next;
00714 e->next = ev;
00715 }
00716 }
00717
00718 #else
00719
00720 int tclthreadmainloop() { return 0; }
00721
00722 struct threaddata *threaddata()
00723 {
00724 static struct threaddata tsd;
00725 return &tsd;
00726 }
00727
00728
00729 void do_tcl_async(char *context, char *script, tcleventcallback callback) {
00730 do_tcl_sync(context, script, callback, 0);
00731 }
00732
00733 #endif
00734
00735 int init_threaddata(int mainthread)
00736 {
00737 struct threaddata *td = threaddata();
00738
00739
00740
00741
00742
00743
00744 td->mainloopfunc = tclthreadmainloop;
00745 td->socklist = NULL;
00746 td->mainthread = mainthread;
00747 td->blocktime.tv_sec = 1;
00748 td->blocktime.tv_usec = 0;
00749 td->MAXSOCKS = 0;
00750 increase_socks_max();
00751 return 0;
00752 }
00753
00754
00755
00756
00757 void init_tcl(int argc, char **argv)
00758 {
00759 #ifdef REPLACE_NOTIFIER
00760 Tcl_NotifierProcs notifierprocs;
00761 #endif
00762
00763 #ifdef USE_TCL_ENCODING
00764 const char *encoding;
00765 int i;
00766 char *langEnv;
00767 #endif
00768 #ifdef USE_TCL_PACKAGE
00769 int j;
00770 char pver[1024] = "";
00771 #endif
00772
00773 #ifdef REPLACE_NOTIFIER
00774 egg_bzero(¬ifierprocs, sizeof(notifierprocs));
00775 notifierprocs.initNotifierProc = tickle_InitNotifier;
00776 notifierprocs.createFileHandlerProc = tickle_CreateFileHandler;
00777 notifierprocs.deleteFileHandlerProc = tickle_DeleteFileHandler;
00778 notifierprocs.setTimerProc = tickle_SetTimer;
00779 notifierprocs.waitForEventProc = tickle_WaitForEvent;
00780 notifierprocs.finalizeNotifierProc = tickle_FinalizeNotifier;
00781
00782 Tcl_SetNotifier(¬ifierprocs);
00783 #endif
00784
00785
00786
00787
00788 #ifdef USE_TCL_FINDEXEC
00789
00790
00791
00792
00793 Tcl_FindExecutable(argv[0]);
00794 #endif
00795
00796
00797 interp = Tcl_CreateInterp();
00798
00799 #ifdef DEBUG_MEM
00800
00801 Tcl_InitMemory(interp);
00802 #endif
00803
00804
00805 Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
00806
00807
00808 Tcl_Init(interp);
00809 Tcl_SetServiceMode(TCL_SERVICE_ALL);
00810
00811
00812 #ifdef USE_TCL_ENCODING
00813
00814
00815
00816 langEnv = getenv("LC_ALL");
00817 if (langEnv == NULL || langEnv[0] == '\0') {
00818 langEnv = getenv("LC_CTYPE");
00819 }
00820 if (langEnv == NULL || langEnv[0] == '\0') {
00821 langEnv = getenv("LANG");
00822 }
00823 if (langEnv == NULL || langEnv[0] == '\0') {
00824 langEnv = NULL;
00825 }
00826
00827 encoding = NULL;
00828 if (langEnv != NULL) {
00829 for (i = 0; localeTable[i].lang != NULL; i++)
00830 if (strcmp(localeTable[i].lang, langEnv) == 0) {
00831 encoding = localeTable[i].encoding;
00832 break;
00833 }
00834
00835
00836
00837
00838 if (encoding == NULL) {
00839 char *p;
00840
00841 for (p = langEnv; *p != '\0'; p++) {
00842 if (*p == '.') {
00843 p++;
00844 break;
00845 }
00846 }
00847 if (*p != '\0') {
00848 Tcl_DString ds;
00849
00850 Tcl_DStringInit(&ds);
00851 Tcl_DStringAppend(&ds, p, -1);
00852
00853 encoding = Tcl_DStringValue(&ds);
00854 Tcl_UtfToLower(Tcl_DStringValue(&ds));
00855 if (Tcl_SetSystemEncoding(NULL, encoding) == TCL_OK) {
00856 Tcl_DStringFree(&ds);
00857 goto resetPath;
00858 }
00859 Tcl_DStringFree(&ds);
00860 encoding = NULL;
00861 }
00862 }
00863 }
00864
00865 if (encoding == NULL) {
00866
00867 encoding = "utf-8";
00868 }
00869
00870 Tcl_SetSystemEncoding(NULL, encoding);
00871
00872 resetPath:
00873
00874
00875 setlocale(LC_CTYPE, "");
00876
00877
00878
00879 setlocale(LC_NUMERIC, "C");
00880
00881
00882
00883 Tcl_GetEncoding(NULL, "iso8859-1");
00884 #endif
00885
00886 #ifdef USE_TCL_PACKAGE
00887
00888 for (j = 0; j <= strlen(egg_version); j++) {
00889 if ((egg_version[j] == ' ') || (egg_version[j] == '+'))
00890 break;
00891 pver[strlen(pver)] = egg_version[j];
00892 }
00893 Tcl_PkgProvide(interp, "eggdrop", pver);
00894 #endif
00895
00896
00897 init_bind();
00898 init_traces();
00899
00900
00901 add_tcl_commands(tcluser_cmds);
00902 add_tcl_commands(tcldcc_cmds);
00903 add_tcl_commands(tclmisc_cmds);
00904 #ifdef USE_TCL_OBJ
00905 add_tcl_objcommands(tclmisc_objcmds);
00906 #endif
00907 add_tcl_commands(tcldns_cmds);
00908 }
00909
00910 void kill_tcl()
00911 {
00912 #ifdef REPLACE_NOTIFIER
00913 tclevent_t *ne, *e = tclevents;
00914
00915 while (e) {
00916 ne = e->next;
00917 e->callback(e->context, e->script, -1, "", 1);
00918 nfree(e);
00919 e = ne;
00920 }
00921 #endif
00922 rem_tcl_coups(def_tcl_coups);
00923 rem_tcl_strings(def_tcl_strings);
00924 rem_tcl_ints(def_tcl_ints);
00925 kill_bind();
00926 Tcl_DeleteInterp(interp);
00927 }
00928
00929
00930
00931
00932
00933
00934 int readtclprog(char *fname)
00935 {
00936 int code;
00937 EGG_CONST char *result;
00938 #ifdef USE_TCL_ENCODING
00939 Tcl_DString dstr;
00940 #endif
00941
00942 if (!file_readable(fname))
00943 return 0;
00944
00945 code = Tcl_EvalFile(interp, fname);
00946 result = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
00947
00948 #ifdef USE_TCL_ENCODING
00949
00950 Tcl_DStringInit(&dstr);
00951 Tcl_UtfToExternalDString(NULL, result, -1, &dstr);
00952 result = Tcl_DStringValue(&dstr);
00953 #endif
00954
00955 if (code != TCL_OK) {
00956 putlog(LOG_MISC, "*", "Tcl error in file '%s':", fname);
00957 putlog(LOG_MISC, "*", "%s", result);
00958 code = 0;
00959 } else {
00960
00961 code = 1;
00962 }
00963
00964 #ifdef USE_TCL_ENCODING
00965 Tcl_DStringFree(&dstr);
00966 #endif
00967
00968 return code;
00969 }
00970
00971 void add_tcl_strings(tcl_strings *list)
00972 {
00973 int i;
00974 strinfo *st;
00975 int tmp;
00976
00977 for (i = 0; list[i].name; i++) {
00978 st = nmalloc(sizeof *st);
00979 strtot += sizeof(strinfo);
00980 st->max = list[i].length - (list[i].flags & STR_DIR);
00981 if (list[i].flags & STR_PROTECT)
00982 st->max = -st->max;
00983 st->str = list[i].buf;
00984 st->flags = (list[i].flags & STR_DIR);
00985 tmp = protect_readonly;
00986 protect_readonly = 0;
00987 tcl_eggstr((ClientData) st, interp, list[i].name, NULL, TCL_TRACE_WRITES);
00988 protect_readonly = tmp;
00989 tcl_eggstr((ClientData) st, interp, list[i].name, NULL, TCL_TRACE_READS);
00990 Tcl_TraceVar(interp, list[i].name, TCL_TRACE_READS | TCL_TRACE_WRITES |
00991 TCL_TRACE_UNSETS, tcl_eggstr, (ClientData) st);
00992 }
00993 }
00994
00995 void rem_tcl_strings(tcl_strings *list)
00996 {
00997 int i, f;
00998 strinfo *st;
00999
01000 f = TCL_GLOBAL_ONLY | TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS;
01001 for (i = 0; list[i].name; i++) {
01002 st = (strinfo *) Tcl_VarTraceInfo(interp, list[i].name, f, tcl_eggstr,
01003 NULL);
01004 Tcl_UntraceVar(interp, list[i].name, f, tcl_eggstr, st);
01005 if (st != NULL) {
01006 strtot -= sizeof(strinfo);
01007 nfree(st);
01008 }
01009 }
01010 }
01011
01012 void add_tcl_ints(tcl_ints *list)
01013 {
01014 int i, tmp;
01015 intinfo *ii;
01016
01017 for (i = 0; list[i].name; i++) {
01018 ii = nmalloc(sizeof *ii);
01019 strtot += sizeof(intinfo);
01020 ii->var = list[i].val;
01021 ii->ro = list[i].readonly;
01022 tmp = protect_readonly;
01023 protect_readonly = 0;
01024 tcl_eggint((ClientData) ii, interp, list[i].name, NULL, TCL_TRACE_WRITES);
01025 protect_readonly = tmp;
01026 tcl_eggint((ClientData) ii, interp, list[i].name, NULL, TCL_TRACE_READS);
01027 Tcl_TraceVar(interp, list[i].name,
01028 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01029 tcl_eggint, (ClientData) ii);
01030 }
01031
01032 }
01033
01034 void rem_tcl_ints(tcl_ints *list)
01035 {
01036 int i, f;
01037 intinfo *ii;
01038
01039 f = TCL_GLOBAL_ONLY | TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS;
01040 for (i = 0; list[i].name; i++) {
01041 ii = (intinfo *) Tcl_VarTraceInfo(interp, list[i].name, f, tcl_eggint,
01042 NULL);
01043 Tcl_UntraceVar(interp, list[i].name, f, tcl_eggint, (ClientData) ii);
01044 if (ii) {
01045 strtot -= sizeof(intinfo);
01046 nfree(ii);
01047 }
01048 }
01049 }
01050
01051
01052
01053 void add_tcl_coups(tcl_coups *list)
01054 {
01055 coupletinfo *cp;
01056 int i;
01057
01058 for (i = 0; list[i].name; i++) {
01059 cp = nmalloc(sizeof *cp);
01060 strtot += sizeof(coupletinfo);
01061 cp->left = list[i].lptr;
01062 cp->right = list[i].rptr;
01063 tcl_eggcouplet((ClientData) cp, interp, list[i].name, NULL,
01064 TCL_TRACE_WRITES);
01065 tcl_eggcouplet((ClientData) cp, interp, list[i].name, NULL,
01066 TCL_TRACE_READS);
01067 Tcl_TraceVar(interp, list[i].name,
01068 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01069 tcl_eggcouplet, (ClientData) cp);
01070 }
01071 }
01072
01073 void rem_tcl_coups(tcl_coups *list)
01074 {
01075 int i, f;
01076 coupletinfo *cp;
01077
01078 f = TCL_GLOBAL_ONLY | TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS;
01079 for (i = 0; list[i].name; i++) {
01080 cp = (coupletinfo *) Tcl_VarTraceInfo(interp, list[i].name, f,
01081 tcl_eggcouplet, NULL);
01082 strtot -= sizeof(coupletinfo);
01083 Tcl_UntraceVar(interp, list[i].name, f, tcl_eggcouplet, (ClientData) cp);
01084 nfree(cp);
01085 }
01086 }
01087
01088
01089
01090 int tcl_threaded()
01091 {
01092 #ifdef HAVE_TCL_GETCURRENTTHREAD
01093 if (Tcl_GetCurrentThread() != (Tcl_ThreadId)0)
01094 return 1;
01095 #endif
01096
01097 return 0;
01098 }
01099
01100
01101
01102 int fork_before_tcl()
01103 {
01104 #ifndef REPLACE_NOTIFIER
01105 return tcl_threaded();
01106 #endif
01107 return 0;
01108 }