tcl.c 24 KB

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