changeset 751:8876412ba633

Irccd: merge commands in command.cpp
author David Demelier <markand@malikania.fr>
date Fri, 03 Aug 2018 20:09:00 +0200
parents 1e1eb83a3f0b
children 252506d9839b
files irccd/main.cpp libirccd-test/irccd/test/command_test.hpp libirccd-test/irccd/test/plugin_cli_test.cpp libirccd-test/irccd/test/rule_cli_test.cpp libirccd-test/irccd/test/server_cli_test.cpp libirccd/CMakeLists.txt libirccd/irccd/daemon/command.cpp libirccd/irccd/daemon/command.hpp libirccd/irccd/daemon/command/plugin_config_command.cpp libirccd/irccd/daemon/command/plugin_config_command.hpp libirccd/irccd/daemon/command/plugin_info_command.cpp libirccd/irccd/daemon/command/plugin_info_command.hpp libirccd/irccd/daemon/command/plugin_list_command.cpp libirccd/irccd/daemon/command/plugin_list_command.hpp libirccd/irccd/daemon/command/plugin_load_command.cpp libirccd/irccd/daemon/command/plugin_load_command.hpp libirccd/irccd/daemon/command/plugin_reload_command.cpp libirccd/irccd/daemon/command/plugin_reload_command.hpp libirccd/irccd/daemon/command/plugin_unload_command.cpp libirccd/irccd/daemon/command/plugin_unload_command.hpp libirccd/irccd/daemon/command/rule_add_command.cpp libirccd/irccd/daemon/command/rule_add_command.hpp libirccd/irccd/daemon/command/rule_edit_command.cpp libirccd/irccd/daemon/command/rule_edit_command.hpp libirccd/irccd/daemon/command/rule_info_command.cpp libirccd/irccd/daemon/command/rule_info_command.hpp libirccd/irccd/daemon/command/rule_list_command.cpp libirccd/irccd/daemon/command/rule_list_command.hpp libirccd/irccd/daemon/command/rule_move_command.cpp libirccd/irccd/daemon/command/rule_move_command.hpp libirccd/irccd/daemon/command/rule_remove_command.cpp libirccd/irccd/daemon/command/rule_remove_command.hpp libirccd/irccd/daemon/command/server_connect_command.cpp libirccd/irccd/daemon/command/server_connect_command.hpp libirccd/irccd/daemon/command/server_disconnect_command.cpp libirccd/irccd/daemon/command/server_disconnect_command.hpp libirccd/irccd/daemon/command/server_info_command.cpp libirccd/irccd/daemon/command/server_info_command.hpp libirccd/irccd/daemon/command/server_invite_command.cpp libirccd/irccd/daemon/command/server_invite_command.hpp libirccd/irccd/daemon/command/server_join_command.cpp libirccd/irccd/daemon/command/server_join_command.hpp libirccd/irccd/daemon/command/server_kick_command.cpp libirccd/irccd/daemon/command/server_kick_command.hpp libirccd/irccd/daemon/command/server_list_command.cpp libirccd/irccd/daemon/command/server_list_command.hpp libirccd/irccd/daemon/command/server_me_command.cpp libirccd/irccd/daemon/command/server_me_command.hpp libirccd/irccd/daemon/command/server_message_command.cpp libirccd/irccd/daemon/command/server_message_command.hpp libirccd/irccd/daemon/command/server_mode_command.cpp libirccd/irccd/daemon/command/server_mode_command.hpp libirccd/irccd/daemon/command/server_nick_command.cpp libirccd/irccd/daemon/command/server_nick_command.hpp libirccd/irccd/daemon/command/server_notice_command.cpp libirccd/irccd/daemon/command/server_notice_command.hpp libirccd/irccd/daemon/command/server_part_command.cpp libirccd/irccd/daemon/command/server_part_command.hpp libirccd/irccd/daemon/command/server_reconnect_command.cpp libirccd/irccd/daemon/command/server_reconnect_command.hpp libirccd/irccd/daemon/command/server_topic_command.cpp libirccd/irccd/daemon/command/server_topic_command.hpp libirccd/irccd/daemon/transport_client.cpp libirccd/irccd/daemon/transport_client.hpp tests/src/libirccd/command-plugin-config/main.cpp tests/src/libirccd/command-plugin-info/main.cpp tests/src/libirccd/command-plugin-list/main.cpp tests/src/libirccd/command-plugin-load/main.cpp tests/src/libirccd/command-plugin-reload/main.cpp tests/src/libirccd/command-plugin-unload/main.cpp tests/src/libirccd/command-rule-add/main.cpp tests/src/libirccd/command-rule-edit/main.cpp tests/src/libirccd/command-rule-info/main.cpp tests/src/libirccd/command-rule-list/main.cpp tests/src/libirccd/command-rule-move/main.cpp tests/src/libirccd/command-rule-remove/main.cpp tests/src/libirccd/command-server-connect/main.cpp tests/src/libirccd/command-server-disconnect/main.cpp tests/src/libirccd/command-server-info/main.cpp tests/src/libirccd/command-server-invite/main.cpp tests/src/libirccd/command-server-join/main.cpp tests/src/libirccd/command-server-kick/main.cpp tests/src/libirccd/command-server-list/main.cpp tests/src/libirccd/command-server-me/main.cpp tests/src/libirccd/command-server-message/main.cpp tests/src/libirccd/command-server-mode/main.cpp tests/src/libirccd/command-server-nick/main.cpp tests/src/libirccd/command-server-notice/main.cpp tests/src/libirccd/command-server-part/main.cpp tests/src/libirccd/command-server-reconnect/main.cpp tests/src/libirccd/command-server-topic/main.cpp
diffstat 91 files changed, 1512 insertions(+), 3110 deletions(-) [+]
line wrap: on
line diff
--- a/irccd/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/irccd/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -26,39 +26,11 @@
 #include <irccd/string_util.hpp>
 #include <irccd/system.hpp>
 
+#include <irccd/daemon/command.hpp>
 #include <irccd/daemon/dynlib_plugin.hpp>
 #include <irccd/daemon/irccd.hpp>
 #include <irccd/daemon/logger.hpp>
 
-#include <irccd/daemon/command/plugin_config_command.hpp>
-#include <irccd/daemon/command/plugin_info_command.hpp>
-#include <irccd/daemon/command/plugin_list_command.hpp>
-#include <irccd/daemon/command/plugin_list_command.hpp>
-#include <irccd/daemon/command/plugin_load_command.hpp>
-#include <irccd/daemon/command/plugin_reload_command.hpp>
-#include <irccd/daemon/command/plugin_unload_command.hpp>
-#include <irccd/daemon/command/rule_add_command.hpp>
-#include <irccd/daemon/command/rule_edit_command.hpp>
-#include <irccd/daemon/command/rule_info_command.hpp>
-#include <irccd/daemon/command/rule_list_command.hpp>
-#include <irccd/daemon/command/rule_move_command.hpp>
-#include <irccd/daemon/command/rule_remove_command.hpp>
-#include <irccd/daemon/command/server_connect_command.hpp>
-#include <irccd/daemon/command/server_disconnect_command.hpp>
-#include <irccd/daemon/command/server_info_command.hpp>
-#include <irccd/daemon/command/server_invite_command.hpp>
-#include <irccd/daemon/command/server_join_command.hpp>
-#include <irccd/daemon/command/server_kick_command.hpp>
-#include <irccd/daemon/command/server_list_command.hpp>
-#include <irccd/daemon/command/server_me_command.hpp>
-#include <irccd/daemon/command/server_message_command.hpp>
-#include <irccd/daemon/command/server_mode_command.hpp>
-#include <irccd/daemon/command/server_nick_command.hpp>
-#include <irccd/daemon/command/server_notice_command.hpp>
-#include <irccd/daemon/command/server_part_command.hpp>
-#include <irccd/daemon/command/server_reconnect_command.hpp>
-#include <irccd/daemon/command/server_topic_command.hpp>
-
 #include <irccd/daemon/service/plugin_service.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 #include <irccd/daemon/service/server_service.hpp>
--- a/libirccd-test/irccd/test/command_test.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd-test/irccd/test/command_test.hpp	Fri Aug 03 20:09:00 2018 +0200
@@ -24,6 +24,7 @@
 #include <irccd/socket_acceptor.hpp>
 #include <irccd/socket_connector.hpp>
 
+#include <irccd/daemon/command.hpp>
 #include <irccd/daemon/irccd.hpp>
 #include <irccd/daemon/logger.hpp>
 #include <irccd/daemon/service/transport_service.hpp>
--- a/libirccd-test/irccd/test/plugin_cli_test.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd-test/irccd/test/plugin_cli_test.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -16,14 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <irccd/daemon/command/plugin_config_command.hpp>
-#include <irccd/daemon/command/plugin_info_command.hpp>
-#include <irccd/daemon/command/plugin_list_command.hpp>
-#include <irccd/daemon/command/plugin_load_command.hpp>
-#include <irccd/daemon/command/plugin_reload_command.hpp>
-#include <irccd/daemon/command/plugin_unload_command.hpp>
-
 #include <irccd/daemon/service/transport_service.hpp>
+#include <irccd/daemon/command.hpp>
 
 #include "plugin_cli_test.hpp"
 
--- a/libirccd-test/irccd/test/rule_cli_test.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd-test/irccd/test/rule_cli_test.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -16,14 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <irccd/daemon/command/rule_add_command.hpp>
-#include <irccd/daemon/command/rule_edit_command.hpp>
-#include <irccd/daemon/command/rule_info_command.hpp>
-#include <irccd/daemon/command/rule_list_command.hpp>
-#include <irccd/daemon/command/rule_move_command.hpp>
-#include <irccd/daemon/command/rule_remove_command.hpp>
-
 #include <irccd/daemon/service/transport_service.hpp>
+#include <irccd/daemon/command.hpp>
 
 #include "rule_cli_test.hpp"
 
--- a/libirccd-test/irccd/test/server_cli_test.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd-test/irccd/test/server_cli_test.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -16,23 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <irccd/daemon/command/server_connect_command.hpp>
-#include <irccd/daemon/command/server_disconnect_command.hpp>
-#include <irccd/daemon/command/server_info_command.hpp>
-#include <irccd/daemon/command/server_invite_command.hpp>
-#include <irccd/daemon/command/server_join_command.hpp>
-#include <irccd/daemon/command/server_kick_command.hpp>
-#include <irccd/daemon/command/server_list_command.hpp>
-#include <irccd/daemon/command/server_me_command.hpp>
-#include <irccd/daemon/command/server_message_command.hpp>
-#include <irccd/daemon/command/server_mode_command.hpp>
-#include <irccd/daemon/command/server_nick_command.hpp>
-#include <irccd/daemon/command/server_notice_command.hpp>
-#include <irccd/daemon/command/server_part_command.hpp>
-#include <irccd/daemon/command/server_reconnect_command.hpp>
-#include <irccd/daemon/command/server_topic_command.hpp>
-
 #include <irccd/daemon/service/transport_service.hpp>
+#include <irccd/daemon/command.hpp>
 
 #include "server_cli_test.hpp"
 
--- a/libirccd/CMakeLists.txt	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd/CMakeLists.txt	Fri Aug 03 20:09:00 2018 +0200
@@ -21,34 +21,6 @@
 set(
     HEADERS
     ${libirccd_SOURCE_DIR}/irccd/daemon/command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_config_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_info_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_list_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_list_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_load_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_reload_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_unload_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_add_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_edit_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_info_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_list_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_move_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_remove_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_connect_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_disconnect_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_info_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_invite_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_join_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_kick_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_list_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_me_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_message_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_mode_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_nick_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_notice_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_part_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_reconnect_command.hpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_topic_command.hpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/dynlib_plugin.hpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/irccd.hpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/irc.hpp
@@ -69,33 +41,7 @@
 
 set(
     SOURCES
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_config_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_info_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_list_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_load_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_reload_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/plugin_unload_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_add_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_edit_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_info_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_list_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_move_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/rule_remove_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_connect_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_disconnect_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_info_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_invite_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_join_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_kick_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_list_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_me_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_message_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_mode_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_nick_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_notice_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_part_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_reconnect_command.cpp
-    ${libirccd_SOURCE_DIR}/irccd/daemon/command/server_topic_command.cpp
+    ${libirccd_SOURCE_DIR}/irccd/daemon/command.cpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/dynlib_plugin.cpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/irccd.cpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/irc.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd/irccd/daemon/command.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -0,0 +1,822 @@
+/*
+ * command.cpp -- remote command
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <irccd/daemon/service/plugin_service.hpp>
+#include <irccd/daemon/service/rule_service.hpp>
+#include <irccd/daemon/service/server_service.hpp>
+
+#include <irccd/daemon/irccd.hpp>
+#include <irccd/daemon/plugin.hpp>
+#include <irccd/daemon/rule.hpp>
+#include <irccd/daemon/rule_util.hpp>
+#include <irccd/daemon/server.hpp>
+#include <irccd/daemon/server_util.hpp>
+#include <irccd/daemon/transport_client.hpp>
+
+#include <irccd/string_util.hpp>
+
+#include "command.hpp"
+
+using namespace std::string_literals;
+
+namespace irccd {
+
+namespace {
+
+void exec_set(transport_client& client, plugin& plugin, const nlohmann::json& args)
+{
+    assert(args.count("value") > 0);
+
+    const auto var = args.find("variable");
+    const auto value = args.find("value");
+
+    if (var == args.end() || !var->is_string())
+        throw irccd_error(irccd_error::error::incomplete_message);
+    if (value == args.end() || !value->is_string())
+        throw irccd_error(irccd_error::error::incomplete_message);
+
+    auto config = plugin.get_options();
+
+    config[*var] = *value;
+    plugin.set_options(config);
+    client.success("plugin-config");
+}
+
+void exec_get(transport_client& client, plugin& plugin, const nlohmann::json& args)
+{
+    auto variables = nlohmann::json::object();
+    auto var = args.find("variable");
+
+    if (var != args.end() && var->is_string())
+        variables[var->get<std::string>()] = plugin.get_options()[*var];
+    else
+        for (const auto& pair : plugin.get_options())
+            variables[pair.first] = pair.second;
+
+    /*
+     * Don't put all variables into the response, put them into a sub property
+     * 'variables' instead.
+     *
+     * It's easier for the client to iterate over all.
+     */
+    client.write({
+        { "command",    "plugin-config" },
+        { "variables",  variables       }
+    });
+}
+
+} // !namespace
+
+// {{{ plugin_config_command
+
+auto plugin_config_command::get_name() const noexcept -> std::string_view
+{
+    return "plugin-config";
+}
+
+void plugin_config_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("plugin");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw plugin_error(plugin_error::invalid_identifier);
+
+    const auto plugin = irccd.plugins().require(*id);
+
+    if (args.count("value") > 0)
+        exec_set(client, *plugin, args);
+    else
+        exec_get(client, *plugin, args);
+}
+
+// }}}
+
+// {{{ plugin_info_command
+
+auto plugin_info_command::get_name() const noexcept -> std::string_view
+{
+    return "plugin-info";
+}
+
+void plugin_info_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("plugin");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw plugin_error(plugin_error::invalid_identifier);
+
+    const auto plugin = irccd.plugins().require(*id);
+
+    client.write({
+        { "command",    "plugin-info"                       },
+        { "author",     std::string(plugin->get_author())   },
+        { "license",    std::string(plugin->get_license())  },
+        { "summary",    std::string(plugin->get_summary())  },
+        { "version",    std::string(plugin->get_version())  }
+    });
+}
+
+// }}}
+
+// {{{ plugin_list_command
+
+auto plugin_list_command::get_name() const noexcept -> std::string_view
+{
+    return "plugin-list";
+}
+
+void plugin_list_command::exec(irccd& irccd, transport_client& client, const document&)
+{
+    auto list = nlohmann::json::array();
+
+    for (const auto& plg : irccd.plugins().all())
+        list += plg->get_id();
+
+    client.write({
+        { "command",    "plugin-list"   },
+        { "list",       list            }
+    });
+}
+
+// }}}
+
+// {{{ plugin_load_command
+
+auto plugin_load_command::get_name() const noexcept -> std::string_view
+{
+    return "plugin-load";
+}
+
+void plugin_load_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("plugin");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw plugin_error(plugin_error::invalid_identifier);
+
+    irccd.plugins().load(*id, "");
+    client.success("plugin-load");
+}
+
+// }}}
+
+// {{{ plugin_reload_command
+
+auto plugin_reload_command::get_name() const noexcept -> std::string_view
+{
+    return "plugin-reload";
+}
+
+void plugin_reload_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("plugin");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw plugin_error(plugin_error::invalid_identifier);
+
+    irccd.plugins().reload(*id);
+    client.success("plugin-reload");
+}
+
+// }}}
+
+// {{{ plugin_unload_command
+
+auto plugin_unload_command::get_name() const noexcept -> std::string_view
+{
+    return "plugin-unload";
+}
+
+void plugin_unload_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("plugin");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw plugin_error(plugin_error::invalid_identifier);
+
+    irccd.plugins().unload(*id);
+    client.success("plugin-unload");
+}
+
+// }}}
+
+// {{{ rule_add_command
+
+auto rule_add_command::get_name() const noexcept -> std::string_view
+{
+    return "rule-add";
+}
+
+void rule_add_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto index = args.optional<unsigned>("index", irccd.rules().length());
+
+    if (!index || *index > irccd.rules().length())
+        throw rule_error(rule_error::error::invalid_index);
+
+    irccd.rules().insert(rule_util::from_json(args), *index);
+    client.success("rule-add");
+}
+
+// }}}
+
+// {{{ rule_edit_command
+
+auto rule_edit_command::get_name() const noexcept -> std::string_view
+{
+    return "rule-edit";
+}
+
+void rule_edit_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    static const auto updateset = [] (auto& set, auto args, const auto& key) {
+        for (const auto& v : args["remove-"s + key]) {
+            if (v.is_string())
+                set.erase(v.template get<std::string>());
+        }
+        for (const auto& v : args["add-"s + key]) {
+            if (v.is_string())
+                set.insert(v.template get<std::string>());
+        }
+    };
+
+    const auto index = args.get<unsigned>("index");
+
+    if (!index)
+        throw rule_error(rule_error::invalid_index);
+
+    // Create a copy to avoid incomplete edition in case of errors.
+    auto rule = irccd.rules().require(*index);
+
+    updateset(rule.get_channels(), args, "channels");
+    updateset(rule.get_events(), args, "events");
+    updateset(rule.get_plugins(), args, "plugins");
+    updateset(rule.get_servers(), args, "servers");
+
+    auto action = args.find("action");
+
+    if (action != args.end()) {
+        if (!action->is_string())
+            throw rule_error(rule_error::error::invalid_action);
+
+        if (action->get<std::string>() == "accept")
+            rule.set_action(rule::action::accept);
+        else if (action->get<std::string>() == "drop")
+            rule.set_action(rule::action::drop);
+        else
+            throw rule_error(rule_error::invalid_action);
+    }
+
+    // All done, sync the rule.
+    irccd.rules().require(*index) = rule;
+    client.success("rule-edit");
+}
+
+// }}}
+
+// {{{ rule_info_command
+
+auto rule_info_command::get_name() const noexcept -> std::string_view
+{
+    return "rule-info";
+}
+
+void rule_info_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto index = args.get<unsigned>("index");
+
+    if (!index)
+        throw rule_error(rule_error::invalid_index);
+
+    auto json = rule_util::to_json(irccd.rules().require(*index));
+
+    json.push_back({"command", "rule-info"});
+    client.write(std::move(json));
+}
+
+// }}}
+
+// {{{ rule_list_command
+
+auto rule_list_command::get_name() const noexcept -> std::string_view
+{
+    return "rule-list";
+}
+
+void rule_list_command::exec(irccd& irccd, transport_client& client, const document&)
+{
+    auto array = nlohmann::json::array();
+
+    for (const auto& rule : irccd.rules().list())
+        array.push_back(rule_util::to_json(rule));
+
+    client.write({
+        { "command",    "rule-list"         },
+        { "list",       std::move(array)    }
+    });
+}
+
+// }}}
+
+// {{{ rule_move_command
+
+auto rule_move_command::get_name() const noexcept -> std::string_view
+{
+    return "rule-move";
+}
+
+void rule_move_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto from = args.get<unsigned>("from");
+    const auto to = args.get<unsigned>("to");
+
+    if (!from || !to)
+        throw rule_error(rule_error::invalid_index);
+
+    /*
+     * Examples of moves
+     * --------------------------------------------------------------
+     *
+     * Before: [0] [1] [2]
+     *
+     * from = 0
+     * to   = 2
+     *
+     * After:  [1] [2] [0]
+     *
+     * --------------------------------------------------------------
+     *
+     * Before: [0] [1] [2]
+     *
+     * from = 2
+     * to   = 0
+     *
+     * After:  [2] [0] [1]
+     *
+     * --------------------------------------------------------------
+     *
+     * Before: [0] [1] [2]
+     *
+     * from = 0
+     * to   = 123
+     *
+     * After:  [1] [2] [0]
+     */
+
+    // Ignore dumb input.
+    if (*from == *to) {
+        client.success("rule-move");
+        return;
+    }
+
+    if (*from >= irccd.rules().length())
+        throw rule_error(rule_error::error::invalid_index);
+
+    const auto save = irccd.rules().list()[*from];
+
+    irccd.rules().remove(*from);
+    irccd.rules().insert(save, *to > irccd.rules().length() ? irccd.rules().length() : *to);
+    client.success("rule-move");
+}
+
+// }}}
+
+// {{{ rule_remove_command
+
+auto rule_remove_command::get_name() const noexcept -> std::string_view
+{
+    return "rule-remove";
+}
+
+void rule_remove_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto index = args.get<unsigned>("index");
+
+    if (!index || *index >= irccd.rules().length())
+        throw rule_error(rule_error::invalid_index);
+
+    irccd.rules().remove(*index);
+    client.success("rule-remove");
+}
+
+// }}}
+
+// {{{ server_connect_command
+
+auto server_connect_command::get_name() const noexcept -> std::string_view
+{
+    return "server-connect";
+}
+
+void server_connect_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    auto server = server_util::from_json(irccd.get_service(), args);
+
+    if (irccd.servers().has(server->get_id()))
+        throw server_error(server_error::already_exists);
+
+    irccd.servers().add(std::move(server));
+    client.success("server-connect");
+}
+
+// }}}
+
+// {{{ server_disconnect_command
+
+auto server_disconnect_command::get_name() const noexcept -> std::string_view
+{
+    return "server-disconnect";
+}
+
+void server_disconnect_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto it = args.find("server");
+
+    if (it == args.end())
+        irccd.servers().clear();
+    else {
+        if (!it->is_string() || !string_util::is_identifier(it->get<std::string>()))
+            throw server_error(server_error::invalid_identifier);
+
+        const auto name = it->get<std::string>();
+
+        irccd.servers().require(name);
+        irccd.servers().remove(name);
+    }
+
+    client.success("server-disconnect");
+}
+
+// }}}
+
+// {{{ server_info_command
+
+auto server_info_command::get_name() const noexcept -> std::string_view
+{
+    return "server-info";
+}
+
+void server_info_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+
+    const auto server = irccd.servers().require(*id);
+
+    // Construct the JSON response.
+    auto response = document::object();
+
+    // General stuff.
+    response.push_back({"command", "server-info"});
+    response.push_back({"name", server->get_id()});
+    response.push_back({"host", server->get_host()});
+    response.push_back({"port", server->get_port()});
+    response.push_back({"nickname", server->get_nickname()});
+    response.push_back({"username", server->get_username()});
+    response.push_back({"realname", server->get_realname()});
+    response.push_back({"channels", server->get_channels()});
+
+    // Optional stuff.
+    if ((server->get_options() & server::options::ipv6) == server::options::ipv6)
+        response.push_back({"ipv6", true});
+    if ((server->get_options() & server::options::ssl) == server::options::ssl)
+        response.push_back({"ssl", true});
+    if ((server->get_options() & server::options::ssl_verify) == server::options::ssl_verify)
+        response.push_back({"sslVerify", true});
+
+    client.write(response);
+}
+
+// }}}
+
+// {{{ server_invite_command
+
+auto server_invite_command::get_name() const noexcept -> std::string_view
+{
+    return "server-invite";
+}
+
+void server_invite_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto target = args.get<std::string>("target");
+    const auto channel = args.get<std::string>("channel");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!target || target->empty())
+        throw server_error(server_error::invalid_nickname);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+
+    irccd.servers().require(*id)->invite(*target, *channel);
+    client.success("server-invite");
+}
+
+// }}}
+
+// {{{ server_join_command
+
+auto server_join_command::get_name() const noexcept -> std::string_view
+{
+    return "server-join";
+}
+
+void server_join_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("channel");
+    const auto password = args.optional<std::string>("password", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!password)
+        throw server_error(server_error::invalid_password);
+
+    irccd.servers().require(*id)->join(*channel, *password);
+    client.success("server-join");
+}
+
+// }}}
+
+// {{{ server_kick_command
+
+auto server_kick_command::get_name() const noexcept -> std::string_view
+{
+    return "server-kick";
+}
+
+void server_kick_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto target = args.get<std::string>("target");
+    const auto channel = args.get<std::string>("channel");
+    const auto reason = args.optional<std::string>("reason", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!target || target->empty())
+        throw server_error(server_error::invalid_nickname);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!reason)
+        throw server_error(server_error::invalid_message);
+
+    irccd.servers().require(*id)->kick(*target, *channel, *reason);
+    client.success("server-kick");
+}
+
+// }}}
+
+// {{{ server_list_command
+
+auto server_list_command::get_name() const noexcept -> std::string_view
+{
+    return "server-list";
+}
+
+void server_list_command::exec(irccd& irccd, transport_client& client, const document&)
+{
+    auto json = nlohmann::json::object();
+    auto list = nlohmann::json::array();
+
+    for (const auto& server : irccd.servers().all())
+        list.push_back(server->get_id());
+
+    client.write({
+        { "command",    "server-list"   },
+        { "list",       std::move(list) }
+    });
+}
+
+// }}}
+
+// {{{ server_me_command
+
+auto server_me_command::get_name() const noexcept -> std::string_view
+{
+    return "server-me";
+}
+
+void server_me_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("target");
+    const auto message = args.optional<std::string>("message", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!message)
+        throw server_error(server_error::invalid_message);
+
+    irccd.servers().require(*id)->me(*channel, *message);
+    client.success("server-me");
+}
+
+// }}}
+
+// {{{ server_message_command
+
+auto server_message_command::get_name() const noexcept -> std::string_view
+{
+    return "server-message";
+}
+
+void server_message_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("target");
+    const auto message = args.optional<std::string>("message", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!message)
+        throw server_error(server_error::invalid_message);
+
+    irccd.servers().require(*id)->message(*channel, *message);
+    client.success("server-message");
+}
+
+// }}}
+
+// {{{ server_mode_command
+
+auto server_mode_command::get_name() const noexcept -> std::string_view
+{
+    return "server-mode";
+}
+
+void server_mode_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("channel");
+    const auto mode = args.get<std::string>("mode");
+    const auto limit = args.optional<std::string>("limit", "");
+    const auto user = args.optional<std::string>("user", "");
+    const auto mask = args.optional<std::string>("mask", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!mode || mode->empty())
+        throw server_error(server_error::invalid_mode);
+    if (!limit || !user || !mask)
+        throw server_error(server_error::invalid_mode);
+
+    irccd.servers().require(*id)->mode(*channel, *mode, *limit, *user, *mask);
+    client.success("server-mode");
+}
+
+// }}}
+
+// {{{ server_nick_command
+
+auto server_nick_command::get_name() const noexcept -> std::string_view
+{
+    return "server-nick";
+}
+
+void server_nick_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto nick = args.get<std::string>("nickname");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!nick || nick->empty())
+        throw server_error(server_error::invalid_nickname);
+
+    irccd.servers().require(*id)->set_nickname(*nick);
+    client.success("server-nick");
+}
+
+// }}}
+
+// {{{ server_notice_command
+
+auto server_notice_command::get_name() const noexcept -> std::string_view
+{
+    return "server-notice";
+}
+
+void server_notice_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("target");
+    const auto message = args.optional<std::string>("message", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!message)
+        throw server_error(server_error::invalid_message);
+
+    irccd.servers().require(*id)->notice(*channel, *message);
+    client.success("server-notice");
+}
+
+// }}}
+
+// {{{ server_part_command
+
+auto server_part_command::get_name() const noexcept -> std::string_view
+{
+    return "server-part";
+}
+
+void server_part_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("channel");
+    const auto reason = args.optional<std::string>("reason", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!reason)
+        throw server_error(server_error::invalid_message);
+
+    irccd.servers().require(*id)->part(*channel, *reason);
+    client.success("server-part");
+}
+
+// }}}
+
+// {{{ server_reconnect_command
+
+auto server_reconnect_command::get_name() const noexcept -> std::string_view
+{
+    return "server-reconnect";
+}
+
+void server_reconnect_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto it = args.find("server");
+
+    if (it == args.end())
+        irccd.servers().reconnect();
+    else {
+        if (!it->is_string() || !string_util::is_identifier(it->get<std::string>()))
+            throw server_error(server_error::invalid_identifier);
+
+        irccd.servers().reconnect(it->get<std::string>());
+    }
+
+    client.success("server-reconnect");
+}
+
+// }}}
+
+// {{{ server_topic_command
+
+auto server_topic_command::get_name() const noexcept -> std::string_view
+{
+    return "server-topic";
+}
+
+void server_topic_command::exec(irccd& irccd, transport_client& client, const document& args)
+{
+    const auto id = args.get<std::string>("server");
+    const auto channel = args.get<std::string>("channel");
+    const auto topic = args.optional<std::string>("topic", "");
+
+    if (!id || !string_util::is_identifier(*id))
+        throw server_error(server_error::invalid_identifier);
+    if (!channel || channel->empty())
+        throw server_error(server_error::invalid_channel);
+    if (!topic)
+        throw server_error(server_error::invalid_message);
+
+    irccd.servers().require(*id)->topic(*channel, *topic);
+    client.success("server-topic");
+}
+
+// }}}
+
+} // !irccd
--- a/libirccd/irccd/daemon/command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd/irccd/daemon/command.hpp	Fri Aug 03 20:09:00 2018 +0200
@@ -24,17 +24,19 @@
  * \brief Remote commands.
  */
 
-#include <string>
+#include <irccd/sysconfig.hpp>
 
-#include <irccd/sysconfig.hpp>
+#include <string_view>
+
 #include <irccd/json_util.hpp>
 
 namespace irccd {
 
 class irccd;
-class irccdctl;
 class transport_client;
 
+// {{{ command
+
 /**
  * \brief Server side remote command
  */
@@ -55,7 +57,7 @@
      *
      * \return the command name
      */
-    virtual std::string get_name() const noexcept = 0;
+    virtual auto get_name() const noexcept -> std::string_view = 0;
 
     /**
      * Execute the command.
@@ -73,6 +75,679 @@
     virtual void exec(irccd& irccd, transport_client& client, const document& args) = 0;
 };
 
+// }}}
+
+// {{{ plugin_config_command
+
+/**
+ * \brief Implementation of plugin-config transport command.
+ *
+ * Replies:
+ *
+ *   - plugin_error::not_found
+ */
+class plugin_config_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ plugin_info_command
+
+/**
+ * \brief Implementation of plugin-info transport command.
+ *
+ * Replies:
+ *
+ *   - plugin_error::not_found
+ */
+class plugin_info_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ plugin_list_command
+
+/**
+ * \brief Implementation of plugin-list transport command.
+ */
+class plugin_list_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ plugin_load_command
+
+/**
+ * \brief Implementation of plugin-load transport command.
+ *
+ * Replies:
+ *
+ *   - plugin_error::already_exists
+ *   - plugin_error::not_found
+ *   - plugin_error::exec_error
+ */
+class plugin_load_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ plugin_reload_command
+
+/**
+ * \brief Implementation of plugin-reload transport command.
+ *
+ * Replies:
+ *
+ *   - plugin_error::not_found
+ *   - plugin_error::exec_error
+ */
+class plugin_reload_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ plugin_unload_command
+
+/**
+ * \brief Implementation of plugin-unload transport command.
+ *
+ * Replies:
+ *
+ *   - plugin_error::not_found
+ *   - plugin_error::exec_error
+ */
+class plugin_unload_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ rule_add_command
+
+/**
+ * \brief Implementation of rule-add transport command.
+ *
+ * Replies:
+ *
+ *   - rule_error::invalid_action
+ */
+class rule_add_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ rule_edit_command
+
+/**
+ * \brief Implementation of rule-edit transport command.
+ *
+ * Replies:
+ *
+ *   - rule_error::invalid_index
+ *   - rule_error::invalid_action
+ */
+class rule_edit_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ rule_info_command
+
+/**
+ * \brief Implementation of rule-info transport command.
+ *
+ * Replies:
+ *
+ *   - rule_error::invalid_index
+ */
+class rule_info_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ rule_list_command
+
+/**
+ * \brief Implementation of rule-list transport command.
+ */
+class rule_list_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ rule_move_command
+
+/**
+ * \brief Implementation of rule-move transport command.
+ *
+ * Replies:
+ *
+ *   - rule_error::invalid_index
+ */
+class rule_move_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ rule_remove_command
+
+/**
+ * \brief Implementation of rule-remove transport command.
+ *
+ * Replies:
+ *
+ *   - rule_error::invalid_index
+ */
+class rule_remove_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_connect_command
+
+/**
+ * \brief Implementation of server-connect transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::already_exists,
+ *   - server_error::invalid_hostname,
+ *   - server_error::invalid_identifier,
+ *   - server_error::invalid_port_number,
+ *   - server_error::ssl_disabled.
+ */
+class server_connect_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_disconnect_command
+
+/**
+ * \brief Implementation of server-disconnect transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_disconnect_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_info_command
+
+/**
+ * \brief Implementation of server-info transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_info_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_invite_command
+
+/**
+ * \brief Implementation of server-invite transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::invalid_nickname,
+ *   - server_error::not_found.
+ */
+class server_invite_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_join_command
+
+/**
+ * \brief Implementation of server-join transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_join_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_kick_command
+
+/**
+ * \brief Implementation of server-kick transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::invalid_nickname,
+ *   - server_error::not_found.
+ */
+class server_kick_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_list_command
+
+/**
+ * \brief Implementation of server-list transport command.
+ */
+class server_list_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_me_command
+
+/**
+ * \brief Implementation of server-me transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_me_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_message_command
+
+/**
+ * \brief Implementation of server-message transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_message_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_mode_command
+
+/**
+ * \brief Implementation of server-mode transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::invalid_mode,
+ *   - server_error::not_found.
+ */
+class server_mode_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_nick_command
+
+/**
+ * \brief Implementation of server-nick transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_identifier,
+ *   - server_error::invalid_nickname,
+ *   - server_error::not_found.
+ */
+class server_nick_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_notice_command
+
+/**
+ * \brief Implementation of server-notice transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_notice_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_part_command
+
+/**
+ * \brief Implementation of server-part transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_part_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_reconnect_command
+
+/**
+ * \brief Implementation of server-reconnect transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_reconnect_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
+// {{{ server_topic_command
+
+/**
+ * \brief Implementation of server-topic transport command.
+ *
+ * Replies:
+ *
+ *   - server_error::invalid_channel,
+ *   - server_error::invalid_identifier,
+ *   - server_error::not_found.
+ */
+class server_topic_command : public command {
+public:
+    /**
+     * \copydoc command::get_name
+     */
+    auto get_name() const noexcept -> std::string_view override;
+
+    /**
+     * \copydoc command::exec
+     */
+    void exec(irccd& irccd, transport_client& client, const document& args) override;
+};
+
+// }}}
+
 } // !irccd
 
 #endif // !IRCCD_DAEMON_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/plugin_config_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * plugin_config_command.cpp -- implementation of plugin-config transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/plugin_service.hpp>
-
-#include "plugin_config_command.hpp"
-
-namespace irccd {
-
-namespace {
-
-void exec_set(transport_client& client, plugin& plugin, const nlohmann::json& args)
-{
-    assert(args.count("value") > 0);
-
-    const auto var = args.find("variable");
-    const auto value = args.find("value");
-
-    if (var == args.end() || !var->is_string())
-        throw irccd_error(irccd_error::error::incomplete_message);
-    if (value == args.end() || !value->is_string())
-        throw irccd_error(irccd_error::error::incomplete_message);
-
-    auto config = plugin.get_options();
-
-    config[*var] = *value;
-    plugin.set_options(config);
-    client.success("plugin-config");
-}
-
-void exec_get(transport_client& client, plugin& plugin, const nlohmann::json& args)
-{
-    auto variables = nlohmann::json::object();
-    auto var = args.find("variable");
-
-    if (var != args.end() && var->is_string())
-        variables[var->get<std::string>()] = plugin.get_options()[*var];
-    else
-        for (const auto& pair : plugin.get_options())
-            variables[pair.first] = pair.second;
-
-    /*
-     * Don't put all variables into the response, put them into a sub property
-     * 'variables' instead.
-     *
-     * It's easier for the client to iterate over all.
-     */
-    client.write({
-        { "command",    "plugin-config" },
-        { "variables",  variables       }
-    });
-}
-
-} // !namespace
-
-std::string plugin_config_command::get_name() const noexcept
-{
-    return "plugin-config";
-}
-
-void plugin_config_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("plugin");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw plugin_error(plugin_error::invalid_identifier);
-
-    const auto plugin = irccd.plugins().require(*id);
-
-    if (args.count("value") > 0)
-        exec_set(client, *plugin, args);
-    else
-        exec_get(client, *plugin, args);
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/plugin_config_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * plugin_config_command.hpp -- implementation of plugin-config transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_PLUGIN_CONFIG_COMMAND_HPP
-#define IRCCD_DAEMON_PLUGIN_CONFIG_COMMAND_HPP
-
-/**
- * \file plugin_config_command.hpp
- * \brief Implementation of plugin-config transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of plugin-config transport command.
- *
- * Replies:
- *
- *   - plugin_error::not_found
- */
-class plugin_config_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_PLUGIN_CONFIG_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/plugin_info_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * plugin_info_command.cpp -- implementation of plugin-info transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/plugin_service.hpp>
-
-#include "plugin_info_command.hpp"
-
-namespace irccd {
-
-std::string plugin_info_command::get_name() const noexcept
-{
-    return "plugin-info";
-}
-
-void plugin_info_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("plugin");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw plugin_error(plugin_error::invalid_identifier);
-
-    const auto plugin = irccd.plugins().require(*id);
-
-    client.write({
-        { "command",    "plugin-info"                       },
-        { "author",     std::string(plugin->get_author())   },
-        { "license",    std::string(plugin->get_license())  },
-        { "summary",    std::string(plugin->get_summary())  },
-        { "version",    std::string(plugin->get_version())  }
-    });
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/plugin_info_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * plugin_info_command.hpp -- implementation of plugin-info transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_PLUGIN_INFO_COMMAND_HPP
-#define IRCCD_DAEMON_PLUGIN_INFO_COMMAND_HPP
-
-/**
- * \file plugin_info_command.hpp
- * \brief Implementation of plugin-info transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of plugin-info transport command.
- *
- * Replies:
- *
- *   - plugin_error::not_found
- */
-class plugin_info_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_PLUGIN_INFO_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/plugin_list_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * plugin_list_command.cpp -- implementation of plugin-list transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/plugin_service.hpp>
-
-#include "plugin_list_command.hpp"
-
-namespace irccd {
-
-std::string plugin_list_command::get_name() const noexcept
-{
-    return "plugin-list";
-}
-
-void plugin_list_command::exec(irccd& irccd, transport_client& client, const document&)
-{
-    auto list = nlohmann::json::array();
-
-    for (const auto& plg : irccd.plugins().all())
-        list += plg->get_id();
-
-    client.write({
-        { "command",    "plugin-list"   },
-        { "list",       list            }
-    });
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/plugin_list_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * plugin_list_command.hpp -- implementation of plugin-list transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/**
- * \file plugin_list_command.hpp
- * \brief Implementation of plugin-list transport command.
- */
-
-#ifndef IRCCD_DAEMON_PLUGIN_LIST_COMMAND_HPP
-#define IRCCD_DAEMON_PLUGIN_LIST_COMMAND_HPP
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of plugin-list transport command.
- */
-class plugin_list_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_PLUGIN_LIST_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/plugin_load_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * plugin_load_command.cpp -- implementation of plugin-load transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/plugin_service.hpp>
-
-#include "plugin_load_command.hpp"
-
-namespace irccd {
-
-std::string plugin_load_command::get_name() const noexcept
-{
-    return "plugin-load";
-}
-
-void plugin_load_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("plugin");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw plugin_error(plugin_error::invalid_identifier);
-
-    irccd.plugins().load(*id, "");
-    client.success("plugin-load");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/plugin_load_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * plugin_load_command.hpp -- implementation of plugin-load transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_PLUGIN_LOAD_COMMAND_HPP
-#define IRCCD_DAEMON_PLUGIN_LOAD_COMMAND_HPP
-
-/**
- * \file plugin_load_command.hpp
- * \brief Implementation of plugin-load transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of plugin-load transport command.
- *
- * Replies:
- *
- *   - plugin_error::already_exists
- *   - plugin_error::not_found
- *   - plugin_error::exec_error
- */
-class plugin_load_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_PLUGIN_LOAD_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/plugin_reload_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * plugin_reload_command.cpp -- implementation of plugin-reload transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/plugin_service.hpp>
-
-#include "plugin_reload_command.hpp"
-
-namespace irccd {
-
-std::string plugin_reload_command::get_name() const noexcept
-{
-    return "plugin-reload";
-}
-
-void plugin_reload_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("plugin");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw plugin_error(plugin_error::invalid_identifier);
-
-    irccd.plugins().reload(*id);
-    client.success("plugin-reload");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/plugin_reload_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * plugin_reload_command.hpp -- implementation of plugin-reload transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_PLUGIN_RELOAD_COMMAND_HPP
-#define IRCCD_DAEMON_PLUGIN_RELOAD_COMMAND_HPP
-
-/**
- * \file plugin_reload_command.hpp
- * \brief Implementation of plugin-reload transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of plugin-reload transport command.
- *
- * Replies:
- *
- *   - plugin_error::not_found
- *   - plugin_error::exec_error
- */
-class plugin_reload_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_PLUGIN_RELOAD_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/plugin_unload_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * plugin_unload_command.cpp -- implementation of plugin-unload transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/plugin_service.hpp>
-
-#include "plugin_unload_command.hpp"
-
-namespace irccd {
-
-std::string plugin_unload_command::get_name() const noexcept
-{
-    return "plugin-unload";
-}
-
-void plugin_unload_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("plugin");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw plugin_error(plugin_error::invalid_identifier);
-
-    irccd.plugins().unload(*id);
-    client.success("plugin-unload");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/plugin_unload_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * plugin_unload_command.hpp -- implementation of plugin-unload transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_PLUGIN_UNLOAD_COMMAND_HPP
-#define IRCCD_DAEMON_PLUGIN_UNLOAD_COMMAND_HPP
-
-/**
- * \file plugin_unload_command.hpp
- * \brief Implementation of plugin-unload transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of plugin-unload transport command.
- *
- * Replies:
- *
- *   - plugin_error::not_found
- *   - plugin_error::exec_error
- */
-class plugin_unload_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_PLUGIN_UNLOAD_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/rule_add_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * rule_add_command.cpp -- implementation of rule-add transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-#include <irccd/daemon/rule_util.hpp>
-
-#include <irccd/daemon/service/rule_service.hpp>
-
-#include "rule_add_command.hpp"
-
-namespace irccd {
-
-std::string rule_add_command::get_name() const noexcept
-{
-    return "rule-add";
-}
-
-void rule_add_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto index = args.optional<unsigned>("index", irccd.rules().length());
-
-    if (!index || *index > irccd.rules().length())
-        throw rule_error(rule_error::error::invalid_index);
-
-    irccd.rules().insert(rule_util::from_json(args), *index);
-    client.success("rule-add");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/rule_add_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * rule_add_command.hpp -- implementation of rule-add transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_RULE_ADD_COMMAND_HPP
-#define IRCCD_DAEMON_RULE_ADD_COMMAND_HPP
-
-/**
- * \file rule_add_command.hpp
- * \brief Implementation of rule-add transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of rule-add transport command.
- *
- * Replies:
- *
- *   - rule_error::invalid_action
- */
-class rule_add_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_RULE_ADD_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/rule_edit_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * rule_edit_command.cpp -- implementation of rule-edit transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/rule_util.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/rule_service.hpp>
-
-#include "rule_edit_command.hpp"
-
-using namespace std::string_literals;
-
-namespace irccd {
-
-std::string rule_edit_command::get_name() const noexcept
-{
-    return "rule-edit";
-}
-
-void rule_edit_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    static const auto updateset = [] (auto& set, auto args, const auto& key) {
-        for (const auto& v : args["remove-"s + key]) {
-            if (v.is_string())
-                set.erase(v.template get<std::string>());
-        }
-        for (const auto& v : args["add-"s + key]) {
-            if (v.is_string())
-                set.insert(v.template get<std::string>());
-        }
-    };
-
-    const auto index = args.get<unsigned>("index");
-
-    if (!index)
-        throw rule_error(rule_error::invalid_index);
-
-    // Create a copy to avoid incomplete edition in case of errors.
-    auto rule = irccd.rules().require(*index);
-
-    updateset(rule.get_channels(), args, "channels");
-    updateset(rule.get_events(), args, "events");
-    updateset(rule.get_plugins(), args, "plugins");
-    updateset(rule.get_servers(), args, "servers");
-
-    auto action = args.find("action");
-
-    if (action != args.end()) {
-        if (!action->is_string())
-            throw rule_error(rule_error::error::invalid_action);
-
-        if (action->get<std::string>() == "accept")
-            rule.set_action(rule::action::accept);
-        else if (action->get<std::string>() == "drop")
-            rule.set_action(rule::action::drop);
-        else
-            throw rule_error(rule_error::invalid_action);
-    }
-
-    // All done, sync the rule.
-    irccd.rules().require(*index) = rule;
-    client.success("rule-edit");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/rule_edit_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * rule_edit_command.hpp -- implementation of rule-edit transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_RULE_EDIT_COMMAND_HPP
-#define IRCCD_DAEMON_RULE_EDIT_COMMAND_HPP
-
-/**
- * \file rule_edit_command.hpp
- * \brief Implementation of rule-edit transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of rule-edit transport command.
- *
- * Replies:
- *
- *   - rule_error::invalid_index
- *   - rule_error::invalid_action
- */
-class rule_edit_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_RULE_EDIT_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/rule_info_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * rule_info_command.cpp -- implementation of rule-info transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/rule_util.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/rule_service.hpp>
-
-#include "rule_info_command.hpp"
-
-namespace irccd {
-
-std::string rule_info_command::get_name() const noexcept
-{
-    return "rule-info";
-}
-
-void rule_info_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto index = args.get<unsigned>("index");
-
-    if (!index)
-        throw rule_error(rule_error::invalid_index);
-
-    auto json = rule_util::to_json(irccd.rules().require(*index));
-
-    json.push_back({"command", "rule-info"});
-    client.write(std::move(json));
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/rule_info_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * rule_info_command.hpp -- implementation of rule-info transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_RULE_INFO_COMMAND_HPP
-#define IRCCD_DAEMON_RULE_INFO_COMMAND_HPP
-
-/**
- * \file rule_info_command.hpp
- * \brief Implementation of rule-info transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of rule-info transport command.
- *
- * Replies:
- *
- *   - rule_error::invalid_index
- */
-class rule_info_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_RULE_INFO_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/rule_list_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * rule_list_command.cpp -- implementation of rule-list transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/rule_util.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/rule_service.hpp>
-
-#include "rule_list_command.hpp"
-
-namespace irccd {
-
-std::string rule_list_command::get_name() const noexcept
-{
-    return "rule-list";
-}
-
-void rule_list_command::exec(irccd& irccd, transport_client& client, const document&)
-{
-    auto array = nlohmann::json::array();
-
-    for (const auto& rule : irccd.rules().list())
-        array.push_back(rule_util::to_json(rule));
-
-    client.write({
-        { "command",    "rule-list"         },
-        { "list",       std::move(array)    }
-    });
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/rule_list_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * rule_list_command.hpp -- implementation of rule-list transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_RULE_LIST_COMMAND_HPP
-#define IRCCD_DAEMON_RULE_LIST_COMMAND_HPP
-
-/**
- * \file rule_list_command.hpp
- * \brief Implementation of rule-list transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of rule-list transport command.
- */
-class rule_list_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_RULE_ADD_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/rule_move_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-/*
- * rule_move_command.cpp -- implementation of rule-move transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/rule_util.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/rule_service.hpp>
-
-#include "rule_move_command.hpp"
-
-namespace irccd {
-
-std::string rule_move_command::get_name() const noexcept
-{
-    return "rule-move";
-}
-
-void rule_move_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto from = args.get<unsigned>("from");
-    const auto to = args.get<unsigned>("to");
-
-    if (!from || !to)
-        throw rule_error(rule_error::invalid_index);
-
-    /*
-     * Examples of moves
-     * --------------------------------------------------------------
-     *
-     * Before: [0] [1] [2]
-     *
-     * from = 0
-     * to   = 2
-     *
-     * After:  [1] [2] [0]
-     *
-     * --------------------------------------------------------------
-     *
-     * Before: [0] [1] [2]
-     *
-     * from = 2
-     * to   = 0
-     *
-     * After:  [2] [0] [1]
-     *
-     * --------------------------------------------------------------
-     *
-     * Before: [0] [1] [2]
-     *
-     * from = 0
-     * to   = 123
-     *
-     * After:  [1] [2] [0]
-     */
-
-    // Ignore dumb input.
-    if (*from == *to) {
-        client.success("rule-move");
-        return;
-    }
-
-    if (*from >= irccd.rules().length())
-        throw rule_error(rule_error::error::invalid_index);
-
-    const auto save = irccd.rules().list()[*from];
-
-    irccd.rules().remove(*from);
-    irccd.rules().insert(save, *to > irccd.rules().length() ? irccd.rules().length() : *to);
-    client.success("rule-move");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/rule_move_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * rule_move_command.hpp -- implementation of rule-move transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_RULE_MOVE_COMMAND_HPP
-#define IRCCD_DAEMON_RULE_MOVE_COMMAND_HPP
-
-/**
- * \file rule_move_command.hpp
- * \brief Implementation of rule-move transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of rule-move transport command.
- *
- * Replies:
- *
- *   - rule_error::invalid_index
- */
-class rule_move_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_RULE_MOVE_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/rule_remove_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * rule_remove_command.cpp -- implementation of rule-remove transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/rule_service.hpp>
-
-#include "rule_remove_command.hpp"
-
-namespace irccd {
-
-std::string rule_remove_command::get_name() const noexcept
-{
-    return "rule-remove";
-}
-
-void rule_remove_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto index = args.get<unsigned>("index");
-
-    if (!index || *index >= irccd.rules().length())
-        throw rule_error(rule_error::invalid_index);
-
-    irccd.rules().remove(*index);
-    client.success("rule-remove");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/rule_remove_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * rule_remove_command.hpp -- implementation of rule-remove transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_RULE_REMOVE_COMMAND_HPP
-#define IRCCD_DAEMON_RULE_REMOVE_COMMAND_HPP
-
-/**
- * \file rule_remove_command.hpp
- * \brief Implementation of rule-remove transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of rule-remove transport command.
- *
- * Replies:
- *
- *   - rule_error::invalid_index
- */
-class rule_remove_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_RULE_REMOVE_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_connect_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * server_connect_command.cpp -- implementation of server-connect transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/server_util.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_connect_command.hpp"
-
-namespace irccd {
-
-std::string server_connect_command::get_name() const noexcept
-{
-    return "server-connect";
-}
-
-void server_connect_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    auto server = server_util::from_json(irccd.get_service(), args);
-
-    if (irccd.servers().has(server->get_id()))
-        throw server_error(server_error::already_exists);
-
-    irccd.servers().add(std::move(server));
-    client.success("server-connect");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_connect_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * server_connect_command.hpp -- implementation of server-connect transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_CONNECT_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_CONNECT_COMMAND_HPP
-
-/**
- * \file server_connect_command.hpp
- * \brief Implementation of server-connect transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-connect transport command.
- *
- * Replies:
- *
- *   - server_error::already_exists,
- *   - server_error::invalid_hostname,
- *   - server_error::invalid_identifier,
- *   - server_error::invalid_port_number,
- *   - server_error::ssl_disabled.
- */
-class server_connect_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_CONNECT_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_disconnect_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_disconnect_command.cpp -- implementation of server-disconnect transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_disconnect_command.hpp"
-
-namespace irccd {
-
-std::string server_disconnect_command::get_name() const noexcept
-{
-    return "server-disconnect";
-}
-
-void server_disconnect_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto it = args.find("server");
-
-    if (it == args.end())
-        irccd.servers().clear();
-    else {
-        if (!it->is_string() || !string_util::is_identifier(it->get<std::string>()))
-            throw server_error(server_error::invalid_identifier);
-
-        const auto name = it->get<std::string>();
-
-        irccd.servers().require(name);
-        irccd.servers().remove(name);
-    }
-
-    client.success("server-disconnect");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_disconnect_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * server_disconnect_command.hpp -- implementation of server-disconnect transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_DISCONNECT_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_DISCONNECT_COMMAND_HPP
-
-/**
- * \file server_disconnect_command.hpp
- * \brief Implementation of server-disconnect transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-disconnect transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_disconnect_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_DISCONNECT_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_info_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * server_info_command.cpp -- implementation of server-info transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/server_util.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_info_command.hpp"
-
-namespace irccd {
-
-std::string server_info_command::get_name() const noexcept
-{
-    return "server-info";
-}
-
-void server_info_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-
-    const auto server = irccd.servers().require(*id);
-
-    // Construct the JSON response.
-    auto response = document::object();
-
-    // General stuff.
-    response.push_back({"command", "server-info"});
-    response.push_back({"name", server->get_id()});
-    response.push_back({"host", server->get_host()});
-    response.push_back({"port", server->get_port()});
-    response.push_back({"nickname", server->get_nickname()});
-    response.push_back({"username", server->get_username()});
-    response.push_back({"realname", server->get_realname()});
-    response.push_back({"channels", server->get_channels()});
-
-    // Optional stuff.
-    if ((server->get_options() & server::options::ipv6) == server::options::ipv6)
-        response.push_back({"ipv6", true});
-    if ((server->get_options() & server::options::ssl) == server::options::ssl)
-        response.push_back({"ssl", true});
-    if ((server->get_options() & server::options::ssl_verify) == server::options::ssl_verify)
-        response.push_back({"sslVerify", true});
-
-    client.write(response);
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_info_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * server_info_command.hpp -- implementation of server-info transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_INFO_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_INFO_COMMAND_HPP
-
-/**
- * \file server_info_command.hpp
- * \brief Implementation of server-info transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-info transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_info_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_INFO_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_invite_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_invite_command.cpp -- implementation of server-invite transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_invite_command.hpp"
-
-namespace irccd {
-
-std::string server_invite_command::get_name() const noexcept
-{
-    return "server-invite";
-}
-
-void server_invite_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto target = args.get<std::string>("target");
-    const auto channel = args.get<std::string>("channel");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!target || target->empty())
-        throw server_error(server_error::invalid_nickname);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-
-    irccd.servers().require(*id)->invite(*target, *channel);
-    client.success("server-invite");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_invite_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * server_invite_command.hpp -- implementation of server-invite transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_INVITE_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_INVITE_COMMAND_HPP
-
-/**
- * \file server_invite_command.hpp
- * \brief Implementation of server-invite transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-invite transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::invalid_nickname,
- *   - server_error::not_found.
- */
-class server_invite_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_INVITE_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_join_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_join_command.cpp -- implementation of server-join transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_join_command.hpp"
-
-namespace irccd {
-
-std::string server_join_command::get_name() const noexcept
-{
-    return "server-join";
-}
-
-void server_join_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("channel");
-    const auto password = args.optional<std::string>("password", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!password)
-        throw server_error(server_error::invalid_password);
-
-    irccd.servers().require(*id)->join(*channel, *password);
-    client.success("server-join");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_join_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_join_command.hpp -- implementation of server-join transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_JOIN_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_JOIN_COMMAND_HPP
-
-/**
- * \file server_join_command.hpp
- * \brief Implementation of server-join transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-join transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_join_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_JOIN_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_kick_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * server_kick_command.cpp -- implementation of server-kick transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_kick_command.hpp"
-
-namespace irccd {
-
-std::string server_kick_command::get_name() const noexcept
-{
-    return "server-kick";
-}
-
-void server_kick_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto target = args.get<std::string>("target");
-    const auto channel = args.get<std::string>("channel");
-    const auto reason = args.optional<std::string>("reason", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!target || target->empty())
-        throw server_error(server_error::invalid_nickname);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!reason)
-        throw server_error(server_error::invalid_message);
-
-    irccd.servers().require(*id)->kick(*target, *channel, *reason);
-    client.success("server-kick");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_kick_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * server_kick_command.hpp -- implementation of server-kick transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_KICK_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_KICK_COMMAND_HPP
-
-/**
- * \file server_kick_command.hpp
- * \brief Implementation of server-kick transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-kick transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::invalid_nickname,
- *   - server_error::not_found.
- */
-class server_kick_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_KICK_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_list_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * server_list_command.cpp -- implementation of server-list transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_list_command.hpp"
-
-namespace irccd {
-
-std::string server_list_command::get_name() const noexcept
-{
-    return "server-list";
-}
-
-void server_list_command::exec(irccd& irccd, transport_client& client, const document&)
-{
-    auto json = nlohmann::json::object();
-    auto list = nlohmann::json::array();
-
-    for (const auto& server : irccd.servers().all())
-        list.push_back(server->get_id());
-
-    client.write({
-        { "command",    "server-list"   },
-        { "list",       std::move(list) }
-    });
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_list_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * server_list_command.hpp -- implementation of server-list transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_LIST_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_LIST_COMMAND_HPP
-
-/**
- * \file server_list_command.hpp
- * \brief Implementation of server-list transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-list transport command.
- */
-class server_list_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_LIST_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_me_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_me_command.cpp -- implementation of server-me transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_me_command.hpp"
-
-namespace irccd {
-
-std::string server_me_command::get_name() const noexcept
-{
-    return "server-me";
-}
-
-void server_me_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("target");
-    const auto message = args.optional<std::string>("message", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!message)
-        throw server_error(server_error::invalid_message);
-
-    irccd.servers().require(*id)->me(*channel, *message);
-    client.success("server-me");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_me_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_me_command.hpp -- implementation of server-me transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_ME_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_ME_COMMAND_HPP
-
-/**
- * \file server_me_command.hpp
- * \brief Implementation of server-me transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-me transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_me_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_ME_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_message_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_message_command.cpp -- implementation of server-message transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_message_command.hpp"
-
-namespace irccd {
-
-std::string server_message_command::get_name() const noexcept
-{
-    return "server-message";
-}
-
-void server_message_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("target");
-    const auto message = args.optional<std::string>("message", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!message)
-        throw server_error(server_error::invalid_message);
-
-    irccd.servers().require(*id)->message(*channel, *message);
-    client.success("server-message");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_message_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_message_command.hpp -- implementation of server-message transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_MESSAGE_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_MESSAGE_COMMAND_HPP
-
-/**
- * \file server_message_command.hpp
- * \brief Implementation of server-message transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-message transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_message_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_MESSAGE_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_mode_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * server_mode_command.cpp -- implementation of server-mode transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_mode_command.hpp"
-
-namespace irccd {
-
-std::string server_mode_command::get_name() const noexcept
-{
-    return "server-mode";
-}
-
-void server_mode_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("channel");
-    const auto mode = args.get<std::string>("mode");
-    const auto limit = args.optional<std::string>("limit", "");
-    const auto user = args.optional<std::string>("user", "");
-    const auto mask = args.optional<std::string>("mask", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!mode || mode->empty())
-        throw server_error(server_error::invalid_mode);
-    if (!limit || !user || !mask)
-        throw server_error(server_error::invalid_mode);
-
-    irccd.servers().require(*id)->mode(*channel, *mode, *limit, *user, *mask);
-    client.success("server-mode");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_mode_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * server_mode_command.hpp -- implementation of server-mode transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_MODE_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_MODE_COMMAND_HPP
-
-/**
- * \file server_mode_command.hpp
- * \brief Implementation of server-mode transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-mode transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::invalid_mode,
- *   - server_error::not_found.
- */
-class server_mode_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_MODE_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_nick_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * server_nick_command.cpp -- implementation of server-nick transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_nick_command.hpp"
-
-namespace irccd {
-
-std::string server_nick_command::get_name() const noexcept
-{
-    return "server-nick";
-}
-
-void server_nick_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto nick = args.get<std::string>("nickname");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!nick || nick->empty())
-        throw server_error(server_error::invalid_nickname);
-
-    irccd.servers().require(*id)->set_nickname(*nick);
-    client.success("server-nick");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_nick_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_nick_command.hpp -- implementation of server-nick transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_NICK_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_NICK_COMMAND_HPP
-
-/**
- * \file server_nick_command.hpp
- * \brief Implementation of server-nick transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-nick transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_identifier,
- *   - server_error::invalid_nickname,
- *   - server_error::not_found.
- */
-class server_nick_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_NICK_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_notice_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_notice_command.cpp -- implementation of server-notice transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_notice_command.hpp"
-
-namespace irccd {
-
-std::string server_notice_command::get_name() const noexcept
-{
-    return "server-notice";
-}
-
-void server_notice_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("target");
-    const auto message = args.optional<std::string>("message", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!message)
-        throw server_error(server_error::invalid_message);
-
-    irccd.servers().require(*id)->notice(*channel, *message);
-    client.success("server-notice");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_notice_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_notice_command.hpp -- implementation of server-notice transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_NOTICE_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_NOTICE_COMMAND_HPP
-
-/**
- * \file server_notice_command.hpp
- * \brief Implementation of server-notice transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-notice transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_notice_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_NOTICE_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_part_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_part_command.cpp -- implementation of server-part transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_part_command.hpp"
-
-namespace irccd {
-
-std::string server_part_command::get_name() const noexcept
-{
-    return "server-part";
-}
-
-void server_part_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("channel");
-    const auto reason = args.optional<std::string>("reason", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!reason)
-        throw server_error(server_error::invalid_message);
-
-    irccd.servers().require(*id)->part(*channel, *reason);
-    client.success("server-part");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_part_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_part_command.hpp -- implementation of server-part transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_PART_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_PART_COMMAND_HPP
-
-/**
- * \file server_part_command.hpp
- * \brief Implementation of server-part transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-part transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_part_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_PART_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_reconnect_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * server_reconnect_command.cpp -- implementation of server-reconnect transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_reconnect_command.hpp"
-
-namespace irccd {
-
-std::string server_reconnect_command::get_name() const noexcept
-{
-    return "server-reconnect";
-}
-
-void server_reconnect_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto it = args.find("server");
-
-    if (it == args.end())
-        irccd.servers().reconnect();
-    else {
-        if (!it->is_string() || !string_util::is_identifier(it->get<std::string>()))
-            throw server_error(server_error::invalid_identifier);
-
-        irccd.servers().reconnect(it->get<std::string>());
-    }
-
-    client.success("server-reconnect");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_reconnect_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * server_reconnect_command.hpp -- implementation of server-reconnect transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_RECONNECT_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_RECONNECT_COMMAND_HPP
-
-/**
- * \file server_reconnect_command.hpp
- * \brief Implementation of server-reconnect transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-reconnect transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_reconnect_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_RECONNECT_COMMAND_HPP
--- a/libirccd/irccd/daemon/command/server_topic_command.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * server_topic_command.cpp -- implementation of server-topic transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <irccd/json_util.hpp>
-#include <irccd/string_util.hpp>
-
-#include <irccd/daemon/irccd.hpp>
-#include <irccd/daemon/transport_client.hpp>
-
-#include <irccd/daemon/service/server_service.hpp>
-
-#include "server_topic_command.hpp"
-
-namespace irccd {
-
-std::string server_topic_command::get_name() const noexcept
-{
-    return "server-topic";
-}
-
-void server_topic_command::exec(irccd& irccd, transport_client& client, const document& args)
-{
-    const auto id = args.get<std::string>("server");
-    const auto channel = args.get<std::string>("channel");
-    const auto topic = args.optional<std::string>("topic", "");
-
-    if (!id || !string_util::is_identifier(*id))
-        throw server_error(server_error::invalid_identifier);
-    if (!channel || channel->empty())
-        throw server_error(server_error::invalid_channel);
-    if (!topic)
-        throw server_error(server_error::invalid_message);
-
-    irccd.servers().require(*id)->topic(*channel, *topic);
-    client.success("server-topic");
-}
-
-} // !irccd
--- a/libirccd/irccd/daemon/command/server_topic_command.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * server_topic_command.hpp -- implementation of server-topic transport command
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef IRCCD_DAEMON_SERVER_TOPIC_COMMAND_HPP
-#define IRCCD_DAEMON_SERVER_TOPIC_COMMAND_HPP
-
-/**
- * \file server_topic_command.hpp
- * \brief Implementation of server-topic transport command.
- */
-
-#include <irccd/daemon/command.hpp>
-
-namespace irccd {
-
-/**
- * \brief Implementation of server-topic transport command.
- *
- * Replies:
- *
- *   - server_error::invalid_channel,
- *   - server_error::invalid_identifier,
- *   - server_error::not_found.
- */
-class server_topic_command : public command {
-public:
-    /**
-     * \copydoc command::get_name
-     */
-    std::string get_name() const noexcept override;
-
-    /**
-     * \copydoc command::exec
-     */
-    void exec(irccd& irccd, transport_client& client, const document& args) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_DAEMON_SERVER_TOPIC_COMMAND_HPP
--- a/libirccd/irccd/daemon/transport_client.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd/irccd/daemon/transport_client.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -87,7 +87,7 @@
     error(std::move(code), "", std::move(handler));
 }
 
-void transport_client::error(std::error_code code, std::string cname, io::write_handler handler)
+void transport_client::error(std::error_code code, std::string_view cname, io::write_handler handler)
 {
     assert(code);
 
@@ -97,8 +97,9 @@
         { "errorMessage",   code.message()          }
     });
 
+    // TODO: check newer version of JSON for string_view support.
     if (!cname.empty())
-        json["command"] = std::move(cname);
+        json["command"] = std::string(cname);
 
     const auto self = shared_from_this();
 
--- a/libirccd/irccd/daemon/transport_client.hpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/libirccd/irccd/daemon/transport_client.hpp	Fri Aug 03 20:09:00 2018 +0200
@@ -22,6 +22,7 @@
 #include <cassert>
 #include <deque>
 #include <memory>
+#include <string_view>
 
 #include <irccd/stream.hpp>
 
@@ -146,7 +147,7 @@
      * \param handler the optional handler
      * \note If a write operation is running, it is postponed once ready.
      */
-    void error(std::error_code code, std::string command, io::write_handler handler = nullptr);
+    void error(std::error_code code, std::string_view command, io::write_handler handler = nullptr);
 };
 
 } // !irccd
--- a/tests/src/libirccd/command-plugin-config/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-plugin-config/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "plugin-config"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/plugin_config_command.hpp>
 #include <irccd/daemon/service/plugin_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-info/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-plugin-info/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "plugin-info"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/plugin_info_command.hpp>
 #include <irccd/daemon/service/plugin_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-list/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-plugin-list/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "plugin-list"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/plugin_list_command.hpp>
 #include <irccd/daemon/service/plugin_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-load/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-plugin-load/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "plugin-load"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/plugin_load_command.hpp>
 #include <irccd/daemon/service/plugin_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-reload/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-plugin-reload/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "plugin-reload"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/plugin_reload_command.hpp>
 #include <irccd/daemon/service/plugin_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-plugin-unload/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-plugin-unload/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "plugin-unload"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/plugin_unload_command.hpp>
 #include <irccd/daemon/service/plugin_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-add/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-rule-add/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -21,8 +21,6 @@
 
 #include <irccd/json_util.hpp>
 
-#include <irccd/daemon/command/rule_add_command.hpp>
-#include <irccd/daemon/command/rule_list_command.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-edit/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-rule-edit/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -21,8 +21,6 @@
 
 #include <irccd/json_util.hpp>
 
-#include <irccd/daemon/command/rule_edit_command.hpp>
-#include <irccd/daemon/command/rule_info_command.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-info/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-rule-info/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -21,7 +21,6 @@
 
 #include <irccd/json_util.hpp>
 
-#include <irccd/daemon/command/rule_info_command.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-list/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-rule-list/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -21,7 +21,6 @@
 
 #include <irccd/json_util.hpp>
 
-#include <irccd/daemon/command/rule_list_command.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-move/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-rule-move/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -21,8 +21,6 @@
 
 #include <irccd/json_util.hpp>
 
-#include <irccd/daemon/command/rule_list_command.hpp>
-#include <irccd/daemon/command/rule_move_command.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-rule-remove/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-rule-remove/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -21,8 +21,6 @@
 
 #include <irccd/json_util.hpp>
 
-#include <irccd/daemon/command/rule_remove_command.hpp>
-#include <irccd/daemon/command/rule_list_command.hpp>
 #include <irccd/daemon/service/rule_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-connect/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-connect/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-connect"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_connect_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-disconnect/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-disconnect/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-disconnect"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_disconnect_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/mock_server.hpp>
--- a/tests/src/libirccd/command-server-info/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-info/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-info"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_info_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-invite/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-invite/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-invite"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_invite_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-join/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-join/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-join"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_join_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-kick/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-kick/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-kick"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_kick_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-list/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-list/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-list"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_list_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-me/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-me/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-me"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_me_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-message/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-message/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-message"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_message_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-mode/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-mode/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-mode"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_mode_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-nick/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-nick/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-nick"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_nick_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-notice/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-notice/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-notice"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_notice_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-part/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-part/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-part"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_part_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-reconnect/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-reconnect/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-reconnect"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_reconnect_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>
--- a/tests/src/libirccd/command-server-topic/main.cpp	Fri Aug 03 19:31:00 2018 +0200
+++ b/tests/src/libirccd/command-server-topic/main.cpp	Fri Aug 03 20:09:00 2018 +0200
@@ -19,7 +19,6 @@
 #define BOOST_TEST_MODULE "server-topic"
 #include <boost/test/unit_test.hpp>
 
-#include <irccd/daemon/command/server_topic_command.hpp>
 #include <irccd/daemon/service/server_service.hpp>
 
 #include <irccd/test/command_test.hpp>