1 /*
2  * tclmisc.c -- handles:
3  *   Tcl stubs for everything else
4  *
5  * $Id: tclmisc.c,v 1.49 (1.0.2) 2004/04/17 22:42:11 [Xp-AvR] Exp $
6  */
7 
8 #include "main.h"
9 #include "modules.h"
10 #include "tandem.h"
11 #include "md5/md5.h"
12 #ifdef TIME_WITH_SYS_TIME
13 # include <sys/time.h>
14 # include <time.h>
15 #else
16 # ifdef HAVE_SYS_TIME_H
17 #  include <sys/time.h>
18 # else
19 #  include <time.h>
20 # endif
21 #endif
22 #include <sys/stat.h>
23 #ifdef HAVE_UNAME
24 #include <sys/utsname.h>
25 #endif
26 
27 extern p_tcl_bind_list bind_table_list;
28 extern tcl_timer_t *timer, *utimer;
29 extern struct dcc_t *dcc;
30 extern char origbotname[], botnetnick[], quit_msg[];
31 extern struct userrec *userlist;
32 extern time_t now;
33 extern module_entry *module_list;
34 extern int max_logs;
35 extern log_t *logs;
36 extern Tcl_Interp *interp;
37 
38 #ifdef IPV6
39 extern char myipv6host[120];
40 
41 static int tcl_myip6 STDVAR
42 {
43   char s[120];
44 
45   getmyip();
46 
47   BADARGS(1, 1, "");
48 
49   s[0] = 0;
50   if(strlen(myipv6host) < 120)
51     strcpy(s, myipv6host);
52   Tcl_AppendResult(irp, s, NULL);
53   return TCL_OK;
54 }
55 #endif /* IPV6 */
56 
expmem_tclmisc()57 int expmem_tclmisc()
58 {
59   int i, tot = 0;
60 
61   for (i = 0; i < max_logs; i++)
62     if (logs[i].filename != NULL) {
63       tot += strlen(logs[i].filename) + 1;
64       tot += strlen(logs[i].chname) + 1;
65     }
66   return tot;
67 }
68 
69 /* logfile [<modes> <channel> <filename>] */
70 static int tcl_logfile STDVAR
71 {
72   int i;
73   char s[151];
74 
75   BADARGS(1, 4, " ?logModes channel logFile?");
76 
77   if (argc == 1) {
78     for (i = 0; i < max_logs; i++)
79       if (logs[i].filename != NULL) {
80         strcpy(s, masktype(logs[i].mask));
81         strcat(s, " ");
82         strcat(s, logs[i].chname);
83         strcat(s, " ");
84         strcat(s, logs[i].filename);
85         Tcl_AppendElement(interp, s);
86       }
87       return TCL_OK;
88   }
89 
90   BADARGS(4, 4, " ?logModes channel logFile?");
91 
92   for (i = 0; i < max_logs; i++)
93     if ((logs[i].filename != NULL) && (!strcmp(logs[i].filename, argv[3]))) {
94       logs[i].flags &= ~LF_EXPIRING;
95       logs[i].mask = logmodes(argv[1]);
96       nfree(logs[i].chname);
97       logs[i].chname = NULL;
98       if (!logs[i].mask) {
99         nfree(logs[i].filename);
100         logs[i].filename = NULL;
101         if (logs[i].f != NULL) {
102           fclose(logs[i].f);
103           logs[i].f = NULL;
104         }
105         logs[i].flags = 0;
106       } else {
107         logs[i].chname = (char *) nmalloc(strlen(argv[2]) + 1);
108         strcpy(logs[i].chname, argv[2]);
109       }
110       Tcl_AppendResult(interp, argv[3], NULL);
111       return TCL_OK;
112     }
113   if (!logmodes(argv[1])) {
114     Tcl_AppendResult(interp, "can't remove \"", argv[3],
115                      "\" from list: no such logfile", NULL);
116     return TCL_ERROR;
117   }
118   for (i = 0; i < max_logs; i++)
119     if (logs[i].filename == NULL) {
120       logs[i].flags = 0;
121       logs[i].mask = logmodes(argv[1]);
122       logs[i].filename = (char *) nmalloc(strlen(argv[3]) + 1);
123       strcpy(logs[i].filename, argv[3]);
124       logs[i].chname = (char *) nmalloc(strlen(argv[2]) + 1);
125       strcpy(logs[i].chname, argv[2]);
126       Tcl_AppendResult(interp, argv[3], NULL);
127       return TCL_OK;
128     }
129   Tcl_AppendResult(interp, "reached max # of logfiles", NULL);
130   return TCL_ERROR;
131 }
132 
133 static int tcl_putlog STDVAR
134 {
135   char logtext[501];
136 
137   BADARGS(2, 2, " text");
138 
139   strncpyz(logtext, argv[1], sizeof logtext);
140   putlog(LOG_MISC, "*", "%s", logtext);
141   return TCL_OK;
142 }
143 
144 static int tcl_putcmdlog STDVAR
145 {
146   char logtext[501];
147 
148   BADARGS(2, 2, " text");
149 
150   strncpyz(logtext, argv[1], sizeof logtext);
151   putlog(LOG_CMDS, "*", "%s", logtext);
152   return TCL_OK;
153 }
154 
155 static int tcl_putxferlog STDVAR
156 {
157   char logtext[501];
158 
159   BADARGS(2, 2, " text");
160 
161   strncpyz(logtext, argv[1], sizeof logtext);
162   putlog(LOG_FILES, "*", "%s", logtext);
163   return TCL_OK;
164 }
165 
166 static int tcl_putloglev STDVAR
167 {
168   int lev = 0;
169   char logtext[501];
170 
171   BADARGS(4, 4, " level channel text");
172 
173   lev = logmodes(argv[1]);
174   if (!lev) {
175     Tcl_AppendResult(irp, "No valid log-level given", NULL);
176     return TCL_ERROR;
177   }
178   strncpyz(logtext, argv[3], sizeof logtext);
179 
180   putlog(lev, argv[2], "%s", logtext);
181   return TCL_OK;
182 }
183 
184 static int tcl_binds STDVAR
185 {
186   int matching = 0;
187   char *g, flg[100], hits[11];
188   EVANGELINE_CONST char *list[5];
189   tcl_bind_list_t *tl, *tl_kind;
190   tcl_bind_mask_t *tm;
191   tcl_cmd_t *tc;
192 
193   BADARGS(1, 2, " ?type/mask?");
194 
195   if (argv[1])
196     tl_kind = find_bind_table(argv[1]);
197   else
198     tl_kind = NULL;
199   if (!tl_kind && argv[1])
200     matching = 1;
201   for (tl = tl_kind ? tl_kind : bind_table_list; tl;
202        tl = tl_kind ? 0 : tl->next) {
203     if (tl->flags & HT_DELETED)
204       continue;
205     for (tm = tl->first; tm; tm = tm->next) {
206       if (tm->flags & TBM_DELETED)
207         continue;
208       for (tc = tm->first; tc; tc = tc->next) {
209         if (tc->attributes & TC_DELETED)
210           continue;
211         if (matching &&
212             !wild_match_per(argv[1], tl->name) &&
213             !wild_match_per(argv[1], tm->mask) &&
214             !wild_match_per(argv[1], tc->func_name))
215           continue;
216         build_flags(flg, &(tc->flags), NULL);
217         EvangelineSnprintf(hits, sizeof hits, "%i", (int) tc->hits);
218         list[0] = tl->name;
219         list[1] = flg;
220         list[2] = tm->mask;
221         list[3] = hits;
222         list[4] = tc->func_name;
223         g = Tcl_Merge(5, list);
224         Tcl_AppendElement(irp, g);
225         Tcl_Free((char *) g);
226       }
227     }
228   }
229   return TCL_OK;
230 }
231 
232 static int tcl_timer STDVAR
233 {
234   unsigned long x;
235   char s[16];
236 
237   BADARGS(3, 3, " minutes command");
238 
239   if (atoi(argv[1]) < 0) {
240     Tcl_AppendResult(irp, "time value must be positive", NULL);
241     return TCL_ERROR;
242   }
243   if (argv[2][0] != '#') {
244     x = add_timer(&timer, atoi(argv[1]), argv[2], 0L);
245     EvangelineSnprintf(s, sizeof s, "timer%lu", x);
246     Tcl_AppendResult(irp, s, NULL);
247   }
248   return TCL_OK;
249 }
250 
251 static int tcl_utimer STDVAR
252 {
253   unsigned long x;
254   char s[16];
255 
256   BADARGS(3, 3, " seconds command");
257 
258   if (atoi(argv[1]) < 0) {
259     Tcl_AppendResult(irp, "time value must be positive", NULL);
260     return TCL_ERROR;
261   }
262   if (argv[2][0] != '#') {
263     x = add_timer(&utimer, atoi(argv[1]), argv[2], 0L);
264     EvangelineSnprintf(s, sizeof s, "timer%lu", x);
265     Tcl_AppendResult(irp, s, NULL);
266   }
267   return TCL_OK;
268 }
269 
270 static int tcl_killtimer STDVAR
271 {
272   BADARGS(2, 2, " timerID");
273 
274   if (strncmp(argv[1], "timer", 5)) {
275     Tcl_AppendResult(irp, "argument is not a timerID", NULL);
276     return TCL_ERROR;
277   }
278   if (remove_timer(&timer, atol(&argv[1][5])))
279     return TCL_OK;
280   Tcl_AppendResult(irp, "invalid timerID", NULL);
281   return TCL_ERROR;
282 }
283 
284 static int tcl_killutimer STDVAR
285 {
286   BADARGS(2, 2, " timerID");
287 
288   if (strncmp(argv[1], "timer", 5)) {
289     Tcl_AppendResult(irp, "argument is not a timerID", NULL);
290     return TCL_ERROR;
291   }
292   if (remove_timer(&utimer, atol(&argv[1][5])))
293     return TCL_OK;
294   Tcl_AppendResult(irp, "invalid timerID", NULL);
295   return TCL_ERROR;
296 }
297 
298 static int tcl_timers STDVAR
299 {
300   BADARGS(1, 1, "");
301 
302   list_timers(irp, timer);
303   return TCL_OK;
304 }
305 
306 static int tcl_utimers STDVAR
307 {
308   BADARGS(1, 1, "");
309 
310   list_timers(irp, utimer);
311   return TCL_OK;
312 }
313 
314 static int tcl_duration STDVAR
315 {
316   char s[70];
317   unsigned long sec, tmp;
318 
319   BADARGS(2, 2, " seconds");
320 
321   if (atol(argv[1]) <= 0) {
322     Tcl_AppendResult(irp, "0 seconds", NULL);
323     return TCL_OK;
324   }
325   sec = atol(argv[1]);
326 
327   s[0] = 0;
328   if (sec >= 31536000) {
329     tmp = (sec / 31536000);
330     sprintf(s, "%lu year%s ", tmp, (tmp == 1) ? "" : "s");
331     sec -= (tmp * 31536000);
332   }
333   if (sec >= 604800) {
334     tmp = (sec / 604800);
335     sprintf(&s[strlen(s)], "%lu week%s ", tmp, (tmp == 1) ? "" : "s");
336     sec -= (tmp * 604800);
337   }
338   if (sec >= 86400) {
339     tmp = (sec / 86400);
340     sprintf(&s[strlen(s)], "%lu day%s ", tmp, (tmp == 1) ? "" : "s");
341     sec -= (tmp * 86400);
342   }
343   if (sec >= 3600) {
344     tmp = (sec / 3600);
345     sprintf(&s[strlen(s)], "%lu hour%s ", tmp, (tmp == 1) ? "" : "s");
346     sec -= (tmp * 3600);
347   }
348   if (sec >= 60) {
349     tmp = (sec / 60);
350     sprintf(&s[strlen(s)], "%lu minute%s ", tmp, (tmp == 1) ? "" : "s");
351     sec -= (tmp * 60);
352   }
353   if (sec > 0) {
354     tmp = (sec);
355     sprintf(&s[strlen(s)], "%lu second%s", tmp, (tmp == 1) ? "" : "s");
356   }
357   if (strlen(s) > 0 && s[strlen(s) - 1] == ' ')
358     s[strlen(s) - 1] = 0;
359   Tcl_AppendResult(irp, s, NULL);
360   return TCL_OK;
361 }
362 
363 static int tcl_unixtime STDVAR
364 {
365   char s[11];
366   time_t now2 = time(NULL);
367 
368   BADARGS(1, 1, "");
369 
370   EvangelineSnprintf(s, sizeof s, "%lu", (unsigned long) now2);
371   Tcl_AppendResult(irp, s, NULL);
372   return TCL_OK;
373 }
374 
375 static int tcl_ctime STDVAR
376 {
377   time_t tt;
378   char s[25];
379 
380   BADARGS(2, 2, " unixtime");
381 
382   tt = (time_t) atol(argv[1]);
383   strncpyz(s, ctime(&tt), sizeof s);
384   Tcl_AppendResult(irp, s, NULL);
385   return TCL_OK;
386 }
387 
388 static int tcl_strftime STDVAR
389 {
390   char buf[512];
391   struct tm *tm1;
392   time_t t;
393 
394   BADARGS(2, 3, " format ?time?");
395 
396   if (argc == 3)
397     t = atol(argv[2]);
398   else
399     t = now;
400   tm1 = localtime(&t);
401   if (EvangelineStrftime(buf, sizeof(buf) - 1, argv[1], tm1)) {
402     Tcl_AppendResult(irp, buf, NULL);
403     return TCL_OK;
404   }
405   Tcl_AppendResult(irp, " error with strftime", NULL);
406   return TCL_ERROR;
407 }
408 
409 static int tcl_myip STDVAR
410 {
411   char s[16];
412 
413   BADARGS(1, 1, "");
414 
415   EvangelineSnprintf(s, sizeof s, "%lu", iptolong(getmyip()));
416   Tcl_AppendResult(irp, s, NULL);
417   return TCL_OK;
418 }
419 
420 static int tcl_rand STDVAR
421 {
422   unsigned long x;
423   char s[11];
424 
425   BADARGS(2, 2, " limit");
426 
427   if (atol(argv[1]) <= 0) {
428     Tcl_AppendResult(irp, "random limit must be greater than zero", NULL);
429     return TCL_ERROR;
430   }
431    x = random() % (unsigned long) (atol(argv[1]));
432 
433   EvangelineSnprintf(s, sizeof s, "%lu", x);
434   Tcl_AppendResult(irp, s, NULL);
435   return TCL_OK;
436 }
437 
438 static int tcl_sendnote STDVAR
439 {
440   char s[5], from[NOTENAMELEN + 1], to[NOTENAMELEN + 1], msg[451];
441 
442   BADARGS(4, 4, " from to message");
443 
444   strncpyz(from, argv[1], sizeof from);
445   strncpyz(to, argv[2], sizeof to);
446   strncpyz(msg, argv[3], sizeof msg);
447   EvangelineSnprintf(s, sizeof s, "%d", add_note(to, from, msg, -1, 0));
448   Tcl_AppendResult(irp, s, NULL);
449   return TCL_OK;
450 }
451 
452 static int tcl_dumpfile STDVAR
453 {
454   char nick[NICKLEN];
455   struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
456 
457   BADARGS(3, 3, " nickname filename");
458 
459   strncpyz(nick, argv[1], sizeof nick);
460   get_user_flagrec(get_user_by_nick(nick), &fr, NULL);
461   return TCL_OK;
462 }
463 
464 static int tcl_dccdumpfile STDVAR
465 {
466   int idx, i;
467   struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
468 
469   BADARGS(3, 3, " idx filename");
470 
471   i = atoi(argv[1]);
472   idx = findidx(i);
473   if (idx < 0) {
474     Tcl_AppendResult(irp, "illegal idx", NULL);
475     return TCL_ERROR;
476   }
477   get_user_flagrec(get_user_by_handle(userlist, dcc[idx].nick), &fr, NULL);
478 
479   return TCL_OK;
480 }
481 
482 static int tcl_backup STDVAR
483 {
484   BADARGS(1, 1, "");
485 
486   call_hook(HOOK_BACKUP);
487   return TCL_OK;
488 }
489 
490 static int tcl_die STDVAR
491 {
492   char s[1024];
493 
494   BADARGS(1, 2, " ?reason?");
495 
496   if (argc == 2) {
497     EvangelineSnprintf(s, sizeof s, "BOT SHUTDOWN (%s)", argv[1]);
498     strncpyz(quit_msg, argv[1], 1024);
499   } else {
500     strncpyz(s, "BOT SHUTDOWN (No reason)", sizeof s);
501     quit_msg[0] = 0;
502   }
503   kill_bot(s, quit_msg[0] ? quit_msg : "EXIT");
504   return TCL_OK;
505 }
506 
507 static int tcl_loadmodule STDVAR
508 {
509   const char *p;
510 
511   BADARGS(2, 2, " module-name");
512 
513   p = module_load(argv[1]);
514   if (p && strcmp(p, MOD_ALREADYLOAD) && !strcmp(argv[0], "loadmodule"))
515     putlog(LOG_MISC, "*", "%s %s: %s", MOD_CANTLOADMOD, argv[1], p);
516   Tcl_AppendResult(irp, p, NULL);
517   return TCL_OK;
518 }
519 
520 static int tcl_unloadmodule STDVAR
521 {
522   BADARGS(2, 2, " module-name");
523 
524   Tcl_AppendResult(irp, module_unload(argv[1], botnetnick), NULL);
525   return TCL_OK;
526 }
527 
528 static int tcl_unames STDVAR
529 {
530   char *unix_n, *vers_n;
531 #ifdef HAVE_UNAME
532   struct utsname un;
533 
534   if (uname(&un) < 0) {
535 #endif
536     unix_n = "*unkown*";
537     vers_n = "";
538 #ifdef HAVE_UNAME
539   } else {
540     unix_n = un.sysname;
541     vers_n = un.release;
542   }
543 #endif
544   Tcl_AppendResult(irp, unix_n, " ", vers_n, NULL);
545   return TCL_OK;
546 }
547 
548 static int tcl_modules STDVAR
549 {
550   int i;
551   char *p, s[24], s2[24];
552   EVANGELINE_CONST char *list[100], *list2[2];
553   dependancy *dep;
554   module_entry *current;
555 
556   BADARGS(1, 1, "");
557 
558   for (current = module_list; current; current = current->next) {
559     list[0] = current->name;
560     EvangelineSnprintf(s, sizeof s, "%d.%d", current->major, current->minor);
561     list[1] = s;
562     i = 2;
563     for (dep = dependancy_list; dep && (i < 100); dep = dep->next) {
564       if (dep->needing == current) {
565         list2[0] = dep->needed->name;
566         EvangelineSnprintf(s2, sizeof s2, "%d.%d", dep->major, dep->minor);
567         list2[1] = s2;
568         list[i] = Tcl_Merge(2, list2);
569         i++;
570       }
571     }
572     p = Tcl_Merge(i, list);
573     Tcl_AppendElement(irp, p);
574     Tcl_Free((char *) p);
575     while (i > 2) {
576       i--;
577       Tcl_Free((char *) list[i]);
578     }
579   }
580   return TCL_OK;
581 }
582 
583 static int tcl_callevent STDVAR
584 {
585   BADARGS(2, 2, " event");
586 
587   check_tcl_event(argv[1]);
588   return TCL_OK;
589 }
590 
591 #ifdef USE_TCL_OBJ
tcl_md5(cd,irp,objc,objv)592 static int tcl_md5(cd, irp, objc, objv)
593 ClientData cd;
594 Tcl_Interp *irp;
595 int objc;
596 Tcl_Obj *CONST objv[];
597 {
598 #else
599 static int tcl_md5 STDVAR
600 {
601 #endif /* USE_TCL_OBJ */
602   MD5_CTX md5context;
603   char digest_string[33], *string;
604   unsigned char digest[16];
605   int i, len;
606 
607 #ifdef USE_TCL_OBJ
608   if (objc != 2) {
609     Tcl_WrongNumArgs(irp, 1, objv, "string");
610     return TCL_ERROR;
611   }
612 #  ifdef USE_TCL_BYTE_ARRAYS
613     string = (unsigned char *)Tcl_GetByteArrayFromObj(objv[1], &len);
614 #  else
615   string = Tcl_GetStringFromObj(objv[1], &len);
616 #  endif /* USE_TCL_BYTE_ARRAYS */
617 #else /* USE_TCL_OBJ */
618   BADARGS(2, 2, " string");
619 
620   string = argv[1];
621   len = strlen(argv[1]);
622 #endif /* USE_TCL_OBJ */
623 
624   MD5_Init(&md5context);
625   MD5_Update(&md5context, (unsigned char *) string, len);
626   MD5_Final(digest, &md5context);
627   for (i = 0; i < 16; i++)
628     sprintf(digest_string + (i * 2), "%.2x", digest[i]);
629   Tcl_AppendResult(irp, digest_string, NULL);
630   return TCL_OK;
631 }
632 
633 static int tcl_md5sum STDVAR
634 {
635   char *md5Digest;
636 
637   BADARGS(2, 2, " fname");
638   if (file_readable(argv[1])) {
639     md5Digest = getMd5ControlSum(argv[1]);
640     Tcl_AppendResult(irp, md5Digest, NULL);
641   }
642 
643   return TCL_OK;
644 }
645 
646 static int tcl_source STDVAR
647 {
648   char fname[260];
649 
650   BADARGS(2, 2, " ?path?");
651   strncpy(fname, argv[1], 260);
652   fname[259]=0;
653   if (file_readable(fname))
654     readtclprog(fname);
655 
656   return TCL_OK;
657 }
658 
659 tcl_cmds tclmisc_objcmds[] = {
660 #ifdef USE_TCL_OBJ
661   {"md5", tcl_md5},
662 #endif /* USE_TCL_OBJ */
663   {NULL,     NULL}
664 };
665 
666 tcl_cmds tclmisc_cmds[] = {
667   {"logfile",           tcl_logfile},
668   {"putlog",             tcl_putlog},
669   {"putcmdlog",       tcl_putcmdlog},
670   {"putxferlog",     tcl_putxferlog},
671   {"putloglev",       tcl_putloglev},
672   {"timer",               tcl_timer},
673   {"utimer",             tcl_utimer},
674   {"killtimer",       tcl_killtimer},
675   {"killutimer",     tcl_killutimer},
676   {"timers",             tcl_timers},
677   {"utimers",           tcl_utimers},
678   {"unixtime",         tcl_unixtime},
679   {"strftime",         tcl_strftime},
680   {"ctime",               tcl_ctime},
681   {"myip",                 tcl_myip},
682 #ifdef IPV6
683   {"myip6",               tcl_myip6},
684 #endif /* IPV6 */
685   {"rand",                 tcl_rand},
686   {"sendnote",         tcl_sendnote},
687   {"dumpfile",         tcl_dumpfile},
688   {"dccdumpfile",   tcl_dccdumpfile},
689   {"backup",             tcl_backup},
690   {"exit",                  tcl_die},
691   {"die",                   tcl_die},
692   {"unames",             tcl_unames},
693   {"unloadmodule", tcl_unloadmodule},
694   {"loadmodule",     tcl_loadmodule},
695   {"checkmodule",    tcl_loadmodule},
696   {"modules",           tcl_modules},
697   {"duration",         tcl_duration},
698 #ifndef USE_TCL_OBJ
699   {"md5",                   tcl_md5},
700 #endif /* USE_TCL_OBJ */
701   {"md5sum",             tcl_md5sum},
702   {"binds",               tcl_binds},
703   {"callevent",       tcl_callevent},
704   {"source",             tcl_source},
705   {NULL,                       NULL}
706 };
707