summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--degesch.c892
1 files changed, 429 insertions, 463 deletions
diff --git a/degesch.c b/degesch.c
index 50f29d4..98c9df2 100644
--- a/degesch.c
+++ b/degesch.c
@@ -895,44 +895,19 @@ REF_COUNTABLE_METHODS (channel)
enum buffer_line_flags
{
- BUFFER_LINE_HIGHLIGHT = 1 << 0 ///< The user was highlighted by this
-};
-
-enum buffer_line_type
-{
- BUFFER_LINE_PRIVMSG, ///< PRIVMSG
- BUFFER_LINE_ACTION, ///< PRIVMSG ACTION
- BUFFER_LINE_NOTICE, ///< NOTICE
- BUFFER_LINE_JOIN, ///< JOIN
- BUFFER_LINE_PART, ///< PART
- BUFFER_LINE_KICK, ///< KICK
- BUFFER_LINE_NICK, ///< NICK
- BUFFER_LINE_TOPIC, ///< TOPIC
- BUFFER_LINE_QUIT, ///< QUIT
- BUFFER_LINE_STATUS, ///< Whatever status messages
- BUFFER_LINE_ERROR ///< Whatever error messages
-};
-
-struct buffer_line_args
-{
- char *who; ///< Name of the origin or NULL (user)
- char *object; ///< Object of action
- char *text; ///< Text of message
- char *reason; ///< Reason for PART, KICK, QUIT
- char *prefixes; ///< Channel user prefixes
+ BUFFER_LINE_STATUS = 1 << 0, ///< Status message
+ BUFFER_LINE_ERROR = 1 << 1, ///< Error message
+ BUFFER_LINE_HIGHLIGHT = 1 << 2, ///< The user was highlighted by this
+ BUFFER_LINE_SKIP_FILE = 1 << 3 ///< Don't log this to file
};
struct buffer_line
{
LIST_HEADER (struct buffer_line)
- // We use the "type" and "flags" mostly just as formatting hints
-
- enum buffer_line_type type; ///< Type of the event
int flags; ///< Flags
-
time_t when; ///< Time of the event
- struct buffer_line_args args; ///< Arguments
+ struct formatter *formatter; ///< Line data
};
struct buffer_line *
@@ -942,14 +917,15 @@ buffer_line_new (void)
return self;
}
+// FIXME: see if we can't rearrange the code in some way to get rid of this
+static void formatter_free (struct formatter *self);
+
static void
buffer_line_destroy (struct buffer_line *self)
{
- free (self->args.who);
- free (self->args.object);
- free (self->args.text);
- free (self->args.reason);
- free (self->args.prefixes);
+ if (self->formatter)
+ formatter_free (self->formatter);
+ free (self->formatter);
free (self);
}
@@ -2006,14 +1982,20 @@ attribute_printer_update (struct attribute_printer *self)
// then flush it either to a terminal, or a log file with formatting stripped.
//
// Format strings use a #-quoted notation, to differentiate from printf:
-// #s inserts a string
-// #d inserts a signed integer; also supports the #<N> and #0<N> notation
+// #s inserts a string (expected to be in UTF-8)
+// #d inserts a signed integer
+//
+// #S inserts a string from the server with unknown encoding
// #m inserts a mIRC-formatted string (auto-resets at boundaries)
+// #n cuts the nickname from a string and automatically colours it
//
// #a inserts named attributes (auto-resets)
// #r resets terminal attributes
// #c sets foreground color
// #C sets background color
+//
+// Modifiers:
+// & free() the string argument after using it
enum formatter_item_type
{
@@ -2021,7 +2003,8 @@ enum formatter_item_type
FORMATTER_ITEM_ATTR, ///< Formatting attributes
FORMATTER_ITEM_FG_COLOR, ///< Foreground color
FORMATTER_ITEM_BG_COLOR, ///< Background color
- FORMATTER_ITEM_SIMPLE ///< For mIRC formatting only so far
+ FORMATTER_ITEM_SIMPLE, ///< For mIRC formatting only so far
+ FORMATTER_ITEM_IGNORE_ATTR ///< Un/set attribute ignoration
};
struct formatter_item
@@ -2053,17 +2036,19 @@ formatter_item_destroy (struct formatter_item *self)
struct formatter
{
struct app_context *ctx; ///< Application context
- bool ignore_new_attributes; ///< Whether to ignore new attributes
+ struct server *s; ///< Server
struct formatter_item *items; ///< Items
struct formatter_item *items_tail; ///< Tail of items
};
static void
-formatter_init (struct formatter *self, struct app_context *ctx)
+formatter_init (struct formatter *self,
+ struct app_context *ctx, struct server *s)
{
memset (self, 0, sizeof *self);
self->ctx = ctx;
+ self->s = s;
}
static void
@@ -2076,8 +2061,6 @@ formatter_free (struct formatter *self)
static void
formatter_add_item (struct formatter *self, struct formatter_item template_)
{
- if (template_.type != FORMATTER_ITEM_TEXT && self->ignore_new_attributes)
- return;
if (template_.text)
template_.text = xstrdup (template_.text);
@@ -2198,36 +2181,70 @@ formatter_parse_mirc (struct formatter *self, const char *s)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// FIXME: try to reorder the code so that we don't need these
+static char * irc_to_utf8 (struct app_context *ctx, const char *text);
+static bool irc_is_this_us (struct server *s, const char *prefix);
+
+static void
+formatter_parse_nick (struct formatter *self, char *s)
+{
+ char *nick = irc_cut_nickname (s);
+ int color = str_map_hash (nick, strlen (nick)) % 8;
+
+ // We always use the default color for ourselves
+ if (self->s && irc_is_this_us (self->s, nick))
+ color = -1;
+
+ // Never use the black colour, could become transparent on black terminals
+ if (color == COLOR_BLACK)
+ color = -1;
+
+ FORMATTER_ADD_ITEM (self, FG_COLOR, .color = color);
+
+ char *x = irc_to_utf8 (self->ctx, nick);
+ free (nick);
+ FORMATTER_ADD_TEXT (self, x);
+ free (x);
+
+ // Need to reset the color afterwards
+ FORMATTER_ADD_ITEM (self, FG_COLOR, .color = -1);
+}
+
static const char *
formatter_parse_field (struct formatter *self,
const char *field, struct str *buf, va_list *ap)
{
- size_t width = 0;
- bool zero_padded = false;
+ bool free_string = false;
+ char *s = NULL;
+ char *tmp = NULL;
int c;
restart:
switch ((c = *field++))
{
- char *s;
-
// We can push boring text content to the caller's buffer
// and let it flush the buffer only when it's actually needed
+ case 'd':
+ tmp = xstrdup_printf ("%d", va_arg (*ap, int));
+ str_append (buf, tmp);
+ free (tmp);
+ break;
case 's':
- s = va_arg (*ap, char *);
- for (size_t len = strlen (s); len < width; len++)
- str_append_c (buf, ' ');
- str_append (buf, s);
+ str_append (buf, (s = va_arg (*ap, char *)));
break;
- case 'd':
- s = xstrdup_printf ("%d", va_arg (*ap, int));
- for (size_t len = strlen (s); len < width; len++)
- str_append_c (buf, " 0"[zero_padded]);
- str_append (buf, s);
- free (s);
+
+ case 'S':
+ tmp = irc_to_utf8 (self->ctx, (s = va_arg (*ap, char *)));
+ str_append (buf, tmp);
+ free (tmp);
break;
case 'm':
- formatter_parse_mirc (self, va_arg (*ap, char *));
+ tmp = irc_to_utf8 (self->ctx, (s = va_arg (*ap, char *)));
+ formatter_parse_mirc (self, tmp);
+ free (tmp);
+ break;
+ case 'n':
+ formatter_parse_nick (self, (s = va_arg (*ap, char *)));
break;
case 'a':
@@ -2244,28 +2261,28 @@ restart:
break;
default:
- if (c == '0' && !zero_padded)
- zero_padded = true;
- else if (isdigit_ascii (c))
- width = width * 10 + (c - '0');
+ if (c == '&' && !free_string)
+ free_string = true;
else if (c)
hard_assert (!"unexpected format specifier");
else
hard_assert (!"unexpected end of format string");
goto restart;
}
+
+ if (free_string)
+ free (s);
return field;
}
+// I was unable to take a pointer of a bare "va_list" when it was passed in
+// as a function argument, so it has to be a pointer from the beginning
static void
-formatter_add (struct formatter *self, const char *format, ...)
+formatter_addv (struct formatter *self, const char *format, va_list *ap)
{
struct str buf;
str_init (&buf);
- va_list ap;
- va_start (ap, format);
-
while (*format)
{
if (*format != '#' || *++format == '#')
@@ -2279,17 +2296,61 @@ formatter_add (struct formatter *self, const char *format, ...)
str_reset (&buf);
}
- format = formatter_parse_field (self, format, &buf, &ap);
+ format = formatter_parse_field (self, format, &buf, ap);
}
if (buf.len)
FORMATTER_ADD_TEXT (self, buf.str);
str_free (&buf);
+}
+
+static void
+formatter_add (struct formatter *self, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ formatter_addv (self, format, &ap);
va_end (ap);
}
static void
+formatter_add_from (struct formatter *self, struct formatter *other)
+{
+ for (struct formatter_item *iter = other->items; iter; iter = iter->next)
+ formatter_add_item (self, *iter);
+}
+
+static bool
+formatter_flush_attr
+ (struct attribute_printer *state, struct formatter_item *item)
+{
+ switch (item->type)
+ {
+ case FORMATTER_ITEM_ATTR:
+ attribute_printer_apply (state, item->attribute);
+ state->want = 0;
+ state->want_foreground = -1;
+ state->want_background = -1;
+ return true;
+ case FORMATTER_ITEM_SIMPLE:
+ state->want |= item->attribute;
+ attribute_printer_update (state);
+ return true;
+ case FORMATTER_ITEM_FG_COLOR:
+ state->want_foreground = item->color;
+ attribute_printer_update (state);
+ return true;
+ case FORMATTER_ITEM_BG_COLOR:
+ state->want_background = item->color;
+ attribute_printer_update (state);
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void
formatter_flush (struct formatter *self, FILE *stream)
{
terminal_printer_fn printer = get_attribute_printer (stream);
@@ -2305,6 +2366,7 @@ formatter_flush (struct formatter *self, FILE *stream)
attribute_printer_init (&state, self->ctx, printer);
attribute_printer_reset (&state);
+ int attribute_ignore = 0;
LIST_FOR_EACH (struct formatter_item, iter, self->items)
{
switch (iter->type)
@@ -2316,24 +2378,13 @@ formatter_flush (struct formatter *self, FILE *stream)
fputs (term, stream);
free (term);
break;
- case FORMATTER_ITEM_ATTR:
- attribute_printer_apply (&state, iter->attribute);
- state.want = 0;
- state.want_foreground = -1;
- state.want_background = -1;
- break;
- case FORMATTER_ITEM_SIMPLE:
- state.want |= iter->attribute;
- attribute_printer_update (&state);
- break;
- case FORMATTER_ITEM_FG_COLOR:
- state.want_foreground = iter->color;
- attribute_printer_update (&state);
- break;
- case FORMATTER_ITEM_BG_COLOR:
- state.want_background = iter->color;
- attribute_printer_update (&state);
+ case FORMATTER_ITEM_IGNORE_ATTR:
+ attribute_ignore += iter->attribute;
break;
+ default:
+ if (attribute_ignore <= 0
+ && !formatter_flush_attr (&state, iter))
+ hard_assert (!"unhandled formatter item type");
}
}
attribute_printer_reset (&state);
@@ -2373,125 +2424,30 @@ buffer_line_display (struct app_context *ctx,
// confused as to when an event has happened
buffer_update_time (ctx, line->when);
- struct buffer_line_args *a = &line->args;
-
- char *nick = NULL;
- const char *userhost = NULL;
-
- // TODO: always assign the default colour to ourselves
- // FIXME: never use the black colour, use the default instead
- int nick_color = -1;
- int object_color = -1;
-
- if (a->who)
- {
- nick = irc_cut_nickname (a->who);
- userhost = irc_find_userhost (a->who);
- nick_color = str_map_hash (nick, strlen (nick)) % 8;
- }
- if (a->object)
- object_color = str_map_hash (a->object, strlen (a->object)) % 8;
-
struct formatter f;
- formatter_init (&f, ctx);
+ formatter_init (&f, ctx, NULL);
struct tm current;
if (!localtime_r (&line->when, &current))
print_error ("%s: %s", "localtime_r", strerror (errno));
else
- formatter_add (&f, "#a#02d:#02d:#02d#r ",
- ATTR_TIMESTAMP, current.tm_hour, current.tm_min, current.tm_sec);
+ formatter_add (&f, "#a#&s#r ", ATTR_TIMESTAMP,
+ xstrdup_printf ("%02d:%02d:%02d",
+ current.tm_hour, current.tm_min, current.tm_sec));
// Ignore all formatting for messages coming from other buffers, that is
// either from the global or server buffer. Instead print them in grey.
if (is_external)
{
formatter_add (&f, "#a", ATTR_EXTERNAL);
- f.ignore_new_attributes = true;
+ FORMATTER_ADD_ITEM (&f, IGNORE_ATTR, .attribute = 1);
}
- switch (line->type)
- {
- case BUFFER_LINE_PRIVMSG:
- if (line->flags & BUFFER_LINE_HIGHLIGHT)
- formatter_add (&f, "#a<#s#s>#r #m",
- ATTR_HIGHLIGHT, a->prefixes ? a->prefixes : "", nick, a->text);
- else
- formatter_add (&f, "<#s#c#s#r> #m",
- a->prefixes ? a->prefixes : "", nick_color, nick, a->text);
- break;
- case BUFFER_LINE_ACTION:
- if (line->flags & BUFFER_LINE_HIGHLIGHT)
- formatter_add (&f, " #a*#r ", ATTR_HIGHLIGHT);
- else
- formatter_add (&f, " #a*#r ", ATTR_ACTION);
- formatter_add (&f, "#c#s#r #m", nick_color, nick, a->text);
- break;
- case BUFFER_LINE_NOTICE:
- formatter_add (&f, " - ");
- if (line->flags & BUFFER_LINE_HIGHLIGHT)
- formatter_add (&f, "#a#s(#s)#r: #m",
- ATTR_HIGHLIGHT, "Notice", nick, a->text);
- else
- formatter_add (&f, "#s(#c#s#r): #m",
- "Notice", nick_color, nick, a->text);
- break;
- case BUFFER_LINE_JOIN:
- formatter_add (&f, "#a-->#r ", ATTR_JOIN);
- formatter_add (&f, "#c#s#r (#a#s#r) #a#s#r #s",
- nick_color, nick, ATTR_USERHOST, userhost,
- ATTR_JOIN, "has joined", a->object);
- break;
- case BUFFER_LINE_PART:
- formatter_add (&f, "#a<--#r ", ATTR_PART);
- formatter_add (&f, "#c#s#r (#a#s#r) #a#s#r #s",
- nick_color, nick, ATTR_USERHOST, userhost,
- ATTR_PART, "has left", a->object);
- if (a->reason)
- formatter_add (&f, " (#m)", a->reason);
- break;
- case BUFFER_LINE_KICK:
- formatter_add (&f, "#a<--#r ", ATTR_PART);
- formatter_add (&f, "#c#s#r (#a#s#r) #a#s#r #c#s#r",
- nick_color, nick, ATTR_USERHOST, userhost,
- ATTR_PART, "has kicked", object_color, a->object);
- if (a->reason)
- formatter_add (&f, " (#m)", a->reason);
- break;
- case BUFFER_LINE_NICK:
- formatter_add (&f, " - ");
- if (a->who)
- formatter_add (&f, "#c#s#r #s #c#s#r",
- nick_color, nick,
- "is now known as", object_color, a->object);
- else
- formatter_add (&f, "#s #s",
- "You are now known as", a->object);
- break;
- case BUFFER_LINE_TOPIC:
+ if (line->flags & BUFFER_LINE_STATUS)
formatter_add (&f, " - ");
- formatter_add (&f, "#c#s#r #s \"#m\"",
- nick_color, nick,
- "has changed the topic to", a->text);
- break;
- case BUFFER_LINE_QUIT:
- formatter_add (&f, "#a<--#r ", ATTR_PART);
- formatter_add (&f, "#c#s#r (#a#s#r) #a#s#r",
- nick_color, nick, ATTR_USERHOST, userhost,
- ATTR_PART, "has quit");
- if (a->reason)
- formatter_add (&f, " (#m)", a->reason);
- break;
- case BUFFER_LINE_STATUS:
- formatter_add (&f, " - ");
- formatter_add (&f, "#s", a->text);
- break;
- case BUFFER_LINE_ERROR:
+ if (line->flags & BUFFER_LINE_ERROR)
formatter_add (&f, "#a=!=#r ", ATTR_ERROR);
- formatter_add (&f, "#s", a->text);
- }
-
- free (nick);
+ formatter_add_from (&f, line->formatter);
input_hide (&ctx->input);
@@ -2506,18 +2462,19 @@ buffer_line_display (struct app_context *ctx,
}
static void
-buffer_send_internal (struct app_context *ctx, struct buffer *buffer,
- enum buffer_line_type type, int flags,
- struct buffer_line_args a)
+log_formatter (struct app_context *ctx,
+ struct buffer *buffer, int flags, struct formatter *f)
{
if (!buffer)
buffer = ctx->global_buffer;
struct buffer_line *line = buffer_line_new ();
- line->type = type;
line->flags = flags;
line->when = time (NULL);
- line->args = a;
+ line->formatter = xmalloc (sizeof *line->formatter);
+
+ // Move the formater inside
+ *line->formatter = *f;
LIST_APPEND_WITH_TAIL (buffer->lines, buffer->lines_tail, line);
buffer->lines_count++;
@@ -2551,16 +2508,37 @@ buffer_send_internal (struct app_context *ctx, struct buffer *buffer,
}
}
-#define buffer_send(ctx, buffer, type, flags, ...) \
- buffer_send_internal ((ctx), (buffer), (type), (flags), \
- (struct buffer_line_args) { __VA_ARGS__ })
+static void
+log_full (struct app_context *ctx, struct server *s, struct buffer *buffer,
+ int flags, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+
+ struct formatter f;
+ formatter_init (&f, ctx, s);
+ formatter_addv (&f, format, &ap);
+ log_formatter (ctx, buffer, flags, &f);
+
+ va_end (ap);
+}
+
+#define log_global(ctx, flags, ...) \
+ log_full ((ctx), NULL, (ctx)->global_buffer, flags, __VA_ARGS__)
+#define log_server(s, buffer, flags, ...) \
+ log_full ((s)->ctx, s, (buffer), flags, __VA_ARGS__)
+
+#define log_global_status(ctx, ...) \
+ log_global ((ctx), BUFFER_LINE_STATUS, __VA_ARGS__)
+#define log_global_error(ctx, ...) \
+ log_global ((ctx), BUFFER_LINE_ERROR, __VA_ARGS__)
-#define buffer_send_status(ctx, buffer, ...) \
- buffer_send (ctx, buffer, BUFFER_LINE_STATUS, 0, \
- .text = xstrdup_printf (__VA_ARGS__))
-#define buffer_send_error(ctx, buffer, ...) \
- buffer_send (ctx, buffer, BUFFER_LINE_ERROR, 0, \
- .text = xstrdup_printf (__VA_ARGS__))
+#define log_server_status(s, buffer, ...) \
+ log_server ((s), (buffer), BUFFER_LINE_STATUS, __VA_ARGS__)
+#define log_server_error(s, buffer, ...) \
+ log_server ((s), (buffer), BUFFER_LINE_ERROR, __VA_ARGS__)
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static struct buffer *
buffer_by_name (struct app_context *ctx, const char *name)
@@ -2656,8 +2634,9 @@ buffer_merge (struct app_context *ctx,
{
// XXX: anything better to do? This situation is arguably rare and I'm
// not entirely sure what action to take.
- buffer_send_status (ctx, buffer,
- "Buffer %s was merged into this buffer", merged->name);
+ // XXX: what good is log_*_status() when we can't use it?
+ log_full (ctx, NULL, buffer, BUFFER_LINE_STATUS,
+ "Buffer #s was merged into this buffer", merged->name);
// Find all lines from "merged" newer than the newest line in "buffer"
struct buffer_line *start = merged->lines;
@@ -2688,8 +2667,8 @@ buffer_merge (struct app_context *ctx,
buffer->lines_tail = tail;
buffer->lines_count += n;
- // XXX: we don't want to log this entry to a file
- buffer_send_status (ctx, buffer, "End of merged content");
+ log_full (ctx, NULL, buffer, BUFFER_LINE_STATUS | BUFFER_LINE_SKIP_FILE,
+ "End of merged content");
}
static void
@@ -2928,8 +2907,8 @@ irc_left_channel (struct channel *channel)
static void
remove_conflicting_buffer (struct server *s, struct buffer *buffer)
{
- buffer_send_status (s->ctx, NULL,
- "Removed buffer %s because of casemapping conflict", buffer->name);
+ log_server_status (s, s->buffer,
+ "Removed buffer #s because of casemapping conflict", buffer->name);
if (s->ctx->current_buffer == buffer)
buffer_activate (s->ctx, s->buffer);
buffer_remove (s->ctx, buffer);
@@ -3081,8 +3060,9 @@ irc_queue_reconnect (struct server *s)
// TODO: exponentional backoff
// XXX: maybe add a state for when a connect is queued?
hard_assert (s->state == IRC_DISCONNECTED);
- buffer_send_status (s->ctx, s->buffer,
- "Trying to reconnect in %ld seconds...", delay);
+ log_server_status (s, s->buffer,
+ "Trying to reconnect in #&s seconds...",
+ xstrdup_printf ("%" PRId64, delay));
poller_timer_set (&s->reconnect_tmr, delay * 1000);
}
@@ -3129,7 +3109,7 @@ ca_error:
}
// Only inform the user if we're not actually verifying
- buffer_send_error (s->ctx, s->buffer, "%s", error->message);
+ log_server_error (s, s->buffer, "#s", error->message);
error_free (error);
return true;
}
@@ -3153,13 +3133,13 @@ irc_initialize_ssl (struct server *s, struct error **e)
{
char *path = resolve_config_filename (ssl_cert);
if (!path)
- buffer_send_error (s->ctx, NULL,
- "%s: %s", "Cannot open file", ssl_cert);
+ log_server_error (s, s->buffer,
+ "#s: #s", "Cannot open file", ssl_cert);
// XXX: perhaps we should read the file ourselves for better messages
else if (!SSL_use_certificate_file (s->ssl, path, SSL_FILETYPE_PEM)
|| !SSL_use_PrivateKey_file (s->ssl, path, SSL_FILETYPE_PEM))
- buffer_send_error (s->ctx, NULL,
- "%s: %s", "Setting the SSL client certificate failed",
+ log_server_error (s, s->buffer,
+ "#s: #s", "Setting the SSL client certificate failed",
ERR_error_string (ERR_get_error (), NULL));
free (path);
}
@@ -3318,7 +3298,7 @@ try_finish_quit (struct app_context *ctx)
static void
initiate_quit (struct app_context *ctx)
{
- buffer_send_status (ctx, NULL, "Shutting down");
+ log_global_status (ctx, "Shutting down");
// Destroy the user interface
input_stop (&ctx->input);
@@ -3425,7 +3405,7 @@ static void
on_irc_ping_timeout (void *user_data)
{
struct server *s = user_data;
- buffer_send_error (s->ctx, s->buffer, "Connection timeout");
+ log_server_error (s, s->buffer, "Connection timeout");
on_irc_disconnected (s);
}
@@ -3531,12 +3511,12 @@ on_irc_readable (const struct pollfd *fd, struct server *s)
case IRC_READ_AGAIN:
goto end;
case IRC_READ_ERROR:
- buffer_send_error (s->ctx, s->buffer,
+ log_server_error (s, s->buffer,
"Reading from the IRC server failed");
disconnected = true;
goto end;
case IRC_READ_EOF:
- buffer_send_error (s->ctx, s->buffer,
+ log_server_error (s, s->buffer,
"The IRC server closed the connection");
disconnected = true;
goto end;
@@ -3546,7 +3526,7 @@ on_irc_readable (const struct pollfd *fd, struct server *s)
if (buf->len >= (1 << 20))
{
- buffer_send_error (s->ctx, s->buffer,
+ log_server_error (s, s->buffer,
"The IRC server seems to spew out data frantically");
irc_shutdown (s);
goto end;
@@ -3636,7 +3616,7 @@ irc_finish_connection (struct server *s, int socket)
bool use_ssl = get_config_boolean (s->config, "ssl");
if (use_ssl && !irc_initialize_ssl (s, &e))
{
- buffer_send_error (ctx, s->buffer, "Connection failed: %s", e->message);
+ log_server_error (s, s->buffer, "Connection failed: #s", e->message);
error_free (e);
xclose (s->socket);
@@ -3646,7 +3626,7 @@ irc_finish_connection (struct server *s, int socket)
return;
}
- buffer_send_status (ctx, s->buffer, "Connection established");
+ log_server_status (s, s->buffer, "Connection established");
s->state = IRC_CONNECTED;
poller_fd_init (&s->read_event, &ctx->poller, s->socket);
@@ -3664,14 +3644,14 @@ static void
irc_on_connector_connecting (void *user_data, const char *address)
{
struct server *s = user_data;
- buffer_send_status (s->ctx, s->buffer, "Connecting to %s...", address);
+ log_server_status (s, s->buffer, "Connecting to #s...", address);
}
static void
irc_on_connector_error (void *user_data, const char *error)
{
struct server *s = user_data;
- buffer_send_error (s->ctx, s->buffer, "Connection failed: %s", error);
+ log_server_error (s, s->buffer, "Connection failed: #s", error);
}
static void
@@ -3741,8 +3721,6 @@ static bool
irc_initiate_connect_socks (struct server *s,
const struct str_vector *addresses, struct error **e)
{
- struct app_context *ctx = s->ctx;
-
const char *socks_host = get_config_string (s->config, "socks_host");
int64_t socks_port_int = get_config_integer (s->config, "socks_port");
@@ -3760,12 +3738,9 @@ irc_initiate_connect_socks (struct server *s,
char *socks_port = xstrdup_printf ("%" PRIi64, socks_port_int);
- char *address = format_host_port_pair (irc_host, irc_port);
- char *socks_address = format_host_port_pair (socks_host, socks_port);
- buffer_send_status (ctx, s->buffer,
- "Connecting to %s via %s...", address, socks_address);
- free (socks_address);
- free (address);
+ log_server_status (s, s->buffer, "Connecting to #&s via #&s...",
+ format_host_port_pair (irc_host, irc_port),
+ format_host_port_pair (socks_host, socks_port));
// TODO: the SOCKS code needs a rewrite so that we don't block on it either;
// perhaps it could act as a special kind of connector
@@ -3790,13 +3765,12 @@ static void
irc_initiate_connect (struct server *s)
{
hard_assert (s->state == IRC_DISCONNECTED);
- struct app_context *ctx = s->ctx;
const char *addresses = get_config_string (s->config, "addresses");
if (!addresses || !addresses[strspn (addresses, ",")])
{
// No sense in trying to reconnect
- buffer_send_error (ctx, s->buffer,
+ log_server_error (s, s->buffer,
"No addresses specified in configuration");
return;
}
@@ -3813,7 +3787,7 @@ irc_initiate_connect (struct server *s)
if (e)
{
- buffer_send_error (s->ctx, s->buffer, "%s", e->message);
+ log_server_error (s, s->buffer, "#s", e->message);
error_free (e);
irc_queue_reconnect (s);
}
@@ -3972,6 +3946,8 @@ irc_cut_nickname (const char *prefix)
return xstrndup (prefix, strcspn (prefix, "!@"));
}
+// XXX: shouldn't we rather return "" on failure? Or just make a wrapper
+// for logging purposes, to be more resilient?
static const char *
irc_find_userhost (const char *prefix)
{
@@ -4307,27 +4283,20 @@ irc_handle_invite (struct server *s, const struct irc_message *msg)
if (!msg->prefix || msg->params.len < 2)
return;
- const char *target = msg->params.vector[0];
+ const char *target = msg->params.vector[0];
const char *channel_name = msg->params.vector[1];
struct buffer *buffer;
if (!(buffer = str_map_find (&s->irc_buffer_map, channel_name)))
buffer = s->buffer;
- // FIXME: logging
- char *who = irc_cut_nickname (msg->prefix);
- char *who_utf8 = irc_to_utf8 (s->ctx, who);
- free (who);
-
// IRCv3.2 invite-notify extension allows the target to be someone else
if (irc_is_this_us (s, target))
- buffer_send_status (s->ctx, buffer,
- "%s has invited you to %s", who_utf8, channel_name);
+ log_server_status (s, buffer,
+ "#n has invited you to #S", msg->prefix, channel_name);
else
- buffer_send_status (s->ctx, buffer,
- "%s has invited %s to %s", who_utf8, target, channel_name);
-
- free (who_utf8);
+ log_server_status (s, buffer,
+ "#n has invited #n to #S", msg->prefix, target, channel_name);
}
static void
@@ -4375,9 +4344,10 @@ irc_handle_join (struct server *s, const struct irc_message *msg)
// Finally log the message
if (buffer)
{
- buffer_send (s->ctx, buffer, BUFFER_LINE_JOIN, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .object = irc_to_utf8 (s->ctx, channel_name));
+ log_server (s, buffer, 0, "#a-->#r #n (#a#S#r) #a#s#r #S",
+ ATTR_JOIN, msg->prefix,
+ ATTR_USERHOST, irc_find_userhost (msg->prefix),
+ ATTR_JOIN, "has joined", channel_name);
}
}
@@ -4393,7 +4363,7 @@ irc_handle_kick (struct server *s, const struct irc_message *msg)
|| irc_is_channel (s, target))
return;
- const char *message = "";
+ const char *message = NULL;
if (msg->params.len > 2)
message = msg->params.vector[2];
@@ -4414,10 +4384,15 @@ irc_handle_kick (struct server *s, const struct irc_message *msg)
if (buffer)
{
- buffer_send (s->ctx, buffer, BUFFER_LINE_KICK, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .object = irc_to_utf8 (s->ctx, target),
- .reason = irc_to_utf8 (s->ctx, message));
+ struct formatter f;
+ formatter_init (&f, s->ctx, s);
+ formatter_add (&f, "#a<--#r #n (#a#S#r) #a#s#r #n",
+ ATTR_PART, msg->prefix,
+ ATTR_USERHOST, irc_find_userhost (msg->prefix),
+ ATTR_PART, "has kicked", target);
+ if (message)
+ formatter_add (&f, " (#m)", message);
+ log_formatter (s->ctx, buffer, 0, &f);
}
}
@@ -4427,17 +4402,14 @@ irc_handle_mode (struct server *s, const struct irc_message *msg)
if (!msg->prefix || msg->params.len < 1)
return;
- char *who = irc_cut_nickname (msg->prefix);
const char *context = msg->params.vector[0];
// Join the modes back to a single string
struct str_vector copy;
str_vector_init (&copy);
str_vector_add_vector (&copy, msg->params.vector + 1);
- char *reconstructed = join_str_vector (&copy, ' ');
+ char *modes = join_str_vector (&copy, ' ');
str_vector_free (&copy);
- char *modes = irc_to_utf8 (s->ctx, reconstructed);
- free (reconstructed);
if (irc_is_channel (s, context))
{
@@ -4449,27 +4421,23 @@ irc_handle_mode (struct server *s, const struct irc_message *msg)
if (channel)
irc_handle_mode_channel (s, channel, msg->params.vector + 1);
- // FIXME: logging
if (buffer)
{
- buffer_send_status (s->ctx, buffer,
- "Mode %s [%s] by %s", context, modes, who);
+ log_server_status (s, buffer,
+ "Mode #S [#S] by #n", context, modes, msg->prefix);
}
}
else if (irc_is_this_us (s, context))
{
irc_handle_mode_user (s, msg->params.vector + 1);
-
- // FIXME: logging
- buffer_send_status (s->ctx, s->buffer,
- "User mode [%s] by %s", modes, who);
+ log_server_status (s, s->buffer,
+ "User mode [#S] by #n", modes, msg->prefix);
}
else
{
// XXX: this shouldn't happen, reconnect?
}
- free (who);
free (modes);
// Our own modes might have changed
@@ -4504,12 +4472,13 @@ irc_handle_nick (struct server *s, const struct irc_message *msg)
str_map_find (&s->irc_buffer_map, user->nickname);
if (pm_buffer)
{
- char *who = irc_is_this_us (s, msg->prefix)
- ? NULL
- : irc_to_utf8 (s->ctx, msg->prefix);
- buffer_send (s->ctx, pm_buffer, BUFFER_LINE_NICK, 0,
- .who = who,
- .object = irc_to_utf8 (s->ctx, new_nickname));
+ // TODO: make macros of the two cases? (They are repeated below.)
+ if (irc_is_this_us (s, msg->prefix))
+ log_server (s, pm_buffer, BUFFER_LINE_STATUS, "#s #n",
+ "You are now known as", new_nickname);
+ else
+ log_server (s, pm_buffer, BUFFER_LINE_STATUS, "#n #s #n",
+ msg->prefix, "is now known as", new_nickname);
}
// The new nickname may collide with a user referenced by a PM buffer,
@@ -4566,9 +4535,8 @@ irc_handle_nick (struct server *s, const struct irc_message *msg)
// We've already done that
if (buffer == pm_buffer)
continue;
-
- buffer_send (s->ctx, buffer, BUFFER_LINE_NICK, 0,
- .object = irc_to_utf8 (s->ctx, new_nickname));
+ log_server (s, buffer, BUFFER_LINE_STATUS, "#s #n",
+ "You are now known as", new_nickname);
}
}
else
@@ -4579,9 +4547,9 @@ irc_handle_nick (struct server *s, const struct irc_message *msg)
struct buffer *buffer =
str_map_find (&s->irc_buffer_map, iter->channel->name);
hard_assert (buffer != NULL);
- buffer_send (s->ctx, buffer, BUFFER_LINE_NICK, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .object = irc_to_utf8 (s->ctx, new_nickname));
+
+ log_server (s, pm_buffer, BUFFER_LINE_STATUS, "#n #s #n",
+ msg->prefix, "is now known as", new_nickname);
}
}
@@ -4600,18 +4568,8 @@ static void
irc_handle_ctcp_reply (struct server *s,
const struct irc_message *msg, struct ctcp_chunk *chunk)
{
- char *nickname = irc_cut_nickname (msg->prefix);
- char *nickname_utf8 = irc_to_utf8 (s->ctx, nickname);
- char *tag_utf8 = irc_to_utf8 (s->ctx, chunk->tag.str);
- char *text_utf8 = irc_to_utf8 (s->ctx, chunk->text.str);
-
- buffer_send_status (s->ctx, s->buffer,
- "CTCP reply from %s: %s %s", nickname_utf8, tag_utf8, text_utf8);
-
- free (nickname);
- free (nickname_utf8);
- free (tag_utf8);
- free (text_utf8);
+ log_server_status (s, s->buffer, "CTCP reply from #n: #S #S",
+ msg->prefix, chunk->tag.str, chunk->text.str);
}
static void
@@ -4623,12 +4581,16 @@ irc_handle_notice_text (struct server *s,
if (buffer)
{
- int flags = irc_is_highlight (s, text->str)
- ? BUFFER_LINE_HIGHLIGHT
- : 0;
- buffer_send (s->ctx, buffer, BUFFER_LINE_NOTICE, flags,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .text = irc_to_utf8 (s->ctx, text->str));
+ // TODO: factor out?
+ char *nick = irc_cut_nickname (msg->prefix);
+ // IRCv3.2 echo-message could otherwise cause us to highlight ourselves
+ if (!irc_is_this_us (s, msg->prefix) && irc_is_highlight (s, text->str))
+ log_server (s, buffer, BUFFER_LINE_STATUS | BUFFER_LINE_HIGHLIGHT,
+ "#a#s(#S)#r: #m", ATTR_HIGHLIGHT, "Notice", nick, text->str);
+ else
+ log_server (s, buffer, BUFFER_LINE_STATUS,
+ "#s(#n): #m", "Notice", msg->prefix, text->str);
+ free (nick);
}
}
@@ -4682,10 +4644,15 @@ irc_handle_part (struct server *s, const struct irc_message *msg)
if (buffer)
{
- buffer_send (s->ctx, buffer, BUFFER_LINE_PART, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .object = irc_to_utf8 (s->ctx, channel_name),
- .reason = irc_to_utf8 (s->ctx, message));
+ struct formatter f;
+ formatter_init (&f, s->ctx, s);
+ formatter_add (&f, "#a<--#r #n (#a#s#r) #a#s#r #S",
+ ATTR_PART, msg->prefix,
+ ATTR_USERHOST, irc_find_userhost (msg->prefix),
+ ATTR_PART, "has left", channel_name);
+ if (message)
+ formatter_add (&f, " (#m)", message);
+ log_formatter (s->ctx, buffer, 0, &f);
}
}
@@ -4727,27 +4694,19 @@ irc_send_ctcp_reply (struct server *s,
va_end (ap);
irc_send (s, "NOTICE %s :\x01%s\x01", recipient, m.str);
-
- char *text_utf8 = irc_to_utf8 (s->ctx, m.str);
- char *recipient_utf8 = irc_to_utf8 (s->ctx, recipient);
- str_free (&m);
-
- buffer_send_status (s->ctx, s->buffer,
- "CTCP reply to %s: %s", recipient_utf8, text_utf8);
- free (text_utf8);
- free (recipient_utf8);
+ // FIXME: CAP echo-message?
+ log_server_status (s, s->buffer,
+ "CTCP reply to #S: #&S", recipient, str_steal (&m));
}
static void
irc_handle_ctcp_request (struct server *s,
const struct irc_message *msg, struct ctcp_chunk *chunk)
{
- char *nickname = irc_cut_nickname (msg->prefix);
- char *nickname_utf8 = irc_to_utf8 (s->ctx, nickname);
- char *tag_utf8 = irc_to_utf8 (s->ctx, chunk->tag.str);
+ char *nickname = irc_cut_nickname (msg->prefix);
- buffer_send_status (s->ctx, s->buffer,
- "CTCP requested by %s: %s", nickname_utf8, tag_utf8);
+ log_server_status (s, s->buffer,
+ "CTCP requested by #n: #S", nickname, chunk->tag.str);
const char *target = msg->params.vector[0];
const char *recipient = nickname;
@@ -4778,8 +4737,6 @@ irc_handle_ctcp_request (struct server *s,
}
free (nickname);
- free (nickname_utf8);
- free (tag_utf8);
}
static void
@@ -4808,16 +4765,23 @@ irc_handle_privmsg_text (struct server *s,
if (buffer)
{
// TODO: some more obvious indication of highlights
- int flags = irc_is_highlight (s, text->str)
- ? BUFFER_LINE_HIGHLIGHT
- : 0;
- enum buffer_line_type type = is_action
- ? BUFFER_LINE_ACTION
- : BUFFER_LINE_PRIVMSG;
- buffer_send (s->ctx, buffer, type, flags,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .text = irc_to_utf8 (s->ctx, text->str),
- .prefixes = xstrdup (prefixes));
+ // IRCv3.2 echo-message could otherwise cause us to highlight ourselves
+ bool is_highlight = !irc_is_this_us (s, msg->prefix)
+ && irc_is_highlight (s, text->str);
+
+ // TODO: factor out?
+ char *nick = irc_cut_nickname (msg->prefix);
+ if (is_action)
+ log_server (s, buffer, is_highlight ? BUFFER_LINE_HIGHLIGHT : 0,
+ " #a*#r #n #m",
+ is_highlight ? ATTR_HIGHLIGHT : ATTR_ACTION,
+ msg->prefix, text->str);
+ else if (is_highlight)
+ log_server (s, buffer, BUFFER_LINE_HIGHLIGHT,
+ "#a<#s#s>#r #m", ATTR_HIGHLIGHT, prefixes, nick, text->str);
+ else
+ log_server (s, buffer, 0, "<#s#n> #m", prefixes, nick, text->str);
+ free (nick);
}
}
@@ -4840,6 +4804,20 @@ irc_handle_privmsg (struct server *s, const struct irc_message *msg)
}
static void
+log_quit (struct server *s,
+ struct buffer *buffer, const char *prefix, const char *reason)
+{
+ struct formatter f;
+ formatter_init (&f, s->ctx, s);
+ formatter_add (&f, "#a<--#r #n (#a#S#r) #a#s#r",
+ ATTR_PART, prefix, ATTR_USERHOST, irc_find_userhost (prefix),
+ ATTR_PART, "has quit");
+ if (reason)
+ formatter_add (&f, " (#m)", reason);
+ log_formatter (s->ctx, buffer, 0, &f);
+}
+
+static void
irc_handle_quit (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix)
@@ -4864,9 +4842,7 @@ irc_handle_quit (struct server *s, const struct irc_message *msg)
str_map_find (&s->irc_buffer_map, user->nickname);
if (buffer)
{
- buffer_send (s->ctx, buffer, BUFFER_LINE_QUIT, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .reason = irc_to_utf8 (s->ctx, message));
+ log_quit (s, buffer, msg->prefix, message);
// TODO: set some kind of a flag in the buffer and when the user
// reappears on a channel (JOIN), log a "is back online" message.
@@ -4877,11 +4853,8 @@ irc_handle_quit (struct server *s, const struct irc_message *msg)
// Log a message in all channels the user is in
LIST_FOR_EACH (struct user_channel, iter, user->channels)
{
- buffer = str_map_find (&s->irc_buffer_map, iter->channel->name);
- if (buffer)
- buffer_send (s->ctx, buffer, BUFFER_LINE_QUIT, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .reason = irc_to_utf8 (s->ctx, message));
+ if ((buffer = str_map_find (&s->irc_buffer_map, iter->channel->name)))
+ log_quit (s, buffer, msg->prefix, message);
// This destroys "iter" which doesn't matter to us
irc_remove_user_from_channel (user, iter->channel);
@@ -4913,9 +4886,8 @@ irc_handle_topic (struct server *s, const struct irc_message *msg)
if (buffer)
{
- buffer_send (s->ctx, buffer, BUFFER_LINE_TOPIC, 0,
- .who = irc_to_utf8 (s->ctx, msg->prefix),
- .text = irc_to_utf8 (s->ctx, topic));
+ log_server (s, buffer, BUFFER_LINE_STATUS, "#n #s \"#m\"",
+ msg->prefix, "has changed the topic to", topic);
}
}
@@ -5139,8 +5111,7 @@ irc_process_names (struct server *s, struct channel *channel)
struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel->name);
if (buffer)
{
- // FIXME: logging
- buffer_send_status (s->ctx, buffer, "Users on %s: %s",
+ log_server_status (s, buffer, "Users on #S: #S",
channel->name, all_users);
}
@@ -5188,10 +5159,7 @@ irc_handle_rpl_topic (struct server *s, const struct irc_message *msg)
}
if (buffer)
- {
- // FIXME: logging
- buffer_send_status (s->ctx, buffer, "The topic is: %s", topic);
- }
+ log_server_status (s, buffer, "The topic is: #m", topic);
}
static void
@@ -5248,9 +5216,8 @@ irc_handle_rpl_creationtime (struct server *s, const struct irc_message *msg)
if (buffer)
{
- char *x = make_time_string (created);
- buffer_send_status (s->ctx, buffer, "Channel created on %s", x);
- free (x);
+ log_server_status (s, buffer, "Channel created on #&s",
+ make_time_string (created));
}
}
@@ -5273,13 +5240,11 @@ irc_handle_rpl_topicwhotime (struct server *s, const struct irc_message *msg)
hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer));
- // Topic set by x (y@z) on ...
if (buffer)
{
- // FIXME: logging
- char *x = make_time_string (changed);
- buffer_send_status (s->ctx, buffer, "Topic set by %s on %s", who, x);
- free (x);
+ log_server_status (s, buffer, "Topic set by #n (#a#S#r) on #&s",
+ who, ATTR_USERHOST, irc_find_userhost (who),
+ make_time_string (changed));
}
}
@@ -5296,9 +5261,8 @@ irc_handle_rpl_inviting (struct server *s, const struct irc_message *msg)
if (!(buffer = str_map_find (&s->irc_buffer_map, channel_name)))
buffer = s->buffer;
- // FIXME: logging
- buffer_send_status (s->ctx, buffer,
- "You have invited %s to %s", nickname, channel_name);
+ log_server_status (s, buffer,
+ "You have invited #n to #S", nickname, channel_name);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -5538,10 +5502,8 @@ irc_process_numeric (struct server *s,
{
// Join the parameter vector back, recode it to our internal encoding
// and send it to the server buffer
- char *reconstructed = join_str_vector (&copy, ' ');
- buffer_send (s->ctx, buffer, BUFFER_LINE_STATUS, 0,
- .text = irc_to_utf8 (s->ctx, reconstructed));
- free (reconstructed);
+ log_server (s, buffer, BUFFER_LINE_STATUS,
+ "#&S", join_str_vector (&copy, ' '));
}
str_vector_free (&copy);
@@ -5721,8 +5683,7 @@ send_autosplit_message (struct server *s, struct send_autosplit_args a)
struct error *e = NULL;
if (!irc_autosplit_message (s, a.message, fixed_part, &lines, &e))
{
- buffer_send_error (s->ctx,
- buffer ? buffer : s->buffer, "%s", e->message);
+ log_server_error (s, buffer ? buffer : s->buffer, "#s", e->message);
error_free (e);
goto end;
}
@@ -5745,9 +5706,11 @@ log_outcoming_action (struct server *s,
(void) a;
if (buffer && soft_assert (s->irc_user))
- buffer_send (s->ctx, buffer, BUFFER_LINE_ACTION, 0,
- .who = irc_to_utf8 (s->ctx, s->irc_user->nickname),
- .text = irc_to_utf8 (s->ctx, line));
+ {
+ // TODO: factor out, copied from irc_handle_privmsg_text()
+ log_server (s, buffer, 0, " #a*#r #n #m",
+ ATTR_ACTION, s->irc_user->nickname, line);
+ }
// This can only be sent from a user or channel buffer
}
@@ -5774,14 +5737,13 @@ log_outcoming_privmsg (struct server *s,
}
if (buffer && soft_assert (s->irc_user))
- buffer_send (s->ctx, buffer, BUFFER_LINE_PRIVMSG, 0,
- .who = irc_to_utf8 (s->ctx, s->irc_user->nickname),
- .text = irc_to_utf8 (s->ctx, line),
- .prefixes = xstrdup (prefixes));
+ {
+ // TODO: factor out, copied from irc_handle_privmsg_text()
+ log_server (s, buffer, 0,
+ "<#s#n> #m", prefixes, s->irc_user->nickname, line);
+ }
else
- // TODO: fix logging and encoding
- buffer_send (s->ctx, s->buffer, BUFFER_LINE_STATUS, 0,
- .text = xstrdup_printf ("MSG(%s): %s", a->target, line));
+ log_server_status (s, s->buffer, "MSG(#n): #m", a->target, line);
}
#define SEND_AUTOSPLIT_PRIVMSG(s, target, message) \
@@ -5793,13 +5755,13 @@ log_outcoming_notice (struct server *s,
struct send_autosplit_args *a, struct buffer *buffer, const char *line)
{
if (buffer && soft_assert (s->irc_user))
- buffer_send (s->ctx, buffer, BUFFER_LINE_NOTICE, 0,
- .who = irc_to_utf8 (s->ctx, s->irc_user->nickname),
- .text = irc_to_utf8 (s->ctx, line));
+ {
+ // TODO: factor out, copied from irc_handle_notice_text()
+ log_server (s, buffer, BUFFER_LINE_STATUS,
+ "#s(#n): #m", "Notice", s->irc_user->nickname, line);
+ }
else
- // TODO: fix logging and encoding
- buffer_send (s->ctx, s->buffer, BUFFER_LINE_STATUS, 0,
- .text = xstrdup_printf ("Notice -> %s: %s", a->target, line));
+ log_server_status (s, s->buffer, "Notice -> #n: #m", a->target, line);
}
#define SEND_AUTOSPLIT_NOTICE(s, target, message) \
@@ -6049,7 +6011,7 @@ try_handle_buffer_goto (struct app_context *ctx, const char *word)
return false;
if (n > INT_MAX || !buffer_goto (ctx, n))
- buffer_send_error (ctx, NULL, "%s: %s", "No such buffer", word);
+ log_global_error (ctx, "#s: #s", "No such buffer", word);
return true;
}
@@ -6069,12 +6031,12 @@ try_decode_buffer (struct app_context *ctx, const char *word)
static void
show_buffers_list (struct app_context *ctx)
{
- buffer_send_status (ctx, NULL, "%s", "");
- buffer_send_status (ctx, NULL, "Buffers list:");
+ log_global_status (ctx, "");
+ log_global_status (ctx, "Buffers list:");
int i = 1;
LIST_FOR_EACH (struct buffer, iter, ctx->buffers)
- buffer_send_status (ctx, NULL, " [%d] %s", i++, iter->name);
+ log_global_status (ctx, " [#d] #s", i++, iter->name);
}
static void
@@ -6088,11 +6050,11 @@ handle_buffer_close (struct app_context *ctx, struct handler_args *a)
buffer = try_decode_buffer (ctx, (which = cut_word (&a->arguments)));
if (!buffer)
- buffer_send_error (ctx, NULL, "%s: %s", "No such buffer", which);
+ log_global_error (ctx, "#s: #s", "No such buffer", which);
else if (buffer == ctx->global_buffer)
- buffer_send_error (ctx, NULL, "Can't close the global buffer");
+ log_global_error (ctx, "Can't close the global buffer");
else if (buffer->type == BUFFER_SERVER)
- buffer_send_error (ctx, NULL, "Can't close a server buffer");
+ log_global_error (ctx, "Can't close a server buffer");
else
{
if (buffer == ctx->current_buffer)
@@ -6114,7 +6076,7 @@ handle_buffer_move (struct app_context *ctx, struct handler_args *a)
if (request == 0 || request > total)
{
- buffer_send_error (ctx, NULL, "%s: %s",
+ log_global_error (ctx, "#s: #s",
"Can't move buffer", "requested position is out of range");
return true;
}
@@ -6241,8 +6203,8 @@ handle_command_set_assign_item (struct app_context *ctx,
if (e)
{
- buffer_send_error (ctx, NULL,
- "Failed to set option \"%s\": %s", key, e->message);
+ log_global_error (ctx,
+ "Failed to set option \"#s\": #s", key, e->message);
error_free (e);
}
else
@@ -6250,7 +6212,7 @@ handle_command_set_assign_item (struct app_context *ctx,
struct str_vector tmp;
str_vector_init (&tmp);
dump_matching_options (ctx, key, &tmp);
- buffer_send_status (ctx, NULL, "Option changed: %s", tmp.vector[0]);
+ log_global_status (ctx, "Option changed: #s", tmp.vector[0]);
str_vector_free (&tmp);
}
}
@@ -6275,15 +6237,14 @@ handle_command_set_assign
config_item_parse (arguments, strlen (arguments), true, &e);
if (e)
{
- buffer_send_error (ctx, NULL, "Invalid value: %s", e->message);
+ log_global_error (ctx, "Invalid value: #s", e->message);
error_free (e);
return true;
}
if ((add | remove) && !config_item_type_is_string (new_->type))
{
- buffer_send_error (ctx, NULL,
- "+= / -= operators need a string argument");
+ log_global_error (ctx, "+= / -= operators need a string argument");
config_item_destroy (new_);
return true;
}
@@ -6310,12 +6271,12 @@ handle_command_set (struct app_context *ctx, struct handler_args *a)
bool result = true;
if (!all.len)
- buffer_send_error (ctx, NULL, "No matches: %s", option);
+ log_global_error (ctx, "No matches: #s", option);
else if (!*a->arguments)
{
- buffer_send_status (ctx, NULL, "%s", "");
+ log_global_status (ctx, "");
for (size_t i = 0; i < all.len; i++)
- buffer_send_status (ctx, NULL, "%s", all.vector[i]);
+ log_global_status (ctx, "#s", all.vector[i]);
}
else
result = handle_command_set_assign (ctx, &all, a->arguments);
@@ -6340,13 +6301,12 @@ handle_command_save (struct app_context *ctx, struct handler_args *a)
if (!filename)
{
- buffer_send_error (ctx, NULL,
- "%s: %s", "Saving configuration failed", e->message);
+ log_global_error (ctx,
+ "#s: #s", "Saving configuration failed", e->message);
error_free (e);
}
else
- buffer_send_status (ctx, NULL,
- "Configuration written to `%s'", filename);
+ log_global_status (ctx, "Configuration written to `#s'", filename);
free (filename);
return true;
}
@@ -6354,12 +6314,14 @@ handle_command_save (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_msg (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (!*a->arguments)
return false;
char *target = cut_word (&a->arguments);
if (!*a->arguments)
- buffer_send_error (ctx, a->s->buffer, "No text to send");
+ log_server_error (a->s, a->s->buffer, "No text to send");
else
SEND_AUTOSPLIT_PRIVMSG (a->s, target, a->arguments);
return true;
@@ -6373,9 +6335,9 @@ handle_command_query (struct app_context *ctx, struct handler_args *a)
char *target = cut_word (&a->arguments);
if (irc_is_channel (a->s, target))
- buffer_send_error (ctx, a->s->buffer, "Cannot query a channel");
+ log_server_error (a->s, a->s->buffer, "Cannot query a channel");
else if (!*a->arguments)
- buffer_send_error (ctx, a->s->buffer, "No text to send");
+ log_server_error (a->s, a->s->buffer, "No text to send");
else
{
buffer_activate (ctx, irc_get_or_make_user_buffer (a->s, target));
@@ -6387,12 +6349,14 @@ handle_command_query (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_notice (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (!*a->arguments)
return false;
char *target = cut_word (&a->arguments);
if (!*a->arguments)
- buffer_send_error (ctx, a->s->buffer, "No text to send");
+ log_server_error (a->s, a->s->buffer, "No text to send");
else
SEND_AUTOSPLIT_NOTICE (a->s, target, a->arguments);
return true;
@@ -6401,6 +6365,8 @@ handle_command_notice (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_ctcp (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (!*a->arguments)
return false;
@@ -6417,13 +6383,15 @@ handle_command_ctcp (struct app_context *ctx, struct handler_args *a)
else
irc_send (a->s, "PRIVMSG %s :\x01%s\x01", target, tag);
- buffer_send_status (ctx, a->s->buffer, "CTCP query to %s: %s", target, tag);
+ log_server_status (a->s, a->s->buffer, "CTCP query to #S: #S", target, tag);
return true;
}
static bool
handle_command_me (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (a->buffer->type == BUFFER_CHANNEL)
SEND_AUTOSPLIT_ACTION (a->s,
a->buffer->channel->name, a->arguments);
@@ -6431,8 +6399,8 @@ handle_command_me (struct app_context *ctx, struct handler_args *a)
SEND_AUTOSPLIT_ACTION (a->s,
a->buffer->user->nickname, a->arguments);
else
- buffer_send_error (ctx, a->s->buffer,
- "Can't do this from a server buffer (%s)",
+ log_server_error (a->s, a->s->buffer,
+ "Can't do this from a server buffer (#s)",
"send CTCP actions");
return true;
}
@@ -6457,18 +6425,19 @@ handle_command_quit (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_join (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
// XXX: send the last known channel key?
if (irc_is_channel (a->s, a->arguments))
// XXX: we may want to split the list of channels
irc_send (a->s, "JOIN %s", a->arguments);
else if (a->buffer->type != BUFFER_CHANNEL)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't join",
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't join",
"no channel name given and this buffer is not a channel");
// TODO: have a better way of checking if we're on the channel
else if (a->buffer->channel->users)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't join", "you already are on the channel");
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't join",
+ "you already are on the channel");
else if (*a->arguments)
irc_send (a->s, "JOIN %s :%s", a->buffer->channel->name, a->arguments);
else
@@ -6488,6 +6457,8 @@ part_channel (struct server *s, const char *channel_name, const char *reason)
static bool
handle_command_part (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (irc_is_channel (a->s, a->arguments))
{
struct str_vector v;
@@ -6498,13 +6469,12 @@ handle_command_part (struct app_context *ctx, struct handler_args *a)
str_vector_free (&v);
}
else if (a->buffer->type != BUFFER_CHANNEL)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't part",
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't part",
"no channel name given and this buffer is not a channel");
// TODO: have a better way of checking if we're on the channel
else if (!a->buffer->channel->users)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't part", "you're not on the channel");
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't part",
+ "you're not on the channel");
else
part_channel (a->s, a->buffer->channel->name, a->arguments);
return true;
@@ -6533,6 +6503,8 @@ cycle_channel (struct server *s, const char *channel_name, const char *reason)
static bool
handle_command_cycle (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (irc_is_channel (a->s, a->arguments))
{
struct str_vector v;
@@ -6543,13 +6515,12 @@ handle_command_cycle (struct app_context *ctx, struct handler_args *a)
str_vector_free (&v);
}
else if (a->buffer->type != BUFFER_CHANNEL)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't cycle",
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't cycle",
"no channel name given and this buffer is not a channel");
// TODO: have a better way of checking if we're on the channel
else if (!a->buffer->channel->users)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't cycle", "you're not on the channel");
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't cycle",
+ "you're not on the channel");
else
cycle_channel (a->s, a->buffer->channel->name, a->arguments);
return true;
@@ -6558,6 +6529,8 @@ handle_command_cycle (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_mode (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
// Channel names prefixed by "+" collide with mode strings,
// so we just disallow specifying these channels
char *target = NULL;
@@ -6576,8 +6549,7 @@ handle_command_mode (struct app_context *ctx, struct handler_args *a)
target = cut_word (&a->arguments);
if (!target)
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't change mode",
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't change mode",
"no target given and this buffer is neither a PM nor a channel");
else if (*a->arguments)
// XXX: split channel mode params as necessary using irc_max_modes?
@@ -6738,11 +6710,11 @@ resolve_server (struct app_context *ctx, struct handler_args *a,
{
char *server_name = cut_word (&a->arguments);
if (!(s = str_map_find (&ctx->servers, server_name)))
- buffer_send_error (ctx, NULL, "/%s: %s: %s",
+ log_global_error (ctx, "/#s: #s: #s",
command_name, "no such server", server_name);
}
else if (a->buffer->type == BUFFER_GLOBAL)
- buffer_send_error (ctx, NULL, "/%s: %s",
+ log_global_error (ctx, "/#s: #s",
command_name, "no server name given and this buffer is global");
else
s = a->buffer->server;
@@ -6758,7 +6730,7 @@ handle_command_connect (struct app_context *ctx, struct handler_args *a)
if (irc_is_connected (s))
{
- buffer_send_error (ctx, s->buffer, "Already connected");
+ log_server_error (s, s->buffer, "Already connected");
return true;
}
if (s->state == IRC_CONNECTING)
@@ -6778,11 +6750,11 @@ handle_command_disconnect (struct app_context *ctx, struct handler_args *a)
if (s->state == IRC_CONNECTING)
{
- buffer_send_status (ctx, s->buffer, "Connecting aborted");
+ log_server_status (s, s->buffer, "Connecting aborted");
irc_destroy_connector (s);
}
else if (!irc_is_connected (s))
- buffer_send_error (ctx, s->buffer, "Not connected");
+ log_server_error (s, s->buffer, "Not connected");
else
irc_initiate_disconnect (s, *a->arguments ? a->arguments : NULL);
return true;
@@ -6804,6 +6776,8 @@ handle_command_names (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_whois (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (*a->arguments)
irc_send (a->s, "WHOIS %s", a->arguments);
else if (a->buffer->type == BUFFER_PM)
@@ -6811,8 +6785,7 @@ handle_command_whois (struct app_context *ctx, struct handler_args *a)
else if (a->buffer->type == BUFFER_SERVER)
irc_send (a->s, "WHOIS %s", a->s->irc_user->nickname);
else
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't request info",
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't request info",
"no target given and this buffer is not a PM nor a server");
return true;
}
@@ -6820,13 +6793,14 @@ handle_command_whois (struct app_context *ctx, struct handler_args *a)
static bool
handle_command_whowas (struct app_context *ctx, struct handler_args *a)
{
+ (void) ctx;
+
if (*a->arguments)
irc_send (a->s, "WHOWAS %s", a->arguments);
else if (a->buffer->type == BUFFER_PM)
irc_send (a->s, "WHOWAS %s", a->buffer->user->nickname);
else
- buffer_send_error (ctx, a->buffer,
- "%s: %s", "Can't request info",
+ log_server_error (a->s, a->buffer, "#s: #s", "Can't request info",
"no target given and this buffer is not a PM");
return true;
}
@@ -7038,25 +7012,21 @@ try_handle_command_help_option (struct app_context *ctx, const char *name)
struct config_schema *schema = item->schema;
if (!schema)
{
- buffer_send_error (ctx, NULL, "%s: %s", "Option not recognized", name);
+ log_global_error (ctx, "#s: #s", "Option not recognized", name);
return true;
}
- buffer_send_status (ctx, NULL, "%s", "");
- buffer_send_status (ctx, NULL,
- "Option \"%s\":", name);
- buffer_send_status (ctx, NULL,
- " Description: %s", schema->comment);
- buffer_send_status (ctx, NULL,
- " Type: %s", config_item_type_name (schema->type));
- buffer_send_status (ctx, NULL,
- " Default: %s", schema->default_ ? schema->default_ : "null");
+ log_global_status (ctx, "");
+ log_global_status (ctx, "Option \"#s\":", name);
+ log_global_status (ctx, " Description: #s", schema->comment);
+ log_global_status (ctx, " Type: #s", config_item_type_name (schema->type));
+ log_global_status (ctx, " Default: #s",
+ schema->default_ ? schema->default_ : "null");
struct str tmp;
str_init (&tmp);
config_item_write (item, false, &tmp);
- buffer_send_status (ctx, NULL,
- " Current value: %s", tmp.str);
+ log_global_status (ctx, " Current value: #s", tmp.str);
str_free (&tmp);
return true;
}
@@ -7066,8 +7036,8 @@ handle_command_help (struct app_context *ctx, struct handler_args *a)
{
if (!*a->arguments)
{
- buffer_send_status (ctx, NULL, "%s", "");
- buffer_send_status (ctx, NULL, "Commands:");
+ log_global_status (ctx, "");
+ log_global_status (ctx, "Commands:");
int longest = 0;
for (size_t i = 0; i < N_ELEMENTS (g_command_handlers); i++)
@@ -7078,8 +7048,8 @@ handle_command_help (struct app_context *ctx, struct handler_args *a)
for (size_t i = 0; i < N_ELEMENTS (g_command_handlers); i++)
{
struct command_handler *handler = &g_command_handlers[i];
- buffer_send_status (ctx, NULL,
- " %-*s %s", longest, handler->name, handler->description);
+ log_global_status (ctx, " #&s", xstrdup_printf
+ ("%-*s %s", longest, handler->name, handler->description));
}
return true;
}
@@ -7091,17 +7061,16 @@ handle_command_help (struct app_context *ctx, struct handler_args *a)
if (strcasecmp_ascii (command, handler->name))
continue;
- buffer_send_status (ctx, NULL, "%s", "");
- buffer_send_status (ctx, NULL, "%s: %s",
+ log_global_status (ctx, "");
+ log_global_status (ctx, "#s: #s",
handler->name, handler->description);
- buffer_send_status (ctx, NULL, " Arguments: %s",
+ log_global_status (ctx, " Arguments: #s",
handler->usage ? handler->usage : "(none)");
return true;
}
if (!try_handle_command_help_option (ctx, command))
- buffer_send_error (ctx, NULL,
- "%s: %s", "No such command or option", command);
+ log_global_error (ctx, "#s: #s", "No such command or option", command);
return true;
}
@@ -7163,29 +7132,28 @@ process_user_command (struct app_context *ctx, char *input)
struct command_handler *handler = str_map_find (&partial, command_name);
if (!handler)
- buffer_send_error (ctx, NULL,
- "%s: %s", "No such command", command_name);
+ log_global_error (ctx, "#s: #s", "No such command", command_name);
else if ((handler->flags & HANDLER_SERVER)
&& args.buffer->type == BUFFER_GLOBAL)
- buffer_send_error (ctx, NULL,
- "/%s: %s", command_name, "can't do this from a global buffer");
+ log_global_error (ctx, "/#s: #s",
+ command_name, "can't do this from a global buffer");
else if ((handler->flags & HANDLER_SERVER)
&& !irc_is_connected ((args.s = args.buffer->server)))
- buffer_send_error (ctx, args.s->buffer, "Not connected");
+ log_server_error (args.s, args.s->buffer, "Not connected");
else if ((handler->flags & HANDLER_NEEDS_REG)
&& args.s->state != IRC_REGISTERED)
- buffer_send_error (ctx, args.s->buffer, "Not registered");
+ log_server_error (args.s, args.s->buffer, "Not registered");
else if (((handler->flags & HANDLER_CHANNEL_FIRST)
&& !(args.channel_name =
try_get_channel (&args, maybe_cut_word)))
|| ((handler->flags & HANDLER_CHANNEL_LAST)
&& !(args.channel_name =
try_get_channel (&args, maybe_cut_word_from_end))))
- buffer_send_error (ctx, args.buffer, "/%s: %s", command_name,
+ log_server_error (args.s, args.buffer, "/#s: #s", command_name,
"no channel name given and this buffer is not a channel");
else if (!handler->handler (ctx, &args))
- buffer_send_error (ctx, NULL,
- "%s: /%s %s", "Usage", handler->name, handler->usage);
+ log_global_error (ctx,
+ "#s: /#s #s", "Usage", handler->name, handler->usage);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -7195,12 +7163,9 @@ send_message_to_target (struct server *s,
const char *target, char *message, struct buffer *buffer)
{
if (!irc_is_connected (s))
- {
- buffer_send_error (s->ctx, buffer, "Not connected");
- return;
- }
-
- SEND_AUTOSPLIT_PRIVMSG (s, target, message);
+ log_server_error (s, buffer, "Not connected");
+ else
+ SEND_AUTOSPLIT_PRIVMSG (s, target, message);
}
static void
@@ -7213,7 +7178,8 @@ send_message_to_current_buffer (struct app_context *ctx, char *message)
{
case BUFFER_GLOBAL:
case BUFFER_SERVER:
- buffer_send_error (ctx, buffer, "This buffer is not a channel");
+ log_full (ctx, NULL, buffer, BUFFER_LINE_ERROR,
+ "This buffer is not a channel");
break;
case BUFFER_CHANNEL:
send_message_to_target (buffer->server,