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