diff irccdctl/cli.cpp @ 345:006452e4a997

Irccdctl: unify cli commands
author David Demelier <markand@malikania.fr>
date Sun, 13 Nov 2016 09:45:54 +0100
parents 4665fffff6f2
children 24b1709093e7
line wrap: on
line diff
--- a/irccdctl/cli.cpp	Sat Nov 12 22:58:48 2016 +0100
+++ b/irccdctl/cli.cpp	Sun Nov 13 09:45:54 2016 +0100
@@ -16,15 +16,23 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <iostream>
+
 #include <json.hpp>
 
 #include "cli.hpp"
+#include "elapsed-timer.hpp"
 #include "irccdctl.hpp"
+#include "options.hpp"
 #include "util.hpp"
-#include "elapsed-timer.hpp"
 
 namespace irccd {
 
+/*
+ * Cli.
+ * ------------------------------------------------------------------
+ */
+
 void Cli::check(const nlohmann::json &response)
 {
     if (!util::json::getBool(response, "status", false)) {
@@ -80,4 +88,723 @@
     check(request(irccdctl, args));
 }
 
+namespace cli {
+
+/*
+ * PluginConfigCli.
+ * ------------------------------------------------------------------
+ */
+
+void PluginConfigCli::set(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    check(request(irccdctl, nlohmann::json::object({
+        { "plugin", args[0] },
+        { "variable", args[1] },
+        { "value", args[2] }
+    })));
+}
+
+void PluginConfigCli::get(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    auto result = request(irccdctl, nlohmann::json::object({
+        { "plugin", args[0] },
+        { "variable", args[1] }
+    }));
+
+    check(result);
+
+    if (result["variables"].is_object())
+        std::cout << util::json::pretty(result["variables"][args[1]]) << std::endl;
+}
+
+void PluginConfigCli::getall(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    auto result = request(irccdctl, nlohmann::json::object({{ "plugin", args[0] }}));
+
+    check(result);
+
+    auto variables = result["variables"];
+
+    for (auto v = variables.begin(); v != variables.end(); ++v)
+        std::cout << std::setw(16) << std::left << v.key() << " : " << util::json::pretty(v.value()) << std::endl;
+}
+
+PluginConfigCli::PluginConfigCli()
+    : Cli("plugin-config",
+          "configure a plugin",
+          "plugin-config plugin [variable] [value]",
+          "Get or set plugin configuration.\n\n"
+          "Examples:\n"
+          "\tirccdctl plugin-config ask")
+{
+}
+
+void PluginConfigCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    switch (args.size()) {
+    case 3:
+        set(irccdctl, args);
+        break;
+    case 2:
+        get(irccdctl, args);
+        break;
+    case 1:
+        getall(irccdctl, args);
+        break;
+    default:
+        throw std::invalid_argument("plugin-config requires at least 1 argument");
+    }
+}
+
+/*
+ * PluginInfoCli.
+ * ------------------------------------------------------------------
+ */
+
+PluginInfoCli::PluginInfoCli()
+    : Cli("plugin-info",
+          "get plugin information",
+          "plugin-info plugin",
+          "Get plugin information\n\n"
+          "Example:\n"
+          "\tirccdctl plugin-info ask"
+    )
+{
+}
+
+void PluginInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 1)
+        throw std::invalid_argument("plugin-info requires 1 argument");
+
+    auto result = request(irccdctl, {{ "plugin", args[0] }});
+
+    std::cout << std::boolalpha;
+    std::cout << "Author         : " << util::json::getString(result, "author") << std::endl;
+    std::cout << "License        : " << util::json::getString(result, "license") << std::endl;
+    std::cout << "Summary        : " << util::json::getString(result, "summary") << std::endl;
+    std::cout << "Version        : " << util::json::getString(result, "version") << std::endl;
+}
+
+/*
+ * PluginListCli.
+ * ------------------------------------------------------------------
+ */
+
+PluginListCli::PluginListCli()
+    : Cli("plugin-list",
+          "list loaded plugins",
+          "plugin-list",
+          "Get the list of all loaded plugins.\n\n"
+          "Example:\n"
+          "\tirccdctl plugin-list")
+{
+}
+
+void PluginListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &)
+{
+    auto result = request(irccdctl);
+
+    for (const auto &value : result["list"])
+        if (value.is_string())
+            std::cout << value.get<std::string>() << std::endl;
+}
+
+/*
+ * PluginLoadCli.
+ * ------------------------------------------------------------------
+ */
+
+PluginLoadCli::PluginLoadCli()
+    : Cli("plugin-load",
+          "load a plugin",
+          "plugin-load logger",
+          "Load a plugin into the irccd instance.\n\n"
+          "Example:\n"
+          "\tirccdctl plugin-load logger")
+{
+}
+
+void PluginLoadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 1)
+        throw std::invalid_argument("plugin-load requires 1 argument");
+
+    check(request(irccdctl, {{"plugin", args[0]}}));
+}
+
+/*
+ * PluginReloadCli.
+ * ------------------------------------------------------------------
+ */
+
+PluginReloadCli::PluginReloadCli()
+    : Cli("plugin-reload",
+          "reload a plugin",
+          "plugin-reload plugin",
+          "Call the onReload event on the specified plugin.")
+{
+}
+
+void PluginReloadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 1)
+        throw std::invalid_argument("plugin-reload requires 1 argument");
+
+    check(request(irccdctl, {{ "plugin", args[0] }}));
+}
+
+/*
+ * PluginUnloadCli.
+ * ------------------------------------------------------------------
+ */
+
+PluginUnloadCli::PluginUnloadCli()
+    : Cli("plugin-unload",
+          "unload a plugin",
+          "plugin-unload plugin",
+          "Unload a loaded plugin from the irccd instance.\n\n"
+          "Example:\n"
+          "tirccdctl plugin-unload logger")
+{
+}
+
+void PluginUnloadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 1)
+        throw std::invalid_argument("plugin-unload requires 1 argument");
+
+    check(request(irccdctl, {{ "plugin", args[0] }}));
+}
+
+/*
+ * ServerChannelCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerChannelMode::ServerChannelMode()
+    : Cli("server-cmode",
+          "change channel mode",
+          "server-cmode server channel mode",
+          "Change the mode of the specified channel.\n\n"
+          "Example:\n"
+          "\tirccdctl server-cmode freenode #staff +t")
+{
+}
+
+void ServerChannelMode::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::invalid_argument("server-cmode requires 3 arguments");
+
+    check(request(irccdctl, {
+        { "command",    "server-cmode"  },
+        { "server",     args[0]         },
+        { "channel",    args[1]         },
+        { "mode",       args[2]         }
+    }));
+}
+
+/*
+ * ServerChannelNoticeCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerChannelNoticeCli::ServerChannelNoticeCli()
+    : Cli("server-cnotice",
+          "send a channel notice",
+          "server-cnotice server channel message",
+          "Send a message notice on a channel.\n\n"
+          "Example:\n"
+          "\tirccdctl server-cnotice freenode #staff \"Don't flood!\"")
+{
+}
+
+void ServerChannelNoticeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::invalid_argument("server-cnotice requires 3 arguments");
+
+    check(request(irccdctl, {
+        { "command",    "server-cnotice"    },
+        { "server",     args[0]             },
+        { "channel",    args[1]             },
+        { "message",    args[2]             }
+    }));
+}
+
+/*
+ * ServerConnectCli.
+ * ------------------------------------------------------------------
+ */
+
+namespace {
+
+option::Result parse(std::vector<std::string> &args)
+{
+    option::Options options{
+        { "-c",             true    },
+        { "--command",      true    },
+        { "-n",             true    },
+        { "--nickname",     true    },
+        { "-r",             true    },
+        { "--realname",     true    },
+        { "-S",             false   },
+        { "--ssl-verify",   false   },
+        { "-s",             false   },
+        { "--ssl",          false   },
+        { "-u",             true    },
+        { "--username",     true    }
+    };
+
+    return option::read(args, options);
+}
+
+} // !namespace
+
+ServerConnectCli::ServerConnectCli()
+    : Cli("server-connect",
+          "add a server",
+          "server-connect [options] id host [port]",
+          "Connect to a server.\n\n"
+          "Available options:\n"
+          "  -c, --command\t\tspecify the command char\n"
+          "  -n, --nickname\tspecify a nickname\n"
+          "  -r, --realname\tspecify a real name\n"
+          "  -S, --ssl-verify\tverify SSL\n"
+          "  -s, --ssl\t\tconnect using SSL\n"
+          "  -u, --username\tspecify a user name\n\n"
+          "Example:\n"
+          "\tirccdctl server-connect -n jean example irc.example.org\n"
+          "\tirccdctl server-connect --ssl example irc.example.org 6697")
+{
+}
+
+void ServerConnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    std::vector<std::string> copy(args);
+
+    option::Result result = parse(copy);
+    option::Result::const_iterator it;
+
+    if (copy.size() < 2)
+        throw std::invalid_argument("server-connect requires at least 2 arguments");
+
+    auto object = nlohmann::json::object({
+        { "name", copy[0] },
+        { "host", copy[1] }
+    });
+
+    if (copy.size() == 3) {
+        if (!util::isNumber(copy[2]))
+            throw std::invalid_argument("invalid port number");
+
+        object["port"] = std::stoi(copy[2]);
+    }
+
+    if (result.count("-S") > 0 || result.count("--ssl-verify") > 0)
+        object["sslVerify"] = true;
+    if (result.count("-s") > 0 || result.count("--ssl") > 0)
+        object["ssl"] = true;
+    if ((it = result.find("-n")) != result.end() || (it = result.find("--nickname")) != result.end())
+        object["nickname"] = it->second;
+    if ((it = result.find("-r")) != result.end() || (it = result.find("--realname")) != result.end())
+        object["realname"] = it->second;
+    if ((it = result.find("-u")) != result.end() || (it = result.find("--username")) != result.end())
+        object["username"] = it->second;
+
+    check(request(irccdctl, object));
+}
+
+/*
+ * ServerDisconnectCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerDisconnectCli::ServerDisconnectCli()
+    : Cli("server-disconnect",
+          "disconnect server",
+          "server-disconnect [server]",
+          "Disconnect from a server.\n\n"
+          "If server is not specified, irccd disconnects all servers.\n\n"
+          "Example:\n"
+          "\tirccdctl server-disconnect localhost")
+{
+}
+
+void ServerDisconnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    auto object = nlohmann::json::object({
+        { "command", "server-disconnect" }
+    });
+
+    if (args.size() > 0)
+        object["server"] = args[0];
+
+    check(request(irccdctl, object));
+}
+
+/*
+ * ServerInfoCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerInfoCli::ServerInfoCli()
+    : Cli("server-info",
+          "get server information",
+          "server-info server",
+          "Get information about a server.\n\n"
+          "Example:\n"
+          "\tirccdctl server-info freenode")
+{
+}
+
+void ServerInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 1)
+        throw std::invalid_argument("server-info requires 1 argument");
+
+    auto result = request(irccdctl, {
+        { "command",    "server-info"   },
+        { "server",     args[0]         }
+    });
+
+    check(result);
+
+    std::cout << std::boolalpha;
+    std::cout << "Name           : " << util::json::pretty(result["name"]) << std::endl;
+    std::cout << "Host           : " << util::json::pretty(result["host"]) << std::endl;
+    std::cout << "Port           : " << util::json::pretty(result["port"]) << std::endl;
+    std::cout << "Ipv6           : " << util::json::pretty(result["ipv6"]) << std::endl;
+    std::cout << "SSL            : " << util::json::pretty(result["ssl"]) << std::endl;
+    std::cout << "SSL verified   : " << util::json::pretty(result["sslVerify"]) << std::endl;
+    std::cout << "Channels       : ";
+
+    for (const auto &v : result["channels"])
+        if (v.is_string())
+            std::cout << v.get<std::string>() << " ";
+
+    std::cout << std::endl;
+
+    std::cout << "Nickname       : " << util::json::pretty(result["nickname"]) << std::endl;
+    std::cout << "User name      : " << util::json::pretty(result["username"]) << std::endl;
+    std::cout << "Real name      : " << util::json::pretty(result["realname"]) << std::endl;
+}
+
+/*
+ * ServerInviteCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerInviteCli::ServerInviteCli()
+    : Cli("server-invite",
+          "invite someone",
+          "server-invite server nickname channel",
+          "Invite the specified target on the channel.\n\n"
+          "Example:\n"
+          "\tirccdctl server-invite freenode xorg62 #staff")
+{
+}
+
+void ServerInviteCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::invalid_argument("server-invite requires 3 arguments");
+
+    check(request(irccdctl, {
+        { "command",    "server-invite" },
+        { "server",     args[0]         },
+        { "target",     args[1]         },
+        { "channel",    args[2]         }
+    }));
+}
+
+/*
+ * ServerJoinCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerJoinCli::ServerJoinCli()
+    : Cli("server-join",
+          "join a channel",
+          "server-join server channel [password]",
+          "Join the specified channel, the password is optional.\n\n"
+          "Example:\n"
+          "\tirccdctl server-join freenode #test\n"
+          "\tirccdctl server-join freenode #private-club secret")
+{
+}
+
+void ServerJoinCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 2)
+        throw std::invalid_argument("server-join requires at least 2 arguments");
+
+    auto object = nlohmann::json::object({
+        { "server",     args[0]         },
+        { "channel",    args[1]         }
+    });
+
+    if (args.size() == 3)
+        object["password"] = args[2];
+
+    check(request(irccdctl, object));
+}
+
+/*
+ * ServerKickCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerKickCli::ServerKickCli()
+    : Cli("server-kick",
+          "kick someone from a channel",
+          "server-kick server target channel [reason]",
+          "Kick the specified target from the channel, the reason is optional.\n\n"
+          "Example:\n"
+          "\tirccdctl server-kick freenode jean #staff \"Stop flooding\"")
+{
+}
+
+void ServerKickCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::invalid_argument("server-kick requires at least 3 arguments ");
+
+    auto object = nlohmann::json::object({
+        { "server",     args[0] },
+        { "target",     args[1] },
+        { "channel",    args[2] }
+    });
+
+    if (args.size() == 4)
+        object["reason"] = args[3];
+
+    check(request(irccdctl, object));
+}
+
+/*
+ * ServerListCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerListCli::ServerListCli()
+    : Cli("server-list",
+          "get list of servers",
+          "server-list\n\n",
+          "Get the list of all connected servers.\n\n"
+          "Example:\n"
+          "\tirccdctl server-list")
+{
+}
+
+void ServerListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &)
+{
+    auto response = request(irccdctl);
+
+    check(response);
+
+    for (const auto &n : response["list"])
+        if (n.is_string())
+            std::cout << n.get<std::string>() << std::endl;
+}
+
+/*
+ * ServerMeCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerMeCli::ServerMeCli()
+    : Cli("server-me",
+          "send an action emote",
+          "server-me server target message",
+          "Send an action emote.\n\n"
+          "Example:\n"
+          "\tirccdctl server-me freenode #staff \"going back soon\"")
+{
+}
+
+void ServerMeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::runtime_error("server-me requires 3 arguments");
+
+    check(request(irccdctl, {
+        { "server",     args[0]     },
+        { "target",     args[1]     },
+        { "message",    args[2]     }
+    }));
+}
+
+/*
+ * ServerMessageCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerMessageCli::ServerMessageCli()
+    : Cli("server-message",
+          "send a message",
+          "server-message server target message",
+          "Send a message to the specified target or channel.\n\n"
+          "Example:\n"
+          "\tirccdctl server-message freenode #staff \"Hello from irccd\"")
+{
+}
+
+void ServerMessageCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::invalid_argument("server-message requires 3 arguments");
+
+    check(request(irccdctl, {
+        { "server",     args[0] },
+        { "target",     args[1] },
+        { "message",    args[2] }
+    }));
+}
+
+/*
+ * ServerModeCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerModeCli::ServerModeCli()
+    : Cli("server-mode",
+          "the the user mode",
+          "server-mode server mode",
+          "Set the irccd's user mode.\n\n"
+          "Example:\n"
+          "\tirccdctl server-mode +i")
+{
+}
+
+void ServerModeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 2)
+        throw std::invalid_argument("server-mode requires 2 arguments");
+
+    check(request(irccdctl, {
+        { "server", args[0] },
+        { "mode",   args[1] }
+    }));
+}
+
+/*
+ * ServerNickCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerNickCli::ServerNickCli()
+    : Cli("server-nick",
+          "change your nickname",
+          "server-nick server nickname",
+          "Change irccd's nickname.\n\n"
+          "Example:\n"
+          "\tirccdctl server-nick freenode david")
+{
+}
+
+void ServerNickCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 2)
+        throw std::invalid_argument("server-nick requires 2 arguments");
+
+    check(request(irccdctl, {
+        { "server",     args[0] },
+        { "nickname",   args[1] }
+    }));
+}
+
+/*
+ * ServerNoticeCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerNoticeCli::ServerNoticeCli()
+    : Cli("server-notice",
+          "send a private notice",
+          "server-notice server target message",
+          "Send a private notice to the specified target.\n\n"
+          "Example:\n"
+          "\tirccdctl server-notice freenode jean \"I know you are here.\"")
+{
+}
+
+void ServerNoticeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 3)
+        throw std::invalid_argument("server-notice requires 3 arguments");
+
+    check(request(irccdctl, {
+        { "server",     args[0] },
+        { "target",     args[1] },
+        { "message",    args[2] }
+    }));
+}
+
+/*
+ * ServerPartCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerPartCli::ServerPartCli()
+    : Cli("server-part",
+          "leave a channel",
+          "server-part server channel [reason]",
+          "Leave the specified channel, the reason is optional.\n\n"
+          "Not all IRC servers support giving a reason to leave a channel, do not "
+          "specify it if this is a concern.\n\n"
+          "Example:\n"
+          "\tirccdctl server-part freenode #staff"
+          "\tirccdctl server-part freenode #botwar \"too noisy\"")
+{
+}
+
+void ServerPartCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    if (args.size() < 2)
+        throw std::invalid_argument("server-part requires at least 2 arguments");
+
+    auto object = nlohmann::json::object({
+        { "server",     args[0] },
+        { "channel",    args[1] }
+    });
+
+    if (args.size() >= 3)
+        object["reason"] = args[2];
+
+    check(request(irccdctl, object));
+}
+
+/*
+ * ServerReconnectCli.
+ * ------------------------------------------------------------------
+ */
+
+ServerReconnectCli::ServerReconnectCli()
+    : Cli("server-reconnect",
+          "force reconnection of a server",
+          "server-reconnect [server]",
+          "Force reconnection of one or all servers.\n\n"
+          "If server is not specified, all servers will try to reconnect.\n\n"
+          "Example:\n"
+          "\tirccdctl server-reconnect\n"
+          "\tirccdctl server-reconnect wanadoo")
+{
+}
+
+void ServerReconnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
+{
+    auto object = nlohmann::json::object({
+        { "command", "server-reconnect" }
+    });
+
+    if (args.size() >= 1)
+        object["server"] = args[0];
+
+    check(request(irccdctl, object));
+}
+
+} // !cli
+
 } // !irccd