/* * tcldcc.c -- handles: * Tcl stubs for the dcc commands * * $Id: tcldcc.c,v 1.70 2011/02/13 14:19:33 simple Exp $ */ /* * Copyright (C) 1997 Robey Pointer * Copyright (C) 1999 - 2011 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. */ #include "main.h" #include "tandem.h" #include "modules.h" extern Tcl_Interp *interp; extern tcl_timer_t *timer, *utimer; extern struct dcc_t *dcc; extern char botnetnick[]; extern int dcc_total, backgrd, parties, make_userfile, do_restart, remote_boots, max_dcc; extern party_t *party; extern tand_t *tandbot; extern time_t now; extern unsigned long otraffic_irc, otraffic_irc_today, itraffic_irc, itraffic_irc_today, otraffic_bn, otraffic_bn_today, itraffic_bn, itraffic_bn_today, otraffic_dcc, otraffic_dcc_today, itraffic_dcc, itraffic_dcc_today, otraffic_trans, otraffic_trans_today, itraffic_trans, itraffic_trans_today, otraffic_unknown, itraffic_unknown, otraffic_unknown_today, itraffic_unknown_today; static struct portmap *root = NULL; int expmem_tcldcc(void) { int tot = 0; struct portmap *pmap; for (pmap = root; pmap; pmap = pmap->next) tot += sizeof(struct portmap); return tot; } static int tcl_putdcc STDVAR { int j; BADARGS(3, 4, " idx text ?options?"); if ((argc == 4) && egg_strcasecmp(argv[3], "-raw")) { Tcl_AppendResult(irp, "unknown putdcc option: should be ", "-raw", NULL); return TCL_ERROR; } j = findidx(atoi(argv[1])); if (j < 0) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (argc == 4) tputs(dcc[j].sock, argv[2], strlen(argv[2])); else dumplots(j, "", argv[2]); return TCL_OK; } /* Allows tcl scripts to send out raw data. Can be used for fast server write. * The server idx is 0. * * Usage: putdccraw * * Example: putdccraw 6 13 "eggdrop rulz\n" * * Added by . */ static int tcl_putdccraw STDVAR { #if 0 int i, j = 0, z; BADARGS(4, 4, " idx size text"); z = atoi(argv[1]); for (i = 0; i < dcc_total; i++) { if (!z && !strcmp(dcc[i].nick, "(server)")) { j = dcc[i].sock; break; } else if (dcc[i].sock == z) { j = dcc[i].sock; break; } } if (i == dcc_total) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } tputs(j, argv[3], atoi(argv[2])); return TCL_OK; #endif Tcl_AppendResult(irp, "putdccraw is deprecated. " "Please use putdcc/putnow instead.", NULL); return TCL_ERROR; } static int tcl_dccsimul STDVAR { int idx; BADARGS(3, 3, " idx command"); idx = findidx(atoi(argv[1])); if (idx >= 0 && (dcc[idx].type->flags & DCT_SIMUL)) { int l = strlen(argv[2]); if (l > 510) { l = 510; argv[2][510] = 0; /* Restrict length of cmd */ } if (dcc[idx].type && dcc[idx].type->activity) { dcc[idx].type->activity(idx, argv[2], l); return TCL_OK; } } else { Tcl_AppendResult(irp, "invalid idx", NULL); } return TCL_ERROR; } static int tcl_dccbroadcast STDVAR { char msg[401]; BADARGS(2, 2, " message"); strncpyz(msg, argv[1], sizeof msg); chatout("*** %s\n", msg); botnet_send_chat(-1, botnetnick, msg); check_tcl_bcst(botnetnick, -1, msg); return TCL_OK; } static int tcl_hand2idx STDVAR { int i; char s[11]; BADARGS(2, 2, " nickname"); for (i = 0; i < dcc_total; i++) if ((dcc[i].type->flags & (DCT_SIMUL | DCT_BOT)) && !egg_strcasecmp(argv[1], dcc[i].nick)) { egg_snprintf(s, sizeof s, "%ld", dcc[i].sock); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } Tcl_AppendResult(irp, "-1", NULL); return TCL_OK; } static int tcl_getchan STDVAR { char s[7]; int idx; BADARGS(2, 2, " idx"); idx = findidx(atoi(argv[1])); if (idx < 0 || (dcc[idx].type != &DCC_CHAT && dcc[idx].type != &DCC_SCRIPT)) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (dcc[idx].type == &DCC_SCRIPT) egg_snprintf(s, sizeof s, "%d", dcc[idx].u.script->u.chat->channel); else egg_snprintf(s, sizeof s, "%d", dcc[idx].u.chat->channel); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_setchan STDVAR { int idx, chan; module_entry *me; BADARGS(3, 3, " idx channel"); idx = findidx(atoi(argv[1])); if (idx < 0 || (dcc[idx].type != &DCC_CHAT && dcc[idx].type != &DCC_SCRIPT)) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (argv[2][0] < '0' || argv[2][0] > '9') { if (!strcmp(argv[2], "-1") || !egg_strcasecmp(argv[2], "off")) chan = -1; else { Tcl_SetVar(irp, "_chan", argv[2], 0); if (Tcl_VarEval(irp, "assoc ", "$_chan", NULL) != TCL_OK || tcl_resultempty()) { Tcl_AppendResult(irp, "channel name is invalid", NULL); return TCL_ERROR; } chan = tcl_resultint(); } } else chan = atoi(argv[2]); if ((chan < -1) || (chan > 199999)) { Tcl_AppendResult(irp, "channel out of range; must be -1 through 199999", NULL); return TCL_ERROR; } if (dcc[idx].type == &DCC_SCRIPT) dcc[idx].u.script->u.chat->channel = chan; else { int oldchan = dcc[idx].u.chat->channel; if (dcc[idx].u.chat->channel >= 0) { if ((chan >= GLOBAL_CHANS) && (oldchan < GLOBAL_CHANS)) botnet_send_part_idx(idx, "*script*"); check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock, dcc[idx].u.chat->channel); } dcc[idx].u.chat->channel = chan; if (chan < GLOBAL_CHANS) botnet_send_join_idx(idx, oldchan); check_tcl_chjn(botnetnick, dcc[idx].nick, chan, geticon(idx), dcc[idx].sock, dcc[idx].host); } /* Console autosave. */ if ((me = module_find("console", 1, 1))) { Function *func = me->funcs; (func[CONSOLE_DOSTORE]) (idx); } return TCL_OK; } static int tcl_dccputchan STDVAR { int chan; char msg[401]; BADARGS(3, 3, " channel message"); chan = atoi(argv[1]); if ((chan < 0) || (chan > 199999)) { Tcl_AppendResult(irp, "channel out of range; must be 0 through 199999", NULL); return TCL_ERROR; } strncpyz(msg, argv[2], sizeof msg); chanout_but(-1, chan, "*** %s\n", argv[2]); botnet_send_chan(-1, botnetnick, NULL, chan, argv[2]); check_tcl_bcst(botnetnick, chan, argv[2]); return TCL_OK; } static int tcl_console STDVAR { int i, j, pls, arg; module_entry *me; BADARGS(2, 4, " idx ?channel? ?console-modes?"); i = findidx(atoi(argv[1])); if (i < 0 || dcc[i].type != &DCC_CHAT) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } pls = 1; for (arg = 2; arg < argc; arg++) { if (argv[arg][0] && ((strchr(CHANMETA, argv[arg][0]) != NULL) || (argv[arg][0] == '*'))) { if ((argv[arg][0] != '*') && (!findchan_by_dname(argv[arg]))) { /* If we dont find the channel, and it starts with a +, assume it * should be the console flags to set. */ if (argv[arg][0] == '+') goto do_console_flags; Tcl_AppendResult(irp, "invalid channel", NULL); return TCL_ERROR; } strncpyz(dcc[i].u.chat->con_chan, argv[arg], 81); } else { if ((argv[arg][0] != '+') && (argv[arg][0] != '-')) dcc[i].u.chat->con_flags = 0; do_console_flags: for (j = 0; j < strlen(argv[arg]); j++) { if (argv[arg][j] == '+') pls = 1; else if (argv[arg][j] == '-') pls = -1; else { char s[2]; s[0] = argv[arg][j]; s[1] = 0; if (pls == 1) dcc[i].u.chat->con_flags |= logmodes(s); else dcc[i].u.chat->con_flags &= ~logmodes(s); } } } } Tcl_AppendElement(irp, dcc[i].u.chat->con_chan); Tcl_AppendElement(irp, masktype(dcc[i].u.chat->con_flags)); /* Console autosave. */ if (argc > 2 && (me = module_find("console", 1, 1))) { Function *func = me->funcs; (func[CONSOLE_DOSTORE]) (i); } return TCL_OK; } static int tcl_strip STDVAR { int i, j, pls, arg; module_entry *me; BADARGS(2, 4, " idx ?strip-flags?"); i = findidx(atoi(argv[1])); if (i < 0 || dcc[i].type != &DCC_CHAT) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } pls = 1; for (arg = 2; arg < argc; arg++) { if ((argv[arg][0] != '+') && (argv[arg][0] != '-')) dcc[i].u.chat->strip_flags = 0; for (j = 0; j < strlen(argv[arg]); j++) { if (argv[arg][j] == '+') pls = 1; else if (argv[arg][j] == '-') pls = -1; else { char s[2]; s[0] = argv[arg][j]; s[1] = 0; if (pls == 1) dcc[i].u.chat->strip_flags |= stripmodes(s); else dcc[i].u.chat->strip_flags &= ~stripmodes(s); } } } Tcl_AppendElement(irp, stripmasktype(dcc[i].u.chat->strip_flags)); /* Console autosave. */ if (argc > 2 && (me = module_find("console", 1, 1))) { Function *func = me->funcs; (func[CONSOLE_DOSTORE]) (i); } return TCL_OK; } static int tcl_echo STDVAR { int i; module_entry *me; BADARGS(2, 3, " idx ?status?"); i = findidx(atoi(argv[1])); if (i < 0 || dcc[i].type != &DCC_CHAT) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (argc == 3) { if (atoi(argv[2])) dcc[i].status |= STAT_ECHO; else dcc[i].status &= ~STAT_ECHO; } if (dcc[i].status & STAT_ECHO) Tcl_AppendResult(irp, "1", NULL); else Tcl_AppendResult(irp, "0", NULL); /* Console autosave. */ if (argc > 2 && (me = module_find("console", 1, 1))) { Function *func = me->funcs; (func[CONSOLE_DOSTORE]) (i); } return TCL_OK; } static int tcl_page STDVAR { int i; char x[20]; module_entry *me; BADARGS(2, 3, " idx ?status?"); i = findidx(atoi(argv[1])); if (i < 0 || dcc[i].type != &DCC_CHAT) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (argc == 3) { int l = atoi(argv[2]); if (!l) dcc[i].status &= ~STAT_PAGE; else { dcc[i].status |= STAT_PAGE; dcc[i].u.chat->max_line = l; } } if (dcc[i].status & STAT_PAGE) { egg_snprintf(x, sizeof x, "%d", dcc[i].u.chat->max_line); Tcl_AppendResult(irp, x, NULL); } else Tcl_AppendResult(irp, "0", NULL); /* Console autosave. */ if ((argc > 2) && (me = module_find("console", 1, 1))) { Function *func = me->funcs; (func[CONSOLE_DOSTORE]) (i); } return TCL_OK; } static int tcl_control STDVAR { int idx; void *hold; BADARGS(3, 3, " idx command"); idx = findidx(atoi(argv[1])); if (idx < 0) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (dcc[idx].type->flags & DCT_CHAT) { if (dcc[idx].u.chat->channel >= 0) { chanout_but(idx, dcc[idx].u.chat->channel, "*** %s has gone.\n", dcc[idx].nick); check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock, dcc[idx].u.chat->channel); botnet_send_part_idx(idx, "gone"); } check_tcl_chof(dcc[idx].nick, dcc[idx].sock); } hold = dcc[idx].u.other; dcc[idx].u.script = get_data_ptr(sizeof(struct script_info)); dcc[idx].u.script->u.other = hold; dcc[idx].u.script->type = dcc[idx].type; dcc[idx].type = &DCC_SCRIPT; /* Do not buffer data anymore. All received and stored data is passed * over to the dcc functions from now on. */ sockoptions(dcc[idx].sock, EGG_OPTION_UNSET, SOCK_BUFFER); strncpyz(dcc[idx].u.script->command, argv[2], 120); return TCL_OK; } static int tcl_valididx STDVAR { int idx; BADARGS(2, 2, " idx"); idx = findidx(atoi(argv[1])); if (idx < 0 || !(dcc[idx].type->flags & DCT_VALIDIDX)) Tcl_AppendResult(irp, "0", NULL); else Tcl_AppendResult(irp, "1", NULL); return TCL_OK; } static int tcl_killdcc STDVAR { int idx; BADARGS(2, 3, " idx ?reason?"); idx = findidx(atoi(argv[1])); if (idx < 0) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if ((dcc[idx].sock == STDOUT) && !backgrd) /* Don't kill terminal socket */ return TCL_OK; if (dcc[idx].type->flags & DCT_CHAT) { /* Make sure 'whom' info is updated */ chanout_but(idx, dcc[idx].u.chat->channel, "*** %s has left the %s%s%s\n", dcc[idx].nick, dcc[idx].u.chat ? "channel" : "partyline", argc == 3 ? ": " : "", argc == 3 ? argv[2] : ""); botnet_send_part_idx(idx, argc == 3 ? argv[2] : ""); if ((dcc[idx].u.chat->channel >= 0) && (dcc[idx].u.chat->channel < GLOBAL_CHANS)) check_tcl_chpt(botnetnick, dcc[idx].nick, dcc[idx].sock, dcc[idx].u.chat->channel); check_tcl_chof(dcc[idx].nick, dcc[idx].sock); } killsock(dcc[idx].sock); killtransfer(idx); lostdcc(idx); return TCL_OK; } static int tcl_putbot STDVAR { int i; char msg[401]; BADARGS(3, 3, " botnick message"); i = nextbot(argv[1]); if (i < 0) { Tcl_AppendResult(irp, "bot is not on the botnet", NULL); return TCL_ERROR; } strncpyz(msg, argv[2], sizeof msg); botnet_send_zapf(i, botnetnick, argv[1], msg); return TCL_OK; } static int tcl_putallbots STDVAR { char msg[401]; BADARGS(2, 2, " message"); strncpyz(msg, argv[1], sizeof msg); botnet_send_zapf_broad(-1, botnetnick, NULL, msg); return TCL_OK; } static int tcl_idx2hand STDVAR { int idx; BADARGS(2, 2, " idx"); idx = findidx(atoi(argv[1])); if (idx < 0) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } Tcl_AppendResult(irp, dcc[idx].nick, NULL); return TCL_OK; } static int tcl_islinked STDVAR { int i; BADARGS(2, 2, " bot"); i = nextbot(argv[1]); if (i < 0) Tcl_AppendResult(irp, "0", NULL); else Tcl_AppendResult(irp, "1", NULL); return TCL_OK; } static int tcl_bots STDVAR { tand_t *bot; BADARGS(1, 1, ""); for (bot = tandbot; bot; bot = bot->next) Tcl_AppendElement(irp, bot->bot); return TCL_OK; } static int tcl_botlist STDVAR { char *p, sh[2], string[20]; EGG_CONST char *list[4]; tand_t *bot; BADARGS(1, 1, ""); sh[1] = 0; list[3] = sh; list[2] = string; for (bot = tandbot; bot; bot = bot->next) { list[0] = bot->bot; list[1] = (bot->uplink == (tand_t *) 1) ? botnetnick : bot->uplink->bot; strncpyz(string, int_to_base10(bot->ver), sizeof string); sh[0] = bot->share; p = Tcl_Merge(4, list); Tcl_AppendElement(irp, p); Tcl_Free((char *) p); } return TCL_OK; } static int tcl_dcclist STDVAR { int i; char *p, idxstr[10], timestamp[11], other[160]; long tv; EGG_CONST char *list[6]; BADARGS(1, 2, " ?type?"); for (i = 0; i < dcc_total; i++) { if (argc == 1 || ((argc == 2) && (dcc[i].type && !egg_strcasecmp(dcc[i].type->name, argv[1])))) { egg_snprintf(idxstr, sizeof idxstr, "%ld", dcc[i].sock); tv = dcc[i].timeval; egg_snprintf(timestamp, sizeof timestamp, "%ld", tv); if (dcc[i].type && dcc[i].type->display) dcc[i].type->display(i, other); else { egg_snprintf(other, sizeof other, "?:%lX !! ERROR !!", (long) dcc[i].type); break; } list[0] = idxstr; list[1] = dcc[i].nick; list[2] = dcc[i].host; list[3] = dcc[i].type ? dcc[i].type->name : "*UNKNOWN*"; list[4] = other; list[5] = timestamp; p = Tcl_Merge(6, list); Tcl_AppendElement(irp, p); Tcl_Free((char *) p); } } return TCL_OK; } static int tcl_whom STDVAR { int chan, i; char c[2], idle[11], work[20], *p; long tv = 0; EGG_CONST char *list[7]; BADARGS(2, 2, " chan"); if (argv[1][0] == '*') chan = -1; else { if ((argv[1][0] < '0') || (argv[1][0] > '9')) { Tcl_SetVar(interp, "_chan", argv[1], 0); if ((Tcl_VarEval(interp, "assoc ", "$_chan", NULL) != TCL_OK) || tcl_resultempty()) { Tcl_AppendResult(irp, "channel name is invalid", NULL); return TCL_ERROR; } chan = tcl_resultint(); } else chan = atoi(argv[1]); if ((chan < 0) || (chan > 199999)) { Tcl_AppendResult(irp, "channel out of range; must be 0 through 199999", NULL); return TCL_ERROR; } } for (i = 0; i < dcc_total; i++) if (dcc[i].type == &DCC_CHAT) { if (dcc[i].u.chat->channel == chan || chan == -1) { c[0] = geticon(i); c[1] = 0; tv = (now - dcc[i].timeval) / 60; egg_snprintf(idle, sizeof idle, "%li", tv); list[0] = dcc[i].nick; list[1] = botnetnick; list[2] = dcc[i].host; list[3] = c; list[4] = idle; list[5] = dcc[i].u.chat->away ? dcc[i].u.chat->away : ""; if (chan == -1) { egg_snprintf(work, sizeof work, "%d", dcc[i].u.chat->channel); list[6] = work; } p = Tcl_Merge((chan == -1) ? 7 : 6, list); Tcl_AppendElement(irp, p); Tcl_Free((char *) p); } } for (i = 0; i < parties; i++) { if (party[i].chan == chan || chan == -1) { c[0] = party[i].flag; c[1] = 0; if (party[i].timer == 0L) strcpy(idle, "0"); else { tv = (now - party[i].timer) / 60; egg_snprintf(idle, sizeof idle, "%li", tv); } list[0] = party[i].nick; list[1] = party[i].bot; list[2] = party[i].from ? party[i].from : ""; list[3] = c; list[4] = idle; list[5] = party[i].status & PLSTAT_AWAY ? party[i].away : ""; if (chan == -1) { egg_snprintf(work, sizeof work, "%d", party[i].chan); list[6] = work; } p = Tcl_Merge((chan == -1) ? 7 : 6, list); Tcl_AppendElement(irp, p); Tcl_Free((char *) p); } } return TCL_OK; } static int tcl_dccused STDVAR { char s[20]; BADARGS(1, 1, ""); egg_snprintf(s, sizeof s, "%d", dcc_total); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } static int tcl_getdccidle STDVAR { int x, idx; char s[21]; BADARGS(2, 2, " idx"); idx = findidx(atoi(argv[1])); if (idx < 0) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } x = (now - dcc[idx].timeval); egg_snprintf(s, sizeof s, "%d", x); Tcl_AppendElement(irp, s); return TCL_OK; } static int tcl_getdccaway STDVAR { int idx; BADARGS(2, 2, " idx"); idx = findidx(atol(argv[1])); if (idx < 0 || dcc[idx].type != &DCC_CHAT) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (dcc[idx].u.chat->away == NULL) return TCL_OK; Tcl_AppendResult(irp, dcc[idx].u.chat->away, NULL); return TCL_OK; } static int tcl_setdccaway STDVAR { int idx; BADARGS(3, 3, " idx message"); idx = findidx(atol(argv[1])); if (idx < 0 || dcc[idx].type != &DCC_CHAT) { Tcl_AppendResult(irp, "invalid idx", NULL); return TCL_ERROR; } if (!argv[2][0]) { if (dcc[idx].u.chat->away != NULL) not_away(idx); return TCL_OK; } set_away(idx, argv[2]); return TCL_OK; } static int tcl_link STDVAR { int x, i; char bot[HANDLEN + 1], bot2[HANDLEN + 1]; BADARGS(2, 3, " ?via-bot? bot"); strncpyz(bot, argv[1], sizeof bot); if (argc == 3) { x = 1; strncpyz(bot2, argv[2], sizeof bot2); i = nextbot(bot); if (i < 0) x = 0; else botnet_send_link(i, botnetnick, bot, bot2); } else x = botlink("", -2, bot); egg_snprintf(bot, sizeof bot, "%d", x); Tcl_AppendResult(irp, bot, NULL); return TCL_OK; } static int tcl_unlink STDVAR { int i, x; char bot[HANDLEN + 1]; BADARGS(2, 3, " bot ?comment?"); strncpyz(bot, argv[1], sizeof bot); i = nextbot(bot); if (i < 0) x = 0; else { x = 1; if (!egg_strcasecmp(bot, dcc[i].nick)) x = botunlink(-2, bot, argv[2], botnetnick); else botnet_send_unlink(i, botnetnick, lastbot(bot), bot, argv[2]); } egg_snprintf(bot, sizeof bot, "%d", x); Tcl_AppendResult(irp, bot, NULL); return TCL_OK; } static int tcl_connect STDVAR { int i, z, sock; char s[81]; BADARGS(3, 3, " hostname port"); if (dcc_total == max_dcc && increase_socks_max()) { Tcl_AppendResult(irp, "out of dcc table space", NULL); return TCL_ERROR; } sock = getsock(0); if (sock < 0) { Tcl_AppendResult(irp, MISC_NOFREESOCK, NULL); return TCL_ERROR; } z = open_telnet_raw(sock, argv[1], atoi(argv[2])); if (z < 0) { killsock(sock); if (z == -2) strncpyz(s, "DNS lookup failed", sizeof s); else neterror(s); Tcl_AppendResult(irp, s, NULL); return TCL_ERROR; } i = new_dcc(&DCC_SOCKET, 0); dcc[i].sock = sock; dcc[i].port = atoi(argv[2]); strcpy(dcc[i].nick, "*"); strncpyz(dcc[i].host, argv[1], UHOSTMAX); egg_snprintf(s, sizeof s, "%d", sock); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } /* Create a new listening port (or destroy one) * * listen bots/all/users [mask] * listen script [flag] * listen off */ static int tcl_listen STDVAR { int i, j, idx = -1, port, realport; char s[11], msg[256]; struct portmap *pmap = NULL, *pold = NULL; BADARGS(3, 5, " port type ?mask?/?proc ?flag??"); port = realport = atoi(argv[1]); for (pmap = root; pmap; pold = pmap, pmap = pmap->next) if (pmap->realport == port) { port = pmap->mappedto; break; } for (i = 0; i < dcc_total; i++) if ((dcc[i].type == &DCC_TELNET) && (dcc[i].port == port)) idx = i; if (!egg_strcasecmp(argv[2], "off")) { if (pmap) { if (pold) pold->next = pmap->next; else root = pmap->next; nfree(pmap); } /* Remove */ if (idx < 0) { Tcl_AppendResult(irp, "no such listen port is open", NULL); return TCL_ERROR; } killsock(dcc[idx].sock); lostdcc(idx); return TCL_OK; } if (idx < 0) { /* Make new one */ if (dcc_total >= max_dcc && increase_socks_max()) { Tcl_AppendResult(irp, "No more DCC slots available.", NULL); return TCL_ERROR; } /* Try to grab port */ j = port + 20; i = -1; while (port < j && i < 0) { i = open_listen(&port); if (i == -1) port++; else if (i == -2) break; } if (i == -1) { egg_snprintf(msg, sizeof msg, "Couldn't listen on port '%d' on the " "given address. Please make sure 'my-ip' is set correctly, " "or try a different port.", realport); Tcl_AppendResult(irp, msg, NULL); return TCL_ERROR; } else if (i == -2) { Tcl_AppendResult(irp, "Couldn't assign the requested IP. Please make " "sure 'my-ip' is set properly.", NULL); return TCL_ERROR; } idx = new_dcc(&DCC_TELNET, 0); dcc[idx].addr = iptolong(getmyip()); dcc[idx].port = port; dcc[idx].sock = i; dcc[idx].timeval = now; } /* script? */ if (!strcmp(argv[2], "script")) { strcpy(dcc[idx].nick, "(script)"); if (argc < 4) { Tcl_AppendResult(irp, "a proc name must be specified for a script listen", NULL); killsock(dcc[idx].sock); lostdcc(idx); return TCL_ERROR; } if (argc == 5) { if (strcmp(argv[4], "pub")) { Tcl_AppendResult(irp, "unknown flag: ", argv[4], ". allowed flags: pub", NULL); killsock(dcc[idx].sock); lostdcc(idx); return TCL_ERROR; } dcc[idx].status = LSTN_PUBLIC; } strncpyz(dcc[idx].host, argv[3], UHOSTMAX); egg_snprintf(s, sizeof s, "%d", port); Tcl_AppendResult(irp, s, NULL); return TCL_OK; } /* bots/users/all */ if (!strcmp(argv[2], "bots")) strcpy(dcc[idx].nick, "(bots)"); else if (!strcmp(argv[2], "users")) strcpy(dcc[idx].nick, "(users)"); else if (!strcmp(argv[2], "all")) strcpy(dcc[idx].nick, "(telnet)"); if (!dcc[idx].nick[0]) { Tcl_AppendResult(irp, "invalid listen type: must be one of ", "bots, users, all, off, script", NULL); killsock(dcc[idx].sock); dcc_total--; return TCL_ERROR; } if (argc == 4) strncpyz(dcc[idx].host, argv[3], UHOSTMAX); else strcpy(dcc[idx].host, "*"); egg_snprintf(s, sizeof s, "%d", port); Tcl_AppendResult(irp, s, NULL); if (!pmap) { pmap = nmalloc(sizeof(struct portmap)); pmap->next = root; root = pmap; } pmap->realport = realport; pmap->mappedto = port; putlog(LOG_MISC, "*", "Listening at telnet port %d (%s).", port, argv[2]); return TCL_OK; } static int tcl_boot STDVAR { char who[NOTENAMELEN + 1]; int i, ok = 0; BADARGS(2, 3, " user@bot ?reason?"); strncpyz(who, argv[1], sizeof who); if (strchr(who, '@') != NULL) { char whonick[HANDLEN + 1]; splitc(whonick, who, '@'); whonick[HANDLEN] = 0; if (!egg_strcasecmp(who, botnetnick)) strncpyz(who, whonick, sizeof who); else if (remote_boots > 0) { i = nextbot(who); if (i < 0) return TCL_OK; botnet_send_reject(i, botnetnick, NULL, whonick, who, argv[2] ? argv[2] : ""); } else return TCL_OK; } for (i = 0; i < dcc_total; i++) if (!ok && (dcc[i].type->flags & DCT_CANBOOT) && !egg_strcasecmp(dcc[i].nick, who)) { do_boot(i, botnetnick, argv[2] ? argv[2] : ""); ok = 1; } return TCL_OK; } static int tcl_rehash STDVAR { BADARGS(1, 1, ""); if (make_userfile) { putlog(LOG_MISC, "*", USERF_NONEEDNEW); make_userfile = 0; } write_userfile(-1); putlog(LOG_MISC, "*", USERF_REHASHING); do_restart = -2; return TCL_OK; } static int tcl_restart STDVAR { BADARGS(1, 1, ""); if (!backgrd) { Tcl_AppendResult(interp, "You can't restart a -n bot", NULL); return TCL_ERROR; } if (make_userfile) { putlog(LOG_MISC, "*", USERF_NONEEDNEW); make_userfile = 0; } write_userfile(-1); putlog(LOG_MISC, "*", MISC_RESTARTING); wipe_timers(interp, &utimer); wipe_timers(interp, &timer); do_restart = -1; return TCL_OK; } static int tcl_traffic STDVAR { char buf[1024]; unsigned long out_total_today, out_total; unsigned long in_total_today, in_total; /* IRC traffic */ sprintf(buf, "irc %ld %ld %ld %ld", itraffic_irc_today, itraffic_irc + itraffic_irc_today, otraffic_irc_today, otraffic_irc + otraffic_irc_today); Tcl_AppendElement(irp, buf); /* Botnet traffic */ sprintf(buf, "botnet %ld %ld %ld %ld", itraffic_bn_today, itraffic_bn + itraffic_bn_today, otraffic_bn_today, otraffic_bn + otraffic_bn_today); Tcl_AppendElement(irp, buf); /* Partyline */ sprintf(buf, "partyline %ld %ld %ld %ld", itraffic_dcc_today, itraffic_dcc + itraffic_dcc_today, otraffic_dcc_today, otraffic_dcc + otraffic_dcc_today); Tcl_AppendElement(irp, buf); /* Transfer */ sprintf(buf, "transfer %ld %ld %ld %ld", itraffic_trans_today, itraffic_trans + itraffic_trans_today, otraffic_trans_today, otraffic_trans + otraffic_trans_today); Tcl_AppendElement(irp, buf); /* Misc traffic */ sprintf(buf, "misc %ld %ld %ld %ld", itraffic_unknown_today, itraffic_unknown + itraffic_unknown_today, otraffic_unknown_today, otraffic_unknown + otraffic_unknown_today); Tcl_AppendElement(irp, buf); /* Totals */ in_total_today = itraffic_irc_today + itraffic_bn_today + itraffic_dcc_today + itraffic_trans_today + itraffic_unknown_today; in_total = in_total_today + itraffic_irc + itraffic_bn + itraffic_dcc + itraffic_trans + itraffic_unknown; out_total_today = otraffic_irc_today + otraffic_bn_today + otraffic_dcc_today + itraffic_trans_today + otraffic_unknown_today; out_total = out_total_today + otraffic_irc + otraffic_bn + otraffic_dcc + otraffic_trans + otraffic_unknown; sprintf(buf, "total %ld %ld %ld %ld", in_total_today, in_total, out_total_today, out_total); Tcl_AppendElement(irp, buf); return TCL_OK; } tcl_cmds tcldcc_cmds[] = { {"putdcc", tcl_putdcc}, {"putdccraw", tcl_putdccraw}, {"putidx", tcl_putdcc}, {"dccsimul", tcl_dccsimul}, {"dccbroadcast", tcl_dccbroadcast}, {"hand2idx", tcl_hand2idx}, {"getchan", tcl_getchan}, {"setchan", tcl_setchan}, {"dccputchan", tcl_dccputchan}, {"console", tcl_console}, {"strip", tcl_strip}, {"echo", tcl_echo}, {"page", tcl_page}, {"control", tcl_control}, {"valididx", tcl_valididx}, {"killdcc", tcl_killdcc}, {"putbot", tcl_putbot}, {"putallbots", tcl_putallbots}, {"idx2hand", tcl_idx2hand}, {"bots", tcl_bots}, {"botlist", tcl_botlist}, {"dcclist", tcl_dcclist}, {"whom", tcl_whom}, {"dccused", tcl_dccused}, {"getdccidle", tcl_getdccidle}, {"getdccaway", tcl_getdccaway}, {"setdccaway", tcl_setdccaway}, {"islinked", tcl_islinked}, {"link", tcl_link}, {"unlink", tcl_unlink}, {"connect", tcl_connect}, {"listen", tcl_listen}, {"boot", tcl_boot}, {"rehash", tcl_rehash}, {"restart", tcl_restart}, {"traffic", tcl_traffic}, {NULL, NULL} };