commit 628c770832d884749a00a4a38f2b9c1f8d50b0b2
parent 1d0762a214430910daaf493d7f25dbe024de58ba
Author: hhvn <dev@hhvn.uk>
Date: Sun, 6 Mar 2022 21:40:32 +0000
Restore from logs.
Diffstat:
5 files changed, 115 insertions(+), 1 deletion(-)
diff --git a/src/chan.c b/src/chan.c
@@ -62,7 +62,10 @@ chan_create(struct Server *server, char *name, int priv) {
channel->history->unread = 0;
channel->history->server = server;
channel->history->channel = channel;
- channel->history->history = NULL;
+ if (server)
+ channel->history->history = hist_loadlog(channel->history, server->name, name);
+ else
+ channel->history->history = NULL;
return channel;
}
diff --git a/src/config.c b/src/config.c
@@ -307,6 +307,11 @@ struct Config config[] = {
.strhandle = config_redraws,
.description = {
"Format of footer of /server -auto output", NULL}},
+ {"format.ui.logrestore", 1, Val_string,
+ .str = "%{=}%{c:93}<--- Restored log up until %{b}%{time:%c,${1}}%{b} -->",
+ .strhandle = config_redraws,
+ .description = {
+ "Format of log restore footer.", NULL}},
{"format.ui.grep.start", 1, Val_string,
.str = "%{b}%{c:94}Results of ${1}:",
.strhandle = config_redraws,
diff --git a/src/hirc.h b/src/hirc.h
@@ -95,6 +95,7 @@ struct History *hist_format(struct HistInfo *history, enum Activity activity,
enum HistOpt options, char *format, ...);
int hist_len(struct History **history);
int hist_log(struct History *hist);
+struct History *hist_loadlog(struct HistInfo *hist, char *server, char *channel);
void hist_purgeopt(struct HistInfo *histinfo, enum HistOpt options);
/* serv.c */
diff --git a/src/hist.c b/src/hist.c
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <ncurses.h>
#include <sys/stat.h>
#include "hirc.h"
@@ -236,6 +237,7 @@ hist_log(struct History *hist) {
}
}
+ /* use ',' as it's illegal in dns hostnames (I think) and channel names */
if (hist->origin->channel)
snprintf(filename, sizeof(filename), "%s/%s,%s.log", logdir, hist->origin->server->name, hist->origin->channel->name);
else
@@ -277,6 +279,108 @@ hist_log(struct History *hist) {
fclose(f);
}
+struct History *
+hist_loadlog(struct HistInfo *hist, char *server, char *channel) {
+ struct History *head = NULL, *p, *prev;
+ char filename[2048];
+ char *logdir;
+ FILE *f;
+ char *lines[HIST_MAX];
+ char buf[2048];
+ int i, j;
+ char *tok[9];
+ char *save;
+ time_t timestamp;
+ enum Activity activity;
+ char *prefix;
+ size_t len;
+ struct Nick *from;
+ char *format;
+
+ if (!server || !hist)
+ return NULL;
+
+ if ((logdir = config_gets("log.dir")) == NULL)
+ return NULL;
+
+ logdir = homepath(logdir);
+
+ if (channel)
+ snprintf(filename, sizeof(filename), "%s/%s,%s.log", logdir, server, channel);
+ else
+ snprintf(filename, sizeof(filename), "%s/%s.log", logdir, server);
+
+ if (!(f = fopen(filename, "rb")))
+ return NULL;
+
+ memset(lines, 0, sizeof(lines));
+
+ while (fgets(buf, sizeof(buf), f)) {
+ free(lines[HIST_MAX - 1]);
+ memmove(lines + 1, lines, HIST_MAX - 1);
+ buf[strlen(buf) - 1] = '\0'; /* strip newline */
+ lines[0] = estrdup(buf);
+ }
+
+ for (i = 0, prev = NULL; i < HIST_MAX && lines[i]; i++) {
+ tok[0] = strtok_r(lines[i], "\t", &save);
+ for (j = 1; j < 9; j++)
+ tok[j] = strtok_r(NULL, "\t", &save);
+
+ if (!tok[0] || !tok[1] || !tok[2] ||
+ !tok[3] || !tok[4] || !tok[5] ||
+ !tok[6] || !tok[7] || !tok[8])
+ continue;
+
+ timestamp = (time_t)strtoll(tok[0], NULL, 10);
+ activity = (int)strtol(tok[1], NULL, 10);
+
+ len = 1;
+ if (*tok[5] != ' ')
+ len += strlen(tok[5]);
+ if (*tok[6] != ' ')
+ len += strlen(tok[6]) + 1;
+ if (*tok[7] != ' ')
+ len += strlen(tok[7]) + 1;
+ prefix = emalloc(len);
+ snprintf(prefix, len, "%s%s%s%s%s",
+ tok[5] ? tok[5] : "",
+ tok[6] ? "!" : "", tok[6] ? tok[6] : "",
+ tok[7] ? "@" : "", tok[7] ? tok[7] : "");
+ from = nick_create(prefix, *tok[4], hist->server);
+ if (from)
+ from->self = *tok[3] == '1';
+
+ p = hist_create(hist, from, tok[8], activity, timestamp, *tok[2] == '1' ? HIST_SHOW : 0);
+
+ if (!head)
+ head = p;
+
+ if (prev) {
+ prev->next = p;
+ p->prev = prev;
+ }
+ prev = p;
+
+ nick_free(from);
+ free(lines[i]);
+ }
+
+ fclose(f);
+
+ if (head) {
+ len = snprintf(format, 0, "SELF_LOG_RESTORE %lld :log restored up to", (long long)head->timestamp) + 1;
+ format = emalloc(len);
+ snprintf(format, len, "SELF_LOG_RESTORE %lld :log restored up to", (long long)head->timestamp);
+ p = hist_create(hist, NULL, format, Activity_status, time(NULL), HIST_SHOW);
+ free(format);
+ p->next = head;
+ head->prev = p;
+ head = p;
+ }
+ return head;
+}
+
int
hist_len(struct History **history) {
struct History *p;
diff --git a/src/ui.c b/src/ui.c
@@ -93,6 +93,7 @@ struct {
{"SELF_AUTOCMDS_START", "format.ui.autocmds.start"},
{"SELF_AUTOCMDS_LIST", "format.ui.autocmds"},
{"SELF_AUTOCMDS_END", "format.ui.autocmds.end"},
+ {"SELF_LOG_RESTORE", "format.ui.logrestore"},
/* Real commands/numerics from server */
{"PRIVMSG", "format.privmsg"},
{"NOTICE", "format.notice"},