tcl.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  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. */
  8. #include <stdlib.h> /* getenv() */
  9. #include <locale.h> /* setlocale() */
  10. #include "main.h"
  11. #include <sys/stat.h>
  12. #if ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)) || (TCL_MAJOR_VERSION > 8)
  13. #define USE_BYTE_ARRAYS
  14. #endif
  15. /* Used for read/write to internal strings */
  16. typedef struct {
  17. char *str; /* Pointer to actual string in eggdrop */
  18. int max; /* max length (negative: read-only var
  19. when protect is on) (0: read-only ALWAYS) */
  20. int flags; /* 1 = directory */
  21. } strinfo;
  22. typedef struct {
  23. int *var;
  24. int ro;
  25. } intinfo;
  26. extern time_t online_since;
  27. extern int backgrd, flood_telnet_thr, flood_telnet_time;
  28. extern int shtime, share_greet;
  29. extern int allow_new_telnets, use_telnet_banner;
  30. extern int default_flags, conmask, connect_timeout;
  31. extern int firewallport, notify_users_at, flood_thr, ignore_time;
  32. extern int reserved_port_min, reserved_port_max, localhub;
  33. extern char origbotname[], botuser[], motdfile[], admin[], userfile[],
  34. firewall[], notify_new[], hostname[], hostname6[], myip[], myip6[],
  35. tempdir[], owner[], network[], botnetnick[],
  36. bannerfile[], egg_version[], natip[],
  37. textdir[], pid_file[], dcc_prefix[],
  38. netpass[];
  39. extern int die_on_sighup, die_on_sigterm,
  40. enable_simul, dcc_total, debug_output, identtimeout,
  41. protect_telnet, dupwait_timeout, egg_numver, share_unlinks,
  42. dcc_sanitycheck, sort_users, tands, resolve_timeout,
  43. default_uflags, strict_host, userfile_perm;
  44. extern struct dcc_t *dcc;
  45. extern tcl_timer_t *timer, *utimer;
  46. int protect_readonly = 0; /* turn on/off readonly protection */
  47. char whois_fields[1025] = ""; /* fields to display in a .whois */
  48. Tcl_Interp *interp; /* eggdrop always uses the same
  49. interpreter */
  50. int dcc_flood_thr = 3;
  51. int use_invites = 1; /* Jason/drummer */
  52. int use_exempts = 1; /* Jason/drummer */
  53. int force_expire = 0; /* Rufus */
  54. int remote_boots = 2;
  55. int allow_dk_cmds = 1;
  56. int must_be_owner = 1;
  57. int max_dcc = 200; /* needs at least 4 or 5 just to
  58. get started. 20 should be enough */
  59. int quiet_save = 1; /* quiet-save patch by Lucas */
  60. int strtot = 0;
  61. int handlen = HANDLEN;
  62. int utftot = 0;
  63. int clientdata_stuff = 0;
  64. /* Prototypes for tcl */
  65. Tcl_Interp *Tcl_CreateInterp();
  66. int expmem_tcl()
  67. {
  68. return strtot + utftot + clientdata_stuff;
  69. }
  70. int findidx(int z)
  71. {
  72. int j;
  73. for (j = 0; j < dcc_total; j++)
  74. if ((dcc[j].sock == z) && (dcc[j].type->flags & DCT_VALIDIDX))
  75. return j;
  76. return -1;
  77. }
  78. static void botnet_change(char *new)
  79. {
  80. if (egg_strcasecmp(botnetnick, new)) {
  81. /* Trying to change bot's nickname */
  82. if (tands > 0) {
  83. putlog(LOG_MISC, "*", "* Tried to change my botnet nick, but I'm still linked to a botnet.");
  84. putlog(LOG_MISC, "*", "* (Unlink and try again.)");
  85. return;
  86. } else {
  87. if (botnetnick[0])
  88. putlog(LOG_MISC, "*", "* IDENTITY CHANGE: %s -> %s", botnetnick, new);
  89. strcpy(botnetnick, new);
  90. }
  91. }
  92. }
  93. /*
  94. * Vars, traces, misc
  95. */
  96. int init_dcc_max(), init_misc();
  97. /* Used for read/write to integer couplets */
  98. typedef struct {
  99. int *left; /* left side of couplet */
  100. int *right; /* right side */
  101. } coupletinfo;
  102. /* Read/write integer couplets (int1:int2) */
  103. #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8))
  104. static char *tcl_eggcouplet(ClientData cdata, Tcl_Interp *irp, CONST char *name1,
  105. CONST char *name2, int flags)
  106. #else
  107. static char *tcl_eggcouplet(ClientData cdata, Tcl_Interp *irp, char *name1,
  108. char *name2, int flags)
  109. #endif
  110. {
  111. char *s, s1[41];
  112. coupletinfo *cp = (coupletinfo *) cdata;
  113. if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
  114. egg_snprintf(s1, sizeof s1, "%d:%d", *(cp->left), *(cp->right));
  115. Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
  116. if (flags & TCL_TRACE_UNSETS)
  117. Tcl_TraceVar(interp, name1,
  118. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  119. tcl_eggcouplet, cdata);
  120. } else { /* writes */
  121. s = (char *) Tcl_GetVar2(interp, name1, name2, 0);
  122. if (s != NULL) {
  123. int nr1, nr2;
  124. if (strlen(s) > 40)
  125. s[40] = 0;
  126. sscanf(s, "%d%*c%d", &nr1, &nr2);
  127. *(cp->left) = nr1;
  128. *(cp->right) = nr2;
  129. }
  130. }
  131. return NULL;
  132. }
  133. /* Read or write normal integer.
  134. */
  135. #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8))
  136. static char *tcl_eggint(ClientData cdata, Tcl_Interp *irp, CONST char *name1,
  137. CONST char *name2, int flags)
  138. #else
  139. static char *tcl_eggint(ClientData cdata, Tcl_Interp *irp, char *name1,
  140. char *name2, int flags)
  141. #endif
  142. {
  143. char *s, s1[40];
  144. long l;
  145. intinfo *ii = (intinfo *) cdata;
  146. if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
  147. /* Special cases */
  148. if ((int *) ii->var == &conmask)
  149. strcpy(s1, masktype(conmask));
  150. else if ((int *) ii->var == &default_flags) {
  151. struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
  152. fr.global = default_flags;
  153. fr.udef_global = default_uflags;
  154. build_flags(s1, &fr, 0);
  155. } else if ((int *) ii->var == &userfile_perm) {
  156. egg_snprintf(s1, sizeof s1, "0%o", userfile_perm);
  157. } else
  158. egg_snprintf(s1, sizeof s1, "%d", *(int *) ii->var);
  159. Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
  160. if (flags & TCL_TRACE_UNSETS)
  161. Tcl_TraceVar(interp, name1,
  162. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  163. tcl_eggint, cdata);
  164. return NULL;
  165. } else { /* Writes */
  166. s = (char *) Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
  167. if (s != NULL) {
  168. if ((int *) ii->var == &conmask) {
  169. if (s[0])
  170. conmask = logmodes(s);
  171. else
  172. conmask = LOG_MODES | LOG_MISC | LOG_CMDS;
  173. } else if ((int *) ii->var == &default_flags) {
  174. struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
  175. break_down_flags(s, &fr, 0);
  176. default_flags = sanity_check(fr.global); /* drummer */
  177. default_uflags = fr.udef_global;
  178. } else if ((int *) ii->var == &userfile_perm) {
  179. int p = oatoi(s);
  180. if (p <= 0)
  181. return "invalid userfile permissions";
  182. userfile_perm = p;
  183. } else if ((ii->ro == 2) || ((ii->ro == 1) && protect_readonly)) {
  184. return "read-only variable";
  185. } else {
  186. if (Tcl_ExprLong(interp, s, &l) == TCL_ERROR)
  187. return interp->result;
  188. if ((int *) ii->var == &max_dcc) {
  189. if (l < max_dcc)
  190. return "you can't DECREASE max-dcc";
  191. max_dcc = l;
  192. init_dcc_max();
  193. } else
  194. *(ii->var) = (int) l;
  195. }
  196. }
  197. return NULL;
  198. }
  199. }
  200. /* Read/write normal string variable
  201. */
  202. #if (((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)) || (TCL_MAJOR_VERSION > 8))
  203. static char *tcl_eggstr(ClientData cdata, Tcl_Interp *irp, CONST char *name1,
  204. CONST char *name2, int flags)
  205. #else
  206. static char *tcl_eggstr(ClientData cdata, Tcl_Interp *irp, char *name1,
  207. char *name2, int flags)
  208. #endif
  209. {
  210. char *s;
  211. strinfo *st = (strinfo *) cdata;
  212. if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
  213. if ((st->str == firewall) && (firewall[0])) {
  214. char s1[127];
  215. egg_snprintf(s1, sizeof s1, "%s:%d", firewall, firewallport);
  216. Tcl_SetVar2(interp, name1, name2, s1, TCL_GLOBAL_ONLY);
  217. } else
  218. Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
  219. if (flags & TCL_TRACE_UNSETS) {
  220. Tcl_TraceVar(interp, name1, TCL_TRACE_READS | TCL_TRACE_WRITES |
  221. TCL_TRACE_UNSETS, tcl_eggstr, cdata);
  222. if ((st->max <= 0) && (protect_readonly || (st->max == 0)))
  223. return "read-only variable"; /* it won't return the error... */
  224. }
  225. return NULL;
  226. } else { /* writes */
  227. if ((st->max <= 0) && (protect_readonly || (st->max == 0))) {
  228. Tcl_SetVar2(interp, name1, name2, st->str, TCL_GLOBAL_ONLY);
  229. return "read-only variable";
  230. }
  231. #ifdef USE_BYTE_ARRAYS
  232. #undef malloc
  233. #undef free
  234. {
  235. Tcl_Obj *obj;
  236. unsigned char *bytes;
  237. int len;
  238. obj = Tcl_GetVar2Ex(interp, name1, name2, 0);
  239. if (!obj) return(NULL);
  240. len = 0;
  241. bytes = Tcl_GetByteArrayFromObj(obj, &len);
  242. if (!bytes) return(NULL);
  243. s = malloc(len+1);
  244. memcpy(s, bytes, len);
  245. s[len] = 0;
  246. }
  247. #else
  248. s = (char *) Tcl_GetVar2(interp, name1, name2, 0);
  249. #endif
  250. if (s != NULL) {
  251. if (strlen(s) > abs(st->max))
  252. s[abs(st->max)] = 0;
  253. if (st->str == botnetnick)
  254. botnet_change(s);
  255. else if (st->str == firewall) {
  256. splitc(firewall, s, ':');
  257. if (!firewall[0])
  258. strcpy(firewall, s);
  259. else
  260. firewallport = atoi(s);
  261. } else
  262. strcpy(st->str, s);
  263. if ((st->flags) && (s[0])) {
  264. if (st->str[strlen(st->str) - 1] != '/')
  265. strcat(st->str, "/");
  266. }
  267. #ifdef USE_BYTE_ARRAYS
  268. free(s);
  269. #endif
  270. }
  271. return NULL;
  272. }
  273. }
  274. /* Add/remove tcl commands
  275. */
  276. #ifdef USE_BYTE_ARRAYS
  277. static int utf_converter(ClientData cdata, Tcl_Interp *myinterp, int objc,
  278. Tcl_Obj *CONST objv[])
  279. {
  280. char **strings, *byteptr;
  281. int i, len, retval, diff;
  282. void **callback_data;
  283. Function func;
  284. ClientData cd;
  285. objc += 5;
  286. strings = (char **)nmalloc(sizeof(char *) * objc);
  287. egg_memset(strings, 0, sizeof(char *) * objc);
  288. diff = utftot;
  289. utftot += sizeof(char *) * objc;
  290. objc -= 5;
  291. for (i = 0; i < objc; i++) {
  292. byteptr = (char *)Tcl_GetByteArrayFromObj(objv[i], &len);
  293. strings[i] = (char *)nmalloc(len+1);
  294. utftot += len+1;
  295. strncpy(strings[i], byteptr, len);
  296. strings[i][len] = 0;
  297. }
  298. callback_data = (void **)cdata;
  299. func = (Function) callback_data[0];
  300. cd = (ClientData) callback_data[1];
  301. diff -= utftot;
  302. retval = func(cd, myinterp, objc, strings);
  303. for (i = 0; i < objc; i++) nfree(strings[i]);
  304. nfree(strings);
  305. utftot += diff;
  306. return(retval);
  307. }
  308. void cmd_delete_callback(ClientData cdata)
  309. {
  310. nfree(cdata);
  311. clientdata_stuff -= sizeof(void *) * 2;
  312. }
  313. void add_tcl_commands(tcl_cmds *table)
  314. {
  315. void **cdata;
  316. while (table->name) {
  317. cdata = (void **)nmalloc(sizeof(void *) * 2);
  318. clientdata_stuff += sizeof(void *) * 2;
  319. cdata[0] = table->func;
  320. cdata[1] = NULL;
  321. Tcl_CreateObjCommand(interp, table->name, utf_converter, (ClientData) cdata,
  322. cmd_delete_callback);
  323. table++;
  324. }
  325. }
  326. void add_cd_tcl_cmds(cd_tcl_cmd *table)
  327. {
  328. void **cdata;
  329. while (table->name) {
  330. cdata = (void **)nmalloc(sizeof(void *) * 2);
  331. clientdata_stuff += sizeof(void *) * 2;
  332. cdata[0] = table->callback;
  333. cdata[1] = table->cdata;
  334. Tcl_CreateObjCommand(interp, table->name, utf_converter, (ClientData) cdata,
  335. cmd_delete_callback);
  336. table++;
  337. }
  338. }
  339. #else
  340. void add_tcl_commands(tcl_cmds *table)
  341. {
  342. int i;
  343. for (i = 0; table[i].name; i++)
  344. Tcl_CreateCommand(interp, table[i].name, table[i].func, NULL, NULL);
  345. }
  346. void add_cd_tcl_cmds(cd_tcl_cmd *table)
  347. {
  348. while (table->name) {
  349. Tcl_CreateCommand(interp, table->name, table->callback,
  350. (ClientData) table->cdata, NULL);
  351. table++;
  352. }
  353. }
  354. #endif
  355. void rem_tcl_commands(tcl_cmds *table)
  356. {
  357. int i;
  358. for (i = 0; table[i].name; i++)
  359. Tcl_DeleteCommand(interp, table[i].name);
  360. }
  361. void rem_cd_tcl_cmds(cd_tcl_cmd *table)
  362. {
  363. while (table->name) {
  364. Tcl_DeleteCommand(interp, table->name);
  365. table++;
  366. }
  367. }
  368. void add_tcl_objcommands(tcl_cmds *table)
  369. {
  370. #if (TCL_MAJOR_VERSION >= 8)
  371. int i;
  372. for (i = 0; table[i].name; i++)
  373. Tcl_CreateObjCommand(interp, table[i].name, table[i].func, (ClientData) 0, NULL);
  374. #endif
  375. }
  376. /* Strings */
  377. static tcl_strings def_tcl_strings[] =
  378. {
  379. {"botnet-nick", botnetnick, HANDLEN, 0},
  380. {"origbotname", origbotname, HANDLEN, 0},
  381. {"userfile", userfile, 120, STR_PROTECT},
  382. {"admin", admin, 120, 0},
  383. {"owner", owner, 120, STR_PROTECT},
  384. {"my-ip", myip, 120, 0},
  385. {"my-hostname", hostname, 120, 0},
  386. {"my-ip6", myip6, 120, 0},
  387. {"my-hostname6", hostname6, 120, 0},
  388. {"nat-ip", natip, 120, 0},
  389. {"username", botuser, 10, 0},
  390. {"version", egg_version, 0, STR_PROTECT},
  391. {"firewall", firewall, 120, 0},
  392. {"pidfile", pid_file, 120, STR_PROTECT},
  393. {"dcc_prefix", dcc_prefix, 1, 0},
  394. {NULL, NULL, 0, 0}
  395. };
  396. /* Ints */
  397. static tcl_ints def_tcl_ints[] =
  398. {
  399. {"localhub", &localhub, 2},
  400. {"handlen", &handlen, 2},
  401. {"dcc-flood-thr", &dcc_flood_thr, 0},
  402. {"reserved-port", &reserved_port_min, 0},
  403. /* booleans (really just ints) */
  404. {"console", &conmask, 0},
  405. {"default-flags", &default_flags, 0},
  406. /* moved from eggdrop.h */
  407. {"numversion", &egg_numver, 2},
  408. {"die-on-sighup", &die_on_sighup, 1},
  409. {"die-on-sigterm", &die_on_sigterm, 1},
  410. {"remote-boots", &remote_boots, 1},
  411. {"debug-output", &debug_output, 1},
  412. {"protect-telnet", &protect_telnet, 0},
  413. {"sort-users", &sort_users, 0},
  414. {"ident-timeout", &identtimeout, 0},
  415. {"resolve-timeout", &resolve_timeout, 0},
  416. {"dupwait-timeout", &dupwait_timeout, 0},
  417. {"strict-host", &strict_host, 0}, /* drummer */
  418. {NULL, NULL, 0} /* arthur2 */
  419. };
  420. static tcl_coups def_tcl_coups[] =
  421. {
  422. {"telnet-flood", &flood_telnet_thr, &flood_telnet_time},
  423. {"reserved-portrange", &reserved_port_min, &reserved_port_max},
  424. {NULL, NULL, NULL}
  425. };
  426. /* Set up Tcl variables that will hook into eggdrop internal vars via
  427. * trace callbacks.
  428. */
  429. static void init_traces()
  430. {
  431. add_tcl_coups(def_tcl_coups);
  432. add_tcl_strings(def_tcl_strings);
  433. add_tcl_ints(def_tcl_ints);
  434. }
  435. void kill_tcl()
  436. {
  437. rem_tcl_coups(def_tcl_coups);
  438. rem_tcl_strings(def_tcl_strings);
  439. rem_tcl_ints(def_tcl_ints);
  440. kill_bind();
  441. Tcl_DeleteInterp(interp);
  442. }
  443. extern tcl_cmds tcluser_cmds[], tcldcc_cmds[], tclmisc_cmds[], tclmisc_objcmds[], tcldns_cmds[];
  444. /* Not going through Tcl's crazy main() system (what on earth was he
  445. * smoking?!) so we gotta initialize the Tcl interpreter
  446. */
  447. void init_tcl(int argc, char **argv)
  448. {
  449. #if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) || (TCL_MAJOR_VERSION > 8)
  450. const char *encoding;
  451. int i;
  452. char *langEnv;
  453. #endif
  454. int j;
  455. char pver[1024] = "";
  456. /* This must be done *BEFORE* Tcl_SetSystemEncoding(),
  457. * or Tcl_SetSystemEncoding() will cause a segfault.
  458. */
  459. /* This is used for 'info nameofexecutable'.
  460. * The filename in argv[0] must exist in a directory listed in
  461. * the environment variable PATH for it to register anything.
  462. */
  463. Tcl_FindExecutable(argv[0]);
  464. /* Initialize the interpreter */
  465. interp = Tcl_CreateInterp();
  466. #ifdef DEBUG_MEM
  467. /* Initialize Tcl's memory debugging if we want it */
  468. Tcl_InitMemory(interp);
  469. #endif
  470. /* Set Tcl variable tcl_interactive to 0 */
  471. Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
  472. /* Setup script library facility */
  473. Tcl_Init(interp);
  474. /* Code based on Tcl's TclpSetInitialEncodings() */
  475. #if (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) || (TCL_MAJOR_VERSION > 8)
  476. /* Determine the current encoding from the LC_* or LANG environment
  477. * variables.
  478. */
  479. langEnv = getenv("LC_ALL");
  480. if (langEnv == NULL || langEnv[0] == '\0') {
  481. langEnv = getenv("LC_CTYPE");
  482. }
  483. if (langEnv == NULL || langEnv[0] == '\0') {
  484. langEnv = getenv("LANG");
  485. }
  486. if (langEnv == NULL || langEnv[0] == '\0') {
  487. langEnv = NULL;
  488. }
  489. encoding = NULL;
  490. if (langEnv != NULL) {
  491. for (i = 0; localeTable[i].lang != NULL; i++)
  492. if (strcmp(localeTable[i].lang, langEnv) == 0) {
  493. encoding = localeTable[i].encoding;
  494. break;
  495. }
  496. /* There was no mapping in the locale table. If there is an
  497. * encoding subfield, we can try to guess from that.
  498. */
  499. if (encoding == NULL) {
  500. char *p;
  501. for (p = langEnv; *p != '\0'; p++) {
  502. if (*p == '.') {
  503. p++;
  504. break;
  505. }
  506. }
  507. if (*p != '\0') {
  508. Tcl_DString ds;
  509. Tcl_DStringInit(&ds);
  510. Tcl_DStringAppend(&ds, p, -1);
  511. encoding = Tcl_DStringValue(&ds);
  512. Tcl_UtfToLower(Tcl_DStringValue(&ds));
  513. if (Tcl_SetSystemEncoding(NULL, encoding) == TCL_OK) {
  514. Tcl_DStringFree(&ds);
  515. goto resetPath;
  516. }
  517. Tcl_DStringFree(&ds);
  518. encoding = NULL;
  519. }
  520. }
  521. }
  522. if (encoding == NULL) {
  523. encoding = "iso8859-1";
  524. }
  525. Tcl_SetSystemEncoding(NULL, encoding);
  526. resetPath:
  527. /* Initialize the C library's locale subsystem. */
  528. setlocale(LC_CTYPE, "");
  529. /* In case the initial locale is not "C", ensure that the numeric
  530. * processing is done in "C" locale regardless. */
  531. setlocale(LC_NUMERIC, "C");
  532. /* Keep the iso8859-1 encoding preloaded. The IO package uses it for
  533. * gets on a binary channel. */
  534. Tcl_GetEncoding(NULL, "iso8859-1");
  535. #endif
  536. /* Add eggdrop to Tcl's package list */
  537. for (j = 0; j <= strlen(egg_version); j++) {
  538. if ((egg_version[j] == ' ') || (egg_version[j] == '+'))
  539. break;
  540. pver[strlen(pver)] = egg_version[j];
  541. }
  542. Tcl_PkgProvide(interp, "eggdrop", pver);
  543. /* Initialize binds and traces */
  544. Context;
  545. init_bind();
  546. init_traces();
  547. /* Add new commands */
  548. add_tcl_commands(tcluser_cmds);
  549. add_tcl_commands(tcldcc_cmds);
  550. add_tcl_commands(tclmisc_cmds);
  551. add_tcl_commands(tcldns_cmds);
  552. Context;
  553. }
  554. void do_tcl(char *whatzit, char *script)
  555. {
  556. int code;
  557. code = Tcl_Eval(interp, script);
  558. if (code != TCL_OK) {
  559. putlog(LOG_MISC, "*", "Tcl error in script for '%s':", whatzit);
  560. putlog(LOG_MISC, "*", "%s", interp->result);
  561. }
  562. }
  563. /* Interpret tcl file fname.
  564. *
  565. * returns: 1 - if everything was okay
  566. */
  567. int readtclprog(char *fname)
  568. {
  569. int code, nc;
  570. FILE *f;
  571. char *buf, *tptr, templine[8192], *temps;
  572. char *horeting;
  573. struct stat st;
  574. /* Check whether file is readable. */
  575. Context;
  576. if ((f = fopen(fname, "r")) == NULL)
  577. return 0;
  578. fclose(f);
  579. if (stat(fname, &st)) {
  580. fatal("broken file", 0);
  581. }
  582. buf = nmalloc(st.st_size * 2.5);
  583. *buf = 0;
  584. f = fopen(fname, "r");
  585. if (!f)
  586. fatal("broken file", 0);
  587. while(fgets(templine, sizeof(templine), f)) {
  588. nc = 0;
  589. if(strchr(templine, '\n')) {
  590. tptr = templine;
  591. while( (tptr = strchr(tptr, '\n')) ) {
  592. nc++;
  593. *tptr++ = 0;
  594. }
  595. }
  596. horeting = decryptit(templine);
  597. temps = (char *) decrypt_string(netpass, horeting);
  598. strcat(buf, temps);
  599. nfree(temps);
  600. while (nc > 0) {
  601. strcat(buf, "\n");
  602. nc--;
  603. }
  604. }
  605. code = Tcl_Eval(interp, buf);
  606. if (code != TCL_OK) {
  607. putlog(LOG_MISC, "*", "Tcl error in file '%s':", fname);
  608. putlog(LOG_MISC, "*", "%s", Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY));
  609. memset(buf, 0, st.st_size*2.5);
  610. nfree(buf);
  611. return 0;
  612. }
  613. memset(buf, 0, st.st_size*2.5);
  614. nfree(buf);
  615. /* Refresh internal variables */
  616. return 1;
  617. }
  618. void add_tcl_strings(tcl_strings *list)
  619. {
  620. int i;
  621. strinfo *st;
  622. int tmp;
  623. for (i = 0; list[i].name; i++) {
  624. st = (strinfo *) nmalloc(sizeof(strinfo));
  625. strtot += sizeof(strinfo);
  626. st->max = list[i].length - (list[i].flags & STR_DIR);
  627. if (list[i].flags & STR_PROTECT)
  628. st->max = -st->max;
  629. st->str = list[i].buf;
  630. st->flags = (list[i].flags & STR_DIR);
  631. tmp = protect_readonly;
  632. protect_readonly = 0;
  633. tcl_eggstr((ClientData) st, interp, list[i].name, NULL, TCL_TRACE_WRITES);
  634. tcl_eggstr((ClientData) st, interp, list[i].name, NULL, TCL_TRACE_READS);
  635. Tcl_TraceVar(interp, list[i].name, TCL_TRACE_READS | TCL_TRACE_WRITES |
  636. TCL_TRACE_UNSETS, tcl_eggstr, (ClientData) st);
  637. }
  638. }
  639. void rem_tcl_strings(tcl_strings *list)
  640. {
  641. int i;
  642. strinfo *st;
  643. for (i = 0; list[i].name; i++) {
  644. st = (strinfo *) Tcl_VarTraceInfo(interp, list[i].name,
  645. TCL_TRACE_READS |
  646. TCL_TRACE_WRITES |
  647. TCL_TRACE_UNSETS,
  648. tcl_eggstr, NULL);
  649. Tcl_UntraceVar(interp, list[i].name,
  650. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  651. tcl_eggstr, st);
  652. if (st != NULL) {
  653. strtot -= sizeof(strinfo);
  654. nfree(st);
  655. }
  656. }
  657. }
  658. void add_tcl_ints(tcl_ints *list)
  659. {
  660. int i, tmp;
  661. intinfo *ii;
  662. for (i = 0; list[i].name; i++) {
  663. ii = nmalloc(sizeof(intinfo));
  664. strtot += sizeof(intinfo);
  665. ii->var = list[i].val;
  666. ii->ro = list[i].readonly;
  667. tmp = protect_readonly;
  668. protect_readonly = 0;
  669. tcl_eggint((ClientData) ii, interp, list[i].name, NULL, TCL_TRACE_WRITES);
  670. protect_readonly = tmp;
  671. tcl_eggint((ClientData) ii, interp, list[i].name, NULL, TCL_TRACE_READS);
  672. Tcl_TraceVar(interp, list[i].name,
  673. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  674. tcl_eggint, (ClientData) ii);
  675. }
  676. }
  677. void rem_tcl_ints(tcl_ints *list)
  678. {
  679. int i;
  680. intinfo *ii;
  681. for (i = 0; list[i].name; i++) {
  682. ii = (intinfo *) Tcl_VarTraceInfo(interp, list[i].name,
  683. TCL_TRACE_READS |
  684. TCL_TRACE_WRITES |
  685. TCL_TRACE_UNSETS,
  686. tcl_eggint, NULL);
  687. Tcl_UntraceVar(interp, list[i].name,
  688. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  689. tcl_eggint, (ClientData) ii);
  690. if (ii) {
  691. strtot -= sizeof(intinfo);
  692. nfree(ii);
  693. }
  694. }
  695. }
  696. /* Allocate couplet space for tracing couplets
  697. */
  698. void add_tcl_coups(tcl_coups *list)
  699. {
  700. coupletinfo *cp;
  701. int i;
  702. for (i = 0; list[i].name; i++) {
  703. cp = (coupletinfo *) nmalloc(sizeof(coupletinfo));
  704. strtot += sizeof(coupletinfo);
  705. cp->left = list[i].lptr;
  706. cp->right = list[i].rptr;
  707. tcl_eggcouplet((ClientData) cp, interp, list[i].name, NULL,
  708. TCL_TRACE_WRITES);
  709. tcl_eggcouplet((ClientData) cp, interp, list[i].name, NULL,
  710. TCL_TRACE_READS);
  711. Tcl_TraceVar(interp, list[i].name,
  712. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  713. tcl_eggcouplet, (ClientData) cp);
  714. }
  715. }
  716. void rem_tcl_coups(tcl_coups * list)
  717. {
  718. coupletinfo *cp;
  719. int i;
  720. for (i = 0; list[i].name; i++) {
  721. cp = (coupletinfo *) Tcl_VarTraceInfo(interp, list[i].name,
  722. TCL_TRACE_READS |
  723. TCL_TRACE_WRITES |
  724. TCL_TRACE_UNSETS,
  725. tcl_eggcouplet, NULL);
  726. strtot -= sizeof(coupletinfo);
  727. Tcl_UntraceVar(interp, list[i].name,
  728. TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
  729. tcl_eggcouplet, (ClientData) cp);
  730. nfree(cp);
  731. }
  732. }