/* Received a ctcp-dcc. */ static void filesys_dcc_send(char *nick, char *from, struct userrec *u, char *text) { char *param, *ip, *prt, *buf = NULL, *msg; int atr = u ? u->flags : 0, i, j = 0; if (text[j] == '"') { text[j] = ' '; for (j = 1; text[j] != '"' && text[j] != '\0'; j++) { if (text[j] == ' ') { text[j] = '_'; } } text[j] = ' '; } buf = nmalloc(strlen(text) + 1); msg = buf; strcpy(buf, text); param = newsplit(&msg); if (!(atr & USER_XFER)) { putlog(LOG_FILES, "*", "Refused DCC SEND %s (no access): %s!%s", param, nick, from); if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :No access\n", nick); } else if (!dccin[0] && !upload_to_cd) { dprintf(DP_HELP, "NOTICE %s :DCC file transfers not supported.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from); } else if (strchr(param, '/')) { dprintf(DP_HELP, "NOTICE %s :Filename cannot have '/' in it...\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from); } else { ip = newsplit(&msg); prt = newsplit(&msg); if (atoi(prt) < 1024 || atoi(prt) > 65535) { /* Invalid port */ dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): invalid port", param, nick); } else if (atoi(msg) == 0) { dprintf(DP_HELP, "NOTICE %s :Sorry, file size info must be included.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): no file size", param, nick); } else if (dcc_maxsize && (atoi(msg) > (dcc_maxsize * 1024))) { dprintf(DP_HELP, "NOTICE %s :Sorry, file too large.\n", nick); putlog(LOG_FILES, "*", "Refused dcc send %s (%s): file too large", param, nick); } else { /* This looks like a good place for a sanity check. */ if (!sanitycheck_dcc(nick, from, ip, prt)) { my_free(buf); return; } i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info)); if (i < 0) { dprintf(DP_HELP, "NOTICE %s :Sorry, too many DCC connections.\n", nick); putlog(LOG_MISC, "*", "DCC connections full: SEND %s (%s!%s)", param, nick, from); return; } dcc[i].addr = my_atoul(ip); dcc[i].port = atoi(prt); dcc[i].sock = -1; dcc[i].user = u; strcpy(dcc[i].nick, nick); strcpy(dcc[i].host, from); dcc[i].u.dns->cbuf = get_data_ptr(strlen(param) + 1); strcpy(dcc[i].u.dns->cbuf, param); dcc[i].u.dns->ibuf = atoi(msg); dcc[i].u.dns->ip = dcc[i].addr; dcc[i].u.dns->dns_type = RES_HOSTBYIP; dcc[i].u.dns->dns_success = filesys_dcc_send_hostresolved; dcc[i].u.dns->dns_failure = filesys_dcc_send_hostresolved; dcc[i].u.dns->type = &DCC_FORK_SEND; dcc_dnshostbyip(dcc[i].addr); } } my_free(buf); }
/* This only handles CHAT requests, otherwise it's handled in transfer. */ static int filesys_DCC_CHAT(char *nick, char *from, char *handle, char *object, char *keyword, char *text) { char *param, *ip, *prt, buf[512], *msg = buf; int i, sock; struct userrec *u = get_user_by_handle(userlist, handle); struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 }; if (egg_strcasecmp(object, botname)) return 0; if (!egg_strncasecmp(text, "SEND ", 5)) { filesys_dcc_send(nick, from, u, text + 5); return 1; } if (egg_strncasecmp(text, "CHAT ", 5) || !u) return 0; strcpy(buf, text + 5); get_user_flagrec(u, &fr, 0); param = newsplit(&msg); if (dcc_total == max_dcc && increase_socks_max()) { putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT(file)", param, nick, from); } else if (glob_party(fr) || (!require_p && chan_op(fr))) return 0; /* Allow ctcp.so to pick up the chat */ else if (!glob_xfer(fr)) { if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED2); putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED, nick, from); } else if (u_pass_match(u, "-")) { if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED3); putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED4, nick, from); } else if (!dccdir[0]) { putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED5, nick, from); } else { ip = newsplit(&msg); prt = newsplit(&msg); sock = getsock(0); if (sock < 0 || open_telnet_dcc(sock, ip, prt) < 0) { neterror(buf); if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", nick, DCC_CONNECTFAILED1, buf); putlog(LOG_MISC, "*", "%s: CHAT(file) (%s!%s)", DCC_CONNECTFAILED2, nick, from); putlog(LOG_MISC, "*", " (%s)", buf); killsock(sock); } else if (atoi(prt) < 1024 || atoi(prt) > 65535) { /* Invalid port */ if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog(LOG_FILES, "*", "%s: %s!%s", DCC_REFUSED7, nick, from); } else { i = new_dcc(&DCC_FILES_PASS, sizeof(struct file_info)); dcc[i].addr = my_atoul(ip); dcc[i].port = atoi(prt); dcc[i].sock = sock; strcpy(dcc[i].nick, u->handle); strcpy(dcc[i].host, from); dcc[i].status = STAT_ECHO; dcc[i].timeval = now; dcc[i].u.file->chat = get_data_ptr(sizeof(struct chat_info)); strcpy(dcc[i].u.file->chat->con_chan, "*"); dcc[i].user = u; putlog(LOG_MISC, "*", "DCC connection: CHAT(file) (%s!%s)", nick, from); dprintf(i, "%s\n", DCC_ENTERPASS); } } return 1; }
static int _dcc_send(int idx, char *filename, char *nick, char *dir, int resend) { int x; char *nfn, *buf = NULL; if (strlen(nick) > NICKMAX) nick[NICKMAX] = 0; if (resend) x = raw_dcc_resend(filename, nick, dcc[idx].nick, dir); else x = raw_dcc_send(filename, nick, dcc[idx].nick, dir); if (x == DCCSEND_FULL) { dprintf(idx, "Sorry, too many DCC connections. (try again later)\n"); putlog(LOG_FILES, "*", "DCC connections full: %sGET %s [%s]", filename, resend ? "RE" : "", dcc[idx].nick); return 0; } if (x == DCCSEND_NOSOCK) { if (reserved_port_min) { dprintf(idx, "All my DCC SEND ports are in use. Try later.\n"); putlog(LOG_FILES, "*", "DCC port in use (can't open): %sGET %s [%s]", resend ? "RE" : "", filename, dcc[idx].nick); } else { dprintf(idx, "Unable to listen at a socket.\n"); putlog(LOG_FILES, "*", "DCC socket error: %sGET %s [%s]", filename, resend ? "RE" : "", dcc[idx].nick); } return 0; } if (x == DCCSEND_BADFN) { dprintf(idx, "File not found ?\n"); putlog(LOG_FILES, "*", "DCC file not found: %sGET %s [%s]", filename, resend ? "RE" : "", dcc[idx].nick); return 0; } if (x == DCCSEND_FEMPTY) { dprintf(idx, "The file is empty. Aborted transfer.\n"); putlog(LOG_FILES, "*", "DCC file is empty: %s [%s]", filename, dcc[idx].nick); return 0; } nfn = strrchr(dir, '/'); if (nfn == NULL) nfn = dir; else nfn++; /* Eliminate any spaces in the filename. */ if (strchr(nfn, ' ')) { char *p; malloc_strcpy(buf, nfn); p = nfn = buf; while ((p = strchr(p, ' ')) != NULL) *p = '_'; } if (egg_strcasecmp(nick, dcc[idx].nick)) dprintf(DP_HELP, "NOTICE %s :Here is %s file from %s %s...\n", nick, resend ? "the" : "a", dcc[idx].nick, resend ? "again " : ""); dprintf(idx, "%sending: %s to %s\n", resend ? "Res" : "S", nfn, nick); my_free(buf); return 1; }
static int do_dcc_send(int idx, char *dir, char *fn, char *nick, int resend) { char *s = NULL, *s1 = NULL; int x; if (nick && strlen(nick) > NICKMAX) nick[NICKMAX] = 0; if (dccdir[0] == 0) { dprintf(idx, "DCC file transfers not supported.\n"); putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "", fn, dcc[idx].nick); return 0; } if (strchr(fn, '/') != NULL) { dprintf(idx, "Filename cannot have '/' in it...\n"); putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "", fn, dcc[idx].nick); return 0; } if (dir[0]) { s = nmalloc(strlen(dccdir) + strlen(dir) + strlen(fn) + 2); sprintf(s, "%s%s/%s", dccdir, dir, fn); } else { s = nmalloc(strlen(dccdir) + strlen(fn) + 1); sprintf(s, "%s%s", dccdir, fn); } if (!file_readable(s)) { dprintf(idx, "No such file.\n"); putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "", fn, dcc[idx].nick); my_free(s); return 0; } if (!nick || !nick[0]) nick = dcc[idx].nick; /* Already have too many transfers active for this user? queue it */ if (at_limit(nick)) { char xxx[1024]; sprintf(xxx, "%d*%s%s", (int) strlen(dccdir), dccdir, dir); queue_file(xxx, fn, dcc[idx].nick, nick); dprintf(idx, "Queued: %s to %s\n", fn, nick); my_free(s); return 1; } if (copy_to_tmp) { char *tempfn = mktempfile(fn); /* Copy this file to /tmp, add a random prefix to the filename. */ s = nrealloc(s, strlen(dccdir) + strlen(dir) + strlen(fn) + 2); sprintf(s, "%s%s%s%s", dccdir, dir, dir[0] ? "/" : "", fn); s1 = nrealloc(s1, strlen(tempdir) + strlen(tempfn) + 1); sprintf(s1, "%s%s", tempdir, tempfn); my_free(tempfn); if (copyfile(s, s1) != 0) { dprintf(idx, "Can't make temporary copy of file!\n"); putlog(LOG_FILES | LOG_MISC, "*", "Refused dcc %sget %s: copy to %s FAILED!", resend ? "re" : "", fn, tempdir); my_free(s); my_free(s1); return 0; } } else { s1 = nrealloc(s1, strlen(dccdir) + strlen(dir) + strlen(fn) + 2); sprintf(s1, "%s%s%s%s", dccdir, dir, dir[0] ? "/" : "", fn); } s = nrealloc(s, strlen(dir) + strlen(fn) + 2); sprintf(s, "%s%s%s", dir, dir[0] ? "/" : "", fn); x = _dcc_send(idx, s1, nick, s, resend); if (x != DCCSEND_OK) wipe_tmp_filename(s1, -1); my_free(s); my_free(s1); return x; }
int def_gotshare(struct userrec *u, struct user_entry *e, char *data, int idx) { putlog(LOG_CMDS, "*", "%s: change %s %s", dcc[idx].nick, e->type->name, u->handle); return e->type->set(u, e, data); }
int shell_exec(char *cmdline, char *input, char **output, char **erroutput) { if (!cmdline) return 0; Tempfile *in = NULL, *out = NULL, *err = NULL; int x; int parent = getpid(); /* Set up temp files */ in = new Tempfile("in"); if (!in || in->error) { // putlog(LOG_ERRORS, "*" , "exec: Couldn't open '%s': %s", in->file, strerror(errno)); if (in) delete in; return 0; } if (input) { if (fwrite(input, strlen(input), 1, in->f) != 1) { // putlog(LOG_ERRORS, "*", "exec: Couldn't write to '%s': %s", in->file, strerror(errno)); delete in; return 0; } fseek(in->f, 0, SEEK_SET); } err = new Tempfile("err"); if (!err || err->error) { // putlog(LOG_ERRORS, "*", "exec: Couldn't open '%s': %s", err->file, strerror(errno)); delete in; if (err) delete err; return 0; } out = new Tempfile("out"); if (!out || out->error) { // putlog(LOG_ERRORS, "*", "exec: Couldn't open '%s': %s", out->file, strerror(errno)); delete in; delete err; if (out) delete out; return 0; } x = fork(); if (x == -1) { putlog(LOG_ERRORS, "*", "exec: fork() failed: %s", strerror(errno)); delete in; delete err; delete out; return 0; } if (x) { /* Parent: wait for the child to complete */ int st = 0; size_t fs = 0; waitpid(x, &st, 0); /* child is now complete, read the files into buffers */ delete in; fflush(out->f); fflush(err->f); if (erroutput) { char *buf = NULL; fseek(err->f, 0, SEEK_END); fs = ftell(err->f); if (fs == 0) { (*erroutput) = NULL; } else { buf = (char *) my_calloc(1, fs + 1); fseek(err->f, 0, SEEK_SET); fread(buf, 1, fs, err->f); buf[fs] = 0; (*erroutput) = buf; } } delete err; if (output) { char *buf = NULL; fseek(out->f, 0, SEEK_END); fs = ftell(out->f); if (fs == 0) { (*output) = NULL; } else { buf = (char *) my_calloc(1, fs + 1); fseek(out->f, 0, SEEK_SET); fread(buf, 1, fs, out->f); buf[fs] = 0; (*output) = buf; } } delete out; return 1; } else { /* Child: make fd's and set them up as std* */ // int ind, outd, errd; char *argv[4] = { NULL, NULL, NULL, NULL }; // ind = fileno(inpFile); // outd = fileno(outFile); // errd = fileno(errFile); if (dup2(in->fd, STDIN_FILENO) == (-1)) { kill(parent, SIGCHLD); exit(1); } if (dup2(out->fd, STDOUT_FILENO) == (-1)) { kill(parent, SIGCHLD); exit(1); } if (dup2(err->fd, STDERR_FILENO) == (-1)) { kill(parent, SIGCHLD); exit(1); } argv[0] = "sh"; argv[1] = "-c"; argv[2] = cmdline; argv[3] = NULL; execvp(argv[0], &argv[0]); kill(parent, SIGCHLD); exit(1); } }
/* break link with a tandembot */ int botunlink(int idx, char *nick, char *reason) { char s[20]; register int i; tand_t *bot; Context; if (nick[0] == '*') dprintf(idx, "%s\n", BOT_UNLINKALL); for (i = 0; i < dcc_total; i++) { if ((nick[0] == '*') || !strcasecmp(dcc[i].nick, nick)) { if (dcc[i].type == &DCC_FORK_BOT) { if (idx >= 0) dprintf(idx, "%s: %s -> %s.\n", BOT_KILLLINKATTEMPT, dcc[i].nick, dcc[i].host); putlog(LOG_BOTS, "*", "%s: %s -> %s:%d", BOT_KILLLINKATTEMPT, dcc[i].nick, dcc[i].host, dcc[i].port); killsock(dcc[i].sock); lostdcc(i); if (nick[0] != '*') return 1; } else if (dcc[i].type == &DCC_BOT_NEW) { if (idx >= 0) dprintf(idx, "%s %s.\n", BOT_ENDLINKATTEMPT, dcc[i].nick); putlog(LOG_BOTS, "*", "%s %s @ %s:%d", "Stopped trying to link", dcc[i].nick, dcc[i].host, dcc[i].port); killsock(dcc[i].sock); lostdcc(i); if (nick[0] != '*') return 1; else i--; } else if (dcc[i].type == &DCC_BOT) { char s[1024]; Context; if (idx >= 0) dprintf(idx, "%s %s.\n", BOT_BREAKLINK, dcc[i].nick); else if ((idx == -3) && (b_status(i) & STAT_SHARE) && !share_unlinks) return -1; dprintf(i, "bye\n"); if (reason && reason[0]) { simple_sprintf(s, "%s %s (%s)", BOT_UNLINKEDFROM, dcc[i].nick, reason); } else { simple_sprintf(s, "%s %s", BOT_UNLINKEDFROM, dcc[i].nick); } chatout("*** %s\n", s); botnet_send_unlinked(i, dcc[i].nick, s); killsock(dcc[i].sock); lostdcc(i); if (nick[0] != '*') return 1; else i--; } } } Context; if ((idx >= 0) && (nick[0] != '*')) { dprintf(idx, "%s\n", BOT_NOTCONNECTED); /* The internal bot list is desynched from the dcc list * sometimes. While we still search for the bug, provide * an easy way to clear out those `ghost'-bots. -FK */ bot = findbot(nick); if (bot) { dprintf(idx, "BUG: Found bot `%s' in internal bot list! Removing.\n", nick); rembot(bot->bot); } } if (nick[0] == '*') { dprintf(idx, "%s\n", BOT_WIPEBOTTABLE); while (tandbot) rembot(tandbot->bot); while (parties) { parties--; /* Assert? */ if (party[i].chan >= 0) check_tcl_chpt(party[i].bot, party[i].nick, party[i].sock, party[i].chan); } strcpy(s, "killassoc &"); Tcl_Eval(interp, s); } return 0; }
/* link to another bot */ int botlink(char *linker, int idx, char *nick) { struct bot_addr *bi; struct userrec *u; register int i; Context; u = get_user_by_handle(userlist, nick); if (!u || !(u->flags & USER_BOT)) { if (idx >= 0) dprintf(idx, "%s %s\n", nick, BOT_BOTUNKNOWN); } else if (!strcasecmp(nick, botnetnick)) { if (idx >= 0) dprintf(idx, "%s\n", BOT_CANTLINKMYSELF); } else if (in_chain(nick) && (idx != -3)) { if (idx >= 0) dprintf(idx, "%s\n", BOT_ALREADYLINKED); } else { for (i = 0; i < dcc_total; i++) if ((dcc[i].user == u) && ((dcc[i].type == &DCC_FORK_BOT) || (dcc[i].type == &DCC_BOT_NEW))) { if (idx >= 0) dprintf(idx, "%s\n", BOT_ALREADYLINKING); return 0; } /* address to connect to is in 'info' */ bi = (struct bot_addr *) get_user(&USERENTRY_BOTADDR, u); if (!bi || !strlen(bi->address) || !bi->telnet_port) { if (idx >= 0) { dprintf(idx, "%s '%s'.\n", BOT_NOTELNETADDY, nick); dprintf(idx, "%s .chaddr %s %s\n", MISC_USEFORMAT, nick, MISC_CHADDRFORMAT); } } else if (dcc_total == max_dcc) { if (idx >= 0) dprintf(idx, "%s\n", DCC_TOOMANYDCCS1); } else { Context; correct_handle(nick); i = new_dcc(&DCC_FORK_BOT, sizeof(struct bot_info)); dcc[i].port = bi->telnet_port; strcpy(dcc[i].nick, nick); strcpy(dcc[i].host, bi->address); dcc[i].timeval = now; strcpy(dcc[i].u.bot->linker, linker); strcpy(dcc[i].u.bot->version, "(primitive bot)"); if (idx > -2) putlog(LOG_BOTS, "*", "%s %s at %s:%d ...", BOT_LINKING, nick, bi->address, bi->telnet_port); dcc[i].u.bot->numver = idx; dcc[i].timeval = now; dcc[i].u.bot->port = dcc[i].port; /* remember where i started */ dcc[i].sock = getsock(SOCK_STRONGCONN); dcc[i].user = u; if (open_telnet_raw(dcc[i].sock, bi->address, dcc[i].port) < 0) failed_link(i); return 1; } } return 0; }
static int dcc_seen(struct userrec *u, int idx, char *par) { putlog(LOG_CMDS, "*", "#%s# seen %s", dcc[idx].nick, par); do_seen(idx, "", dcc[idx].nick, dcc[idx].nick, "", par); return 0; }
void CheckLogs(time_t unixtime) { char tmplog[MAXLINE], olddate[MAXLINE]; char *currdate; struct tm *log_tm; time_t oldts; DIR *dp; struct dirent *dirp; int lmatches, len; if (MaxLogs) { /* * We must now check if there are MaxLogs log files * in HPath/. If so, delete the oldest one to make * room for the current one. */ if (!(dp = opendir(HPath))) { putlog(LOG1, "Error reading log directory: %s", strerror(errno)); return; } ircsprintf(tmplog, "%s.", LogFile); len = strlen(tmplog); lmatches = 0; olddate[0] = '\0'; currdate = NULL; /* * Go through all the files in the directory and * pick out the ones that match "LogFile." */ while ((dirp = readdir(dp))) { if (!ircncmp(dirp->d_name, tmplog, len)) { ++lmatches; /* * Now check the date on the log file to see * if its the oldest. */ if (!*olddate) strcpy(olddate, dirp->d_name + len); else { currdate = dirp->d_name + len; if (atol(olddate) > atol(currdate)) strcpy(olddate, currdate); } } } if ((lmatches >= MaxLogs) && *olddate) { /* * There are too many log files in the directory, * delete the oldest one - it will be: LogFile.olddate */ ircsprintf(tmplog, "%s/%s.%s", HPath, LogFile, olddate); unlink(tmplog); } closedir(dp); } /* if (MaxLogs) */ /* * Now rename the current log file. Use the TS of one * second ago since this log file is actually yesterday's, * because it just turned midnight. */ oldts = unixtime - 1; log_tm = localtime(&oldts); ircsprintf(tmplog, "%s.%d%02d%02d", LogFile, 1900 + log_tm->tm_year, log_tm->tm_mon + 1, log_tm->tm_mday); rename(LogFile, tmplog); } /* CheckLogs() */
static int uff_uncomp(int idx, char *filename) { putlog(LOG_BOTS, "*", "Uncompressing user file from %s.", dcc[idx].nick); return uncompress_file(filename); }
static int uff_comp(int idx, char *filename) { putlog(LOG_BOTS, "*", "Compressing user file for %s.", dcc[idx].nick); return compress_file(filename, compress_level); }
/* Compresses a file `f_src' and saves it as `f_target'. */ static int compress_to_file(char *f_src, char *f_target, int mode_num) { char buf[BUFLEN] = "", mode[5] = ""; FILE *fin = NULL, *fout = NULL; size_t len; adjust_mode_num(&mode_num); simple_snprintf(mode, sizeof mode, "wb%d", mode_num); if (!is_file(f_src)) { putlog(LOG_MISC, "*", "Failed to compress file `%s': not a file.", f_src); return COMPF_ERROR; } fin = fopen(f_src, "rb"); if (!fin) { putlog(LOG_MISC, "*", "Failed to compress file `%s': open failed: %s.", f_src, strerror(errno)); return COMPF_ERROR; } fout = gzopen(f_target, mode); if (!fout) { putlog(LOG_MISC, "*", "Failed to compress file `%s': gzopen failed.", f_src); return COMPF_ERROR; } #ifdef HAVE_MMAP if (compress_to_file_mmap(fout, fin) == COMPF_SUCCESS) { compressed_files++; return COMPF_SUCCESS; } else { /* To be on the safe side, close the file before attempting * to write again. */ gzclose(fout); fout = gzopen(f_target, mode); } #endif /* HAVE_MMAP */ while (1) { len = fread(buf, 1, sizeof(buf), fin); if (ferror(fin)) { putlog(LOG_MISC, "*", "Failed to compress file `%s': fread failed: %s", f_src, strerror(errno)); return COMPF_ERROR; } if (!len) break; if (gzwrite(fout, buf, (unsigned int) len) != len) { putlog(LOG_MISC, "*", "Failed to compress file `%s': gzwrite failed.", f_src); return COMPF_ERROR; } } fclose(fin); if (gzclose(fout) != Z_OK) { putlog(LOG_MISC, "*", "Failed to compress file `%s': gzclose failed.", f_src); return COMPF_ERROR; } compressed_files++; return COMPF_SUCCESS; }
void putlog(int type, const char *chname, const char *format, ...) { char va_out[LOGLINEMAX + 1] = ""; va_list va; va_start(va, format); egg_vsnprintf(va_out, sizeof(va_out), format, va); va_end(va); if (!va_out[0]) { putlog(LOG_ERRORS, "*", "Empty putlog() detected"); return; } if (!log_repeated) { if (type == last_type && !egg_strncasecmp(chname, last_chname, sizeof(last_chname)) && !egg_strncasecmp(va_out, last_log, sizeof(last_log))) { ++log_repeats; return; } if (log_repeats) { log_repeated = 1; putlog(type, last_chname, "Last message repeated %d times.\n", log_repeats); log_repeats = 0; } strlcpy(last_log, va_out, sizeof(last_log)); last_type = type; strlcpy(last_chname, chname, sizeof(last_chname)); } else log_repeated = 0; char *p = NULL; if ((p = strchr(va_out, '\n'))) /* make sure no trailing newline */ *p = 0; int idx = 0; char out[LOGLINEMAX + 1] = ""; if (conf.bot && conf.bot->hub) { char stamp[34] = ""; struct tm *t = gmtime(&now); egg_strftime(stamp, sizeof(stamp), LOG_TS, t); /* Place the timestamp in the string to be printed */ strlcpy(out, stamp, sizeof(out)); strlcat(out, " ", sizeof(out)); strlcat(out, va_out, sizeof(out)); } else strlcpy(out, va_out, sizeof(out)); /* strcat(out, "\n"); */ #ifdef no /* FIXME: WRITE LOG HERE */ int logfile_masks = LOG_CMDS|LOG_ERRORS|LOG_WARN|LOG_BOTS|LOG_MISC; if (logfile_masks && (logfile_masks & type)) logfile(type, out); #endif /* broadcast to hubs */ if (chname[0] == '*' && conf.bot && conf.bot->nick) botnet_send_log(-1, conf.bot->nick, type, out); for (idx = 0; idx < dcc_total; idx++) { if (dcc[idx].type && (dcc[idx].type == &DCC_CHAT && dcc[idx].simul == -1) && (dcc[idx].u.chat->con_flags & type)) { if ((chname[0] == '@') || (chname[0] == '*') || (dcc[idx].u.chat->con_chan[0] == '*') || (!rfc_casecmp(chname, dcc[idx].u.chat->con_chan))) dprintf(idx, "%s\n", out); } } if ((!backgrd) && (!term_z)) { dprintf(DP_STDOUT, "%s\n", out); } else if ((type & LOG_ERRORS || type & LOG_MISC) && use_stderr) { dprintf(DP_STDERR, "%s\n", va_out); } }
/* * Note: * - We write chanmode "" too, so that the bot won't use default-chanmode * instead of "" * - We will write empty need-xxxx too, why not? (less code + lazyness) */ static void write_channels() { FILE *f; char s[121], w[1024], w2[1024], name[163]; char need1[242], need2[242], need3[242], need4[242], need5[242]; struct chanset_t *chan; struct udef_struct *ul; Context; if (!chanfile[0]) return; sprintf(s, "%s~new", chanfile); f = fopen(s, "w"); chmod(s, userfile_perm); if (f == NULL) { putlog(LOG_MISC, "*", "ERROR writing channel file."); return; } if (!quiet_save) putlog(LOG_MISC, "*", "Writing channel file ..."); fprintf(f, "#Dynamic Channel File for %s (%s) -- written %s\n", origbotname, ver, ctime(&now)); for (chan = chanset; chan; chan = chan->next) { convert_element(chan->dname, name); get_mode_protect(chan, w); convert_element(w, w2); convert_element(chan->need_op, need1); convert_element(chan->need_invite, need2); convert_element(chan->need_key, need3); convert_element(chan->need_unban, need4); convert_element(chan->need_limit, need5); fprintf(f, "channel %s %s%schanmode %s idle-kick %d stopnethack-mode %d \ need-op %s need-invite %s need-key %s need-unban %s need-limit %s \ flood-chan %d:%d flood-ctcp %d:%d flood-join %d:%d \ flood-kick %d:%d flood-deop %d:%d flood-nick %d:%d \ %cclearbans %cenforcebans %cdynamicbans %cuserbans %cautoop %cbitch \ %cgreet %cprotectops %cprotectfriends %cdontkickops \ %cstatuslog %crevenge %crevengebot %cautovoice %csecret \ %cshared %ccycle %cseen %cinactive %cdynamicexempts %cuserexempts \ %cdynamicinvites %cuserinvites %cnodesynch ", channel_static(chan) ? "set" : "add", name, channel_static(chan) ? " " : " { ", w2, chan->idle_kick, /* idle-kick 0 is same as dont-idle-kick (less code)*/ chan->stopnethack_mode, need1, need2, need3, need4, need5, chan->flood_pub_thr, chan->flood_pub_time, chan->flood_ctcp_thr, chan->flood_ctcp_time, chan->flood_join_thr, chan->flood_join_time, chan->flood_kick_thr, chan->flood_kick_time, chan->flood_deop_thr, chan->flood_deop_time, chan->flood_nick_thr, chan->flood_nick_time, PLSMNS(channel_clearbans(chan)), PLSMNS(channel_enforcebans(chan)), PLSMNS(channel_dynamicbans(chan)), PLSMNS(!channel_nouserbans(chan)), PLSMNS(channel_autoop(chan)), PLSMNS(channel_bitch(chan)), PLSMNS(channel_greet(chan)), PLSMNS(channel_protectops(chan)), PLSMNS(channel_protectfriends(chan)), PLSMNS(channel_dontkickops(chan)), PLSMNS(channel_logstatus(chan)), PLSMNS(channel_revenge(chan)), PLSMNS(channel_revengebot(chan)), PLSMNS(channel_autovoice(chan)), PLSMNS(channel_secret(chan)), PLSMNS(channel_shared(chan)), PLSMNS(channel_cycle(chan)), PLSMNS(channel_seen(chan)), PLSMNS(channel_inactive(chan)), PLSMNS(channel_dynamicexempts(chan)), PLSMNS(!channel_nouserexempts(chan)), PLSMNS(channel_dynamicinvites(chan)), PLSMNS(!channel_nouserinvites(chan)), PLSMNS(channel_nodesynch(chan))); for (ul = udef; ul; ul = ul->next) { if (ul->defined && ul->name) { if (ul->type == UDEF_FLAG) fprintf(f, "%c%s%s ", getudef(ul->values, chan->dname) ? '+' : '-', "udef-flag-", ul->name); else if (ul->type == UDEF_INT) fprintf(f, "%s%s %d ", "udef-int-", ul->name, getudef(ul->values, chan->dname)); else debug1("UDEF-ERROR: unknown type %d", ul->type); } } fprintf(f, "%s\n", channel_static(chan) ? "" : "}"); if (fflush(f)) { putlog(LOG_MISC, "*", "ERROR writing channel file."); fclose(f); return; } } fclose(f); unlink(chanfile); movefile(s, chanfile); }