/* tclmisc.c * * Copyright (C) 1997 Robey Pointer * Copyright (C) 1999 - 2006 Eggheads Development Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id: tclmisc.c,v 1.15 2006-11-20 13:53:36 tothwolf Exp $ */ #include "main.h" #include "modules.h" #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #include #ifdef HAVE_UNAME # include #endif #include "md5/md5.h" #include "botmsg.h" /* add_note */ #include "dcc.h" /* STRIP_*, strip_mirc_codes, struct dcc_t */ #include "dccutil.h" /* findidx */ #include "logfile.h" /* LOG_*, putlog */ #include "help.h" /* showhelp, tellhelp */ #include "match.h" /* wild_match_per, reload_help_data */ #include "misc.h" /* strncpyz, randint, kill_bot */ #include "net.h" /* getmyip */ extern p_tcl_bind_list bind_table_list; extern tcl_timer_t *timer, *utimer; extern struct dcc_t *dcc; extern char botnetnick[], quit_msg[]; extern struct userrec *userlist; extern time_t now; extern module_entry *module_list; extern Tcl_Interp *interp; static int tcl_binds(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { int matching = 0; char *g, flg[100], hits[11]; EGG_CONST char *list[5]; tcl_bind_list_t *tl, *tl_kind; tcl_bind_mask_t *tm; tcl_cmd_t *tc; BADARGS(1, 2, " ?type/mask?"); if (argv[1]) tl_kind = find_bind_table(argv[1]); else tl_kind = NULL; if (!tl_kind && argv[1]) matching = 1; for (tl = tl_kind ? tl_kind : bind_table_list; tl; tl = tl_kind ? 0 : tl->next) { if (tl->flags & HT_DELETED) continue; for (tm = tl->first; tm; tm = tm->next) { if (tm->flags & TBM_DELETED) continue; for (tc = tm->first; tc; tc = tc->next) { if (tc->attributes & TC_DELETED) continue; if (matching && !wild_match_per(argv[1], tl->name) && !wild_match_per(argv[1], tm->mask) && !wild_match_per(argv[1], tc->func_name)) continue; build_flags(flg, &(tc->flags), NULL); egg_snprintf(hits, sizeof hits, "%i", (int) tc->hits); list[0] = tl->name; list[1] = flg; list[2] = tm->mask; list[3] = hits; list[4] = tc->func_name; g = Tcl_Merge(5, list); Tcl_AppendElement(irp, g); Tcl_Free((char *) g); } } } return TCL_OK; } static int tcl_timer(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { unsigned long x; char s[16]; BADARGS(3, 3, " minutes command"); if (atoi(argv[1]) < 0) { Tcl_AppendResult(irp, "time value must be positive", NULL); return TCL_ERROR; } if (argv[2][0] != '#') { x = add_timer(&timer, atoi(argv[1]), argv[2], 0L); egg_snprintf(s, sizeof s, "timer%lu", x); Tcl_AppendResult(irp, s, NULL); } return TCL_OK; } static int tcl_utimer(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { unsigned long x; char s[16]; BADARGS(3, 3, " seconds command"); if (atoi(argv[1]) < 0) { Tcl_AppendResult(irp, "time value must be positive", NULL); return TCL_ERROR; } if (argv[2][0] != '#') { x = add_timer(&utimer, atoi(argv[1]), argv[2], 0L); egg_snprintf(s, sizeof s, "timer%lu", x); Tcl_AppendResult(irp, s, NULL); } return TCL_OK; } static int tcl_killtimer(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(2, 2, " timerID"); if (strncmp(argv[1], "timer", 5)) { Tcl_AppendResult(irp, "argument is not a timerID", NULL); return TCL_ERROR; } if (remove_timer(&timer, atol(&argv[1][5]))) return TCL_OK; Tcl_AppendResult(irp, "invalid timerID", NULL); return TCL_ERROR; } static int tcl_killutimer(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(2, 2, " timerID"); if (strncmp(argv[1], "timer", 5)) { Tcl_AppendResult(irp, "argument is not a timerID", NULL); return TCL_ERROR; } if (remove_timer(&utimer, atol(&argv[1][5]))) return TCL_OK; Tcl_AppendResult(irp, "invalid timerID", NULL); return TCL_ERROR; } static int tcl_timers(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(1, 1, ""); list_timers(irp, timer); return TCL_OK; } static int tcl_utimers(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(1, 1, ""); list_timers(irp, utimer); return TCL_OK; } static int tcl_duration(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char s[70]; unsigned long sec, tmp; BADARGS(2, 2, " seconds"); if (atol(argv[1]) <= 0) { Tcl_AppendResult(irp, "0 seconds", NULL); return TCL_OK; } sec = atol(argv[1]); s[0] = 0; if (sec >= 31536000) { tmp = (sec / 31536000); sprintf(s, "%lu year%s ", tmp, (tmp == 1) ? "" : "s"); sec -= (tmp * 31536000); } if (sec >= 604800) { tmp = (sec / 604800); sprintf(&s[strlen(s)], "%lu week%s ", tmp, (tmp == 1) ? "" : "s"); sec -= (tmp * 604800); } if (sec >= 86400) { tmp = (sec / 86400); sprintf(&s[strlen(s)], "%lu day%s ", tmp, (tmp == 1) ? "" : "s"); sec -= (tmp * 86400); } if (sec >= 3600) { tmp = (sec / 3600); sprintf(&s[strlen(s)], "%lu hour%s ", tmp, (tmp == 1) ? "" : "s"); sec -= (tmp * 3600); } if (sec >= 60) { tmp = (sec / 60); sprintf(&s[strlen(s)], "%lu minute%s ", tmp, (tmp == 1) ? "" : "s"); sec -= (tmp * 60); } if (sec > 0) { tmp = (sec); sprintf(&s[strlen(s)], "%lu second%s", tmp, (tmp == 1) ? "" : "s"); } if (strlen(s) > 0 && s[strlen(s) - 1] == ' ') s[strlen(s) - 1] = 0; Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_unixtime(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char s[11]; time_t now2 = time(NULL); BADARGS(1, 1, ""); egg_snprintf(s, sizeof s, "%li", now2); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_ctime(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { time_t tt; char s[25]; BADARGS(2, 2, " unixtime"); tt = (time_t) atol(argv[1]); strncpyz(s, ctime(&tt), sizeof s); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_strftime(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char buf[512]; struct tm *tm1; time_t t; BADARGS(2, 3, " format ?time?"); if (argc == 3) t = atol(argv[2]); else t = now; tm1 = localtime(&t); if (egg_strftime(buf, sizeof(buf) - 1, argv[1], tm1)) { Tcl_AppendResult(irp, buf, NULL); return TCL_OK; } Tcl_AppendResult(irp, " error with strftime", NULL); return TCL_ERROR; } static int tcl_myip(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char s[16]; BADARGS(1, 1, ""); egg_snprintf(s, sizeof s, "%lu", iptolong(getmyip())); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_rand(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { unsigned long x; char s[11]; BADARGS(2, 2, " limit"); if (atol(argv[1]) <= 0) { Tcl_AppendResult(irp, "random limit must be greater than zero", NULL); return TCL_ERROR; } x = randint((unsigned long) (atol(argv[1]))); egg_snprintf(s, sizeof s, "%lu", x); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_sendnote(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char s[5], from[NOTENAMELEN + 1], to[NOTENAMELEN + 1], msg[451]; BADARGS(4, 4, " from to message"); strncpyz(from, argv[1], sizeof from); strncpyz(to, argv[2], sizeof to); strncpyz(msg, argv[3], sizeof msg); egg_snprintf(s, sizeof s, "%d", add_note(to, from, msg, -1, 0)); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_dumpfile(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char nick[NICKLEN]; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; BADARGS(3, 3, " nickname filename"); strncpyz(nick, argv[1], sizeof nick); get_user_flagrec(get_user_by_nick(nick), &fr, NULL); showhelp(argv[1], argv[2], &fr, HELP_TEXT); return TCL_OK; } static int tcl_dccdumpfile(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { int idx, i; struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 }; BADARGS(3, 3, " idx filename"); i = atoi(argv[1]); idx = findidx(i); if (idx < 0) { Tcl_AppendResult(irp, "illegal idx", NULL); return TCL_ERROR; } get_user_flagrec(get_user_by_handle(userlist, dcc[idx].nick), &fr, NULL); tellhelp(idx, argv[2], &fr, HELP_TEXT); return TCL_OK; } static int tcl_backup(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(1, 1, ""); call_hook(HOOK_BACKUP); return TCL_OK; } static int tcl_die(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char s[1024]; BADARGS(1, 2, " ?reason?"); if (argc == 2) { egg_snprintf(s, sizeof s, "BOT SHUTDOWN (%s)", argv[1]); strncpyz(quit_msg, argv[1], 1024); } else { strncpyz(s, "BOT SHUTDOWN (No reason)", sizeof s); quit_msg[0] = 0; } kill_bot(s, quit_msg[0] ? quit_msg : "EXIT"); return TCL_OK; } static int tcl_loadmodule(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { const char *p; BADARGS(2, 2, " module-name"); p = module_load(argv[1]); if (p && strcmp(p, MOD_ALREADYLOAD) && !strcmp(argv[0], "loadmodule")) putlog(LOG_MISC, "*", "%s %s: %s", MOD_CANTLOADMOD, argv[1], p); Tcl_AppendResult(irp, p, NULL); return TCL_OK; } static int tcl_unloadmodule(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(2, 2, " module-name"); Tcl_AppendResult(irp, module_unload(argv[1], botnetnick), NULL); return TCL_OK; } static int tcl_unames(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char *unix_n, *vers_n; #ifdef HAVE_UNAME struct utsname un; if (uname(&un) < 0) { #endif unix_n = "*unkown*"; vers_n = ""; #ifdef HAVE_UNAME } else { unix_n = un.sysname; vers_n = un.release; } #endif Tcl_AppendResult(irp, unix_n, " ", vers_n, NULL); return TCL_OK; } static int tcl_modules(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { int i; char *p, s[24], s2[24]; EGG_CONST char *list[100], *list2[2]; dependancy *dep; module_entry *current; BADARGS(1, 1, ""); for (current = module_list; current; current = current->next) { list[0] = current->name; egg_snprintf(s, sizeof s, "%d.%d", current->major, current->minor); list[1] = s; i = 2; for (dep = dependancy_list; dep && (i < 100); dep = dep->next) { if (dep->needing == current) { list2[0] = dep->needed->name; egg_snprintf(s2, sizeof s2, "%d.%d", dep->major, dep->minor); list2[1] = s2; list[i] = Tcl_Merge(2, list2); i++; } } p = Tcl_Merge(i, list); Tcl_AppendElement(irp, p); Tcl_Free((char *) p); while (i > 2) { i--; Tcl_Free((char *) list[i]); } } return TCL_OK; } static int tcl_callevent(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { BADARGS(2, 2, " event"); check_tcl_event(argv[1]); return TCL_OK; } static int tcl_stripcodes(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { int flags = 0; char *p; BADARGS(3, 3, " strip-flags string"); for (p = argv[1]; *p; p++) switch (*p) { case 'a': flags |= STRIP_ANSI; break; case 'b': flags |= STRIP_BOLD; break; case 'c': flags |= STRIP_COLOR; break; case 'g': flags |= STRIP_BELLS; break; case 'r': flags |= STRIP_REV; break; case 'u': flags |= STRIP_UNDER; break; default: Tcl_AppendResult(irp, "Invalid strip-flags: ", argv[1], NULL); return TCL_ERROR; } strip_mirc_codes(flags, argv[2]); Tcl_AppendResult(irp, argv[2], NULL); return TCL_OK; } #ifdef USE_TCL_OBJ static int tcl_md5(cd, irp, objc, objv) ClientData cd; Tcl_Interp *irp; int objc; Tcl_Obj *CONST objv[]; { #else static int tcl_md5(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { #endif /* USE_TCL_OBJ */ MD5_CTX md5context; char digest_string[33], *string; unsigned char digest[16]; int i, len; #ifdef USE_TCL_OBJ if (objc != 2) { Tcl_WrongNumArgs(irp, 1, objv, "string"); return TCL_ERROR; } # ifdef USE_TCL_BYTE_ARRAYS string = (unsigned char *)Tcl_GetByteArrayFromObj(objv[1], &len); # else string = Tcl_GetStringFromObj(objv[1], &len); # endif /* USE_TCL_BYTE_ARRAYS */ #else /* USE_TCL_OBJ */ BADARGS(2, 2, " string"); string = argv[1]; len = strlen(argv[1]); #endif /* USE_TCL_OBJ */ MD5_Init(&md5context); MD5_Update(&md5context, (unsigned char *) string, len); MD5_Final(digest, &md5context); for (i = 0; i < 16; i++) sprintf(digest_string + (i * 2), "%.2x", digest[i]); Tcl_AppendResult(irp, digest_string, NULL); return TCL_OK; } tcl_cmds tclmisc_objcmds[] = { #ifdef USE_TCL_OBJ {"md5", tcl_md5}, #endif /* USE_TCL_OBJ */ {NULL, NULL} }; tcl_cmds tclmisc_cmds[] = { {"timer", tcl_timer}, {"utimer", tcl_utimer}, {"killtimer", tcl_killtimer}, {"killutimer", tcl_killutimer}, {"timers", tcl_timers}, {"utimers", tcl_utimers}, {"unixtime", tcl_unixtime}, {"strftime", tcl_strftime}, {"ctime", tcl_ctime}, {"myip", tcl_myip}, {"rand", tcl_rand}, {"sendnote", tcl_sendnote}, {"dumpfile", tcl_dumpfile}, {"dccdumpfile", tcl_dccdumpfile}, {"backup", tcl_backup}, {"exit", tcl_die}, {"die", tcl_die}, {"unames", tcl_unames}, {"unloadmodule", tcl_unloadmodule}, {"loadmodule", tcl_loadmodule}, {"checkmodule", tcl_loadmodule}, {"modules", tcl_modules}, {"duration", tcl_duration}, #ifndef USE_TCL_OBJ {"md5", tcl_md5}, #endif /* USE_TCL_OBJ */ {"binds", tcl_binds}, {"callevent", tcl_callevent}, {"stripcodes", tcl_stripcodes}, {NULL, NULL} };