From fe251f72b5267f0223a0fe76910ffd215c34c40e Mon Sep 17 00:00:00 2001 From: Arnaud Cornet Date: Sat, 17 Jan 2009 14:16:31 +0100 Subject: [PATCH] [FEATURE] /quote bip backlog [n] /quote bip backlog triggers a log replay. With the optional argument n in hours, you can request a backlog of a few hours. --- src/bip.c | 11 +++++++ src/irc.c | 24 ++++++++++----- src/irc.h | 1 + src/log.c | 91 ++++++++++++++++++++++++++++++++++--------------------- src/log.h | 3 +- 5 files changed, 87 insertions(+), 43 deletions(-) diff --git a/src/bip.c b/src/bip.c index 8cead63..5a52e00 100644 --- a/src/bip.c +++ b/src/bip.c @@ -1988,6 +1988,8 @@ void adm_bip_help(struct link_client *ic, int admin, const char *subhelp) bip_notify(ic, "/BIP ON_CONNECT_SEND # Clears on_connect_send"); bip_notify(ic, "/BIP AWAY_NICK # Set away nick"); bip_notify(ic, "/BIP AWAY_NICK # clear away nick"); + bip_notify(ic, "/BIP BACKLOG [n] # backlog text of the n last " + "hours"); } else if (admin && strcasecmp(subhelp, "RELOAD") == 0) { bip_notify(ic, "/BIP RELOAD (admin only) :"); bip_notify(ic, " Reloads bip configuration file and apply " @@ -2237,6 +2239,15 @@ int adm_bip(bip_t *bip, struct link_client *ic, struct line *line, int privmsg) bip_notify(ic, "-- AWAY_NICK command needs zero or one" " argument"); } + } else if (irc_line_elem_case_equals(line, privmsg + 1, "BACKLOG")) { + if (irc_line_count(line) == privmsg + 2) { + irc_cli_backlog(ic, 0); + } else if (irc_line_count(line) == privmsg + 3) { + int hours = atoi(irc_line_elem(line, privmsg + 2)); + irc_cli_backlog(ic, hours); + } else { + bip_notify(ic, "-- BACKLOG takes 0 or one argument"); + } } else if (admin && irc_line_elem_case_equals(line, privmsg + 1, "ADD_CONN")) { if (irc_line_count(line) != privmsg + 4) { diff --git a/src/irc.c b/src/irc.c index 0c696da..cf587e1 100644 --- a/src/irc.c +++ b/src/irc.c @@ -650,7 +650,7 @@ static void irc_cli_make_join(struct link_client *ic) } } -static void irc_cli_backlog(struct link_client *ic) +void irc_cli_backlog(struct link_client *ic, int hours) { struct user *user; @@ -664,17 +664,25 @@ static void irc_cli_backlog(struct link_client *ic) return; } + if (hours != 0) { + /* have some limit */ + if (hours > 24 * 366) + hours = 24 * 366; + } + list_t *backlogl; char *bl; + list_t *bllines; backlogl = log_backlogs(LINK(ic)->log); while ((bl = list_remove_first(backlogl))) { - list_t *bllines; - bllines = backlog_lines_from_last_mark(LINK(ic)->log, bl, - LINK(ic)->l_server->nick); - mylog(LOG_INFO, "backlogging: %s", bl); - write_lines(CONN(ic), bllines); - list_free(bllines); + bllines = backlog_lines(LINK(ic)->log, bl, + LINK(ic)->l_server->nick, hours); + if (bllines) { + mylog(LOG_INFO, "backlogging: %s", bl); + write_lines(CONN(ic), bllines); + list_free(bllines); + } free(bl); } list_free(backlogl); @@ -787,7 +795,7 @@ static int irc_cli_startup(bip_t *bip, struct link_client *ic, } irc_cli_make_join(ic); - irc_cli_backlog(ic); + irc_cli_backlog(ic, 0); log_client_connected(LINK(ic)->log); free(init_nick); diff --git a/src/irc.h b/src/irc.h index 340f100..950b740 100644 --- a/src/irc.h +++ b/src/irc.h @@ -263,6 +263,7 @@ struct link *irc_link_new(); void link_kill(bip_t *bip, struct link *); void unbind_from_link(struct link_client *ic); char *nick_from_ircmask(const char *mask); +void irc_cli_backlog(struct link_client *ic, int hours); #define BIP_FAKEMASK "!bip@bip.bip.bip" #endif diff --git a/src/log.c b/src/log.c index c095cdc..528e9bc 100644 --- a/src/log.c +++ b/src/log.c @@ -16,6 +16,7 @@ #include "irc.h" #include "util.h" #include +#include extern int errno; extern int log_level; @@ -292,7 +293,6 @@ static int log_add_file(log_t *logdata, const char *destination, store->name = bip_strdup(destination); store->skip_advance = 0; hash_insert(&logdata->logfgs, destination, store); - list_it_init(&store->file_group, &store->file_it); } if (!conf_log && logdata->user->backlog) { @@ -302,6 +302,8 @@ static int log_add_file(log_t *logdata, const char *destination, if (lf) { list_add_last(&store->file_group, lf); + if (list_it_item(&store->file_it) == NULL) + list_it_init_last(&store->file_group, &store->file_it); store->file_offset = lf->len; } return 1; @@ -912,8 +914,20 @@ char *log_beautify(log_t *logdata, const char *buf, const char *storename, return ret; } +static time_t compute_time(const char *buf) +{ + struct tm tm; + int err; + err = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &tm.tm_mday, &tm.tm_mon, + &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + if (err != 6) + return (time_t)-1; + tm.tm_year -= 1900; + return mktime(&tm); +} + static int log_backread_file(log_t *log, logstore_t *store, logfile_t *lf, - list_t *res, const char *dest) + list_t *res, const char *dest, time_t start) { char *buf, *logbr; int close = 0; @@ -931,7 +945,7 @@ static int log_backread_file(log_t *log, logstore_t *store, logfile_t *lf, close = 1; } - if (list_get_first(&store->file_group) == lf) { + if (!start && list_it_item(&store->file_it) == lf) { mylog(LOG_DEBUG, "Seeking %s to %d", lf->filename, store->file_offset); if (fseek(lf->file, store->file_offset, SEEK_SET)) { @@ -968,6 +982,15 @@ static int log_backread_file(log_t *log, logstore_t *store, logfile_t *lf, if (buf[0] == 0 || buf[0] == '\n') continue; + if (start != 0) { + time_t linetime = compute_time(buf); + /* parse error, don't backlog */ + if (linetime == (time_t)-1) + continue; + /* too old line, don't backlog */ + if (linetime < start) + continue; + } logbr = log_beautify(log, buf, store->name, dest); if (logbr) list_add_last(res, logbr); @@ -1010,14 +1033,15 @@ static list_t *log_backread(log_t *log, const char *storename, const char *dest) return NULL; } - list_iterator_t file_it; + list_iterator_t file_it = store->file_it; logfile_t *logf; ret = list_new(NULL); - for (list_it_init(&store->file_group, &file_it); + for (file_it = store->file_it; (logf = list_it_item(&file_it)); list_it_next(&file_it)) { - if (!log_backread_file(log, store, logf, ret, dest)) { + if (!log_backread_file(log, store, logf, ret, dest, + (time_t)0)) { log_reinit(store); return ret; } @@ -1213,29 +1237,26 @@ int log_parse_date(char *strdate, int *year, int *month, int *mday, int *hour, return ret; } -logfile_t *logstore_get_file_at(logstore_t *store, time_t at) +void logstore_get_file_at(logstore_t *store, time_t at, list_iterator_t *li) { - list_iterator_t li; - - for (list_it_init(&store->file_group, &li); list_it_item(&li); - list_it_next(&li)) { - logfile_t *lf = list_it_item(&li); + for (list_it_init(&store->file_group, li); list_it_item(li); + list_it_next(li)) { + logfile_t *lf = list_it_item(li); if (mktime(&lf->last_log) > at) - return lf; + return; } - return NULL; } -#if 0 -list_t *backlog_hours(log_t *log, const char *storename, int hours) +static list_t *log_backread_hours(log_t *log, const char *storename, + const char *dest, int hours) { - time_t blstarttime, linetime; + time_t blstarttime; struct timeval tv; - struct tm tm; logstore_t *store; - logfile_t *lf; - const char *line; + logfile_t *logf; + list_t *ret; + list_iterator_t file_it; gettimeofday(&tv, NULL); if (tv.tv_sec <= 3600 * 24 * hours) @@ -1243,36 +1264,38 @@ list_t *backlog_hours(log_t *log, const char *storename, int hours) blstarttime = tv.tv_sec - 3600 * 24 * hours; store = hash_get(&log->logfgs, storename); - lf = logstore_get_file_at(store, blstarttime); - foreach_logline(lf, line) { - log_parse_date(line, &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - tm.tm_year -= 1900; - tm.tm_isdst = -1; - - linetime = mktime(&tm); - if (linetime > blstarttime) { + ret = list_new(NULL); + for (logstore_get_file_at(store, blstarttime, &file_it); + (logf = list_it_item(&file_it)); + list_it_next(&file_it)) { + if (!log_backread_file(log, store, logf, ret, dest, + blstarttime)) { + log_reinit(store); + return ret; } } + return ret; } -#endif -list_t *backlog_lines_from_last_mark(log_t *log, const char *bl, - const char *cli_nick) +list_t *backlog_lines(log_t *log, const char *bl, const char *cli_nick, + int hours) { list_t *ret; struct line l; const char *dest; - ret = list_new(NULL); + ret = NULL; if (ischannel(*bl)) dest = bl; else dest = cli_nick; if (log_has_backlog(log, bl)) { - ret = log_backread(log, bl, dest); + if (hours == 0) + ret = log_backread(log, bl, dest); + else + ret = log_backread_hours(log, bl, dest, hours); /* * This exception is cosmetic, but you want it. * Most of the time, you get backlog from your own nick for diff --git a/src/log.h b/src/log.h index a627f61..8584cc6 100644 --- a/src/log.h +++ b/src/log.h @@ -103,5 +103,6 @@ int check_dir(char *filename, int is_fatal); void log_reset_store(log_t *log, const char *storename); list_t *log_backlogs(log_t *log); -list_t *backlog_lines_from_last_mark(log_t *log, const char *bl, const char *); +list_t *backlog_lines(log_t *log, const char *bl, const char *cli_nick, + int hours); #endif