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