tcl.c 24 KB

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