aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--degesch.c168
1 files changed, 110 insertions, 58 deletions
diff --git a/degesch.c b/degesch.c
index c6e2d0c..3ed0e48 100644
--- a/degesch.c
+++ b/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,
@@ -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);
}
}