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 -----------------------------------------------------
|
// --- User input handling -----------------------------------------------------
|
||||||
|
|
||||||
// HANDLER_NEEDS_REG is primarily for message sending commands,
|
// 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);
|
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
|
static bool
|
||||||
handle_command_server (struct handler_args *a)
|
handle_command_server (struct handler_args *a)
|
||||||
{
|
{
|
||||||
|
@ -7153,7 +7254,7 @@ handle_command_server (struct handler_args *a)
|
||||||
if (!strcasecmp_ascii (action, "list"))
|
if (!strcasecmp_ascii (action, "list"))
|
||||||
show_servers_list (ctx);
|
show_servers_list (ctx);
|
||||||
else if (!strcasecmp_ascii (action, "add"))
|
else if (!strcasecmp_ascii (action, "add"))
|
||||||
; // TODO: <name>
|
result = handle_server_add (a);
|
||||||
else if (!strcasecmp_ascii (action, "remove"))
|
else if (!strcasecmp_ascii (action, "remove"))
|
||||||
; // TODO: <name>
|
; // TODO: <name>
|
||||||
else if (!strcasecmp_ascii (action, "rename"))
|
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
|
static void
|
||||||
load_servers (struct app_context *ctx)
|
load_servers (struct app_context *ctx)
|
||||||
{
|
{
|
||||||
struct config_item_ *servers =
|
|
||||||
config_item_get (ctx->config.root, "servers", NULL);
|
|
||||||
|
|
||||||
struct str_map_iter iter;
|
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;
|
struct config_item_ *subtree;
|
||||||
while ((s = str_map_iter_next (&iter)))
|
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: "
|
log_global_error (ctx, "Error in configuration: "
|
||||||
"ignoring server `#s' as it's not an object", iter.link->key);
|
"ignoring server `#s' as it's not an object", name);
|
||||||
else
|
else if (check_server_name_for_addition (ctx, name))
|
||||||
load_server_from_config (ctx, iter.link->key, s);
|
server_add (ctx, name, subtree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue