1 /*
2 * tclmisc.c -- handles:
3 * Tcl stubs for everything else
4 */
5 /*
6 * Copyright (C) 1997 Robey Pointer
7 * Copyright (C) 1999 - 2021 Eggheads Development Team
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #include "main.h"
25 #include "modules.h"
26 #include "tandem.h"
27 #include "md5/md5.h"
28
29 #ifdef TIME_WITH_SYS_TIME
30 # include <sys/time.h>
31 # include <time.h>
32 #else
33 # ifdef HAVE_SYS_TIME_H
34 # include <sys/time.h>
35 # else
36 # include <time.h>
37 # endif
38 #endif
39
40 #include <sys/stat.h>
41 #include <sys/utsname.h>
42
43 extern p_tcl_bind_list bind_table_list;
44 extern tcl_timer_t *timer, *utimer;
45 extern struct dcc_t *dcc;
46 extern char botnetnick[], quit_msg[];
47 extern struct userrec *userlist;
48 extern time_t now;
49 extern module_entry *module_list;
50 extern int max_logs, cache_hit, cache_miss;
51 extern log_t *logs;
52 extern Tcl_Interp *interp;
53
expmem_tclmisc()54 int expmem_tclmisc()
55 {
56 int i, tot = 0;
57
58 for (i = 0; i < max_logs; i++) {
59 if (logs[i].filename != NULL) {
60 tot += strlen(logs[i].filename) + 1;
61 tot += strlen(logs[i].chname) + 1;
62 }
63 }
64
65 return tot;
66 }
67
68 /*
69 * Logging
70 */
71
72 /* logfile [<modes> <channel> <filename>] */
73 static int tcl_logfile STDVAR
74 {
75 int i;
76 char s[151];
77
78 BADARGS(1, 4, " ?logModes channel logFile?");
79
80 if (argc == 1) {
81 /* They just want a list of the logfiles and modes */
82 for (i = 0; i < max_logs; i++)
83 if (logs[i].filename != NULL) {
84 egg_snprintf(s, sizeof s, "%s %s %s", masktype(logs[i].mask),
85 logs[i].chname, logs[i].filename);
86 Tcl_AppendElement(interp, s);
87 }
88 return TCL_OK;
89 }
90
91 BADARGS(4, 4, " ?logModes channel logFile?");
92
93 if (*argv[1] && !*argv[2]) {
94 Tcl_AppendResult(interp,
95 "log modes set, but no channel specified", NULL);
96 return TCL_ERROR;
97 }
98 if (*argv[2] && !strchr(CHANMETA, *argv[2]) && strcmp(argv[2], "*")) {
99 Tcl_AppendResult(interp, "invalid channel prefix", NULL);
100 return TCL_ERROR;
101 }
102 if (*argv[2] && strchr(argv[2], ' ')) {
103 Tcl_AppendResult(interp, "channel names cannot contain spaces", NULL);
104 return TCL_ERROR;
105 }
106
107 for (i = 0; i < max_logs; i++)
108 if ((logs[i].filename != NULL) && (!strcmp(logs[i].filename, argv[3]))) {
109 logs[i].flags &= ~LF_EXPIRING;
110 logs[i].mask = logmodes(argv[1]);
111 nfree(logs[i].chname);
112 logs[i].chname = NULL;
113 if (!logs[i].mask) {
114 /* ending logfile */
115 nfree(logs[i].filename);
116 logs[i].filename = NULL;
117 if (logs[i].f != NULL) {
118 fclose(logs[i].f);
119 logs[i].f = NULL;
120 }
121 logs[i].flags = 0;
122 } else {
123 logs[i].chname = nmalloc(strlen(argv[2]) + 1);
124 strcpy(logs[i].chname, argv[2]);
125 }
126 Tcl_AppendResult(interp, argv[3], NULL);
127 return TCL_OK;
128 }
129 /* Do not add logfiles without any flags to log ++rtc */
130 if (!logmodes(argv[1])) {
131 Tcl_AppendResult(interp, "can't remove \"", argv[3],
132 "\" from list: no such logfile", NULL);
133 return TCL_ERROR;
134 }
135 for (i = 0; i < max_logs; i++)
136 if (logs[i].filename == NULL) {
137 logs[i].flags = 0;
138 logs[i].mask = logmodes(argv[1]);
139 logs[i].filename = nmalloc(strlen(argv[3]) + 1);
140 strcpy(logs[i].filename, argv[3]);
141 logs[i].chname = nmalloc(strlen(argv[2]) + 1);
142 strcpy(logs[i].chname, argv[2]);
143 Tcl_AppendResult(interp, argv[3], NULL);
144 return TCL_OK;
145 }
146 Tcl_AppendResult(interp, "reached max # of logfiles", NULL);
147 return TCL_ERROR;
148 }
149
150 static int tcl_putlog STDVAR
151 {
152 char logtext[501];
153
154 BADARGS(2, 2, " text");
155
156 strlcpy(logtext, argv[1], sizeof logtext);
157 putlog(LOG_MISC, "*", "%s", logtext);
158 return TCL_OK;
159 }
160
161 static int tcl_putcmdlog STDVAR
162 {
163 char logtext[501];
164
165 BADARGS(2, 2, " text");
166
167 strlcpy(logtext, argv[1], sizeof logtext);
168 putlog(LOG_CMDS, "*", "%s", logtext);
169 return TCL_OK;
170 }
171
172 static int tcl_putxferlog STDVAR
173 {
174 char logtext[501];
175
176 BADARGS(2, 2, " text");
177
178 strlcpy(logtext, argv[1], sizeof logtext);
179 putlog(LOG_FILES, "*", "%s", logtext);
180 return TCL_OK;
181 }
182
183 static int tcl_putloglev STDVAR
184 {
185 int lev = 0;
186 char logtext[501];
187
188 BADARGS(4, 4, " flag(s) channel text");
189
190 lev = logmodes(argv[1]);
191 if (!lev) {
192 Tcl_AppendResult(irp, "No valid log flag given", NULL);
193 return TCL_ERROR;
194 }
195 strlcpy(logtext, argv[3], sizeof logtext);
196
197 putlog(lev, argv[2], "%s", logtext);
198 return TCL_OK;
199 }
200
201 static int tcl_binds STDVAR
202 {
203 int matching = 0;
204 char *g, flg[100], hits[11];
205 EGG_CONST char *list[5];
206 tcl_bind_list_t *tl, *tl_kind;
207 tcl_bind_mask_t *tm;
208 tcl_cmd_t *tc;
209
210 BADARGS(1, 2, " ?type/mask?");
211
212 if (argv[1])
213 tl_kind = find_bind_table(argv[1]);
214 else
215 tl_kind = NULL;
216 if (!tl_kind && argv[1])
217 matching = 1;
218 for (tl = tl_kind ? tl_kind : bind_table_list; tl;
219 tl = tl_kind ? 0 : tl->next) {
220 if (tl->flags & HT_DELETED)
221 continue;
222 for (tm = tl->first; tm; tm = tm->next) {
223 if (tm->flags & TBM_DELETED)
224 continue;
225 for (tc = tm->first; tc; tc = tc->next) {
226 if (tc->attributes & TC_DELETED)
227 continue;
228 if (matching &&
229 !wild_match_per(argv[1], tl->name) &&
230 !wild_match_per(argv[1], tm->mask) &&
231 !wild_match_per(argv[1], tc->func_name))
232 continue;
233 build_flags(flg, &(tc->flags), NULL);
234 egg_snprintf(hits, sizeof hits, "%i", (int) tc->hits);
235 list[0] = tl->name;
236 list[1] = flg;
237 list[2] = tm->mask;
238 list[3] = hits;
239 list[4] = tc->func_name;
240 g = Tcl_Merge(5, list);
241 Tcl_AppendElement(irp, g);
242 Tcl_Free((char *) g);
243 }
244 }
245 }
246 return TCL_OK;
247 }
248
249 static int tcl_timer STDVAR
250 {
251 unsigned long x;
252 char s[26];
253
254 BADARGS(3, 4, " minutes command ?count?");
255
256 if (atoi(argv[1]) < 0) {
257 Tcl_AppendResult(irp, "time value must be positive", NULL);
258 return TCL_ERROR;
259 }
260 if (argc == 4 && atoi(argv[3]) < 0) {
261 Tcl_AppendResult(irp, "count value must be >= 0", NULL);
262 return TCL_ERROR;
263 }
264 if (argv[2][0] != '#') {
265 x = add_timer(&timer, atoi(argv[1]), (argc == 4 ? atoi(argv[3]) : 1),
266 argv[2], 0L);
267 snprintf(s, sizeof s, "timer%lu", x);
268 Tcl_AppendResult(irp, s, NULL);
269 }
270 return TCL_OK;
271 }
272
273 static int tcl_utimer STDVAR
274 {
275 unsigned long x;
276 char s[26];
277
278 BADARGS(3, 4, " seconds command ?count?");
279
280 if (atoi(argv[1]) < 0) {
281 Tcl_AppendResult(irp, "time value must be positive", NULL);
282 return TCL_ERROR;
283 }
284 if (argc == 4 && atoi(argv[3]) < 0) {
285 Tcl_AppendResult(irp, "count value must be >= 0", NULL);
286 return TCL_ERROR;
287 }
288 if (argv[2][0] != '#') {
289 x = add_timer(&utimer, atoi(argv[1]), (argc == 4 ? atoi(argv[3]) : 1),
290 argv[2], 0L);
291 snprintf(s, sizeof s, "timer%lu", x);
292 Tcl_AppendResult(irp, s, NULL);
293 }
294 return TCL_OK;
295 }
296
297 static int tcl_killtimer STDVAR
298 {
299 BADARGS(2, 2, " timerID");
300
301 if (strncmp(argv[1], "timer", 5)) {
302 Tcl_AppendResult(irp, "argument is not a timerID", NULL);
303 return TCL_ERROR;
304 }
305 if (remove_timer(&timer, atol(&argv[1][5])))
306 return TCL_OK;
307 Tcl_AppendResult(irp, "invalid timerID", NULL);
308 return TCL_ERROR;
309 }
310
311 static int tcl_killutimer STDVAR
312 {
313 BADARGS(2, 2, " timerID");
314
315 if (strncmp(argv[1], "timer", 5)) {
316 Tcl_AppendResult(irp, "argument is not a timerID", NULL);
317 return TCL_ERROR;
318 }
319 if (remove_timer(&utimer, atol(&argv[1][5])))
320 return TCL_OK;
321 Tcl_AppendResult(irp, "invalid timerID", NULL);
322 return TCL_ERROR;
323 }
324
325 static int tcl_timers STDVAR
326 {
327 BADARGS(1, 1, "");
328
329 list_timers(irp, timer);
330 return TCL_OK;
331 }
332
333 static int tcl_utimers STDVAR
334 {
335 BADARGS(1, 1, "");
336
337 list_timers(irp, utimer);
338 return TCL_OK;
339 }
340
341 static int tcl_duration STDVAR
342 {
343 char s[70];
344 unsigned long sec, tmp;
345
346 BADARGS(2, 2, " seconds");
347
348 if (atol(argv[1]) <= 0) {
349 Tcl_AppendResult(irp, "0 seconds", NULL);
350 return TCL_OK;
351 }
352 sec = atol(argv[1]);
353
354 s[0] = 0;
355 if (sec >= 31536000) {
356 tmp = (sec / 31536000);
357 sprintf(s, "%lu year%s ", tmp, (tmp == 1) ? "" : "s");
358 sec -= (tmp * 31536000);
359 }
360 if (sec >= 604800) {
361 tmp = (sec / 604800);
362 sprintf(&s[strlen(s)], "%lu week%s ", tmp, (tmp == 1) ? "" : "s");
363 sec -= (tmp * 604800);
364 }
365 if (sec >= 86400) {
366 tmp = (sec / 86400);
367 sprintf(&s[strlen(s)], "%lu day%s ", tmp, (tmp == 1) ? "" : "s");
368 sec -= (tmp * 86400);
369 }
370 if (sec >= 3600) {
371 tmp = (sec / 3600);
372 sprintf(&s[strlen(s)], "%lu hour%s ", tmp, (tmp == 1) ? "" : "s");
373 sec -= (tmp * 3600);
374 }
375 if (sec >= 60) {
376 tmp = (sec / 60);
377 sprintf(&s[strlen(s)], "%lu minute%s ", tmp, (tmp == 1) ? "" : "s");
378 sec -= (tmp * 60);
379 }
380 if (sec > 0) {
381 tmp = (sec);
382 sprintf(&s[strlen(s)], "%lu second%s", tmp, (tmp == 1) ? "" : "s");
383 }
384 if (strlen(s) > 0 && s[strlen(s) - 1] == ' ')
385 s[strlen(s) - 1] = 0;
386 Tcl_AppendResult(irp, s, NULL);
387 return TCL_OK;
388 }
389
390 static int tcl_unixtime STDVAR
391 {
392 char s[11];
393 time_t now2 = time(NULL);
394
395 BADARGS(1, 1, "");
396
397 egg_snprintf(s, sizeof s, "%li", (long) now2);
398 Tcl_AppendResult(irp, s, NULL);
399 return TCL_OK;
400 }
401
402 static int tcl_ctime STDVAR
403 {
404 time_t tt;
405 char s[25];
406
407 BADARGS(2, 2, " unixtime");
408
409 tt = (time_t) atol(argv[1]);
410 strlcpy(s, ctime(&tt), sizeof s);
411 Tcl_AppendResult(irp, s, NULL);
412 return TCL_OK;
413 }
414
415 static int tcl_strftime STDVAR
416 {
417 char buf[512];
418 struct tm *tm1;
419 time_t t;
420
421 BADARGS(2, 3, " format ?time?");
422
423 if (argc == 3)
424 t = atol(argv[2]);
425 else
426 t = now;
427 tm1 = localtime(&t);
428 if (strftime(buf, sizeof(buf) - 1, argv[1], tm1)) {
429 Tcl_AppendResult(irp, buf, NULL);
430 return TCL_OK;
431 }
432 Tcl_AppendResult(irp, " error with strftime", NULL);
433 return TCL_ERROR;
434 }
435
436 static int tcl_myip STDVAR
437 {
438 #ifdef IPV6
439 char s[INET6_ADDRSTRLEN];
440 #else
441 char s[INET_ADDRSTRLEN];
442 #endif
443
444
445 BADARGS(1, 1, "");
446
447 getdccaddr(NULL, s, sizeof s);
448 Tcl_AppendResult(irp, s, NULL);
449 return TCL_OK;
450 }
451
452 static int tcl_rand STDVAR
453 {
454 long i;
455 unsigned long x;
456 char s[11];
457
458 BADARGS(2, 2, " limit");
459
460 i = atol(argv[1]);
461
462 if (i <= 0) {
463 Tcl_AppendResult(irp, "random limit must be greater than 0", NULL);
464 return TCL_ERROR;
465 } else if (i > RANDOM_MAX) {
466 Tcl_AppendResult(irp, "random limit must be equal to or less than ",
467 int_to_base10(RANDOM_MAX), NULL);
468 return TCL_ERROR;
469 }
470
471 x = randint(i);
472
473 egg_snprintf(s, sizeof s, "%lu", x);
474
475 Tcl_AppendResult(irp, s, NULL);
476 return TCL_OK;
477 }
478
479 static int tcl_sendnote STDVAR
480 {
481 char s[5], from[NOTENAMELEN + 1], to[NOTENAMELEN + 1], msg[451];
482
483 BADARGS(4, 4, " from to message");
484
485 strlcpy(from, argv[1], sizeof from);
486 strlcpy(to, argv[2], sizeof to);
487 strlcpy(msg, argv[3], sizeof msg);
488 egg_snprintf(s, sizeof s, "%d", add_note(to, from, msg, -1, 0));
489 Tcl_AppendResult(irp, s, NULL);
490 return TCL_OK;
491 }
492
493 static int tcl_dumpfile STDVAR
494 {
495 char nick[NICKLEN];
496 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
497
498 BADARGS(3, 3, " nickname filename");
499
500 strlcpy(nick, argv[1], sizeof nick);
501 get_user_flagrec(get_user_by_nick(nick), &fr, NULL);
502 showhelp(argv[1], argv[2], &fr, HELP_TEXT);
503 return TCL_OK;
504 }
505
506 static int tcl_dccdumpfile STDVAR
507 {
508 int idx, i;
509 struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
510
511 BADARGS(3, 3, " idx filename");
512
513 i = atoi(argv[1]);
514 idx = findidx(i);
515 if (idx < 0) {
516 Tcl_AppendResult(irp, "illegal idx", NULL);
517 return TCL_ERROR;
518 }
519 get_user_flagrec(get_user_by_handle(userlist, dcc[idx].nick), &fr, NULL);
520
521 tellhelp(idx, argv[2], &fr, HELP_TEXT);
522 return TCL_OK;
523 }
524
525 static int tcl_backup STDVAR
526 {
527 BADARGS(1, 1, "");
528
529 call_hook(HOOK_BACKUP);
530 return TCL_OK;
531 }
532
533 static int tcl_die STDVAR
534 {
535 char s[1024];
536
537 BADARGS(1, 2, " ?reason?");
538
539 if (argc == 2) {
540 egg_snprintf(s, sizeof s, "BOT SHUTDOWN (%s)", argv[1]);
541 strlcpy(quit_msg, argv[1], 1024);
542 } else {
543 strlcpy(s, "BOT SHUTDOWN (No reason)", sizeof s);
544 quit_msg[0] = 0;
545 }
546 kill_bot(s, quit_msg[0] ? quit_msg : "EXIT");
547 return TCL_OK;
548 }
549
550 static int tcl_loadmodule STDVAR
551 {
552 const char *p;
553
554 BADARGS(2, 2, " module-name");
555
556 p = module_load(argv[1]);
557 if (p && strcmp(p, MOD_ALREADYLOAD) && !strcmp(argv[0], "loadmodule"))
558 putlog(LOG_MISC, "*", "%s %s: %s", MOD_CANTLOADMOD, argv[1], p);
559 Tcl_AppendResult(irp, p, NULL);
560 return TCL_OK;
561 }
562
563 static int tcl_unloadmodule STDVAR
564 {
565 BADARGS(2, 2, " module-name");
566
567 Tcl_AppendResult(irp, module_unload(argv[1], botnetnick), NULL);
568 return TCL_OK;
569 }
570
571 static int tcl_unames STDVAR
572 {
573 Tcl_AppendResult(irp, egg_uname(), NULL);
574 return TCL_OK;
575 }
576
577 static int tcl_modules STDVAR
578 {
579 int i;
580 char *p, s[24], s2[24];
581 EGG_CONST char *list[100], *list2[2];
582 dependancy *dep;
583 module_entry *current;
584
585 BADARGS(1, 1, "");
586
587 for (current = module_list; current; current = current->next) {
588 list[0] = current->name;
589 egg_snprintf(s, sizeof s, "%d.%d", current->major, current->minor);
590 list[1] = s;
591 i = 2;
592 for (dep = dependancy_list; dep && (i < 100); dep = dep->next) {
593 if (dep->needing == current) {
594 list2[0] = dep->needed->name;
595 egg_snprintf(s2, sizeof s2, "%d.%d", dep->major, dep->minor);
596 list2[1] = s2;
597 list[i] = Tcl_Merge(2, list2);
598 i++;
599 }
600 }
601 p = Tcl_Merge(i, list);
602 Tcl_AppendElement(irp, p);
603 Tcl_Free((char *) p);
604 while (i > 2) {
605 i--;
606 Tcl_Free((char *) list[i]);
607 }
608 }
609 return TCL_OK;
610 }
611
612 static int tcl_loadhelp STDVAR
613 {
614 BADARGS(2, 2, " helpfile-name");
615
616 add_help_reference(argv[1]);
617 return TCL_OK;
618 }
619
620 static int tcl_unloadhelp STDVAR
621 {
622 BADARGS(2, 2, " helpfile-name");
623
624 rem_help_reference(argv[1]);
625 return TCL_OK;
626 }
627
628 static int tcl_reloadhelp STDVAR
629 {
630 BADARGS(1, 1, "");
631
632 reload_help_data();
633 return TCL_OK;
634 }
635
636 static int tcl_callevent STDVAR
637 {
638 BADARGS(2, 2, " event");
639
640 check_tcl_event(argv[1]);
641 return TCL_OK;
642 }
643
644 static int tcl_stripcodes STDVAR
645 {
646 int flags = 0;
647 char *p;
648
649 BADARGS(3, 3, " strip-flags string");
650
651 for (p = argv[1]; *p; p++)
652 switch (*p) {
653 case 'c':
654 flags |= STRIP_COLOR;
655 break;
656 case 'b':
657 flags |= STRIP_BOLD;
658 break;
659 case 'r':
660 flags |= STRIP_REVERSE;
661 break;
662 case 'u':
663 flags |= STRIP_UNDERLINE;
664 break;
665 case 'a':
666 flags |= STRIP_ANSI;
667 break;
668 case 'g':
669 flags |= STRIP_BELLS;
670 break;
671 case 'o':
672 flags |= STRIP_ORDINARY;
673 break;
674 case 'i':
675 flags |= STRIP_ITALICS;
676 break;
677 case '*':
678 flags |= STRIP_ALL;
679 break;
680 default:
681 Tcl_AppendResult(irp, "Invalid strip-flags: ", argv[1], NULL);
682 return TCL_ERROR;
683 }
684
685 p = Tcl_Alloc(strlen(argv[2]) + 1);
686 strcpy(p, argv[2]);
687 strip_mirc_codes(flags, p);
688 Tcl_SetResult(irp, p, TCL_DYNAMIC);
689 return TCL_OK;
690 }
691
tcl_md5(cd,irp,objc,objv)692 static int tcl_md5(cd, irp, objc, objv)
693 ClientData cd;
694 Tcl_Interp *irp;
695 int objc;
696 Tcl_Obj *CONST objv[];
697 {
698 MD5_CTX md5context;
699 char digest_string[33], *string;
700 unsigned char digest[16];
701 int i, len;
702
703 if (objc != 2) {
704 Tcl_WrongNumArgs(irp, 1, objv, "string");
705 return TCL_ERROR;
706 }
707 string = Tcl_GetStringFromObj(objv[1], &len);
708
709 MD5_Init(&md5context);
710 MD5_Update(&md5context, (unsigned char *) string, len);
711 MD5_Final(digest, &md5context);
712 for (i = 0; i < 16; i++)
713 sprintf(digest_string + (i * 2), "%.2x", digest[i]);
714 Tcl_AppendResult(irp, digest_string, NULL);
715 return TCL_OK;
716 }
717
718 static int tcl_matchaddr STDVAR
719 {
720 BADARGS(3, 3, " mask address");
721
722 if (match_addr(argv[1], argv[2]))
723 Tcl_AppendResult(irp, "1", NULL);
724 else
725 Tcl_AppendResult(irp, "0", NULL);
726 return TCL_OK;
727 }
728
729 static int tcl_matchcidr STDVAR
730 {
731 BADARGS(4, 4, " block address prefix");
732
733 if (cidr_match(argv[1], argv[2], atoi(argv[3])))
734 Tcl_AppendResult(irp, "1", NULL);
735 else
736 Tcl_AppendResult(irp, "0", NULL);
737 return TCL_OK;
738 }
739
740 static int tcl_matchstr STDVAR
741 {
742 BADARGS(3, 3, " pattern string");
743
744 if (wild_match(argv[1], argv[2]))
745 Tcl_AppendResult(irp, "1", NULL);
746 else
747 Tcl_AppendResult(irp, "0", NULL);
748 return TCL_OK;
749 }
750
751 tcl_cmds tclmisc_objcmds[] = {
752 {"md5", tcl_md5},
753 {NULL, NULL}
754 };
755
756 static int tcl_status STDVAR
757 {
758 char s[15];
759
760 BADARGS(1, 2, " ?type?");
761
762 if ((argc < 2) || !strcmp(argv[1], "cpu")) {
763 Tcl_AppendElement(irp, "cputime");
764 egg_snprintf(s, sizeof s, "%f", getcputime());
765 Tcl_AppendElement(irp, s);
766 }
767 if ((argc < 2) || !strcmp(argv[1], "mem")) {
768 Tcl_AppendElement(irp, "expmem");
769 egg_snprintf(s, sizeof s, "%d", expected_memory());
770 Tcl_AppendElement(irp, s);
771 }
772 if ((argc < 2) || !strcmp(argv[1], "ipv6")) {
773 Tcl_AppendElement(irp, "ipv6");
774 #ifdef IPV6
775 Tcl_AppendElement(irp, "enabled");
776 #else
777 Tcl_AppendElement(irp, "disabled");
778 #endif
779 }
780 if ((argc < 2) || !strcmp(argv[1], "tls")) {
781 Tcl_AppendElement(irp, "tls");
782 #ifdef TLS
783 Tcl_AppendElement(irp, SSLeay_version(SSLEAY_VERSION));
784 #else
785 Tcl_AppendElement(irp, "disabled");
786 #endif
787 }
788 if ((argc < 2) || !strcmp(argv[1], "cache")) {
789 Tcl_AppendElement(irp, "usercache");
790 egg_snprintf(s, sizeof s, "%4.1f", 100.0 *
791 ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
792 Tcl_AppendElement(irp, s);
793 }
794
795 return TCL_OK;
796 }
797
798 static int tcl_rfcequal STDVAR
799 {
800 BADARGS(3, 3, " string1 string2");
801
802 Tcl_AppendResult(irp, !rfc_casecmp(argv[1], argv[2]) ? "1" : "0", NULL);
803
804 return TCL_OK;
805 }
806
807 tcl_cmds tclmisc_cmds[] = {
808 {"logfile", tcl_logfile},
809 {"putlog", tcl_putlog},
810 {"putcmdlog", tcl_putcmdlog},
811 {"putxferlog", tcl_putxferlog},
812 {"putloglev", tcl_putloglev},
813 {"timer", tcl_timer},
814 {"utimer", tcl_utimer},
815 {"killtimer", tcl_killtimer},
816 {"killutimer", tcl_killutimer},
817 {"timers", tcl_timers},
818 {"utimers", tcl_utimers},
819 {"unixtime", tcl_unixtime},
820 {"strftime", tcl_strftime},
821 {"ctime", tcl_ctime},
822 {"myip", tcl_myip},
823 {"rand", tcl_rand},
824 {"sendnote", tcl_sendnote},
825 {"dumpfile", tcl_dumpfile},
826 {"dccdumpfile", tcl_dccdumpfile},
827 {"backup", tcl_backup},
828 {"exit", tcl_die},
829 {"die", tcl_die},
830 {"unames", tcl_unames},
831 {"unloadmodule", tcl_unloadmodule},
832 {"loadmodule", tcl_loadmodule},
833 {"checkmodule", tcl_loadmodule},
834 {"modules", tcl_modules},
835 {"loadhelp", tcl_loadhelp},
836 {"unloadhelp", tcl_unloadhelp},
837 {"reloadhelp", tcl_reloadhelp},
838 {"duration", tcl_duration},
839 {"binds", tcl_binds},
840 {"callevent", tcl_callevent},
841 {"stripcodes", tcl_stripcodes},
842 {"matchaddr", tcl_matchaddr},
843 {"matchcidr", tcl_matchcidr},
844 {"matchstr", tcl_matchstr},
845 {"status", tcl_status},
846 {"rfcequal", tcl_rfcequal},
847 {NULL, NULL}
848 };
849