diff options
-rw-r--r-- | degesch.c | 168 |
1 files changed, 110 insertions, 58 deletions
@@ -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, @@ -7145,6 +7233,19 @@ show_servers_list (struct app_context *ctx) } 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) { struct app_context *ctx = a->ctx; @@ -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")) @@ -8439,69 +8540,20 @@ 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); } } |