aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--degesch.c111
1 files changed, 94 insertions, 17 deletions
diff --git a/degesch.c b/degesch.c
index d0b0a83..193b898 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1018,6 +1018,8 @@ struct buffer
unsigned unseen_messages_count; ///< # messages since last visited
bool highlighted; ///< We've been highlighted
+ FILE *log_file; ///< Log file
+
// Origin information:
struct server *server; ///< Reference to server
@@ -1041,6 +1043,8 @@ buffer_destroy (struct buffer *self)
input_buffer_destroy (self->input_data);
LIST_FOR_EACH (struct buffer_line, iter, self->lines)
buffer_line_destroy (iter);
+ if (self->log_file)
+ (void) fclose (self->log_file);
if (self->user)
user_unref (self->user);
if (self->channel)
@@ -1550,6 +1554,10 @@ static struct config_schema g_config_behaviour[] =
.comment = "Beep when highlighted or on a new invisible PM",
.type = CONFIG_ITEM_BOOLEAN,
.default_ = "on" },
+ { .name = "logging",
+ .comment = "Log buffer contents to file",
+ .type = CONFIG_ITEM_BOOLEAN,
+ .default_ = "off" },
{}
};
@@ -2483,6 +2491,20 @@ buffer_update_time (struct app_context *ctx, time_t now)
}
static void
+buffer_line_flush (struct buffer_line *line, struct formatter *f, FILE *output)
+{
+ int flags = line->flags;
+ if (flags & BUFFER_LINE_INDENT) formatter_add (f, " ");
+ if (flags & BUFFER_LINE_STATUS) formatter_add (f, " - ");
+ if (flags & BUFFER_LINE_ERROR) formatter_add (f, "#a=!=#r ", ATTR_ERROR);
+
+ formatter_add_from (f, line->formatter);
+ formatter_add (f, "\n");
+ formatter_flush (f, output);
+ formatter_free (f);
+}
+
+static void
buffer_line_display (struct app_context *ctx,
struct buffer_line *line, bool is_external)
{
@@ -2494,12 +2516,13 @@ buffer_line_display (struct app_context *ctx,
formatter_init (&f, ctx, NULL);
struct tm current;
+ char buf[9];
if (!localtime_r (&line->when, &current))
print_error ("%s: %s", "localtime_r", strerror (errno));
+ else if (!strftime (buf, sizeof buf, "%T", &current))
+ print_error ("%s: %s", "strftime", "buffer too small");
else
- formatter_add (&f, "#a#&s#r ", ATTR_TIMESTAMP,
- xstrdup_printf ("%02d:%02d:%02d",
- current.tm_hour, current.tm_min, current.tm_sec));
+ formatter_add (&f, "#a#s#r ", ATTR_TIMESTAMP, buf);
// Ignore all formatting for messages coming from other buffers, that is
// either from the global or server buffer. Instead print them in grey.
@@ -2509,24 +2532,31 @@ buffer_line_display (struct app_context *ctx,
FORMATTER_ADD_ITEM (&f, IGNORE_ATTR, .attribute = 1);
}
- if (line->flags & BUFFER_LINE_INDENT)
- formatter_add (&f, " ");
- if (line->flags & BUFFER_LINE_STATUS)
- formatter_add (&f, " - ");
- if (line->flags & BUFFER_LINE_ERROR)
- formatter_add (&f, "#a=!=#r ", ATTR_ERROR);
- formatter_add_from (&f, line->formatter);
-
input_hide (&ctx->input);
+ buffer_line_flush (line, &f, stdout);
+ input_show (&ctx->input);
+}
- // TODO: write the line to a log file; note that the global and server
- // buffers musn't collide with filenames
+static void
+buffer_line_write_to_log (struct app_context *ctx,
+ struct buffer_line *line, FILE *log_file)
+{
+ if (line->flags & BUFFER_LINE_SKIP_FILE)
+ return;
- formatter_add (&f, "\n");
- formatter_flush (&f, stdout);
- formatter_free (&f);
+ struct formatter f;
+ formatter_init (&f, ctx, NULL);
- input_show (&ctx->input);
+ struct tm current;
+ char buf[20];
+ if (!gmtime_r (&line->when, &current))
+ print_error ("%s: %s", "gmtime_r", strerror (errno));
+ else if (!strftime (buf, sizeof buf, "%F %T", &current))
+ print_error ("%s: %s", "strftime", "buffer too small");
+ else
+ formatter_add (&f, "#s ", buf);
+
+ buffer_line_flush (line, &f, log_file);
}
static void
@@ -2547,6 +2577,9 @@ log_formatter (struct app_context *ctx,
LIST_APPEND_WITH_TAIL (buffer->lines, buffer->lines_tail, line);
buffer->lines_count++;
+ if (buffer->log_file)
+ buffer_line_write_to_log (ctx, line, buffer->log_file);
+
if (get_config_boolean (ctx->config.root, "behaviour.beep_on_highlight"))
if ((flags & BUFFER_LINE_HIGHLIGHT)
|| (buffer->type == BUFFER_PM && buffer != ctx->current_buffer))
@@ -2634,6 +2667,41 @@ log_full (struct app_context *ctx, struct server *s, struct buffer *buffer,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+static void
+make_log_filename (const char *filename, struct str *output)
+{
+ for (const char *p = filename; *p; p++)
+ // XXX: anything more to replace?
+ if (strchr ("/\\ ", *p))
+ str_append_c (output, '_');
+ else
+ str_append_c (output, tolower_ascii (*p));
+}
+
+static void
+buffer_open_log_file (struct app_context *ctx, struct buffer *buffer)
+{
+ if (!get_config_boolean (ctx->config.root, "behaviour.logging"))
+ return;
+
+ struct str path;
+ str_init (&path);
+ get_xdg_home_dir (&path, "XDG_DATA_HOME", ".local/share");
+ str_append_printf (&path, "/%s/%s", PROGRAM_NAME, "logs");
+
+ (void) mkdir_with_parents (path.str, NULL);
+
+ // TODO: make sure global and server buffers don't collide with filenames
+ str_append_c (&path, '/');
+ make_log_filename (buffer->name, &path);
+ str_append (&path, ".log");
+
+ if (!(buffer->log_file = fopen (path.str, "ab")))
+ log_global_error (ctx, "Couldn't open log file `#s': #s",
+ path.str, strerror (errno));
+ str_free (&path);
+}
+
static struct buffer *
buffer_by_name (struct app_context *ctx, const char *name)
{
@@ -2648,6 +2716,8 @@ buffer_add (struct app_context *ctx, struct buffer *buffer)
str_map_set (&ctx->buffers_by_name, buffer->name, buffer);
LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
+ buffer_open_log_file (ctx, buffer);
+
// In theory this can't cause changes in the prompt
refresh_prompt (ctx);
}
@@ -2776,6 +2846,13 @@ buffer_rename (struct app_context *ctx,
str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
str_map_set (&ctx->buffers_by_name, new_name, buffer);
+ if (buffer->log_file)
+ {
+ (void) fclose (buffer->log_file);
+ buffer->log_file = NULL;
+ }
+ buffer_open_log_file (ctx, buffer);
+
free (buffer->name);
buffer->name = xstrdup (new_name);