degesch: implement /server add
This commit is contained in:
parent
15d3129ea3
commit
096a179e09
168
degesch.c
168
degesch.c
|
@ -6291,6 +6291,94 @@ dump_matching_options
|
|||
}
|
||||
}
|
||||
|
||||
// --- Server management -------------------------------------------------------
|
||||
|
||||
static struct str_map *
|
||||
get_servers_config (struct app_context *ctx)
|
||||
{
|
||||
return &config_item_get (ctx->config.root, "servers", NULL)->value.object;
|
||||
}
|
||||
|
||||
static bool
|
||||
validate_server_name (const char *name)
|
||||
{
|
||||
for (const unsigned char *p = (const unsigned char *) name; *p; p++)
|
||||
if (*p < 32 || *p == '.')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_server_name_for_addition (struct app_context *ctx, const char *name)
|
||||
{
|
||||
if (!strcasecmp_ascii (name, ctx->global_buffer->name))
|
||||
log_global_error (ctx, "Cannot create server `#s': #s",
|
||||
name, "name collides with the global buffer");
|
||||
else if (str_map_find (&ctx->servers, name))
|
||||
log_global_error (ctx, "Cannot create server `#s': #s",
|
||||
name, "server already exists");
|
||||
else if (!validate_server_name (name))
|
||||
log_global_error (ctx, "Cannot create server `#s': #s",
|
||||
name, "invalid server name");
|
||||
else
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct server *
|
||||
server_add (struct app_context *ctx,
|
||||
const char *name, struct config_item_ *subtree)
|
||||
{
|
||||
hard_assert (!str_map_find (&ctx->servers, name));
|
||||
|
||||
struct server *s = xmalloc (sizeof *s);
|
||||
server_init (s, &ctx->poller);
|
||||
|
||||
s->ctx = ctx;
|
||||
s->name = xstrdup (name);
|
||||
str_map_set (&ctx->servers, s->name, s);
|
||||
s->config = subtree;
|
||||
|
||||
// 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);
|
||||
|
||||
config_schema_apply_to_object (g_config_server, subtree, s);
|
||||
config_schema_call_changed (subtree);
|
||||
|
||||
// Connect to the server ASAP
|
||||
// TODO: make this configurable ("autoconnect")
|
||||
poller_timer_set (&s->reconnect_tmr, 0);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
server_add_new (struct app_context *ctx, const char *name)
|
||||
{
|
||||
// Note that there may already be something in the configuration under
|
||||
// that key that we've ignored earlier, and there may also be
|
||||
// a case-insensitive conflict. Those things may only happen as a result
|
||||
// of manual edits to the configuration, though, and they're not really
|
||||
// going to break anything. They only cause surprises when loading.
|
||||
struct str_map *servers = get_servers_config (ctx);
|
||||
struct config_item_ *subtree = config_item_object ();
|
||||
str_map_set (servers, name, subtree);
|
||||
|
||||
struct server *s = server_add (ctx, name, subtree);
|
||||
struct error *e = NULL;
|
||||
if (!irc_autofill_user_info (s, &e))
|
||||
{
|
||||
log_server_error (s, s->buffer,
|
||||
"#s: #s", "Failed to fill in user details", e->message);
|
||||
error_free (e);
|
||||
}
|
||||
}
|
||||
|
||||
// --- User input handling -----------------------------------------------------
|
||||
|
||||
// HANDLER_NEEDS_REG is primarily for message sending commands,
|
||||
|
@ -7144,6 +7232,19 @@ show_servers_list (struct app_context *ctx)
|
|||
log_global_indent (ctx, " #s", s->name);
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_server_add (struct handler_args *a)
|
||||
{
|
||||
char *name = cut_word (&a->arguments);
|
||||
if (*a->arguments)
|
||||
return false;
|
||||
|
||||
struct app_context *ctx = a->ctx;
|
||||
if (check_server_name_for_addition (ctx, name))
|
||||
server_add_new (ctx, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_command_server (struct handler_args *a)
|
||||
{
|
||||
|
@ -7153,7 +7254,7 @@ handle_command_server (struct handler_args *a)
|
|||
if (!strcasecmp_ascii (action, "list"))
|
||||
show_servers_list (ctx);
|
||||
else if (!strcasecmp_ascii (action, "add"))
|
||||
; // TODO: <name>
|
||||
result = handle_server_add (a);
|
||||
else if (!strcasecmp_ascii (action, "remove"))
|
||||
; // TODO: <name>
|
||||
else if (!strcasecmp_ascii (action, "rename"))
|
||||
|
@ -8438,70 +8539,21 @@ load_configuration (struct app_context *ctx)
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
load_server_from_config (struct app_context *ctx,
|
||||
const char *name, struct config_item_ *subtree)
|
||||
{
|
||||
// They're case-insensitive in the application but not so in the config
|
||||
if (str_map_find (&ctx->servers, name))
|
||||
{
|
||||
log_global_error (ctx, "Error in configuration: "
|
||||
"ignoring server `#s' as it collides with another one", name);
|
||||
return;
|
||||
}
|
||||
|
||||
struct server *s = xmalloc (sizeof *s);
|
||||
server_init (s, &ctx->poller);
|
||||
|
||||
s->ctx = ctx;
|
||||
s->name = xstrdup (name);
|
||||
str_map_set (&ctx->servers, s->name, s);
|
||||
s->config = subtree;
|
||||
|
||||
// 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);
|
||||
|
||||
config_schema_apply_to_object (g_config_server, subtree, s);
|
||||
config_schema_call_changed (subtree);
|
||||
|
||||
// XXX: is this desirable in here? I think we should do it only when
|
||||
// actually creating a new server instead of every time we load them.
|
||||
struct error *e = NULL;
|
||||
if (!irc_autofill_user_info (s, &e))
|
||||
{
|
||||
log_server_error (s, s->buffer,
|
||||
"#s: #s", "Failed to fill in user details", e->message);
|
||||
error_free (e);
|
||||
}
|
||||
|
||||
// Connect to the server ASAP
|
||||
// TODO: make this configurable ("autoconnect")
|
||||
poller_timer_set (&s->reconnect_tmr, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
load_servers (struct app_context *ctx)
|
||||
{
|
||||
struct config_item_ *servers =
|
||||
config_item_get (ctx->config.root, "servers", NULL);
|
||||
|
||||
struct str_map_iter iter;
|
||||
str_map_iter_init (&iter, &servers->value.object);
|
||||
str_map_iter_init (&iter, get_servers_config (ctx));
|
||||
|
||||
struct config_item_ *s;
|
||||
while ((s = str_map_iter_next (&iter)))
|
||||
struct config_item_ *subtree;
|
||||
while ((subtree = str_map_iter_next (&iter)))
|
||||
{
|
||||
if (s->type != CONFIG_ITEM_OBJECT)
|
||||
const char *name = iter.link->key;
|
||||
if (subtree->type != CONFIG_ITEM_OBJECT)
|
||||
log_global_error (ctx, "Error in configuration: "
|
||||
"ignoring server `#s' as it's not an object", iter.link->key);
|
||||
else
|
||||
load_server_from_config (ctx, iter.link->key, s);
|
||||
"ignoring server `#s' as it's not an object", name);
|
||||
else if (check_server_name_for_addition (ctx, name))
|
||||
server_add (ctx, name, subtree);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue