parent
bedbadd396
commit
ca8540e217
288
degesch.c
288
degesch.c
|
@ -1013,10 +1013,18 @@ struct server
|
||||||
{
|
{
|
||||||
struct app_context *ctx; ///< Application context
|
struct app_context *ctx; ///< Application context
|
||||||
|
|
||||||
|
char *name; ///< Server identifier
|
||||||
|
struct buffer *buffer; ///< The buffer for this server
|
||||||
|
|
||||||
|
// Configuration:
|
||||||
|
|
||||||
|
struct config_item_ *config; ///< Configuration root
|
||||||
bool reconnect; ///< Whether to reconnect on conn. fail.
|
bool reconnect; ///< Whether to reconnect on conn. fail.
|
||||||
unsigned long reconnect_delay; ///< Reconnect delay in seconds
|
unsigned long reconnect_delay; ///< Reconnect delay in seconds
|
||||||
bool manual_disconnect; ///< Don't reconnect
|
bool manual_disconnect; ///< Don't reconnect
|
||||||
|
|
||||||
|
// Connection:
|
||||||
|
|
||||||
enum server_state state; ///< Connection state
|
enum server_state state; ///< Connection state
|
||||||
struct connector *connector; ///< Connection establisher
|
struct connector *connector; ///< Connection establisher
|
||||||
|
|
||||||
|
@ -1030,8 +1038,7 @@ struct server
|
||||||
// TODO: an output queue to prevent excess floods (this will be needed
|
// TODO: an output queue to prevent excess floods (this will be needed
|
||||||
// especially for away status polling)
|
// especially for away status polling)
|
||||||
|
|
||||||
char *name; ///< Server identifier
|
// IRC:
|
||||||
struct buffer *buffer; ///< The buffer for this server
|
|
||||||
|
|
||||||
struct str_map irc_users; ///< IRC user data
|
struct str_map irc_users; ///< IRC user data
|
||||||
struct str_map irc_channels; ///< IRC channel data
|
struct str_map irc_channels; ///< IRC channel data
|
||||||
|
@ -1055,6 +1062,8 @@ static void irc_initiate_connect (struct server *s);
|
||||||
static void
|
static void
|
||||||
server_init (struct server *self, struct poller *poller)
|
server_init (struct server *self, struct poller *poller)
|
||||||
{
|
{
|
||||||
|
memset (self, 0, sizeof *self);
|
||||||
|
|
||||||
self->socket = -1;
|
self->socket = -1;
|
||||||
str_init (&self->read_buffer);
|
str_init (&self->read_buffer);
|
||||||
self->state = IRC_DISCONNECTED;
|
self->state = IRC_DISCONNECTED;
|
||||||
|
@ -1111,6 +1120,13 @@ server_free (struct server *self)
|
||||||
str_map_free (&self->irc_buffer_map);
|
str_map_free (&self->irc_buffer_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
server_destroy (void *self)
|
||||||
|
{
|
||||||
|
server_free (self);
|
||||||
|
free (self);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
struct app_context
|
struct app_context
|
||||||
|
@ -1122,7 +1138,7 @@ struct app_context
|
||||||
bool no_colors; ///< Colour output mode
|
bool no_colors; ///< Colour output mode
|
||||||
bool isolate_buffers; ///< Isolate global/server buffers
|
bool isolate_buffers; ///< Isolate global/server buffers
|
||||||
|
|
||||||
struct server server; ///< Our only server so far
|
struct str_map servers; ///< Our servers
|
||||||
|
|
||||||
// Events:
|
// Events:
|
||||||
|
|
||||||
|
@ -1138,14 +1154,13 @@ struct app_context
|
||||||
struct buffer *buffers; ///< All our buffers in order
|
struct buffer *buffers; ///< All our buffers in order
|
||||||
struct buffer *buffers_tail; ///< The tail of our buffers
|
struct buffer *buffers_tail; ///< The tail of our buffers
|
||||||
|
|
||||||
|
struct buffer *global_buffer; ///< The global buffer
|
||||||
|
struct buffer *current_buffer; ///< The current buffer
|
||||||
struct buffer *last_buffer; ///< Last used buffer
|
struct buffer *last_buffer; ///< Last used buffer
|
||||||
|
|
||||||
// TODO: make buffer names fully unique like weechat does
|
// TODO: make buffer names fully unique like weechat does
|
||||||
struct str_map buffers_by_name; ///< Buffers by name
|
struct str_map buffers_by_name; ///< Buffers by name
|
||||||
|
|
||||||
struct buffer *global_buffer; ///< The global buffer
|
|
||||||
struct buffer *current_buffer; ///< The current buffer
|
|
||||||
|
|
||||||
// TODO: So that we always output proper date change messages
|
// TODO: So that we always output proper date change messages
|
||||||
time_t last_displayed_msg_time; ///< Time of last displayed message
|
time_t last_displayed_msg_time; ///< Time of last displayed message
|
||||||
|
|
||||||
|
@ -1171,9 +1186,9 @@ app_context_init (struct app_context *self)
|
||||||
config_init (&self->config);
|
config_init (&self->config);
|
||||||
poller_init (&self->poller);
|
poller_init (&self->poller);
|
||||||
|
|
||||||
server_init (&self->server, &self->poller);
|
str_map_init (&self->servers);
|
||||||
self->server.ctx = self;
|
self->servers.free = server_destroy;
|
||||||
self->server.name = xstrdup ("server");
|
self->servers.key_xfrm = irc_strxfrm;
|
||||||
|
|
||||||
str_map_init (&self->buffers_by_name);
|
str_map_init (&self->buffers_by_name);
|
||||||
self->buffers_by_name.key_xfrm = irc_strxfrm;
|
self->buffers_by_name.key_xfrm = irc_strxfrm;
|
||||||
|
@ -1213,7 +1228,7 @@ app_context_free (struct app_context *self)
|
||||||
buffer_destroy (iter);
|
buffer_destroy (iter);
|
||||||
str_map_free (&self->buffers_by_name);
|
str_map_free (&self->buffers_by_name);
|
||||||
|
|
||||||
server_free (&self->server);
|
str_map_free (&self->servers);
|
||||||
poller_free (&self->poller);
|
poller_free (&self->poller);
|
||||||
|
|
||||||
iconv_close (self->latin1_to_utf8);
|
iconv_close (self->latin1_to_utf8);
|
||||||
|
@ -1415,9 +1430,9 @@ register_config_modules (struct app_context *ctx)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
get_config_string (struct app_context *ctx, const char *key)
|
get_config_string (struct config_item_ *root, const char *key)
|
||||||
{
|
{
|
||||||
struct config_item_ *item = config_item_get (ctx->config.root, key, NULL);
|
struct config_item_ *item = config_item_get (root, key, NULL);
|
||||||
hard_assert (item);
|
hard_assert (item);
|
||||||
if (item->type == CONFIG_ITEM_NULL)
|
if (item->type == CONFIG_ITEM_NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1426,9 +1441,10 @@ get_config_string (struct app_context *ctx, const char *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
set_config_string (struct app_context *ctx, const char *key, const char *value)
|
set_config_string
|
||||||
|
(struct config_item_ *root, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
struct config_item_ *item = config_item_get (ctx->config.root, key, NULL);
|
struct config_item_ *item = config_item_get (root, key, NULL);
|
||||||
hard_assert (item);
|
hard_assert (item);
|
||||||
|
|
||||||
struct str s;
|
struct str s;
|
||||||
|
@ -1448,17 +1464,17 @@ set_config_string (struct app_context *ctx, const char *key, const char *value)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
static int64_t
|
||||||
get_config_integer (struct app_context *ctx, const char *key)
|
get_config_integer (struct config_item_ *root, const char *key)
|
||||||
{
|
{
|
||||||
struct config_item_ *item = config_item_get (ctx->config.root, key, NULL);
|
struct config_item_ *item = config_item_get (root, key, NULL);
|
||||||
hard_assert (item && item->type == CONFIG_ITEM_INTEGER);
|
hard_assert (item && item->type == CONFIG_ITEM_INTEGER);
|
||||||
return item->value.integer;
|
return item->value.integer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
get_config_boolean (struct app_context *ctx, const char *key)
|
get_config_boolean (struct config_item_ *root, const char *key)
|
||||||
{
|
{
|
||||||
struct config_item_ *item = config_item_get (ctx->config.root, key, NULL);
|
struct config_item_ *item = config_item_get (root, key, NULL);
|
||||||
hard_assert (item && item->type == CONFIG_ITEM_BOOLEAN);
|
hard_assert (item && item->type == CONFIG_ITEM_BOOLEAN);
|
||||||
return item->value.boolean;
|
return item->value.boolean;
|
||||||
}
|
}
|
||||||
|
@ -1687,7 +1703,7 @@ init_attribute (struct app_context *ctx, int id, const char *default_)
|
||||||
#undef XX
|
#undef XX
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *user = get_config_string (ctx, table[id]);
|
const char *user = get_config_string (ctx->config.root, table[id]);
|
||||||
if (user)
|
if (user)
|
||||||
ctx->attrs[id] = xstrdup (user);
|
ctx->attrs[id] = xstrdup (user);
|
||||||
else
|
else
|
||||||
|
@ -2483,19 +2499,19 @@ buffer_remove (struct app_context *ctx, struct buffer *buffer)
|
||||||
if (buffer->user)
|
if (buffer->user)
|
||||||
str_map_set (&s->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);
|
|
||||||
buffer_destroy (buffer);
|
|
||||||
|
|
||||||
if (buffer == ctx->last_buffer)
|
|
||||||
ctx->last_buffer = NULL;
|
|
||||||
|
|
||||||
// It's not a good idea to remove these buffers, but it's even a worse
|
// It's not a good idea to remove these buffers, but it's even a worse
|
||||||
// one to leave the pointers point to invalid memory
|
// one to leave the pointers point to invalid memory
|
||||||
if (buffer == ctx->global_buffer)
|
if (buffer == ctx->global_buffer)
|
||||||
ctx->global_buffer = NULL;
|
ctx->global_buffer = NULL;
|
||||||
if (buffer == ctx->server.buffer)
|
if (buffer->type == BUFFER_SERVER)
|
||||||
ctx->server.buffer = NULL;
|
buffer->server->buffer = NULL;
|
||||||
|
|
||||||
|
if (buffer == ctx->last_buffer)
|
||||||
|
ctx->last_buffer = NULL;
|
||||||
|
|
||||||
|
str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
|
||||||
|
LIST_UNLINK_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
|
||||||
|
buffer_destroy (buffer);
|
||||||
|
|
||||||
refresh_prompt (ctx);
|
refresh_prompt (ctx);
|
||||||
}
|
}
|
||||||
|
@ -2635,19 +2651,11 @@ buffer_get_index (struct app_context *ctx, struct buffer *buffer)
|
||||||
static void
|
static void
|
||||||
init_buffers (struct app_context *ctx)
|
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 *global = ctx->global_buffer = buffer_new ();
|
||||||
struct buffer *server = ctx->server.buffer = buffer_new ();
|
|
||||||
|
|
||||||
global->type = BUFFER_GLOBAL;
|
global->type = BUFFER_GLOBAL;
|
||||||
global->name = xstrdup (PROGRAM_NAME);
|
global->name = xstrdup (PROGRAM_NAME);
|
||||||
|
|
||||||
server->type = BUFFER_SERVER;
|
|
||||||
server->name = xstrdup ("server");
|
|
||||||
server->server = &ctx->server;
|
|
||||||
|
|
||||||
buffer_add (ctx, global);
|
buffer_add (ctx, global);
|
||||||
buffer_add (ctx, server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Users, channels ---------------------------------------------------------
|
// --- Users, channels ---------------------------------------------------------
|
||||||
|
@ -2811,12 +2819,12 @@ irc_initialize_ssl_ctx (struct server *s, struct error **e)
|
||||||
{
|
{
|
||||||
// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
|
// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
|
||||||
|
|
||||||
bool verify = get_config_boolean (s->ctx, "server.ssl_verify");
|
bool verify = get_config_boolean (s->config, "ssl_verify");
|
||||||
if (!verify)
|
if (!verify)
|
||||||
SSL_CTX_set_verify (s->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
SSL_CTX_set_verify (s->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||||
|
|
||||||
const char *ca_file = get_config_string (s->ctx, "server.ca_file");
|
const char *ca_file = get_config_string (s->config, "ssl_ca_file");
|
||||||
const char *ca_path = get_config_string (s->ctx, "server.ca_path");
|
const char *ca_path = get_config_string (s->config, "ssl_ca_path");
|
||||||
|
|
||||||
struct error *error = NULL;
|
struct error *error = NULL;
|
||||||
if (ca_file || ca_path)
|
if (ca_file || ca_path)
|
||||||
|
@ -2866,7 +2874,7 @@ irc_initialize_ssl (struct server *s, struct error **e)
|
||||||
if (!s->ssl)
|
if (!s->ssl)
|
||||||
goto error_ssl_2;
|
goto error_ssl_2;
|
||||||
|
|
||||||
const char *ssl_cert = get_config_string (s->ctx, "server.ssl_cert");
|
const char *ssl_cert = get_config_string (s->config, "ssl_cert");
|
||||||
if (ssl_cert)
|
if (ssl_cert)
|
||||||
{
|
{
|
||||||
char *path = resolve_config_filename (ssl_cert);
|
char *path = resolve_config_filename (ssl_cert);
|
||||||
|
@ -3011,8 +3019,19 @@ irc_destroy_connector (struct server *s)
|
||||||
static void
|
static void
|
||||||
try_finish_quit (struct app_context *ctx)
|
try_finish_quit (struct app_context *ctx)
|
||||||
{
|
{
|
||||||
// TODO: multiserver
|
if (!ctx->quitting)
|
||||||
if (ctx->quitting && !irc_is_connected (&ctx->server))
|
return;
|
||||||
|
|
||||||
|
struct str_map_iter iter;
|
||||||
|
str_map_iter_init (&iter, &ctx->servers);
|
||||||
|
|
||||||
|
bool disconnected_all = true;
|
||||||
|
struct server *s;
|
||||||
|
while ((s = str_map_iter_next (&iter)))
|
||||||
|
if (irc_is_connected (s))
|
||||||
|
disconnected_all = false;
|
||||||
|
|
||||||
|
if (disconnected_all)
|
||||||
ctx->polling = false;
|
ctx->polling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3025,13 +3044,18 @@ initiate_quit (struct app_context *ctx)
|
||||||
buffer_send_status (ctx, ctx->global_buffer, "Shutting down");
|
buffer_send_status (ctx, ctx->global_buffer, "Shutting down");
|
||||||
|
|
||||||
// Initiate a connection close
|
// Initiate a connection close
|
||||||
// TODO: multiserver
|
struct str_map_iter iter;
|
||||||
struct server *s = &ctx->server;
|
str_map_iter_init (&iter, &ctx->servers);
|
||||||
if (irc_is_connected (s))
|
|
||||||
// XXX: when we go async, we'll have to flush output buffers first
|
struct server *s;
|
||||||
irc_shutdown (s);
|
while ((s = str_map_iter_next (&iter)))
|
||||||
else if (s->state == IRC_CONNECTING)
|
{
|
||||||
irc_destroy_connector (s);
|
if (irc_is_connected (s))
|
||||||
|
// XXX: when we go async, we'll have to flush output buffers first
|
||||||
|
irc_shutdown (s);
|
||||||
|
else if (s->state == IRC_CONNECTING)
|
||||||
|
irc_destroy_connector (s);
|
||||||
|
}
|
||||||
|
|
||||||
ctx->quitting = true;
|
ctx->quitting = true;
|
||||||
try_finish_quit (ctx);
|
try_finish_quit (ctx);
|
||||||
|
@ -3248,9 +3272,9 @@ end:
|
||||||
static void
|
static void
|
||||||
irc_register (struct server *s)
|
irc_register (struct server *s)
|
||||||
{
|
{
|
||||||
const char *nickname = get_config_string (s->ctx, "server.nickname");
|
const char *nickname = get_config_string (s->config, "nickname");
|
||||||
const char *username = get_config_string (s->ctx, "server.username");
|
const char *username = get_config_string (s->config, "username");
|
||||||
const char *realname = get_config_string (s->ctx, "server.realname");
|
const char *realname = get_config_string (s->config, "realname");
|
||||||
|
|
||||||
// These are filled automatically if needed
|
// These are filled automatically if needed
|
||||||
hard_assert (nickname && username && realname);
|
hard_assert (nickname && username && realname);
|
||||||
|
@ -3268,7 +3292,7 @@ irc_finish_connection (struct server *s, int socket)
|
||||||
s->socket = socket;
|
s->socket = socket;
|
||||||
|
|
||||||
struct error *e = NULL;
|
struct error *e = NULL;
|
||||||
bool use_ssl = get_config_boolean (ctx, "server.ssl");
|
bool use_ssl = get_config_boolean (s->config, "ssl");
|
||||||
if (use_ssl && !irc_initialize_ssl (s, &e))
|
if (use_ssl && !irc_initialize_ssl (s, &e))
|
||||||
{
|
{
|
||||||
buffer_send_error (ctx, s->buffer, "Connection failed: %s", e->message);
|
buffer_send_error (ctx, s->buffer, "Connection failed: %s", e->message);
|
||||||
|
@ -3378,13 +3402,13 @@ irc_initiate_connect_socks (struct server *s,
|
||||||
{
|
{
|
||||||
struct app_context *ctx = s->ctx;
|
struct app_context *ctx = s->ctx;
|
||||||
|
|
||||||
const char *socks_host = get_config_string (ctx, "server.socks_host");
|
const char *socks_host = get_config_string (s->config, "socks_host");
|
||||||
int64_t socks_port_int = get_config_integer (ctx, "server.socks_port");
|
int64_t socks_port_int = get_config_integer (s->config, "socks_port");
|
||||||
|
|
||||||
const char *socks_username =
|
const char *socks_username =
|
||||||
get_config_string (ctx, "server.socks_username");
|
get_config_string (s->config, "socks_username");
|
||||||
const char *socks_password =
|
const char *socks_password =
|
||||||
get_config_string (ctx, "server.socks_password");
|
get_config_string (s->config, "socks_password");
|
||||||
|
|
||||||
if (!socks_host)
|
if (!socks_host)
|
||||||
return false;
|
return false;
|
||||||
|
@ -3427,7 +3451,7 @@ irc_initiate_connect (struct server *s)
|
||||||
hard_assert (s->state == IRC_DISCONNECTED);
|
hard_assert (s->state == IRC_DISCONNECTED);
|
||||||
struct app_context *ctx = s->ctx;
|
struct app_context *ctx = s->ctx;
|
||||||
|
|
||||||
const char *addresses = get_config_string (ctx, "server.addresses");
|
const char *addresses = get_config_string (s->config, "addresses");
|
||||||
if (!addresses || !addresses[strspn (addresses, ",")])
|
if (!addresses || !addresses[strspn (addresses, ",")])
|
||||||
{
|
{
|
||||||
// No sense in trying to reconnect
|
// No sense in trying to reconnect
|
||||||
|
@ -4231,7 +4255,7 @@ irc_on_registered (struct server *s, const char *nickname)
|
||||||
// we can also use WHOIS if it's not supported (optional by RFC 2812)
|
// we can also use WHOIS if it's not supported (optional by RFC 2812)
|
||||||
irc_send (s, "USERHOST %s", s->irc_user->nickname);
|
irc_send (s, "USERHOST %s", s->irc_user->nickname);
|
||||||
|
|
||||||
const char *autojoin = get_config_string (s->ctx, "server.autojoin");
|
const char *autojoin = get_config_string (s->config, "autojoin");
|
||||||
if (autojoin)
|
if (autojoin)
|
||||||
irc_send (s, "JOIN :%s", autojoin);
|
irc_send (s, "JOIN :%s", autojoin);
|
||||||
|
|
||||||
|
@ -5098,10 +5122,16 @@ handle_command_me (struct app_context *ctx, char *arguments)
|
||||||
static bool
|
static bool
|
||||||
handle_command_quit (struct app_context *ctx, char *arguments)
|
handle_command_quit (struct app_context *ctx, char *arguments)
|
||||||
{
|
{
|
||||||
// TODO: multiserver
|
struct str_map_iter iter;
|
||||||
struct server *s = &ctx->server;
|
str_map_iter_init (&iter, &ctx->servers);
|
||||||
if (irc_is_connected (s))
|
|
||||||
irc_initiate_disconnect (s, *arguments ? arguments : NULL);
|
struct server *s;
|
||||||
|
while ((s = str_map_iter_next (&iter)))
|
||||||
|
{
|
||||||
|
if (irc_is_connected (s))
|
||||||
|
irc_initiate_disconnect (s, *arguments ? arguments : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
initiate_quit (ctx);
|
initiate_quit (ctx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5159,8 +5189,24 @@ handle_command_part (struct app_context *ctx, char *arguments)
|
||||||
static bool
|
static bool
|
||||||
handle_command_connect (struct app_context *ctx, char *arguments)
|
handle_command_connect (struct app_context *ctx, char *arguments)
|
||||||
{
|
{
|
||||||
// TODO: multiserver
|
struct server *s = NULL;
|
||||||
struct server *s = &ctx->server;
|
if (*arguments)
|
||||||
|
{
|
||||||
|
char *name = cut_word (&arguments);
|
||||||
|
if (!(s = str_map_find (&ctx->servers, name)))
|
||||||
|
buffer_send_error (ctx, ctx->global_buffer,
|
||||||
|
"%s: %s: %s", "Can't connect", "no such server", name);
|
||||||
|
}
|
||||||
|
else if (ctx->current_buffer->type == BUFFER_GLOBAL)
|
||||||
|
buffer_send_error (ctx, ctx->current_buffer,
|
||||||
|
"%s: %s", "Can't connect",
|
||||||
|
"no server name given and this buffer is global");
|
||||||
|
else
|
||||||
|
s = ctx->current_buffer->server;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (irc_is_connected (s))
|
if (irc_is_connected (s))
|
||||||
{
|
{
|
||||||
buffer_send_error (ctx, s->buffer, "Already connected");
|
buffer_send_error (ctx, s->buffer, "Already connected");
|
||||||
|
@ -5177,8 +5223,17 @@ handle_command_connect (struct app_context *ctx, char *arguments)
|
||||||
static bool
|
static bool
|
||||||
handle_command_disconnect (struct app_context *ctx, char *arguments)
|
handle_command_disconnect (struct app_context *ctx, char *arguments)
|
||||||
{
|
{
|
||||||
// TODO: multiserver
|
// TODO: try to take server name from arguments
|
||||||
struct server *s = &ctx->server;
|
struct server *s = NULL;
|
||||||
|
if (ctx->current_buffer->type == BUFFER_GLOBAL)
|
||||||
|
buffer_send_error (ctx, ctx->current_buffer,
|
||||||
|
"%s: %s", "Can't disconnect", "this buffer is global");
|
||||||
|
else
|
||||||
|
s = ctx->current_buffer->server;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (s->state == IRC_CONNECTING)
|
if (s->state == IRC_CONNECTING)
|
||||||
{
|
{
|
||||||
buffer_send_status (ctx, s->buffer, "Connecting aborted");
|
buffer_send_status (ctx, s->buffer, "Connecting aborted");
|
||||||
|
@ -5292,7 +5347,7 @@ g_command_handlers[] =
|
||||||
NOT_IMPLEMENTED (invite)
|
NOT_IMPLEMENTED (invite)
|
||||||
|
|
||||||
{ "connect", "Connect to the server",
|
{ "connect", "Connect to the server",
|
||||||
NULL,
|
"[server]",
|
||||||
handle_command_connect },
|
handle_command_connect },
|
||||||
{ "disconnect", "Disconnect from the server",
|
{ "disconnect", "Disconnect from the server",
|
||||||
"[reason]",
|
"[reason]",
|
||||||
|
@ -6264,11 +6319,11 @@ app_editline_init (struct input *self)
|
||||||
// --- Configuration loading ---------------------------------------------------
|
// --- Configuration loading ---------------------------------------------------
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
autofill_user_info (struct app_context *ctx, struct error **e)
|
autofill_user_info (struct server *s, struct error **e)
|
||||||
{
|
{
|
||||||
const char *nickname = get_config_string (ctx, "server.nickname");
|
const char *nickname = get_config_string (s->config, "nickname");
|
||||||
const char *username = get_config_string (ctx, "server.username");
|
const char *username = get_config_string (s->config, "username");
|
||||||
const char *realname = get_config_string (ctx, "server.realname");
|
const char *realname = get_config_string (s->config, "realname");
|
||||||
|
|
||||||
if (nickname && username && realname)
|
if (nickname && username && realname)
|
||||||
return true;
|
return true;
|
||||||
|
@ -6280,9 +6335,9 @@ autofill_user_info (struct app_context *ctx, struct error **e)
|
||||||
|
|
||||||
// FIXME: set_config_strings() writes errors on its own
|
// FIXME: set_config_strings() writes errors on its own
|
||||||
if (!nickname)
|
if (!nickname)
|
||||||
set_config_string (ctx, "server.nickname", pwd->pw_name);
|
set_config_string (s->config, "nickname", pwd->pw_name);
|
||||||
if (!username)
|
if (!username)
|
||||||
set_config_string (ctx, "server.username", pwd->pw_name);
|
set_config_string (s->config, "username", pwd->pw_name);
|
||||||
|
|
||||||
// Not all systems have the GECOS field but the vast majority does
|
// Not all systems have the GECOS field but the vast majority does
|
||||||
if (!realname)
|
if (!realname)
|
||||||
|
@ -6294,7 +6349,7 @@ autofill_user_info (struct app_context *ctx, struct error **e)
|
||||||
if (comma)
|
if (comma)
|
||||||
*comma = '\0';
|
*comma = '\0';
|
||||||
|
|
||||||
set_config_string (ctx, "server.realname", gecos);
|
set_config_string (s->config, "realname", gecos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -6371,18 +6426,9 @@ load_configuration (struct app_context *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
config_load (&ctx->config, root ? root : config_item_object ());
|
config_load (&ctx->config, root ? root : config_item_object ());
|
||||||
if (!autofill_user_info (ctx, &e))
|
|
||||||
{
|
|
||||||
print_error ("%s: %s", "failed to fill in user details", e->message);
|
|
||||||
error_free (e);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->isolate_buffers =
|
ctx->isolate_buffers =
|
||||||
get_config_boolean (ctx, "behaviour.isolate_buffers");
|
get_config_boolean (ctx->config.root, "behaviour.isolate_buffers");
|
||||||
ctx->server.reconnect =
|
|
||||||
get_config_boolean (ctx, "server.reconnect");
|
|
||||||
ctx->server.reconnect_delay =
|
|
||||||
get_config_integer (ctx, "server.reconnect_delay");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Signals -----------------------------------------------------------------
|
// --- Signals -----------------------------------------------------------------
|
||||||
|
@ -6453,6 +6499,26 @@ setup_signal_handlers (void)
|
||||||
|
|
||||||
// --- I/O event handlers ------------------------------------------------------
|
// --- I/O event handlers ------------------------------------------------------
|
||||||
|
|
||||||
|
// FIXME: merge this with initiate_quit()
|
||||||
|
static void
|
||||||
|
preinitiate_quit (struct app_context *ctx)
|
||||||
|
{
|
||||||
|
struct str_map_iter iter;
|
||||||
|
str_map_iter_init (&iter, &ctx->servers);
|
||||||
|
|
||||||
|
struct server *s;
|
||||||
|
while ((s = str_map_iter_next (&iter)))
|
||||||
|
{
|
||||||
|
// There may be a timer set to reconnect to the server
|
||||||
|
// TODO: a faster timer for quitting
|
||||||
|
// XXX: why do we do this? Just to reset the reconnect timer?
|
||||||
|
irc_reset_connection_timeouts (s);
|
||||||
|
|
||||||
|
if (irc_is_connected (s))
|
||||||
|
irc_initiate_disconnect (s, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
|
on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
|
||||||
{
|
{
|
||||||
|
@ -6461,15 +6527,7 @@ on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
|
||||||
|
|
||||||
if (g_termination_requested && !ctx->quitting)
|
if (g_termination_requested && !ctx->quitting)
|
||||||
{
|
{
|
||||||
// There may be a timer set to reconnect to the server
|
preinitiate_quit (ctx);
|
||||||
// TODO: multiserver
|
|
||||||
struct server *s = &ctx->server;
|
|
||||||
// TODO: a faster timer for quitting
|
|
||||||
// XXX: why do we do this? Just to reset the reconnect timer?
|
|
||||||
irc_reset_connection_timeouts (s);
|
|
||||||
|
|
||||||
if (irc_is_connected (s))
|
|
||||||
irc_initiate_disconnect (s, NULL);
|
|
||||||
initiate_quit (ctx);
|
initiate_quit (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6588,6 +6646,43 @@ display_logo (void)
|
||||||
str_vector_free (&v);
|
str_vector_free (&v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_server (struct app_context *ctx)
|
||||||
|
{
|
||||||
|
struct server *s = xmalloc (sizeof *s);
|
||||||
|
server_init (s, &ctx->poller);
|
||||||
|
|
||||||
|
s->ctx = ctx;
|
||||||
|
s->name = xstrdup ("server");
|
||||||
|
str_map_set (&ctx->servers, s->name, s);
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
s->config = config_item_get (ctx->config.root, "server", NULL);
|
||||||
|
hard_assert (s->config != NULL);
|
||||||
|
|
||||||
|
s->reconnect = get_config_boolean (s->config, "reconnect");
|
||||||
|
s->reconnect_delay = get_config_integer (s->config, "reconnect_delay");
|
||||||
|
|
||||||
|
struct error *e = NULL;
|
||||||
|
if (!autofill_user_info (s, &e))
|
||||||
|
{
|
||||||
|
print_error ("%s: %s", "failed to fill in user details", e->message);
|
||||||
|
error_free (e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a buffer and activate it
|
||||||
|
struct buffer *buffer = s->buffer = buffer_new ();
|
||||||
|
buffer->type = BUFFER_SERVER;
|
||||||
|
buffer->name = xstrdup (s->name);
|
||||||
|
buffer->server = s;
|
||||||
|
|
||||||
|
buffer_add (ctx, buffer);
|
||||||
|
buffer_activate (ctx, buffer);
|
||||||
|
|
||||||
|
// Connect to the server ASAP
|
||||||
|
poller_timer_set (&s->reconnect_tmr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -6650,10 +6745,9 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
refresh_prompt (&ctx);
|
refresh_prompt (&ctx);
|
||||||
input_start (&ctx.input, argv[0]);
|
input_start (&ctx.input, argv[0]);
|
||||||
buffer_activate (&ctx, ctx.server.buffer);
|
|
||||||
|
|
||||||
// Connect to the server ASAP
|
// TODO: finish multi-server
|
||||||
poller_timer_set (&ctx.server.reconnect_tmr, 0);
|
create_server (&ctx);
|
||||||
|
|
||||||
ctx.polling = true;
|
ctx.polling = true;
|
||||||
while (ctx.polling)
|
while (ctx.polling)
|
||||||
|
|
Loading…
Reference in New Issue