From 950f052d1b6967e8833dd4ea37fd914320f51b35 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Thu, 30 Apr 2015 00:02:14 +0200
Subject: degesch: refactor for multiserver
Just some basic preparations before it becomes too costly.
---
degesch.c | 974 +++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 515 insertions(+), 459 deletions(-)
diff --git a/degesch.c b/degesch.c
index 52a7f94..e0089bf 100644
--- a/degesch.c
+++ b/degesch.c
@@ -389,10 +389,9 @@ struct buffer
// Origin information:
- struct user *user; ///< Reference to user
+ struct server *server; ///< Reference to server
struct channel *channel; ///< Reference to channel
-
- // TODO: eventually a reference to the server for server buffers
+ struct user *user; ///< Reference to user
};
static struct buffer *
@@ -419,18 +418,9 @@ buffer_destroy (struct buffer *self)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-struct app_context
+struct server
{
- // Configuration:
-
- struct str_map config; ///< User configuration
- char *attrs[ATTR_COUNT]; ///< Terminal attributes
- bool no_colors; ///< Colour output mode
- bool reconnect; ///< Whether to reconnect on conn. fail.
- unsigned long reconnect_delay; ///< Reconnect delay in seconds
- bool isolate_buffers; ///< Isolate global/server buffers
-
- // Server connection:
+ struct app_context *ctx; ///< Application context
int irc_fd; ///< Socket FD of the server
struct str read_buffer; ///< Input yet to be processed
@@ -450,6 +440,8 @@ struct app_context
// maybe also broadcast all buffers about the disconnection event
// TODO: when getting connected again, rejoin all current channels
+ struct buffer *buffer; ///< The buffer for this server
+
struct str_map irc_users; ///< IRC user data
struct str_map irc_channels; ///< IRC channel data
struct str_map irc_buffer_map; ///< Maps IRC identifiers to buffers
@@ -460,12 +452,86 @@ struct app_context
// Events:
- struct poller_fd tty_event; ///< Terminal input event
- struct poller_fd signal_event; ///< Signal FD event
-
struct poller_timer ping_tmr; ///< We should send a ping
struct poller_timer timeout_tmr; ///< Connection seems to be dead
struct poller_timer reconnect_tmr; ///< We should reconnect now
+};
+
+static void on_irc_ping_timeout (void *user_data);
+static void on_irc_timeout (void *user_data);
+static void on_irc_reconnect_timeout (void *user_data);
+
+static void
+server_init (struct server *self, struct poller *poller)
+{
+ self->irc_fd = -1;
+ str_init (&self->read_buffer);
+ self->irc_ready = false;
+
+ str_map_init (&self->irc_users);
+ self->irc_users.key_xfrm = irc_strxfrm;
+ str_map_init (&self->irc_channels);
+ self->irc_channels.key_xfrm = irc_strxfrm;
+ str_map_init (&self->irc_buffer_map);
+ self->irc_buffer_map.key_xfrm = irc_strxfrm;
+
+ poller_timer_init (&self->timeout_tmr, poller);
+ self->timeout_tmr.dispatcher = on_irc_timeout;
+ self->timeout_tmr.user_data = self;
+
+ poller_timer_init (&self->ping_tmr, poller);
+ self->ping_tmr.dispatcher = on_irc_ping_timeout;
+ self->ping_tmr.user_data = self;
+
+ poller_timer_init (&self->reconnect_tmr, poller);
+ self->reconnect_tmr.dispatcher = on_irc_reconnect_timeout;
+ self->reconnect_tmr.user_data = self;
+}
+
+static void
+server_free (struct server *self)
+{
+ if (self->irc_fd != -1)
+ {
+ xclose (self->irc_fd);
+ poller_fd_reset (&self->irc_event);
+ }
+ str_free (&self->read_buffer);
+
+ if (self->ssl)
+ SSL_free (self->ssl);
+ if (self->ssl_ctx)
+ SSL_CTX_free (self->ssl_ctx);
+
+ if (self->irc_user)
+ user_unref (self->irc_user);
+ free (self->irc_user_mode);
+ free (self->irc_user_host);
+
+ str_map_free (&self->irc_users);
+ str_map_free (&self->irc_channels);
+ str_map_free (&self->irc_buffer_map);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+struct app_context
+{
+ // Configuration:
+
+ struct str_map config; ///< User configuration
+ char *attrs[ATTR_COUNT]; ///< Terminal attributes
+ bool no_colors; ///< Colour output mode
+ bool reconnect; ///< Whether to reconnect on conn. fail.
+ unsigned long reconnect_delay; ///< Reconnect delay in seconds
+ bool isolate_buffers; ///< Isolate global/server buffers
+
+ struct server server; ///< Our only server so far
+
+ // Events:
+
+ struct poller_fd tty_event; ///< Terminal input event
+ struct poller_fd signal_event; ///< Signal FD event
struct poller poller; ///< Manages polled descriptors
bool quitting; ///< User requested quitting
@@ -483,7 +549,6 @@ struct app_context
struct str_map buffers_by_name; ///< Excludes GLOBAL and SERVER
struct buffer *global_buffer; ///< The global buffer
- struct buffer *server_buffer; ///< The server buffer
struct buffer *current_buffer; ///< The current buffer
// TODO: So that we always output proper date change messages
@@ -503,10 +568,6 @@ struct app_context
}
*g_ctx;
-static void on_irc_ping_timeout (void *user_data);
-static void on_irc_timeout (void *user_data);
-static void on_irc_reconnect_timeout (void *user_data);
-
static void
app_context_init (struct app_context *self)
{
@@ -516,19 +577,11 @@ app_context_init (struct app_context *self)
self->config.free = free;
load_config_defaults (&self->config, g_config_table);
- self->irc_fd = -1;
- str_init (&self->read_buffer);
- self->irc_ready = false;
-
- str_map_init (&self->irc_users);
- self->irc_users.key_xfrm = irc_strxfrm;
- str_map_init (&self->irc_channels);
- self->irc_channels.key_xfrm = irc_strxfrm;
- str_map_init (&self->irc_buffer_map);
- self->irc_buffer_map.key_xfrm = irc_strxfrm;
-
poller_init (&self->poller);
+ server_init (&self->server, &self->poller);
+ self->server.ctx = self;
+
str_map_init (&self->buffers_by_name);
self->buffers_by_name.key_xfrm = irc_strxfrm;
@@ -559,32 +612,13 @@ app_context_free (struct app_context *self)
str_map_free (&self->config);
for (size_t i = 0; i < ATTR_COUNT; i++)
free (self->attrs[i]);
- str_free (&self->read_buffer);
-
- if (self->irc_fd != -1)
- {
- xclose (self->irc_fd);
- poller_fd_reset (&self->irc_event);
- }
- if (self->ssl)
- SSL_free (self->ssl);
- if (self->ssl_ctx)
- SSL_CTX_free (self->ssl_ctx);
-
- if (self->irc_user)
- user_unref (self->irc_user);
- free (self->irc_user_mode);
- free (self->irc_user_host);
// FIXME: this doesn't free the history state
LIST_FOR_EACH (struct buffer, iter, self->buffers)
buffer_destroy (iter);
str_map_free (&self->buffers_by_name);
- str_map_free (&self->irc_users);
- str_map_free (&self->irc_channels);
- str_map_free (&self->irc_buffer_map);
-
+ server_free (&self->server);
poller_free (&self->poller);
iconv_close (self->latin1_to_utf8);
@@ -1342,7 +1376,8 @@ buffer_send_internal (struct app_context *ctx, struct buffer *buffer,
if (buffer == ctx->current_buffer)
buffer_line_display (ctx, line, false);
else if (!ctx->isolate_buffers &&
- (buffer == ctx->global_buffer || buffer == ctx->server_buffer))
+ (buffer == ctx->global_buffer ||
+ buffer == ctx->current_buffer->server->buffer))
buffer_line_display (ctx, line, true);
else
{
@@ -1408,10 +1443,11 @@ buffer_remove (struct app_context *ctx, struct buffer *buffer)
#endif // RL_READLINE_VERSION
// And make sure to unlink the buffer from "irc_buffer_map"
+ struct server *s = buffer->server;
if (buffer->channel)
- str_map_set (&ctx->irc_buffer_map, buffer->channel->name, NULL);
+ str_map_set (&s->irc_buffer_map, buffer->channel->name, NULL);
if (buffer->user)
- str_map_set (&ctx->irc_buffer_map, buffer->user->nickname, NULL);
+ str_map_set (&s->irc_buffer_map, buffer->user->nickname, NULL);
str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
LIST_UNLINK_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
@@ -1424,8 +1460,8 @@ buffer_remove (struct app_context *ctx, struct buffer *buffer)
// one to leave the pointers point to invalid memory
if (buffer == ctx->global_buffer)
ctx->global_buffer = NULL;
- if (buffer == ctx->server_buffer)
- ctx->server_buffer = NULL;
+ if (buffer == ctx->server.buffer)
+ ctx->server.buffer = NULL;
refresh_prompt (ctx);
}
@@ -1530,7 +1566,7 @@ buffer_rename (struct app_context *ctx,
hard_assert (buffer->type == BUFFER_PM);
struct buffer *collision =
- str_map_find (&ctx->irc_buffer_map, new_name);
+ str_map_find (&buffer->server->irc_buffer_map, new_name);
if (collision)
{
// TODO: use full weechat-style buffer names
@@ -1618,13 +1654,14 @@ init_buffers (struct app_context *ctx)
{
// At the moment we have only two global everpresent buffers
struct buffer *global = ctx->global_buffer = buffer_new ();
- struct buffer *server = ctx->server_buffer = buffer_new ();
+ struct buffer *server = ctx->server.buffer = buffer_new ();
global->type = BUFFER_GLOBAL;
global->name = xstrdup (PROGRAM_NAME);
server->type = BUFFER_SERVER;
server->name = xstrdup (str_map_find (&ctx->config, "irc_host"));
+ server->server = &ctx->server;
LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, global);
LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, server);
@@ -1636,33 +1673,33 @@ static void
irc_user_on_destroy (void *object, void *user_data)
{
struct user *user = object;
- struct app_context *ctx = user_data;
- str_map_set (&ctx->irc_users, user->nickname, NULL);
+ struct server *s = user_data;
+ str_map_set (&s->irc_users, user->nickname, NULL);
}
static struct user *
-irc_make_user (struct app_context *ctx, char *nickname)
+irc_make_user (struct server *s, char *nickname)
{
- hard_assert (!str_map_find (&ctx->irc_users, nickname));
+ hard_assert (!str_map_find (&s->irc_users, nickname));
struct user *user = user_new ();
user->on_destroy = irc_user_on_destroy;
- user->user_data = ctx;
+ user->user_data = s;
user->nickname = nickname;
- str_map_set (&ctx->irc_users, user->nickname, user);
+ str_map_set (&s->irc_users, user->nickname, user);
return user;
}
static struct buffer *
-irc_get_or_make_user_buffer (struct app_context *ctx, const char *nickname)
+irc_get_or_make_user_buffer (struct server *s, const char *nickname)
{
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, nickname);
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, nickname);
if (buffer)
return buffer;
- struct user *user = str_map_find (&ctx->irc_users, nickname);
+ struct user *user = str_map_find (&s->irc_users, nickname);
if (!user)
- user = irc_make_user (ctx, xstrdup (nickname));
+ user = irc_make_user (s, xstrdup (nickname));
else
user = user_ref (user);
@@ -1670,9 +1707,10 @@ irc_get_or_make_user_buffer (struct app_context *ctx, const char *nickname)
buffer = buffer_new ();
buffer->type = BUFFER_PM;
buffer->name = xstrdup (nickname);
+ buffer->server = s;
buffer->user = user;
- LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
- str_map_set (&ctx->irc_buffer_map, user->nickname, buffer);
+ LIST_APPEND_WITH_TAIL (s->ctx->buffers, s->ctx->buffers_tail, buffer);
+ str_map_set (&s->irc_buffer_map, user->nickname, buffer);
return buffer;
}
@@ -1698,24 +1736,24 @@ static void
irc_channel_on_destroy (void *object, void *user_data)
{
struct channel *channel = object;
- struct app_context *ctx = user_data;
+ struct server *s = user_data;
LIST_FOR_EACH (struct channel_user, iter, channel->users)
irc_channel_unlink_user (channel, iter);
- str_map_set (&ctx->irc_channels, channel->name, NULL);
+ str_map_set (&s->irc_channels, channel->name, NULL);
}
static struct channel *
-irc_make_channel (struct app_context *ctx, char *name)
+irc_make_channel (struct server *s, char *name)
{
- hard_assert (!str_map_find (&ctx->irc_channels, name));
+ hard_assert (!str_map_find (&s->irc_channels, name));
struct channel *channel = channel_new ();
channel->on_destroy = irc_channel_on_destroy;
- channel->user_data = ctx;
+ channel->user_data = s;
channel->name = name;
channel->mode = xstrdup ("");
channel->topic = NULL;
- str_map_set (&ctx->irc_channels, channel->name, channel);
+ str_map_set (&s->irc_channels, channel->name, channel);
return channel;
}
@@ -1743,37 +1781,38 @@ irc_find_userhost (const char *prefix)
}
static bool
-irc_is_this_us (struct app_context *ctx, const char *prefix)
+irc_is_this_us (struct server *s, const char *prefix)
{
char *nick = irc_cut_nickname (prefix);
- bool result = !irc_strcmp (nick, ctx->irc_user->nickname);
+ bool result = !irc_strcmp (nick, s->irc_user->nickname);
free (nick);
return result;
}
static bool
-irc_is_channel (struct app_context *ctx, const char *ident)
+irc_is_channel (struct server *s, const char *ident)
{
- (void) ctx; // TODO: parse prefixes from server features
+ (void) s; // TODO: parse prefixes from server features
return *ident && !!strchr ("#&+!", *ident);
}
static void
-irc_shutdown (struct app_context *ctx)
+irc_shutdown (struct server *s)
{
// TODO: set a timer after which we cut the connection?
// Generally non-critical
- if (ctx->ssl)
- soft_assert (SSL_shutdown (ctx->ssl) != -1);
+ if (s->ssl)
+ soft_assert (SSL_shutdown (s->ssl) != -1);
else
- soft_assert (shutdown (ctx->irc_fd, SHUT_WR) == 0);
+ soft_assert (shutdown (s->irc_fd, SHUT_WR) == 0);
}
static void
try_finish_quit (struct app_context *ctx)
{
- if (ctx->quitting && ctx->irc_fd == -1)
+ // TODO: multiserver
+ if (ctx->quitting && ctx->server.irc_fd == -1)
ctx->polling = false;
}
@@ -1790,11 +1829,14 @@ initiate_quit (struct app_context *ctx)
// This is okay as long as we're not called from within readline
rl_callback_handler_remove ();
- // Initiate a connection close
buffer_send_status (ctx, ctx->global_buffer, "Shutting down");
- if (ctx->irc_fd != -1)
+
+ // Initiate a connection close
+ // TODO: multiserver
+ struct server *s = &ctx->server;
+ if (s->irc_fd != -1)
// XXX: when we go async, we'll have to flush output buffers first
- irc_shutdown (ctx);
+ irc_shutdown (s);
ctx->quitting = true;
try_finish_quit (ctx);
@@ -1823,13 +1865,13 @@ irc_to_term (struct app_context *ctx, const char *text)
return term;
}
-static bool irc_send (struct app_context *ctx,
+static bool irc_send (struct server *s,
const char *format, ...) ATTRIBUTE_PRINTF (2, 3);
static bool
-irc_send (struct app_context *ctx, const char *format, ...)
+irc_send (struct server *s, const char *format, ...)
{
- if (!soft_assert (ctx->irc_fd != -1))
+ if (!soft_assert (s->irc_fd != -1))
{
print_debug ("tried sending a message to a dead server connection");
return false;
@@ -1845,30 +1887,30 @@ irc_send (struct app_context *ctx, const char *format, ...)
if (g_debug_mode)
{
struct app_readline_state state;
- if (ctx->readline_prompt_shown)
+ if (s->ctx->readline_prompt_shown)
app_readline_hide (&state);
- char *term = irc_to_term (ctx, str.str);
+ char *term = irc_to_term (s->ctx, str.str);
fprintf (stderr, "[IRC] <== \"%s\"\n", term);
free (term);
- if (ctx->readline_prompt_shown)
- app_readline_restore (&state, ctx->readline_prompt);
+ if (s->ctx->readline_prompt_shown)
+ app_readline_restore (&state, s->ctx->readline_prompt);
}
str_append (&str, "\r\n");
bool result = true;
- if (ctx->ssl)
+ if (s->ssl)
{
// TODO: call SSL_get_error() to detect if a clean shutdown has occured
- if (SSL_write (ctx->ssl, str.str, str.len) != (int) str.len)
+ if (SSL_write (s->ssl, str.str, str.len) != (int) str.len)
{
LOG_FUNC_FAILURE ("SSL_write",
ERR_error_string (ERR_get_error (), NULL));
result = false;
}
}
- else if (write (ctx->irc_fd, str.str, str.len) != (ssize_t) str.len)
+ else if (write (s->irc_fd, str.str, str.len) != (ssize_t) str.len)
{
LOG_LIBC_FAILURE ("write");
result = false;
@@ -1893,24 +1935,24 @@ irc_get_boolean_from_config
}
static bool
-irc_initialize_ssl_ctx (struct app_context *ctx, struct error **e)
+irc_initialize_ssl_ctx (struct server *s, struct error **e)
{
// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
bool verify;
- if (!irc_get_boolean_from_config (ctx, "ssl_verify", &verify, e))
+ if (!irc_get_boolean_from_config (s->ctx, "ssl_verify", &verify, e))
return false;
if (!verify)
- SSL_CTX_set_verify (ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
+ SSL_CTX_set_verify (s->ssl_ctx, SSL_VERIFY_NONE, NULL);
- const char *ca_file = str_map_find (&ctx->config, "ca_file");
- const char *ca_path = str_map_find (&ctx->config, "ca_path");
+ const char *ca_file = str_map_find (&s->ctx->config, "ca_file");
+ const char *ca_path = str_map_find (&s->ctx->config, "ca_path");
struct error *error = NULL;
if (ca_file || ca_path)
{
- if (SSL_CTX_load_verify_locations (ctx->ssl_ctx, ca_file, ca_path))
+ if (SSL_CTX_load_verify_locations (s->ssl_ctx, ca_file, ca_path))
return true;
error_set (&error, "%s: %s",
@@ -1919,7 +1961,7 @@ irc_initialize_ssl_ctx (struct app_context *ctx, struct error **e)
goto ca_error;
}
- if (!SSL_CTX_set_default_verify_paths (ctx->ssl_ctx))
+ if (!SSL_CTX_set_default_verify_paths (s->ssl_ctx))
{
error_set (&error, "%s: %s",
"Couldn't load the default CA certificate bundle",
@@ -1936,48 +1978,48 @@ ca_error:
}
// Only inform the user if we're not actually verifying
- buffer_send_error (ctx, ctx->server_buffer, "%s", error->message);
+ buffer_send_error (s->ctx, s->buffer, "%s", error->message);
error_free (error);
return true;
}
static bool
-irc_initialize_ssl (struct app_context *ctx, struct error **e)
+irc_initialize_ssl (struct server *s, struct error **e)
{
const char *error_info = NULL;
- ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
- if (!ctx->ssl_ctx)
+ s->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
+ if (!s->ssl_ctx)
goto error_ssl_1;
- if (!irc_initialize_ssl_ctx (ctx, e))
+ if (!irc_initialize_ssl_ctx (s, e))
goto error_ssl_2;
- ctx->ssl = SSL_new (ctx->ssl_ctx);
- if (!ctx->ssl)
+ s->ssl = SSL_new (s->ssl_ctx);
+ if (!s->ssl)
goto error_ssl_2;
- const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
+ const char *ssl_cert = str_map_find (&s->ctx->config, "ssl_cert");
if (ssl_cert)
{
char *path = resolve_config_filename (ssl_cert);
if (!path)
- buffer_send_error (ctx, ctx->global_buffer,
+ buffer_send_error (s->ctx, s->ctx->global_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 (ctx->ssl, path, SSL_FILETYPE_PEM)
- || !SSL_use_PrivateKey_file (ctx->ssl, path, SSL_FILETYPE_PEM))
- buffer_send_error (ctx, ctx->global_buffer,
+ 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, s->ctx->global_buffer,
"%s: %s", "Setting the SSL client certificate failed",
ERR_error_string (ERR_get_error (), NULL));
free (path);
}
- SSL_set_connect_state (ctx->ssl);
- if (!SSL_set_fd (ctx->ssl, ctx->irc_fd))
+ SSL_set_connect_state (s->ssl);
+ if (!SSL_set_fd (s->ssl, s->irc_fd))
goto error_ssl_3;
// Avoid SSL_write() returning SSL_ERROR_WANT_READ
- SSL_set_mode (ctx->ssl, SSL_MODE_AUTO_RETRY);
+ SSL_set_mode (s->ssl, SSL_MODE_AUTO_RETRY);
- switch (xssl_get_error (ctx->ssl, SSL_connect (ctx->ssl), &error_info))
+ switch (xssl_get_error (s->ssl, SSL_connect (s->ssl), &error_info))
{
case SSL_ERROR_NONE:
return true;
@@ -1988,11 +2030,11 @@ irc_initialize_ssl (struct app_context *ctx, struct error **e)
}
error_ssl_3:
- SSL_free (ctx->ssl);
- ctx->ssl = NULL;
+ SSL_free (s->ssl);
+ s->ssl = NULL;
error_ssl_2:
- SSL_CTX_free (ctx->ssl_ctx);
- ctx->ssl_ctx = NULL;
+ SSL_CTX_free (s->ssl_ctx);
+ s->ssl_ctx = NULL;
error_ssl_1:
// XXX: these error strings are really nasty; also there could be
// multiple errors on the OpenSSL stack.
@@ -2003,7 +2045,7 @@ error_ssl_1:
}
static bool
-irc_establish_connection (struct app_context *ctx,
+irc_establish_connection (struct server *s,
const char *host, const char *port, struct error **e)
{
struct addrinfo gai_hints, *gai_result, *gai_iter;
@@ -2044,8 +2086,7 @@ irc_establish_connection (struct app_context *ctx,
real_host = buf;
char *address = format_host_port_pair (real_host, port);
- buffer_send_status (ctx, ctx->server_buffer,
- "Connecting to %s...", address);
+ buffer_send_status (s->ctx, s->buffer, "Connecting to %s...", address);
free (address);
if (!connect (sockfd, gai_iter->ai_addr, gai_iter->ai_addrlen))
@@ -2062,7 +2103,7 @@ irc_establish_connection (struct app_context *ctx,
return false;
}
- ctx->irc_fd = sockfd;
+ s->irc_fd = sockfd;
return true;
}
@@ -2114,14 +2155,15 @@ make_prompt (struct app_context *ctx, struct str *output)
if (buffer != ctx->global_buffer)
{
+ struct server *s = buffer->server;
str_append_c (output, ' ');
- if (ctx->irc_fd == -1)
+ if (s->irc_fd == -1)
str_append (output, "(disconnected)");
else
{
- str_append (output, ctx->irc_user->nickname);
- if (*ctx->irc_user_mode)
- str_append_printf (output, "(%s)", ctx->irc_user_mode);
+ str_append (output, s->irc_user->nickname);
+ if (*s->irc_user_mode)
+ str_append_printf (output, "(%s)", s->irc_user_mode);
}
}
@@ -2440,13 +2482,13 @@ ctcp_destroy (struct ctcp_chunk *list)
// TODO: we alse definitely need to parse server capability messages
static struct buffer *
-irc_get_buffer_for_message (struct app_context *ctx,
+irc_get_buffer_for_message (struct server *s,
const struct irc_message *msg, const char *target)
{
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, target);
- if (irc_is_channel (ctx, target))
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, target);
+ if (irc_is_channel (s, target))
{
- struct channel *channel = str_map_find (&ctx->irc_channels, target);
+ struct channel *channel = str_map_find (&s->irc_channels, target);
hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer));
@@ -2460,17 +2502,17 @@ irc_get_buffer_for_message (struct app_context *ctx,
// Don't make user buffers for servers (they can send NOTICEs)
if (!irc_find_userhost (msg->prefix))
- return ctx->server_buffer;
+ return s->buffer;
char *nickname = irc_cut_nickname (msg->prefix);
- buffer = irc_get_or_make_user_buffer (ctx, nickname);
+ buffer = irc_get_or_make_user_buffer (s, nickname);
free (nickname);
}
return buffer;
}
static bool
-irc_is_highlight (struct app_context *ctx, const char *message)
+irc_is_highlight (struct server *s, const char *message)
{
// Well, this is rather crude but it should make most users happy.
// Ideally we could do this at least in proper Unicode.
@@ -2478,7 +2520,7 @@ irc_is_highlight (struct app_context *ctx, const char *message)
for (char *p = copy; *p; p++)
*p = irc_tolower (*p);
- char *nick = xstrdup (ctx->irc_user->nickname);
+ char *nick = xstrdup (s->irc_user->nickname);
for (char *p = nick; *p; p++)
*p = irc_tolower (*p);
@@ -2504,32 +2546,33 @@ irc_is_highlight (struct app_context *ctx, const char *message)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
-irc_handle_join (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_join (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 1)
return;
const char *channel_name = msg->params.vector[0];
- if (!irc_is_channel (ctx, channel_name))
+ if (!irc_is_channel (s, channel_name))
return;
- struct channel *channel = str_map_find (&ctx->irc_channels, channel_name);
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, channel_name);
+ struct channel *channel = str_map_find (&s->irc_channels, channel_name);
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer));
// We've joined a new channel
- if (!channel && irc_is_this_us (ctx, msg->prefix))
+ if (!channel && irc_is_this_us (s, msg->prefix))
{
buffer = buffer_new ();
buffer->type = BUFFER_CHANNEL;
buffer->name = xstrdup (channel_name);
+ buffer->server = s;
buffer->channel = channel =
- irc_make_channel (ctx, xstrdup (channel_name));
- LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
- str_map_set (&ctx->irc_buffer_map, channel->name, buffer);
+ irc_make_channel (s, xstrdup (channel_name));
+ LIST_APPEND_WITH_TAIL (s->ctx->buffers, s->ctx->buffers_tail, buffer);
+ str_map_set (&s->irc_buffer_map, channel->name, buffer);
- buffer_activate (ctx, buffer);
+ buffer_activate (s->ctx, buffer);
}
// This is weird, ignoring
@@ -2538,9 +2581,9 @@ irc_handle_join (struct app_context *ctx, const struct irc_message *msg)
// Get or make a user object
char *nickname = irc_cut_nickname (msg->prefix);
- struct user *user = str_map_find (&ctx->irc_users, nickname);
+ struct user *user = str_map_find (&s->irc_users, nickname);
if (!user)
- user = irc_make_user (ctx, nickname);
+ user = irc_make_user (s, nickname);
else
{
user = user_ref (user);
@@ -2560,31 +2603,31 @@ irc_handle_join (struct app_context *ctx, const struct irc_message *msg)
// Finally log the message
if (buffer)
{
- buffer_send (ctx, buffer, BUFFER_LINE_JOIN, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .object = irc_to_utf8 (ctx, channel_name));
+ 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));
}
}
static void
-irc_handle_kick (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_kick (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 2)
return;
const char *channel_name = msg->params.vector[0];
const char *target = msg->params.vector[1];
- if (!irc_is_channel (ctx, channel_name)
- || irc_is_channel (ctx, target))
+ if (!irc_is_channel (s, channel_name)
+ || irc_is_channel (s, target))
return;
const char *message = "";
if (msg->params.len > 2)
message = msg->params.vector[2];
- struct user *user = str_map_find (&ctx->irc_users, target);
- struct channel *channel = str_map_find (&ctx->irc_channels, channel_name);
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, channel_name);
+ struct user *user = str_map_find (&s->irc_users, target);
+ struct channel *channel = str_map_find (&s->irc_channels, channel_name);
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer));
@@ -2594,22 +2637,22 @@ irc_handle_kick (struct app_context *ctx, const struct irc_message *msg)
if (buffer)
{
- buffer_send (ctx, buffer, BUFFER_LINE_KICK, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .object = irc_to_utf8 (ctx, target),
- .reason = irc_to_utf8 (ctx, message));
+ 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));
}
}
static void
-irc_handle_mode (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_mode (struct server *s, const struct irc_message *msg)
{
// TODO: parse the mode change and apply it
// TODO: log a message
}
static void
-irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_nick (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 1)
return;
@@ -2617,40 +2660,40 @@ irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
const char *new_nickname = msg->params.vector[0];
char *nickname = irc_cut_nickname (msg->prefix);
- struct user *user = str_map_find (&ctx->irc_users, nickname);
+ struct user *user = str_map_find (&s->irc_users, nickname);
free (nickname);
if (!user)
return;
// What the fuck
// TODO: probably log a message and force a reconnect
- if (str_map_find (&ctx->irc_users, new_nickname))
+ if (str_map_find (&s->irc_users, new_nickname))
return;
// Log a message in any PM buffer and rename it;
// we may even have one for ourselves
struct buffer *pm_buffer =
- str_map_find (&ctx->irc_buffer_map, user->nickname);
+ str_map_find (&s->irc_buffer_map, user->nickname);
if (pm_buffer)
{
- str_map_set (&ctx->irc_buffer_map, new_nickname, pm_buffer);
- str_map_set (&ctx->irc_buffer_map, user->nickname, NULL);
+ str_map_set (&s->irc_buffer_map, new_nickname, pm_buffer);
+ str_map_set (&s->irc_buffer_map, user->nickname, NULL);
- char *who = irc_is_this_us (ctx, msg->prefix)
- ? irc_to_utf8 (ctx, msg->prefix)
+ char *who = irc_is_this_us (s, msg->prefix)
+ ? irc_to_utf8 (s->ctx, msg->prefix)
: NULL;
- buffer_send (ctx, pm_buffer, BUFFER_LINE_NICK, 0,
+ buffer_send (s->ctx, pm_buffer, BUFFER_LINE_NICK, 0,
.who = who,
- .object = irc_to_utf8 (ctx, new_nickname));
+ .object = irc_to_utf8 (s->ctx, new_nickname));
// TODO: use a full weechat-style buffer name here
- buffer_rename (ctx, pm_buffer, new_nickname);
+ buffer_rename (s->ctx, pm_buffer, new_nickname);
}
- if (irc_is_this_us (ctx, msg->prefix))
+ if (irc_is_this_us (s, msg->prefix))
{
// Log a message in all open buffers on this server
struct str_map_iter iter;
- str_map_iter_init (&iter, &ctx->irc_buffer_map);
+ str_map_iter_init (&iter, &s->irc_buffer_map);
struct buffer *buffer;
while ((buffer = str_map_iter_next (&iter)))
{
@@ -2658,8 +2701,8 @@ irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
if (buffer == pm_buffer)
continue;
- buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
- .object = irc_to_utf8 (ctx, new_nickname));
+ buffer_send (s->ctx, buffer, BUFFER_LINE_NICK, 0,
+ .object = irc_to_utf8 (s->ctx, new_nickname));
}
}
else
@@ -2668,35 +2711,35 @@ irc_handle_nick (struct app_context *ctx, const struct irc_message *msg)
LIST_FOR_EACH (struct user_channel, iter, user->channels)
{
struct buffer *buffer =
- str_map_find (&ctx->irc_buffer_map, iter->channel->name);
+ str_map_find (&s->irc_buffer_map, iter->channel->name);
hard_assert (buffer != NULL);
- buffer_send (ctx, buffer, BUFFER_LINE_NICK, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .object = irc_to_utf8 (ctx, new_nickname));
+ 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));
}
}
// Finally rename the user
- str_map_set (&ctx->irc_users, new_nickname, user_ref (user));
- str_map_set (&ctx->irc_users, user->nickname, NULL);
+ str_map_set (&s->irc_users, new_nickname, user_ref (user));
+ str_map_set (&s->irc_users, user->nickname, NULL);
free (user->nickname);
user->nickname = xstrdup (new_nickname);
// We might have renamed ourselves
- refresh_prompt (ctx);
+ refresh_prompt (s->ctx);
}
static void
-irc_handle_ctcp_reply (struct app_context *ctx,
+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 (ctx, nickname);
- char *tag_utf8 = irc_to_utf8 (ctx, chunk->tag.str);
- char *text_utf8 = irc_to_utf8 (ctx, chunk->text.str);
+ 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 (ctx, ctx->server_buffer,
+ buffer_send_status (s->ctx, s->buffer,
"CTCP reply from %s: %s %s", nickname_utf8, tag_utf8, text_utf8);
free (nickname);
@@ -2706,26 +2749,26 @@ irc_handle_ctcp_reply (struct app_context *ctx,
}
static void
-irc_handle_notice_text (struct app_context *ctx,
+irc_handle_notice_text (struct server *s,
const struct irc_message *msg, struct str *text)
{
const char *target = msg->params.vector[0];
- struct buffer *buffer = irc_get_buffer_for_message (ctx, msg, target);
+ struct buffer *buffer = irc_get_buffer_for_message (s, msg, target);
if (buffer)
{
// TODO: some more obvious indication of highlights
- int flags = irc_is_highlight (ctx, text->str)
+ int flags = irc_is_highlight (s, text->str)
? BUFFER_LINE_HIGHLIGHT
: 0;
- buffer_send (ctx, buffer, BUFFER_LINE_NOTICE, flags,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .text = irc_to_utf8 (ctx, text->str));
+ 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));
}
}
static void
-irc_handle_notice (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_notice (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 2)
return;
@@ -2734,20 +2777,20 @@ irc_handle_notice (struct app_context *ctx, const struct irc_message *msg)
struct ctcp_chunk *chunks = ctcp_parse (msg->params.vector[1]);
LIST_FOR_EACH (struct ctcp_chunk, iter, chunks)
if (!iter->is_extended)
- irc_handle_notice_text (ctx, msg, &iter->text);
+ irc_handle_notice_text (s, msg, &iter->text);
else
- irc_handle_ctcp_reply (ctx, msg, iter);
+ irc_handle_ctcp_reply (s, msg, iter);
ctcp_destroy (chunks);
}
static void
-irc_handle_part (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_part (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 1)
return;
const char *channel_name = msg->params.vector[0];
- if (!irc_is_channel (ctx, channel_name))
+ if (!irc_is_channel (s, channel_name))
return;
const char *message = "";
@@ -2755,11 +2798,11 @@ irc_handle_part (struct app_context *ctx, const struct irc_message *msg)
message = msg->params.vector[1];
char *nickname = irc_cut_nickname (msg->prefix);
- struct user *user = str_map_find (&ctx->irc_users, nickname);
+ struct user *user = str_map_find (&s->irc_users, nickname);
free (nickname);
- struct channel *channel = str_map_find (&ctx->irc_channels, channel_name);
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, channel_name);
+ struct channel *channel = str_map_find (&s->irc_channels, channel_name);
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer));
@@ -2769,20 +2812,20 @@ irc_handle_part (struct app_context *ctx, const struct irc_message *msg)
if (buffer)
{
- buffer_send (ctx, buffer, BUFFER_LINE_PART, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .object = irc_to_utf8 (ctx, channel_name),
- .reason = irc_to_utf8 (ctx, message));
+ 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));
}
}
static void
-irc_handle_ping (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_ping (struct server *s, const struct irc_message *msg)
{
if (msg->params.len)
- irc_send (ctx, "PONG :%s", msg->params.vector[0]);
+ irc_send (s, "PONG :%s", msg->params.vector[0]);
else
- irc_send (ctx, "PONG");
+ irc_send (s, "PONG");
}
static char *
@@ -2798,11 +2841,11 @@ ctime_now (char buf[26])
return buf;
}
-static void irc_send_ctcp_reply (struct app_context *ctx, const char *recipient,
+static void irc_send_ctcp_reply (struct server *s, const char *recipient,
const char *format, ...) ATTRIBUTE_PRINTF (3, 4);
static void
-irc_send_ctcp_reply (struct app_context *ctx,
+irc_send_ctcp_reply (struct server *s,
const char *recipient, const char *format, ...)
{
struct str m;
@@ -2813,46 +2856,46 @@ irc_send_ctcp_reply (struct app_context *ctx,
str_append_vprintf (&m, format, ap);
va_end (ap);
- irc_send (ctx, "NOTICE %s :\x01%s\x01", recipient, m.str);
+ irc_send (s, "NOTICE %s :\x01%s\x01", recipient, m.str);
- char *text_utf8 = irc_to_utf8 (ctx, m.str);
- char *recipient_utf8 = irc_to_utf8 (ctx, recipient);
+ 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 (ctx, ctx->server_buffer,
+ buffer_send_status (s->ctx, s->buffer,
"CTCP reply to %s: %s", recipient_utf8, text_utf8);
free (text_utf8);
free (recipient_utf8);
}
static void
-irc_handle_ctcp_request (struct app_context *ctx,
+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 (ctx, nickname);
- char *tag_utf8 = irc_to_utf8 (ctx, chunk->tag.str);
+ 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);
- buffer_send_status (ctx, ctx->server_buffer,
+ buffer_send_status (s->ctx, s->buffer,
"CTCP requested by %s: %s", nickname_utf8, tag_utf8);
const char *target = msg->params.vector[0];
const char *recipient = nickname;
- if (irc_is_channel (ctx, target))
+ if (irc_is_channel (s, target))
recipient = target;
if (!strcmp (chunk->tag.str, "CLIENTINFO"))
- irc_send_ctcp_reply (ctx, recipient, "CLIENTINFO %s %s %s %s",
+ irc_send_ctcp_reply (s, recipient, "CLIENTINFO %s %s %s %s",
"PING", "VERSION", "TIME", "CLIENTINFO");
else if (!strcmp (chunk->tag.str, "PING"))
- irc_send_ctcp_reply (ctx, recipient, "PING %s", chunk->text.str);
+ irc_send_ctcp_reply (s, recipient, "PING %s", chunk->text.str);
else if (!strcmp (chunk->tag.str, "VERSION"))
{
struct utsname info;
if (uname (&info))
LOG_LIBC_FAILURE ("uname");
else
- irc_send_ctcp_reply (ctx, recipient, "VERSION %s %s on %s %s",
+ irc_send_ctcp_reply (s, recipient, "VERSION %s %s on %s %s",
PROGRAM_NAME, PROGRAM_VERSION, info.sysname, info.machine);
}
else if (!strcmp (chunk->tag.str, "TIME"))
@@ -2861,7 +2904,7 @@ irc_handle_ctcp_request (struct app_context *ctx,
if (!ctime_now (buf))
LOG_LIBC_FAILURE ("asctime_r");
else
- irc_send_ctcp_reply (ctx, recipient, "TIME %s", buf);
+ irc_send_ctcp_reply (s, recipient, "TIME %s", buf);
}
free (nickname);
@@ -2870,29 +2913,29 @@ irc_handle_ctcp_request (struct app_context *ctx,
}
static void
-irc_handle_privmsg_text (struct app_context *ctx,
+irc_handle_privmsg_text (struct server *s,
const struct irc_message *msg, struct str *text, bool is_action)
{
const char *target = msg->params.vector[0];
- struct buffer *buffer = irc_get_buffer_for_message (ctx, msg, target);
+ struct buffer *buffer = irc_get_buffer_for_message (s, msg, target);
if (buffer)
{
// TODO: some more obvious indication of highlights
- int flags = irc_is_highlight (ctx, text->str)
+ 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 (ctx, buffer, type, flags,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .text = irc_to_utf8 (ctx, text->str));
+ buffer_send (s->ctx, buffer, type, flags,
+ .who = irc_to_utf8 (s->ctx, msg->prefix),
+ .text = irc_to_utf8 (s->ctx, text->str));
}
}
static void
-irc_handle_privmsg (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_privmsg (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 2)
return;
@@ -2901,26 +2944,26 @@ irc_handle_privmsg (struct app_context *ctx, const struct irc_message *msg)
struct ctcp_chunk *chunks = ctcp_parse (msg->params.vector[1]);
LIST_FOR_EACH (struct ctcp_chunk, iter, chunks)
if (!iter->is_extended)
- irc_handle_privmsg_text (ctx, msg, &iter->text, false);
+ irc_handle_privmsg_text (s, msg, &iter->text, false);
else if (!strcmp (iter->tag.str, "ACTION"))
- irc_handle_privmsg_text (ctx, msg, &iter->text, true);
+ irc_handle_privmsg_text (s, msg, &iter->text, true);
else
- irc_handle_ctcp_request (ctx, msg, iter);
+ irc_handle_ctcp_request (s, msg, iter);
ctcp_destroy (chunks);
}
static void
-irc_handle_quit (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_quit (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix)
return;
// What the fuck
- if (irc_is_this_us (ctx, msg->prefix))
+ if (irc_is_this_us (s, msg->prefix))
return;
char *nickname = irc_cut_nickname (msg->prefix);
- struct user *user = str_map_find (&ctx->irc_users, nickname);
+ struct user *user = str_map_find (&s->irc_users, nickname);
free (nickname);
if (!user)
return;
@@ -2931,12 +2974,12 @@ irc_handle_quit (struct app_context *ctx, const struct irc_message *msg)
// Log a message in any PM buffer
struct buffer *buffer =
- str_map_find (&ctx->irc_buffer_map, user->nickname);
+ str_map_find (&s->irc_buffer_map, user->nickname);
if (buffer)
{
- buffer_send (ctx, buffer, BUFFER_LINE_QUIT, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .reason = irc_to_utf8 (ctx, message));
+ buffer_send (s->ctx, buffer, BUFFER_LINE_QUIT, 0,
+ .who = irc_to_utf8 (s->ctx, msg->prefix),
+ .reason = irc_to_utf8 (s->ctx, message));
// TODO: set some kind of a flag in the buffer and when the user
// reappers on a channel (JOIN), log a "is back online" message.
@@ -2947,11 +2990,11 @@ irc_handle_quit (struct app_context *ctx, 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 (&ctx->irc_buffer_map, iter->channel->name);
+ buffer = str_map_find (&s->irc_buffer_map, iter->channel->name);
if (buffer)
- buffer_send (ctx, buffer, BUFFER_LINE_QUIT, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .reason = irc_to_utf8 (ctx, message));
+ buffer_send (s->ctx, buffer, BUFFER_LINE_QUIT, 0,
+ .who = irc_to_utf8 (s->ctx, msg->prefix),
+ .reason = irc_to_utf8 (s->ctx, message));
// This destroys "iter" which doesn't matter to us
irc_remove_user_from_channel (user, iter->channel);
@@ -2959,18 +3002,18 @@ irc_handle_quit (struct app_context *ctx, const struct irc_message *msg)
}
static void
-irc_handle_topic (struct app_context *ctx, const struct irc_message *msg)
+irc_handle_topic (struct server *s, const struct irc_message *msg)
{
if (!msg->prefix || msg->params.len < 2)
return;
const char *channel_name = msg->params.vector[0];
const char *topic = msg->params.vector[1];
- if (!irc_is_channel (ctx, channel_name))
+ if (!irc_is_channel (s, channel_name))
return;
- struct channel *channel = str_map_find (&ctx->irc_channels, channel_name);
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, channel_name);
+ struct channel *channel = str_map_find (&s->irc_channels, channel_name);
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
hard_assert ((channel && buffer) ||
(channel && !buffer) || (!channel && !buffer));
@@ -2983,16 +3026,16 @@ irc_handle_topic (struct app_context *ctx, const struct irc_message *msg)
if (buffer)
{
- buffer_send (ctx, buffer, BUFFER_LINE_TOPIC, 0,
- .who = irc_to_utf8 (ctx, msg->prefix),
- .text = irc_to_utf8 (ctx, topic));
+ buffer_send (s->ctx, buffer, BUFFER_LINE_TOPIC, 0,
+ .who = irc_to_utf8 (s->ctx, msg->prefix),
+ .text = irc_to_utf8 (s->ctx, topic));
}
}
static struct irc_handler
{
char *name;
- void (*handler) (struct app_context *ctx, const struct irc_message *msg);
+ void (*handler) (struct server *s, const struct irc_message *msg);
}
g_irc_handlers[] =
{
@@ -3018,7 +3061,7 @@ irc_handler_cmp_by_name (const void *a, const void *b)
}
static bool
-irc_try_parse_word_for_userhost (struct app_context *ctx, const char *word)
+irc_try_parse_word_for_userhost (struct server *s, const char *word)
{
regex_t re;
int err = regcomp (&re, "^[^!@]+!([^!@]+@[^!@]+)$", REG_EXTENDED);
@@ -3029,8 +3072,8 @@ irc_try_parse_word_for_userhost (struct app_context *ctx, const char *word)
bool result = false;
if (!regexec (&re, word, 2, matches, 0))
{
- free (ctx->irc_user_host);
- ctx->irc_user_host = xstrndup (word + matches[1].rm_so,
+ free (s->irc_user_host);
+ s->irc_user_host = xstrndup (word + matches[1].rm_so,
matches[1].rm_eo - matches[1].rm_so);
result = true;
}
@@ -3039,19 +3082,19 @@ irc_try_parse_word_for_userhost (struct app_context *ctx, const char *word)
}
static void
-irc_try_parse_welcome_for_userhost (struct app_context *ctx, const char *m)
+irc_try_parse_welcome_for_userhost (struct server *s, const char *m)
{
struct str_vector v;
str_vector_init (&v);
split_str_ignore_empty (m, ' ', &v);
for (size_t i = 0; i < v.len; i++)
- if (irc_try_parse_word_for_userhost (ctx, v.vector[i]))
+ if (irc_try_parse_word_for_userhost (s, v.vector[i]))
break;
str_vector_free (&v);
}
static void
-irc_process_numeric (struct app_context *ctx,
+irc_process_numeric (struct server *s,
const struct irc_message *msg, unsigned long numeric)
{
// Numerics typically have human-readable information
@@ -3067,8 +3110,8 @@ irc_process_numeric (struct app_context *ctx,
// and send it to the server buffer
char *reconstructed = join_str_vector (©, ' ');
str_vector_free (©);
- buffer_send (ctx, ctx->server_buffer, BUFFER_LINE_STATUS, 0,
- .text = irc_to_utf8 (ctx, reconstructed));
+ buffer_send (s->ctx, s->buffer, BUFFER_LINE_STATUS, 0,
+ .text = irc_to_utf8 (s->ctx, reconstructed));
free (reconstructed);
switch (numeric)
@@ -3076,7 +3119,7 @@ irc_process_numeric (struct app_context *ctx,
case IRC_RPL_WELCOME:
// We still issue a USERHOST anyway as this is in general unreliable
if (msg->params.len == 2)
- irc_try_parse_welcome_for_userhost (ctx, msg->params.vector[1]);
+ irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]);
break;
case IRC_RPL_ISUPPORT:
// TODO: parse this, mainly PREFIX; see
@@ -3100,51 +3143,51 @@ static void
irc_process_message (const struct irc_message *msg,
const char *raw, void *user_data)
{
- struct app_context *ctx = user_data;
+ struct server *s = user_data;
if (g_debug_mode)
{
struct app_readline_state state;
- if (ctx->readline_prompt_shown)
+ if (s->ctx->readline_prompt_shown)
app_readline_hide (&state);
- char *term = irc_to_term (ctx, raw);
+ char *term = irc_to_term (s->ctx, raw);
fprintf (stderr, "[IRC] ==> \"%s\"\n", term);
free (term);
- if (ctx->readline_prompt_shown)
- app_readline_restore (&state, ctx->readline_prompt);
+ if (s->ctx->readline_prompt_shown)
+ app_readline_restore (&state, s->ctx->readline_prompt);
}
// XXX: or is the 001 numeric enough? For what?
- if (!ctx->irc_ready && (!strcasecmp (msg->command, "MODE")
+ if (!s->irc_ready && (!strcasecmp (msg->command, "MODE")
|| !strcasecmp (msg->command, "376") // RPL_ENDOFMOTD
|| !strcasecmp (msg->command, "422"))) // ERR_NOMOTD
{
// XXX: should we really print this?
- buffer_send_status (ctx, ctx->server_buffer, "Successfully connected");
- ctx->irc_ready = true;
- refresh_prompt (ctx);
+ buffer_send_status (s->ctx, s->buffer, "Successfully connected");
+ s->irc_ready = true;
+ refresh_prompt (s->ctx);
// TODO: parse any response and store the result for us in app_context;
// this enables proper message splitting on output;
// we can also use WHOIS if it's not supported (optional by RFC 2812)
- irc_send (ctx, "USERHOST %s", ctx->irc_user->nickname);
+ irc_send (s, "USERHOST %s", s->irc_user->nickname);
- const char *autojoin = str_map_find (&ctx->config, "autojoin");
+ const char *autojoin = str_map_find (&s->ctx->config, "autojoin");
if (autojoin)
- irc_send (ctx, "JOIN :%s", autojoin);
+ irc_send (s, "JOIN :%s", autojoin);
}
struct irc_handler key = { .name = msg->command };
struct irc_handler *handler = bsearch (&key, g_irc_handlers,
N_ELEMENTS (g_irc_handlers), sizeof key, irc_handler_cmp_by_name);
if (handler)
- handler->handler (ctx, msg);
+ handler->handler (s, msg);
unsigned long numeric;
if (xstrtoul (&numeric, msg->command, 10))
- irc_process_numeric (ctx, msg, numeric);
+ irc_process_numeric (s, msg, numeric);
}
// --- Message autosplitting magic ---------------------------------------------
@@ -3241,15 +3284,15 @@ error:
/// Automatically splits messages that arrive at other clients with our prefix
/// so that they don't arrive cut off by the server
static bool
-irc_autosplit_message (struct app_context *ctx, const char *message,
+irc_autosplit_message (struct server *s, const char *message,
int fixed_part, struct str_vector *output, struct error **e)
{
// :!@
int space_in_one_message = 0;
- if (ctx->irc_user_host)
+ if (s->irc_user_host)
space_in_one_message = 510
- - 1 - (int) strlen (ctx->irc_user->nickname)
- - 1 - (int) strlen (ctx->irc_user_host)
+ - 1 - (int) strlen (s->irc_user->nickname)
+ - 1 - (int) strlen (s->irc_user_host)
- 1 - fixed_part;
// However we don't always have the full info for message splitting
@@ -3262,7 +3305,7 @@ irc_autosplit_message (struct app_context *ctx, const char *message,
struct send_autosplit_args;
-typedef void (*send_autosplit_logger_fn) (struct app_context *ctx,
+typedef void (*send_autosplit_logger_fn) (struct server *s,
struct send_autosplit_args *args, struct buffer *buffer, const char *line);
struct send_autosplit_args
@@ -3276,86 +3319,86 @@ struct send_autosplit_args
};
static void
-send_autosplit_message (struct app_context *ctx, struct send_autosplit_args a)
+send_autosplit_message (struct server *s, struct send_autosplit_args a)
{
- struct buffer *buffer = str_map_find (&ctx->irc_buffer_map, a.target);
+ struct buffer *buffer = str_map_find (&s->irc_buffer_map, a.target);
int fixed_part = strlen (a.command) + 1 + strlen (a.target) + 1 + 1
+ strlen (a.prefix) + strlen (a.suffix);
struct str_vector lines;
str_vector_init (&lines);
struct error *e = NULL;
- if (!irc_autosplit_message (ctx, a.message, fixed_part, &lines, &e))
+ if (!irc_autosplit_message (s, a.message, fixed_part, &lines, &e))
{
- buffer_send_error (ctx,
- buffer ? buffer : ctx->server_buffer, "%s", e->message);
+ buffer_send_error (s->ctx,
+ buffer ? buffer : s->buffer, "%s", e->message);
error_free (e);
goto end;
}
for (size_t i = 0; i < lines.len; i++)
{
- irc_send (ctx, "%s %s :%s%s%s", a.command, a.target,
+ irc_send (s, "%s %s :%s%s%s", a.command, a.target,
a.prefix, lines.vector[i], a.suffix);
- a.logger (ctx, &a, buffer, lines.vector[i]);
+ a.logger (s, &a, buffer, lines.vector[i]);
}
end:
str_vector_free (&lines);
}
static void
-log_outcoming_action (struct app_context *ctx,
+log_outcoming_action (struct server *s,
struct send_autosplit_args *a, struct buffer *buffer, const char *line)
{
(void) a;
if (buffer)
- buffer_send (ctx, buffer, BUFFER_LINE_ACTION, 0,
- .who = irc_to_utf8 (ctx, ctx->irc_user->nickname),
- .text = irc_to_utf8 (ctx, line));
+ 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));
// This can only be sent from a user or channel buffer
}
-#define SEND_AUTOSPLIT_ACTION(ctx, target, message) \
- send_autosplit_message ((ctx), (struct send_autosplit_args) \
+#define SEND_AUTOSPLIT_ACTION(s, target, message) \
+ send_autosplit_message ((s), (struct send_autosplit_args) \
{ "PRIVMSG", (target), (message), log_outcoming_action, \
"\x01" "ACTION ", "\x01" })
static void
-log_outcoming_privmsg (struct app_context *ctx,
+log_outcoming_privmsg (struct server *s,
struct send_autosplit_args *a, struct buffer *buffer, const char *line)
{
if (buffer)
- buffer_send (ctx, buffer, BUFFER_LINE_PRIVMSG, 0,
- .who = irc_to_utf8 (ctx, ctx->irc_user->nickname),
- .text = irc_to_utf8 (ctx, line));
+ 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));
else
// TODO: fix logging and encoding
- buffer_send (ctx, ctx->server_buffer, BUFFER_LINE_STATUS, 0,
+ buffer_send (s->ctx, s->buffer, BUFFER_LINE_STATUS, 0,
.text = xstrdup_printf ("MSG(%s): %s", a->target, line));
}
-#define SEND_AUTOSPLIT_PRIVMSG(ctx, target, message) \
- send_autosplit_message ((ctx), (struct send_autosplit_args) \
+#define SEND_AUTOSPLIT_PRIVMSG(s, target, message) \
+ send_autosplit_message ((s), (struct send_autosplit_args) \
{ "PRIVMSG", (target), (message), log_outcoming_privmsg, "", "" })
static void
-log_outcoming_notice (struct app_context *ctx,
+log_outcoming_notice (struct server *s,
struct send_autosplit_args *a, struct buffer *buffer, const char *line)
{
if (buffer)
- buffer_send (ctx, buffer, BUFFER_LINE_NOTICE, 0,
- .who = irc_to_utf8 (ctx, ctx->irc_user->nickname),
- .text = irc_to_utf8 (ctx, line));
+ 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));
else
// TODO: fix logging and encoding
- buffer_send (ctx, ctx->server_buffer, BUFFER_LINE_STATUS, 0,
+ buffer_send (s->ctx, s->buffer, BUFFER_LINE_STATUS, 0,
.text = xstrdup_printf ("Notice -> %s: %s", a->target, line));
}
-#define SEND_AUTOSPLIT_NOTICE(ctx, target, message) \
- send_autosplit_message ((ctx), (struct send_autosplit_args) \
+#define SEND_AUTOSPLIT_NOTICE(s, target, message) \
+ send_autosplit_message ((s), (struct send_autosplit_args) \
{ "NOTICE", (target), (message), log_outcoming_notice, "", "" })
// --- User input handling -----------------------------------------------------
@@ -3406,10 +3449,14 @@ server_command_check (struct app_context *ctx, const char *action)
if (ctx->current_buffer->type == BUFFER_GLOBAL)
buffer_send_error (ctx, ctx->current_buffer,
"Can't do this from a global buffer (%s)", action);
- else if (ctx->irc_fd == -1)
- buffer_send_error (ctx, ctx->server_buffer, "Not connected");
else
- return true;
+ {
+ struct server *s = ctx->current_buffer->server;
+ if (s->irc_fd == -1)
+ buffer_send_error (ctx, s->buffer, "Not connected");
+ else
+ return true;
+ }
return false;
}
@@ -3441,9 +3488,9 @@ handle_buffer_close (struct app_context *ctx, char *arguments)
else if (buffer == ctx->global_buffer)
buffer_send_error (ctx, ctx->global_buffer,
"Can't close the global buffer");
- else if (buffer == ctx->server_buffer)
+ else if (buffer->type == BUFFER_SERVER)
buffer_send_error (ctx, ctx->global_buffer,
- "Can't close the server buffer");
+ "Can't close a server buffer");
else
{
if (buffer == ctx->current_buffer)
@@ -3488,11 +3535,12 @@ handle_command_msg (struct app_context *ctx, char *arguments)
if (!*arguments)
return false;
+ struct server *s = ctx->current_buffer->server;
char *target = cut_word (&arguments);
if (!*arguments)
- buffer_send_error (ctx, ctx->server_buffer, "No text to send");
+ buffer_send_error (ctx, s->buffer, "No text to send");
else
- SEND_AUTOSPLIT_PRIVMSG (ctx, target, arguments);
+ SEND_AUTOSPLIT_PRIVMSG (s, target, arguments);
return true;
}
@@ -3504,15 +3552,16 @@ handle_command_query (struct app_context *ctx, char *arguments)
if (!*arguments)
return false;
+ struct server *s = ctx->current_buffer->server;
char *target = cut_word (&arguments);
- if (irc_is_channel (ctx, target))
- buffer_send_error (ctx, ctx->server_buffer, "Cannot query a channel");
+ if (irc_is_channel (s, target))
+ buffer_send_error (ctx, s->buffer, "Cannot query a channel");
else if (!*arguments)
- buffer_send_error (ctx, ctx->server_buffer, "No text to send");
+ buffer_send_error (ctx, s->buffer, "No text to send");
else
{
- buffer_activate (ctx, irc_get_or_make_user_buffer (ctx, target));
- SEND_AUTOSPLIT_PRIVMSG (ctx, target, arguments);
+ buffer_activate (ctx, irc_get_or_make_user_buffer (s, target));
+ SEND_AUTOSPLIT_PRIVMSG (s, target, arguments);
}
return true;
}
@@ -3525,11 +3574,12 @@ handle_command_notice (struct app_context *ctx, char *arguments)
if (!*arguments)
return false;
+ struct server *s = ctx->current_buffer->server;
char *target = cut_word (&arguments);
if (!*arguments)
- buffer_send_error (ctx, ctx->server_buffer, "No text to send");
+ buffer_send_error (ctx, s->buffer, "No text to send");
else
- SEND_AUTOSPLIT_NOTICE (ctx, target, arguments);
+ SEND_AUTOSPLIT_NOTICE (s, target, arguments);
return true;
}
@@ -3549,12 +3599,13 @@ handle_command_ctcp (struct app_context *ctx, char *arguments)
for (char *p = tag; *p; p++)
*p = toupper_ascii (*p);
+ struct server *s = ctx->current_buffer->server;
if (*arguments)
- irc_send (ctx, "PRIVMSG %s :\x01%s %s\x01", target, tag, arguments);
+ irc_send (s, "PRIVMSG %s :\x01%s %s\x01", target, tag, arguments);
else
- irc_send (ctx, "PRIVMSG %s :\x01%s\x01", target, tag);
+ irc_send (s, "PRIVMSG %s :\x01%s\x01", target, tag);
- buffer_send_status (ctx, ctx->server_buffer,
+ buffer_send_status (ctx, s->buffer,
"CTCP query to %s: %s", target, tag);
return true;
}
@@ -3565,14 +3616,15 @@ handle_command_me (struct app_context *ctx, char *arguments)
if (!server_command_check (ctx, "send messages"))
return true;
+ struct server *s = ctx->current_buffer->server;
if (ctx->current_buffer->type == BUFFER_CHANNEL)
- SEND_AUTOSPLIT_ACTION (ctx,
+ SEND_AUTOSPLIT_ACTION (s,
ctx->current_buffer->channel->name, arguments);
else if (ctx->current_buffer->type == BUFFER_PM)
- SEND_AUTOSPLIT_ACTION (ctx,
+ SEND_AUTOSPLIT_ACTION (s,
ctx->current_buffer->user->nickname, arguments);
else
- buffer_send_error (ctx, ctx->server_buffer,
+ buffer_send_error (ctx, s->buffer,
"Can't do this from a server buffer (%s)",
"send CTCP actions");
return true;
@@ -3581,12 +3633,14 @@ handle_command_me (struct app_context *ctx, char *arguments)
static bool
handle_command_quit (struct app_context *ctx, char *arguments)
{
- if (ctx->irc_fd != -1)
+ // TODO: multiserver
+ struct server *s = &ctx->server;
+ if (s->irc_fd != -1)
{
if (*arguments)
- irc_send (ctx, "QUIT :%s", arguments);
+ irc_send (s, "QUIT :%s", arguments);
else
- irc_send (ctx, "QUIT :%s", PROGRAM_NAME " " PROGRAM_VERSION);
+ irc_send (s, "QUIT :%s", PROGRAM_NAME " " PROGRAM_VERSION);
}
initiate_quit (ctx);
return true;
@@ -3598,10 +3652,11 @@ handle_command_join (struct app_context *ctx, char *arguments)
if (!server_command_check (ctx, "join"))
return true;
+ struct server *s = ctx->current_buffer->server;
if (*arguments)
// TODO: check if the arguments are in the form of
// "channel(,channel)* key(,key)*"
- irc_send (ctx, "JOIN %s", arguments);
+ irc_send (s, "JOIN %s", arguments);
else
{
if (ctx->current_buffer->type != BUFFER_CHANNEL)
@@ -3615,7 +3670,7 @@ handle_command_join (struct app_context *ctx, char *arguments)
"you already are on the channel");
else
// TODO: send the key if known
- irc_send (ctx, "JOIN %s", ctx->current_buffer->channel->name);
+ irc_send (s, "JOIN %s", ctx->current_buffer->channel->name);
}
return true;
}
@@ -3626,10 +3681,11 @@ handle_command_part (struct app_context *ctx, char *arguments)
if (!server_command_check (ctx, "part"))
return true;
+ struct server *s = ctx->current_buffer->server;
if (*arguments)
// TODO: check if the arguments are in the form of "channel(,channel)*"
// TODO: make sure to send the reason as one argument
- irc_send (ctx, "PART %s", arguments);
+ irc_send (s, "PART %s", arguments);
else
{
if (ctx->current_buffer->type != BUFFER_CHANNEL)
@@ -3641,7 +3697,7 @@ handle_command_part (struct app_context *ctx, char *arguments)
buffer_send_error (ctx, ctx->current_buffer,
"%s: %s", "Can't join", "you're not on the channel");
else
- irc_send (ctx, "PART %s", ctx->current_buffer->channel->name);
+ irc_send (s, "PART %s", ctx->current_buffer->channel->name);
}
return true;
}
@@ -3652,10 +3708,11 @@ handle_command_list (struct app_context *ctx, char *arguments)
if (!server_command_check (ctx, "list channels"))
return true;
+ struct server *s = ctx->current_buffer->server;
if (*arguments)
- irc_send (ctx, "LIST %s", arguments);
+ irc_send (s, "LIST %s", arguments);
else
- irc_send (ctx, "LIST");
+ irc_send (s, "LIST");
return true;
}
@@ -3667,7 +3724,8 @@ handle_command_nick (struct app_context *ctx, char *arguments)
if (!*arguments)
return false;
- irc_send (ctx, "NICK %s", cut_word (&arguments));
+ struct server *s = ctx->current_buffer->server;
+ irc_send (s, "NICK %s", cut_word (&arguments));
return true;
}
@@ -3677,7 +3735,8 @@ handle_command_quote (struct app_context *ctx, char *arguments)
if (!server_command_check (ctx, "quote"))
return true;
- irc_send (ctx, "%s", arguments);
+ struct server *s = ctx->current_buffer->server;
+ irc_send (s, "%s", arguments);
return true;
}
@@ -3834,16 +3893,16 @@ process_user_command (struct app_context *ctx, char *command)
}
static void
-send_message_to_target (struct app_context *ctx,
+send_message_to_target (struct server *s,
const char *target, char *message, struct buffer *buffer)
{
- if (ctx->irc_fd == -1)
+ if (s->irc_fd == -1)
{
- buffer_send_error (ctx, buffer, "Not connected");
+ buffer_send_error (s->ctx, buffer, "Not connected");
return;
}
- SEND_AUTOSPLIT_PRIVMSG (ctx, target, message);
+ SEND_AUTOSPLIT_PRIVMSG (s, target, message);
}
static void
@@ -3859,10 +3918,12 @@ send_message_to_current_buffer (struct app_context *ctx, char *message)
buffer_send_error (ctx, buffer, "This buffer is not a channel");
break;
case BUFFER_CHANNEL:
- send_message_to_target (ctx, buffer->channel->name, message, buffer);
+ send_message_to_target (buffer->server,
+ buffer->channel->name, message, buffer);
break;
case BUFFER_PM:
- send_message_to_target (ctx, buffer->user->nickname, message, buffer);
+ send_message_to_target (buffer->server,
+ buffer->user->nickname, message, buffer);
break;
}
}
@@ -3896,15 +3957,15 @@ enum irc_read_result
};
static enum irc_read_result
-irc_fill_read_buffer_ssl (struct app_context *ctx, struct str *buf)
+irc_fill_read_buffer_ssl (struct server *s, struct str *buf)
{
int n_read;
start:
- n_read = SSL_read (ctx->ssl, buf->str + buf->len,
+ n_read = SSL_read (s->ssl, buf->str + buf->len,
buf->alloc - buf->len - 1 /* null byte */);
const char *error_info = NULL;
- switch (xssl_get_error (ctx->ssl, n_read, &error_info))
+ switch (xssl_get_error (s->ssl, n_read, &error_info))
{
case SSL_ERROR_NONE:
buf->str[buf->len += n_read] = '\0';
@@ -3917,7 +3978,7 @@ start:
{
// Let it finish the handshake as we don't poll for writability;
// any errors are to be collected by SSL_read() in the next iteration
- struct pollfd pfd = { .fd = ctx->irc_fd, .events = POLLOUT };
+ struct pollfd pfd = { .fd = s->irc_fd, .events = POLLOUT };
soft_assert (poll (&pfd, 1, 0) > 0);
goto start;
}
@@ -3930,11 +3991,11 @@ start:
}
static enum irc_read_result
-irc_fill_read_buffer (struct app_context *ctx, struct str *buf)
+irc_fill_read_buffer (struct server *s, struct str *buf)
{
ssize_t n_read;
start:
- n_read = recv (ctx->irc_fd, buf->str + buf->len,
+ n_read = recv (s->irc_fd, buf->str + buf->len,
buf->alloc - buf->len - 1 /* null byte */, 0);
if (n_read > 0)
@@ -3954,133 +4015,134 @@ start:
return IRC_READ_ERROR;
}
-static bool irc_connect (struct app_context *, struct error **);
-static void irc_queue_reconnect (struct app_context *);
+static bool irc_connect (struct server *s, struct error **);
+static void irc_queue_reconnect (struct server *s);
static void
-irc_cancel_timers (struct app_context *ctx)
+irc_cancel_timers (struct server *s)
{
- poller_timer_reset (&ctx->timeout_tmr);
- poller_timer_reset (&ctx->ping_tmr);
- poller_timer_reset (&ctx->reconnect_tmr);
+ poller_timer_reset (&s->timeout_tmr);
+ poller_timer_reset (&s->ping_tmr);
+ poller_timer_reset (&s->reconnect_tmr);
}
static void
on_irc_reconnect_timeout (void *user_data)
{
- struct app_context *ctx = user_data;
+ struct server *s = user_data;
struct error *e = NULL;
- if (irc_connect (ctx, &e))
+ if (irc_connect (s, &e))
return;
- buffer_send_error (ctx, ctx->server_buffer, "%s", e->message);
+ buffer_send_error (s->ctx, s->buffer, "%s", e->message);
error_free (e);
- irc_queue_reconnect (ctx);
+ irc_queue_reconnect (s);
}
static void
-irc_queue_reconnect (struct app_context *ctx)
+irc_queue_reconnect (struct server *s)
{
// TODO: exponentional backoff
- hard_assert (ctx->irc_fd == -1);
- buffer_send_status (ctx, ctx->server_buffer,
- "Trying to reconnect in %ld seconds...", ctx->reconnect_delay);
- poller_timer_set (&ctx->reconnect_tmr, ctx->reconnect_delay * 1000);
+ hard_assert (s->irc_fd == -1);
+ buffer_send_status (s->ctx, s->buffer,
+ "Trying to reconnect in %ld seconds...", s->ctx->reconnect_delay);
+ poller_timer_set (&s->reconnect_tmr, s->ctx->reconnect_delay * 1000);
}
static void
-on_irc_disconnected (struct app_context *ctx)
+on_irc_disconnected (struct server *s)
{
// Get rid of the dead socket and related things
- if (ctx->ssl)
+ if (s->ssl)
{
- SSL_free (ctx->ssl);
- ctx->ssl = NULL;
- SSL_CTX_free (ctx->ssl_ctx);
- ctx->ssl_ctx = NULL;
+ SSL_free (s->ssl);
+ s->ssl = NULL;
+ SSL_CTX_free (s->ssl_ctx);
+ s->ssl_ctx = NULL;
}
- xclose (ctx->irc_fd);
- ctx->irc_fd = -1;
- ctx->irc_ready = false;
+ xclose (s->irc_fd);
+ s->irc_fd = -1;
+ s->irc_ready = false;
- user_unref (ctx->irc_user);
- ctx->irc_user = NULL;
+ user_unref (s->irc_user);
+ s->irc_user = NULL;
- free (ctx->irc_user_mode);
- ctx->irc_user_mode = NULL;
- free (ctx->irc_user_host);
- ctx->irc_user_host = NULL;
+ free (s->irc_user_mode);
+ s->irc_user_mode = NULL;
+ free (s->irc_user_host);
+ s->irc_user_host = NULL;
- ctx->irc_event.closed = true;
- poller_fd_reset (&ctx->irc_event);
+ s->irc_event.closed = true;
+ poller_fd_reset (&s->irc_event);
// All of our timers have lost their meaning now
- irc_cancel_timers (ctx);
+ irc_cancel_timers (s);
- if (ctx->quitting)
- try_finish_quit (ctx);
- else if (!ctx->reconnect)
+ if (s->ctx->quitting)
+ try_finish_quit (s->ctx);
+ else if (!s->ctx->reconnect)
// XXX: not sure if we want this in a client
- initiate_quit (ctx);
+ // FIXME: no, we don't, would need to be changed for multiserver anyway
+ initiate_quit (s->ctx);
else
- irc_queue_reconnect (ctx);
+ irc_queue_reconnect (s);
}
static void
on_irc_ping_timeout (void *user_data)
{
- struct app_context *ctx = user_data;
- buffer_send_error (ctx, ctx->server_buffer, "Connection timeout");
- on_irc_disconnected (ctx);
+ struct server *s = user_data;
+ buffer_send_error (s->ctx, s->buffer, "Connection timeout");
+ on_irc_disconnected (s);
}
static void
on_irc_timeout (void *user_data)
{
// Provoke a response from the server
- struct app_context *ctx = user_data;
- irc_send (ctx, "PING :%s",
- (char *) str_map_find (&ctx->config, "nickname"));
+ struct server *s = user_data;
+ irc_send (s, "PING :%s",
+ (char *) str_map_find (&s->ctx->config, "nickname"));
}
static void
-irc_reset_connection_timeouts (struct app_context *ctx)
+irc_reset_connection_timeouts (struct server *s)
{
- irc_cancel_timers (ctx);
- poller_timer_set (&ctx->timeout_tmr, 3 * 60 * 1000);
- poller_timer_set (&ctx->ping_tmr, (3 * 60 + 30) * 1000);
+ irc_cancel_timers (s);
+ poller_timer_set (&s->timeout_tmr, 3 * 60 * 1000);
+ poller_timer_set (&s->ping_tmr, (3 * 60 + 30) * 1000);
}
static void
-on_irc_readable (const struct pollfd *fd, struct app_context *ctx)
+on_irc_readable (const struct pollfd *fd, struct server *s)
{
if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
- (void) set_blocking (ctx->irc_fd, false);
+ (void) set_blocking (s->irc_fd, false);
- struct str *buf = &ctx->read_buffer;
- enum irc_read_result (*fill_buffer)(struct app_context *, struct str *)
- = ctx->ssl
+ struct str *buf = &s->read_buffer;
+ enum irc_read_result (*fill_buffer)(struct server *, struct str *)
+ = s->ssl
? irc_fill_read_buffer_ssl
: irc_fill_read_buffer;
bool disconnected = false;
while (true)
{
str_ensure_space (buf, 512);
- switch (fill_buffer (ctx, buf))
+ switch (fill_buffer (s, buf))
{
case IRC_READ_AGAIN:
goto end;
case IRC_READ_ERROR:
- buffer_send_error (ctx, ctx->server_buffer,
+ buffer_send_error (s->ctx, s->buffer,
"Reading from the IRC server failed");
disconnected = true;
goto end;
case IRC_READ_EOF:
- buffer_send_error (ctx, ctx->server_buffer,
+ buffer_send_error (s->ctx, s->buffer,
"The IRC server closed the connection");
disconnected = true;
goto end;
@@ -4090,25 +4152,27 @@ on_irc_readable (const struct pollfd *fd, struct app_context *ctx)
if (buf->len >= (1 << 20))
{
- buffer_send_error (ctx, ctx->server_buffer,
+ buffer_send_error (s->ctx, s->buffer,
"The IRC server seems to spew out data frantically");
- irc_shutdown (ctx);
+ irc_shutdown (s);
goto end;
}
}
end:
- (void) set_blocking (ctx->irc_fd, true);
- irc_process_buffer (buf, irc_process_message, ctx);
+ (void) set_blocking (s->irc_fd, true);
+ irc_process_buffer (buf, irc_process_message, s);
if (disconnected)
- on_irc_disconnected (ctx);
+ on_irc_disconnected (s);
else
- irc_reset_connection_timeouts (ctx);
+ irc_reset_connection_timeouts (s);
}
static bool
-irc_connect (struct app_context *ctx, struct error **e)
+irc_connect (struct server *s, struct error **e)
{
+ struct app_context *ctx = s->ctx;
+
const char *irc_host = str_map_find (&ctx->config, "irc_host");
const char *irc_port = str_map_find (&ctx->config, "irc_port");
@@ -4137,7 +4201,7 @@ irc_connect (struct app_context *ctx, struct error **e)
{
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, ctx->server_buffer,
+ buffer_send_status (ctx, s->buffer,
"Connecting to %s via %s...", address, socks_address);
free (socks_address);
free (address);
@@ -4151,36 +4215,36 @@ irc_connect (struct app_context *ctx, struct error **e)
error_free (error);
return false;
}
- ctx->irc_fd = fd;
+ s->irc_fd = fd;
}
- else if (!irc_establish_connection (ctx, irc_host, irc_port, e))
+ else if (!irc_establish_connection (s, irc_host, irc_port, e))
return false;
- if (use_ssl && !irc_initialize_ssl (ctx, e))
+ if (use_ssl && !irc_initialize_ssl (s, e))
{
- xclose (ctx->irc_fd);
- ctx->irc_fd = -1;
+ xclose (s->irc_fd);
+ s->irc_fd = -1;
return false;
}
- buffer_send_status (ctx, ctx->server_buffer, "Connection established");
+ buffer_send_status (ctx, s->buffer, "Connection established");
- poller_fd_init (&ctx->irc_event, &ctx->poller, ctx->irc_fd);
- ctx->irc_event.dispatcher = (poller_fd_fn) on_irc_readable;
- ctx->irc_event.user_data = ctx;
+ poller_fd_init (&s->irc_event, &ctx->poller, s->irc_fd);
+ s->irc_event.dispatcher = (poller_fd_fn) on_irc_readable;
+ s->irc_event.user_data = s;
- poller_fd_set (&ctx->irc_event, POLLIN);
- irc_reset_connection_timeouts (ctx);
+ poller_fd_set (&s->irc_event, POLLIN);
+ irc_reset_connection_timeouts (s);
- irc_send (ctx, "NICK %s", nickname);
- irc_send (ctx, "USER %s 8 * :%s", username, realname);
+ irc_send (s, "NICK %s", nickname);
+ irc_send (s, "USER %s 8 * :%s", username, realname);
// XXX: maybe we should wait for the first message from the server
// FIXME: the user may exist already after we've reconnected. Either
// make sure that there's no reference of this nick upon disconnection,
// or search in "irc_users" first... or something.
- ctx->irc_user = irc_make_user (ctx, xstrdup (nickname));
- ctx->irc_user_mode = xstrdup ("");
- ctx->irc_user_host = NULL;
+ s->irc_user = irc_make_user (s, xstrdup (nickname));
+ s->irc_user_mode = xstrdup ("");
+ s->irc_user_host = NULL;
return true;
}
@@ -4195,10 +4259,14 @@ on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
if (g_termination_requested && !ctx->quitting)
{
// There may be a timer set to reconnect to the server
- irc_cancel_timers (ctx);
-
- if (ctx->irc_fd != -1)
- irc_send (ctx, "QUIT :Terminated by signal");
+ // TODO: multiserver
+ struct server *s = &ctx->server;
+ // TODO: a faster timer for quitting
+ irc_reset_connection_timeouts (s);
+
+ // FIXME: use a normal quit message
+ if (s->irc_fd != -1)
+ irc_send (s, "QUIT :Terminated by signal");
initiate_quit (ctx);
}
@@ -4455,18 +4523,6 @@ load_config (struct app_context *ctx, struct error **e)
static void
init_poller_events (struct app_context *ctx)
{
- poller_timer_init (&ctx->timeout_tmr, &ctx->poller);
- ctx->timeout_tmr.dispatcher = on_irc_timeout;
- ctx->timeout_tmr.user_data = ctx;
-
- poller_timer_init (&ctx->ping_tmr, &ctx->poller);
- ctx->ping_tmr.dispatcher = on_irc_ping_timeout;
- ctx->ping_tmr.user_data = ctx;
-
- poller_timer_init (&ctx->reconnect_tmr, &ctx->poller);
- ctx->reconnect_tmr.dispatcher = on_irc_reconnect_timeout;
- ctx->reconnect_tmr.user_data = ctx;
-
poller_fd_init (&ctx->signal_event, &ctx->poller, g_signal_pipe[0]);
ctx->signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable;
ctx->signal_event.user_data = ctx;
@@ -4554,13 +4610,13 @@ main (int argc, char *argv[])
init_colors (&ctx);
init_poller_events (&ctx);
init_buffers (&ctx);
- ctx.current_buffer = ctx.server_buffer;
+ ctx.current_buffer = ctx.server.buffer;
refresh_prompt (&ctx);
// TODO: connect asynchronously (first step towards multiple servers)
- if (!irc_connect (&ctx, &e))
+ if (!irc_connect (&ctx.server, &e))
{
- buffer_send_error (&ctx, ctx.server_buffer, "%s", e->message);
+ buffer_send_error (&ctx, ctx.server.buffer, "%s", e->message);
error_free (e);
exit (EXIT_FAILURE);
}
--
cgit v1.2.3-70-g09d2