static void cmd_servers(struct userrec *u, int idx, char *par) { struct server_list *x = serverlist; int i; char s[1024]; putlog(LOG_CMDS, "*", "#%s# servers", dcc[idx].nick); if (!x) { dprintf(idx, "There are no servers in the server list.\n"); } else { dprintf(idx, "Server list:\n"); i = 0; for (; x; x = x->next) { if ((i == curserv) && realservername) egg_snprintf(s, sizeof s, " %s:%d (%s) <- I am here", x->name, x->port ? x->port : default_port, realservername); else egg_snprintf(s, sizeof s, " %s:%d %s", x->name, x->port ? x->port : default_port, (i == curserv) ? "<- I am here" : ""); dprintf(idx, "%s\n", s); i++; } dprintf(idx, "End of server list.\n"); } }
void check_tcl_chpt(const char *bot, const char *hand, int sock, int chan) { char u[11], v[11]; egg_snprintf(u, sizeof u, "%d", sock); egg_snprintf(v, sizeof v, "%d", chan); Tcl_SetVar(interp, "_chpt1", (char *) bot, 0); Tcl_SetVar(interp, "_chpt2", (char *) hand, 0); Tcl_SetVar(interp, "_chpt3", (char *) u, 0); Tcl_SetVar(interp, "_chpt4", (char *) v, 0); check_tcl_bind(H_chpt, v, 0, " $_chpt1 $_chpt2 $_chpt3 $_chpt4", MATCH_MASK | BIND_STACKABLE); }
void tell_verbose_uptime(int idx) { char s[256] = "", s1[121] = "", s2[81] = "", outbuf[501] = ""; time_t total, hr, min; #if HAVE_GETRUSAGE struct rusage ru; #else # if HAVE_CLOCK clock_t cl; # endif #endif /* HAVE_GETRUSAGE */ daysdur(now, online_since, s, sizeof(s)); if (backgrd) strlcpy(s1, "background", sizeof(s1)); else { if (term_z) strlcpy(s1, "terminal mode", sizeof(s1)); else strlcpy(s1, "log dump mode", sizeof(s1)); } simple_snprintf(outbuf, sizeof(outbuf), "Online for %s", s); if (restart_time) { daysdur(now, restart_time, s, sizeof(s)); size_t olen = strlen(outbuf); simple_snprintf(&outbuf[olen], sizeof(outbuf) - olen, " (%s %s)", restart_was_update ? "updated" : "restarted", s); } #if HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &ru); total = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec; hr = (int) (total / 60); min = (int) (total - (hr * 60)); egg_snprintf(s2, sizeof(s2), "CPU %02d:%02d (load avg %3.1f%%)", (int) hr, (int) min, 100.0 * ((float) total / (float) (now - online_since))); #else # if HAVE_CLOCK cl = (clock() / CLOCKS_PER_SEC); hr = (int) (cl / 60); min = (int) (cl - (hr * 60)); egg_snprintf(s2, sizeof(s2), "CPU %02d:%02d (load avg %3.1f%%)", (int) hr, (int) min, 100.0 * ((float) cl / (float) (now - online_since))); # else simple_snprintf(s2, sizeof(s2), "CPU ???"); # endif #endif /* HAVE_GETRUSAGE */ dprintf(idx, "%s (%s) %s cache hit %4.1f%%\n", outbuf, s1, s2, 100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss))); }
/* Check for tcl-bound dcc command, return 1 if found * dcc: proc-name <handle> <sock> <args...> */ int check_tcl_dcc(const char *cmd, int idx, const char *args) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; int x; char s[11]; get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan); egg_snprintf(s, sizeof s, "%ld", dcc[idx].sock); Tcl_SetVar(interp, "_dcc1", (char *) dcc[idx].nick, 0); Tcl_SetVar(interp, "_dcc2", (char *) s, 0); Tcl_SetVar(interp, "_dcc3", (char *) args, 0); x = check_tcl_bind(H_dcc, cmd, &fr, " $_dcc1 $_dcc2 $_dcc3", MATCH_PARTIAL | BIND_USE_ATTR | BIND_HAS_BUILTINS); if (x == BIND_AMBIGUOUS) { dprintf(idx, MISC_AMBIGUOUS); return 0; } if (x == BIND_NOMATCH) { dprintf(idx, MISC_NOSUCHCMD); return 0; } /* We return 1 to leave the partyline */ if (x == BIND_QUIT) /* CMD_LEAVE, 'quit' */ return 1; if (x == BIND_EXEC_LOG) putlog(LOG_CMDS, "*", "#%s# %s %s", dcc[idx].nick, cmd, args); return 0; }
/* Handle someone being booted from dcc chat. */ void do_boot(int idx, char *by, char *reason) { int files = (dcc[idx].type != &DCC_CHAT); dprintf(idx, DCC_BOOTED1); dprintf(idx, DCC_BOOTED2, files ? "file section" : "bot", by, reason[0] ? ": " : ".", reason); /* If it's a partyliner (chatterer :) */ /* Horrible assumption that DCT_CHAT using structure uses same format * as DCC_CHAT */ if ((dcc[idx].type->flags & DCT_CHAT) && (dcc[idx].u.chat->channel >= 0)) { char x[1024]; egg_snprintf(x, sizeof x, DCC_BOOTED3, by, dcc[idx].nick, reason[0] ? ": " : "", reason); chanout_but(idx, dcc[idx].u.chat->channel, "*** %s.\n", x); if (dcc[idx].u.chat->channel < GLOBAL_CHANS) botnet_send_part_idx(idx, x); } check_tcl_chof(dcc[idx].nick, dcc[idx].sock); if ((dcc[idx].sock != STDOUT) || backgrd) { killsock(dcc[idx].sock); lostdcc(idx); /* Entry must remain in the table so it can be logged by the caller */ } else { dprintf(DP_STDOUT, "\n### SIMULATION RESET\n\n"); dcc_chatter(idx); } return; }
/* Check timers, execute the ones that have expired. */ void do_check_timers(tcl_timer_t ** stack) { tcl_timer_t *mark = *stack, *old = NULL; char x[16]; /* New timers could be added by a Tcl script inside a current timer * so i'll just clear out the timer list completely, and add any * unexpired timers back on. */ *stack = NULL; while (mark) { if (mark->mins > 0) mark->mins--; old = mark; mark = mark->next; if (!old->mins) { egg_snprintf(x, sizeof x, "timer%lu", old->id); do_tcl(x, old->cmd); if (old->count == 1) { nfree(old->cmd); nfree(old); continue; } else { old->mins = old->interval; if (old->count > 1) old->count--; } } old->next = *stack; *stack = old; } }
static void backup_chanfile() { char s[125]; putlog(LOG_MISC, "*", "Backing up channel file..."); egg_snprintf(s, sizeof s, "%s~bak", chanfile); copyfile(chanfile, s); }
/* Return list of timers. */ void list_timers(Tcl_Interp *irp, tcl_timer_t *stack) { char mins[10], id[16], *x; EGG_CONST char *argv[3]; tcl_timer_t *mark; for (mark = stack; mark; mark = mark->next) { egg_snprintf(mins, sizeof mins, "%u", mark->mins); egg_snprintf(id, sizeof id, "timer%lu", mark->id); argv[0] = mins; argv[1] = mark->cmd; argv[2] = id; x = Tcl_Merge(3, argv); Tcl_AppendElement(irp, x); Tcl_Free((char *) x); } }
/* Show list of current dcc's to a dcc-chatter * positive value: idx given -- negative value: sock given */ void tell_dcc(int zidx) { int i, j, nicklen = 0; char other[160]; char format[81]; /* calculate max nicklen */ for (i = 0; i < dcc_total; i++) { if (strlen(dcc[i].nick) > nicklen) nicklen = strlen(dcc[i].nick); } if (nicklen < 9) nicklen = 9; j = 60 - nicklen; if (j < 15) j = 15; if (j > 40) j = 40; egg_snprintf(format, sizeof format, "%%-3s %%-%u.%us %%-6s %%-%u.%us %%s\n", j, j, nicklen, nicklen); dprintf(zidx, format, "IDX", "ADDR", "+ PORT", "NICK", "TYPE INFO"); dprintf(zidx, format, "---", "------------------------------------------------------", "------", "--------------------------------", "----- ---------"); egg_snprintf(format, sizeof format, "%%-3d %%-%u.%us %%c%%5d %%-%u.%us %%s\n", j, j, nicklen, nicklen); /* Show server */ for (i = 0; i < dcc_total; i++) { if (dcc[i].type && dcc[i].type->display) dcc[i].type->display(i, other); else { sprintf(other, "?:%lX !! ERROR !!", (long) dcc[i].type); break; } dprintf(zidx, format, dcc[i].sock, iptostr(&dcc[i].sockname.addr.sa), #ifdef TLS dcc[i].ssl ? '+' : ' ', dcc[i].port, dcc[i].nick, other); #else ' ', dcc[i].port, dcc[i].nick, other); #endif } }
void backup_userfile(void) { char s[125]; if (quiet_save < 2) putlog(LOG_MISC, "*", USERF_BACKUP); egg_snprintf(s, sizeof s, "%s~bak", userfile); copyfile(userfile, s); }
void check_tcl_listen(const char *cmd, int idx) { char s[11]; int x; egg_snprintf(s, sizeof s, "%d", idx); Tcl_SetVar(interp, "_n", (char *) s, 0); x = Tcl_VarEval(interp, cmd, " $_n", NULL); if (x == TCL_ERROR) putlog(LOG_MISC, "*", "error on listen: %s", interp->result); }
static int tcl_dccused(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { char s[20]; BADARGS(1, 1, ""); egg_snprintf(s, sizeof s, "%d", dcc_total); Tcl_AppendResult(irp, s, NULL); return TCL_OK; }
void check_tcl_away(const char *bot, int idx, const char *msg) { char u[11]; egg_snprintf(u, sizeof u, "%d", idx); Tcl_SetVar(interp, "_away1", (char *) bot, 0); Tcl_SetVar(interp, "_away2", (char *) u, 0); Tcl_SetVar(interp, "_away3", msg ? (char *) msg : "", 0); check_tcl_bind(H_away, bot, 0, " $_away1 $_away2 $_away3", MATCH_MASK | BIND_STACKABLE); }
/* Show list of current dcc's to a dcc-chatter * positive value: idx given -- negative value: sock given */ void tell_dcc(int zidx) { int i, j; char other[160]; char format[81]; int nicklen; /* calculate max nicklen */ nicklen = 0; for (i = 0; i < dcc_total; i++) { if (strlen(dcc[i].nick) > nicklen) nicklen = strlen(dcc[i].nick); } if (nicklen < 9) nicklen = 9; egg_snprintf(format, sizeof format, "%%-4s %%-8s %%-5s %%-%us %%-17s %%s\n", nicklen); dprintf(zidx, format, "SOCK", "ADDR", "PORT", "NICK", "HOST", "TYPE"); dprintf(zidx, format, "----", "--------", "-----", "---------", "-----------------", "----"); egg_snprintf(format, sizeof format, "%%-4d %%08X %%5d %%-%us %%-17s %%s\n", nicklen); /* Show server */ for (i = 0; i < dcc_total; i++) { j = strlen(dcc[i].host); if (j > 17) j -= 17; else j = 0; if (dcc[i].type && dcc[i].type->display) dcc[i].type->display(i, other); else { sprintf(other, "?:%lX !! ERROR !!", (long) dcc[i].type); break; } dprintf(zidx, format, dcc[i].sock, dcc[i].addr, dcc[i].port, dcc[i].nick, dcc[i].host + j, other); } }
/* PUB `seen' trigger. */ static int pub_seen(char *nick, char *host, char *hand, char *channel, char *text) { char prefix[91]; /* sizeof(name) + strlen("PRIVMSG :") */ struct chanset_t *chan = findchan_by_dname(channel); if ((chan != NULL) && channel_seen(chan)) { egg_snprintf(prefix, sizeof prefix, "PRIVMSG %s :", chan->name); do_seen(DP_HELP, prefix, nick, hand, chan->dname, text); } return 0; }
void check_tcl_chatactbcst(const char *from, int chan, const char *text, tcl_bind_list_t *tl) { char s[11]; egg_snprintf(s, sizeof s, "%d", chan); Tcl_SetVar(interp, "_cab1", (char *) from, 0); Tcl_SetVar(interp, "_cab2", (char *) s, 0); Tcl_SetVar(interp, "_cab3", (char *) text, 0); check_tcl_bind(tl, text, 0, " $_cab1 $_cab2 $_cab3", MATCH_MASK | BIND_STACKABLE); }
void check_tcl_chjn(const char *bot, const char *nick, int chan, const char type, int sock, const char *host) { struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 }; char s[11], t[2], u[11]; t[0] = type; t[1] = 0; switch (type) { case '*': fr.global = USER_OWNER; break; case '+': fr.global = USER_MASTER; break; case '@': fr.global = USER_OP; break; case '^': fr.global = USER_HALFOP; break; case '%': fr.global = USER_BOTMAST; } egg_snprintf(s, sizeof s, "%d", chan); egg_snprintf(u, sizeof u, "%d", sock); Tcl_SetVar(interp, "_chjn1", (char *) bot, 0); Tcl_SetVar(interp, "_chjn2", (char *) nick, 0); Tcl_SetVar(interp, "_chjn3", (char *) s, 0); Tcl_SetVar(interp, "_chjn4", (char *) t, 0); Tcl_SetVar(interp, "_chjn5", (char *) u, 0); Tcl_SetVar(interp, "_chjn6", (char *) host, 0); check_tcl_bind(H_chjn, s, &fr, " $_chjn1 $_chjn2 $_chjn3 $_chjn4 $_chjn5 $_chjn6", MATCH_MASK | BIND_STACKABLE); }
static int tcl_getchan(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { 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; }
/* Called from the Context macro. */ void eggContext(const char *file, int line, const char *module) { char x[31], *p; p = strrchr(file, '/'); if (!module) { strncpyz(x, p ? p + 1 : file, sizeof x); } else egg_snprintf(x, 31, "%s:%s", module, p ? p + 1 : file); cx_ptr = ((cx_ptr + 1) & 15); strcpy(cx_file[cx_ptr], x); cx_line[cx_ptr] = line; cx_note[cx_ptr][0] = 0; }
/* Remove the default msg/dcc/fil commands from the Tcl interpreter */ void rem_builtins(tcl_bind_list_t *table, cmd_t *cc) { int k, i; char p[1024], *l; for (i = 0; cc[i].name; i++) { egg_snprintf(p, sizeof p, "*%s:%s", table->name, cc[i].funcname ? cc[i].funcname : cc[i].name); l = nmalloc(Tcl_ScanElement(p, &k)); Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES); Tcl_DeleteCommand(interp, p); unbind_bind_entry(table, cc[i].flags, cc[i].name, l); nfree(l); } }
void check_tcl_chonof(char *hand, int sock, tcl_bind_list_t *tl) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; char s[11]; struct userrec *u; u = get_user_by_handle(userlist, hand); touch_laston(u, "partyline", now); get_user_flagrec(u, &fr, NULL); Tcl_SetVar(interp, "_chonof1", (char *) hand, 0); egg_snprintf(s, sizeof s, "%d", sock); Tcl_SetVar(interp, "_chonof2", (char *) s, 0); check_tcl_bind(tl, hand, &fr, " $_chonof1 $_chonof2", MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE | BIND_WANTRET); }
static int tcl_dcclist(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { 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 void cmd_servers(struct userrec *u, int idx, char *par) { struct server_list *x = serverlist; int i; char s[1024]; putlog(LOG_CMDS, "*", "#%s# servers", dcc[idx].nick); if (!x) { dprintf(idx, "No servers.\n"); } else { dprintf(idx, "My server list:\n"); i = 0; while (x != NULL) { egg_snprintf(s, sizeof s, "%14s %20.20s:%-10d", (i == curserv) ? "I am here ->" : "", x->name, x->port ? x->port : default_port); if (x->realname) egg_snprintf(s + 46, sizeof s - 46, " (%-.20s)", x->realname); dprintf(idx, "%s\n", s); x = x->next; i++; } } }
/* This helps the memory debugging */ void *_get_data_ptr(int size, char *file, int line) { char *p; #ifdef DEBUG_MEM char x[1024]; p = strrchr(file, '/'); egg_snprintf(x, sizeof x, "dccutil.c:%s", p ? p + 1 : file); p = n_malloc(size, x, line); #else p = nmalloc(size); #endif egg_bzero(p, size); return p; }
static int got311(char *from, char *msg) { char *n1, *n2, *u, *h; n1 = newsplit(&msg); n2 = newsplit(&msg); u = newsplit(&msg); h = newsplit(&msg); if (!n1 || !n2 || !u || !h) return 0; if (match_my_nick(n2)) egg_snprintf(botuserhost, sizeof botuserhost, "%s@%s", u, h); return 0; }
static int tcl_hand2idx(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { 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_getdccidle(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { 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; }
/* Bring the default msg/dcc/fil commands into the Tcl interpreter */ void add_builtins(tcl_bind_list_t *tl, cmd_t *cc) { int k, i; char p[1024], *l; cd_tcl_cmd table[2]; table[0].name = p; table[0].callback = tl->func; table[1].name = NULL; for (i = 0; cc[i].name; i++) { egg_snprintf(p, sizeof p, "*%s:%s", tl->name, cc[i].funcname ? cc[i].funcname : cc[i].name); l = nmalloc(Tcl_ScanElement(p, &k)); Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES); table[0].cdata = (void *) cc[i].func; add_cd_tcl_cmds(table); bind_bind_entry(tl, cc[i].flags, cc[i].name, l); nfree(l); } }
const char *check_tcl_filt(int idx, const char *text) { char s[11]; int x; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; egg_snprintf(s, sizeof s, "%ld", dcc[idx].sock); get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan); Tcl_SetVar(interp, "_filt1", (char *) s, 0); Tcl_SetVar(interp, "_filt2", (char *) text, 0); x = check_tcl_bind(H_filt, text, &fr, " $_filt1 $_filt2", MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE | BIND_WANTRET | BIND_ALTER_ARGS); if (x == BIND_EXECUTED || x == BIND_EXEC_LOG) { if (interp->result == NULL || !interp->result[0]) return ""; else return interp->result; } else return text; }
int detect_dcc_flood(time_t *timer, struct chat_info *chat, int idx) { time_t t; if (!dcc_flood_thr) return 0; t = now; if (*timer != t) { *timer = t; chat->msgs_per_sec = 0; } else { chat->msgs_per_sec++; if (chat->msgs_per_sec > dcc_flood_thr) { /* FLOOD */ dprintf(idx, "*** FLOOD: %s.\n", IRC_GOODBYE); /* Evil assumption here that flags&DCT_CHAT implies chat type */ if ((dcc[idx].type->flags & DCT_CHAT) && chat && (chat->channel >= 0)) { char x[1024]; egg_snprintf(x, sizeof x, DCC_FLOODBOOT, dcc[idx].nick); chanout_but(idx, chat->channel, "*** %s", x); if (chat->channel < GLOBAL_CHANS) botnet_send_part_idx(idx, x); } check_tcl_chof(dcc[idx].nick, dcc[idx].sock); if ((dcc[idx].sock != STDOUT) || backgrd) { killsock(dcc[idx].sock); lostdcc(idx); } else { dprintf(DP_STDOUT, "\n### SIMULATION RESET ###\n\n"); dcc_chatter(idx); } return 1; /* <- flood */ } } return 0; }