changeset 488:7e273b7f4f92

Irccd: new coding style, closes #576
author David Demelier <markand@malikania.fr>
date Tue, 26 Sep 2017 17:18:47 +0200
parents beb6c638b841
children 349fe29d86d5
files irccd/main.cpp irccdctl/cli.cpp irccdctl/main.cpp libcommon/irccd/ini.cpp libcommon/irccd/ini.hpp libcommon/irccd/logger.cpp libcommon/irccd/logger.hpp libcommon/irccd/system.cpp libcommon/irccd/system.hpp libcommon/irccd/util.cpp libcommon/irccd/util.hpp libirccd-js/CMakeLists.txt libirccd-js/irccd/js_directory_module.cpp libirccd-js/irccd/js_directory_module.hpp libirccd-js/irccd/js_elapsed_timer_module.cpp libirccd-js/irccd/js_elapsed_timer_module.hpp libirccd-js/irccd/js_file_module.cpp libirccd-js/irccd/js_file_module.hpp libirccd-js/irccd/js_irccd_module.cpp libirccd-js/irccd/js_irccd_module.hpp libirccd-js/irccd/js_logger_module.cpp libirccd-js/irccd/js_logger_module.hpp libirccd-js/irccd/js_plugin.cpp libirccd-js/irccd/js_plugin.hpp libirccd-js/irccd/js_plugin_module.cpp libirccd-js/irccd/js_plugin_module.hpp libirccd-js/irccd/js_server_module.cpp libirccd-js/irccd/js_server_module.hpp libirccd-js/irccd/js_system_module.cpp libirccd-js/irccd/js_system_module.hpp libirccd-js/irccd/js_timer_module.cpp libirccd-js/irccd/js_timer_module.hpp libirccd-js/irccd/js_unicode_module.cpp libirccd-js/irccd/js_unicode_module.hpp libirccd-js/irccd/js_util_module.cpp libirccd-js/irccd/js_util_module.hpp libirccd-js/irccd/mod-directory.cpp libirccd-js/irccd/mod-directory.hpp libirccd-js/irccd/mod-elapsed-timer.cpp libirccd-js/irccd/mod-elapsed-timer.hpp libirccd-js/irccd/mod-file.cpp libirccd-js/irccd/mod-file.hpp libirccd-js/irccd/mod-irccd.cpp libirccd-js/irccd/mod-irccd.hpp libirccd-js/irccd/mod-logger.cpp libirccd-js/irccd/mod-logger.hpp libirccd-js/irccd/mod-plugin.cpp libirccd-js/irccd/mod-plugin.hpp libirccd-js/irccd/mod-server.cpp libirccd-js/irccd/mod-server.hpp libirccd-js/irccd/mod-system.cpp libirccd-js/irccd/mod-system.hpp libirccd-js/irccd/mod-timer.cpp libirccd-js/irccd/mod-timer.hpp libirccd-js/irccd/mod-unicode.cpp libirccd-js/irccd/mod-unicode.hpp libirccd-js/irccd/mod-util.cpp libirccd-js/irccd/mod-util.hpp libirccd-js/irccd/module.hpp libirccd-js/irccd/plugin-js.cpp libirccd-js/irccd/plugin-js.hpp libirccd-js/irccd/timer.cpp libirccd-js/irccd/timer.hpp libirccd-test/irccd/command-tester.cpp libirccd-test/irccd/command-tester.hpp libirccd-test/irccd/plugin-tester.cpp libirccd-test/irccd/plugin-tester.hpp libirccd-test/irccd/plugin_test.cpp libirccd-test/irccd/server-tester.cpp libirccd-test/irccd/server-tester.hpp libirccd/CMakeLists.txt libirccd/irccd/command.cpp libirccd/irccd/command.hpp libirccd/irccd/config.cpp libirccd/irccd/config.hpp libirccd/irccd/irccd.cpp libirccd/irccd/irccd.hpp libirccd/irccd/plugin-dynlib.hpp libirccd/irccd/plugin.cpp libirccd/irccd/plugin.hpp libirccd/irccd/rule.cpp libirccd/irccd/rule.hpp libirccd/irccd/server.cpp libirccd/irccd/server.hpp libirccd/irccd/service.cpp libirccd/irccd/service.hpp libirccd/irccd/transport.cpp libirccd/irccd/transport.hpp libirccdctl/irccd/client.cpp tests/cmd-plugin-config/main.cpp tests/cmd-plugin-info/main.cpp tests/cmd-plugin-list/main.cpp tests/cmd-plugin-load/main.cpp tests/cmd-plugin-reload/main.cpp tests/cmd-plugin-unload/main.cpp tests/cmd-rule-add/main.cpp tests/cmd-rule-edit/main.cpp tests/cmd-rule-info/main.cpp tests/cmd-rule-list/main.cpp tests/cmd-rule-move/main.cpp tests/cmd-rule-remove/main.cpp tests/cmd-server-cmode/main.cpp tests/cmd-server-cnotice/main.cpp tests/cmd-server-connect/main.cpp tests/cmd-server-disconnect/main.cpp tests/cmd-server-info/main.cpp tests/cmd-server-invite/main.cpp tests/cmd-server-join/main.cpp tests/cmd-server-kick/main.cpp tests/cmd-server-list/main.cpp tests/cmd-server-me/main.cpp tests/cmd-server-message/main.cpp tests/cmd-server-mode/main.cpp tests/cmd-server-nick/main.cpp tests/cmd-server-notice/main.cpp tests/cmd-server-part/main.cpp tests/cmd-server-reconnect/main.cpp tests/cmd-server-topic/main.cpp tests/js-elapsedtimer/main.cpp tests/js-file/main.cpp tests/js-irccd/main.cpp tests/js-logger/main.cpp tests/js-system/main.cpp tests/js-timer/main.cpp tests/js-unicode/main.cpp tests/js-util/main.cpp tests/js/main.cpp tests/logger/main.cpp tests/plugin-ask/main.cpp tests/plugin-auth/main.cpp tests/plugin-hangman/main.cpp tests/plugin-history/main.cpp tests/plugin-logger/main.cpp tests/plugin-plugin/main.cpp tests/rules/main.cpp tests/service-plugin/main.cpp tests/timer/main.cpp tests/util/main.cpp
diffstat 138 files changed, 8497 insertions(+), 8464 deletions(-) [+]
line wrap: on
line diff
--- a/irccd/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/irccd/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -44,18 +44,18 @@
 #include "irccd.hpp"
 
 #if defined(WITH_JS)
-#   include "mod-directory.hpp"
-#   include "mod-elapsed-timer.hpp"
-#   include "mod-file.hpp"
-#   include "mod-irccd.hpp"
-#   include "mod-logger.hpp"
-#   include "mod-plugin.hpp"
-#   include "mod-server.hpp"
-#   include "mod-system.hpp"
-#   include "mod-timer.hpp"
-#   include "mod-unicode.hpp"
-#   include "mod-util.hpp"
-#   include "plugin-js.hpp"
+#   include <js_directory_module.hpp>
+#   include <js_elapsed_timer_module.hpp>
+#   include <js_file_module.hpp>
+#   include <js_irccd_module.hpp>
+#   include <js_logger_module.hpp>
+#   include <js_plugin_module.hpp>
+#   include <js_server_module.hpp>
+#   include <js_system_module.hpp>
+#   include <js_timer_module.hpp>
+#   include <js_unicode_module.hpp>
+#   include <js_util_module.hpp>
+#   include "js_plugin.hpp"
 #endif
 
 using namespace fmt::literals;
@@ -64,11 +64,11 @@
 
 namespace {
 
-std::unique_ptr<Irccd> instance;
+std::unique_ptr<irccd::irccd> instance;
 
 void usage()
 {
-    std::cerr << "usage: " << sys::programName() << " [options...]\n\n";
+    std::cerr << "usage: " << sys::program_name() << " [options...]\n\n";
     std::cerr << "Available options:\n";
     std::cerr << "  -c, --config file       specify the configuration file\n";
     std::cerr << "  -f, --foreground        do not run as a daemon\n";
@@ -78,7 +78,7 @@
     std::exit(1);
 }
 
-void version(const option::Result &options)
+void version(const option::Result& options)
 {
     std::cout << IRCCD_VERSION << std::endl;
 
@@ -106,13 +106,13 @@
     instance->stop();
 }
 
-void init(int &argc, char **&argv)
+void init(int& argc, char**& argv)
 {
     // Needed for some components.
-    sys::setProgramName("irccd");
+    sys::set_program_name("irccd");
 
     // Default logging to console.
-    log::setVerbose(false);
+    log::set_verbose(false);
 
     // Register some signals.
     signal(SIGINT, stop);
@@ -130,7 +130,7 @@
     ++ argv;
 }
 
-option::Result parse(int &argc, char **&argv)
+option::Result parse(int& argc, char**& argv)
 {
     // Parse command line options.
     option::Result result;
@@ -150,7 +150,7 @@
 
         result = option::read(argc, argv, options);
 
-        for (const auto &pair : result) {
+        for (const auto& pair : result) {
             if (pair.first == "-h" || pair.first == "--help")
                 usage();
                 // NOTREACHED
@@ -158,32 +158,32 @@
                 version(result);
                 // NOTREACHED
             if (pair.first == "-v" || pair.first == "--verbose")
-                log::setVerbose(true);
+                log::set_verbose(true);
         }
-    } catch (const std::exception &ex) {
-        log::warning() << sys::programName() << ": " << ex.what() << std::endl;
+    } catch (const std::exception& ex) {
+        log::warning() << sys::program_name() << ": " << ex.what() << std::endl;
         usage();
     }
 
     return result;
 }
 
-Config open(const option::Result &result)
+config open(const option::Result& result)
 {
     auto it = result.find("-c");
 
     if (it != result.end() || (it = result.find("--config")) != result.end()) {
         try {
-            return Config(it->second);
+            return config(it->second);
         } catch (const std::exception &ex) {
             throw std::runtime_error("{}: {}"_format(it->second, ex.what()));
         }
     }
 
-    return Config::find();
+    return config::find();
 }
 
-void loadPid(const std::string &path)
+void load_pid(const std::string& path)
 {
     if (path.empty())
         return;
@@ -200,12 +200,12 @@
 #else
         throw std::runtime_error("pidfile option not supported on this platform");
 #endif
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         log::warning() << "irccd: " << ex.what() << std::endl;
     }
 }
 
-void loadGid(const std::string gid)
+void load_gid(const std::string& gid)
 {
     try {
         if (!gid.empty())
@@ -214,12 +214,12 @@
 #else
             throw std::runtime_error(" gid option not supported on this platform");
 #endif
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         log::warning() << "irccd: " << ex.what() << std::endl;
     }
 }
 
-void loadUid(const std::string &uid)
+void load_uid(const std::string& uid)
 {
     try {
         if (!uid.empty())
@@ -228,12 +228,12 @@
 #else
             throw std::runtime_error("uid option not supported on this platform");
 #endif
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         log::warning() << "irccd: " << ex.what() << std::endl;
     }
 }
 
-void loadForeground(bool foreground, const option::Result &options)
+void load_foreground(bool foreground, const option::Result& options)
 {
     try {
 #if defined(HAVE_DAEMON)
@@ -243,12 +243,12 @@
         if (options.count("-f") > 0 || options.count("--foreground") > 0 || foreground)
             throw std::runtime_error("foreground option not supported on this platform");
 #endif
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         log::warning() << "irccd: " << ex.what() << std::endl;
     }
 }
 
-void load(const Config &config, const option::Result &options)
+void load(const config& config, const option::Result& options)
 {
     /*
      * Order matters, please be careful when changing this.
@@ -258,95 +258,95 @@
      */
 
     // [logs] and [format] sections.
-    config.loadLogs();
-    config.loadFormats();
+    config.load_logs();
+    config.load_formats();
 
     // Show message here to use the formats.
     log::info() << "irccd: using " << config.path() << std::endl;
 
     // [general] section.
-    loadPid(config.pidfile());
-    loadGid(config.gid());
-    loadUid(config.uid());
-    loadForeground(config.isForeground(), options);
+    load_pid(config.pidfile());
+    load_gid(config.gid());
+    load_uid(config.uid());
+    load_foreground(config.is_foreground(), options);
 
     // [transport]
-    for (const auto &transport : config.loadTransports())
+    for (const auto& transport : config.load_transports())
         instance->transports().add(transport);
 
     // [server] section.
-    for (const auto &server : config.loadServers())
+    for (const auto& server : config.load_servers())
         instance->servers().add(server);
 
     // [rule] section.
-    for (const auto &rule : config.loadRules())
+    for (const auto& rule : config.load_rules())
         instance->rules().add(rule);
 
     // [plugin] section.
-    config.loadPlugins(*instance);
+    config.load_plugins(*instance);
 }
 
 } // !namespace
 
-int main(int argc, char **argv)
+int main(int argc, char** argv)
 {
     init(argc, argv);
 
     option::Result options = parse(argc, argv);
 
-    instance = std::make_unique<Irccd>();
-    instance->commands().add(std::make_unique<command::PluginConfigCommand>());
-    instance->commands().add(std::make_unique<command::PluginInfoCommand>());
-    instance->commands().add(std::make_unique<command::PluginListCommand>());
-    instance->commands().add(std::make_unique<command::PluginLoadCommand>());
-    instance->commands().add(std::make_unique<command::PluginReloadCommand>());
-    instance->commands().add(std::make_unique<command::PluginUnloadCommand>());
-    instance->commands().add(std::make_unique<command::ServerChannelModeCommand>());
-    instance->commands().add(std::make_unique<command::ServerChannelNoticeCommand>());
-    instance->commands().add(std::make_unique<command::ServerConnectCommand>());
-    instance->commands().add(std::make_unique<command::ServerDisconnectCommand>());
-    instance->commands().add(std::make_unique<command::ServerInfoCommand>());
-    instance->commands().add(std::make_unique<command::ServerInviteCommand>());
-    instance->commands().add(std::make_unique<command::ServerJoinCommand>());
-    instance->commands().add(std::make_unique<command::ServerKickCommand>());
-    instance->commands().add(std::make_unique<command::ServerListCommand>());
-    instance->commands().add(std::make_unique<command::ServerMeCommand>());
-    instance->commands().add(std::make_unique<command::ServerMessageCommand>());
-    instance->commands().add(std::make_unique<command::ServerModeCommand>());
-    instance->commands().add(std::make_unique<command::ServerNickCommand>());
-    instance->commands().add(std::make_unique<command::ServerNoticeCommand>());
-    instance->commands().add(std::make_unique<command::ServerPartCommand>());
-    instance->commands().add(std::make_unique<command::ServerReconnectCommand>());
-    instance->commands().add(std::make_unique<command::ServerTopicCommand>());
-    instance->commands().add(std::make_unique<command::RuleAddCommand>());
-    instance->commands().add(std::make_unique<command::RuleEditCommand>());
-    instance->commands().add(std::make_unique<command::RuleInfoCommand>());
-    instance->commands().add(std::make_unique<command::RuleListCommand>());
-    instance->commands().add(std::make_unique<command::RuleMoveCommand>());
-    instance->commands().add(std::make_unique<command::RuleRemoveCommand>());
+    instance = std::make_unique<irccd::irccd>();
+    instance->commands().add(std::make_unique<plugin_config_command>());
+    instance->commands().add(std::make_unique<plugin_info_command>());
+    instance->commands().add(std::make_unique<plugin_list_command>());
+    instance->commands().add(std::make_unique<plugin_load_command>());
+    instance->commands().add(std::make_unique<plugin_reload_command>());
+    instance->commands().add(std::make_unique<plugin_unload_command>());
+    instance->commands().add(std::make_unique<server_channel_mode_command>());
+    instance->commands().add(std::make_unique<server_channel_notice_command>());
+    instance->commands().add(std::make_unique<server_connect_command>());
+    instance->commands().add(std::make_unique<server_disconnect_command>());
+    instance->commands().add(std::make_unique<server_info_command>());
+    instance->commands().add(std::make_unique<server_invite_command>());
+    instance->commands().add(std::make_unique<server_join_command>());
+    instance->commands().add(std::make_unique<server_kick_command>());
+    instance->commands().add(std::make_unique<server_list_command>());
+    instance->commands().add(std::make_unique<server_me_command>());
+    instance->commands().add(std::make_unique<server_message_command>());
+    instance->commands().add(std::make_unique<server_mode_command>());
+    instance->commands().add(std::make_unique<server_nick_command>());
+    instance->commands().add(std::make_unique<server_notice_command>());
+    instance->commands().add(std::make_unique<server_part_command>());
+    instance->commands().add(std::make_unique<server_reconnect_command>());
+    instance->commands().add(std::make_unique<server_topic_command>());
+    instance->commands().add(std::make_unique<rule_add_command>());
+    instance->commands().add(std::make_unique<rule_edit_command>());
+    instance->commands().add(std::make_unique<rule_info_command>());
+    instance->commands().add(std::make_unique<rule_list_command>());
+    instance->commands().add(std::make_unique<rule_move_command>());
+    instance->commands().add(std::make_unique<rule_remove_command>());
 
     // Load Javascript API and plugin loader.
 #if defined(WITH_JS)
-    auto loader = std::make_unique<JsPluginLoader>(*instance);
+    auto loader = std::make_unique<js_plugin_loader>(*instance);
 
-    loader->addModule(std::make_unique<IrccdModule>());
-    loader->addModule(std::make_unique<DirectoryModule>());
-    loader->addModule(std::make_unique<ElapsedTimerModule>());
-    loader->addModule(std::make_unique<FileModule>());
-    loader->addModule(std::make_unique<LoggerModule>());
-    loader->addModule(std::make_unique<PluginModule>());
-    loader->addModule(std::make_unique<ServerModule>());
-    loader->addModule(std::make_unique<SystemModule>());
-    loader->addModule(std::make_unique<TimerModule>());
-    loader->addModule(std::make_unique<UnicodeModule>());
-    loader->addModule(std::make_unique<UtilModule>());
+    loader->add_module(std::make_unique<js_irccd_module>());
+    loader->add_module(std::make_unique<js_directory_module>());
+    loader->add_module(std::make_unique<js_elapsed_timer_module>());
+    loader->add_module(std::make_unique<js_file_module>());
+    loader->add_module(std::make_unique<js_logger_module>());
+    loader->add_module(std::make_unique<js_plugin_module>());
+    loader->add_module(std::make_unique<js_server_module>());
+    loader->add_module(std::make_unique<js_system_module>());
+    loader->add_module(std::make_unique<js_timer_module>());
+    loader->add_module(std::make_unique<js_unicode_module>());
+    loader->add_module(std::make_unique<js_util_module>());
 
     instance->plugins().addLoader(std::move(loader));
 #endif
 
     try {
         load(open(options), options);
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         log::warning() << "error: " << ex.what() << std::endl;
         return 1;
     }
--- a/irccdctl/cli.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/irccdctl/cli.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -40,8 +40,8 @@
 
 void Cli::check(const nlohmann::json &response)
 {
-    if (!util::json::getBool(response, "status", false)) {
-        auto error = util::json::getString(response, "error");
+    if (!util::json::get_bool(response, "status", false)) {
+        auto error = util::json::get_string(response, "error");
 
         if (error.empty())
             throw std::runtime_error("command failed with an unknown error");
@@ -78,7 +78,7 @@
 
     if (!msg.is_object())
         throw std::runtime_error("no response received");
-    if (util::json::getString(msg, "command") != m_name)
+    if (util::json::get_string(msg, "command") != m_name)
         throw std::runtime_error("unexpected command result received");
 
     check(msg);
@@ -187,10 +187,10 @@
     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;
+    std::cout << "Author         : " << util::json::get_string(result, "author") << std::endl;
+    std::cout << "License        : " << util::json::get_string(result, "license") << std::endl;
+    std::cout << "Summary        : " << util::json::get_string(result, "summary") << std::endl;
+    std::cout << "Version        : " << util::json::get_string(result, "version") << std::endl;
 }
 
 /*
@@ -407,7 +407,7 @@
     });
 
     if (copy.size() == 3) {
-        if (!util::isNumber(copy[2]))
+        if (!util::is_int(copy[2]))
             throw std::invalid_argument("invalid port number");
 
         object["port"] = std::stoi(copy[2]);
@@ -909,9 +909,9 @@
 
     // Index.
     if (result.count("-i") > 0)
-        json["index"] = util::toNumber<unsigned>(result.find("-i")->second);
+        json["index"] = util::to_number<unsigned>(result.find("-i")->second);
     if (result.count("--index") > 0)
-        json["index"] = util::toNumber<unsigned>(result.find("--index")->second);
+        json["index"] = util::to_number<unsigned>(result.find("--index")->second);
 
     // And action.
     if (copy[0] != "accept" && copy[0] != "drop")
@@ -1013,7 +1013,7 @@
     }
 
     // Index.
-    json["index"] = util::toNumber<unsigned>(copy[0]);
+    json["index"] = util::to_number<unsigned>(copy[0]);
 
     check(request(irccdctl, json));
 }
--- a/irccdctl/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/irccdctl/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -51,7 +51,7 @@
     bool first = true;
 
     for (const auto &cmd : commands) {
-        log::warning() << (first ? "usage: " : "       ") << sys::programName() << " "
+        log::warning() << (first ? "usage: " : "       ") << sys::program_name() << " "
                        << cmd->usage() << std::endl;
         first = false;
     }
@@ -61,7 +61,7 @@
 
 void help()
 {
-    log::warning() << "usage: " << sys::programName() << " [options...] <command> [command-options...] [command-args...]\n\n";
+    log::warning() << "usage: " << sys::program_name() << " [options...] <command> [command-options...] [command-args...]\n\n";
     log::warning() << "General options:\n";
     log::warning() << "\t-c, --config file\tspecify the configuration file\n";
     log::warning() << "\t    --help\t\tshow this help\n";
@@ -78,7 +78,7 @@
         log::warning() << "\t" << std::left << std::setw(32)
                        << cmd->name() << cmd->summary() << std::endl;
 
-    log::warning() << "\nFor more information on a command, type " << sys::programName() << " help <command>" << std::endl;
+    log::warning() << "\nFor more information on a command, type " << sys::program_name() << " help <command>" << std::endl;
     std::exit(1);
 }
 
@@ -91,7 +91,7 @@
     if (it == commands.end()) {
         log::warning() << "no command named " << command << std::endl;
     } else {
-        log::warning() << "usage: " << sys::programName() << " " << (*it)->usage() << "\n" << std::endl;
+        log::warning() << "usage: " << sys::program_name() << " " << (*it)->usage() << "\n" << std::endl;
         log::warning() << (*it)->help() << std::endl;
     }
 
@@ -116,9 +116,9 @@
  * domain = "ipv4 or ipv6" (Optional, default: ipv4)
  * ssl = true | false
  */
-void readConnectIp(const ini::Section &sc)
+void readConnectIp(const ini::section &sc)
 {
-    ini::Section::const_iterator it;
+    ini::section::const_iterator it;
     std::string host, port;
 
     if ((it = sc.find("host")) == sc.end())
@@ -145,7 +145,7 @@
 
     address = net::resolveOne(host, port, domain, SOCK_STREAM);
 
-    if ((it = sc.find("ssl")) != sc.end() && util::isBoolean(it->value()))
+    if ((it = sc.find("ssl")) != sc.end() && util::is_boolean(it->value()))
 #if defined(WITH_SSL)
         client = std::make_unique<TlsClient>();
 #else
@@ -165,7 +165,7 @@
  * type = "unix"
  * path = "path to socket file"
  */
-void readConnectLocal(const ini::Section &sc)
+void readConnectLocal(const ini::section &sc)
 {
 #if !defined(IRCCD_SYSTEM_WINDOWS)
     auto it = sc.find("path");
@@ -188,7 +188,7 @@
  *
  * Generic function for reading the [connect] section.
  */
-void readConnect(const ini::Section &sc)
+void readConnect(const ini::section &sc)
 {
     auto it = sc.find("type");
 
@@ -218,12 +218,12 @@
  * [general]
  * verbose = true
  */
-void readGeneral(const ini::Section &sc)
+void readGeneral(const ini::section &sc)
 {
     auto verbose = sc.find("verbose");
 
     if (verbose != sc.end())
-        log::setVerbose(util::isBoolean(verbose->value()));
+        log::set_verbose(util::is_boolean(verbose->value()));
 }
 
 /*
@@ -236,7 +236,7 @@
  * cmd1 = ( "command", "arg1, "...", "argn" )
  * cmd2 = ( "command", "arg1, "...", "argn" )
  */
-Alias readAlias(const ini::Section &sc, const std::string &name)
+Alias readAlias(const ini::section &sc, const std::string &name)
 {
     Alias alias(name);
 
@@ -265,8 +265,8 @@
 void read(const std::string &path)
 {
     try {
-        ini::Document doc = ini::readFile(path);
-        ini::Document::const_iterator it;
+        ini::document doc = ini::read_file(path);
+        ini::document::const_iterator it;
 
         if (!client && (it = doc.find("connect")) != doc.end())
             readConnect(*it);
@@ -414,10 +414,10 @@
         }
 
         if (result.count("-v") != 0 || result.count("--verbose") != 0) {
-            log::setVerbose(true);
+            log::set_verbose(true);
         }
     } catch (const std::exception &ex) {
-        log::warning("{}: {}"_format(sys::programName(), ex.what()));
+        log::warning("{}: {}"_format(sys::program_name(), ex.what()));
         usage();
     }
 
@@ -494,7 +494,7 @@
 
 void init(int &argc, char **&argv)
 {
-    sys::setProgramName("irccdctl");
+    sys::set_program_name("irccdctl");
     net::init();
 
     --argc;
@@ -569,7 +569,7 @@
             }
         }
     } catch (const std::exception &ex) {
-        log::warning() << sys::programName() << ": " << ex.what() << std::endl;
+        log::warning() << sys::program_name() << ": " << ex.what() << std::endl;
         std::exit(1);
     }
 
@@ -586,7 +586,7 @@
     }
 
     if (!client) {
-        log::warning("{}: no connection specified"_format(sys::programName()));
+        log::warning("{}: no connection specified"_format(sys::program_name()));
         std::exit(1);
     }
 
@@ -611,6 +611,6 @@
     try {
         exec(args);
     } catch (const std::exception &ex) {
-        std::cerr << sys::programName() << ": unrecoverable error: " << ex.what() << std::endl;
+        std::cerr << sys::program_name() << ": unrecoverable error: " << ex.what() << std::endl;
     }
 }
--- a/libcommon/irccd/ini.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/ini.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -26,25 +26,21 @@
 
 // for PathIsRelative.
 #if defined(_WIN32)
-#   if !defined(WIN32_LEAN_AND_MEAN)
-#       define WIN32_LEAN_AND_MEAN
-#   endif
-
-#   include <shlwapi.h>
+#  include <Shlwapi.h>
 #endif
 
 #include "ini.hpp"
 
 namespace irccd {
 
+namespace ini {
+
 namespace {
 
-using namespace ini;
+using stream_iterator = std::istreambuf_iterator<char>;
+using token_iterator = std::vector<token>::const_iterator;
 
-using StreamIterator = std::istreambuf_iterator<char>;
-using TokenIterator = std::vector<Token>::const_iterator;
-
-inline bool isAbsolute(const std::string &path) noexcept
+inline bool is_absolute(const std::string& path) noexcept
 {
 #if defined(_WIN32)
     return !PathIsRelative(path.c_str());
@@ -53,28 +49,28 @@
 #endif
 }
 
-inline bool isQuote(char c) noexcept
+inline bool is_quote(char c) noexcept
 {
     return c == '\'' || c == '"';
 }
 
-inline bool isSpace(char c) noexcept
+inline bool is_space(char c) noexcept
 {
     // Custom version because std::isspace includes \n as space.
     return c == ' ' || c == '\t';
 }
 
-inline bool isList(char c) noexcept
+inline bool is_list(char c) noexcept
 {
     return c == '(' || c == ')' || c == ',';
 }
 
-inline bool isReserved(char c) noexcept
+inline bool is_reserved(char c) noexcept
 {
-    return isList(c) || isQuote(c) || c == '[' || c == ']' || c == '@' || c == '#' || c == '=';
+    return is_list(c) || is_quote(c) || c == '[' || c == ']' || c == '@' || c == '#' || c == '=';
 }
 
-void analyseLine(int &line, int &column, StreamIterator &it) noexcept
+void analyse_line(int& line, int& column, stream_iterator& it) noexcept
 {
     assert(*it == '\n');
 
@@ -83,7 +79,7 @@
     column = 0;
 }
 
-void analyseComment(int &column, StreamIterator &it, StreamIterator end) noexcept
+void analyse_comment(int& column, stream_iterator& it, stream_iterator end) noexcept
 {
     assert(*it == '#');
 
@@ -93,36 +89,36 @@
     }
 }
 
-void analyseSpaces(int &column, StreamIterator &it, StreamIterator end) noexcept
+void analyse_spaces(int& column, stream_iterator& it, stream_iterator end) noexcept
 {
-    assert(isSpace(*it));
+    assert(is_space(*it));
 
-    while (it != end && isSpace(*it)) {
+    while (it != end && is_space(*it)) {
         ++ column;
         ++ it;
     }
 }
 
-void analyseList(Tokens &list, int line, int &column, StreamIterator &it) noexcept
+void analyse_list(tokens& list, int line, int& column, stream_iterator& it) noexcept
 {
-    assert(isList(*it));
+    assert(is_list(*it));
 
     switch (*it++) {
     case '(':
-        list.emplace_back(Token::ListBegin, line, column++);
+        list.emplace_back(token::list_begin, line, column++);
         break;
     case ')':
-        list.emplace_back(Token::ListEnd, line, column++);
+        list.emplace_back(token::list_end, line, column++);
         break;
     case ',':
-        list.emplace_back(Token::Comma, line, column++);
+        list.emplace_back(token::comma, line, column++);
         break;
     default:
         break;
     }
 }
 
-void analyseSection(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end)
+void analyse_section(tokens& list, int& line, int& column, stream_iterator& it, stream_iterator end)
 {
     assert(*it == '[');
 
@@ -132,35 +128,39 @@
     // Read section name.
     ++ it;
     while (it != end && *it != ']') {
-        if (*it == '\n')
-            throw Error(line, column, "section not terminated, missing ']'");
-        if (isReserved(*it))
-            throw Error(line, column, "section name expected after '[', got '" + std::string(1, *it) + "'");
+        if (*it == '\n') {
+            throw exception(line, column, "section not terminated, missing ']'");
+        }
+        if (is_reserved(*it)) {
+            throw exception(line, column, "section name expected after '[', got '" + std::string(1, *it) + "'");
+        }
 
         ++ column;
         value += *it++;
     }
 
-    if (it == end)
-        throw Error(line, column, "section name expected after '[', got <EOF>");
-    if (value.empty())
-        throw Error(line, column, "empty section name");
+    if (it == end) {
+        throw exception(line, column, "section name expected after '[', got <EOF>");
+    }
+    if (value.empty()) {
+        throw exception(line, column, "empty section name");
+    }
 
     // Remove ']'.
     ++ it;
 
-    list.emplace_back(Token::Section, line, save, std::move(value));
+    list.emplace_back(token::section, line, save, std::move(value));
 }
 
-void analyseAssign(Tokens &list, int &line, int &column, StreamIterator &it)
+void analyse_assign(tokens& list, int& line, int& column, stream_iterator& it)
 {
     assert(*it == '=');
 
-    list.push_back({ Token::Assign, line, column++ });
+    list.push_back({ token::assign, line, column++ });
     ++ it;
 }
 
-void analyseQuotedWord(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end)
+void analyse_quoted_word(tokens& list, int& line, int& column, stream_iterator& it, stream_iterator end)
 {
     std::string value;
     int save = column;
@@ -172,31 +172,32 @@
         value += *it++;
     }
 
-    if (it == end)
-        throw Error(line, column, "undisclosed '" + std::string(1, quote) + "', got <EOF>");
+    if (it == end) {
+        throw exception(line, column, "undisclosed '" + std::string(1, quote) + "', got <EOF>");
+    }
 
     // Remove quote.
     ++ it;
 
-    list.push_back({ Token::QuotedWord, line, save, std::move(value) });
+    list.push_back({ token::quoted_word, line, save, std::move(value) });
 }
 
-void analyseWord(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end)
+void analyse_word(tokens& list, int& line, int& column, stream_iterator& it, stream_iterator end)
 {
-    assert(!isReserved(*it));
+    assert(!is_reserved(*it));
 
     std::string value;
     int save = column;
 
-    while (it != end && !std::isspace(*it) && !isReserved(*it)) {
+    while (it != end && !std::isspace(*it) && !is_reserved(*it)) {
         ++ column;
         value += *it++;
     }
 
-    list.push_back({ Token::Word, line, save, std::move(value) });
+    list.push_back({ token::word, line, save, std::move(value) });
 }
 
-void analyseInclude(Tokens &list, int &line, int &column, StreamIterator &it, StreamIterator end)
+void analyse_include(tokens& list, int& line, int& column, stream_iterator& it, stream_iterator end)
 {
     assert(*it == '@');
 
@@ -205,117 +206,127 @@
 
     // Read include.
     ++ it;
-    while (it != end && !isSpace(*it)) {
+    while (it != end && !is_space(*it)) {
         ++ column;
         include += *it++;
     }
 
-    if (include != "include")
-        throw Error(line, column, "expected include after '@' token");
+    if (include != "include") {
+        throw exception(line, column, "expected include after '@' token");
+    }
 
-    list.push_back({ Token::Include, line, save });
+    list.push_back({ token::include, line, save });
 }
 
-void parseOptionValueSimple(Option &option, TokenIterator &it)
+void parse_option_value_simple(option& option, token_iterator& it)
 {
-    assert(it->type() == Token::Word || it->type() == Token::QuotedWord);
+    assert(it->type() == token::word || it->type() == token::quoted_word);
 
     option.push_back((it++)->value());
 }
 
-void parseOptionValueList(Option &option, TokenIterator &it, TokenIterator end)
+void parse_option_value_list(option& option, token_iterator& it, token_iterator end)
 {
-    assert(it->type() == Token::ListBegin);
+    assert(it->type() == token::list_begin);
 
-    TokenIterator save = it++;
+    token_iterator save = it++;
 
-    while (it != end && it->type() != Token::ListEnd) {
+    while (it != end && it->type() != token::list_end) {
         switch (it->type()) {
-        case Token::Comma:
+        case token::comma:
             // Previous must be a word.
-            if (it[-1].type() != Token::Word && it[-1].type() != Token::QuotedWord)
-                throw Error(it->line(), it->column(), "unexpected comma after '" + it[-1].value() + "'");
+            if (it[-1].type() != token::word && it[-1].type() != token::quoted_word) {
+                throw exception(it->line(), it->column(), "unexpected comma after '" + it[-1].value() + "'");
+            }
 
             ++ it;
             break;
-        case Token::Word:
-        case Token::QuotedWord:
+        case token::word:
+        case token::quoted_word:
             option.push_back((it++)->value());
             break;
         default:
-            throw Error(it->line(), it->column(), "unexpected '" + it[-1].value() + "' in list construct");
+            throw exception(it->line(), it->column(), "unexpected '" + it[-1].value() + "' in list construct");
             break;
         }
     }
 
-    if (it == end)
-        throw Error(save->line(), save->column(), "unterminated list construct");
+    if (it == end) {
+        throw exception(save->line(), save->column(), "unterminated list construct");
+    }
 
     // Remove ).
     ++ it;
 }
 
-void parseOption(Section &sc, TokenIterator &it, TokenIterator end)
+void parse_option(section& sc, token_iterator& it, token_iterator end)
 {
-    Option option(it->value());
-
-    TokenIterator save = it;
+    option option(it->value());
+    token_iterator save(it);
 
     // No '=' or something else?
-    if (++it == end)
-        throw Error(save->line(), save->column(), "expected '=' assignment, got <EOF>");
-    if (it->type() != Token::Assign)
-        throw Error(it->line(), it->column(), "expected '=' assignment, got " + it->value());
+    if (++it == end) {
+        throw exception(save->line(), save->column(), "expected '=' assignment, got <EOF>");
+    }
+    if (it->type() != token::assign) {
+        throw exception(it->line(), it->column(), "expected '=' assignment, got " + it->value());
+    }
 
     // Empty options are allowed so just test for words.
     if (++it != end) {
-        if (it->type() == Token::Word || it->type() == Token::QuotedWord)
-            parseOptionValueSimple(option, it);
-        else if (it->type() == Token::ListBegin)
-            parseOptionValueList(option, it, end);
+        if (it->type() == token::word || it->type() == token::quoted_word) {
+            parse_option_value_simple(option, it);
+        } else if (it->type() == token::list_begin) {
+            parse_option_value_list(option, it, end);
+        }
     }
 
     sc.push_back(std::move(option));
 }
 
-void parseInclude(Document &doc, const std::string &path, TokenIterator &it, TokenIterator end)
+void parse_include(document& doc, const std::string& path, token_iterator& it, token_iterator end)
 {
-    TokenIterator save = it;
+    token_iterator save(it);
 
-    if (++it == end)
-        throw Error(save->line(), save->column(), "expected file name after '@include' statement, got <EOF>");
-    if (it->type() != Token::Word && it->type() != Token::QuotedWord)
-        throw Error(it->line(), it->column(), "expected file name after '@include' statement, got " + it->value());
+    if (++it == end) {
+        throw exception(save->line(), save->column(), "expected file name after '@include' statement, got <EOF>");
+    }
+    if (it->type() != token::word && it->type() != token::quoted_word) {
+        throw exception(it->line(), it->column(), "expected file name after '@include' statement, got " + it->value());
+    }
 
     std::string value = (it++)->value();
     std::string file;
 
-    if (!isAbsolute(value))
+    if (!is_absolute(value)) {
 #if defined(_WIN32)
         file = path + "\\" + value;
 #else
         file = path + "/" + value;
 #endif
-    else
+    } else {
         file = value;
+    }
 
-    for (const auto &sc : readFile(file))
+    for (const auto& sc : read_file(file)) {
         doc.push_back(sc);
+    }
 }
 
-void parseSection(Document &doc, TokenIterator &it, TokenIterator end)
+void parse_section(document& doc, token_iterator& it, token_iterator end)
 {
-    Section sc(it->value());
+    section sc(it->value());
 
     // Skip [section].
     ++ it;
 
     // Read until next section.
-    while (it != end && it->type() != Token::Section) {
-        if (it->type() != Token::Word)
-            throw Error(it->line(), it->column(), "unexpected token '" + it->value() + "' in section definition");
+    while (it != end && it->type() != token::section) {
+        if (it->type() != token::word) {
+            throw exception(it->line(), it->column(), "unexpected token '" + it->value() + "' in section definition");
+        }
 
-        parseOption(sc, it, end);
+        parse_option(sc, it, end);
     }
 
     doc.push_back(std::move(sc));
@@ -323,96 +334,98 @@
 
 } // !namespace
 
-namespace ini {
-
-Tokens analyse(std::istreambuf_iterator<char> it, std::istreambuf_iterator<char> end)
+tokens analyse(std::istreambuf_iterator<char> it, std::istreambuf_iterator<char> end)
 {
-    Tokens list;
+    tokens list;
     int line = 1;
     int column = 0;
 
     while (it != end) {
-        if (*it == '\n')
-            analyseLine(line, column, it);
-        else if (*it == '#')
-            analyseComment(column, it, end);
-        else if (*it == '[')
-            analyseSection(list, line, column, it, end);
-        else if (*it == '=')
-            analyseAssign(list, line, column, it);
-        else if (isSpace(*it))
-            analyseSpaces(column, it, end);
-        else if (*it == '@')
-            analyseInclude(list, line, column, it, end);
-        else if (isQuote(*it))
-            analyseQuotedWord(list, line, column, it, end);
-        else if (isList(*it))
-            analyseList(list, line, column, it);
-        else
-            analyseWord(list, line, column, it, end);
+        if (*it == '\n') {
+            analyse_line(line, column, it);
+        } else if (*it == '#') {
+            analyse_comment(column, it, end);
+        } else if (*it == '[') {
+            analyse_section(list, line, column, it, end);
+        } else if (*it == '=') {
+            analyse_assign(list, line, column, it);
+        } else if (is_space(*it)) {
+            analyse_spaces(column, it, end);
+        } else if (*it == '@') {
+            analyse_include(list, line, column, it, end);
+        } else if (is_quote(*it)) {
+            analyse_quoted_word(list, line, column, it, end);
+        } else if (is_list(*it)) {
+            analyse_list(list, line, column, it);
+        } else {
+            analyse_word(list, line, column, it, end);
+        }
     }
 
     return list;
 }
 
-Tokens analyse(std::istream &stream)
+tokens analyse(std::istream& stream)
 {
     return analyse(std::istreambuf_iterator<char>(stream), {});
 }
 
-Document parse(const Tokens &tokens, const std::string &path)
+document parse(const tokens& tokens, const std::string& path)
 {
-    Document doc;
-    TokenIterator it = tokens.cbegin();
-    TokenIterator end = tokens.cend();
+    document doc;
+    token_iterator it = tokens.cbegin();
+    token_iterator end = tokens.cend();
 
     while (it != end) {
         switch (it->type()) {
-        case Token::Include:
-            parseInclude(doc, path, it, end);
+        case token::include:
+            parse_include(doc, path, it, end);
             break;
-        case Token::Section:
-            parseSection(doc, it, end);
+        case token::section:
+            parse_section(doc, it, end);
             break;
         default:
-            throw Error(it->line(), it->column(), "unexpected '" + it->value() + "' on root document");
+            throw exception(it->line(), it->column(), "unexpected '" + it->value() + "' on root document");
         }
     }
 
     return doc;
 }
 
-Document readFile(const std::string &filename)
+document read_file(const std::string& filename)
 {
     // Get parent path.
     auto parent = filename;
     auto pos = parent.find_last_of("/\\");
 
-    if (pos != std::string::npos)
+    if (pos != std::string::npos) {
         parent.erase(pos);
-    else
+    } else {
         parent = ".";
+    }
 
     std::ifstream input(filename);
 
-    if (!input)
-        throw Error(0, 0, std::strerror(errno));
+    if (!input) {
+        throw exception(0, 0, std::strerror(errno));
+    }
 
     return parse(analyse(input), parent);
 }
 
-Document readString(const std::string &buffer)
+document read_string(const std::string& buffer)
 {
     std::istringstream iss(buffer);
 
     return parse(analyse(iss));
 }
 
-void dump(const Tokens &tokens)
+void dump(const tokens& tokens)
 {
-    for (const Token &token: tokens)
+    for (const token& token: tokens) {
         // TODO: add better description
         std::cout << token.line() << ":" << token.column() << ": " << token.value() << std::endl;
+    }
 }
 
 } // !ini
--- a/libcommon/irccd/ini.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/ini.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,13 +16,14 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef IRCCD_INI_HPP
-#define IRCCD_INI_HPP
+#ifndef INI_HPP
+#define INI_HPP
 
 /**
  * \file ini.hpp
  * \brief Extended .ini file parser.
  * \author David Demelier <markand@malikania.fr>
+ * \version 1.0.0
  */
 
 /**
@@ -42,7 +43,8 @@
  *   - an option **must** always be defined in a section,
  *   - empty options must be surrounded by quotes,
  *   - lists can not includes trailing commas,
- *   - include statement must always be at the beginning of files (in no sections),
+ *   - include statement must always be at the beginning of files
+ *     (in no sections),
  *   - comments starts with # until the end of line,
  *   - options with spaces **must** use quotes.
  *
@@ -57,7 +59,8 @@
  *
  * # Redefinition
  *
- * Sections can be redefined multiple times and are kept the order they are seen.
+ * Sections can be redefined multiple times and are kept the order they are
+ * seen.
  *
  * ````ini
  * [section]
@@ -67,7 +70,7 @@
  * value = "2"
  * ````
  *
- * The ini::Document object will contains two ini::Section.
+ * The ini::document object will contains two ini::Section.
  *
  * # Lists
  *
@@ -86,8 +89,8 @@
  *
  * # Include statement
  *
- * You can split a file into several pieces, if the include statement contains a relative path, the path will be relative
- * to the current file being parsed.
+ * You can split a file into several pieces, if the include statement contains a
+ * relative path, the path will be relative to the current file being parsed.
  *
  * You **must** use the include statement before any section.
  *
@@ -103,6 +106,32 @@
  * ````
  */
 
+/**
+ * \cond INI_HIDDEN_SYMBOLS
+ */
+
+#if !defined(IRCCD_EXPORT)
+#   if defined(INI_DLL)
+#       if defined(_WIN32)
+#           if defined(INI_BUILDING_DLL)
+#               define IRCCD_EXPORT __declspec(dllexport)
+#           else
+#               define IRCCD_EXPORT __declspec(dllimport)
+#           endif
+#       else
+#           define IRCCD_EXPORT
+#       endif
+#   else
+#       define IRCCD_EXPORT
+#   endif
+#endif
+
+/**
+ * \endcond
+ */
+
+#include <sysconfig.hpp>
+
 #include <algorithm>
 #include <cassert>
 #include <exception>
@@ -110,8 +139,6 @@
 #include <string>
 #include <vector>
 
-#include "sysconfig.hpp"
-
 namespace irccd {
 
 /**
@@ -119,16 +146,16 @@
  */
 namespace ini {
 
-class Document;
+class document;
 
 /**
- * \brief Error in a file.
+ * \brief exception in a file.
  */
-class Error : public std::exception {
+class exception : public std::exception {
 private:
     int m_line;                 //!< line number
     int m_column;               //!< line column
-    std::string m_message;      //!< error message
+    std::string m_message;      //!< exception message
 
 public:
     /**
@@ -138,7 +165,7 @@
      * \param column the column
      * \param msg the message
      */
-    inline Error(int line, int column, std::string msg) noexcept
+    inline exception(int line, int column, std::string msg) noexcept
         : m_line(line)
         , m_column(column)
         , m_message(std::move(msg))
@@ -166,11 +193,11 @@
     }
 
     /**
-     * Return the raw error message (no line and column shown).
+     * Return the raw exception message (no line and column shown).
      *
-     * \return the error message
+     * \return the exception message
      */
-    const char *what() const noexcept override
+    const char* what() const noexcept override
     {
         return m_message.c_str();
     }
@@ -183,24 +210,24 @@
  *
  * \see analyze
  */
-class Token {
+class token {
 public:
     /**
-     * \brief Token type.
+     * \brief token type.
      */
-    enum Type {
-        Include,                //!< include statement
-        Section,                //!< [section]
-        Word,                   //!< word without quotes
-        QuotedWord,             //!< word with quotes
-        Assign,                 //!< = assignment
-        ListBegin,              //!< begin of list (
-        ListEnd,                //!< end of list )
-        Comma                   //!< list separation
+    enum type {
+        include,                //!< include statement
+        section,                //!< [section]
+        word,                   //!< word without quotes
+        quoted_word,            //!< word with quotes
+        assign,                 //!< = assignment
+        list_begin,             //!< begin of list (
+        list_end,               //!< end of list )
+        comma                   //!< list separation
     };
 
 private:
-    Type m_type;
+    type m_type;
     int m_line;
     int m_column;
     std::string m_value;
@@ -214,30 +241,30 @@
      * \param column the column
      * \param value the value
      */
-    Token(Type type, int line, int column, std::string value = "") noexcept
+    token(type type, int line, int column, std::string value = "") noexcept
         : m_type(type)
         , m_line(line)
         , m_column(column)
     {
         switch (type) {
-        case Include:
+        case include:
             m_value = "@include";
             break;
-        case Section:
-        case Word:
-        case QuotedWord:
+        case section:
+        case word:
+        case quoted_word:
             m_value = value;
             break;
-        case Assign:
+        case assign:
             m_value = "=";
             break;
-        case ListBegin:
+        case list_begin:
             m_value = "(";
             break;
-        case ListEnd:
+        case list_end:
             m_value = ")";
             break;
-        case Comma:
+        case comma:
             m_value = ",";
             break;
         default:
@@ -250,7 +277,7 @@
      *
      * \return the type
      */
-    inline Type type() const noexcept
+    inline type type() const noexcept
     {
         return m_type;
     }
@@ -276,12 +303,12 @@
     }
 
     /**
-     * Get the value. For words, quoted words and section, the value is the content. Otherwise it's the
-     * characters parsed.
+     * Get the value. For words, quoted words and section, the value is the
+     * content. Otherwise it's the characters parsed.
      *
      * \return the value
      */
-    inline const std::string &value() const noexcept
+    inline const std::string& value() const noexcept
     {
         return m_value;
     }
@@ -290,12 +317,12 @@
 /**
  * List of tokens in order they are analyzed.
  */
-using Tokens = std::vector<Token>;
+using tokens = std::vector<token>;
 
 /**
- * \brief Option definition.
+ * \brief option definition.
  */
-class Option : public std::vector<std::string> {
+class option : public std::vector<std::string> {
 private:
     std::string m_key;
 
@@ -306,7 +333,7 @@
      * \pre key must not be empty
      * \param key the key
      */
-    inline Option(std::string key) noexcept
+    inline option(std::string key) noexcept
         : std::vector<std::string>()
         , m_key(std::move(key))
     {
@@ -320,7 +347,7 @@
      * \param key the key
      * \param value the value
      */
-    inline Option(std::string key, std::string value) noexcept
+    inline option(std::string key, std::string value) noexcept
         : m_key(std::move(key))
     {
         assert(!m_key.empty());
@@ -335,7 +362,7 @@
      * \param key the key
      * \param values the values
      */
-    inline Option(std::string key, std::vector<std::string> values) noexcept
+    inline option(std::string key, std::vector<std::string> values) noexcept
         : std::vector<std::string>(std::move(values))
         , m_key(std::move(key))
     {
@@ -347,7 +374,7 @@
      *
      * \return the key
      */
-    inline const std::string &key() const noexcept
+    inline const std::string& key() const noexcept
     {
         return m_key;
     }
@@ -357,7 +384,7 @@
      *
      * \return the value
      */
-    inline const std::string &value() const noexcept
+    inline const std::string& value() const noexcept
     {
         static std::string dummy;
 
@@ -368,7 +395,7 @@
 /**
  * \brief Section that contains one or more options.
  */
-class Section : public std::vector<Option> {
+class section : public std::vector<option> {
 private:
     std::string m_key;
 
@@ -379,7 +406,7 @@
      * \pre key must not be empty
      * \param key the key
      */
-    inline Section(std::string key) noexcept
+    inline section(std::string key) noexcept
         : m_key(std::move(key))
     {
         assert(!m_key.empty());
@@ -390,7 +417,7 @@
      *
      * \return the key
      */
-    inline const std::string &key() const noexcept
+    inline const std::string& key() const noexcept
     {
         return m_key;
     }
@@ -401,7 +428,7 @@
      * \param key the option key
      * \return true if the option exists
      */
-    inline bool contains(const std::string &key) const noexcept
+    inline bool contains(const std::string& key) const noexcept
     {
         return find(key) != end();
     }
@@ -412,9 +439,9 @@
      * \param key the key
      * \return the iterator or end() if not found
      */
-    inline iterator find(const std::string &key) noexcept
+    inline iterator find(const std::string& key) noexcept
     {
-        return std::find_if(begin(), end(), [&] (const auto &o) {
+        return std::find_if(begin(), end(), [&] (const auto& o) {
             return o.key() == key;
         });
     }
@@ -425,9 +452,9 @@
      * \param key the key
      * \return the iterator or end() if not found
      */
-    inline const_iterator find(const std::string &key) const noexcept
+    inline const_iterator find(const std::string& key) const noexcept
     {
-        return std::find_if(cbegin(), cend(), [&] (const auto &o) {
+        return std::find_if(cbegin(), cend(), [&] (const auto& o) {
             return o.key() == key;
         });
     }
@@ -439,7 +466,7 @@
      * \return the option
      * \pre contains(key) must return true
      */
-    inline Option &operator[](const std::string &key)
+    inline option& operator[](const std::string& key)
     {
         assert(contains(key));
 
@@ -453,7 +480,7 @@
      * \return the option
      * \pre contains(key) must return true
      */
-    inline const Option &operator[](const std::string &key) const
+    inline const option& operator[](const std::string& key) const
     {
         assert(contains(key));
 
@@ -463,7 +490,7 @@
     /**
      * Inherited operators.
      */
-    using std::vector<Option>::operator[];
+    using std::vector<option>::operator[];
 };
 
 /**
@@ -471,7 +498,7 @@
  * \see readFile
  * \see readString
  */
-class Document : public std::vector<Section> {
+class document : public std::vector<section> {
 public:
     /**
      * Check if a document has a specific section.
@@ -479,9 +506,9 @@
      * \param key the key
      * \return true if the document contains the section
      */
-    inline bool contains(const std::string &key) const noexcept
+    inline bool contains(const std::string& key) const noexcept
     {
-        return std::find_if(begin(), end(), [&] (const auto &sc) { return sc.key() == key; }) != end();
+        return find(key) != end();
     }
 
     /**
@@ -490,9 +517,9 @@
      * \param key the key
      * \return the iterator or end() if not found
      */
-    inline iterator find(const std::string &key) noexcept
+    inline iterator find(const std::string& key) noexcept
     {
-        return std::find_if(begin(), end(), [&] (const auto &o) {
+        return std::find_if(begin(), end(), [&] (const auto& o) {
             return o.key() == key;
         });
     }
@@ -503,9 +530,9 @@
      * \param key the key
      * \return the iterator or end() if not found
      */
-    inline const_iterator find(const std::string &key) const noexcept
+    inline const_iterator find(const std::string& key) const noexcept
     {
-        return std::find_if(cbegin(), cend(), [&] (const auto &o) {
+        return std::find_if(cbegin(), cend(), [&] (const auto& o) {
             return o.key() == key;
         });
     }
@@ -517,7 +544,7 @@
      * \return the section
      * \pre contains(key) must return true
      */
-    inline Section &operator[](const std::string &key)
+    inline section& operator[](const std::string& key)
     {
         assert(contains(key));
 
@@ -531,7 +558,7 @@
      * \return the section
      * \pre contains(key) must return true
      */
-    inline const Section &operator[](const std::string &key) const
+    inline const section& operator[](const std::string& key) const
     {
         assert(contains(key));
 
@@ -541,31 +568,31 @@
     /**
      * Inherited operators.
      */
-    using std::vector<Section>::operator[];
+    using std::vector<section>::operator[];
 };
 
 /**
- * Analyse a stream and detect potential syntax errors. This does not parse the file like including other
- * files in include statement.
+ * Analyse a stream and detect potential syntax errors. This does not parse the
+ * file like including other files in include statement.
  *
- * It does only analysis, for example if an option is defined under no section, this does not trigger an
- * error while it's invalid.
+ * It does only analysis, for example if an option is defined under no section,
+ * this does not trigger an exception while it's invalid.
  *
  * \param it the iterator
  * \param end where to stop
  * \return the list of tokens
- * \throws Error on errors
+ * \throws exception on errors
  */
-IRCCD_EXPORT Tokens analyse(std::istreambuf_iterator<char> it, std::istreambuf_iterator<char> end);
+IRCCD_EXPORT tokens analyse(std::istreambuf_iterator<char> it, std::istreambuf_iterator<char> end);
 
 /**
  * Overloaded function for stream.
  *
  * \param stream the stream
  * \return the list of tokens
- * \throws Error on errors
+ * \throws exception on errors
  */
-IRCCD_EXPORT Tokens analyse(std::istream &stream);
+IRCCD_EXPORT tokens analyse(std::istream& stream);
 
 /**
  * Parse the produced tokens.
@@ -573,39 +600,40 @@
  * \param tokens the tokens
  * \param path the parent path
  * \return the document
- * \throw Error on errors
+ * \throw exception on errors
  */
-IRCCD_EXPORT Document parse(const Tokens &tokens, const std::string &path = ".");
+IRCCD_EXPORT document parse(const tokens& tokens, const std::string& path = ".");
 
 /**
  * Parse a file.
  *
  * \param filename the file name
  * \return the document
- * \throw Error on errors
+ * \throw exception on errors
  */
-IRCCD_EXPORT Document readFile(const std::string &filename);
+IRCCD_EXPORT document read_file(const std::string& filename);
 
 /**
  * Parse a string.
  *
- * If the string contains include statements, they are relative to the current working directory.
+ * If the string contains include statements, they are relative to the current
+ * working directory.
  *
  * \param buffer the buffer
  * \return the document
- * \throw Error on errors
+ * \throw exception on exceptions
  */
-IRCCD_EXPORT Document readString(const std::string &buffer);
+IRCCD_EXPORT document read_string(const std::string& buffer);
 
 /**
  * Show all tokens and their description.
  *
  * \param tokens the tokens
  */
-IRCCD_EXPORT void dump(const Tokens &tokens);
+IRCCD_EXPORT void dump(const tokens& tokens);
 
 } // !ini
 
 } // !irccd
 
-#endif // !IRCCD_INI_HPP
+#endif // !INI_HPP
--- a/libcommon/irccd/logger.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/logger.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -44,33 +44,33 @@
  */
 
 std::atomic<bool> verbose{false};
-std::unique_ptr<Logger> iface{new ConsoleLogger};
-std::unique_ptr<Filter> filter{new Filter};
+std::unique_ptr<logger> use_iface{new console_logger};
+std::unique_ptr<filter> use_filter{new filter};
 
 /*
- * Buffer -- output buffer.
+ * buffer -- output buffer.
  * ------------------------------------------------------------------
  *
  * This class inherits from std::stringbuf and writes the messages to the
  * specified interface function which is one of info, warning and debug.
  */
 
-class Buffer : public std::stringbuf {
+class buffer : public std::stringbuf {
 public:
-    enum Level {
-        Debug,
-        Info,
-        Warning
+    enum class level {
+        debug,
+        info,
+        warning
     };
 
 private:
-    Level m_level;
+    level level_;
 
     void debug(std::string line)
     {
         // Print only in debug mode, the buffer is flushed anyway.
 #if !defined(NDEBUG)
-        iface->debug(filter->preDebug(std::move(line)));
+        use_iface->debug(use_filter->pre_debug(std::move(line)));
 #else
         (void)line;
 #endif
@@ -80,19 +80,19 @@
     {
         // Print only if verbose, the buffer will be flushed anyway.
         if (verbose)
-            iface->info(filter->preInfo(std::move(line)));
+            use_iface->info(use_filter->pre_info(std::move(line)));
     }
 
     void warning(std::string line)
     {
-        iface->warning(filter->preWarning(std::move(line)));
+        use_iface->warning(use_filter->pre_warning(std::move(line)));
     }
 
 public:
-    inline Buffer(Level level) noexcept
-        : m_level(level)
+    inline buffer(level level) noexcept
+        : level_(level)
     {
-        assert(level >= Debug && level <= Warning);
+        assert(level >= level::debug && level <= level::warning);
     }
 
     virtual int sync() override
@@ -101,19 +101,19 @@
         std::string::size_type pos;
 
         while ((pos = buffer.find("\n")) != std::string::npos) {
-            std::string line = buffer.substr(0, pos);
+            auto line = buffer.substr(0, pos);
 
             // Remove this line.
             buffer.erase(buffer.begin(), buffer.begin() + pos + 1);
 
-            switch (m_level) {
-            case Level::Debug:
+            switch (level_) {
+            case level::debug:
                 debug(std::move(line));
                 break;
-            case Level::Info:
+            case level::info:
                 info(std::move(line));
                 break;
-            case Level::Warning:
+            case level::warning:
                 warning(std::move(line));
                 break;
             default:
@@ -133,108 +133,108 @@
  */
 
 // Buffers.
-Buffer bufferInfo{Buffer::Info};
-Buffer bufferWarning{Buffer::Warning};
-Buffer bufferDebug{Buffer::Debug};
+buffer buffer_info{buffer::level::info};
+buffer buffer_warning{buffer::level::warning};
+buffer buffer_debug{buffer::level::debug};
 
 // Stream outputs.
-std::ostream streamInfo(&bufferInfo);
-std::ostream streamWarning(&bufferWarning);
-std::ostream streamDebug(&bufferDebug);
+std::ostream stream_info(&buffer_info);
+std::ostream stream_warning(&buffer_warning);
+std::ostream stream_debug(&buffer_debug);
 
 } // !namespace
 
 /*
- * ConsoleLogger
+ * console_logger
  * ------------------------------------------------------------------
  */
 
-void ConsoleLogger::info(const std::string &line)
+void console_logger::info(const std::string& line)
 {
     std::cout << line << std::endl;
 }
 
-void ConsoleLogger::warning(const std::string &line)
+void console_logger::warning(const std::string& line)
 {
     std::cerr << line << std::endl;
 }
 
-void ConsoleLogger::debug(const std::string &line)
+void console_logger::debug(const std::string& line)
 {
     std::cout << line << std::endl;
 }
 
 /*
- * FileLogger
+ * file_logger
  * ------------------------------------------------------------------
  */
 
-FileLogger::FileLogger(std::string normal, std::string errors)
-    : m_outputNormal(std::move(normal))
-    , m_outputError(std::move(errors))
+file_logger::file_logger(std::string normal, std::string errors)
+    : output_normal_(std::move(normal))
+    , output_error_(std::move(errors))
 {
 }
 
-void FileLogger::info(const std::string &line)
+void file_logger::info(const std::string& line)
 {
-    std::ofstream(m_outputNormal, std::ofstream::out | std::ofstream::app) << line << std::endl;
+    std::ofstream(output_normal_, std::ofstream::out | std::ofstream::app) << line << std::endl;
 }
 
-void FileLogger::warning(const std::string &line)
+void file_logger::warning(const std::string& line)
 {
-    std::ofstream(m_outputError, std::ofstream::out | std::ofstream::app) << line << std::endl;
+    std::ofstream(output_error_, std::ofstream::out | std::ofstream::app) << line << std::endl;
 }
 
-void FileLogger::debug(const std::string &line)
+void file_logger::debug(const std::string& line)
 {
-    std::ofstream(m_outputNormal, std::ofstream::out | std::ofstream::app) << line << std::endl;
+    std::ofstream(output_normal_, std::ofstream::out | std::ofstream::app) << line << std::endl;
 }
 
 /*
- * SilentLogger
+ * silent_logger
  * ------------------------------------------------------------------
  */
 
-void SilentLogger::info(const std::string &)
+void silent_logger::info(const std::string&)
 {
 }
 
-void SilentLogger::warning(const std::string &)
+void silent_logger::warning(const std::string&)
 {
 }
 
-void SilentLogger::debug(const std::string &)
+void silent_logger::debug(const std::string&)
 {
 }
 
 /*
- * SyslogLogger
+ * syslog_logger
  * ------------------------------------------------------------------
  */
 
 #if defined(HAVE_SYSLOG)
 
-SyslogLogger::SyslogLogger()
+syslog_logger::syslog_logger()
 {
-    openlog(sys::programName().c_str(), LOG_PID, LOG_DAEMON);
+    openlog(sys::program_name().c_str(), LOG_PID, LOG_DAEMON);
 }
 
-SyslogLogger::~SyslogLogger()
+syslog_logger::~syslog_logger()
 {
     closelog();
 }
 
-void SyslogLogger::info(const std::string &line)
+void syslog_logger::info(const std::string& line)
 {
     syslog(LOG_INFO | LOG_USER, "%s", line.c_str());
 }
 
-void SyslogLogger::warning(const std::string &line)
+void syslog_logger::warning(const std::string& line)
 {
     syslog(LOG_WARNING | LOG_USER, "%s", line.c_str());
 }
 
-void SyslogLogger::debug(const std::string &line)
+void syslog_logger::debug(const std::string& line)
 {
     syslog(LOG_DEBUG | LOG_USER, "%s", line.c_str());
 }
@@ -246,50 +246,50 @@
  * ------------------------------------------------------------------
  */
 
-void setLogger(std::unique_ptr<Logger> newiface) noexcept
+void set_logger(std::unique_ptr<logger> new_iface) noexcept
 {
-    assert(newiface);
+    assert(new_iface);
 
-    iface = std::move(newiface);
+    use_iface = std::move(new_iface);
 }
 
-void setFilter(std::unique_ptr<Filter> newfilter) noexcept
+void set_filter(std::unique_ptr<filter> newfilter) noexcept
 {
-    assert(filter);
+    assert(newfilter);
 
-    filter = std::move(newfilter);
+    use_filter = std::move(newfilter);
 }
 
-std::ostream &info(const std::string &message)
+std::ostream& info(const std::string& message)
 {
     if (!message.empty())
-        streamInfo << message << std::endl;
+        stream_info << message << std::endl;
 
-    return streamInfo;
+    return stream_info;
 }
 
-std::ostream &warning(const std::string &message)
+std::ostream& warning(const std::string& message)
 {
     if (!message.empty())
-        streamWarning << message << std::endl;
+        stream_warning << message << std::endl;
 
-    return streamWarning;
+    return stream_warning;
 }
 
-std::ostream &debug(const std::string &message)
+std::ostream& debug(const std::string& message)
 {
     if (!message.empty())
-        streamDebug << message << std::endl;
+        stream_debug << message << std::endl;
 
-    return streamDebug;
+    return stream_debug;
 }
 
-bool isVerbose() noexcept
+bool is_verbose() noexcept
 {
     return verbose;
 }
 
-void setVerbose(bool mode) noexcept
+void set_verbose(bool mode) noexcept
 {
     verbose = mode;
 }
--- a/libcommon/irccd/logger.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/logger.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -35,26 +35,26 @@
 namespace log {
 
 /*
- * Logger -- abstract logging interface
+ * logger -- abstract logging interface
  * ------------------------------------------------------------------
  */
 
 /**
  * \brief Interface to implement new logger mechanisms.
  *
- * Derive from this class and use log::setLogger() to change logging system.
+ * Derive from this class and use log::set_logger() to change logging system.
  *
- * \see File
- * \see Console
- * \see Syslog
- * \see Silent
+ * \see file_logger
+ * \see console_logger
+ * \see syslog_logger
+ * \see silent_logger
  */
-class Logger {
+class logger {
 public:
     /**
      * Virtual destructor defaulted.
      */
-    virtual ~Logger() = default;
+    virtual ~logger() = default;
 
     /**
      * Write a debug message.
@@ -64,7 +64,7 @@
      * \param line the data
      * \see log::debug
      */
-    virtual void debug(const std::string &line) = 0;
+    virtual void debug(const std::string& line) = 0;
 
     /**
      * Write a information message.
@@ -74,7 +74,7 @@
      * \param line the data
      * \see log::info
      */
-    virtual void info(const std::string &line) = 0;
+    virtual void info(const std::string& line) = 0;
 
     /**
      * Write an error message.
@@ -84,11 +84,11 @@
      * \param line the data
      * \see log::warning
      */
-    virtual void warning(const std::string &line) = 0;
+    virtual void warning(const std::string& line) = 0;
 };
 
 /*
- * Filter -- modify messages before printing
+ * filter -- modify messages before printing
  * ------------------------------------------------------------------
  */
 
@@ -97,12 +97,12 @@
  *
  * Derive from this class and use log::setFilter.
  */
-class Filter {
+class filter {
 public:
     /**
      * Virtual destructor defaulted.
      */
-    virtual ~Filter() = default;
+    virtual ~filter() = default;
 
     /**
      * Update the debug message.
@@ -110,7 +110,7 @@
      * \param input the message
      * \return the updated message
      */
-    virtual std::string preDebug(std::string input) const
+    virtual std::string pre_debug(std::string input) const
     {
         return input;
     }
@@ -121,7 +121,7 @@
      * \param input the message
      * \return the updated message
      */
-    virtual std::string preInfo(std::string input) const
+    virtual std::string pre_info(std::string input) const
     {
         return input;
     }
@@ -132,14 +132,14 @@
      * \param input the message
      * \return the updated message
      */
-    virtual std::string preWarning(std::string input) const
+    virtual std::string pre_warning(std::string input) const
     {
         return input;
     }
 };
 
 /*
- * Console -- logs to console
+ * console_logger -- logs to console
  * ------------------------------------------------------------------
  */
 
@@ -147,36 +147,36 @@
  * \brief Logger implementation for console output using std::cout and
  *        std::cerr.
  */
-class ConsoleLogger : public Logger {
+class console_logger : public logger {
 public:
     /**
-     * \copydoc Logger::debug
+     * \copydoc logger::debug
      */
-    IRCCD_EXPORT void debug(const std::string &line) override;
+    void debug(const std::string& line) override;
 
     /**
-     * \copydoc Logger::info
+     * \copydoc logger::info
      */
-    IRCCD_EXPORT void info(const std::string &line) override;
+    void info(const std::string& line) override;
 
     /**
-     * \copydoc Logger::warning
+     * \copydoc logger::warning
      */
-    IRCCD_EXPORT void warning(const std::string &line) override;
+    void warning(const std::string& line) override;
 };
 
 /*
- * File -- logs to a file
+ * file_logger -- logs to a file
  * ------------------------------------------------------------------
  */
 
 /**
  * \brief Output to a files.
  */
-class FileLogger : public Logger {
+class file_logger : public logger {
 private:
-    std::string m_outputNormal;
-    std::string m_outputError;
+    std::string output_normal_;
+    std::string output_error_;
 
 public:
     /**
@@ -185,26 +185,26 @@
      * \param normal the path to the normal logs
      * \param errors the path to the errors logs
      */
-    IRCCD_EXPORT FileLogger(std::string normal, std::string errors);
+    file_logger(std::string normal, std::string errors);
 
     /**
-     * \copydoc Logger::debug
+     * \copydoc logger::debug
      */
-    IRCCD_EXPORT void debug(const std::string &line) override;
+    void debug(const std::string& line) override;
 
     /**
-     * \copydoc Logger::info
+     * \copydoc logger::info
      */
-    IRCCD_EXPORT void info(const std::string &line) override;
+    void info(const std::string& line) override;
 
     /**
-     * \copydoc Logger::warning
+     * \copydoc logger::warning
      */
-    IRCCD_EXPORT void warning(const std::string &line) override;
+    void warning(const std::string& line) override;
 };
 
 /*
- * Silent -- disable all logs
+ * silent_logger -- disable all logs
  * ------------------------------------------------------------------
  */
 
@@ -213,26 +213,26 @@
  *
  * Useful for unit tests when some classes may emits log.
  */
-class SilentLogger : public Logger {
+class silent_logger : public logger {
 public:
     /**
-     * \copydoc Logger::debug
+     * \copydoc logger::debug
      */
-    IRCCD_EXPORT void debug(const std::string &line) override;
+    void debug(const std::string& line) override;
 
     /**
-     * \copydoc Logger::info
+     * \copydoc logger::info
      */
-    IRCCD_EXPORT void info(const std::string &line) override;
+    void info(const std::string& line) override;
 
     /**
-     * \copydoc Logger::warning
+     * \copydoc logger::warning
      */
-    IRCCD_EXPORT void warning(const std::string &line) override;
+    void warning(const std::string& line) override;
 };
 
 /*
- * Syslog -- system logger
+ * syslog_logger -- system logger
  * ------------------------------------------------------------------
  */
 
@@ -241,32 +241,32 @@
 /**
  * \brief Implements logger into syslog.
  */
-class SyslogLogger : public Logger {
+class syslog_logger : public logger {
 public:
     /**
      * Open the syslog.
      */
-    IRCCD_EXPORT SyslogLogger();
+    syslog_logger();
 
     /**
      * Close the syslog.
      */
-    IRCCD_EXPORT ~SyslogLogger();
+    ~syslog_logger();
 
     /**
-     * \copydoc Logger::debug
+     * \copydoc logger::debug
      */
-    IRCCD_EXPORT void debug(const std::string &line) override;
+    void debug(const std::string& line) override;
 
     /**
-     * \copydoc Logger::info
+     * \copydoc logger::info
      */
-    IRCCD_EXPORT void info(const std::string &line) override;
+    void info(const std::string& line) override;
 
     /**
-     * \copydoc Logger::warning
+     * \copydoc logger::warning
      */
-    IRCCD_EXPORT void warning(const std::string &line) override;
+    void warning(const std::string& line) override;
 };
 
 #endif // !HAVE_SYSLOG
@@ -282,7 +282,7 @@
  * \pre iface must not be null
  * \param iface the new interface
  */
-IRCCD_EXPORT void setLogger(std::unique_ptr<Logger> iface) noexcept;
+IRCCD_EXPORT void set_logger(std::unique_ptr<logger> iface) noexcept;
 
 /**
  * Set an optional filter.
@@ -290,7 +290,7 @@
  * \pre filter must not be null
  * \param filter the filter
  */
-IRCCD_EXPORT void setFilter(std::unique_ptr<Filter> filter) noexcept;
+IRCCD_EXPORT void set_filter(std::unique_ptr<filter> filter) noexcept;
 
 /**
  * Get the stream for informational messages.
@@ -301,7 +301,7 @@
  * \return the stream
  * \note Has no effect if verbose is set to false.
  */
-IRCCD_EXPORT std::ostream &info(const std::string &message = "");
+IRCCD_EXPORT std::ostream& info(const std::string& message = "");
 
 /**
  * Get the stream for warnings.
@@ -311,7 +311,7 @@
  * \param message the optional message to write
  * \return the stream
  */
-IRCCD_EXPORT std::ostream &warning(const std::string &message = "");
+IRCCD_EXPORT std::ostream& warning(const std::string& message = "");
 
 /**
  * Get the stream for debug messages.
@@ -322,21 +322,21 @@
  * \return the stream
  * \note Has no effect if compiled in release mode.
  */
-IRCCD_EXPORT std::ostream &debug(const std::string &message = "");
+IRCCD_EXPORT std::ostream& debug(const std::string& message = "");
 
 /**
  * Tells if verbose is enabled.
  *
  * \return true if enabled
  */
-IRCCD_EXPORT bool isVerbose() noexcept;
+IRCCD_EXPORT bool is_verbose() noexcept;
 
 /**
  * Set the verbosity mode.
  *
  * \param mode the new mode
  */
-IRCCD_EXPORT void setVerbose(bool mode) noexcept;
+IRCCD_EXPORT void set_verbose(bool mode) noexcept;
 
 } // !log
 
--- a/libcommon/irccd/system.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/system.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -111,15 +111,15 @@
 namespace {
 
 /*
- * XXX: the setprogname() function keeps a pointer without copying it so when
+ * The setprogname() function keeps a pointer without copying it so when
  * main's argv is modified, we're not using the same name so create our own
  * copy.
  */
 
-std::string programNameCopy;
+std::string program_name_value;
 
 /*
- * setHelper.
+ * set_privileges.
  * ------------------------------------------------------------------
  *
  * This is an helper for setting the uid or gid. It accepts both numeric and
@@ -140,28 +140,32 @@
  *   - getter the function to get the id from the informal structure
  */
 template <typename IntType, typename LookupFunc, typename SetterFunc, typename FieldGetter>
-void setHelper(const std::string &typeName, const std::string &value, LookupFunc lookup, SetterFunc setter, FieldGetter getter)
+void set_privileges(const std::string& type_name,
+                    const std::string& value,
+                    LookupFunc lookup,
+                    SetterFunc setter,
+                    FieldGetter getter)
 {
-    IntType id;
+    IntType id = 0;
 
-    if (util::isNumber(value))
+    if (util::is_int(value))
         id = std::stoi(value);
     else {
         auto info = lookup(value.c_str());
 
         if (info == nullptr) {
-            log::warning() << "irccd: invalid " << typeName << ": " << std::strerror(errno) << std::endl;
+            log::warning() << "irccd: invalid " << type_name << ": " << std::strerror(errno) << std::endl;
             return;
         } else {
             id = getter(info);
-            log::debug() << "irccd: " << typeName << " " << value << " resolved to: " << id << std::endl;
+            log::debug() << "irccd: " << type_name << " " << value << " resolved to: " << id << std::endl;
         }
     }
 
     if (setter(id) < 0)
-        log::warning() << "irccd: could not set " << typeName << ": " << std::strerror(errno) << std::endl;
+        log::warning() << "irccd: could not set " << type_name << ": " << std::strerror(errno) << std::endl;
     else
-        log::info() << "irccd: setting " << typeName << " to " << value << std::endl;
+        log::info() << "irccd: setting " << type_name << " to " << value << std::endl;
 }
 
 /*
@@ -397,18 +401,18 @@
 
 } // !namespace
 
-void setProgramName(std::string name) noexcept
+void set_program_name(std::string name) noexcept
 {
-    programNameCopy = std::move(name);
+    program_name_value = std::move(name);
 
 #if defined(HAVE_SETPROGNAME)
-    setprogname(programNameCopy.c_str());
+    setprogname(program_name_value.c_str());
 #endif
 }
 
-const std::string &programName() noexcept
+const std::string& program_name() noexcept
 {
-    return programNameCopy;
+    return program_name_value;
 }
 
 std::string name()
@@ -513,7 +517,7 @@
 #endif
 }
 
-std::string env(const std::string &var)
+std::string env(const std::string& var)
 {
     auto value = std::getenv(var.c_str());
 
@@ -525,9 +529,9 @@
 
 #if defined(HAVE_SETUID)
 
-void setUid(const std::string &value)
+void set_uid(const std::string& value)
 {
-    setHelper<uid_t>("uid", value, &getpwnam, &setuid, [] (const struct passwd *pw) {
+    set_privileges<uid_t>("uid", value, &getpwnam, &setuid, [] (auto pw) {
         return pw->pw_uid;
     });
 }
@@ -536,9 +540,9 @@
 
 #if defined(HAVE_SETGID)
 
-void setGid(const std::string &value)
+void set_gid(const std::string& value)
 {
-    setHelper<gid_t>("gid", value, &getgrnam, &setgid, [] (const struct group *gr) {
+    set_privileges<gid_t>("gid", value, &getgrnam, &setgid, [] (auto gr) {
         return gr->gr_gid;
     });
 }
--- a/libcommon/irccd/system.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/system.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -44,14 +44,14 @@
  *
  * \param name the program name
  */
-IRCCD_EXPORT void setProgramName(std::string name) noexcept;
+IRCCD_EXPORT void set_program_name(std::string name) noexcept;
 
 /**
  * Get the program name.
  *
  * \return the program name
  */
-IRCCD_EXPORT const std::string &programName() noexcept;
+IRCCD_EXPORT const std::string& program_name() noexcept;
 
 /**
  * Get the system name.
@@ -72,7 +72,7 @@
  *
  * \return the number of seconds
  */
-IRCCD_EXPORT uint64_t uptime();
+IRCCD_EXPORT std::uint64_t uptime();
 
 /**
  * Get the milliseconds elapsed since the application
@@ -80,14 +80,14 @@
  *
  * \return the milliseconds
  */
-IRCCD_EXPORT uint64_t ticks();
+IRCCD_EXPORT std::uint64_t ticks();
 
 /**
  * Get an environment variable.
  *
  * \return the value or empty string
  */
-IRCCD_EXPORT std::string env(const std::string &var);
+IRCCD_EXPORT std::string env(const std::string& var);
 
 /**
  * Get home directory usually /home/foo
@@ -103,7 +103,7 @@
  *
  * \param value the value
  */
-IRCCD_EXPORT void setUid(const std::string &value);
+IRCCD_EXPORT void set_uid(const std::string& value);
 
 #endif
 
@@ -114,7 +114,7 @@
  *
  * \param value the value
  */
-IRCCD_EXPORT void setGid(const std::string &value);
+IRCCD_EXPORT void set_gid(const std::string& value);
 
 #endif
 
--- a/libcommon/irccd/util.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/util.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -45,7 +45,7 @@
 
 namespace {
 
-const std::unordered_map<std::string, int> colorTable{
+const std::unordered_map<std::string, int> colors{
     { "white",      0   },
     { "black",      1   },
     { "blue",       2   },
@@ -64,7 +64,7 @@
     { "lightgrey",  15  }
 };
 
-const std::unordered_map<std::string, char> attributesTable{
+const std::unordered_map<std::string, char> attributes{
     { "bold",       '\x02'  },
     { "italic",     '\x09'  },
     { "strike",     '\x13'  },
@@ -74,12 +74,12 @@
     { "reverse",    '\x16'  }
 };
 
-inline bool isReserved(char token) noexcept
+inline bool is_reserved(char token) noexcept
 {
     return token == '#' || token == '@' || token == '$' || token == '!';
 }
 
-std::string substituteDate(const std::string &text, const Substitution &params)
+std::string subst_date(const std::string& text, const subst& params)
 {
     std::ostringstream oss;
 
@@ -87,7 +87,8 @@
     oss << std::put_time(std::localtime(&params.time), text.c_str());
 #else
     /*
-     * Quick and dirty hack because GCC does not have this function.
+     * Quick and dirty hack because old version of GCC does not have this
+     * function.
      */
     char buffer[4096];
 
@@ -99,7 +100,7 @@
     return oss.str();
 }
 
-std::string substituteKeywords(const std::string &content, const Substitution &params)
+std::string subst_keywords(const std::string& content, const subst& params)
 {
     auto value = params.keywords.find(content);
 
@@ -109,7 +110,7 @@
     return "";
 }
 
-std::string substituteEnv(const std::string &content)
+std::string subst_env(const std::string& content)
 {
     auto value = std::getenv(content.c_str());
 
@@ -119,14 +120,14 @@
     return "";
 }
 
-std::string substituteAttributes(const std::string &content)
+std::string subst_attrs(const std::string& content)
 {
     std::stringstream oss;
     std::vector<std::string> list = split(content, ",");
 
     // @{} means reset.
     if (list.empty())
-        return std::string(1, attributesTable.at("reset"));
+        return std::string(1, attributes.at("reset"));
 
     // Remove useless spaces.
     std::transform(list.begin(), list.end(), list.begin(), strip);
@@ -142,19 +143,19 @@
         oss << '\x03';
 
         // Foreground.
-        auto it = colorTable.find(foreground);
-        if (it != colorTable.end())
+        auto it = colors.find(foreground);
+        if (it != colors.end())
             oss << it->second;
 
         // Background.
-        if (list.size() >= 2 && (it = colorTable.find(list[1])) != colorTable.end())
+        if (list.size() >= 2 && (it = colors.find(list[1])) != colors.end())
             oss << "," << it->second;
 
         // Attributes.
         for (std::size_t i = 2; i < list.size(); ++i) {
-            auto attribute = attributesTable.find(list[i]);
+            auto attribute = attributes.find(list[i]);
 
-            if (attribute != attributesTable.end())
+            if (attribute != attributes.end())
                 oss << attribute->second;
         }
     }
@@ -162,10 +163,10 @@
     return oss.str();
 }
 
-std::string substituteShell(const std::string &command)
+std::string subst_shell(const std::string& command)
 {
 #if defined(HAVE_POPEN)
-    std::unique_ptr<FILE, std::function<int (FILE *)>> fp(popen(command.c_str(), "r"), pclose);
+    std::unique_ptr<FILE, std::function<int (FILE*)>> fp(popen(command.c_str(), "r"), pclose);
 
     if (fp == nullptr)
         throw std::runtime_error(std::strerror(errno));
@@ -190,9 +191,9 @@
 #endif
 }
 
-std::string substitute(std::string::const_iterator &it, std::string::const_iterator &end, char token, const Substitution &params)
+std::string substitute(std::string::const_iterator& it, std::string::const_iterator& end, char token, const subst& params)
 {
-    assert(isReserved(token));
+    assert(is_reserved(token));
 
     std::string content, value;
 
@@ -212,20 +213,20 @@
 
     switch (token) {
     case '#':
-        if (params.flags & Substitution::Keywords)
-            value = substituteKeywords(content, params);
+        if ((params.flags & subst_flags::keywords) == subst_flags::keywords)
+            value = subst_keywords(content, params);
         break;
     case '$':
-        if (params.flags & Substitution::Env)
-            value = substituteEnv(content);
+        if ((params.flags & subst_flags::env) == subst_flags::env)
+            value = subst_env(content);
         break;
     case '@':
-        if (params.flags & Substitution::IrcAttrs)
-            value = substituteAttributes(content);
+        if ((params.flags & subst_flags::irc_attrs) == subst_flags::irc_attrs)
+            value = subst_attrs(content);
         break;
     case '!':
-        if (params.flags & Substitution::Shell)
-            value = substituteShell(content);
+        if ((params.flags & subst_flags::shell) == subst_flags::shell)
+            value = subst_shell(content);
         break;
     default:
         break;
@@ -236,33 +237,33 @@
 
 } // !namespace
 
-std::string format(std::string text, const Substitution &params)
+std::string format(std::string text, const subst& params)
 {
     /*
      * Change the date format before anything else to avoid interpolation with
      * keywords and user input.
      */
-    if (params.flags & Substitution::Date)
-        text = substituteDate(text, params);
+    if ((params.flags & subst_flags::date) == subst_flags::date)
+        text = subst_date(text, params);
 
     std::ostringstream oss;
 
     for (auto it = text.cbegin(), end = text.cend(); it != end; ) {
         auto token = *it;
 
-        /* Is the current character a reserved token or not? */
-        if (!isReserved(token)) {
+        // Is the current character a reserved token or not?
+        if (!is_reserved(token)) {
             oss << *it++;
             continue;
         }
 
-        /* The token was at the end, just write it and return now. */
+        // The token was at the end, just write it and return now.
         if (++it == end) {
             oss << token;
             continue;
         }
 
-        /* The token is declaring a template variable, substitute it. */
+        // The token is declaring a template variable, substitute it.
         if (*it == '{') {
             oss << substitute(++it, end, token, params);
             continue;
@@ -307,7 +308,7 @@
     return str;
 }
 
-std::vector<std::string> split(const std::string &list, const std::string &delimiters, int max)
+std::vector<std::string> split(const std::string& list, const std::string& delimiters, int max)
 {
     std::vector<std::string> result;
     std::size_t next = -1, current;
@@ -338,10 +339,10 @@
     return result;
 }
 
-MessagePair parseMessage(std::string message, const std::string &cc, const std::string &name)
+message_pack parse_message(std::string message, const std::string& cc, const std::string& name)
 {
-    std::string result = message;
-    bool iscommand = false;
+    auto result = message;
+    auto iscommand = false;
 
     // handle special commands "!<plugin> command"
     if (cc.length() > 0) {
@@ -371,10 +372,13 @@
         }
     }
 
-    return MessagePair(result, ((iscommand) ? MessageType::Command : MessageType::Message));
+    return {
+        iscommand ? message_pack::type::command : message_pack::type::message,
+        result
+    };
 }
 
-bool isBoolean(std::string value) noexcept
+bool is_boolean(std::string value) noexcept
 {
     std::transform(value.begin(), value.end(), value.begin(), [] (auto c) {
         return toupper(c);
@@ -383,7 +387,7 @@
     return value == "1" || value == "YES" || value == "TRUE" || value == "ON";
 }
 
-bool isInt(const std::string &str, int base) noexcept
+bool is_int(const std::string &str, int base) noexcept
 {
     if (str.empty())
         return false;
@@ -395,7 +399,7 @@
     return *ptr == 0;
 }
 
-bool isReal(const std::string &str) noexcept
+bool is_real(const std::string &str) noexcept
 {
     if (str.empty())
         return false;
@@ -407,7 +411,7 @@
     return *ptr == 0;
 }
 
-std::string nextNetwork(std::string &input)
+std::string next_network(std::string& input)
 {
     std::string result;
     std::string::size_type pos = input.find("\r\n\r\n");
--- a/libcommon/irccd/util.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libcommon/irccd/util.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -51,8 +51,7 @@
 namespace util {
 
 /**
- * \enum MessageType
- * \brief Describe which type of message has been received
+ * \brief Pack a message and its type
  *
  * On channels and queries, you may have a special command or a standard message
  * depending on the beginning of the message.
@@ -60,36 +59,95 @@
  * Example: `!reminder help' may invoke the command event if a plugin reminder
  * exists.
  */
-enum class MessageType {
-    Command,                        //!< special command
-    Message                         //!< standard message
+struct message_pack {
+    /**
+     * \brief Describe which type of message has been received
+     */
+    enum class type {
+        command,                        //!< special command
+        message                         //!< standard message
+    } type;
+
+    /**
+     * Message content.
+     */
+    std::string message;
+};
+
+/**
+ * \brief Disable or enable some features.
+ */
+enum class subst_flags : std::uint8_t {
+    date        = (1 << 0),     //!< date templates
+    keywords    = (1 << 1),     //!< keywords
+    env         = (1 << 2),     //!< environment variables
+    shell       = (1 << 3),     //!< command line command
+    irc_attrs   = (1 << 4)      //!< IRC escape codes
 };
 
 /**
- * \brief Combine the type of message and its content.
+ * \cond ENUM_HIDDEN_SYMBOLS
  */
-using MessagePair = std::pair<std::string, MessageType>;
+
+inline subst_flags operator^(subst_flags v1, subst_flags v2) noexcept
+{
+    return static_cast<subst_flags>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2));
+}
+
+inline subst_flags operator&(subst_flags v1, subst_flags v2) noexcept
+{
+    return static_cast<subst_flags>(static_cast<unsigned>(v1)&  static_cast<unsigned>(v2));
+}
+
+inline subst_flags operator|(subst_flags v1, subst_flags v2) noexcept
+{
+    return static_cast<subst_flags>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2));
+}
+
+inline subst_flags operator~(subst_flags v) noexcept
+{
+    return static_cast<subst_flags>(~static_cast<unsigned>(v));
+}
+
+inline subst_flags& operator|=(subst_flags& v1, subst_flags v2) noexcept
+{
+    v1 = static_cast<subst_flags>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2));
+
+    return v1;
+}
+
+inline subst_flags& operator&=(subst_flags& v1, subst_flags v2) noexcept
+{
+    v1 = static_cast<subst_flags>(static_cast<unsigned>(v1)&  static_cast<unsigned>(v2));
+
+    return v1;
+}
+
+inline subst_flags& operator^=(subst_flags& v1, subst_flags v2) noexcept
+{
+    v1 = static_cast<subst_flags>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2));
+
+    return v1;
+}
+
+/**
+ * \endcond
+ */
 
 /**
  * \brief Used for format() function.
  */
-class Substitution {
+class subst {
 public:
     /**
-     * \brief Disable or enable some features.
-     */
-    enum Flags {
-        Date        = (1 << 0),     //!< date templates
-        Keywords    = (1 << 1),     //!< keywords
-        Env         = (1 << 2),     //!< environment variables
-        Shell       = (1 << 3),     //!< command line command
-        IrcAttrs    = (1 << 4)      //!< IRC escape codes
-    };
-
-    /**
      * Flags for selecting templates.
      */
-    std::uint8_t flags{Date | Keywords | Env | IrcAttrs};
+    subst_flags flags{
+        subst_flags::date |
+        subst_flags::keywords |
+        subst_flags::env |
+        subst_flags::irc_attrs
+    };
 
     /**
      * Fill that field if you want a date.
@@ -156,7 +214,7 @@
  *   - <strong>\@{white,black,bold,underline}</strong>: will write white text on
  *     black in both bold and underline.
  */
-IRCCD_EXPORT std::string format(std::string text, const Substitution &params = {});
+IRCCD_EXPORT std::string format(std::string text, const subst& params = {});
 
 /**
  * Remove leading and trailing spaces.
@@ -174,7 +232,7 @@
  * \param max max number of split
  * \return a list of string splitted
  */
-IRCCD_EXPORT std::vector<std::string> split(const std::string &list, const std::string &delimiters, int max = -1);
+IRCCD_EXPORT std::vector<std::string> split(const std::string& list, const std::string& delimiters, int max = -1);
 
 /**
  * Join values by a separator and return a string.
@@ -228,12 +286,17 @@
 /**
  * Parse IRC message and determine if it's a command or a simple message.
  *
+ * If it's a command, the plugin invocation command is removed from the
+ * original message, otherwise it is copied verbatime.
+ *
  * \param message the message line
- * \param commandChar the command char (e.g '!')
+ * \param cchar the command char (e.g '!')
  * \param plugin the plugin name
  * \return the pair
  */
-IRCCD_EXPORT MessagePair parseMessage(std::string message, const std::string &commandChar, const std::string &plugin);
+IRCCD_EXPORT message_pack parse_message(std::string message,
+                                        const std::string& cchar,
+                                        const std::string& plugin);
 
 /**
  * Server and identities must have strict names. This function can
@@ -242,7 +305,7 @@
  * \param name the identifier name
  * \return true if is valid
  */
-inline bool isIdentifierValid(const std::string &name)
+inline bool is_identifier(const std::string& name)
 {
     return std::regex_match(name, std::regex("[A-Za-z0-9-_]+"));
 }
@@ -254,7 +317,7 @@
  * \return true if is boolean
  * \note this function is case-insensitive
  */
-IRCCD_EXPORT bool isBoolean(std::string value) noexcept;
+IRCCD_EXPORT bool is_boolean(std::string value) noexcept;
 
 /**
  * Check if the string is an integer.
@@ -263,15 +326,15 @@
  * \param base the optional base
  * \return true if integer
  */
-IRCCD_EXPORT bool isInt(const std::string &value, int base = 10) noexcept;
-
+IRCCD_EXPORT bool is_int(const std::string& value, int base = 10) noexcept;
+ 
 /**
  * Check if the string is real.
  *
  * \param value the value
  * \return true if real
  */
-IRCCD_EXPORT bool isReal(const std::string &value) noexcept;
+IRCCD_EXPORT bool is_real(const std::string& value) noexcept;
 
 /**
  * Check if the string is a number.
@@ -279,23 +342,9 @@
  * \param value the value
  * \return true if it is a number
  */
-inline bool isNumber(const std::string &value) noexcept
+inline bool is_number(const std::string& value) noexcept
 {
-    return isInt(value) || isReal(value);
-}
-
-/**
- * Tells if a number is bound between the limits.
- *
- * \param value the value to check
- * \param min the minimum
- * \param max the maximum
- * \return true if value is beyond the limits
- */
-template <typename T>
-constexpr bool isBound(T value, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max()) noexcept
-{
-    return value >= min && value <= max;
+    return is_int(value) || is_real(value);
 }
 
 /**
@@ -316,7 +365,9 @@
  * \throw std::out_of_range if the number is not between min and max
  */
 template <typename T>
-inline T toNumber(const std::string &number, T min = std::numeric_limits<T>::min(), T max = std::numeric_limits<T>::max())
+inline T to_number(const std::string& number,
+                   T min = std::numeric_limits<T>::min(),
+                   T max = std::numeric_limits<T>::max())
 {
     static_assert(std::is_integral<T>::value, "T must be integer type");
 
@@ -334,14 +385,6 @@
 }
 
 /**
- * Parse a network message from an input buffer and remove it from it.
- *
- * \param input the buffer, will be updated
- * \return the message or empty string if there is nothing
- */
-IRCCD_EXPORT std::string nextNetwork(std::string &input);
-
-/**
  * Use arguments to avoid compiler warnings about unused parameters.
  */
 template <typename... Args>
@@ -350,6 +393,14 @@
 }
 
 /**
+ * Parse a network message from an input buffer and remove it from it.
+ *
+ * \param input the buffer, will be updated
+ * \return the message or empty string if there is nothing
+ */
+IRCCD_EXPORT std::string next_network(std::string& input);
+
+/**
  * Utilities for nlohmann json.
  */
 namespace json {
@@ -363,7 +414,7 @@
  * \return the value
  * \throw std::runtime_error if the property is missing
  */
-inline nlohmann::json require(const nlohmann::json &json, const std::string &key, nlohmann::json::value_t type)
+inline nlohmann::json require(const nlohmann::json& json, const std::string& key, nlohmann::json::value_t type)
 {
     auto it = json.find(key);
     auto dummy = nlohmann::json(type);
@@ -384,7 +435,7 @@
  * \return the boolean
  * \throw std::runtime_error if the property is missing or not a boolean
  */
-inline bool requireBool(const nlohmann::json &json, const std::string &key)
+inline bool require_bool(const nlohmann::json& json, const std::string& key)
 {
     return require(json, key, nlohmann::json::value_t::boolean);
 }
@@ -397,7 +448,7 @@
  * \return the int
  * \throw std::runtime_error if the property is missing or not ant int
  */
-inline std::int64_t requireInt(const nlohmann::json &json, const std::string &key)
+inline std::int64_t require_int(const nlohmann::json& json, const std::string& key)
 {
     auto it = json.find(key);
 
@@ -420,7 +471,7 @@
  * \return the unsigned int
  * \throw std::runtime_error if the property is missing or not ant int
  */
-inline std::uint64_t requireUint(const nlohmann::json &json, const std::string &key)
+inline std::uint64_t require_uint(const nlohmann::json& json, const std::string& key)
 {
     auto it = json.find(key);
 
@@ -443,7 +494,7 @@
  * \return the string
  * \throw std::runtime_error if the property is missing or not a string
  */
-inline std::string requireString(const nlohmann::json &json, const std::string &key)
+inline std::string require_string(const nlohmann::json& json, const std::string& key)
 {
     return require(json, key, nlohmann::json::value_t::string);
 }
@@ -456,11 +507,11 @@
  * \return the identifier
  * \throw std::runtime_error if the property is invalid
  */
-inline std::string requireIdentifier(const nlohmann::json &json, const std::string &key)
+inline std::string require_identifier(const nlohmann::json& json, const std::string& key)
 {
-    auto id = requireString(json, key);
+    auto id = require_string(json, key);
 
-    if (!isIdentifierValid(id))
+    if (!is_identifier(id))
         throw std::runtime_error("invalid '{}' identifier property");
 
     return id;
@@ -473,7 +524,7 @@
  * \param def the default value if not boolean
  * \return a boolean
  */
-inline bool toBool(const nlohmann::json &json, bool def = false) noexcept
+inline bool to_bool(const nlohmann::json& json, bool def = false) noexcept
 {
     return json.is_boolean() ? json.get<bool>() : def;
 }
@@ -485,7 +536,7 @@
  * \param def the default value if not an int
  * \return an int
  */
-inline std::int64_t toInt(const nlohmann::json &json, std::int64_t def = 0) noexcept
+inline std::int64_t to_int(const nlohmann::json& json, std::int64_t def = 0) noexcept
 {
     return json.is_number_integer() ? json.get<std::int64_t>() : def;
 }
@@ -497,7 +548,7 @@
  * \param def the default value if not a unsigned int
  * \return an unsigned int
  */
-inline std::uint64_t toUint(const nlohmann::json &json, std::uint64_t def = 0) noexcept
+inline std::uint64_t to_uint(const nlohmann::json& json, std::uint64_t def = 0) noexcept
 {
     return json.is_number_unsigned() ? json.get<std::uint64_t>() : def;
 }
@@ -509,7 +560,7 @@
  * \param def the default value if not a string
  * \return a string
  */
-inline std::string toString(const nlohmann::json &json, std::string def = "") noexcept
+inline std::string to_string(const nlohmann::json& json, std::string def = "") noexcept
 {
     return json.is_string() ? json.get<std::string>() : def;
 }
@@ -521,7 +572,7 @@
  * \param property the property key
  * \return the value or null one if not found
  */
-inline nlohmann::json get(const nlohmann::json &json, const std::string &property) noexcept
+inline nlohmann::json get(const nlohmann::json& json, const std::string& property) noexcept
 {
     auto it = json.find(property);
 
@@ -539,9 +590,11 @@
  * \param def the default value
  * \return the boolean
  */
-inline bool getBool(const nlohmann::json &json, const std::string &key, bool def = false) noexcept
+inline bool get_bool(const nlohmann::json& json,
+                     const std::string& key,
+                     bool def = false) noexcept
 {
-    return toBool(get(json, key), def);
+    return to_bool(get(json, key), def);
 }
 
 /**
@@ -552,9 +605,11 @@
  * \param def the default value
  * \return the int
  */
-inline std::int64_t getInt(const nlohmann::json &json, const std::string &key, std::int64_t def = 0) noexcept
+inline std::int64_t get_int(const nlohmann::json& json,
+                            const std::string& key,
+                            std::int64_t def = 0) noexcept
 {
-    return toInt(get(json, key), def);
+    return to_int(get(json, key), def);
 }
 
 /**
@@ -565,9 +620,11 @@
  * \param def the default value
  * \return the unsigned int
  */
-inline std::uint64_t getUint(const nlohmann::json &json, const std::string &key, std::uint64_t def = 0) noexcept
+inline std::uint64_t get_uint(const nlohmann::json& json,
+                              const std::string& key,
+                              std::uint64_t def = 0) noexcept
 {
-    return toUint(get(json, key), def);
+    return to_uint(get(json, key), def);
 }
 
 /**
@@ -580,12 +637,12 @@
  * \return the value
  */
 template <typename T>
-inline T getIntRange(const nlohmann::json &json,
-                     const std::string &key,
-                     std::int64_t min = std::numeric_limits<T>::min(),
-                     std::int64_t max = std::numeric_limits<T>::max()) noexcept
+inline T get_int_range(const nlohmann::json& json,
+                       const std::string& key,
+                       std::int64_t min = std::numeric_limits<T>::min(),
+                       std::int64_t max = std::numeric_limits<T>::max()) noexcept
 {
-    return clamp(getInt(json, key), min, max);
+    return clamp(get_int(json, key), min, max);
 }
 
 /**
@@ -598,12 +655,12 @@
  * \return value
  */
 template <typename T>
-inline T getUintRange(const nlohmann::json &json,
-                    const std::string &key,
-                    std::uint64_t min = std::numeric_limits<T>::min(),
-                    std::uint64_t max = std::numeric_limits<T>::max()) noexcept
+inline T get_uint_range(const nlohmann::json& json,
+                        const std::string& key,
+                        std::uint64_t min = std::numeric_limits<T>::min(),
+                        std::uint64_t max = std::numeric_limits<T>::max()) noexcept
 {
-    return clamp(getUint(json, key), min, max);
+    return clamp(get_uint(json, key), min, max);
 }
 
 /**
@@ -614,9 +671,11 @@
  * \param def the default value
  * \return the string
  */
-inline std::string getString(const nlohmann::json &json, const std::string &key, std::string def = "") noexcept
+inline std::string get_string(const nlohmann::json& json,
+                              const std::string& key,
+                              std::string def = "") noexcept
 {
-    return toString(get(json, key), def);
+    return to_string(get(json, key), def);
 }
 
 /**
@@ -625,7 +684,7 @@
  * \param value the value
  * \return the string
  */
-inline std::string pretty(const nlohmann::json &value)
+inline std::string pretty(const nlohmann::json& value)
 {
     switch (value.type()) {
     case nlohmann::json::value_t::boolean:
@@ -644,7 +703,7 @@
  * \param prop the property
  * \return the pretty value or empty if key does not exist
  */
-inline std::string pretty(const nlohmann::json &object, const std::string &prop)
+inline std::string pretty(const nlohmann::json& object, const std::string& prop)
 {
     auto it = object.find(prop);
 
--- a/libirccd-js/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-js/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
@@ -21,37 +21,37 @@
 set(
     HEADERS
     ${libirccd-js_SOURCE_DIR}/irccd/duktape.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-directory.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-elapsed-timer.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-file.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-irccd.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-logger.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-plugin.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-server.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-system.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-timer.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_directory_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_elapsed_timer_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_file_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_irccd_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_logger_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_plugin_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_server_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_system_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_timer_module.hpp
     ${libirccd-js_SOURCE_DIR}/irccd/module.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-unicode.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-util.hpp
-    ${libirccd-js_SOURCE_DIR}/irccd/plugin-js.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_unicode_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_util_module.hpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_plugin.hpp
     ${libirccd-js_SOURCE_DIR}/irccd/timer.hpp
     ${libirccd-js_SOURCE_DIR}/irccd/unicode.hpp
 )
 
 set(
     SOURCES
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-directory.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-elapsed-timer.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-file.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-irccd.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-logger.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-plugin.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-server.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-system.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-timer.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-unicode.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/mod-util.cpp
-    ${libirccd-js_SOURCE_DIR}/irccd/plugin-js.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_directory_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_elapsed_timer_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_file_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_irccd_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_logger_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_plugin_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_server_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_system_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_timer_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_unicode_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_util_module.cpp
+    ${libirccd-js_SOURCE_DIR}/irccd/js_plugin.cpp
     ${libirccd-js_SOURCE_DIR}/irccd/timer.cpp
     ${libirccd-js_SOURCE_DIR}/irccd/unicode.cpp
 )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_directory_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,384 @@
+/*
+ * js_directory_module.cpp -- irccd.Directory API
+ *
+ * Copyright (c) 2013-2017 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 <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <regex>
+#include <stdexcept>
+#include <string>
+
+#include <boost/filesystem.hpp>
+
+#include "duktape.hpp"
+#include "fs.hpp"
+#include "js_directory_module.hpp"
+#include "js_irccd_module.hpp"
+#include "js_plugin.hpp"
+#include "sysconfig.hpp"
+
+namespace irccd {
+
+namespace {
+
+std::string path(duk_context *ctx)
+{
+    duk_push_this(ctx);
+    duk_get_prop_string(ctx, -1, "path");
+
+    if (duk_get_type(ctx, -1) != DUK_TYPE_STRING)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object");
+
+    auto ret = dukx_get_std_string(ctx, -1);
+
+    if (ret.empty())
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path");
+
+    duk_pop_n(ctx, 2);
+
+    return ret;
+}
+
+/*
+ * Find an entry recursively (or not) in a directory using a predicate which can
+ * be used to test for regular expression, equality.
+ *
+ * Do not use this function directly, use:
+ *
+ * - find_name
+ * - find_regex
+ */
+template <typename Pred>
+std::string find_path(const std::string& base, bool recursive, Pred&& pred)
+{
+    /*
+     * For performance reason, we first iterate over all entries that are
+     * not directories to avoid going deeper recursively if the requested
+     * file is in the current directory.
+     */
+    auto entries = fs::readdir(base);
+
+    for (const auto& entry : entries)
+        if (entry.type != fs::Entry::Dir && pred(entry.name))
+            return base + entry.name;
+
+    if (!recursive)
+        return "";
+
+    for (const auto& entry : entries) {
+        if (entry.type == fs::Entry::Dir) {
+            std::string next = base + entry.name + fs::separator();
+            std::string path = find_path(next, true, pred);
+
+            if (!path.empty())
+                return path;
+        }
+    }
+
+    return "";
+}
+
+/*
+ * Helper for finding by equality.
+ */
+std::string find_name(std::string base, const std::string& pattern, bool recursive)
+{
+    return find_path(base, recursive, [&] (const auto& entryname) -> bool {
+        return pattern == entryname;
+    });
+}
+
+/*
+ * Helper for finding by regular expression
+ */
+std::string find_regex(const std::string& base, std::string pattern, bool recursive)
+{
+    std::regex regexp(pattern, std::regex::ECMAScript);
+    std::smatch smatch;
+
+    return find_path(base, recursive, [&] (const auto& entryname) -> bool {
+        return std::regex_match(entryname, smatch, regexp);
+    });
+}
+
+/*
+ * Generic find function for:
+ *
+ * - Directory.find
+ * - Directory.prototype.find
+ *
+ * The patternIndex is the argument where to test if the argument is a regex or
+ * a string.
+ */
+duk_ret_t find(duk_context* ctx, std::string base, bool recursive, int pattern_index)
+{
+    try {
+        std::string path;
+
+        if (duk_is_string(ctx, pattern_index))
+            path = find_name(base, duk_get_string(ctx, pattern_index), recursive);
+        else {
+            // Check if it's a valid RegExp object.
+            duk_get_global_string(ctx, "RegExp");
+            auto is_regex = duk_instanceof(ctx, pattern_index, -1);
+            duk_pop(ctx);
+
+            if (is_regex) {
+                duk_get_prop_string(ctx, pattern_index, "source");
+                auto pattern = duk_to_string(ctx, -1);
+                duk_pop(ctx);
+
+                path = find_regex(base, pattern, recursive);
+            } else
+                duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern must be a string or a regex expression");
+        }
+
+        if (path.empty())
+            return 0;
+
+        dukx_push_std_string(ctx, path);
+    } catch (const std::exception& ex) {
+        duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
+    }
+
+    return 1;
+}
+
+/*
+ * Generic remove function for:
+ *
+ * - Directory.remove
+ * - Directory.prototype.remove
+ */
+duk_ret_t remove(duk_context* ctx, const std::string& path, bool recursive)
+{
+    boost::system::error_code ec;
+
+    if (!boost::filesystem::is_directory(path, ec) || ec)
+        dukx_throw(ctx, system_error(EINVAL, "not a directory"));
+
+    if (!recursive)
+        boost::filesystem::remove(path, ec);
+    else
+        boost::filesystem::remove_all(path, ec);
+
+    return 0;
+}
+
+/*
+ * Method: Directory.find(pattern, recursive)
+ * --------------------------------------------------------
+ *
+ * Synonym of Directory.find(path, pattern, recursive) but the path is taken
+ * from the directory object.
+ *
+ * Arguments:
+ *   - pattern, the regular expression or file name,
+ *   - recursive, set to true to search recursively (default: false).
+ * Returns:
+ *   The path to the file or undefined if not found.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_find(duk_context* ctx)
+{
+    return find(ctx, path(ctx), duk_get_boolean(ctx, 1), 0);
+}
+
+/*
+ * Method: Directory.remove(recursive)
+ * --------------------------------------------------------
+ *
+ * Synonym of Directory.remove(recursive) but the path is taken from the
+ * directory object.
+ *
+ * Arguments:
+ *   - recursive, recursively or not (default: false).
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_remove(duk_context* ctx)
+{
+    return remove(ctx, path(ctx), duk_get_boolean(ctx, 0));
+}
+
+const duk_function_list_entry methods[] = {
+    { "find",       method_find,    DUK_VARARGS },
+    { "remove",     method_remove,  1           },
+    { nullptr,      nullptr,        0           }
+};
+
+/*
+ * Directory "static" functions
+ * ------------------------------------------------------------------
+ */
+
+/*
+ * Function: irccd.Directory(path, flags) [constructor]
+ * --------------------------------------------------------
+ *
+ * Opens and read the directory at the specified path.
+ *
+ * Arguments:
+ *   - path, the path to the directory,
+ *   - flags, the optional flags (default: 0).
+ * Throws:
+ *   - Any exception on error
+ */
+duk_ret_t constructor(duk_context* ctx)
+{
+    if (!duk_is_constructor_call(ctx))
+        return 0;
+
+    try {
+        auto path = duk_require_string(ctx, 0);
+        auto flags = duk_get_uint(ctx, 1);
+
+        if (!boost::filesystem::is_directory(path))
+            dukx_throw(ctx, system_error(EINVAL, "not a directory"));
+
+        auto list = fs::readdir(path, flags);
+
+        duk_push_this(ctx);
+        duk_push_string(ctx, "count");
+        duk_push_int(ctx, list.size());
+        duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
+        duk_push_string(ctx, "path");
+        dukx_push_std_string(ctx, path);
+        duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
+        duk_push_string(ctx, "entries");
+        duk_push_array(ctx);
+
+        for (unsigned i = 0; i < list.size(); ++i) {
+            duk_push_object(ctx);
+            dukx_push_std_string(ctx, list[i].name);
+            duk_put_prop_string(ctx, -2, "name");
+            duk_push_int(ctx, list[i].type);
+            duk_put_prop_string(ctx, -2, "type");
+            duk_put_prop_index(ctx, -2, i);
+        }
+
+        duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
+    } catch (const std::exception& ex) {
+        dukx_throw(ctx, system_error(errno, ex.what()));
+    }
+
+    return 0;
+}
+
+/*
+ * Function: irccd.Directory.find(path, pattern, recursive)
+ * --------------------------------------------------------
+ *
+ * Find an entry by a pattern or a regular expression.
+ *
+ * Arguments:
+ *   - path, the base path,
+ *   - pattern, the regular expression or file name,
+ *   - recursive, set to true to search recursively (default: false).
+ * Returns:
+ *   The path to the file or undefined on errors or not found.
+ */
+duk_ret_t func_find(duk_context* ctx)
+{
+    return find(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 2), 1);
+}
+
+/*
+ * Function: irccd.Directory.remove(path, recursive)
+ * --------------------------------------------------------
+ *
+ * Remove the directory optionally recursively.
+ *
+ * Arguments:
+ *   - path, the path to the directory,
+ *   - recursive, recursively or not (default: false).
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t func_remove(duk_context *ctx)
+{
+    return remove(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 1));
+}
+
+/*
+ * Function: irccd.Directory.mkdir(path, mode = 0700)
+ * --------------------------------------------------------
+ *
+ * Create a directory specified by path. It will create needed subdirectories
+ * just like you have invoked mkdir -p.
+ *
+ * Arguments:
+ *   - path, the path to the directory,
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t func_mkdir(duk_context *ctx)
+{
+    try {
+        boost::filesystem::create_directories(duk_require_string(ctx, 0));
+    } catch (const std::exception &ex) {
+        dukx_throw(ctx, system_error(errno, ex.what()));
+    }
+
+    return 0;
+}
+
+const duk_function_list_entry functions[] = {
+    { "find",           func_find,      DUK_VARARGS },
+    { "mkdir",          func_mkdir,     DUK_VARARGS },
+    { "remove",         func_remove,    DUK_VARARGS },
+    { nullptr,          nullptr,        0           }
+};
+
+const duk_number_list_entry constants[] = {
+    { "Dot",            static_cast<int>(fs::Dot)               },
+    { "DotDot",         static_cast<int>(fs::DotDot)            },
+    { "TypeUnknown",    static_cast<int>(fs::Entry::Unknown)    },
+    { "TypeDir",        static_cast<int>(fs::Entry::Dir)        },
+    { "TypeFile",       static_cast<int>(fs::Entry::File)       },
+    { "TypeLink",       static_cast<int>(fs::Entry::Link)       },
+    { nullptr,          0                                       }
+};
+
+} // !namespace
+
+js_directory_module::js_directory_module() noexcept
+    : module("Irccd.Directory")
+{
+}
+
+void js_directory_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_c_function(plugin->context(), constructor, 2);
+    duk_put_number_list(plugin->context(), -1, constants);
+    duk_put_function_list(plugin->context(), -1, functions);
+    dukx_push_std_string(plugin->context(), std::string{fs::separator()});
+    duk_put_prop_string(plugin->context(), -2, "separator");
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, methods);
+    duk_put_prop_string(plugin->context(), -2, "prototype");
+    duk_put_prop_string(plugin->context(), -2, "Directory");
+    duk_pop(plugin->context());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_directory_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_directory_module.hpp -- irccd.Directory API
+ *
+ * Copyright (c) 2013-2017 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_JS_DIRECTORY_MODULE_HPP
+#define IRCCD_JS_DIRECTORY_MODULE_HPP
+
+/**
+ * \file mod-directory.hpp
+ * \brief irccd.Directory JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief irccd.Directory JavaScript API.
+ * \ingroup modules
+ */
+class js_directory_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_directory_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd &irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_JS_DIRECTORY_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_elapsed_timer_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,162 @@
+/*
+ * js_elapsed_timer_module.cpp -- irccd.ElapsedTimer API
+ *
+ * Copyright (c) 2013-2017 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/elapsed-timer.hpp>
+#include <irccd/js_plugin.hpp>
+
+#include "js_elapsed_timer_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+const char* signature("\xff""\xff""irccd-elapsed-timer-ptr");
+
+ElapsedTimer* self(duk_context* ctx)
+{
+    StackAssert sa(ctx);
+
+    duk_push_this(ctx);
+    duk_get_prop_string(ctx, -1, signature);
+    auto ptr = static_cast<ElapsedTimer*>(duk_to_pointer(ctx, -1));
+    duk_pop_2(ctx);
+
+    if (!ptr)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object");
+
+    return ptr;
+}
+
+/*
+ * Method: ElapsedTimer.pause
+ * ------------------------------------------------------------------
+ *
+ * Pause the timer, without resetting the current elapsed time stored.
+ */
+duk_ret_t pause(duk_context* ctx)
+{
+    self(ctx)->pause();
+
+    return 0;
+}
+
+/*
+ * Method: ElapsedTimer.reset
+ * ------------------------------------------------------------------
+ *
+ * Reset the elapsed time to 0, the status is not modified.
+ */
+duk_ret_t reset(duk_context* ctx)
+{
+    self(ctx)->reset();
+
+    return 0;
+}
+
+/*
+ * Method: ElapsedTimer.restart
+ * ------------------------------------------------------------------
+ *
+ * Restart the timer without resetting the current elapsed time.
+ */
+duk_ret_t restart(duk_context* ctx)
+{
+    self(ctx)->restart();
+
+    return 0;
+}
+
+/*
+ * Method: ElapsedTimer.elapsed
+ * ------------------------------------------------------------------
+ *
+ * Get the number of elapsed milliseconds.
+ *
+ * Returns:
+ *   The time elapsed.
+ */
+duk_ret_t elapsed(duk_context* ctx)
+{
+    duk_push_uint(ctx, self(ctx)->elapsed());
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.ElapsedTimer() [constructor]
+ * ------------------------------------------------------------------
+ *
+ * Construct a new ElapsedTimer object.
+ */
+duk_ret_t constructor(duk_context* ctx)
+{
+    duk_push_this(ctx);
+    duk_push_pointer(ctx, new ElapsedTimer);
+    duk_put_prop_string(ctx, -2, signature);
+    duk_pop(ctx);
+
+    return 0;
+}
+
+/*
+ * Function: irccd.ElapsedTimer() [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+duk_ret_t destructor(duk_context* ctx)
+{
+    duk_get_prop_string(ctx, 0, signature);
+    delete static_cast<ElapsedTimer*>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+    duk_del_prop_string(ctx, 0, signature);
+
+    return 0;
+}
+
+const duk_function_list_entry methods[] = {
+    { "elapsed",    elapsed,    0 },
+    { "pause",      pause,      0 },
+    { "reset",      reset,      0 },
+    { "restart",    restart,    0 },
+    { nullptr,      nullptr,    0 }
+};
+
+} // !namespace
+
+js_elapsed_timer_module::js_elapsed_timer_module() noexcept
+    : module("Irccd.ElapsedTimer")
+{
+}
+
+void js_elapsed_timer_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_c_function(plugin->context(), constructor, 0);
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, methods);
+    duk_push_c_function(plugin->context(), destructor, 1);
+    duk_set_finalizer(plugin->context(), -2);
+    duk_put_prop_string(plugin->context(), -2, "prototype");
+    duk_put_prop_string(plugin->context(), -2, "ElapsedTimer");
+    duk_pop(plugin->context());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_elapsed_timer_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_elapsed_timer_module.hpp -- irccd.ElapsedTimer API
+ *
+ * Copyright (c) 2013-2017 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_JS_ELAPSED_TIMER_MODULE_HPP
+#define IRCCD_JS_ELAPSED_TIMER_MODULE_HPP
+
+/**
+ * \file js_elapsed_timer_module.hpp
+ * \brief irccd.ElapsedTimer JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Irccd.ElapsedTimer JavaScript API.
+ * \ingroup Javascript modules
+ */
+class js_elapsed_timer_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_elapsed_timer_module() noexcept;
+
+    /**
+     * \copydoc module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_JS_ELAPSED_TIMER_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_file_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,700 @@
+/*
+ * js_file_module.cpp -- Irccd.File API
+ *
+ * Copyright (c) 2013-2017 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 <algorithm>
+#include <array>
+#include <cassert>
+#include <iterator>
+#include <vector>
+
+#include <boost/filesystem.hpp>
+
+#include <irccd/sysconfig.hpp>
+
+#if defined(HAVE_STAT)
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#endif
+
+#include <irccd/fs.hpp>
+#include <irccd/js_plugin.hpp>
+
+#include "js_file_module.hpp"
+#include "js_irccd_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+const char *signature("\xff""\xff""irccd-file-ptr");
+const char *prototype("\xff""\xff""irccd-file-prototype");
+
+#if defined(HAVE_STAT)
+
+/*
+ * push_stat
+ * ------------------------------------------------------------------
+ */
+
+void push_stat(duk_context* ctx, const struct stat& st)
+{
+    StackAssert sa(ctx, 1);
+
+    duk_push_object(ctx);
+
+#if defined(HAVE_STAT_ST_ATIME)
+    duk_push_int(ctx, st.st_atime);
+    duk_put_prop_string(ctx, -2, "atime");
+#endif
+#if defined(HAVE_STAT_ST_BLKSIZE)
+    duk_push_int(ctx, st.st_blksize);
+    duk_put_prop_string(ctx, -2, "blksize");
+#endif
+#if defined(HAVE_STAT_ST_BLOCKS)
+    duk_push_int(ctx, st.st_blocks);
+    duk_put_prop_string(ctx, -2, "blocks");
+#endif
+#if defined(HAVE_STAT_ST_CTIME)
+    duk_push_int(ctx, st.st_ctime);
+    duk_put_prop_string(ctx, -2, "ctime");
+#endif
+#if defined(HAVE_STAT_ST_DEV)
+    duk_push_int(ctx, st.st_dev);
+    duk_put_prop_string(ctx, -2, "dev");
+#endif
+#if defined(HAVE_STAT_ST_GID)
+    duk_push_int(ctx, st.st_gid);
+    duk_put_prop_string(ctx, -2, "gid");
+#endif
+#if defined(HAVE_STAT_ST_INO)
+    duk_push_int(ctx, st.st_ino);
+    duk_put_prop_string(ctx, -2, "ino");
+#endif
+#if defined(HAVE_STAT_ST_MODE)
+    duk_push_int(ctx, st.st_mode);
+    duk_put_prop_string(ctx, -2, "mode");
+#endif
+#if defined(HAVE_STAT_ST_MTIME)
+    duk_push_int(ctx, st.st_mtime);
+    duk_put_prop_string(ctx, -2, "mtime");
+#endif
+#if defined(HAVE_STAT_ST_NLINK)
+    duk_push_int(ctx, st.st_nlink);
+    duk_put_prop_string(ctx, -2, "nlink");
+#endif
+#if defined(HAVE_STAT_ST_RDEV)
+    duk_push_int(ctx, st.st_rdev);
+    duk_put_prop_string(ctx, -2, "rdev");
+#endif
+#if defined(HAVE_STAT_ST_SIZE)
+    duk_push_int(ctx, st.st_size);
+    duk_put_prop_string(ctx, -2, "size");
+#endif
+#if defined(HAVE_STAT_ST_UID)
+    duk_push_int(ctx, st.st_uid);
+    duk_put_prop_string(ctx, -2, "uid");
+#endif
+}
+
+#endif // !HAVE_STAT
+
+// Remove trailing \r for CRLF line style.
+inline std::string clear_crlf(std::string input)
+{
+    if (input.length() > 0 && input.back() == '\r')
+        input.pop_back();
+
+    return input;
+}
+
+file* self(duk_context* ctx)
+{
+    StackAssert sa(ctx);
+
+    duk_push_this(ctx);
+    duk_get_prop_string(ctx, -1, signature);
+    auto ptr = static_cast<file*>(duk_to_pointer(ctx, -1));
+    duk_pop_2(ctx);
+
+    if (!ptr)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
+
+    return ptr;
+}
+
+/*
+ * File methods.
+ * ------------------------------------------------------------------
+ */
+
+/*
+ * Method: File.basename()
+ * --------------------------------------------------------
+ *
+ * Synonym of `irccd.File.basename(path)` but with the path from the file.
+ *
+ * duk_ret_turns:
+ *   The base name.
+ */
+duk_ret_t method_basename(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, fs::baseName(self(ctx)->path()));
+
+    return 1;
+}
+
+/*
+ * Method: File.close()
+ * --------------------------------------------------------
+ *
+ * Force close of the file, automatically called when object is collected.
+ */
+duk_ret_t method_close(duk_context* ctx)
+{
+    self(ctx)->close();
+
+    return 0;
+}
+
+/*
+ * Method: File.dirname()
+ * --------------------------------------------------------
+ *
+ * Synonym of `irccd.File.dirname(path)` but with the path from the file.
+ *
+ * duk_ret_turns:
+ *   The directory name.
+ */
+duk_ret_t method_dirname(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, fs::dirName(self(ctx)->path()));
+
+    return 1;
+}
+
+/*
+ * Method: File.lines()
+ * --------------------------------------------------------
+ *
+ * Read all lines and return an array.
+ *
+ * duk_ret_turns:
+ *   An array with all lines.
+ * Throws
+ *   - Any exception on error.
+ */
+duk_ret_t method_lines(duk_context* ctx)
+{
+    duk_push_array(ctx);
+
+    std::FILE* fp = self(ctx)->handle();
+    std::string buffer;
+    std::array<char, 128> data;
+    std::int32_t i = 0;
+
+    while (std::fgets(&data[0], data.size(), fp) != nullptr) {
+        buffer += data.data();
+
+        auto pos = buffer.find('\n');
+
+        if (pos != std::string::npos) {
+            dukx_push_std_string(ctx, clear_crlf(buffer.substr(0, pos)));
+            duk_put_prop_index(ctx, -2, i++);
+
+            buffer.erase(0, pos + 1);
+        }
+    }
+
+    // Maybe an error in the stream.
+    if (std::ferror(fp))
+        dukx_throw(ctx, system_error());
+
+    // Missing '\n' in end of file.
+    if (!buffer.empty()) {
+        dukx_push_std_string(ctx, clear_crlf(buffer));
+        duk_put_prop_index(ctx, -2, i++);
+    }
+
+    return 1;
+}
+
+/*
+ * Method: File.read(amount)
+ * --------------------------------------------------------
+ *
+ * Read the specified amount of characters or the whole file.
+ *
+ * Arguments:
+ *   - amount, the amount of characters or -1 to read all (Optional, default: -1).
+ * duk_ret_turns:
+ *   The string.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_read(duk_context* ctx)
+{
+    auto file = self(ctx);
+    auto amount = duk_is_number(ctx, 0) ? duk_get_int(ctx, 0) : -1;
+
+    if (amount == 0 || file->handle() == nullptr)
+        return 0;
+
+    try {
+        std::string data;
+        std::size_t total = 0;
+
+        if (amount < 0) {
+            std::array<char, 128> buffer;
+            std::size_t nread;
+
+            while ((nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle())) > 0) {
+                if (std::ferror(file->handle()))
+                    dukx_throw(ctx, system_error());
+
+                std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data));
+                total += nread;
+            }
+        } else {
+            data.resize((std::size_t)amount);
+            total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle());
+
+            if (std::ferror(file->handle()))
+                dukx_throw(ctx, system_error());
+
+            data.resize(total);
+        }
+
+        dukx_push_std_string(ctx, data);
+    } catch (const std::exception&) {
+        dukx_throw(ctx, system_error());
+    }
+
+    return 1;
+}
+
+/*
+ * Method: File.readline()
+ * --------------------------------------------------------
+ *
+ * Read the next line available.
+ *
+ * duk_ret_turns:
+ *   The next line or undefined if eof.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_readline(duk_context* ctx)
+{
+    std::FILE* fp = self(ctx)->handle();
+    std::string result;
+
+    if (fp == nullptr || std::feof(fp))
+        return 0;
+    for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; )
+        result += (char)ch;
+    if (std::ferror(fp))
+        dukx_throw(ctx, system_error());
+
+    dukx_push_std_string(ctx, clear_crlf(result));
+
+    return 1;
+}
+
+/*
+ * Method: File.remove()
+ * --------------------------------------------------------
+ *
+ * Synonym of File.remove(path) but with the path from the file.
+ *
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_remove(duk_context* ctx)
+{
+    if (::remove(self(ctx)->path().c_str()) < 0)
+        dukx_throw(ctx, system_error());
+
+    return 0;
+}
+
+/*
+ * Method: File.seek(type, amount)
+ * --------------------------------------------------------
+ *
+ * Sets the position in the file.
+ *
+ * Arguments:
+ *   - type, the type of setting (File.SeekSet, File.SeekCur, File.SeekSet),
+ *   - amount, the new offset.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_seek(duk_context* ctx)
+{
+    auto fp = self(ctx)->handle();
+    auto type = duk_require_int(ctx, 0);
+    auto amount = duk_require_int(ctx, 1);
+
+    if (fp != nullptr && std::fseek(fp, amount, type) != 0)
+        dukx_throw(ctx, system_error());
+
+    return 0;
+}
+
+#if defined(HAVE_STAT)
+
+/*
+ * Method: File.stat() [optional]
+ * --------------------------------------------------------
+ *
+ * Synonym of File.stat(path) but with the path from the file.
+ *
+ * duk_ret_turns:
+ *   The stat information.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_stat(duk_context* ctx)
+{
+    auto file = self(ctx);
+    struct stat st;
+
+    if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0)
+        dukx_throw(ctx, system_error());
+    else
+        push_stat(ctx, st);
+
+    return 1;
+}
+
+#endif // !HAVE_STAT
+
+/*
+ * Method: File.tell()
+ * --------------------------------------------------------
+ *
+ * Get the actual position in the file.
+ *
+ * duk_ret_turns:
+ *   The position.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_tell(duk_context* ctx)
+{
+    auto fp = self(ctx)->handle();
+    long pos;
+
+    if (fp == nullptr)
+        return 0;
+
+    if ((pos = std::ftell(fp)) == -1L)
+        dukx_throw(ctx, system_error());
+    else
+        duk_push_int(ctx, pos);
+
+    return 1;
+}
+
+/*
+ * Method: File.write(data)
+ * --------------------------------------------------------
+ *
+ * Write some characters to the file.
+ *
+ * Arguments:
+ *   - data, the character to write.
+ * duk_ret_turns:
+ *   The number of bytes written.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t method_write(duk_context* ctx)
+{
+    std::FILE* fp = self(ctx)->handle();
+    std::string data = duk_require_string(ctx, 0);
+
+    if (fp == nullptr)
+        return 0;
+
+    auto nwritten = std::fwrite(data.c_str(), 1, data.length(), fp);
+
+    if (std::ferror(fp))
+        dukx_throw(ctx, system_error());
+
+    duk_push_uint(ctx, nwritten);
+
+    return 1;
+}
+
+const duk_function_list_entry methods[] = {
+    { "basename",   method_basename,    0 },
+    { "close",      method_close,       0 },
+    { "dirname",    method_dirname,     0 },
+    { "lines",      method_lines,       0 },
+    { "read",       method_read,        1 },
+    { "readline",   method_readline,    0 },
+    { "remove",     method_remove,      0 },
+    { "seek",       method_seek,        2 },
+#if defined(HAVE_STAT)
+    { "stat",       method_stat,        0 },
+#endif
+    { "tell",       method_tell,        0 },
+    { "write",      method_write,       1 },
+    { nullptr,      nullptr,            0 }
+};
+
+/*
+ * File "static" functions
+ * ------------------------------------------------------------------
+ */
+
+/*
+ * Function: Irccd.File(path, mode) [constructor]
+ * --------------------------------------------------------
+ *
+ * Open a file specified by path with the specified mode.
+ *
+ * Arguments:
+ *   - path, the path to the file,
+ *   - mode, the mode string.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t constructor(duk_context* ctx)
+{
+    if (!duk_is_constructor_call(ctx))
+        return 0;
+
+    try {
+        dukx_new_file(ctx, new file(duk_require_string(ctx, 0), duk_require_string(ctx, 1)));
+    } catch (const std::exception &) {
+        dukx_throw(ctx, system_error());
+    }
+
+    return 0;
+}
+
+/*
+ * Function: Irccd.File() [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+duk_ret_t destructor(duk_context* ctx)
+{
+    duk_get_prop_string(ctx, 0, signature);
+    delete static_cast<file*>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+    duk_del_prop_string(ctx, 0, signature);
+
+    return 0;
+}
+
+/*
+ * Function: Irccd.File.basename(path)
+ * --------------------------------------------------------
+ *
+ * duk_ret_turn the file basename as specified in `basename(3)` C function.
+ *
+ * Arguments:
+ *   - path, the path to the file.
+ * duk_ret_turns:
+ *   The base name.
+ */
+duk_ret_t function_basename(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, fs::baseName(duk_require_string(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.File.dirname(path)
+ * --------------------------------------------------------
+ *
+ * duk_ret_turn the file directory name as specified in `dirname(3)` C function.
+ *
+ * Arguments:
+ *   - path, the path to the file.
+ * duk_ret_turns:
+ *   The directory name.
+ */
+duk_ret_t function_dirname(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, fs::dirName(duk_require_string(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.File.exists(path)
+ * --------------------------------------------------------
+ *
+ * Check if the file exists.
+ *
+ * Arguments:
+ *   - path, the path to the file.
+ * duk_ret_turns:
+ *   True if exists.
+ * Throws:
+ *   - Any exception if we don't have access.
+ */
+duk_ret_t function_exists(duk_context* ctx)
+{
+    try {
+        duk_push_boolean(ctx, boost::filesystem::exists(duk_require_string(ctx, 0)));
+    } catch (...) {
+        duk_push_boolean(ctx, false);
+    }
+
+    return 1;
+}
+
+/*
+ * function Irccd.File.remove(path)
+ * --------------------------------------------------------
+ *
+ * Remove the file at the specified path.
+ *
+ * Arguments:
+ *   - path, the path to the file.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t function_remove(duk_context* ctx)
+{
+    if (::remove(duk_require_string(ctx, 0)) < 0)
+        dukx_throw(ctx, system_error());
+
+    return 0;
+}
+
+#if defined(HAVE_STAT)
+
+/*
+ * function Irccd.File.stat(path) [optional]
+ * --------------------------------------------------------
+ *
+ * Get file information at the specified path.
+ *
+ * Arguments:
+ *   - path, the path to the file.
+ * duk_ret_turns:
+ *   The stat information.
+ * Throws:
+ *   - Any exception on error.
+ */
+duk_ret_t function_stat(duk_context* ctx)
+{
+    struct stat st;
+
+    if (::stat(duk_require_string(ctx, 0), &st) < 0)
+        dukx_throw(ctx, system_error());
+
+    push_stat(ctx, st);
+
+    return 1;
+}
+
+#endif // !HAVE_STAT
+
+const duk_function_list_entry functions[] = {
+    { "basename",   function_basename,  1 },
+    { "dirname",    function_dirname,   1 },
+    { "exists",     function_exists,    1 },
+    { "remove",     function_remove,    1 },
+#if defined(HAVE_STAT)
+    { "stat",       function_stat,      1 },
+#endif
+    { nullptr,      nullptr,            0 }
+};
+
+const duk_number_list_entry constants[] = {
+    { "SeekCur",    SEEK_CUR },
+    { "SeekEnd",    SEEK_END },
+    { "SeekSet",    SEEK_SET },
+    { nullptr,      0        }
+};
+
+} // !namespace
+
+js_file_module::js_file_module() noexcept
+    : module("Irccd.File")
+{
+}
+
+void js_file_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_c_function(plugin->context(), constructor, 2);
+    duk_put_number_list(plugin->context(), -1, constants);
+    duk_put_function_list(plugin->context(), -1, functions);
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, methods);
+    duk_push_c_function(plugin->context(), destructor, 1);
+    duk_set_finalizer(plugin->context(), -2);
+    duk_dup(plugin->context(), -1);
+    duk_put_global_string(plugin->context(), prototype);
+    duk_put_prop_string(plugin->context(), -2, "prototype");
+    duk_put_prop_string(plugin->context(), -2, "File");
+    duk_pop(plugin->context());
+}
+
+void dukx_new_file(duk_context* ctx, file* fp)
+{
+    assert(ctx);
+    assert(fp);
+
+    StackAssert sa(ctx);
+
+    duk_push_this(ctx);
+    duk_push_pointer(ctx, fp);
+    duk_put_prop_string(ctx, -2, signature);
+    duk_pop(ctx);
+}
+
+void dukx_push_file(duk_context* ctx, file* fp)
+{
+    assert(ctx);
+    assert(fp);
+
+    StackAssert sa(ctx, 1);
+
+    duk_push_object(ctx);
+    duk_push_pointer(ctx, fp);
+    duk_put_prop_string(ctx, -2, signature);
+    duk_get_global_string(ctx, prototype);
+    duk_set_prototype(ctx, -2);
+}
+
+file* dukx_require_file(duk_context* ctx, duk_idx_t index)
+{
+    if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, signature))
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
+
+    duk_get_prop_string(ctx, index, signature);
+    auto fp = static_cast<file*>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+
+    return fp;
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_file_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,184 @@
+/*
+ * js_file_module.hpp -- Irccd.File API
+ *
+ * Copyright (c) 2013-2017 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_JS_FILE_MODULE_HPP
+#define IRCCD_JS_FILE_MODULE_HPP
+
+/**
+ * \file js_file_module.hpp
+ * \brief Irccd.File JavaScript API.
+ */
+
+#include <cassert>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <functional>
+#include <stdexcept>
+#include <string>
+
+#include "duktape.hpp"
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Object for Javascript to perform I/O.
+ *
+ * This class can be constructed to Javascript.
+ *
+ * It is used in:
+ *
+ * - Irccd.File [constructor]
+ * - Irccd.System.popen (optional)
+ */
+class file {
+private:
+    file(const file&) = delete;
+    file& operator=(const file&) = delete;
+
+    file(file&&) = delete;
+    file& operator=(file&&) = delete;
+
+private:
+    std::string path_;
+    std::FILE *stream_;
+    std::function<void (std::FILE*)> destructor_;
+
+public:
+    /**
+     * Construct a file specified by path
+     *
+     * \param path the path
+     * \param mode the mode string (for std::fopen)
+     * \throw std::runtime_error on failures
+     */
+    inline file(std::string path, const std::string& mode)
+        : path_(std::move(path))
+        , destructor_([] (std::FILE* fp) { std::fclose(fp); })
+    {
+        if ((stream_ = std::fopen(path_.c_str(), mode.c_str())) == nullptr)
+            throw std::runtime_error(std::strerror(errno));
+    }
+
+    /**
+     * Construct a file from a already created FILE pointer (e.g. popen).
+     *
+     * The class takes ownership of fp and will close it.
+     *
+     * \pre destructor must not be null
+     * \param fp the file pointer
+     * \param destructor the function to close fp (e.g. std::fclose)
+     */
+    inline file(std::FILE* fp, std::function<void (std::FILE*)> destructor) noexcept
+        : stream_(fp)
+        , destructor_(std::move(destructor))
+    {
+        assert(destructor_ != nullptr);
+    }
+
+    /**
+     * Closes the file.
+     */
+    virtual ~file() noexcept
+    {
+        close();
+    }
+
+    /**
+     * Get the path.
+     *
+     * \return the path
+     * \warning empty when constructed from the FILE constructor
+     */
+    inline const std::string& path() const noexcept
+    {
+        return path_;
+    }
+
+    /**
+     * Get the handle.
+     *
+     * \return the handle or nullptr if the stream was closed
+     */
+    inline std::FILE* handle() noexcept
+    {
+        return stream_;
+    }
+
+    /**
+     * Force close, can be safely called multiple times.
+     */
+    inline void close() noexcept
+    {
+        if (stream_) {
+            destructor_(stream_);
+            stream_ = nullptr;
+        }
+    }
+};
+
+/**
+ * \brief Irccd.File JavaScript API.
+ * \ingroup modules
+ */
+class js_file_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_file_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+/**
+ * Construct the file as this.
+ *
+ * The object prototype takes ownership of fp and will be deleted once
+ * collected.
+ *
+ * \pre fp != nullptr
+ * \param ctx the the context
+ * \param fp the file
+ */
+IRCCD_EXPORT void dukx_new_file(duk_context* ctx, file* fp);
+
+/**
+ * Push a file.
+ *
+ * \pre fp != nullptr
+ * \param ctx the the context
+ * \param fp the file
+ */
+IRCCD_EXPORT void dukx_push_file(duk_context* ctx, file* fp);
+
+/**
+ * Require a file. Raises a JavaScript error if not a File.
+ *
+ * \param ctx the context
+ * \param index the index
+ */
+IRCCD_EXPORT file* dukx_require_file(duk_context* ctx, duk_idx_t index);
+
+} // !irccd
+
+#endif // !IRCCD_JS_FILE_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_irccd_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,232 @@
+/*
+ * js_irccd_module.cpp -- Irccd API
+ *
+ * Copyright (c) 2013-2017 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 <cerrno>
+#include <string>
+#include <unordered_map>
+
+#include <irccd/js_plugin.hpp>
+#include <irccd/sysconfig.hpp>
+
+#include "js_irccd_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+const std::unordered_map<std::string, int> errors{
+    { "E2BIG",              E2BIG           },
+    { "EACCES",             EACCES          },
+    { "EADDRINUSE",         EADDRINUSE      },
+    { "EADDRNOTAVAIL",      EADDRNOTAVAIL   },
+    { "EAFNOSUPPORT",       EAFNOSUPPORT    },
+    { "EAGAIN",             EAGAIN          },
+    { "EALREADY",           EALREADY        },
+    { "EBADF",              EBADF           },
+#if defined(EBADMSG)
+    { "EBADMSG",            EBADMSG         },
+#endif
+    { "EBUSY",              EBUSY           },
+    { "ECANCELED",          ECANCELED       },
+    { "ECHILD",             ECHILD          },
+    { "ECONNABORTED",       ECONNABORTED    },
+    { "ECONNREFUSED",       ECONNREFUSED    },
+    { "ECONNRESET",         ECONNRESET      },
+    { "EDEADLK",            EDEADLK         },
+    { "EDESTADDRREQ",       EDESTADDRREQ    },
+    { "EDOM",               EDOM            },
+    { "EEXIST",             EEXIST          },
+    { "EFAULT",             EFAULT          },
+    { "EFBIG",              EFBIG           },
+    { "EHOSTUNREACH",       EHOSTUNREACH    },
+#if defined(EIDRM)
+    { "EIDRM",              EIDRM           },
+#endif
+    { "EILSEQ",             EILSEQ          },
+    { "EINPROGRESS",        EINPROGRESS     },
+    { "EINTR",              EINTR           },
+    { "EINVAL",             EINVAL          },
+    { "EIO",                EIO             },
+    { "EISCONN",            EISCONN         },
+    { "EISDIR",             EISDIR          },
+    { "ELOOP",              ELOOP           },
+    { "EMFILE",             EMFILE          },
+    { "EMLINK",             EMLINK          },
+    { "EMSGSIZE",           EMSGSIZE        },
+    { "ENAMETOOLONG",       ENAMETOOLONG    },
+    { "ENETDOWN",           ENETDOWN        },
+    { "ENETRESET",          ENETRESET       },
+    { "ENETUNREACH",        ENETUNREACH     },
+    { "ENFILE",             ENFILE          },
+    { "ENOBUFS",            ENOBUFS         },
+#if defined(ENODATA)
+    { "ENODATA",            ENODATA         },
+#endif
+    { "ENODEV",             ENODEV          },
+    { "ENOENT",             ENOENT          },
+    { "ENOEXEC",            ENOEXEC         },
+    { "ENOLCK",             ENOLCK          },
+#if defined(ENOLINK)
+    { "ENOLINK",            ENOLINK         },
+#endif
+    { "ENOMEM",             ENOMEM          },
+#if defined(ENOMSG)
+    { "ENOMSG",             ENOMSG          },
+#endif
+    { "ENOPROTOOPT",        ENOPROTOOPT     },
+    { "ENOSPC",             ENOSPC          },
+#if defined(ENOSR)
+    { "ENOSR",              ENOSR           },
+#endif
+#if defined(ENOSTR)
+    { "ENOSTR",             ENOSTR          },
+#endif
+    { "ENOSYS",             ENOSYS          },
+    { "ENOTCONN",           ENOTCONN        },
+    { "ENOTDIR",            ENOTDIR         },
+    { "ENOTEMPTY",          ENOTEMPTY       },
+#if defined(ENOTRECOVERABLE)
+    { "ENOTRECOVERABLE",    ENOTRECOVERABLE },
+#endif
+    { "ENOTSOCK",           ENOTSOCK        },
+    { "ENOTSUP",            ENOTSUP         },
+    { "ENOTTY",             ENOTTY          },
+    { "ENXIO",              ENXIO           },
+    { "EOPNOTSUPP",         EOPNOTSUPP      },
+    { "EOVERFLOW",          EOVERFLOW       },
+    { "EOWNERDEAD",         EOWNERDEAD      },
+    { "EPERM",              EPERM           },
+    { "EPIPE",              EPIPE           },
+    { "EPROTO",             EPROTO          },
+    { "EPROTONOSUPPORT",    EPROTONOSUPPORT },
+    { "EPROTOTYPE",         EPROTOTYPE      },
+    { "ERANGE",             ERANGE          },
+    { "EROFS",              EROFS           },
+    { "ESPIPE",             ESPIPE          },
+    { "ESRCH",              ESRCH           },
+#if defined(ETIME)
+    { "ETIME",              ETIME           },
+#endif
+    { "ETIMEDOUT",          ETIMEDOUT       },
+#if defined(ETXTBSY)
+    { "ETXTBSY",            ETXTBSY         },
+#endif
+    { "EWOULDBLOCK",        EWOULDBLOCK     },
+    { "EXDEV",              EXDEV           }
+};
+
+duk_ret_t constructor(duk_context* ctx)
+{
+    duk_push_this(ctx);
+    duk_push_int(ctx, duk_require_int(ctx, 0));
+    duk_put_prop_string(ctx, -2, "errno");
+    duk_push_string(ctx, duk_require_string(ctx, 1));
+    duk_put_prop_string(ctx, -2, "message");
+    duk_push_string(ctx, "SystemError");
+    duk_put_prop_string(ctx, -2, "name");
+    duk_pop(ctx);
+
+    return 0;
+}
+
+} // !namespace
+
+system_error::system_error()
+    : errno_(errno)
+    , message_(std::strerror(errno_))
+{
+}
+
+system_error::system_error(int e, std::string message)
+    : errno_(e)
+    , message_(std::move(message))
+{
+}
+
+void system_error::raise(duk_context *ctx) const
+{
+    StackAssert sa(ctx, 0);
+
+    duk_get_global_string(ctx, "Irccd");
+    duk_get_prop_string(ctx, -1, "SystemError");
+    duk_remove(ctx, -2);
+    duk_push_int(ctx, errno_);
+    dukx_push_std_string(ctx, message_);
+    duk_new(ctx, 2);
+    duk_throw(ctx);
+}
+
+js_irccd_module::js_irccd_module() noexcept
+    : module("Irccd")
+{
+}
+
+void js_irccd_module::load(irccd& irccd, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    // irccd.
+    duk_push_object(plugin->context());
+
+    // Version.
+    duk_push_object(plugin->context());
+    duk_push_int(plugin->context(), IRCCD_VERSION_MAJOR);
+    duk_put_prop_string(plugin->context(), -2, "major");
+    duk_push_int(plugin->context(), IRCCD_VERSION_MINOR);
+    duk_put_prop_string(plugin->context(), -2, "minor");
+    duk_push_int(plugin->context(), IRCCD_VERSION_PATCH);
+    duk_put_prop_string(plugin->context(), -2, "patch");
+    duk_put_prop_string(plugin->context(), -2, "version");
+
+    // Create the system_error that inherits from Error.
+    duk_push_c_function(plugin->context(), constructor, 2);
+
+    // Put errno codes into the irccd.system_error object.
+    for (const auto& pair : errors) {
+        duk_push_int(plugin->context(), pair.second);
+        duk_put_prop_string(plugin->context(), -2, pair.first.c_str());
+    }
+
+    duk_push_object(plugin->context());
+    duk_get_global_string(plugin->context(), "Error");
+    duk_get_prop_string(plugin->context(), -1, "prototype");
+    duk_remove(plugin->context(), -2);
+    duk_set_prototype(plugin->context(), -2);
+    duk_put_prop_string(plugin->context(), -2, "prototype");
+    duk_put_prop_string(plugin->context(), -2, "SystemError");
+
+    // Set irccd as global.
+    duk_put_global_string(plugin->context(), "Irccd");
+
+    // Store global instance.
+    duk_push_pointer(plugin->context(), &irccd);
+    duk_put_global_string(plugin->context(), "\xff""\xff""irccd-ref");
+}
+
+irccd& dukx_get_irccd(duk_context *ctx)
+{
+    StackAssert sa(ctx);
+
+    duk_get_global_string(ctx, "\xff""\xff""irccd-ref");
+    auto ptr = static_cast<irccd*>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+
+    return *ptr;
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_irccd_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,93 @@
+/*
+ * js_irccd_module.hpp -- Irccd API
+ *
+ * Copyright (c) 2013-2017 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_JS_IRCCD_MODULE_HPP
+#define IRCCD_JS_IRCCD_MODULE_HPP
+
+/**
+ * \file js_irccd_module.hpp
+ * \brief irccd JavaScript API.
+ */
+
+#include <cerrno>
+#include <cstring>
+#include <string>
+
+#include "duktape.hpp"
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Custom JavaScript exception for system error.
+ */
+class system_error {
+private:
+    int errno_;
+    std::string message_;
+
+public:
+    /**
+     * Create a system error from the current errno value.
+     */
+    system_error();
+
+    /**
+     * Create a system error with the given errno and message.
+     *
+     * \param e the errno number
+     * \param message the message
+     */
+    system_error(int e, std::string message);
+
+    /**
+     * Raise the SystemError Javascript exception.
+     *
+     * \param ctx the context
+     */
+    void raise(duk_context* ctx) const;
+};
+
+/**
+ * \brief Irccd JavaScript API.
+ * \ingroup modules
+ */
+class js_irccd_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_irccd_module() noexcept;
+
+    /**
+     * \copydoc module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+/**
+ * Get irccd instance stored in this context.
+ *
+ * \param ctx the context
+ * \return the irccd reference
+ */
+irccd& dukx_get_irccd(duk_context* ctx);
+
+} // !irccd
+
+#endif // !IRCCD_JS_IRCCD_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_logger_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * js_logger_module.cpp -- Irccd.Logger API
+ *
+ * Copyright (c) 2013-2017 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/logger.hpp>
+
+#include "js_plugin.hpp"
+#include "js_logger_module.hpp"
+#include "js_plugin_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+duk_ret_t print(duk_context* ctx, std::ostream &out)
+{
+    out << "plugin " << dukx_get_plugin(ctx)->name() << ": " << duk_require_string(ctx, 0) << std::endl;
+
+    return 0;
+}
+
+/*
+ * Function: Irccd.Logger.info(message)
+ * --------------------------------------------------------
+ *
+ * Write a verbose message.
+ *
+ * Arguments:
+ *   - message, the message.
+ */
+duk_ret_t info(duk_context* ctx)
+{
+    return print(ctx, log::info());
+}
+
+/*
+ * Function: irccd.Logger.warning(message)
+ * --------------------------------------------------------
+ *
+ * Write a warning message.
+ *
+ * Arguments:
+ *   - message, the warning.
+ */
+duk_ret_t warning(duk_context* ctx)
+{
+    return print(ctx, log::warning());
+}
+
+/*
+ * Function: Logger.debug(message)
+ * --------------------------------------------------------
+ *
+ * Write a debug message, only shown if irccd is compiled in debug.
+ *
+ * Arguments:
+ *   - message, the message.
+ */
+duk_ret_t debug(duk_context* ctx)
+{
+    return print(ctx, log::debug());
+}
+
+const duk_function_list_entry functions[] = {
+    { "info",       info,       1 },
+    { "warning",    warning,    1 },
+    { "debug",      debug,      1 },
+    { nullptr,      nullptr,    0 }
+};
+
+} // !namespace
+
+js_logger_module::js_logger_module() noexcept
+    : module("Irccd.Logger")
+{
+}
+
+void js_logger_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, functions);
+    duk_put_prop_string(plugin->context(), -2, "Logger");
+    duk_pop(plugin->context());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_logger_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_logger_module.hpp -- Irccd.Logger API
+ *
+ * Copyright (c) 2013-2017 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_JS_LOGGER_MODULE_HPP
+#define IRCCD_JS_LOGGER_MODULE_HPP
+
+/**
+ * \file js_logger_module.hpp
+ * \brief Irccd.Logger JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief irccd.Logger JavaScript API.
+ * \ingroup modules
+ */
+class js_logger_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_logger_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_JS_LOGGER_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_plugin.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,434 @@
+/*
+ * plugin-js.cpp -- JavaScript plugins for irccd
+ *
+ * Copyright (c) 2013-2017 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 <boost/filesystem.hpp>
+
+#include "sysconfig.hpp"
+
+#if defined(HAVE_STAT)
+#  include <sys/stat.h>
+#  include <cerrno>
+#  include <cstring>
+#endif
+
+#include "fs.hpp"
+#include "irccd.hpp"
+#include "logger.hpp"
+#include "js_plugin_module.hpp"
+#include "js_server_module.hpp"
+#include "js_plugin.hpp"
+#include "service.hpp"
+#include "timer.hpp"
+
+namespace irccd {
+
+const std::string js_plugin::config_property{"\xff""\xff""irccd-plugin-config"};
+const std::string js_plugin::format_property{"\xff""\xff""irccd-plugin-format"};
+const std::string js_plugin::paths_property{"\xff""\xff""irccd-plugin-paths"};
+
+std::unordered_map<std::string, std::string> js_plugin::get_table(const std::string& name) const
+{
+    StackAssert sa(context_);
+    std::unordered_map<std::string, std::string> result;
+
+    duk_get_global_string(context_, name.c_str());
+    dukx_enumerate(context_, -1, 0, true, [&] (auto ctx) {
+        result.emplace(duk_to_string(ctx, -2), duk_to_string(ctx, -1));
+    });
+    duk_pop(context_);
+
+    return result;
+}
+
+void js_plugin::put_table(const std::string& name, const std::unordered_map<std::string, std::string>& vars)
+{
+    StackAssert sa(context_);
+
+    duk_get_global_string(context_, name.c_str());
+
+    for (const auto &pair : vars) {
+        dukx_push_std_string(context_, pair.second);
+        duk_put_prop_string(context_, -2, pair.first.c_str());
+    }
+
+    duk_pop(context_);
+}
+
+void js_plugin::call(const std::string& name, unsigned nargs)
+{
+    duk_get_global_string(context_, name.c_str());
+
+    if (duk_get_type(context_, -1) == DUK_TYPE_UNDEFINED)
+        // Function not defined, remove the undefined value and all arguments.
+        duk_pop_n(context_, nargs + 1);
+    else {
+        // Call the function and discard the result.
+        duk_insert(context_, -nargs - 1);
+
+        if (duk_pcall(context_, nargs) != 0)
+            throw dukx_exception(context_, -1, true);
+
+        duk_pop(context_);
+    }
+}
+
+void js_plugin::put_vars()
+{
+    StackAssert sa(context_);
+
+    duk_push_pointer(context_, this);
+    duk_put_global_string(context_, "\xff""\xff""plugin");
+    dukx_push_std_string(context_, name());
+    duk_put_global_string(context_, "\xff""\xff""name");
+    dukx_push_std_string(context_, path());
+    duk_put_global_string(context_, "\xff""\xff""path");
+}
+
+js_plugin::js_plugin(std::string name, std::string path)
+    : plugin(name, path)
+{
+    /*
+     * Create two special tables for configuration and formats, they are
+     * referenced later as
+     *
+     *   - irccd.Plugin.config
+     *   - irccd.Plugin.format
+     *   - irccd.Plugin.paths
+     *
+     * In js_plugin_module.cpp.
+     */
+    duk_push_object(context_);
+    duk_put_global_string(context_, config_property.c_str());
+    duk_push_object(context_);
+    duk_put_global_string(context_, format_property.c_str());
+    duk_push_object(context_);
+    duk_put_global_string(context_, paths_property.c_str());
+
+    // Used by many Javascript APIs.
+    duk_push_object(context_);
+    duk_put_global_string(context_, "irccd");
+}
+
+void js_plugin::on_channel_mode(irccd &, const channel_mode_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.mode);
+    dukx_push_std_string(context_, event.argument);
+    call("onChannelMode", 5);
+}
+
+void js_plugin::on_channel_notice(irccd &, const channel_notice_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.message);
+    call("onChannelNotice", 4);
+}
+
+void js_plugin::on_command(irccd &, const message_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.message);
+    call("onCommand", 4);
+}
+
+void js_plugin::on_connect(irccd &, const connect_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    call("onConnect", 1);
+}
+
+void js_plugin::on_invite(irccd &, const invite_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    call("onInvite", 3);
+}
+
+void js_plugin::on_join(irccd &, const join_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    call("onJoin", 3);
+}
+
+void js_plugin::on_kick(irccd &, const kick_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.target);
+    dukx_push_std_string(context_, event.reason);
+    call("onKick", 5);
+}
+
+void js_plugin::on_load(irccd &irccd)
+{
+    StackAssert sa(context_);
+
+    /*
+     * Duktape currently emit useless warnings when a file do
+     * not exists so we do a homemade access.
+     */
+#if defined(HAVE_STAT)
+    struct stat st;
+
+    if (::stat(path().c_str(), &st) < 0)
+        throw std::runtime_error(std::strerror(errno));
+#endif
+
+    // Try to load the file (does not call onLoad yet).
+    dukx_peval_file(context_, path());
+    duk_pop(context_);
+
+    /*
+     * We put configuration and formats after loading the file and before
+     * calling onLoad to allow the plugin adding configuration to
+     * irccd.Plugin.(config|format) before the user.
+     */
+    put_vars();
+    set_config(irccd.plugins().config(name()));
+    set_formats(irccd.plugins().formats(name()));
+    set_paths(irccd.plugins().paths(name()));
+
+    // Read metadata .
+    duk_get_global_string(context_, "info");
+
+    if (duk_get_type(context_, -1) == DUK_TYPE_OBJECT) {
+        // 'author'
+        duk_get_prop_string(context_, -1, "author");
+        set_author(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : author());
+        duk_pop(context_);
+
+        // 'license'
+        duk_get_prop_string(context_, -1, "license");
+        set_license(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : license());
+        duk_pop(context_);
+
+        // 'summary'
+        duk_get_prop_string(context_, -1, "summary");
+        set_summary(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : summary());
+        duk_pop(context_);
+
+        // 'version'
+        duk_get_prop_string(context_, -1, "version");
+        set_version(duk_is_string(context_, -1) ? duk_get_string(context_, -1) : version());
+        duk_pop(context_);
+    }
+
+    duk_pop(context_);
+    call("onLoad", 0);
+}
+
+void js_plugin::on_message(irccd &, const message_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.message);
+    call("onMessage", 4);
+}
+
+void js_plugin::on_me(irccd &, const me_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.message);
+    call("onMe", 4);
+}
+
+void js_plugin::on_mode(irccd &, const mode_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.mode);
+    call("onMode", 3);
+}
+
+void js_plugin::on_names(irccd &, const names_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_array(context_, event.names, dukx_push_std_string);
+    call("onNames", 3);
+}
+
+void js_plugin::on_nick(irccd &, const nick_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.nickname);
+    call("onNick", 3);
+}
+
+void js_plugin::on_notice(irccd &, const notice_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.message);
+    call("onNotice", 3);
+}
+
+void js_plugin::on_part(irccd &, const part_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.reason);
+    call("onPart", 4);
+}
+
+void js_plugin::on_query(irccd &, const query_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.message);
+    call("onQuery", 3);
+}
+
+void js_plugin::on_query_command(irccd &, const query_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.message);
+    call("onQueryCommand", 3);
+}
+
+void js_plugin::on_reload(irccd &)
+{
+    StackAssert sa(context_);
+
+    call("onReload");
+}
+
+void js_plugin::on_topic(irccd &, const topic_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    dukx_push_std_string(context_, event.origin);
+    dukx_push_std_string(context_, event.channel);
+    dukx_push_std_string(context_, event.topic);
+    call("onTopic", 4);
+}
+
+void js_plugin::on_unload(irccd &)
+{
+    StackAssert sa(context_);
+
+    call("onUnload");
+}
+
+void js_plugin::on_whois(irccd &, const whois_event &event)
+{
+    StackAssert sa(context_);
+
+    dukx_push_server(context_, std::move(event.server));
+    duk_push_object(context_);
+    dukx_push_std_string(context_, event.whois.nick);
+    duk_put_prop_string(context_, -2, "nickname");
+    dukx_push_std_string(context_, event.whois.user);
+    duk_put_prop_string(context_, -2, "username");
+    dukx_push_std_string(context_, event.whois.realname);
+    duk_put_prop_string(context_, -2, "realname");
+    dukx_push_std_string(context_, event.whois.host);
+    duk_put_prop_string(context_, -2, "host");
+    dukx_push_array(context_, event.whois.channels, dukx_push_std_string);
+    duk_put_prop_string(context_, -2, "channels");
+    call("onWhois", 2);
+}
+
+js_plugin_loader::js_plugin_loader(irccd &irccd) noexcept
+    : plugin_loader({}, { ".js" })
+    , irccd_(irccd)
+{
+}
+
+js_plugin_loader::~js_plugin_loader() noexcept = default;
+
+void js_plugin_loader::add_module(std::unique_ptr<module> module)
+{
+    assert(module);
+
+    modules_.push_back(std::move(module));
+}
+
+std::shared_ptr<plugin> js_plugin_loader::open(const std::string& id,
+                                               const std::string& path) noexcept
+{
+    if (path.rfind(".js") == std::string::npos)
+        return nullptr;
+
+    try {
+        auto plugin = std::make_shared<js_plugin>(id, path);
+
+        for (const auto& mod : modules_) {
+            log::debug() << "plugin " << plugin->name() << ": ";
+            log::debug() << "loading " << mod->name() << " Javascript API" << std::endl;
+            mod->load(irccd_, plugin);
+        }
+
+        return plugin;
+    } catch (const std::exception &ex) {
+        log::warning() << "plugin " << id << ": " << ex.what() << std::endl;
+    }
+
+    return nullptr;
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_plugin.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,277 @@
+/*
+ * js_plugin.hpp -- JavaScript plugins for irccd
+ *
+ * Copyright (c) 2013-2017 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_JS_PLUGIN_HPP
+#define IRCCD_JS_PLUGIN_HPP
+
+/**
+ * \file js_plugin.hpp
+ * \brief JavaScript plugins for irccd.
+ */
+
+#include <vector>
+
+#include "duktape.hpp"
+#include "plugin.hpp"
+
+namespace irccd {
+
+class module;
+
+/**
+ * \brief JavaScript plugins for irccd.
+ * \ingroup plugins
+ */
+class js_plugin : public plugin {
+public:
+    /**
+     * Global property where to read/write plugin configuration (object).
+     */
+    static const std::string config_property;
+
+    /**
+     * Global property where to read/write plugin formats (object).
+     */
+    static const std::string format_property;
+
+    /**
+     * Global property where paths are defined (object).
+     */
+    static const std::string paths_property;
+
+private:
+    // JavaScript context
+    UniqueContext context_;
+
+    // Private helpers.
+    std::unordered_map<std::string, std::string> get_table(const std::string&) const;
+    void put_table(const std::string&, const std::unordered_map<std::string, std::string>&);
+    void call(const std::string&, unsigned = 0);
+    void put_vars();
+
+public:
+    /**
+     * Constructor.
+     *
+     * \param name the plugin name
+     * \param path the path to the plugin
+     */
+    js_plugin(std::string name, std::string path);
+
+    /**
+     * Access the Duktape context.
+     *
+     * \return the context
+     */
+    inline UniqueContext& context() noexcept
+    {
+        return context_;
+    }
+
+    /**
+     * \copydoc Plugin::config
+     */
+    plugin_config config() override
+    {
+        return get_table(config_property);
+    }
+
+    /**
+     * \copydoc Plugin::setConfig
+     */
+    void set_config(plugin_config config) override
+    {
+        put_table(config_property, config);
+    }
+
+    /**
+     * \copydoc Plugin::formats
+     */
+    plugin_formats formats() override
+    {
+        return get_table(format_property);
+    }
+
+    /**
+     * \copydoc Plugin::setFormats
+     */
+    void set_formats(plugin_formats formats) override
+    {
+        put_table(format_property, formats);
+    }
+
+    /**
+     * \copydoc Plugin::paths
+     */
+    plugin_paths paths() override
+    {
+        return get_table(paths_property);
+    }
+
+    /**
+     * \copydoc Plugin::set_paths
+     */
+    void set_paths(plugin_paths paths) override
+    {
+        put_table(paths_property, std::move(paths));
+    }
+
+    /**
+     * \copydoc Plugin::on_command
+     */
+    void on_command(irccd& irccd, const message_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_connect
+     */
+    void on_connect(irccd& irccd, const connect_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_channel_mode
+     */
+    void on_channel_mode(irccd& irccd, const channel_mode_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_channel_notice
+     */
+    void on_channel_notice(irccd& irccd, const channel_notice_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_invite
+     */
+    void on_invite(irccd& irccd, const invite_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_join
+     */
+    void on_join(irccd& irccd, const join_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_kick
+     */
+    void on_kick(irccd& irccd, const kick_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_load
+     */
+    void on_load(irccd& irccd) override;
+
+    /**
+     * \copydoc Plugin::on_message
+     */
+    void on_message(irccd& irccd, const message_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_me
+     */
+    void on_me(irccd& irccd, const me_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_mode
+     */
+    void on_mode(irccd& irccd, const mode_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_names
+     */
+    void on_names(irccd& irccd, const names_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_nick
+     */
+    void on_nick(irccd& irccd, const nick_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_notice
+     */
+    void on_notice(irccd& irccd, const notice_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_part
+     */
+    void on_part(irccd& irccd, const part_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_query
+     */
+    void on_query(irccd& irccd, const query_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_query_command
+     */
+    void on_query_command(irccd& irccd, const query_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_reload
+     */
+    void on_reload(irccd& irccd) override;
+
+    /**
+     * \copydoc Plugin::on_topic
+     */
+    void on_topic(irccd& irccd, const topic_event& event) override;
+
+    /**
+     * \copydoc Plugin::on_unload
+     */
+    void on_unload(irccd& irccd) override;
+
+    /**
+     * \copydoc Plugin::on_whois
+     */
+    void on_whois(irccd& irccd, const whois_event& event) override;
+};
+
+/**
+ * \brief Implementation for searching Javascript plugins.
+ */
+class js_plugin_loader : public plugin_loader {
+private:
+    irccd& irccd_;
+    std::vector<std::unique_ptr<module>> modules_;
+
+public:
+    /**
+     * Constructor.
+     *
+     * \param irccd the irccd instance
+     */
+    js_plugin_loader(irccd& irccd) noexcept;
+
+    /**
+     * Destructor defaulted.
+     */
+    ~js_plugin_loader() noexcept;
+
+    /**
+     * Register a new module for loading new plugins.
+     *
+     * \param module the module to add
+     */
+    void add_module(std::unique_ptr<module> module);
+
+    /**
+     * \copydoc PluginLoader::open
+     */
+    std::shared_ptr<plugin> open(const std::string& id,
+                                 const std::string& path) noexcept override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_PLUGIN_JS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_plugin_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,385 @@
+/*
+ * js_plugin_module.cpp -- Irccd.Plugin API
+ *
+ * Copyright (c) 2013-2017 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/irccd.hpp>
+#include <irccd/service.hpp>
+
+#include "js_irccd_module.hpp"
+#include "js_plugin.hpp"
+#include "js_plugin_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+const char plugin_ref[] = "\xff""\xff""irccd-plugin-ptr";
+
+/*
+ * wrap
+ * ------------------------------------------------------------------
+ *
+ * Wrap function for these functions because they all takes the same arguments.
+ *
+ * - load,
+ * - reload,
+ * - unload.
+ */
+template <typename Func>
+duk_idx_t wrap(duk_context* ctx, int nret, Func&& func)
+{
+    std::string name = duk_require_string(ctx, 0);
+
+    try {
+        func(dukx_get_irccd(ctx), name);
+    } catch (const std::out_of_range &ex) {
+        dukx_throw(ctx, ReferenceError(ex.what()));
+    } catch (const std::exception &ex) {
+        dukx_throw(ctx, Error(ex.what()));
+    }
+
+    return nret;
+}
+
+/*
+ * set
+ * ------------------------------------------------------------------
+ *
+ * This setter is used to replace the Irccd.Plugin.(config|format|paths)
+ * property when the plugin assign a new one.
+ *
+ * Because the plugin configuration always has higher priority, when a new
+ * object is assigned to 'config' or to the 'format' property, the plugin
+ * configuration is merged to the assigned one, adding or replacing any values.
+ *
+ * Example:
+ *
+ * Plugin 'xyz' does:
+ *
+ * Irccd.Plugin.config = {
+ *      mode: "simple",
+ *      level: "123"
+ * };
+ *
+ * The user configuration is:
+ *
+ * [plugin.xyz]
+ * mode = "hard"
+ * path = "/var"
+ *
+ * The final user table looks like this:
+ *
+ * Irccd.Plugin.Config = {
+ *      mode: "hard",
+ *      level: "123",
+ *      path: "/var"
+ * };
+ */
+duk_ret_t set(duk_context* ctx, const std::string& name)
+{
+    if (!duk_is_object(ctx, 0))
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name.c_str());
+
+    // Merge old table with new one.
+    duk_get_global_string(ctx, name.c_str());
+    duk_enum(ctx, -1, 0);
+
+    while (duk_next(ctx, -1, true))
+        duk_put_prop(ctx, 0);
+
+    // Pop enum and old table.
+    duk_pop_2(ctx);
+
+    // Replace the old table with the new assigned one.
+    duk_put_global_string(ctx, name.c_str());
+
+    return 0;
+}
+
+/*
+ * get
+ * ------------------------------------------------------------------
+ *
+ * Get the Irccd.Plugin.(config|format|paths) property.
+ */
+duk_ret_t get(duk_context* ctx, const std::string& name)
+{
+    duk_get_global_string(ctx, name.c_str());
+
+    return 1;
+}
+
+/*
+ * set_config
+ * ------------------------------------------------------------------
+ *
+ * Wrap setter for Irccd.Plugin.config property.
+ */
+duk_ret_t set_config(duk_context* ctx)
+{
+    return set(ctx, js_plugin::config_property);
+}
+
+/*
+ * get_config
+ * ------------------------------------------------------------------
+ *
+ * Wrap getter for Irccd.Plugin.config property.
+ */
+duk_ret_t get_config(duk_context* ctx)
+{
+    return get(ctx, js_plugin::config_property);
+}
+
+/*
+ * set_format
+ * ------------------------------------------------------------------
+ *
+ * Wrap setter for Irccd.Plugin.format property.
+ */
+duk_ret_t set_format(duk_context* ctx)
+{
+    return set(ctx, js_plugin::format_property);
+}
+
+/*
+ * get_format
+ * ------------------------------------------------------------------
+ *
+ * Wrap getter for Irccd.Plugin.format property.
+ */
+duk_ret_t get_format(duk_context* ctx)
+{
+    return get(ctx, js_plugin::format_property);
+}
+
+/*
+ * set_paths
+ * ------------------------------------------------------------------
+ *
+ * Wrap setter for Irccd.Plugin.format property.
+ */
+duk_ret_t set_paths(duk_context* ctx)
+{
+    return set(ctx, js_plugin::paths_property);
+}
+
+/*
+ * get_paths
+ * ------------------------------------------------------------------
+ *
+ * Wrap getter for Irccd.Plugin.format property.
+ */
+duk_ret_t get_paths(duk_context* ctx)
+{
+    return get(ctx, js_plugin::paths_property);
+}
+
+/*
+ * Function: Irccd.Plugin.info([name])
+ * ------------------------------------------------------------------
+ *
+ * Get information about a plugin.
+ *
+ * The returned object as the following properties:
+ *
+ * - name: (string) the plugin identifier,
+ * - author: (string) the author,
+ * - license: (string) the license,
+ * - summary: (string) a short description,
+ * - version: (string) the version
+ *
+ * Arguments:
+ *   - name, the plugin identifier, if not specified the current plugin is
+ *     selected.
+ * Returns:
+ *   The plugin information or undefined if the plugin was not found.
+ */
+duk_idx_t info(duk_context* ctx)
+{
+    std::shared_ptr<plugin> plugin;
+
+    if (duk_get_top(ctx) >= 1)
+        plugin = dukx_get_irccd(ctx).plugins().get(duk_require_string(ctx, 0));
+    else
+        plugin = dukx_get_plugin(ctx);
+
+    if (!plugin)
+        return 0;
+
+    duk_push_object(ctx);
+    dukx_push_std_string(ctx, plugin->name());
+    duk_put_prop_string(ctx, -2, "name");
+    dukx_push_std_string(ctx, plugin->author());
+    duk_put_prop_string(ctx, -2, "author");
+    dukx_push_std_string(ctx, plugin->license());
+    duk_put_prop_string(ctx, -2, "license");
+    dukx_push_std_string(ctx, plugin->summary());
+    duk_put_prop_string(ctx, -2, "summary");
+    dukx_push_std_string(ctx, plugin->version());
+    duk_put_prop_string(ctx, -2, "version");
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Plugin.list()
+ * ------------------------------------------------------------------
+ *
+ * Get the list of plugins, the array returned contains all plugin names.
+ *
+ * Returns:
+ *   The list of all plugin names.
+ */
+duk_idx_t list(duk_context* ctx)
+{
+    dukx_push_array(ctx, dukx_get_irccd(ctx).plugins().list(), [] (auto ctx, auto plugin) {
+        dukx_push_std_string(ctx, plugin->name());
+    });
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Plugin.load(name)
+ * ------------------------------------------------------------------
+ *
+ * Load a plugin by name. This function will search through the standard
+ * directories.
+ *
+ * Arguments:
+ *   - name, the plugin identifier.
+ * Throws:
+ *   - Error on errors,
+ *   - ReferenceError if the plugin was not found.
+ */
+duk_idx_t load(duk_context* ctx)
+{
+    return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) {
+        irccd.plugins().load(name);
+    });
+}
+
+/*
+ * Function: Irccd.Plugin.reload(name)
+ * ------------------------------------------------------------------
+ *
+ * Reload a plugin by name.
+ *
+ * Arguments:
+ *   - name, the plugin identifier.
+ * Throws:
+ *   - Error on errors,
+ *   - ReferenceError if the plugin was not found.
+ */
+duk_idx_t reload(duk_context* ctx)
+{
+    return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) {
+        irccd.plugins().reload(name);
+    });
+}
+
+/*
+ * Function: Irccd.Plugin.unload(name)
+ * ------------------------------------------------------------------
+ *
+ * Unload a plugin by name.
+ *
+ * Arguments:
+ *   - name, the plugin identifier.
+ * Throws:
+ *   - Error on errors,
+ *   - ReferenceError if the plugin was not found.
+ */
+duk_idx_t unload(duk_context* ctx)
+{
+    return wrap(ctx, 0, [&] (irccd &irccd, const std::string &name) {
+        irccd.plugins().unload(name);
+    });
+}
+
+const duk_function_list_entry functions[] = {
+    { "info",   info,       DUK_VARARGS     },
+    { "list",   list,       0               },
+    { "load",   load,       1               },
+    { "reload", reload,     1               },
+    { "unload", unload,     1               },
+    { nullptr,  nullptr,    0               }
+};
+
+} // !namespace
+
+js_plugin_module::js_plugin_module() noexcept
+    : module("Irccd.Plugin")
+{
+}
+
+void js_plugin_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_push_pointer(plugin->context(), new std::weak_ptr<js_plugin>(plugin));
+    duk_push_object(plugin->context());
+    duk_push_c_function(plugin->context(), [] (auto ctx) -> duk_ret_t {
+        duk_get_global_string(ctx, plugin_ref);
+        delete static_cast<std::shared_ptr<js_plugin>*>(duk_to_pointer(ctx, -1));
+        duk_pop(ctx);
+        duk_push_null(ctx);
+        duk_put_global_string(ctx, plugin_ref);
+        return 0;
+    }, 1);
+    duk_set_finalizer(plugin->context(), -2);
+    duk_put_global_string(plugin->context(), "\xff""\xff""dummy-shared-ptr");
+    duk_put_global_string(plugin->context(), plugin_ref);
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, functions);
+
+    // 'config' property.
+    duk_push_string(plugin->context(), "config");
+    duk_push_c_function(plugin->context(), get_config, 0);
+    duk_push_c_function(plugin->context(), set_config, 1);
+    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+
+    // 'format' property.
+    duk_push_string(plugin->context(), "format");
+    duk_push_c_function(plugin->context(), get_format, 0);
+    duk_push_c_function(plugin->context(), set_format, 1);
+    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+
+    // 'format' property.
+    duk_push_string(plugin->context(), "paths");
+    duk_push_c_function(plugin->context(), get_paths, 0);
+    duk_push_c_function(plugin->context(), set_paths, 1);
+    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+
+    duk_put_prop_string(plugin->context(), -2, "Plugin");
+    duk_pop(plugin->context());
+}
+
+std::shared_ptr<js_plugin> dukx_get_plugin(duk_context* ctx)
+{
+    StackAssert sa(ctx);
+
+    duk_get_global_string(ctx, plugin_ref);
+    auto plugin = static_cast<std::weak_ptr<js_plugin>*>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+
+    return plugin->lock();
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_plugin_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * js_plugin_module.hpp -- Irccd.Plugin API
+ *
+ * Copyright (c) 2013-2017 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_JS_PLUGIN_MODULE_HPP
+#define IRCCD_JS_PLUGIN_MODULE_HPP
+
+/**
+ * \file js_plugin_module.hpp
+ * \brief Irccd.Plugin JavaScript API.
+ */
+
+#include "duktape.hpp"
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Irccd.Plugin JavaScript API.
+ * \ingroup modules
+ */
+class js_plugin_module : public module {
+public:
+    /**
+     * Irccd.Plugin.
+     */
+    js_plugin_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+/**
+ * Access the plugin stored in this context.
+ *
+ * \param ctx the context
+ * \return the plugin
+ */
+std::shared_ptr<js_plugin> dukx_get_plugin(duk_context* ctx);
+
+} // !irccd
+
+#endif // !IRCCD_JS_PLUGIN_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_server_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,581 @@
+/*
+ * js_server_module.cpp -- Irccd.Server API
+ *
+ * Copyright (c) 2013-2017 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 <cassert>
+#include <sstream>
+#include <unordered_map>
+
+#include <irccd.hpp>
+#include <irccd/js_plugin.hpp>
+#include <irccd/server.hpp>
+#include <irccd/service.hpp>
+
+#include "js_irccd_module.hpp"
+#include "js_server_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+const char *signature("\xff""\xff""irccd-server-ptr");
+const char *prototype("\xff""\xff""irccd-server-prototype");
+
+std::shared_ptr<server> self(duk_context* ctx)
+{
+    StackAssert sa(ctx);
+
+    duk_push_this(ctx);
+    duk_get_prop_string(ctx, -1, signature);
+    auto ptr = duk_to_pointer(ctx, -1);
+    duk_pop_2(ctx);
+
+    if (!ptr)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
+
+    return *static_cast<std::shared_ptr<server>*>(ptr);
+}
+
+/*
+ * Method: Server.cmode(channel, mode)
+ * ------------------------------------------------------------------
+ *
+ * Change a channel mode.
+ *
+ * Arguments:
+ *   - channel, the channel,
+ *   - mode, the mode.
+ */
+duk_ret_t cmode(duk_context* ctx)
+{
+    self(ctx)->cmode(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.cnotice(channel, message)
+ * ------------------------------------------------------------------
+ *
+ * Send a channel notice.
+ *
+ * Arguments:
+ *   - channel, the channel,
+ *   - message, the message.
+ */
+duk_ret_t cnotice(duk_context* ctx)
+{
+    self(ctx)->cnotice(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.info()
+ * ------------------------------------------------------------------
+ *
+ * Get the server information as an object containing the following properties:
+ *
+ * name: the server unique name
+ * host: the host name
+ * port: the port number
+ * ssl: true if using ssl
+ * sslVerify: true if ssl was verified
+ * channels: an array of all channels
+ */
+duk_ret_t info(duk_context* ctx)
+{
+    auto server = self(ctx);
+
+    duk_push_object(ctx);
+    dukx_push_std_string(ctx, server->name());
+    duk_put_prop_string(ctx, -2, "name");
+    dukx_push_std_string(ctx, server->host());
+    duk_put_prop_string(ctx, -2, "host");
+    duk_push_int(ctx, server->port());
+    duk_put_prop_string(ctx, -2, "port");
+    duk_push_boolean(ctx, server->flags() & server::ssl);
+    duk_put_prop_string(ctx, -2, "ssl");
+    duk_push_boolean(ctx, server->flags() & server::ssl_verify);
+    duk_put_prop_string(ctx, -2, "sslVerify");
+    dukx_push_std_string(ctx, server->command_char());
+    duk_put_prop_string(ctx, -2, "commandChar");
+    dukx_push_std_string(ctx, server->realname());
+    duk_put_prop_string(ctx, -2, "realname");
+    dukx_push_std_string(ctx, server->nickname());
+    duk_put_prop_string(ctx, -2, "nickname");
+    dukx_push_std_string(ctx, server->username());
+    duk_put_prop_string(ctx, -2, "username");
+    dukx_push_array(ctx, server->channels(), [&] (auto ctx, auto channel) {
+        dukx_push_std_string(ctx, channel);
+    });
+    duk_put_prop_string(ctx, -2, "channels");
+
+    return 1;
+}
+
+/*
+ * Method: Server.invite(target, channel)
+ * ------------------------------------------------------------------
+ *
+ * Invite someone to a channel.
+ *
+ * Arguments:
+ *   - target, the target to invite,
+ *   - channel, the channel.
+ */
+duk_ret_t invite(duk_context* ctx)
+{
+    self(ctx)->invite(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.join(channel, password = undefined)
+ * ------------------------------------------------------------------
+ *
+ * Join a channel with an optional password.
+ *
+ * Arguments:
+ *   - channel, the channel to join,
+ *   - password, the password or undefined to not use.
+ */
+duk_ret_t join(duk_context* ctx)
+{
+    self(ctx)->join(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.kick(target, channel, reason = undefined)
+ * ------------------------------------------------------------------
+ *
+ * Kick someone from a channel.
+ *
+ * Arguments:
+ *   - target, the target to kick,
+ *   - channel, the channel,
+ *   - reason, the optional reason or undefined to not set.
+ */
+duk_ret_t kick(duk_context* ctx)
+{
+    self(ctx)->kick(duk_require_string(ctx, 0), duk_require_string(ctx, 1), dukx_get_std_string(ctx, 2));
+
+    return 0;
+}
+
+/*
+ * Method: Server.me(target, message)
+ * ------------------------------------------------------------------
+ *
+ * Send a CTCP Action.
+ *
+ * Arguments:
+ *   - target, the target or a channel,
+ *   - message, the message.
+ */
+duk_ret_t me(duk_context* ctx)
+{
+    self(ctx)->me(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.message(target, message)
+ * ------------------------------------------------------------------
+ *
+ * Send a message.
+ *
+ * Arguments:
+ *   - target, the target or a channel,
+ *   - message, the message.
+ */
+duk_ret_t message(duk_context* ctx)
+{
+    self(ctx)->message(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.mode(mode)
+ * ------------------------------------------------------------------
+ *
+ * Change your mode.
+ *
+ * Arguments:
+ *   - mode, the new mode.
+ */
+duk_ret_t mode(duk_context* ctx)
+{
+    self(ctx)->mode(duk_require_string(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Method: Server.names(channel)
+ * ------------------------------------------------------------------
+ *
+ * Get the list of names from a channel.
+ *
+ * Arguments:
+ *   - channel, the channel.
+ */
+duk_ret_t names(duk_context* ctx)
+{
+    self(ctx)->names(duk_require_string(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Method: Server.nick(nickname)
+ * ------------------------------------------------------------------
+ *
+ * Change the nickname.
+ *
+ * Arguments:
+ *   - nickname, the nickname.
+ */
+duk_ret_t nick(duk_context* ctx)
+{
+    self(ctx)->set_nickname(duk_require_string(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Method: Server.notice(target, message)
+ * ------------------------------------------------------------------
+ *
+ * Send a private notice.
+ *
+ * Arguments:
+ *   - target, the target,
+ *   - message, the notice message.
+ */
+duk_ret_t notice(duk_context* ctx)
+{
+    self(ctx)->notice(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.part(channel, reason = undefined)
+ * ------------------------------------------------------------------
+ *
+ * Leave a channel.
+ *
+ * Arguments:
+ *   - channel, the channel to leave,
+ *   - reason, the optional reason, keep undefined for portability.
+ */
+duk_ret_t part(duk_context* ctx)
+{
+    self(ctx)->part(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.send(raw)
+ * ------------------------------------------------------------------
+ *
+ * Send a raw message to the IRC server.
+ *
+ * Arguments:
+ *   - raw, the raw message (without terminators).
+ */
+duk_ret_t send(duk_context* ctx)
+{
+    self(ctx)->send(duk_require_string(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Method: Server.topic(channel, topic)
+ * ------------------------------------------------------------------
+ *
+ * Change a channel topic.
+ *
+ * Arguments:
+ *   - channel, the channel,
+ *   - topic, the new topic.
+ */
+duk_ret_t topic(duk_context* ctx)
+{
+    self(ctx)->topic(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    return 0;
+}
+
+/*
+ * Method: Server.whois(target)
+ * ------------------------------------------------------------------
+ *
+ * Get whois information.
+ *
+ * Arguments:
+ *   - target, the target.
+ */
+duk_ret_t whois(duk_context* ctx)
+{
+    self(ctx)->whois(duk_require_string(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Method: Server.toString()
+ * ------------------------------------------------------------------
+ *
+ * Convert the object to std::string, convenience for adding the object
+ * as property key.
+ *
+ * duk_ret_turns:
+ *   The server name (unique).
+ */
+duk_ret_t toString(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, self(ctx)->name());
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Server(params) [constructor]
+ * ------------------------------------------------------------------
+ *
+ * Construct a new server.
+ *
+ * Params must be filled with the following properties:
+ *
+ * name: the name,
+ * host: the host,
+ * ipv6: true to use ipv6,      (Optional: default false)
+ * port: the port number,       (Optional: default 6667)
+ * password: the password,      (Optional: default none)
+ * channels: array of channels  (Optiona: default empty)
+ * ssl: true to use ssl,        (Optional: default false)
+ * sslVerify: true to verify    (Optional: default true)
+ * nickname: "nickname",        (Optional, default: irccd)
+ * username: "user name",       (Optional, default: irccd)
+ * realname: "real name",       (Optional, default: IRC Client Daemon)
+ * commandChar: "!",            (Optional, the command char, default: "!")
+ */
+duk_ret_t constructor(duk_context* ctx)
+{
+    if (!duk_is_constructor_call(ctx))
+        return 0;
+
+    duk_check_type(ctx, 0, DUK_TYPE_OBJECT);
+
+    try {
+        auto json = duk_json_encode(ctx, 0);
+        auto s = server::from_json(nlohmann::json::parse(json));
+
+        duk_push_this(ctx);
+        duk_push_pointer(ctx, new std::shared_ptr<server>(std::move(s)));
+        duk_put_prop_string(ctx, -2, signature);
+        duk_pop(ctx);
+    } catch (const std::exception& ex) {
+        duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
+    }
+
+    return 0;
+}
+
+/*
+ * Function: Irccd.Server() [destructor]
+ * ------------------------------------------------------------------
+ *
+ * Delete the property.
+ */
+duk_ret_t destructor(duk_context* ctx)
+{
+    duk_get_prop_string(ctx, 0, signature);
+    delete static_cast<std::shared_ptr<server>*>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+    duk_del_prop_string(ctx, 0, signature);
+
+    return 0;
+}
+
+/*
+ * Function: Irccd.Server.add(s)
+ * ------------------------------------------------------------------
+ *
+ * Register a new server to the irccd instance.
+ *
+ * Arguments:
+ *   - s, the server to add.
+ */
+duk_ret_t add(duk_context* ctx)
+{
+    dukx_get_irccd(ctx).servers().add(dukx_require_server(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Function: Irccd.Server.find(name)
+ * ------------------------------------------------------------------
+ *
+ * Find a server by name.
+ *
+ * Arguments:
+ *   - name, the server name
+ * duk_ret_turns:
+ *   The server object or undefined if not found.
+ */
+duk_ret_t find(duk_context* ctx)
+{
+    auto server = dukx_get_irccd(ctx).servers().get(duk_require_string(ctx, 0));
+
+    if (!server)
+        return 0;
+
+    dukx_push_server(ctx, server);
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Server.list()
+ * ------------------------------------------------------------------
+ *
+ * Get the map of all loaded servers.
+ *
+ * duk_ret_turns:
+ *   An object with string-to-servers pairs.
+ */
+duk_ret_t list(duk_context* ctx)
+{
+    duk_push_object(ctx);
+
+    for (const auto &server : dukx_get_irccd(ctx).servers().servers()) {
+        dukx_push_server(ctx, server);
+        duk_put_prop_string(ctx, -2, server->name().c_str());
+    }
+
+    return 1;
+}
+
+/*
+ * Function: irccd.Server.remove(name)
+ * ------------------------------------------------------------------
+ *
+ * Remove a server from the irccd instance. You can pass the server object since
+ * it's coercible to a string.
+ *
+ * Arguments:
+ *   - name the server name.
+ */
+duk_ret_t remove(duk_context* ctx)
+{
+    dukx_get_irccd(ctx).servers().remove(duk_require_string(ctx, 0));
+
+    return 0;
+}
+
+const duk_function_list_entry methods[] = {
+    { "cmode",      cmode,      2           },
+    { "cnotice",    cnotice,    2           },
+    { "info",       info,       0           },
+    { "invite",     invite,     2           },
+    { "join",       join,       DUK_VARARGS },
+    { "kick",       kick,       DUK_VARARGS },
+    { "me",         me,         2           },
+    { "message",    message,    2           },
+    { "mode",       mode,       1           },
+    { "names",      names,      1           },
+    { "nick",       nick,       1           },
+    { "notice",     notice,     2           },
+    { "part",       part,       DUK_VARARGS },
+    { "send",       send,       1           },
+    { "topic",      topic,      2           },
+    { "whois",      whois,      1           },
+    { "toString",   toString,   0           },
+    { nullptr,      nullptr,    0           }
+};
+
+const duk_function_list_entry functions[] = {
+    { "add",        add,        1           },
+    { "find",       find,       1           },
+    { "list",       list,       0           },
+    { "remove",     remove,     1           },
+    { nullptr,      nullptr,    0           }
+};
+
+} // !namespace
+
+js_server_module::js_server_module() noexcept
+    : module("Irccd.Server")
+{
+}
+
+void js_server_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_c_function(plugin->context(), constructor, 1);
+    duk_put_function_list(plugin->context(), -1, functions);
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, methods);
+    duk_push_c_function(plugin->context(), destructor, 1);
+    duk_set_finalizer(plugin->context(), -2);
+    duk_dup_top(plugin->context());
+    duk_put_global_string(plugin->context(), prototype);
+    duk_put_prop_string(plugin->context(), -2, "prototype");
+    duk_put_prop_string(plugin->context(), -2, "Server");
+    duk_pop(plugin->context());
+}
+
+void dukx_push_server(duk_context* ctx, std::shared_ptr<server> server)
+{
+    assert(ctx);
+    assert(server);
+
+    StackAssert sa(ctx, 1);
+
+    duk_push_object(ctx);
+    duk_push_pointer(ctx, new std::shared_ptr<class server>(std::move(server)));
+    duk_put_prop_string(ctx, -2, signature);
+    duk_get_global_string(ctx, prototype);
+    duk_set_prototype(ctx, -2);
+}
+
+std::shared_ptr<server> dukx_require_server(duk_context* ctx, duk_idx_t index)
+{
+    if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, signature))
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
+
+    duk_get_prop_string(ctx, index, signature);
+    auto file = *static_cast<std::shared_ptr<server> *>(duk_to_pointer(ctx, -1));
+    duk_pop(ctx);
+
+    return file;
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_server_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,70 @@
+/*
+ * js_server_module.hpp -- Irccd.Server API
+ *
+ * Copyright (c) 2013-2017 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_JS_SERVER_MODULE_HPP
+#define IRCCD_JS_SERVER_MODULE_HPP
+
+/**
+ * \file mod-server.hpp
+ * \brief irccd.Server JavaScript API.
+ */
+
+#include "duktape.hpp"
+#include "module.hpp"
+#include "server.hpp"
+
+namespace irccd {
+
+/**
+ * \brief irccd.Server JavaScript API.
+ * \ingroup modules
+ */
+class js_server_module : public module {
+public:
+    /**
+     * irccd.Server.
+     */
+    js_server_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+/**
+ * Push a server.
+ *
+ * \pre server != nullptr
+ * \param ctx the context
+ * \param server the server
+ */
+void dukx_push_server(duk_context* ctx, std::shared_ptr<server> server);
+
+/**
+ * Require a server. Raise a JavaScript error if not a Server.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the server
+ */
+std::shared_ptr<server> dukx_require_server(duk_context* ctx, duk_idx_t index);
+
+} // !irccd
+
+#endif // !IRCCD_JS_SERVER_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_system_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,244 @@
+/*
+ * js_system_module.cpp -- Irccd.System API
+ *
+ * Copyright (c) 2013-2017 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 <chrono>
+#include <cstdlib>
+#include <thread>
+
+#include <irccd/sysconfig.hpp>
+
+#if defined(HAVE_POPEN)
+#  include <cstdio>
+#endif
+
+#include <irccd/js_plugin.hpp>
+#include <irccd/system.hpp>
+
+#include "js_file_module.hpp"
+#include "js_irccd_module.hpp"
+#include "js_system_module.hpp"
+
+namespace irccd {
+
+namespace {
+
+/*
+ * Function: irccd.System.env(key)
+ * ------------------------------------------------------------------
+ *
+ * Get an environment system variable.
+ *
+ * Arguments:
+ *   - key, the environment variable.
+ * Returns:
+ *   The value.
+ */
+duk_ret_t env(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, sys::env(dukx_get_std_string(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: irccd.System.exec(cmd)
+ * ------------------------------------------------------------------
+ *
+ * Execute a system command.
+ *
+ * Arguments:
+ *   - cmd, the command to execute.
+ */
+duk_ret_t exec(duk_context* ctx)
+{
+    std::system(duk_get_string(ctx, 0));
+
+    return 0;
+}
+
+/*
+ * Function: irccd.System.home()
+ * ------------------------------------------------------------------
+ *
+ * Get the operating system user's home.
+ *
+ * Returns:
+ *   The user home directory.
+ */
+duk_ret_t home(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, sys::home());
+
+    return 1;
+}
+
+/*
+ * Function: irccd.System.name()
+ * ------------------------------------------------------------------
+ *
+ * Get the operating system name.
+ *
+ * Returns:
+ *   The system name.
+ */
+duk_ret_t name(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, sys::name());
+
+    return 1;
+}
+
+#if defined(HAVE_POPEN)
+
+/*
+ * Function: irccd.System.popen(cmd, mode) [optional]
+ * ------------------------------------------------------------------
+ *
+ * Wrapper for popen(3) if the function is available.
+ *
+ * Arguments:
+ *   - cmd, the command to execute,
+ *   - mode, the mode (e.g. "r").
+ * Returns:
+ *   A irccd.File object.
+ * Throws
+ *   - irccd.system_error on failures.
+ */
+duk_ret_t popen(duk_context* ctx)
+{
+    auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
+
+    if (fp == nullptr)
+        dukx_throw(ctx, system_error());
+
+    dukx_push_file(ctx, new file(fp, [] (auto fp) { ::pclose(fp); }));
+
+    return 1;
+}
+
+#endif // !HAVE_POPEN
+
+/*
+ * Function: irccd.System.sleep(delay)
+ * ------------------------------------------------------------------
+ *
+ * Sleep the main loop for the specific delay in seconds.
+ */
+duk_ret_t sleep(duk_context* ctx)
+{
+    std::this_thread::sleep_for(std::chrono::seconds(duk_get_int(ctx, 0)));
+
+    return 0;
+}
+
+/*
+ * Function: irccd.System.ticks()
+ * ------------------------------------------------------------------
+ *
+ * Get the number of milliseconds since irccd was started.
+ *
+ * Returns:
+ *   The number of milliseconds.
+ */
+duk_ret_t ticks(duk_context* ctx)
+{
+    duk_push_int(ctx, sys::ticks());
+
+    return 1;
+}
+
+/*
+ * Function: irccd.System.usleep(delay)
+ * ------------------------------------------------------------------
+ *
+ * Sleep the main loop for the specific delay in microseconds.
+ */
+duk_ret_t usleep(duk_context* ctx)
+{
+    std::this_thread::sleep_for(std::chrono::microseconds(duk_get_int(ctx, 0)));
+
+    return 0;
+}
+
+/*
+ * Function: irccd.System.uptime()
+ * ------------------------------------------------------------------
+ *
+ * Get the system uptime.
+ *
+ * Returns:
+ *   The system uptime.
+ */
+duk_ret_t uptime(duk_context* ctx)
+{
+    duk_push_int(ctx, sys::uptime());
+
+    return 0;
+}
+
+/*
+ * Function: irccd.System.version()
+ * ------------------------------------------------------------------
+ *
+ * Get the operating system version.
+ *
+ * Returns:
+ *   The system version.
+ */
+duk_ret_t version(duk_context* ctx)
+{
+    dukx_push_std_string(ctx, sys::version());
+
+    return 1;
+}
+
+const duk_function_list_entry functions[] = {
+    { "env",        env,        1 },
+    { "exec",       exec,       1 },
+    { "home",       home,       0 },
+    { "name",       name,       0 },
+#if defined(HAVE_POPEN)
+    { "popen",      popen,      2 },
+#endif
+    { "sleep",      sleep,      1 },
+    { "ticks",      ticks,      0 },
+    { "uptime",     uptime,     0 },
+    { "usleep",     usleep,     1 },
+    { "version",    version,    0 },
+    { nullptr,      nullptr,    0 }
+};
+
+} // !namespace
+
+js_system_module::js_system_module() noexcept
+    : module("Irccd.System")
+{
+}
+
+void js_system_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, functions);
+    duk_put_prop_string(plugin->context(), -2, "System");
+    duk_pop(plugin->context());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_system_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_system_module.hpp -- Irccd.System API
+ *
+ * Copyright (c) 2013-2017 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_JS_SYSTEM_MODULE_HPP
+#define IRCCD_JS_SYSTEM_MODULE_HPP
+
+/**
+ * \file mod-system.hpp
+ * \brief irccd.System JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief irccd.System JavaScript API.
+ * \ingroup modules
+ */
+class js_system_module : public module {
+public:
+    /**
+     * irccd.System.
+     */
+    js_system_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_JS_SYSTEM_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_timer_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,210 @@
+/*
+ * js_timer_module.cpp -- Irccd.timer API
+ *
+ * Copyright (c) 2013-2017 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 <format.h>
+
+#include <irccd/irccd.hpp>
+#include <irccd/logger.hpp>
+#include <irccd/js_plugin.hpp>
+#include <irccd/timer.hpp>
+
+#include "js_irccd_module.hpp"
+#include "js_plugin_module.hpp"
+#include "js_timer_module.hpp"
+
+using namespace fmt::literals;
+
+namespace irccd {
+
+namespace {
+
+const char* signature("\xff""\xff""irccd-timer-ptr");
+const char* callback_table("\xff""\xff""irccd-timer-callbacks");
+
+void handle_signal(irccd& instance, std::weak_ptr<js_plugin> ptr, std::string key)
+{
+    auto plugin = ptr.lock();
+
+    if (!plugin)
+        return;
+
+    instance.post([plugin, key] (irccd &) {
+        StackAssert sa(plugin->context());
+
+        duk_get_global_string(plugin->context(), callback_table);
+        duk_get_prop_string(plugin->context(), -1, key.c_str());
+        duk_remove(plugin->context(), -2);
+
+        if (duk_is_callable(plugin->context(), -1)) {
+            if (duk_pcall(plugin->context(), 0) != 0)
+                log::warning("plugin {}: {}"_format(plugin->name(), dukx_exception(plugin->context(), -1).stack));
+            else
+                duk_pop(plugin->context());
+        } else
+            duk_pop(plugin->context());
+    });
+}
+
+std::shared_ptr<timer> self(duk_context* ctx)
+{
+    StackAssert sa(ctx);
+
+    duk_push_this(ctx);
+    duk_get_prop_string(ctx, -1, signature);
+    auto ptr = duk_to_pointer(ctx, -1);
+    duk_pop_2(ctx);
+
+    if (!ptr)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a timer object");
+
+    return *static_cast<std::shared_ptr<timer>*>(ptr);
+}
+
+/*
+ * Method: timer.start()
+ * --------------------------------------------------------
+ *
+ * Start the timer. If the timer is already started the method is a no-op.
+ */
+duk_ret_t start(duk_context* ctx)
+{
+    auto timer = self(ctx);
+
+    if (!timer->is_running())
+        timer->start();
+
+    return 0;
+}
+
+/*
+ * Method: timer.stop()
+ * --------------------------------------------------------
+ *
+ * Stop the timer.
+ */
+duk_ret_t stop(duk_context* ctx)
+{
+    auto timer = self(ctx);
+
+    if (timer->is_running())
+        timer->stop();
+
+    return 0;
+}
+
+const duk_function_list_entry methods[] = {
+    { "start",  start,      0 },
+    { "stop",   stop,       0 },
+    { nullptr,  nullptr,    0 }
+};
+
+/*
+ * Function: Irccd.timer(type, delay, callback) [constructor]
+ * --------------------------------------------------------
+ *
+ * Create a new timer object.
+ *
+ * Arguments:
+ *   - type, the type of timer (irccd.timer.Single or irccd.timer.Repeat),
+ *   - delay, the interval in milliseconds,
+ *   - callback, the function to call.
+ */
+duk_ret_t constructor(duk_context* ctx)
+{
+    // Check parameters.
+    auto type = duk_require_int(ctx, 0);
+    auto delay = duk_require_int(ctx, 1);
+
+    if (type < static_cast<int>(timer::type::single) || type > static_cast<int>(timer::type::repeat))
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type");
+    if (delay < 0)
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "negative delay given");
+    if (!duk_is_callable(ctx, 2))
+        duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function");
+
+    // Construct the timer in 'this'.
+    auto& irccd = dukx_get_irccd(ctx);
+    auto tm = std::make_shared<timer>(static_cast<timer::type>(type), delay);
+    auto hash = std::to_string(reinterpret_cast<std::uintptr_t>(tm.get()));
+
+    tm->on_signal.connect(std::bind(handle_signal, std::ref(irccd),
+        std::weak_ptr<js_plugin>(dukx_get_plugin(ctx)), hash));
+
+    duk_push_this(ctx);
+    duk_push_pointer(ctx, new std::shared_ptr<timer>(std::move(tm)));
+    duk_put_prop_string(ctx, -2, signature);
+    duk_push_string(ctx, hash.c_str());
+    duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key");
+    duk_push_c_function(ctx, [] (duk_context* ctx) -> duk_ret_t {
+        StackAssert sa(ctx);
+
+        duk_get_prop_string(ctx, 0, "\xff""\xff""timer-key");
+        auto hash = duk_get_string(ctx, -1);
+        duk_pop(ctx);
+        duk_get_prop_string(ctx, 0, signature);
+        static_cast<std::shared_ptr<timer>*>(duk_to_pointer(ctx, -1))->get()->stop();
+        delete static_cast<std::shared_ptr<timer>*>(duk_to_pointer(ctx, -1));
+        duk_pop(ctx);
+        duk_get_global_string(ctx, callback_table);
+        duk_del_prop_string(ctx, -1, hash);
+        duk_pop(ctx);
+        log::debug("plugin: timer destroyed");
+
+        return 0;
+    }, 1);
+    duk_set_finalizer(ctx, -2);
+
+    // Save a callback function into the callback table.
+    duk_get_global_string(ctx, callback_table);
+    duk_dup(ctx, 2);
+    duk_put_prop_string(ctx, -2, hash.c_str());
+    duk_pop(ctx);
+
+    return 0;
+}
+
+const duk_number_list_entry constants[] = {
+    { "Single",     static_cast<int>(timer::type::single)   },
+    { "Repeat",     static_cast<int>(timer::type::repeat)   },
+    { nullptr,      0                                       }
+};
+
+} // !namespace
+
+js_timer_module::js_timer_module() noexcept
+    : module("Irccd.timer")
+{
+}
+
+void js_timer_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_c_function(plugin->context(), constructor, 3);
+    duk_put_number_list(plugin->context(), -1, constants);
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, methods);
+    duk_put_prop_string(plugin->context(), -2, "prototype");
+    duk_put_prop_string(plugin->context(), -2, "Timer");
+    duk_pop(plugin->context());
+    duk_push_object(plugin->context());
+    duk_put_global_string(plugin->context(), callback_table);
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_timer_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_timer_module.hpp -- Irccd.Timer API
+ *
+ * Copyright (c) 2013-2017 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_JS_TIMER_MODULE_HPP
+#define IRCCD_JS_TIMER_MODULE_HPP
+
+/**
+ * \file js_timer_module
+ * \brief irccd.Timer JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Irccd.Timer JavaScript API.
+ * \ingroup modules
+ */
+class js_timer_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_timer_module() noexcept;
+
+    /**
+     * \copydoc module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_MOD_TIMER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_unicode_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,153 @@
+/*
+ * js_unicode_module.cpp -- Irccd.Unicode API
+ *
+ * Copyright (c) 2013-2017 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/js_plugin.hpp>
+
+#include "duktape.hpp"
+#include "js_unicode_module.hpp"
+#include "unicode.hpp"
+
+namespace irccd {
+
+namespace {
+
+/*
+ * Function: Irccd.Unicode.isDigit(code)
+ * --------------------------------------------------------
+ *
+ * Arguments:
+ *   - code, the code point.
+ * Returns:
+ *   True if the code is in the digit category.
+ */
+duk_ret_t is_digit(duk_context* ctx)
+{
+    duk_push_boolean(ctx, unicode::isdigit(duk_get_int(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Unicode.isLetter(code)
+ * --------------------------------------------------------
+ *
+ * Arguments:
+ *   - code, the code point.
+ * Returns:
+ *   True if the code is in the letter category.
+ */
+duk_ret_t is_letter(duk_context* ctx)
+{
+    duk_push_boolean(ctx, unicode::isalpha(duk_get_int(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Unicode.isLower(code)
+ * --------------------------------------------------------
+ *
+ * Arguments:
+ *   - code, the code point.
+ * Returns:
+ *   True if the code is lower case.
+ */
+duk_ret_t is_lower(duk_context* ctx)
+{
+    duk_push_boolean(ctx, unicode::islower(duk_get_int(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Unicode.isSpace(code)
+ * --------------------------------------------------------
+ *
+ * Arguments:
+ *   - code, the code point.
+ * Returns:
+ *   True if the code is in the space category.
+ */
+duk_ret_t is_space(duk_context* ctx)
+{
+    duk_push_boolean(ctx, unicode::isspace(duk_get_int(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Unicode.isTitle(code)
+ * --------------------------------------------------------
+ *
+ * Arguments:
+ *   - code, the code point.
+ * Returns:
+ *   True if the code is title case.
+ */
+duk_ret_t is_title(duk_context* ctx)
+{
+    duk_push_boolean(ctx, unicode::istitle(duk_get_int(ctx, 0)));
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Unicode.isUpper(code)
+ * --------------------------------------------------------
+ *
+ * Arguments:
+ *   - code, the code point.
+ * Returns:
+ *   True if the code is upper case.
+ */
+duk_ret_t is_upper(duk_context* ctx)
+{
+    duk_push_boolean(ctx, unicode::isupper(duk_get_int(ctx, 0)));
+
+    return 1;
+}
+
+const duk_function_list_entry functions[] = {
+    { "isDigit",        is_digit,   1 },
+    { "isLetter",       is_letter,  1 },
+    { "isLower",        is_lower,   1 },
+    { "isSpace",        is_space,   1 },
+    { "isTitle",        is_title,   1 },
+    { "isUpper",        is_upper,   1 },
+    { nullptr,          nullptr,    0 }
+};
+
+} // !namespace
+
+js_unicode_module::js_unicode_module() noexcept
+    : module("Irccd.Unicode")
+{
+}
+
+void js_unicode_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, functions);
+    duk_put_prop_string(plugin->context(), -2, "Unicode");
+    duk_pop(plugin->context());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_unicode_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_unicode_module.hpp -- Irccd.Unicode API
+ *
+ * Copyright (c) 2013-2017 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_JS_UNICODE_MODULE_HPP
+#define IRCCD_JS_UNICODE_MODULE_HPP
+
+/**
+ * \file js_unicode_module.hpp
+ * \brief irccd.Unicode JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Irccd.Unicode JavaScript API.
+ * \ingroup modules
+ */
+class js_unicode_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_unicode_module() noexcept;
+
+    /**
+     * \copydoc Module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_JS_UNICODE_MODULE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_util_module.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,300 @@
+/*
+ * js_util_module.cpp -- Irccd.Util API
+ *
+ * Copyright (c) 2013-2017 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 <climits>
+
+#include <libircclient.h>
+
+#include <irccd/util.hpp>
+
+#include "js_util_module.hpp"
+#include "js_plugin.hpp"
+
+namespace irccd {
+
+namespace {
+
+/*
+ * Read parameters for irccd.Util.format function, the object is defined as
+ * following:
+ *
+ * {
+ *   date: the date object
+ *   flags: the flags (not implemented yet)
+ *   field1: a field to substitute in #{} pattern
+ *   field2: a field to substitute in #{} pattern
+ *   fieldn: ...
+ * }
+ */
+util::subst get_subst(duk_context* ctx, int index)
+{
+    util::subst params;
+
+    if (!duk_is_object(ctx, index))
+        return params;
+
+    dukx_enumerate(ctx, index, 0, true, [&] (auto) {
+        if (dukx_get_std_string(ctx, -2) == "date")
+            params.time = static_cast<time_t>(duk_get_number(ctx, -1) / 1000);
+        else
+            params.keywords.insert({dukx_get_std_string(ctx, -2), dukx_get_std_string(ctx, -1)});
+    });
+
+    return params;
+}
+
+/*
+ * split (for Irccd.Util.cut)
+ * ------------------------------------------------------------------
+ *
+ * Extract individual tokens in array or a whole string as a std:::vector.
+ */
+std::vector<std::string> split(duk_context* ctx)
+{
+    duk_require_type_mask(ctx, 0, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_STRING);
+
+    std::vector<std::string> result;
+    std::string pattern = " \t\n";
+
+    if (duk_is_string(ctx, 0))
+        result = util::split(dukx_get_std_string(ctx, 0), pattern);
+    else if (duk_is_array(ctx, 0)) {
+        duk_enum(ctx, 0, DUK_ENUM_ARRAY_INDICES_ONLY);
+
+        while (duk_next(ctx, -1, 1)) {
+            // Split individual tokens as array if spaces are found.
+            auto tmp = util::split(duk_to_string(ctx, -1), pattern);
+
+            result.insert(result.end(), tmp.begin(), tmp.end());
+            duk_pop_2(ctx);
+        }
+    }
+
+    return result;
+}
+
+/*
+ * limit (for Irccd.Util.cut)
+ * ------------------------------------------------------------------
+ *
+ * Get the maxl/maxc argument.
+ *
+ * The argument value is the default and also used as the result returned.
+ */
+int limit(duk_context* ctx, int index, const char* name, int value)
+{
+    if (duk_get_top(ctx) < index || !duk_is_number(ctx, index))
+        return value;
+
+    value = duk_to_int(ctx, index);
+    
+    if (value <= 0)
+        duk_error(ctx, DUK_ERR_RANGE_ERROR, "argument %d (%s) must be positive", index, name);
+
+    return value;
+}
+
+/*
+ * lines (for Irccd.Util.cut)
+ * ------------------------------------------------------------------
+ *
+ * Build a list of lines.
+ *
+ * Several cases possible:
+ *
+ *   - s is the current line
+ *   - abc is the token to add
+ *
+ * s   = ""                 (new line)
+ * s  -> "abc"
+ *
+ * s   = "hello world"      (enough room)
+ * s  -> "hello world abc"
+ *
+ * s   = "hello world"      (not enough room: maxc is smaller)
+ * s+1 = "abc"
+ */
+std::vector<std::string> lines(duk_context* ctx, const std::vector<std::string>& tokens, int maxc)
+{
+    std::vector<std::string> result{""};
+
+    for (const auto& s : tokens) {
+        if (s.length() > static_cast<std::size_t>(maxc))
+            duk_error(ctx, DUK_ERR_RANGE_ERROR, "word '%s' could not fit in maxc limit (%d)", s.c_str(), maxc);
+
+        // Compute the length required (prepend a space if needed)
+        auto required = s.length() + (result.back().empty() ? 0 : 1);
+
+        if (result.back().length() + required > static_cast<std::size_t>(maxc))
+            result.push_back(s);
+        else {
+            if (!result.back().empty())
+                result.back() += ' ';
+
+            result.back() += s;
+        }
+    }
+
+    return result;
+}
+
+/*
+ * Function: Irccd.Util.cut(data, maxc, maxl)
+ * --------------------------------------------------------
+ *
+ * Cut a piece of data into several lines.
+ *
+ * The argument data is a string or a list of strings. In any case, all strings
+ * are first splitted by spaces and trimmed. This ensure that useless
+ * whitespaces are discarded.
+ *
+ * The argument maxc controls the maximum of characters allowed per line, it can
+ * be a positive integer. If undefined is given, a default of 72 is used.
+ *
+ * The argument maxl controls the maximum of lines allowed. It can be a positive
+ * integer or undefined for an infinite list.
+ *
+ * If maxl is used as a limit and the data can not fit within the bounds,
+ * undefined is returned.
+ *
+ * An empty list may be returned if empty strings were found.
+ *
+ * Arguments:
+ *   - data, a string or an array of strings,
+ *   - maxc, max number of colums (Optional, default: 72),
+ *   - maxl, max number of lines (Optional, default: undefined).
+ * Returns:
+ *   A list of strings ready to be sent or undefined if the data is too big.
+ * Throws:
+ *   - RangeError if maxl or maxc are negative numbers,
+ *   - RangeError if one word length was bigger than maxc,
+ *   - TypeError if data is not a string or a list of strings.
+ */
+duk_ret_t cut(duk_context* ctx)
+{
+    auto list = lines(ctx, split(ctx), limit(ctx, 1, "maxc", 72));
+    auto maxl = limit(ctx, 2, "maxl", INT_MAX);
+
+    if (list.size() > static_cast<std::size_t>(maxl))
+        return 0;
+
+    // Empty list but lines() returns at least one.
+    if (list.size() == 1 && list[0].empty()) {
+        duk_push_array(ctx);
+        return 1;
+    }
+
+    dukx_push_array(ctx, list, dukx_push_std_string);
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Util.format(text, parameters)
+ * --------------------------------------------------------
+ *
+ * Format a string with templates.
+ *
+ * Arguments:
+ *   - input, the text to update,
+ *   - params, the parameters.
+ * Returns:
+ *   The converted text.
+ */
+duk_ret_t format(duk_context* ctx)
+{
+    try {
+        dukx_push_std_string(ctx, util::format(dukx_get_std_string(ctx, 0), get_subst(ctx, 1)));
+    } catch (const std::exception &ex) {
+        dukx_throw(ctx, SyntaxError(ex.what()));
+    }
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Util.splituser(ident)
+ * --------------------------------------------------------
+ *
+ * Return the nickname part from a full username.
+ *
+ * Arguments:
+ *   - ident, the full identity.
+ * Returns:
+ *   The nickname.
+ */
+duk_ret_t splituser(duk_context* ctx)
+{
+    auto target = duk_require_string(ctx, 0);
+    char nick[32] = {0};
+
+    irc_target_get_nick(target, nick, sizeof (nick) -1);
+    duk_push_string(ctx, nick);
+
+    return 1;
+}
+
+/*
+ * Function: Irccd.Util.splithost(ident)
+ * --------------------------------------------------------
+ *
+ * Return the hostname part from a full username.
+ *
+ * Arguments:
+ *   - ident, the full identity.
+ * Returns:
+ *   The hostname.
+ */
+duk_ret_t splithost(duk_context* ctx)
+{
+    auto target = duk_require_string(ctx, 0);
+    char host[32] = {0};
+
+    irc_target_get_host(target, host, sizeof (host) -1);
+    duk_push_string(ctx, host);
+
+    return 1;
+}
+
+const duk_function_list_entry functions[] = {
+    { "cut",        cut,        DUK_VARARGS },
+    { "format",     format,     DUK_VARARGS },
+    { "splituser",  splituser,  1           },
+    { "splithost",  splithost,  1           },
+    { nullptr,      nullptr,    0           }
+};
+
+} // !namespace
+
+js_util_module::js_util_module() noexcept
+    : module("Irccd.Util")
+{
+}
+
+void js_util_module::load(irccd&, std::shared_ptr<js_plugin> plugin)
+{
+    StackAssert sa(plugin->context());
+
+    duk_get_global_string(plugin->context(), "Irccd");
+    duk_push_object(plugin->context());
+    duk_put_function_list(plugin->context(), -1, functions);
+    duk_put_prop_string(plugin->context(), -2, "Util");
+    duk_pop(plugin->context());
+}
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd-js/irccd/js_util_module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * js_util_module.hpp -- Irccd.Util API
+ *
+ * Copyright (c) 2013-2017 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_JS_UTIL_MODULE_HPP
+#define IRCCD_JS_UTIL_MODULE_HPP
+
+/**
+ * \file js_util_module.hpp
+ * \brief irccd.Util JavaScript API.
+ */
+
+#include "module.hpp"
+
+namespace irccd {
+
+/**
+ * \brief Irccd.Util JavaScript API.
+ * \ingroup modules
+ */
+class js_util_module : public module {
+public:
+    /**
+     * Constructor.
+     */
+    js_util_module() noexcept;
+
+    /**
+     * \copydoc module::load
+     */
+    void load(irccd& irccd, std::shared_ptr<js_plugin> plugin) override;
+};
+
+} // !irccd
+
+#endif // !IRCCD_MOD_UTIL_HPP
--- a/libirccd-js/irccd/mod-directory.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,386 +0,0 @@
-/*
- * mod-directory.cpp -- Irccd.Directory API
- *
- * Copyright (c) 2013-2017 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 <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <fstream>
-#include <regex>
-#include <stdexcept>
-#include <string>
-
-#include <boost/filesystem.hpp>
-
-#include "duktape.hpp"
-#include "fs.hpp"
-#include "mod-directory.hpp"
-#include "mod-irccd.hpp"
-#include "plugin-js.hpp"
-#include "sysconfig.hpp"
-
-namespace irccd {
-
-namespace {
-
-std::string path(duk_context *ctx)
-{
-    duk_push_this(ctx);
-    duk_get_prop_string(ctx, -1, "path");
-
-    if (duk_get_type(ctx, -1) != DUK_TYPE_STRING)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object");
-
-    auto ret = dukx_get_std_string(ctx, -1);
-
-    if (ret.empty())
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path");
-
-    duk_pop_n(ctx, 2);
-
-    return ret;
-}
-
-/*
- * Find an entry recursively (or not) in a directory using a predicate which can
- * be used to test for regular expression, equality.
- *
- * Do not use this function directly, use:
- *
- * - findName
- * - findRegex
- */
-template <typename Pred>
-std::string findPath(const std::string &base, bool recursive, Pred pred)
-{
-    /*
-     * For performance reason, we first iterate over all entries that are
-     * not directories to avoid going deeper recursively if the requested
-     * file is in the current directory.
-     */
-    auto entries = fs::readdir(base);
-
-    for (const auto &entry : entries)
-        if (entry.type != fs::Entry::Dir && pred(entry.name))
-            return base + entry.name;
-
-    if (!recursive)
-        return "";
-
-    for (const auto &entry : entries) {
-        if (entry.type == fs::Entry::Dir) {
-            std::string next = base + entry.name + fs::separator();
-            std::string path = findPath(next, true, pred);
-
-            if (!path.empty())
-                return path;
-        }
-    }
-
-    return "";
-}
-
-/*
- * Helper for finding by equality.
- */
-std::string findName(std::string base, const std::string &pattern, bool recursive)
-{
-    return findPath(base, recursive, [&] (const std::string &entryname) -> bool {
-        return pattern == entryname;
-    });
-}
-
-/*
- * Helper for finding by regular expression
- */
-std::string findRegex(const std::string &base, std::string pattern, bool recursive)
-{
-    std::regex regexp(pattern, std::regex::ECMAScript);
-    std::smatch smatch;
-
-    return findPath(base, recursive, [&] (const std::string &entryname) -> bool {
-        return std::regex_match(entryname, smatch, regexp);
-    });
-}
-
-/*
- * Generic find function for:
- *
- * - Directory.find
- * - Directory.prototype.find
- *
- * The patternIndex is the argument where to test if the argument is a regex or
- * a string.
- */
-duk_ret_t find(duk_context *ctx, std::string base, bool recursive, int patternIndex)
-{
-    try {
-        std::string path;
-
-        if (duk_is_string(ctx, patternIndex))
-            path = findName(base, duk_get_string(ctx, patternIndex), recursive);
-        else {
-            // Check if it's a valid RegExp object.
-            duk_get_global_string(ctx, "RegExp");
-            auto isRegex = duk_instanceof(ctx, patternIndex, -1);
-            duk_pop(ctx);
-
-            if (isRegex) {
-                duk_get_prop_string(ctx, patternIndex, "source");
-                auto pattern = duk_to_string(ctx, -1);
-                duk_pop(ctx);
-
-                path = findRegex(base, pattern, recursive);
-            } else
-                duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern must be a string or a regex expression");
-        }
-
-        if (path.empty())
-            return 0;
-
-        dukx_push_std_string(ctx, path);
-    } catch (const std::exception &ex) {
-        duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
-    }
-
-    return 1;
-}
-
-/*
- * Generic remove function for:
- *
- * - Directory.remove
- * - Directory.prototype.remove
- */
-duk_ret_t remove(duk_context *ctx, const std::string &path, bool recursive)
-{
-    boost::system::error_code ec;
-
-    if (!boost::filesystem::is_directory(path, ec) || ec) {
-        dukx_throw(ctx, SystemError(EINVAL, "not a directory"));
-    }
-
-    if (!recursive) {
-        boost::filesystem::remove(path, ec);
-    } else {
-        boost::filesystem::remove_all(path, ec);
-    }
-
-    return 0;
-}
-
-/*
- * Method: Directory.find(pattern, recursive)
- * --------------------------------------------------------
- *
- * Synonym of Directory.find(path, pattern, recursive) but the path is taken
- * from the directory object.
- *
- * Arguments:
- *   - pattern, the regular expression or file name,
- *   - recursive, set to true to search recursively (default: false).
- * Returns:
- *   The path to the file or undefined if not found.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodFind(duk_context *ctx)
-{
-    return find(ctx, path(ctx), duk_get_boolean(ctx, 1), 0);
-}
-
-/*
- * Method: Directory.remove(recursive)
- * --------------------------------------------------------
- *
- * Synonym of Directory.remove(recursive) but the path is taken from the
- * directory object.
- *
- * Arguments:
- *   - recursive, recursively or not (default: false).
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodRemove(duk_context *ctx)
-{
-    return remove(ctx, path(ctx), duk_get_boolean(ctx, 0));
-}
-
-const duk_function_list_entry methods[] = {
-    { "find",       methodFind,     DUK_VARARGS },
-    { "remove",     methodRemove,   1           },
-    { nullptr,      nullptr,        0           }
-};
-
-/*
- * Directory "static" functions
- * ------------------------------------------------------------------
- */
-
-/*
- * Function: Irccd.Directory(path, flags) [constructor]
- * --------------------------------------------------------
- *
- * Opens and read the directory at the specified path.
- *
- * Arguments:
- *   - path, the path to the directory,
- *   - flags, the optional flags (default: 0).
- * Throws:
- *   - Any exception on error
- */
-duk_ret_t constructor(duk_context *ctx)
-{
-    if (!duk_is_constructor_call(ctx))
-        return 0;
-
-    try {
-        std::string path = duk_require_string(ctx, 0);
-        std::int8_t flags = duk_get_uint(ctx, 1);
-
-        if (!boost::filesystem::is_directory(path))
-            dukx_throw(ctx, SystemError(EINVAL, "not a directory"));
-
-        std::vector<fs::Entry> list = fs::readdir(path, flags);
-
-        duk_push_this(ctx);
-        duk_push_string(ctx, "count");
-        duk_push_int(ctx, list.size());
-        duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
-        duk_push_string(ctx, "path");
-        dukx_push_std_string(ctx, path);
-        duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
-        duk_push_string(ctx, "entries");
-        duk_push_array(ctx);
-
-        for (unsigned i = 0; i < list.size(); ++i) {
-            duk_push_object(ctx);
-            dukx_push_std_string(ctx, list[i].name);
-            duk_put_prop_string(ctx, -2, "name");
-            duk_push_int(ctx, list[i].type);
-            duk_put_prop_string(ctx, -2, "type");
-            duk_put_prop_index(ctx, -2, i);
-        }
-
-        duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE);
-    } catch (const std::exception &ex) {
-        dukx_throw(ctx, SystemError(errno, ex.what()));
-    }
-
-    return 0;
-}
-
-/*
- * Function: Irccd.Directory.find(path, pattern, recursive)
- * --------------------------------------------------------
- *
- * Find an entry by a pattern or a regular expression.
- *
- * Arguments:
- *   - path, the base path,
- *   - pattern, the regular expression or file name,
- *   - recursive, set to true to search recursively (default: false).
- * Returns:
- *   The path to the file or undefined on errors or not found.
- */
-duk_ret_t funcFind(duk_context *ctx)
-{
-    return find(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 2), 1);
-}
-
-/*
- * Function: Irccd.Directory.remove(path, recursive)
- * --------------------------------------------------------
- *
- * Remove the directory optionally recursively.
- *
- * Arguments:
- *   - path, the path to the directory,
- *   - recursive, recursively or not (default: false).
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t funcRemove(duk_context *ctx)
-{
-    return remove(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 1));
-}
-
-/*
- * Function: Irccd.Directory.mkdir(path, mode = 0700)
- * --------------------------------------------------------
- *
- * Create a directory specified by path. It will create needed subdirectories
- * just like you have invoked mkdir -p.
- *
- * Arguments:
- *   - path, the path to the directory,
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t funcMkdir(duk_context *ctx)
-{
-    try {
-        boost::filesystem::create_directories(duk_require_string(ctx, 0));
-    } catch (const std::exception &ex) {
-        dukx_throw(ctx, SystemError(errno, ex.what()));
-    }
-
-    return 0;
-}
-
-const duk_function_list_entry functions[] = {
-    { "find",           funcFind,   DUK_VARARGS },
-    { "mkdir",          funcMkdir,  DUK_VARARGS },
-    { "remove",         funcRemove, DUK_VARARGS },
-    { nullptr,          nullptr,    0           }
-};
-
-const duk_number_list_entry constants[] = {
-    { "Dot",            static_cast<int>(fs::Dot)               },
-    { "DotDot",         static_cast<int>(fs::DotDot)            },
-    { "TypeUnknown",    static_cast<int>(fs::Entry::Unknown)    },
-    { "TypeDir",        static_cast<int>(fs::Entry::Dir)        },
-    { "TypeFile",       static_cast<int>(fs::Entry::File)       },
-    { "TypeLink",       static_cast<int>(fs::Entry::Link)       },
-    { nullptr,          0                                       }
-};
-
-} // !namespace
-
-DirectoryModule::DirectoryModule() noexcept
-    : Module("Irccd.Directory")
-{
-}
-
-void DirectoryModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_c_function(plugin->context(), constructor, 2);
-    duk_put_number_list(plugin->context(), -1, constants);
-    duk_put_function_list(plugin->context(), -1, functions);
-    dukx_push_std_string(plugin->context(), std::string{fs::separator()});
-    duk_put_prop_string(plugin->context(), -2, "separator");
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, methods);
-    duk_put_prop_string(plugin->context(), -2, "prototype");
-    duk_put_prop_string(plugin->context(), -2, "Directory");
-    duk_pop(plugin->context());
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-directory.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-directory.hpp -- Irccd.Directory API
- *
- * Copyright (c) 2013-2017 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_MOD_DIRECTORY_HPP
-#define IRCCD_MOD_DIRECTORY_HPP
-
-/**
- * \file mod-directory.hpp
- * \brief Irccd.Directory JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Directory JavaScript API.
- * \ingroup modules
- */
-class DirectoryModule : public Module {
-public:
-    /**
-     * Irccd.Directory.
-     */
-    IRCCD_EXPORT DirectoryModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_DIRECTORY_HPP
--- a/libirccd-js/irccd/mod-elapsed-timer.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * mod-elapsed-timer.cpp -- Irccd.ElapsedTimer API
- *
- * Copyright (c) 2013-2017 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 "elapsed-timer.hpp"
-#include "mod-elapsed-timer.hpp"
-#include "plugin-js.hpp"
-
-namespace irccd {
-
-namespace {
-
-const char *Signature("\xff""\xff""irccd-elapsed-timer-ptr");
-
-ElapsedTimer *self(duk_context *ctx)
-{
-    StackAssert sa(ctx);
-
-    duk_push_this(ctx);
-    duk_get_prop_string(ctx, -1, Signature);
-    auto ptr = static_cast<ElapsedTimer *>(duk_to_pointer(ctx, -1));
-    duk_pop_2(ctx);
-
-    if (!ptr)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object");
-
-    return ptr;
-}
-
-/*
- * Method: ElapsedTimer.pause
- * ------------------------------------------------------------------
- *
- * Pause the timer, without resetting the current elapsed time stored.
- */
-duk_ret_t pause(duk_context *ctx)
-{
-    self(ctx)->pause();
-
-    return 0;
-}
-
-/*
- * Method: ElapsedTimer.reset
- * ------------------------------------------------------------------
- *
- * Reset the elapsed time to 0, the status is not modified.
- */
-duk_ret_t reset(duk_context *ctx)
-{
-    self(ctx)->reset();
-
-    return 0;
-}
-
-/*
- * Method: ElapsedTimer.restart
- * ------------------------------------------------------------------
- *
- * Restart the timer without resetting the current elapsed time.
- */
-duk_ret_t restart(duk_context *ctx)
-{
-    self(ctx)->restart();
-
-    return 0;
-}
-
-/*
- * Method: ElapsedTimer.elapsed
- * ------------------------------------------------------------------
- *
- * Get the number of elapsed milliseconds.
- *
- * Returns:
- *   The time elapsed.
- */
-duk_ret_t elapsed(duk_context *ctx)
-{
-    duk_push_uint(ctx, self(ctx)->elapsed());
-
-    return 1;
-}
-
-/*
- * Function: Irccd.ElapsedTimer() [constructor]
- * ------------------------------------------------------------------
- *
- * Construct a new ElapsedTimer object.
- */
-duk_ret_t constructor(duk_context *ctx)
-{
-    duk_push_this(ctx);
-    duk_push_pointer(ctx, new ElapsedTimer);
-    duk_put_prop_string(ctx, -2, Signature);
-    duk_pop(ctx);
-
-    return 0;
-}
-
-/*
- * Function: Irccd.ElapsedTimer() [destructor]
- * ------------------------------------------------------------------
- *
- * Delete the property.
- */
-duk_ret_t destructor(duk_context *ctx)
-{
-    duk_get_prop_string(ctx, 0, Signature);
-    delete static_cast<ElapsedTimer *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-    duk_del_prop_string(ctx, 0, Signature);
-
-    return 0;
-}
-
-const duk_function_list_entry methods[] = {
-    { "elapsed",    elapsed,    0 },
-    { "pause",      pause,      0 },
-    { "reset",      reset,      0 },
-    { "restart",    restart,    0 },
-    { nullptr,      nullptr,    0 }
-};
-
-} // !namespace
-
-ElapsedTimerModule::ElapsedTimerModule() noexcept
-    : Module("Irccd.ElapsedTimer")
-{
-}
-
-void ElapsedTimerModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_c_function(plugin->context(), constructor, 0);
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, methods);
-    duk_push_c_function(plugin->context(), destructor, 1);
-    duk_set_finalizer(plugin->context(), -2);
-    duk_put_prop_string(plugin->context(), -2, "prototype");
-    duk_put_prop_string(plugin->context(), -2, "ElapsedTimer");
-    duk_pop(plugin->context());
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-elapsed-timer.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-elapsed-timer.hpp -- Irccd.ElapsedTimer API
- *
- * Copyright (c) 2013-2017 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_MOD_ELAPSED_TIMER_HPP
-#define IRCCD_MOD_ELAPSED_TIMER_HPP
-
-/**
- * \file mod-elapsed-timer.hpp
- * \brief Irccd.ElapsedTimer JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.ElapsedTimer JavaScript API.
- * \ingroup modules
- */
-class ElapsedTimerModule : public Module {
-public:
-    /**
-     * Irccd.ElapsedTimer.
-     */
-    IRCCD_EXPORT ElapsedTimerModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_ELAPSED_TIMER_HPP
--- a/libirccd-js/irccd/mod-file.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,699 +0,0 @@
-/*
- * mod-file.cpp -- Irccd.File API
- *
- * Copyright (c) 2013-2017 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 <algorithm>
-#include <array>
-#include <cassert>
-#include <iterator>
-#include <vector>
-
-#include <boost/filesystem.hpp>
-
-#include "sysconfig.hpp"
-
-#if defined(HAVE_STAT)
-#  include <sys/types.h>
-#  include <sys/stat.h>
-#endif
-
-#include "fs.hpp"
-#include "mod-file.hpp"
-#include "mod-irccd.hpp"
-#include "plugin-js.hpp"
-
-namespace irccd {
-
-namespace {
-
-const char *Signature("\xff""\xff""irccd-file-ptr");
-const char *Prototype("\xff""\xff""irccd-file-prototype");
-
-#if defined(HAVE_STAT)
-
-/*
- * pushStat
- * ------------------------------------------------------------------
- */
-
-void pushStat(duk_context *ctx, const struct stat &st)
-{
-    StackAssert sa(ctx, 1);
-
-    duk_push_object(ctx);
-
-#if defined(HAVE_STAT_ST_ATIME)
-    duk_push_int(ctx, st.st_atime);
-    duk_put_prop_string(ctx, -2, "atime");
-#endif
-#if defined(HAVE_STAT_ST_BLKSIZE)
-    duk_push_int(ctx, st.st_blksize);
-    duk_put_prop_string(ctx, -2, "blksize");
-#endif
-#if defined(HAVE_STAT_ST_BLOCKS)
-    duk_push_int(ctx, st.st_blocks);
-    duk_put_prop_string(ctx, -2, "blocks");
-#endif
-#if defined(HAVE_STAT_ST_CTIME)
-    duk_push_int(ctx, st.st_ctime);
-    duk_put_prop_string(ctx, -2, "ctime");
-#endif
-#if defined(HAVE_STAT_ST_DEV)
-    duk_push_int(ctx, st.st_dev);
-    duk_put_prop_string(ctx, -2, "dev");
-#endif
-#if defined(HAVE_STAT_ST_GID)
-    duk_push_int(ctx, st.st_gid);
-    duk_put_prop_string(ctx, -2, "gid");
-#endif
-#if defined(HAVE_STAT_ST_INO)
-    duk_push_int(ctx, st.st_ino);
-    duk_put_prop_string(ctx, -2, "ino");
-#endif
-#if defined(HAVE_STAT_ST_MODE)
-    duk_push_int(ctx, st.st_mode);
-    duk_put_prop_string(ctx, -2, "mode");
-#endif
-#if defined(HAVE_STAT_ST_MTIME)
-    duk_push_int(ctx, st.st_mtime);
-    duk_put_prop_string(ctx, -2, "mtime");
-#endif
-#if defined(HAVE_STAT_ST_NLINK)
-    duk_push_int(ctx, st.st_nlink);
-    duk_put_prop_string(ctx, -2, "nlink");
-#endif
-#if defined(HAVE_STAT_ST_RDEV)
-    duk_push_int(ctx, st.st_rdev);
-    duk_put_prop_string(ctx, -2, "rdev");
-#endif
-#if defined(HAVE_STAT_ST_SIZE)
-    duk_push_int(ctx, st.st_size);
-    duk_put_prop_string(ctx, -2, "size");
-#endif
-#if defined(HAVE_STAT_ST_UID)
-    duk_push_int(ctx, st.st_uid);
-    duk_put_prop_string(ctx, -2, "uid");
-#endif
-}
-
-#endif // !HAVE_STAT
-
-// Remove trailing \r for CRLF line style.
-inline std::string clearCr(std::string input)
-{
-    if (input.length() > 0 && input.back() == '\r')
-        input.pop_back();
-
-    return input;
-}
-
-File *self(duk_context *ctx)
-{
-    StackAssert sa(ctx);
-
-    duk_push_this(ctx);
-    duk_get_prop_string(ctx, -1, Signature);
-    auto ptr = static_cast<File *>(duk_to_pointer(ctx, -1));
-    duk_pop_2(ctx);
-
-    if (!ptr)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
-
-    return ptr;
-}
-
-/*
- * File methods.
- * ------------------------------------------------------------------
- */
-
-/*
- * Method: File.basename()
- * --------------------------------------------------------
- *
- * Synonym of `Irccd.File.basename(path)` but with the path from the file.
- *
- * duk_ret_turns:
- *   The base name.
- */
-duk_ret_t methodBasename(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, fs::baseName(self(ctx)->path()));
-
-    return 1;
-}
-
-/*
- * Method: File.close()
- * --------------------------------------------------------
- *
- * Force close of the file, automatically called when object is collected.
- */
-duk_ret_t methodClose(duk_context *ctx)
-{
-    self(ctx)->close();
-
-    return 0;
-}
-
-/*
- * Method: File.dirname()
- * --------------------------------------------------------
- *
- * Synonym of `Irccd.File.dirname(path)` but with the path from the file.
- *
- * duk_ret_turns:
- *   The directory name.
- */
-duk_ret_t methodDirname(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, fs::dirName(self(ctx)->path()));
-
-    return 1;
-}
-
-/*
- * Method: File.lines()
- * --------------------------------------------------------
- *
- * Read all lines and return an array.
- *
- * duk_ret_turns:
- *   An array with all lines.
- * Throws
- *   - Any exception on error.
- */
-duk_ret_t methodLines(duk_context *ctx)
-{
-    duk_push_array(ctx);
-
-    std::FILE *fp = self(ctx)->handle();
-    std::string buffer;
-    std::array<char, 128> data;
-    std::int32_t i = 0;
-
-    while (std::fgets(&data[0], data.size(), fp) != nullptr) {
-        buffer += data.data();
-
-        auto pos = buffer.find('\n');
-
-        if (pos != std::string::npos) {
-            dukx_push_std_string(ctx, clearCr(buffer.substr(0, pos)));
-            duk_put_prop_index(ctx, -2, i++);
-
-            buffer.erase(0, pos + 1);
-        }
-    }
-
-    // Maybe an error in the stream.
-    if (std::ferror(fp))
-        dukx_throw(ctx, SystemError());
-
-    // Missing '\n' in end of file.
-    if (!buffer.empty()) {
-        dukx_push_std_string(ctx, clearCr(buffer));
-        duk_put_prop_index(ctx, -2, i++);
-    }
-
-    return 1;
-}
-
-/*
- * Method: File.read(amount)
- * --------------------------------------------------------
- *
- * Read the specified amount of characters or the whole file.
- *
- * Arguments:
- *   - amount, the amount of characters or -1 to read all (Optional, default: -1).
- * duk_ret_turns:
- *   The string.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodRead(duk_context *ctx)
-{
-    auto file = self(ctx);
-    auto amount = duk_is_number(ctx, 0) ? duk_get_int(ctx, 0) : -1;
-
-    if (amount == 0 || file->handle() == nullptr)
-        return 0;
-
-    try {
-        std::string data;
-        std::size_t total = 0;
-
-        if (amount < 0) {
-            std::array<char, 128> buffer;
-            std::size_t nread;
-
-            while ((nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle())) > 0) {
-                if (std::ferror(file->handle()))
-                    dukx_throw(ctx, SystemError());
-
-                std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data));
-                total += nread;
-            }
-        } else {
-            data.resize((std::size_t)amount);
-            total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle());
-
-            if (std::ferror(file->handle()))
-                dukx_throw(ctx, SystemError());
-
-            data.resize(total);
-        }
-
-        dukx_push_std_string(ctx, data);
-    } catch (const std::exception &) {
-        dukx_throw(ctx, SystemError());
-    }
-
-    return 1;
-}
-
-/*
- * Method: File.readline()
- * --------------------------------------------------------
- *
- * Read the next line available.
- *
- * duk_ret_turns:
- *   The next line or undefined if eof.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodReadline(duk_context *ctx)
-{
-    std::FILE *fp = self(ctx)->handle();
-    std::string result;
-
-    if (fp == nullptr || std::feof(fp))
-        return 0;
-    for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; )
-        result += (char)ch;
-    if (std::ferror(fp))
-        dukx_throw(ctx, SystemError());
-
-    dukx_push_std_string(ctx, clearCr(result));
-
-    return 1;
-}
-
-/*
- * Method: File.remove()
- * --------------------------------------------------------
- *
- * Synonym of File.remove(path) but with the path from the file.
- *
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodRemove(duk_context *ctx)
-{
-    if (::remove(self(ctx)->path().c_str()) < 0)
-        dukx_throw(ctx, SystemError());
-
-    return 0;
-}
-
-/*
- * Method: File.seek(type, amount)
- * --------------------------------------------------------
- *
- * Sets the position in the file.
- *
- * Arguments:
- *   - type, the type of setting (File.SeekSet, File.SeekCur, File.SeekSet),
- *   - amount, the new offset.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodSeek(duk_context *ctx)
-{
-    auto fp = self(ctx)->handle();
-    auto type = duk_require_int(ctx, 0);
-    auto amount = duk_require_int(ctx, 1);
-
-    if (fp != nullptr && std::fseek(fp, amount, type) != 0)
-        dukx_throw(ctx, SystemError());
-
-    return 0;
-}
-
-#if defined(HAVE_STAT)
-
-/*
- * Method: File.stat() [optional]
- * --------------------------------------------------------
- *
- * Synonym of File.stat(path) but with the path from the file.
- *
- * duk_ret_turns:
- *   The stat information.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodStat(duk_context *ctx)
-{
-    auto file = self(ctx);
-    struct stat st;
-
-    if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0)
-        dukx_throw(ctx, SystemError());
-    else
-        pushStat(ctx, st);
-
-    return 1;
-}
-
-#endif // !HAVE_STAT
-
-/*
- * Method: File.tell()
- * --------------------------------------------------------
- *
- * Get the actual position in the file.
- *
- * duk_ret_turns:
- *   The position.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodTell(duk_context *ctx)
-{
-    auto fp = self(ctx)->handle();
-    long pos;
-
-    if (fp == nullptr)
-        return 0;
-
-    if ((pos = std::ftell(fp)) == -1L)
-        dukx_throw(ctx, SystemError());
-    else
-        duk_push_int(ctx, pos);
-
-    return 1;
-}
-
-/*
- * Method: File.write(data)
- * --------------------------------------------------------
- *
- * Write some characters to the file.
- *
- * Arguments:
- *   - data, the character to write.
- * duk_ret_turns:
- *   The number of bytes written.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t methodWrite(duk_context *ctx)
-{
-    std::FILE *fp = self(ctx)->handle();
-    std::string data = duk_require_string(ctx, 0);
-
-    if (fp == nullptr)
-        return 0;
-
-    std::size_t nwritten = std::fwrite(data.c_str(), 1, data.length(), fp);
-
-    if (std::ferror(fp))
-        dukx_throw(ctx, SystemError());
-
-    duk_push_uint(ctx, nwritten);
-
-    return 1;
-}
-
-const duk_function_list_entry methods[] = {
-    { "basename",   methodBasename, 0 },
-    { "close",      methodClose,    0 },
-    { "dirname",    methodDirname,  0 },
-    { "lines",      methodLines,    0 },
-    { "read",       methodRead,     1 },
-    { "readline",   methodReadline, 0 },
-    { "remove",     methodRemove,   0 },
-    { "seek",       methodSeek,     2 },
-#if defined(HAVE_STAT)
-    { "stat",       methodStat,     0 },
-#endif
-    { "tell",       methodTell,     0 },
-    { "write",      methodWrite,    1 },
-    { nullptr,      nullptr,        0 }
-};
-
-/*
- * File "static" functions
- * ------------------------------------------------------------------
- */
-
-/*
- * Function: Irccd.File(path, mode) [constructor]
- * --------------------------------------------------------
- *
- * Open a file specified by path with the specified mode.
- *
- * Arguments:
- *   - path, the path to the file,
- *   - mode, the mode string.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t constructor(duk_context *ctx)
-{
-    if (!duk_is_constructor_call(ctx))
-        return 0;
-
-    try {
-        dukx_new_file(ctx, new File(duk_require_string(ctx, 0), duk_require_string(ctx, 1)));
-    } catch (const std::exception &) {
-        dukx_throw(ctx, SystemError());
-    }
-
-    return 0;
-}
-
-/*
- * Function: Irccd.File() [destructor]
- * ------------------------------------------------------------------
- *
- * Delete the property.
- */
-duk_ret_t destructor(duk_context *ctx)
-{
-    duk_get_prop_string(ctx, 0, Signature);
-    delete static_cast<File *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-    duk_del_prop_string(ctx, 0, Signature);
-
-    return 0;
-}
-
-/*
- * Function: Irccd.File.basename(path)
- * --------------------------------------------------------
- *
- * duk_ret_turn the file basename as specified in `basename(3)` C function.
- *
- * Arguments:
- *   - path, the path to the file.
- * duk_ret_turns:
- *   The base name.
- */
-duk_ret_t functionBasename(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, fs::baseName(duk_require_string(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.File.dirname(path)
- * --------------------------------------------------------
- *
- * duk_ret_turn the file directory name as specified in `dirname(3)` C function.
- *
- * Arguments:
- *   - path, the path to the file.
- * duk_ret_turns:
- *   The directory name.
- */
-duk_ret_t functionDirname(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, fs::dirName(duk_require_string(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.File.exists(path)
- * --------------------------------------------------------
- *
- * Check if the file exists.
- *
- * Arguments:
- *   - path, the path to the file.
- * duk_ret_turns:
- *   True if exists.
- * Throws:
- *   - Any exception if we don't have access.
- */
-duk_ret_t functionExists(duk_context *ctx)
-{
-    try {
-        duk_push_boolean(ctx, boost::filesystem::exists(duk_require_string(ctx, 0)));
-    } catch (...) {
-        duk_push_boolean(ctx, false);
-    }
-
-    return 1;
-}
-
-/*
- * function Irccd.File.remove(path)
- * --------------------------------------------------------
- *
- * Remove the file at the specified path.
- *
- * Arguments:
- *   - path, the path to the file.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t functionRemove(duk_context *ctx)
-{
-    if (::remove(duk_require_string(ctx, 0)) < 0)
-        dukx_throw(ctx, SystemError());
-
-    return 0;
-}
-
-#if defined(HAVE_STAT)
-
-/*
- * function Irccd.File.stat(path) [optional]
- * --------------------------------------------------------
- *
- * Get file information at the specified path.
- *
- * Arguments:
- *   - path, the path to the file.
- * duk_ret_turns:
- *   The stat information.
- * Throws:
- *   - Any exception on error.
- */
-duk_ret_t functionStat(duk_context *ctx)
-{
-    struct stat st;
-
-    if (::stat(duk_require_string(ctx, 0), &st) < 0)
-        dukx_throw(ctx, SystemError());
-
-    pushStat(ctx, st);
-
-    return 1;
-}
-
-#endif // !HAVE_STAT
-
-const duk_function_list_entry functions[] = {
-    { "basename",   functionBasename,   1 },
-    { "dirname",    functionDirname,    1 },
-    { "exists",     functionExists,     1 },
-    { "remove",     functionRemove,     1 },
-#if defined(HAVE_STAT)
-    { "stat",       functionStat,       1 },
-#endif
-    { nullptr,      nullptr,            0 }
-};
-
-const duk_number_list_entry constants[] = {
-    { "SeekCur",    SEEK_CUR },
-    { "SeekEnd",    SEEK_END },
-    { "SeekSet",    SEEK_SET },
-    { nullptr,      0        }
-};
-
-} // !namespace
-
-FileModule::FileModule() noexcept
-    : Module("Irccd.File")
-{
-}
-
-void FileModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_c_function(plugin->context(), constructor, 2);
-    duk_put_number_list(plugin->context(), -1, constants);
-    duk_put_function_list(plugin->context(), -1, functions);
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, methods);
-    duk_push_c_function(plugin->context(), destructor, 1);
-    duk_set_finalizer(plugin->context(), -2);
-    duk_dup(plugin->context(), -1);
-    duk_put_global_string(plugin->context(), Prototype);
-    duk_put_prop_string(plugin->context(), -2, "prototype");
-    duk_put_prop_string(plugin->context(), -2, "File");
-    duk_pop(plugin->context());
-}
-
-void dukx_new_file(duk_context *ctx, File *fp)
-{
-    assert(ctx);
-    assert(fp);
-
-    StackAssert sa(ctx);
-
-    duk_push_this(ctx);
-    duk_push_pointer(ctx, fp);
-    duk_put_prop_string(ctx, -2, Signature);
-    duk_pop(ctx);
-}
-
-void dukx_push_file(duk_context *ctx, File *fp)
-{
-    assert(ctx);
-    assert(fp);
-
-    StackAssert sa(ctx, 1);
-
-    duk_push_object(ctx);
-    duk_push_pointer(ctx, fp);
-    duk_put_prop_string(ctx, -2, Signature);
-    duk_get_global_string(ctx, Prototype);
-    duk_set_prototype(ctx, -2);
-}
-
-File *dukx_require_file(duk_context *ctx, duk_idx_t index)
-{
-    if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature))
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object");
-
-    duk_get_prop_string(ctx, index, Signature);
-    File *file = static_cast<File *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-
-    return file;
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-file.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-/*
- * mod-file.hpp -- Irccd.File API
- *
- * Copyright (c) 2013-2017 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_MOD_FILE_HPP
-#define IRCCD_MOD_FILE_HPP
-
-/**
- * \file mod-file.hpp
- * \brief Irccd.File JavaScript API.
- */
-
-#include <cassert>
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-#include <functional>
-#include <stdexcept>
-#include <string>
-
-#include "duktape.hpp"
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Object for Javascript to perform I/O.
- *
- * This class can be constructed to Javascript.
- *
- * It is used in:
- *
- * - Irccd.File [constructor]
- * - Irccd.System.popen (optional)
- */
-class File {
-private:
-    File(const File &) = delete;
-    File &operator=(const File &) = delete;
-
-    File(File &&) = delete;
-    File &operator=(File &&) = delete;
-
-private:
-    std::string m_path;
-    std::FILE *m_stream;
-    std::function<void (std::FILE *)> m_destructor;
-
-public:
-    /**
-     * Construct a file specified by path
-     *
-     * \param path the path
-     * \param mode the mode string (for std::fopen)
-     * \throw std::runtime_error on failures
-     */
-    inline File(std::string path, const std::string &mode)
-        : m_path(std::move(path))
-        , m_destructor([] (std::FILE *fp) { std::fclose(fp); })
-    {
-        if ((m_stream = std::fopen(m_path.c_str(), mode.c_str())) == nullptr)
-            throw std::runtime_error(std::strerror(errno));
-    }
-
-    /**
-     * Construct a file from a already created FILE pointer (e.g. popen).
-     *
-     * The class takes ownership of fp and will close it.
-     *
-     * \pre destructor must not be null
-     * \param fp the file pointer
-     * \param destructor the function to close fp (e.g. std::fclose)
-     */
-    inline File(std::FILE *fp, std::function<void (std::FILE *)> destructor) noexcept
-        : m_stream(fp)
-        , m_destructor(std::move(destructor))
-    {
-        assert(m_destructor != nullptr);
-    }
-
-    /**
-     * Closes the file.
-     */
-    virtual ~File() noexcept
-    {
-        close();
-    }
-
-    /**
-     * Get the path.
-     *
-     * \return the path
-     * \warning empty when constructed from the FILE constructor
-     */
-    inline const std::string &path() const noexcept
-    {
-        return m_path;
-    }
-
-    /**
-     * Get the handle.
-     *
-     * \return the handle or nullptr if the stream was closed
-     */
-    inline std::FILE *handle() noexcept
-    {
-        return m_stream;
-    }
-
-    /**
-     * Force close, can be safely called multiple times.
-     */
-    inline void close() noexcept
-    {
-        if (m_stream) {
-            m_destructor(m_stream);
-            m_stream = nullptr;
-        }
-    }
-};
-
-/**
- * \brief Irccd.File JavaScript API.
- * \ingroup modules
- */
-class FileModule : public Module {
-public:
-    /**
-     * Irccd.File.
-     */
-    IRCCD_EXPORT FileModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-/**
- * Construct the file as this.
- *
- * The object prototype takes ownership of fp and will be deleted once
- * collected.
- *
- * \pre fp != nullptr
- * \param ctx the the context
- * \param fp the file
- */
-IRCCD_EXPORT void dukx_new_file(duk_context *ctx, File *fp);
-
-/**
- * Push a file.
- *
- * \pre fp != nullptr
- * \param ctx the the context
- * \param fp the file
- */
-IRCCD_EXPORT void dukx_push_file(duk_context *ctx, File *fp);
-
-/**
- * Require a file. Raises a JavaScript error if not a File.
- *
- * \param ctx the context
- * \param index the index
- */
-IRCCD_EXPORT File *dukx_require_file(duk_context *ctx, duk_idx_t index);
-
-} // !irccd
-
-#endif // !IRCCD_MOD_FILE_HPP
--- a/libirccd-js/irccd/mod-irccd.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-/*
- * mod-irccd.cpp -- Irccd API
- *
- * Copyright (c) 2013-2017 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 <cerrno>
-#include <string>
-#include <unordered_map>
-
-#include "mod-irccd.hpp"
-#include "plugin-js.hpp"
-#include "sysconfig.hpp"
-
-namespace irccd {
-
-namespace {
-
-const std::unordered_map<std::string, int> errors{
-    { "E2BIG",              E2BIG           },
-    { "EACCES",             EACCES          },
-    { "EADDRINUSE",         EADDRINUSE      },
-    { "EADDRNOTAVAIL",      EADDRNOTAVAIL   },
-    { "EAFNOSUPPORT",       EAFNOSUPPORT    },
-    { "EAGAIN",             EAGAIN          },
-    { "EALREADY",           EALREADY        },
-    { "EBADF",              EBADF           },
-#if defined(EBADMSG)
-    { "EBADMSG",            EBADMSG         },
-#endif
-    { "EBUSY",              EBUSY           },
-    { "ECANCELED",          ECANCELED       },
-    { "ECHILD",             ECHILD          },
-    { "ECONNABORTED",       ECONNABORTED    },
-    { "ECONNREFUSED",       ECONNREFUSED    },
-    { "ECONNRESET",         ECONNRESET      },
-    { "EDEADLK",            EDEADLK         },
-    { "EDESTADDRREQ",       EDESTADDRREQ    },
-    { "EDOM",               EDOM            },
-    { "EEXIST",             EEXIST          },
-    { "EFAULT",             EFAULT          },
-    { "EFBIG",              EFBIG           },
-    { "EHOSTUNREACH",       EHOSTUNREACH    },
-#if defined(EIDRM)
-    { "EIDRM",              EIDRM           },
-#endif
-    { "EILSEQ",             EILSEQ          },
-    { "EINPROGRESS",        EINPROGRESS     },
-    { "EINTR",              EINTR           },
-    { "EINVAL",             EINVAL          },
-    { "EIO",                EIO             },
-    { "EISCONN",            EISCONN         },
-    { "EISDIR",             EISDIR          },
-    { "ELOOP",              ELOOP           },
-    { "EMFILE",             EMFILE          },
-    { "EMLINK",             EMLINK          },
-    { "EMSGSIZE",           EMSGSIZE        },
-    { "ENAMETOOLONG",       ENAMETOOLONG    },
-    { "ENETDOWN",           ENETDOWN        },
-    { "ENETRESET",          ENETRESET       },
-    { "ENETUNREACH",        ENETUNREACH     },
-    { "ENFILE",             ENFILE          },
-    { "ENOBUFS",            ENOBUFS         },
-#if defined(ENODATA)
-    { "ENODATA",            ENODATA         },
-#endif
-    { "ENODEV",             ENODEV          },
-    { "ENOENT",             ENOENT          },
-    { "ENOEXEC",            ENOEXEC         },
-    { "ENOLCK",             ENOLCK          },
-#if defined(ENOLINK)
-    { "ENOLINK",            ENOLINK         },
-#endif
-    { "ENOMEM",             ENOMEM          },
-#if defined(ENOMSG)
-    { "ENOMSG",             ENOMSG          },
-#endif
-    { "ENOPROTOOPT",        ENOPROTOOPT     },
-    { "ENOSPC",             ENOSPC          },
-#if defined(ENOSR)
-    { "ENOSR",              ENOSR           },
-#endif
-#if defined(ENOSTR)
-    { "ENOSTR",             ENOSTR          },
-#endif
-    { "ENOSYS",             ENOSYS          },
-    { "ENOTCONN",           ENOTCONN        },
-    { "ENOTDIR",            ENOTDIR         },
-    { "ENOTEMPTY",          ENOTEMPTY       },
-#if defined(ENOTRECOVERABLE)
-    { "ENOTRECOVERABLE",    ENOTRECOVERABLE },
-#endif
-    { "ENOTSOCK",           ENOTSOCK        },
-    { "ENOTSUP",            ENOTSUP         },
-    { "ENOTTY",             ENOTTY          },
-    { "ENXIO",              ENXIO           },
-    { "EOPNOTSUPP",         EOPNOTSUPP      },
-    { "EOVERFLOW",          EOVERFLOW       },
-    { "EOWNERDEAD",         EOWNERDEAD      },
-    { "EPERM",              EPERM           },
-    { "EPIPE",              EPIPE           },
-    { "EPROTO",             EPROTO          },
-    { "EPROTONOSUPPORT",    EPROTONOSUPPORT },
-    { "EPROTOTYPE",         EPROTOTYPE      },
-    { "ERANGE",             ERANGE          },
-    { "EROFS",              EROFS           },
-    { "ESPIPE",             ESPIPE          },
-    { "ESRCH",              ESRCH           },
-#if defined(ETIME)
-    { "ETIME",              ETIME           },
-#endif
-    { "ETIMEDOUT",          ETIMEDOUT       },
-#if defined(ETXTBSY)
-    { "ETXTBSY",            ETXTBSY         },
-#endif
-    { "EWOULDBLOCK",        EWOULDBLOCK     },
-    { "EXDEV",              EXDEV           }
-};
-
-duk_ret_t constructor(duk_context *ctx)
-{
-    duk_push_this(ctx);
-    duk_push_int(ctx, duk_require_int(ctx, 0));
-    duk_put_prop_string(ctx, -2, "errno");
-    duk_push_string(ctx, duk_require_string(ctx, 1));
-    duk_put_prop_string(ctx, -2, "message");
-    duk_push_string(ctx, "SystemError");
-    duk_put_prop_string(ctx, -2, "name");
-    duk_pop(ctx);
-
-    return 0;
-}
-
-} // !namespace
-
-SystemError::SystemError()
-    : m_errno(errno)
-    , m_message(std::strerror(m_errno))
-{
-}
-
-SystemError::SystemError(int e, std::string message)
-    : m_errno(e)
-    , m_message(std::move(message))
-{
-}
-
-void SystemError::raise(duk_context *ctx) const
-{
-    StackAssert sa(ctx, 0);
-
-    duk_get_global_string(ctx, "Irccd");
-    duk_get_prop_string(ctx, -1, "SystemError");
-    duk_remove(ctx, -2);
-    duk_push_int(ctx, m_errno);
-    dukx_push_std_string(ctx, m_message);
-    duk_new(ctx, 2);
-    duk_throw(ctx);
-}
-
-IrccdModule::IrccdModule() noexcept
-    : Module("Irccd")
-{
-}
-
-void IrccdModule::load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    // Irccd.
-    duk_push_object(plugin->context());
-
-    // Version.
-    duk_push_object(plugin->context());
-    duk_push_int(plugin->context(), IRCCD_VERSION_MAJOR);
-    duk_put_prop_string(plugin->context(), -2, "major");
-    duk_push_int(plugin->context(), IRCCD_VERSION_MINOR);
-    duk_put_prop_string(plugin->context(), -2, "minor");
-    duk_push_int(plugin->context(), IRCCD_VERSION_PATCH);
-    duk_put_prop_string(plugin->context(), -2, "patch");
-    duk_put_prop_string(plugin->context(), -2, "version");
-
-    // Create the SystemError that inherits from Error.
-    duk_push_c_function(plugin->context(), constructor, 2);
-
-    // Put errno codes into the Irccd.SystemError object.
-    for (const auto &pair : errors) {
-        duk_push_int(plugin->context(), pair.second);
-        duk_put_prop_string(plugin->context(), -2, pair.first.c_str());
-    }
-
-    duk_push_object(plugin->context());
-    duk_get_global_string(plugin->context(), "Error");
-    duk_get_prop_string(plugin->context(), -1, "prototype");
-    duk_remove(plugin->context(), -2);
-    duk_set_prototype(plugin->context(), -2);
-    duk_put_prop_string(plugin->context(), -2, "prototype");
-    duk_put_prop_string(plugin->context(), -2, "SystemError");
-
-    // Set Irccd as global.
-    duk_put_global_string(plugin->context(), "Irccd");
-
-    // Store global instance.
-    duk_push_pointer(plugin->context(), &irccd);
-    duk_put_global_string(plugin->context(), "\xff""\xff""irccd-ref");
-}
-
-Irccd &dukx_get_irccd(duk_context *ctx)
-{
-    StackAssert sa(ctx);
-
-    duk_get_global_string(ctx, "\xff""\xff""irccd-ref");
-    Irccd *irccd = static_cast<Irccd *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-
-    return *irccd;
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-irccd.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * mod-irccd.hpp -- Irccd API
- *
- * Copyright (c) 2013-2017 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_MOD_IRCCD_HPP
-#define IRCCD_MOD_IRCCD_HPP
-
-/**
- * \file mod-irccd.hpp
- * \brief Irccd JavaScript API.
- */
-
-#include <cerrno>
-#include <cstring>
-#include <string>
-
-#include "duktape.hpp"
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Custom JavaScript exception for system error.
- */
-class SystemError {
-private:
-    int m_errno;
-    std::string m_message;
-
-public:
-    /**
-     * Create a system error from the current errno value.
-     */
-    IRCCD_EXPORT SystemError();
-
-    /**
-     * Create a system error with the given errno and message.
-     *
-     * \param e the errno number
-     * \param message the message
-     */
-    IRCCD_EXPORT SystemError(int e, std::string message);
-
-    /**
-     * Raise the SystemError.
-     *
-     * \param ctx the context
-     */
-    IRCCD_EXPORT void raise(duk_context *ctx) const;
-};
-
-/**
- * \brief Irccd JavaScript API.
- * \ingroup modules
- */
-class IrccdModule : public Module {
-public:
-    /**
-     * Irccd.
-     */
-    IRCCD_EXPORT IrccdModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-/**
- * Get irccd instance stored in this context.
- *
- * \param ctx the context
- * \return the irccd reference
- */
-Irccd &dukx_get_irccd(duk_context *ctx);
-
-} // !irccd
-
-#endif // !IRCCD_MOD_IRCCD_HPP
--- a/libirccd-js/irccd/mod-logger.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * mod-logger.cpp -- Irccd.Logger API
- *
- * Copyright (c) 2013-2017 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 "mod-logger.hpp"
-#include "mod-plugin.hpp"
-#include "logger.hpp"
-#include "plugin-js.hpp"
-
-namespace irccd {
-
-namespace {
-
-duk_ret_t print(duk_context *ctx, std::ostream &out)
-{
-    out << "plugin " << dukx_get_plugin(ctx)->name() << ": " << duk_require_string(ctx, 0) << std::endl;
-
-    return 0;
-}
-
-/*
- * Function: Irccd.Logger.info(message)
- * --------------------------------------------------------
- *
- * Write a verbose message.
- *
- * Arguments:
- *   - message, the message.
- */
-duk_ret_t info(duk_context *ctx)
-{
-    return print(ctx, log::info());
-}
-
-/*
- * Function: Irccd.Logger.warning(message)
- * --------------------------------------------------------
- *
- * Write a warning message.
- *
- * Arguments:
- *   - message, the warning.
- */
-duk_ret_t warning(duk_context *ctx)
-{
-    return print(ctx, log::warning());
-}
-
-/*
- * Function: Logger.debug(message)
- * --------------------------------------------------------
- *
- * Write a debug message, only shown if irccd is compiled in debug.
- *
- * Arguments:
- *   - message, the message.
- */
-duk_ret_t debug(duk_context *ctx)
-{
-    return print(ctx, log::debug());
-}
-
-const duk_function_list_entry functions[] = {
-    { "info",       info,       1 },
-    { "warning",    warning,    1 },
-    { "debug",      debug,      1 },
-    { nullptr,      nullptr,    0 }
-};
-
-} // !namespace
-
-LoggerModule::LoggerModule() noexcept
-    : Module("Irccd.Logger")
-{
-}
-
-void LoggerModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, functions);
-    duk_put_prop_string(plugin->context(), -2, "Logger");
-    duk_pop(plugin->context());
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-logger.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-logger.hpp -- Irccd.Logger API
- *
- * Copyright (c) 2013-2017 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_MOD_LOGGER_HPP
-#define IRCCD_MOD_LOGGER_HPP
-
-/**
- * \file mod-logger.hpp
- * \brief Irccd.Logger JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Logger JavaScript API.
- * \ingroup modules
- */
-class LoggerModule : public Module {
-public:
-    /**
-     * Irccd.Logger.
-     */
-    IRCCD_EXPORT LoggerModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_LOGGER_HPP
--- a/libirccd-js/irccd/mod-plugin.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,383 +0,0 @@
-/*
- * mod-plugin.cpp -- Irccd.Plugin API
- *
- * Copyright (c) 2013-2017 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.hpp"
-#include "plugin-js.hpp"
-#include "service.hpp"
-#include "mod-irccd.hpp"
-#include "mod-plugin.hpp"
-
-namespace irccd {
-
-namespace {
-
-const char PluginGlobal[] = "\xff""\xff""irccd-plugin-ptr";
-
-/*
- * wrap
- * ------------------------------------------------------------------
- *
- * Wrap function for these functions because they all takes the same arguments.
- *
- * - load,
- * - reload,
- * - unload.
- */
-template <typename Func>
-duk_idx_t wrap(duk_context *ctx, int nret, Func &&func)
-{
-    std::string name = duk_require_string(ctx, 0);
-
-    try {
-        func(dukx_get_irccd(ctx), name);
-    } catch (const std::out_of_range &ex) {
-        dukx_throw(ctx, ReferenceError(ex.what()));
-    } catch (const std::exception &ex) {
-        dukx_throw(ctx, Error(ex.what()));
-    }
-
-    return nret;
-}
-
-/*
- * set
- * ------------------------------------------------------------------
- *
- * This setter is used to replace the Irccd.plugin->(config|format) property when
- * the plugin assign a new one.
- *
- * Because the plugin configuration always has higher priority, when a new
- * object is assigned to 'config' or to the 'format' property, the plugin
- * configuration is merged to the assigned one, adding or replacing any values.
- *
- * Example:
- *
- * Plugin 'xyz' does:
- *
- * Irccd.plugin->config = {
- *      mode: "simple",
- *      level: "123"
- * };
- *
- * The user configuration is:
- *
- * [plugin->xyz]
- * mode = "hard"
- * path = "/var"
- *
- * The final user table looks like this:
- *
- * Irccd.plugin->config = {
- *      mode: "hard",
- *      level: "123",
- *      path: "/var"
- */
-duk_ret_t set(duk_context *ctx, const char *name)
-{
-    if (!duk_is_object(ctx, 0))
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "'%s' property must be object", name);
-
-    // Merge old table with new one.
-    duk_get_global_string(ctx, name);
-    duk_enum(ctx, -1, 0);
-
-    while (duk_next(ctx, -1, true))
-        duk_put_prop(ctx, 0);
-
-    // Pop enum and old table.
-    duk_pop_2(ctx);
-
-    // Replace the old table with the new assigned one.
-    duk_put_global_string(ctx, name);
-
-    return 0;
-}
-
-/*
- * get
- * ------------------------------------------------------------------
- *
- * Get the Irccd.plugin->(config|format|paths) property.
- */
-duk_ret_t get(duk_context *ctx, const char *name)
-{
-    duk_get_global_string(ctx, name);
-
-    return 1;
-}
-
-/*
- * setConfig
- * ------------------------------------------------------------------
- *
- * Wrap setter for Irccd.plugin->config property.
- */
-duk_ret_t setConfig(duk_context *ctx)
-{
-    return set(ctx, JsPlugin::ConfigProperty);
-}
-
-/*
- * getConfig
- * ------------------------------------------------------------------
- *
- * Wrap getter for Irccd.plugin->config property.
- */
-duk_ret_t getConfig(duk_context *ctx)
-{
-    return get(ctx, JsPlugin::ConfigProperty);
-}
-
-/*
- * setFormat
- * ------------------------------------------------------------------
- *
- * Wrap setter for Irccd.plugin->format property.
- */
-duk_ret_t setFormat(duk_context *ctx)
-{
-    return set(ctx, JsPlugin::FormatProperty);
-}
-
-/*
- * getFormat
- * ------------------------------------------------------------------
- *
- * Wrap getter for Irccd.plugin->format property.
- */
-duk_ret_t getFormat(duk_context *ctx)
-{
-    return get(ctx, JsPlugin::FormatProperty);
-}
-
-/*
- * setPaths
- * ------------------------------------------------------------------
- *
- * Wrap setter for Irccd.plugin->format property.
- */
-duk_ret_t setPaths(duk_context *ctx)
-{
-    return set(ctx, JsPlugin::PathsProperty);
-}
-
-/*
- * getPaths
- * ------------------------------------------------------------------
- *
- * Wrap getter for Irccd.plugin->format property.
- */
-duk_ret_t getPaths(duk_context *ctx)
-{
-    return get(ctx, JsPlugin::PathsProperty);
-}
-
-/*
- * Function: Irccd.plugin.info([name])
- * ------------------------------------------------------------------
- *
- * Get information about a plugin->
- *
- * The returned object as the following properties:
- *
- * - name: (string) the plugin identifier,
- * - author: (string) the author,
- * - license: (string) the license,
- * - summary: (string) a short description,
- * - version: (string) the version
- *
- * Arguments:
- *   - name, the plugin identifier, if not specified the current plugin is
- *     selected.
- * Returns:
- *   The plugin information or undefined if the plugin was not found.
- */
-duk_idx_t info(duk_context *ctx)
-{
-    std::shared_ptr<Plugin> plugin;
-
-    if (duk_get_top(ctx) >= 1)
-        plugin = dukx_get_irccd(ctx).plugins().get(duk_require_string(ctx, 0));
-    else
-        plugin = dukx_get_plugin(ctx);
-
-    if (!plugin)
-        return 0;
-
-    duk_push_object(ctx);
-    dukx_push_std_string(ctx, plugin->name());
-    duk_put_prop_string(ctx, -2, "name");
-    dukx_push_std_string(ctx, plugin->author());
-    duk_put_prop_string(ctx, -2, "author");
-    dukx_push_std_string(ctx, plugin->license());
-    duk_put_prop_string(ctx, -2, "license");
-    dukx_push_std_string(ctx, plugin->summary());
-    duk_put_prop_string(ctx, -2, "summary");
-    dukx_push_std_string(ctx, plugin->version());
-    duk_put_prop_string(ctx, -2, "version");
-
-    return 1;
-}
-
-/*
- * Function: Irccd.plugin->list()
- * ------------------------------------------------------------------
- *
- * Get the list of plugins, the array returned contains all plugin names.
- *
- * Returns:
- *   The list of all plugin names.
- */
-duk_idx_t list(duk_context *ctx)
-{
-    dukx_push_array(ctx, dukx_get_irccd(ctx).plugins().list(), [] (auto ctx, auto plugin) {
-        dukx_push_std_string(ctx, plugin->name());
-    });
-
-    return 1;
-}
-
-/*
- * Function: Irccd.plugin->load(name)
- * ------------------------------------------------------------------
- *
- * Load a plugin by name. This function will search through the standard
- * directories.
- *
- * Arguments:
- *   - name, the plugin identifier.
- * Throws:
- *   - Error on errors,
- *   - ReferenceError if the plugin was not found.
- */
-duk_idx_t load(duk_context *ctx)
-{
-    return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
-        irccd.plugins().load(name);
-    });
-}
-
-/*
- * Function: Irccd.plugin->reload(name)
- * ------------------------------------------------------------------
- *
- * Reload a plugin by name.
- *
- * Arguments:
- *   - name, the plugin identifier.
- * Throws:
- *   - Error on errors,
- *   - ReferenceError if the plugin was not found.
- */
-duk_idx_t reload(duk_context *ctx)
-{
-    return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
-        irccd.plugins().reload(name);
-    });
-}
-
-/*
- * Function: Irccd.plugin->unload(name)
- * ------------------------------------------------------------------
- *
- * Unload a plugin by name.
- *
- * Arguments:
- *   - name, the plugin identifier.
- * Throws:
- *   - Error on errors,
- *   - ReferenceError if the plugin was not found.
- */
-duk_idx_t unload(duk_context *ctx)
-{
-    return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
-        irccd.plugins().unload(name);
-    });
-}
-
-const duk_function_list_entry functions[] = {
-    { "info",   info,       DUK_VARARGS     },
-    { "list",   list,       0               },
-    { "load",   load,       1               },
-    { "reload", reload,     1               },
-    { "unload", unload,     1               },
-    { nullptr,  nullptr,    0               }
-};
-
-} // !namespace
-
-PluginModule::PluginModule() noexcept
-    : Module("Irccd.Plugin")
-{
-}
-
-void PluginModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_push_pointer(plugin->context(), new std::weak_ptr<JsPlugin>(plugin));
-    duk_push_object(plugin->context());
-    duk_push_c_function(plugin->context(), [] (auto *ctx) -> duk_ret_t {
-        duk_get_global_string(ctx, PluginGlobal);
-        delete static_cast<std::shared_ptr<JsPlugin> *>(duk_to_pointer(ctx, -1));
-        duk_pop(ctx);
-        duk_push_null(ctx);
-        duk_put_global_string(ctx, PluginGlobal);
-        return 0;
-    }, 1);
-    duk_set_finalizer(plugin->context(), -2);
-    duk_put_global_string(plugin->context(), "\xff""\xff""dummy-shared-ptr");
-    duk_put_global_string(plugin->context(), PluginGlobal);
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, functions);
-
-    // 'config' property.
-    duk_push_string(plugin->context(), "config");
-    duk_push_c_function(plugin->context(), getConfig, 0);
-    duk_push_c_function(plugin->context(), setConfig, 1);
-    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
-
-    // 'format' property.
-    duk_push_string(plugin->context(), "format");
-    duk_push_c_function(plugin->context(), getFormat, 0);
-    duk_push_c_function(plugin->context(), setFormat, 1);
-    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
-
-    // 'format' property.
-    duk_push_string(plugin->context(), "paths");
-    duk_push_c_function(plugin->context(), getPaths, 0);
-    duk_push_c_function(plugin->context(), setPaths, 1);
-    duk_def_prop(plugin->context(), -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
-
-    duk_put_prop_string(plugin->context(), -2, "Plugin");
-    duk_pop(plugin->context());
-}
-
-std::shared_ptr<JsPlugin> dukx_get_plugin(duk_context *ctx)
-{
-    StackAssert sa(ctx);
-
-    duk_get_global_string(ctx, PluginGlobal);
-    auto plugin = static_cast<std::weak_ptr<JsPlugin> *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-
-    return plugin->lock();
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-plugin.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * mod-plugin.hpp -- Irccd.Plugin API
- *
- * Copyright (c) 2013-2017 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_MOD_PLUGIN_HPP
-#define IRCCD_MOD_PLUGIN_HPP
-
-/**
- * \file mod-plugin.hpp
- * \brief Irccd.Plugin JavaScript API.
- */
-
-#include "duktape.hpp"
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Plugin JavaScript API.
- * \ingroup modules
- */
-class PluginModule : public Module {
-public:
-    /**
-     * Irccd.Plugin.
-     */
-    IRCCD_EXPORT PluginModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-/**
- * Access the plugin stored in this context.
- *
- * \param ctx the context
- * \return the plugin
- */
-std::shared_ptr<irccd::JsPlugin> dukx_get_plugin(duk_context *ctx);
-
-} // !irccd
-
-#endif // !IRCCD_MOD_PLUGIN_HPP
--- a/libirccd-js/irccd/mod-server.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,580 +0,0 @@
-/*
- * mod-server.cpp -- Irccd.Server API
- *
- * Copyright (c) 2013-2017 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 <cassert>
-#include <sstream>
-#include <unordered_map>
-
-#include "irccd.hpp"
-#include "mod-irccd.hpp"
-#include "mod-server.hpp"
-#include "plugin-js.hpp"
-#include "server.hpp"
-#include "service.hpp"
-
-namespace irccd {
-
-namespace {
-
-const char *Signature("\xff""\xff""irccd-server-ptr");
-const char *Prototype("\xff""\xff""irccd-server-prototype");
-
-std::shared_ptr<Server> self(duk_context *ctx)
-{
-    StackAssert sa(ctx);
-
-    duk_push_this(ctx);
-    duk_get_prop_string(ctx, -1, Signature);
-    auto ptr = duk_to_pointer(ctx, -1);
-    duk_pop_2(ctx);
-
-    if (!ptr)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
-
-    return *static_cast<std::shared_ptr<Server> *>(ptr);
-}
-
-/*
- * Method: Server.cmode(channel, mode)
- * ------------------------------------------------------------------
- *
- * Change a channel mode.
- *
- * Arguments:
- *   - channel, the channel,
- *   - mode, the mode.
- */
-duk_ret_t cmode(duk_context *ctx)
-{
-    self(ctx)->cmode(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.cnotice(channel, message)
- * ------------------------------------------------------------------
- *
- * Send a channel notice.
- *
- * Arguments:
- *   - channel, the channel,
- *   - message, the message.
- */
-duk_ret_t cnotice(duk_context *ctx)
-{
-    self(ctx)->cnotice(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.info()
- * ------------------------------------------------------------------
- *
- * Get the server information as an object containing the following properties:
- *
- * name: the server unique name
- * host: the host name
- * port: the port number
- * ssl: true if using ssl
- * sslVerify: true if ssl was verified
- * channels: an array of all channels
- */
-duk_ret_t info(duk_context *ctx)
-{
-    auto server = self(ctx);
-
-    duk_push_object(ctx);
-    dukx_push_std_string(ctx, server->name());
-    duk_put_prop_string(ctx, -2, "name");
-    dukx_push_std_string(ctx, server->host());
-    duk_put_prop_string(ctx, -2, "host");
-    duk_push_int(ctx, server->port());
-    duk_put_prop_string(ctx, -2, "port");
-    duk_push_boolean(ctx, server->flags() & Server::Ssl);
-    duk_put_prop_string(ctx, -2, "ssl");
-    duk_push_boolean(ctx, server->flags() & Server::SslVerify);
-    duk_put_prop_string(ctx, -2, "sslVerify");
-    dukx_push_std_string(ctx, server->commandCharacter());
-    duk_put_prop_string(ctx, -2, "commandChar");
-    dukx_push_std_string(ctx, server->realname());
-    duk_put_prop_string(ctx, -2, "realname");
-    dukx_push_std_string(ctx, server->nickname());
-    duk_put_prop_string(ctx, -2, "nickname");
-    dukx_push_std_string(ctx, server->username());
-    duk_put_prop_string(ctx, -2, "username");
-    dukx_push_array(ctx, server->channels(), [&] (auto ctx, auto channel) {
-        dukx_push_std_string(ctx, channel);
-    });
-    duk_put_prop_string(ctx, -2, "channels");
-
-    return 1;
-}
-
-/*
- * Method: Server.invite(target, channel)
- * ------------------------------------------------------------------
- *
- * Invite someone to a channel.
- *
- * Arguments:
- *   - target, the target to invite,
- *   - channel, the channel.
- */
-duk_ret_t invite(duk_context *ctx)
-{
-    self(ctx)->invite(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.join(channel, password = undefined)
- * ------------------------------------------------------------------
- *
- * Join a channel with an optional password.
- *
- * Arguments:
- *   - channel, the channel to join,
- *   - password, the password or undefined to not use.
- */
-duk_ret_t join(duk_context *ctx)
-{
-    self(ctx)->join(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.kick(target, channel, reason = undefined)
- * ------------------------------------------------------------------
- *
- * Kick someone from a channel.
- *
- * Arguments:
- *   - target, the target to kick,
- *   - channel, the channel,
- *   - reason, the optional reason or undefined to not set.
- */
-duk_ret_t kick(duk_context *ctx)
-{
-    self(ctx)->kick(duk_require_string(ctx, 0), duk_require_string(ctx, 1), dukx_get_std_string(ctx, 2));
-
-    return 0;
-}
-
-/*
- * Method: Server.me(target, message)
- * ------------------------------------------------------------------
- *
- * Send a CTCP Action.
- *
- * Arguments:
- *   - target, the target or a channel,
- *   - message, the message.
- */
-duk_ret_t me(duk_context *ctx)
-{
-    self(ctx)->me(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.message(target, message)
- * ------------------------------------------------------------------
- *
- * Send a message.
- *
- * Arguments:
- *   - target, the target or a channel,
- *   - message, the message.
- */
-duk_ret_t message(duk_context *ctx)
-{
-    self(ctx)->message(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.mode(mode)
- * ------------------------------------------------------------------
- *
- * Change your mode.
- *
- * Arguments:
- *   - mode, the new mode.
- */
-duk_ret_t mode(duk_context *ctx)
-{
-    self(ctx)->mode(duk_require_string(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Method: Server.names(channel)
- * ------------------------------------------------------------------
- *
- * Get the list of names from a channel.
- *
- * Arguments:
- *   - channel, the channel.
- */
-duk_ret_t names(duk_context *ctx)
-{
-    self(ctx)->names(duk_require_string(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Method: Server.nick(nickname)
- * ------------------------------------------------------------------
- *
- * Change the nickname.
- *
- * Arguments:
- *   - nickname, the nickname.
- */
-duk_ret_t nick(duk_context *ctx)
-{
-    self(ctx)->setNickname(duk_require_string(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Method: Server.notice(target, message)
- * ------------------------------------------------------------------
- *
- * Send a private notice.
- *
- * Arguments:
- *   - target, the target,
- *   - message, the notice message.
- */
-duk_ret_t notice(duk_context *ctx)
-{
-    self(ctx)->notice(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.part(channel, reason = undefined)
- * ------------------------------------------------------------------
- *
- * Leave a channel.
- *
- * Arguments:
- *   - channel, the channel to leave,
- *   - reason, the optional reason, keep undefined for portability.
- */
-duk_ret_t part(duk_context *ctx)
-{
-    self(ctx)->part(duk_require_string(ctx, 0), dukx_get_std_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.send(raw)
- * ------------------------------------------------------------------
- *
- * Send a raw message to the IRC server.
- *
- * Arguments:
- *   - raw, the raw message (without terminators).
- */
-duk_ret_t send(duk_context *ctx)
-{
-    self(ctx)->send(duk_require_string(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Method: Server.topic(channel, topic)
- * ------------------------------------------------------------------
- *
- * Change a channel topic.
- *
- * Arguments:
- *   - channel, the channel,
- *   - topic, the new topic.
- */
-duk_ret_t topic(duk_context *ctx)
-{
-    self(ctx)->topic(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    return 0;
-}
-
-/*
- * Method: Server.whois(target)
- * ------------------------------------------------------------------
- *
- * Get whois information.
- *
- * Arguments:
- *   - target, the target.
- */
-duk_ret_t whois(duk_context *ctx)
-{
-    self(ctx)->whois(duk_require_string(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Method: Server.toString()
- * ------------------------------------------------------------------
- *
- * Convert the object to std::string, convenience for adding the object
- * as property key.
- *
- * duk_ret_turns:
- *   The server name (unique).
- */
-duk_ret_t toString(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, self(ctx)->name());
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Server(params) [constructor]
- * ------------------------------------------------------------------
- *
- * Construct a new server.
- *
- * Params must be filled with the following properties:
- *
- * name: the name,
- * host: the host,
- * ipv6: true to use ipv6,      (Optional: default false)
- * port: the port number,       (Optional: default 6667)
- * password: the password,      (Optional: default none)
- * channels: array of channels  (Optiona: default empty)
- * ssl: true to use ssl,        (Optional: default false)
- * sslVerify: true to verify    (Optional: default true)
- * nickname: "nickname",        (Optional, default: irccd)
- * username: "user name",       (Optional, default: irccd)
- * realname: "real name",       (Optional, default: IRC Client Daemon)
- * commandChar: "!",            (Optional, the command char, default: "!")
- */
-duk_ret_t constructor(duk_context *ctx)
-{
-    if (!duk_is_constructor_call(ctx))
-        return 0;
-
-    duk_check_type(ctx, 0, DUK_TYPE_OBJECT);
-
-    try {
-        auto json = duk_json_encode(ctx, 0);
-        auto s = Server::fromJson(nlohmann::json::parse(json));
-
-        duk_push_this(ctx);
-        duk_push_pointer(ctx, new std::shared_ptr<Server>(std::move(s)));
-        duk_put_prop_string(ctx, -2, Signature);
-        duk_pop(ctx);
-    } catch (const std::exception &ex) {
-        duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
-    }
-
-    return 0;
-}
-
-/*
- * Function: Irccd.Server() [destructor]
- * ------------------------------------------------------------------
- *
- * Delete the property.
- */
-duk_ret_t destructor(duk_context *ctx)
-{
-    duk_get_prop_string(ctx, 0, Signature);
-    delete static_cast<std::shared_ptr<Server> *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-    duk_del_prop_string(ctx, 0, Signature);
-
-    return 0;
-}
-
-/*
- * Function: Irccd.Server.add(s)
- * ------------------------------------------------------------------
- *
- * Register a new server to the irccd instance.
- *
- * Arguments:
- *   - s, the server to add.
- */
-duk_ret_t add(duk_context *ctx)
-{
-    dukx_get_irccd(ctx).servers().add(dukx_require_server(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Function: Irccd.Server.find(name)
- * ------------------------------------------------------------------
- *
- * Find a server by name.
- *
- * Arguments:
- *   - name, the server name
- * duk_ret_turns:
- *   The server object or undefined if not found.
- */
-duk_ret_t find(duk_context *ctx)
-{
-    auto server = dukx_get_irccd(ctx).servers().get(duk_require_string(ctx, 0));
-
-    if (!server)
-        return 0;
-
-    dukx_push_server(ctx, server);
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Server.list()
- * ------------------------------------------------------------------
- *
- * Get the map of all loaded servers.
- *
- * duk_ret_turns:
- *   An object with string-to-servers pairs.
- */
-duk_ret_t list(duk_context *ctx)
-{
-    duk_push_object(ctx);
-
-    for (const auto &server : dukx_get_irccd(ctx).servers().servers()) {
-        dukx_push_server(ctx, server);
-        duk_put_prop_string(ctx, -2, server->name().c_str());
-    }
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Server.remove(name)
- * ------------------------------------------------------------------
- *
- * Remove a server from the irccd instance. You can pass the server object since
- * it's coercible to a string.
- *
- * Arguments:
- *   - name the server name.
- */
-duk_ret_t remove(duk_context *ctx)
-{
-    dukx_get_irccd(ctx).servers().remove(duk_require_string(ctx, 0));
-
-    return 0;
-}
-
-const duk_function_list_entry methods[] = {
-    { "cmode",      cmode,      2           },
-    { "cnotice",    cnotice,    2           },
-    { "info",       info,       0           },
-    { "invite",     invite,     2           },
-    { "join",       join,       DUK_VARARGS },
-    { "kick",       kick,       DUK_VARARGS },
-    { "me",         me,         2           },
-    { "message",    message,    2           },
-    { "mode",       mode,       1           },
-    { "names",      names,      1           },
-    { "nick",       nick,       1           },
-    { "notice",     notice,     2           },
-    { "part",       part,       DUK_VARARGS },
-    { "send",       send,       1           },
-    { "topic",      topic,      2           },
-    { "whois",      whois,      1           },
-    { "toString",   toString,   0           },
-    { nullptr,      nullptr,    0           }
-};
-
-const duk_function_list_entry functions[] = {
-    { "add",        add,        1           },
-    { "find",       find,       1           },
-    { "list",       list,       0           },
-    { "remove",     remove,     1           },
-    { nullptr,      nullptr,    0           }
-};
-
-} // !namespace
-
-ServerModule::ServerModule() noexcept
-    : Module("Irccd.Server")
-{
-}
-
-void ServerModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_c_function(plugin->context(), constructor, 1);
-    duk_put_function_list(plugin->context(), -1, functions);
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, methods);
-    duk_push_c_function(plugin->context(), destructor, 1);
-    duk_set_finalizer(plugin->context(), -2);
-    duk_dup_top(plugin->context());
-    duk_put_global_string(plugin->context(), Prototype);
-    duk_put_prop_string(plugin->context(), -2, "prototype");
-    duk_put_prop_string(plugin->context(), -2, "Server");
-    duk_pop(plugin->context());
-}
-
-void dukx_push_server(duk_context *ctx, std::shared_ptr<Server> server)
-{
-    assert(ctx);
-    assert(server);
-
-    StackAssert sa(ctx, 1);
-
-    duk_push_object(ctx);
-    duk_push_pointer(ctx, new std::shared_ptr<Server>(std::move(server)));
-    duk_put_prop_string(ctx, -2, Signature);
-    duk_get_global_string(ctx, Prototype);
-    duk_set_prototype(ctx, -2);
-}
-
-std::shared_ptr<Server> dukx_require_server(duk_context *ctx, duk_idx_t index)
-{
-    if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature))
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object");
-
-    duk_get_prop_string(ctx, index, Signature);
-    auto file = *static_cast<std::shared_ptr<Server> *>(duk_to_pointer(ctx, -1));
-    duk_pop(ctx);
-
-    return file;
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-server.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * mod-server.hpp -- Irccd.Server API
- *
- * Copyright (c) 2013-2017 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_MOD_SERVER_HPP
-#define IRCCD_MOD_SERVER_HPP
-
-/**
- * \file mod-server.hpp
- * \brief Irccd.Server JavaScript API.
- */
-
-#include "duktape.hpp"
-#include "module.hpp"
-#include "server.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Server JavaScript API.
- * \ingroup modules
- */
-class ServerModule : public Module {
-public:
-    /**
-     * Irccd.Server.
-     */
-    IRCCD_EXPORT ServerModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-/**
- * Push a server.
- *
- * \pre server != nullptr
- * \param ctx the context
- * \param server the server
- */
-IRCCD_EXPORT void dukx_push_server(duk_context *ctx, std::shared_ptr<Server> server);
-
-/**
- * Require a server. Raise a JavaScript error if not a Server.
- *
- * \param ctx the context
- * \param index the index
- * \return the server
- */
-IRCCD_EXPORT std::shared_ptr<Server> dukx_require_server(duk_context *ctx, duk_idx_t index);
-
-} // !irccd
-
-#endif // !IRCCD_JS_SERVER_HPP
--- a/libirccd-js/irccd/mod-system.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,243 +0,0 @@
-/*
- * mod-system.cpp -- Irccd.System API
- *
- * Copyright (c) 2013-2017 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 <chrono>
-#include <cstdlib>
-#include <thread>
-
-#include "sysconfig.hpp"
-
-#if defined(HAVE_POPEN)
-#  include <cstdio>
-#endif
-
-#include "mod-file.hpp"
-#include "mod-irccd.hpp"
-#include "mod-system.hpp"
-#include "plugin-js.hpp"
-#include "system.hpp"
-
-namespace irccd {
-
-namespace {
-
-/*
- * Function: Irccd.System.env(key)
- * ------------------------------------------------------------------
- *
- * Get an environment system variable.
- *
- * Arguments:
- *   - key, the environment variable.
- * Returns:
- *   The value.
- */
-duk_ret_t env(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, sys::env(dukx_get_std_string(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.System.exec(cmd)
- * ------------------------------------------------------------------
- *
- * Execute a system command.
- *
- * Arguments:
- *   - cmd, the command to execute.
- */
-duk_ret_t exec(duk_context *ctx)
-{
-    std::system(duk_get_string(ctx, 0));
-
-    return 0;
-}
-
-/*
- * Function: Irccd.System.home()
- * ------------------------------------------------------------------
- *
- * Get the operating system user's home.
- *
- * Returns:
- *   The user home directory.
- */
-duk_ret_t home(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, sys::home());
-
-    return 1;
-}
-
-/*
- * Function: Irccd.System.name()
- * ------------------------------------------------------------------
- *
- * Get the operating system name.
- *
- * Returns:
- *   The system name.
- */
-duk_ret_t name(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, sys::name());
-
-    return 1;
-}
-
-#if defined(HAVE_POPEN)
-
-/*
- * Function: Irccd.System.popen(cmd, mode) [optional]
- * ------------------------------------------------------------------
- *
- * Wrapper for popen(3) if the function is available.
- *
- * Arguments:
- *   - cmd, the command to execute,
- *   - mode, the mode (e.g. "r").
- * Returns:
- *   A Irccd.File object.
- * Throws
- *   - Irccd.SystemError on failures.
- */
-duk_ret_t popen(duk_context *ctx)
-{
-    auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1));
-
-    if (fp == nullptr)
-        dukx_throw(ctx, SystemError());
-
-    dukx_push_file(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); }));
-
-    return 1;
-}
-
-#endif // !HAVE_POPEN
-
-/*
- * Function: Irccd.System.sleep(delay)
- * ------------------------------------------------------------------
- *
- * Sleep the main loop for the specific delay in seconds.
- */
-duk_ret_t sleep(duk_context *ctx)
-{
-    std::this_thread::sleep_for(std::chrono::seconds(duk_get_int(ctx, 0)));
-
-    return 0;
-}
-
-/*
- * Function: Irccd.System.ticks()
- * ------------------------------------------------------------------
- *
- * Get the number of milliseconds since irccd was started.
- *
- * Returns:
- *   The number of milliseconds.
- */
-duk_ret_t ticks(duk_context *ctx)
-{
-    duk_push_int(ctx, sys::ticks());
-
-    return 1;
-}
-
-/*
- * Function: Irccd.System.usleep(delay)
- * ------------------------------------------------------------------
- *
- * Sleep the main loop for the specific delay in microseconds.
- */
-duk_ret_t usleep(duk_context *ctx)
-{
-    std::this_thread::sleep_for(std::chrono::microseconds(duk_get_int(ctx, 0)));
-
-    return 0;
-}
-
-/*
- * Function: Irccd.System.uptime()
- * ------------------------------------------------------------------
- *
- * Get the system uptime.
- *
- * Returns:
- *   The system uptime.
- */
-duk_ret_t uptime(duk_context *ctx)
-{
-    duk_push_int(ctx, sys::uptime());
-
-    return 0;
-}
-
-/*
- * Function: Irccd.System.version()
- * ------------------------------------------------------------------
- *
- * Get the operating system version.
- *
- * Returns:
- *   The system version.
- */
-duk_ret_t version(duk_context *ctx)
-{
-    dukx_push_std_string(ctx, sys::version());
-
-    return 1;
-}
-
-const duk_function_list_entry functions[] = {
-    { "env",        env,        1 },
-    { "exec",       exec,       1 },
-    { "home",       home,       0 },
-    { "name",       name,       0 },
-#if defined(HAVE_POPEN)
-    { "popen",      popen,      2 },
-#endif
-    { "sleep",      sleep,      1 },
-    { "ticks",      ticks,      0 },
-    { "uptime",     uptime,     0 },
-    { "usleep",     usleep,     1 },
-    { "version",    version,    0 },
-    { nullptr,      nullptr,    0 }
-};
-
-} // !namespace
-
-SystemModule::SystemModule() noexcept
-    : Module("Irccd.System")
-{
-}
-
-void SystemModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, functions);
-    duk_put_prop_string(plugin->context(), -2, "System");
-    duk_pop(plugin->context());
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-system.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-system.hpp -- Irccd.System API
- *
- * Copyright (c) 2013-2017 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_MOD_SYSTEM_HPP
-#define IRCCD_MOD_SYSTEM_HPP
-
-/**
- * \file mod-system.hpp
- * \brief Irccd.System JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.System JavaScript API.
- * \ingroup modules
- */
-class SystemModule : public Module {
-public:
-    /**
-     * Irccd.System.
-     */
-    IRCCD_EXPORT SystemModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_SYSTEM_HPP
--- a/libirccd-js/irccd/mod-timer.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,209 +0,0 @@
-/*
- * mod-timer.cpp -- Irccd.Timer API
- *
- * Copyright (c) 2013-2017 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 <format.h>
-
-#include "irccd.hpp"
-#include "logger.hpp"
-#include "mod-irccd.hpp"
-#include "mod-timer.hpp"
-#include "mod-plugin.hpp"
-#include "plugin-js.hpp"
-#include "timer.hpp"
-
-using namespace fmt::literals;
-
-namespace irccd {
-
-namespace {
-
-const char *Signature("\xff""\xff""irccd-timer-ptr");
-const char *CallbackTable("\xff""\xff""irccd-timer-callbacks");
-
-void handleSignal(Irccd& irccd, std::weak_ptr<JsPlugin> ptr, std::string key)
-{
-    auto plugin = ptr.lock();
-
-    if (!plugin)
-        return;
-
-    irccd.post([plugin, key] (Irccd &) {
-        StackAssert sa(plugin->context());
-
-        duk_get_global_string(plugin->context(), CallbackTable);
-        duk_get_prop_string(plugin->context(), -1, key.c_str());
-        duk_remove(plugin->context(), -2);
-
-        if (duk_is_callable(plugin->context(), -1)) {
-            if (duk_pcall(plugin->context(), 0) != 0)
-                log::warning("plugin {}: {}"_format(plugin->name(), dukx_exception(plugin->context(), -1).stack));
-            else
-                duk_pop(plugin->context());
-        } else
-            duk_pop(plugin->context());
-    });
-}
-
-std::shared_ptr<Timer> self(duk_context *ctx)
-{
-    StackAssert sa(ctx);
-
-    duk_push_this(ctx);
-    duk_get_prop_string(ctx, -1, Signature);
-    auto ptr = duk_to_pointer(ctx, -1);
-    duk_pop_2(ctx);
-
-    if (!ptr)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Timer object");
-
-    return *static_cast<std::shared_ptr<Timer> *>(ptr);
-}
-
-/*
- * Method: Timer.start()
- * --------------------------------------------------------
- *
- * Start the timer. If the timer is already started the method is a no-op.
- */
-duk_ret_t start(duk_context *ctx)
-{
-    auto timer = self(ctx);
-
-    if (!timer->isRunning())
-        timer->start();
-
-    return 0;
-}
-
-/*
- * Method: Timer.stop()
- * --------------------------------------------------------
- *
- * Stop the timer.
- */
-duk_ret_t stop(duk_context *ctx)
-{
-    auto timer = self(ctx);
-
-    if (timer->isRunning())
-        timer->stop();
-
-    return 0;
-}
-
-const duk_function_list_entry methods[] = {
-    { "start",  start,      0 },
-    { "stop",   stop,       0 },
-    { nullptr,  nullptr,    0 }
-};
-
-/*
- * Function: Irccd.Timer(type, delay, callback) [constructor]
- * --------------------------------------------------------
- *
- * Create a new timer object.
- *
- * Arguments:
- *   - type, the type of timer (Irccd.Timer.Single or Irccd.Timer.Repeat),
- *   - delay, the interval in milliseconds,
- *   - callback, the function to call.
- */
-duk_ret_t constructor(duk_context *ctx)
-{
-    // Check parameters.
-    auto type = duk_require_int(ctx, 0);
-    auto delay = duk_require_int(ctx, 1);
-
-    if (type < static_cast<int>(TimerType::Single) || type > static_cast<int>(TimerType::Repeat))
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type");
-    if (delay < 0)
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "negative delay given");
-    if (!duk_is_callable(ctx, 2))
-        duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function");
-
-    // Construct the timer in 'this'.
-    auto &irccd = dukx_get_irccd(ctx);
-    auto timer = std::make_shared<Timer>(static_cast<TimerType>(type), delay);
-    auto hash = std::to_string(reinterpret_cast<std::uintptr_t>(timer.get()));
-
-    timer->onSignal.connect(std::bind(handleSignal, std::ref(irccd),
-        std::weak_ptr<JsPlugin>(dukx_get_plugin(ctx)), hash));
-
-    duk_push_this(ctx);
-    duk_push_pointer(ctx, new std::shared_ptr<Timer>(std::move(timer)));
-    duk_put_prop_string(ctx, -2, Signature);
-    duk_push_string(ctx, hash.c_str());
-    duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key");
-    duk_push_c_function(ctx, [] (duk_context *ctx) -> duk_ret_t {
-        StackAssert sa(ctx);
-
-        duk_get_prop_string(ctx, 0, "\xff""\xff""timer-key");
-        auto hash = duk_get_string(ctx, -1);
-        duk_pop(ctx);
-        duk_get_prop_string(ctx, 0, Signature);
-        static_cast<std::shared_ptr<Timer> *>(duk_to_pointer(ctx, -1))->get()->stop();
-        delete static_cast<std::shared_ptr<Timer> *>(duk_to_pointer(ctx, -1));
-        duk_pop(ctx);
-        duk_get_global_string(ctx, CallbackTable);
-        duk_del_prop_string(ctx, -1, hash);
-        duk_pop(ctx);
-        log::debug("plugin: timer destroyed");
-
-        return 0;
-    }, 1);
-    duk_set_finalizer(ctx, -2);
-
-    // Save a callback function into the callback table.
-    duk_get_global_string(ctx, CallbackTable);
-    duk_dup(ctx, 2);
-    duk_put_prop_string(ctx, -2, hash.c_str());
-    duk_pop(ctx);
-
-    return 0;
-}
-
-const duk_number_list_entry constants[] = {
-    { "Single",     static_cast<int>(TimerType::Single) },
-    { "Repeat",     static_cast<int>(TimerType::Repeat) },
-    { nullptr,      0                                   }
-};
-
-} // !namespace
-
-TimerModule::TimerModule() noexcept
-    : Module("Irccd.Timer")
-{
-}
-
-void TimerModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_c_function(plugin->context(), constructor, 3);
-    duk_put_number_list(plugin->context(), -1, constants);
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, methods);
-    duk_put_prop_string(plugin->context(), -2, "prototype");
-    duk_put_prop_string(plugin->context(), -2, "Timer");
-    duk_pop(plugin->context());
-    duk_push_object(plugin->context());
-    duk_put_global_string(plugin->context(), CallbackTable);
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-timer.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-timer.hpp -- Irccd.Timer API
- *
- * Copyright (c) 2013-2017 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_MOD_TIMER_HPP
-#define IRCCD_MOD_TIMER_HPP
-
-/**
- * \file mod-timer.hpp
- * \brief Irccd.Timer JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Timer JavaScript API.
- * \ingroup modules
- */
-class TimerModule : public Module {
-public:
-    /**
-     * Irccd.Timer.
-     */
-    IRCCD_EXPORT TimerModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_TIMER_HPP
--- a/libirccd-js/irccd/mod-unicode.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-/*
- * mod-unicode.cpp -- Irccd.Unicode API
- *
- * Copyright (c) 2013-2017 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 "duktape.hpp"
-#include "mod-unicode.hpp"
-#include "plugin-js.hpp"
-#include "unicode.hpp"
-
-namespace irccd {
-
-namespace {
-
-/*
- * Function: Irccd.Unicode.isDigit(code)
- * --------------------------------------------------------
- *
- * Arguments:
- *   - code, the code point.
- * Returns:
- *   True if the code is in the digit category.
- */
-duk_ret_t isDigit(duk_context *ctx)
-{
-    duk_push_boolean(ctx, unicode::isdigit(duk_get_int(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Unicode.isLetter(code)
- * --------------------------------------------------------
- *
- * Arguments:
- *   - code, the code point.
- * Returns:
- *   True if the code is in the letter category.
- */
-duk_ret_t isLetter(duk_context *ctx)
-{
-    duk_push_boolean(ctx, unicode::isalpha(duk_get_int(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Unicode.isLower(code)
- * --------------------------------------------------------
- *
- * Arguments:
- *   - code, the code point.
- * Returns:
- *   True if the code is lower case.
- */
-duk_ret_t isLower(duk_context *ctx)
-{
-    duk_push_boolean(ctx, unicode::islower(duk_get_int(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Unicode.isSpace(code)
- * --------------------------------------------------------
- *
- * Arguments:
- *   - code, the code point.
- * Returns:
- *   True if the code is in the space category.
- */
-duk_ret_t isSpace(duk_context *ctx)
-{
-    duk_push_boolean(ctx, unicode::isspace(duk_get_int(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Unicode.isTitle(code)
- * --------------------------------------------------------
- *
- * Arguments:
- *   - code, the code point.
- * Returns:
- *   True if the code is title case.
- */
-duk_ret_t isTitle(duk_context *ctx)
-{
-    duk_push_boolean(ctx, unicode::istitle(duk_get_int(ctx, 0)));
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Unicode.isUpper(code)
- * --------------------------------------------------------
- *
- * Arguments:
- *   - code, the code point.
- * Returns:
- *   True if the code is upper case.
- */
-duk_ret_t isUpper(duk_context *ctx)
-{
-    duk_push_boolean(ctx, unicode::isupper(duk_get_int(ctx, 0)));
-
-    return 1;
-}
-
-const duk_function_list_entry functions[] = {
-    { "isDigit",        isDigit,    1 },
-    { "isLetter",       isLetter,   1 },
-    { "isLower",        isLower,    1 },
-    { "isSpace",        isSpace,    1 },
-    { "isTitle",        isTitle,    1 },
-    { "isUpper",        isUpper,    1 },
-    { nullptr,          nullptr,    0 }
-};
-
-} // !namespace
-
-UnicodeModule::UnicodeModule() noexcept
-    : Module("Irccd.Unicode")
-{
-}
-
-void UnicodeModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, functions);
-    duk_put_prop_string(plugin->context(), -2, "Unicode");
-    duk_pop(plugin->context());
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-unicode.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-unicode.cpp -- Irccd.Unicode API
- *
- * Copyright (c) 2013-2017 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_MOD_UNICODE_HPP
-#define IRCCD_MOD_UNICODE_HPP
-
-/**
- * \file mod-unicode.hpp
- * \brief Irccd.Unicode JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Unicode JavaScript API.
- * \ingroup modules
- */
-class UnicodeModule : public Module {
-public:
-    /**
-     * Irccd.Unicode.
-     */
-    IRCCD_EXPORT UnicodeModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_UNICODE_HPP
--- a/libirccd-js/irccd/mod-util.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,303 +0,0 @@
-/*
- * mod-util.cpp -- Irccd.Util API
- *
- * Copyright (c) 2013-2017 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 <climits>
-
-#include <libircclient.h>
-
-#include "mod-util.hpp"
-#include "plugin-js.hpp"
-#include "util.hpp"
-
-namespace irccd {
-
-namespace {
-
-/**
- * Read parameters for Irccd.Util.format function, the object is defined as
- * following:
- *
- * {
- *   date: the date object
- *   flags: the flags (not implemented yet)
- *   field1: a field to substitute in #{} pattern
- *   field2: a field to substitute in #{} pattern
- *   fieldn: ...
- * }
- */
-util::Substitution getSubstitution(duk_context *ctx, int index)
-{
-    util::Substitution params;
-
-    if (!duk_is_object(ctx, index))
-        return params;
-
-    dukx_enumerate(ctx, index, 0, true, [&] (duk_context *) {
-        if (dukx_get_std_string(ctx, -2) == "date")
-            params.time = static_cast<time_t>(duk_get_number(ctx, -1) / 1000);
-        else
-            params.keywords.insert({dukx_get_std_string(ctx, -2), dukx_get_std_string(ctx, -1)});
-    });
-
-    return params;
-}
-
-/*
- * split (for Irccd.Util.cut as cut)
- * ------------------------------------------------------------------
- *
- * Extract individual tokens in array or a whole string as a std:::vector.
- */
-std::vector<std::string> split(duk_context *ctx)
-{
-    duk_require_type_mask(ctx, 0, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_STRING);
-
-    std::vector<std::string> result;
-    std::string pattern = " \t\n";
-
-    if (duk_is_string(ctx, 0)) {
-        result = util::split(dukx_get_std_string(ctx, 0), pattern);
-    } else if (duk_is_array(ctx, 0)) {
-        duk_enum(ctx, 0, DUK_ENUM_ARRAY_INDICES_ONLY);
-
-        while (duk_next(ctx, -1, 1)) {
-            // Split individual tokens as array if spaces are found.
-            auto tmp = util::split(duk_to_string(ctx, -1), pattern);
-
-            result.insert(result.end(), tmp.begin(), tmp.end());
-            duk_pop_2(ctx);
-        }
-    }
-
-    return result;
-}
-
-/*
- * limit (for Irccd.Util.cut as cut)
- * ------------------------------------------------------------------
- *
- * Get the maxl/maxc argument.
- *
- * The argument value is the default and also used as the result returned.
- */
-int limit(duk_context *ctx, int index, const char *name, int value)
-{
-    if (duk_get_top(ctx) < index || !duk_is_number(ctx, index)) {
-        return value;
-    }
-
-    value = duk_to_int(ctx, index);
-    
-    if (value <= 0) {
-        duk_error(ctx, DUK_ERR_RANGE_ERROR, "argument %d (%s) must be positive", index, name);
-    }
-
-    return value;
-}
-
-/*
- * lines (for Irccd.Util.cut as cut)
- * ------------------------------------------------------------------
- *
- * Build a list of lines.
- *
- * Several cases possible:
- *
- *   - s is the current line
- *   - abc is the token to add
- *
- * s   = ""                 (new line)
- * s  -> "abc"
- *
- * s   = "hello world"      (enough room)
- * s  -> "hello world abc"
- *
- * s   = "hello world"      (not enough room: maxc is smaller)
- * s+1 = "abc"
- */
-std::vector<std::string> lines(duk_context *ctx, const std::vector<std::string>& tokens, int maxc)
-{
-    std::vector<std::string> result{""};
-
-    for (const auto &s : tokens) {
-        if (s.length() > static_cast<std::size_t>(maxc)) {
-            duk_error(ctx, DUK_ERR_RANGE_ERROR, "word '%s' could not fit in maxc limit (%d)", s.c_str(), maxc);
-        }
-
-        // Compute the length required (prepend a space if needed)
-        auto required = s.length() + (result.back().empty() ? 0 : 1);
-
-        if (result.back().length() + required > static_cast<std::size_t>(maxc)) {
-            result.push_back(s);
-        } else {
-            if (!result.back().empty()) {
-                result.back() += ' ';
-            }
-            result.back() += s;
-        }
-    }
-
-    return result;
-}
-
-/*
- * Function: Irccd.Util.cut(data, maxc, maxl)
- * --------------------------------------------------------
- *
- * Cut a piece of data into several lines.
- *
- * The argument data is a string or a list of strings. In any case, all strings
- * are first splitted by spaces and trimmed. This ensure that useless
- * whitespaces are discarded.
- *
- * The argument maxc controls the maximum of characters allowed per line, it can
- * be a positive integer. If undefined is given, a default of 72 is used.
- *
- * The argument maxl controls the maximum of lines allowed. It can be a positive
- * integer or undefined for an infinite list.
- *
- * If maxl is used as a limit and the data can not fit within the bounds,
- * undefined is returned.
- *
- * An empty list may be returned if empty strings were found.
- *
- * Arguments:
- *   - data, a string or an array of strings,
- *   - maxc, max number of colums (Optional, default: 72),
- *   - maxl, max number of lines (Optional, default: undefined).
- * Returns:
- *   A list of strings ready to be sent or undefined if the data is too big.
- * Throws:
- *   - RangeError if maxl or maxc are negative numbers,
- *   - RangeError if one word length was bigger than maxc,
- *   - TypeError if data is not a string or a list of strings.
- */
-duk_ret_t cut(duk_context *ctx)
-{
-    auto list = lines(ctx, split(ctx), limit(ctx, 1, "maxc", 72));
-    auto maxl = limit(ctx, 2, "maxl", INT_MAX);
-
-    if (list.size() > static_cast<std::size_t>(maxl)) {
-        return 0;
-    }
-
-    // Empty list but lines() returns at least one.
-    if (list.size() == 1 && list[0].empty()) {
-        duk_push_array(ctx);
-        return 1;
-    }
-
-    dukx_push_array(ctx, list, dukx_push_std_string);
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Util.format(text, parameters)
- * --------------------------------------------------------
- *
- * Format a string with templates.
- *
- * Arguments:
- *   - input, the text to update,
- *   - params, the parameters.
- * Returns:
- *   The converted text.
- */
-duk_ret_t format(duk_context *ctx)
-{
-    try {
-        dukx_push_std_string(ctx, util::format(dukx_get_std_string(ctx, 0), getSubstitution(ctx, 1)));
-    } catch (const std::exception &ex) {
-        dukx_throw(ctx, SyntaxError(ex.what()));
-    }
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Util.splituser(ident)
- * --------------------------------------------------------
- *
- * Return the nickname part from a full username.
- *
- * Arguments:
- *   - ident, the full identity.
- * Returns:
- *   The nickname.
- */
-duk_ret_t splituser(duk_context *ctx)
-{
-    auto target = duk_require_string(ctx, 0);
-    char nick[32] = {0};
-
-    irc_target_get_nick(target, nick, sizeof (nick) -1);
-    duk_push_string(ctx, nick);
-
-    return 1;
-}
-
-/*
- * Function: Irccd.Util.splithost(ident)
- * --------------------------------------------------------
- *
- * Return the hostname part from a full username.
- *
- * Arguments:
- *   - ident, the full identity.
- * Returns:
- *   The hostname.
- */
-duk_ret_t splithost(duk_context *ctx)
-{
-    auto target = duk_require_string(ctx, 0);
-    char host[32] = {0};
-
-    irc_target_get_host(target, host, sizeof (host) -1);
-    duk_push_string(ctx, host);
-
-    return 1;
-}
-
-const duk_function_list_entry functions[] = {
-    { "cut",        cut,        DUK_VARARGS },
-    { "format",     format,     DUK_VARARGS },
-    { "splituser",  splituser,  1           },
-    { "splithost",  splithost,  1           },
-    { nullptr,      nullptr,    0           }
-};
-
-} // !namespace
-
-UtilModule::UtilModule() noexcept
-    : Module("Irccd.Util")
-{
-}
-
-void UtilModule::load(Irccd &, std::shared_ptr<JsPlugin> plugin)
-{
-    StackAssert sa(plugin->context());
-
-    duk_get_global_string(plugin->context(), "Irccd");
-    duk_push_object(plugin->context());
-    duk_put_function_list(plugin->context(), -1, functions);
-    duk_put_prop_string(plugin->context(), -2, "Util");
-    duk_pop(plugin->context());
-}
-
-} // !irccd
--- a/libirccd-js/irccd/mod-util.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * mod-util.hpp -- Irccd.Util API
- *
- * Copyright (c) 2013-2017 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_MOD_UTIL_HPP
-#define IRCCD_MOD_UTIL_HPP
-
-/**
- * \file mod-util.hpp
- * \brief Irccd.Util JavaScript API.
- */
-
-#include "module.hpp"
-
-namespace irccd {
-
-/**
- * \brief Irccd.Util JavaScript API.
- * \ingroup modules
- */
-class UtilModule : public Module {
-public:
-    /**
-     * Irccd.Util.
-     */
-    IRCCD_EXPORT UtilModule() noexcept;
-
-    /**
-     * \copydoc Module::load
-     */
-    IRCCD_EXPORT void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin) override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_MOD_UTIL_HPP
--- a/libirccd-js/irccd/module.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-js/irccd/module.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,11 +21,11 @@
 
 /**
  * \file module.hpp
- * \brief JavaScript API module.
+ * \brief Javascript API module.
  */
 
 /**
- * \defgroup modules JavaScript modules
+ * \defgroup Javascript modules.
  * \brief Modules for the JavaScript API.
  */
 
@@ -37,15 +37,15 @@
 
 namespace irccd {
 
-class Irccd;
-class JsPlugin;
+class irccd;
+class js_plugin;
 
 /**
  * \brief JavaScript API module.
  */
-class Module {
+class module {
 private:
-    std::string m_name;
+    std::string name_;
 
 public:
     /**
@@ -53,25 +53,25 @@
      *
      * \pre !name.empty()
      */
-    inline Module(std::string name) noexcept
-        : m_name(std::move(name))
+    inline module(std::string name) noexcept
+        : name_(std::move(name))
     {
-        assert(!m_name.empty());
+        assert(!name_.empty());
     }
 
     /**
      * Virtual destructor defaulted.
      */
-    virtual ~Module() = default;
+    virtual ~module() noexcept = default;
 
     /**
      * Get the module name.
      *
      * \return the name
      */
-    inline const std::string &name() const noexcept
+    inline const std::string& name() const noexcept
     {
-        return m_name;
+        return name_;
     }
 
     /**
@@ -80,7 +80,7 @@
      * \param irccd the irccd instance
      * \param plugin the plugin
      */
-    virtual void load(Irccd &irccd, std::shared_ptr<JsPlugin> plugin)
+    virtual void load(irccd& irccd, std::shared_ptr<js_plugin> plugin)
     {
         util::unused(irccd, plugin);
     }
--- a/libirccd-js/irccd/plugin-js.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,434 +0,0 @@
-/*
- * plugin-js.cpp -- JavaScript plugins for irccd
- *
- * Copyright (c) 2013-2017 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 <boost/filesystem.hpp>
-
-#include "sysconfig.hpp"
-
-#if defined(HAVE_STAT)
-#  include <sys/stat.h>
-#  include <cerrno>
-#  include <cstring>
-#endif
-
-#include "fs.hpp"
-#include "irccd.hpp"
-#include "logger.hpp"
-#include "mod-plugin.hpp"
-#include "mod-server.hpp"
-#include "plugin-js.hpp"
-#include "service.hpp"
-#include "timer.hpp"
-
-namespace irccd {
-
-const char JsPlugin::ConfigProperty[] = "\xff""\xff""irccd-plugin-config";
-const char JsPlugin::FormatProperty[] = "\xff""\xff""irccd-plugin-format";
-const char JsPlugin::PathsProperty[] = "\xff""\xff""irccd-plugin-paths";
-
-std::unordered_map<std::string, std::string> JsPlugin::getTable(const char *name) const
-{
-    StackAssert sa(m_context);
-    std::unordered_map<std::string, std::string> result;
-
-    duk_get_global_string(m_context, name);
-    dukx_enumerate(m_context, -1, 0, true, [&] (auto ctx) {
-        result.emplace(duk_to_string(ctx, -2), duk_to_string(ctx, -1));
-    });
-    duk_pop(m_context);
-
-    return result;
-}
-
-void JsPlugin::putTable(const char *name, const std::unordered_map<std::string, std::string> &vars)
-{
-    StackAssert sa(m_context);
-
-    duk_get_global_string(m_context, name);
-
-    for (const auto &pair : vars) {
-        dukx_push_std_string(m_context, pair.second);
-        duk_put_prop_string(m_context, -2, pair.first.c_str());
-    }
-
-    duk_pop(m_context);
-}
-
-void JsPlugin::call(const std::string &name, unsigned nargs)
-{
-    duk_get_global_string(m_context, name.c_str());
-
-    if (duk_get_type(m_context, -1) == DUK_TYPE_UNDEFINED)
-        // Function not defined, remove the undefined value and all arguments.
-        duk_pop_n(m_context, nargs + 1);
-    else {
-        // Call the function and discard the result.
-        duk_insert(m_context, -nargs - 1);
-
-        if (duk_pcall(m_context, nargs) != 0)
-            throw dukx_exception(m_context, -1, true);
-
-        duk_pop(m_context);
-    }
-}
-
-void JsPlugin::putVars()
-{
-    StackAssert sa(m_context);
-
-    duk_push_pointer(m_context, this);
-    duk_put_global_string(m_context, "\xff""\xff""plugin");
-    dukx_push_std_string(m_context, name());
-    duk_put_global_string(m_context, "\xff""\xff""name");
-    dukx_push_std_string(m_context, path());
-    duk_put_global_string(m_context, "\xff""\xff""path");
-}
-
-JsPlugin::JsPlugin(std::string name, std::string path)
-    : Plugin(name, path)
-{
-    /*
-     * Create two special tables for configuration and formats, they are
-     * referenced later as
-     *
-     *   - Irccd.Plugin.config
-     *   - Irccd.Plugin.format
-     *   - Irccd.Plugin.paths
-     *
-     * In mod-plugin.cpp.
-     */
-    duk_push_object(m_context);
-    duk_put_global_string(m_context, ConfigProperty);
-    duk_push_object(m_context);
-    duk_put_global_string(m_context, FormatProperty);
-    duk_push_object(m_context);
-    duk_put_global_string(m_context, PathsProperty);
-
-    // Used by many Javascript APIs.
-    duk_push_object(m_context);
-    duk_put_global_string(m_context, "Irccd");
-}
-
-void JsPlugin::onChannelMode(Irccd &, const ChannelModeEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.mode);
-    dukx_push_std_string(m_context, event.argument);
-    call("onChannelMode", 5);
-}
-
-void JsPlugin::onChannelNotice(Irccd &, const ChannelNoticeEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.message);
-    call("onChannelNotice", 4);
-}
-
-void JsPlugin::onCommand(Irccd &, const MessageEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.message);
-    call("onCommand", 4);
-}
-
-void JsPlugin::onConnect(Irccd &, const ConnectEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    call("onConnect", 1);
-}
-
-void JsPlugin::onInvite(Irccd &, const InviteEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    call("onInvite", 3);
-}
-
-void JsPlugin::onJoin(Irccd &, const JoinEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    call("onJoin", 3);
-}
-
-void JsPlugin::onKick(Irccd &, const KickEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.target);
-    dukx_push_std_string(m_context, event.reason);
-    call("onKick", 5);
-}
-
-void JsPlugin::onLoad(Irccd &irccd)
-{
-    StackAssert sa(m_context);
-
-    /*
-     * Duktape currently emit useless warnings when a file do
-     * not exists so we do a homemade access.
-     */
-#if defined(HAVE_STAT)
-    struct stat st;
-
-    if (::stat(path().c_str(), &st) < 0)
-        throw std::runtime_error(std::strerror(errno));
-#endif
-
-    // Try to load the file (does not call onLoad yet).
-    dukx_peval_file(m_context, path());
-    duk_pop(m_context);
-
-    /*
-     * We put configuration and formats after loading the file and before
-     * calling onLoad to allow the plugin adding configuration to
-     * Irccd.Plugin.(config|format) before the user.
-     */
-    putVars();
-    setConfig(irccd.plugins().config(name()));
-    setFormats(irccd.plugins().formats(name()));
-    setPaths(irccd.plugins().paths(name()));
-
-    // Read metadata .
-    duk_get_global_string(m_context, "info");
-
-    if (duk_get_type(m_context, -1) == DUK_TYPE_OBJECT) {
-        // 'author'
-        duk_get_prop_string(m_context, -1, "author");
-        setAuthor(duk_is_string(m_context, -1) ? duk_get_string(m_context, -1) : author());
-        duk_pop(m_context);
-
-        // 'license'
-        duk_get_prop_string(m_context, -1, "license");
-        setLicense(duk_is_string(m_context, -1) ? duk_get_string(m_context, -1) : license());
-        duk_pop(m_context);
-
-        // 'summary'
-        duk_get_prop_string(m_context, -1, "summary");
-        setSummary(duk_is_string(m_context, -1) ? duk_get_string(m_context, -1) : summary());
-        duk_pop(m_context);
-
-        // 'version'
-        duk_get_prop_string(m_context, -1, "version");
-        setVersion(duk_is_string(m_context, -1) ? duk_get_string(m_context, -1) : version());
-        duk_pop(m_context);
-    }
-
-    duk_pop(m_context);
-    call("onLoad", 0);
-}
-
-void JsPlugin::onMessage(Irccd &, const MessageEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.message);
-    call("onMessage", 4);
-}
-
-void JsPlugin::onMe(Irccd &, const MeEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.message);
-    call("onMe", 4);
-}
-
-void JsPlugin::onMode(Irccd &, const ModeEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.mode);
-    call("onMode", 3);
-}
-
-void JsPlugin::onNames(Irccd &, const NamesEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_array(m_context, event.names, dukx_push_std_string);
-    call("onNames", 3);
-}
-
-void JsPlugin::onNick(Irccd &, const NickEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.nickname);
-    call("onNick", 3);
-}
-
-void JsPlugin::onNotice(Irccd &, const NoticeEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.message);
-    call("onNotice", 3);
-}
-
-void JsPlugin::onPart(Irccd &, const PartEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.reason);
-    call("onPart", 4);
-}
-
-void JsPlugin::onQuery(Irccd &, const QueryEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.message);
-    call("onQuery", 3);
-}
-
-void JsPlugin::onQueryCommand(Irccd &, const QueryEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.message);
-    call("onQueryCommand", 3);
-}
-
-void JsPlugin::onReload(Irccd &)
-{
-    StackAssert sa(m_context);
-
-    call("onReload");
-}
-
-void JsPlugin::onTopic(Irccd &, const TopicEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    dukx_push_std_string(m_context, event.origin);
-    dukx_push_std_string(m_context, event.channel);
-    dukx_push_std_string(m_context, event.topic);
-    call("onTopic", 4);
-}
-
-void JsPlugin::onUnload(Irccd &)
-{
-    StackAssert sa(m_context);
-
-    call("onUnload");
-}
-
-void JsPlugin::onWhois(Irccd &, const WhoisEvent &event)
-{
-    StackAssert sa(m_context);
-
-    dukx_push_server(m_context, std::move(event.server));
-    duk_push_object(m_context);
-    dukx_push_std_string(m_context, event.whois.nick);
-    duk_put_prop_string(m_context, -2, "nickname");
-    dukx_push_std_string(m_context, event.whois.user);
-    duk_put_prop_string(m_context, -2, "username");
-    dukx_push_std_string(m_context, event.whois.realname);
-    duk_put_prop_string(m_context, -2, "realname");
-    dukx_push_std_string(m_context, event.whois.host);
-    duk_put_prop_string(m_context, -2, "host");
-    dukx_push_array(m_context, event.whois.channels, dukx_push_std_string);
-    duk_put_prop_string(m_context, -2, "channels");
-    call("onWhois", 2);
-}
-
-JsPluginLoader::JsPluginLoader(Irccd &irccd) noexcept
-    : PluginLoader({}, { ".js" })
-    , m_irccd(irccd)
-{
-}
-
-JsPluginLoader::~JsPluginLoader() noexcept = default;
-
-void JsPluginLoader::addModule(std::unique_ptr<Module> module)
-{
-    assert(module);
-
-    m_modules.push_back(std::move(module));
-}
-
-std::shared_ptr<Plugin> JsPluginLoader::open(const std::string &id,
-                                             const std::string &path) noexcept
-{
-    if (path.rfind(".js") == std::string::npos)
-        return nullptr;
-
-    try {
-        auto plugin = std::make_shared<JsPlugin>(id, path);
-
-        for (const auto &mod : m_modules) {
-            log::debug() << "plugin " << plugin->name() << ": ";
-            log::debug() << "loading " << mod->name() << " Javascript API" << std::endl;
-            mod->load(m_irccd, plugin);
-        }
-
-        return plugin;
-    } catch (const std::exception &ex) {
-        log::warning() << "plugin " << id << ": " << ex.what() << std::endl;
-    }
-
-    return nullptr;
-}
-
-} // !irccd
--- a/libirccd-js/irccd/plugin-js.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-/*
- * plugin-js.hpp -- JavaScript plugins for irccd
- *
- * Copyright (c) 2013-2017 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_PLUGIN_JS_HPP
-#define IRCCD_PLUGIN_JS_HPP
-
-/**
- * \file plugin-js.hpp
- * \brief JavaScript plugins for irccd.
- */
-
-#include <vector>
-
-#include "duktape.hpp"
-#include "plugin.hpp"
-
-namespace irccd {
-
-class Module;
-
-/**
- * \brief JavaScript plugins for irccd.
- * \ingroup plugins
- */
-class JsPlugin : public Plugin {
-public:
-    /**
-     * Global property where to read/write plugin configuration (object).
-     */
-    static const char ConfigProperty[];
-
-    /**
-     * Global property where to read/write plugin formats (object).
-     */
-    static const char FormatProperty[];
-
-    /**
-     * Global property where paths are defined (object).
-     */
-    static const char PathsProperty[];
-
-private:
-    // JavaScript context
-    UniqueContext m_context;
-
-    // Private helpers.
-    std::unordered_map<std::string, std::string> getTable(const char *name) const;
-    void putTable(const char *name, const std::unordered_map<std::string, std::string> &vars);
-    void call(const std::string &name, unsigned nargs = 0);
-    void putVars();
-
-public:
-    /**
-     * Constructor.
-     *
-     * \param name the plugin name
-     * \param path the path to the plugin
-     */
-    IRCCD_EXPORT JsPlugin(std::string name, std::string path);
-
-    /**
-     * Access the Duktape context.
-     *
-     * \return the context
-     */
-    inline UniqueContext &context() noexcept
-    {
-        return m_context;
-    }
-
-    /**
-     * \copydoc Plugin::config
-     */
-    PluginConfig config() override
-    {
-        return getTable(ConfigProperty);
-    }
-
-    /**
-     * \copydoc Plugin::setConfig
-     */
-    void setConfig(PluginConfig config) override
-    {
-        putTable(ConfigProperty, config);
-    }
-
-    /**
-     * \copydoc Plugin::formats
-     */
-    PluginFormats formats() override
-    {
-        return getTable(FormatProperty);
-    }
-
-    /**
-     * \copydoc Plugin::setFormats
-     */
-    void setFormats(PluginFormats formats) override
-    {
-        putTable(FormatProperty, formats);
-    }
-
-    /**
-     * \copydoc Plugin::paths
-     */
-    PluginPaths paths() override
-    {
-        return getTable(PathsProperty);
-    }
-
-    /**
-     * \copydoc Plugin::set_paths
-     */
-    void setPaths(PluginPaths paths) override
-    {
-        putTable(PathsProperty, std::move(paths));
-    }
-
-    /**
-     * \copydoc Plugin::onCommand
-     */
-    IRCCD_EXPORT void onCommand(Irccd &irccd, const MessageEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onConnect
-     */
-    IRCCD_EXPORT void onConnect(Irccd &irccd, const ConnectEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onChannelMode
-     */
-    IRCCD_EXPORT void onChannelMode(Irccd &irccd, const ChannelModeEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onChannelNotice
-     */
-    IRCCD_EXPORT void onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onInvite
-     */
-    IRCCD_EXPORT void onInvite(Irccd &irccd, const InviteEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onJoin
-     */
-    IRCCD_EXPORT void onJoin(Irccd &irccd, const JoinEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onKick
-     */
-    IRCCD_EXPORT void onKick(Irccd &irccd, const KickEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onLoad
-     */
-    IRCCD_EXPORT void onLoad(Irccd &irccd) override;
-
-    /**
-     * \copydoc Plugin::onMessage
-     */
-    IRCCD_EXPORT void onMessage(Irccd &irccd, const MessageEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onMe
-     */
-    IRCCD_EXPORT void onMe(Irccd &irccd, const MeEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onMode
-     */
-    IRCCD_EXPORT void onMode(Irccd &irccd, const ModeEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onNames
-     */
-    IRCCD_EXPORT void onNames(Irccd &irccd, const NamesEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onNick
-     */
-    IRCCD_EXPORT void onNick(Irccd &irccd, const NickEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onNotice
-     */
-    IRCCD_EXPORT void onNotice(Irccd &irccd, const NoticeEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onPart
-     */
-    IRCCD_EXPORT void onPart(Irccd &irccd, const PartEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onQuery
-     */
-    IRCCD_EXPORT void onQuery(Irccd &irccd, const QueryEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onQueryCommand
-     */
-    IRCCD_EXPORT void onQueryCommand(Irccd &irccd, const QueryEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onReload
-     */
-    IRCCD_EXPORT void onReload(Irccd &irccd) override;
-
-    /**
-     * \copydoc Plugin::onTopic
-     */
-    IRCCD_EXPORT void onTopic(Irccd &irccd, const TopicEvent &event) override;
-
-    /**
-     * \copydoc Plugin::onUnload
-     */
-    IRCCD_EXPORT void onUnload(Irccd &irccd) override;
-
-    /**
-     * \copydoc Plugin::onWhois
-     */
-    IRCCD_EXPORT void onWhois(Irccd &irccd, const WhoisEvent &event) override;
-};
-
-/**
- * \brief Implementation for searching Javascript plugins.
- */
-class JsPluginLoader : public PluginLoader {
-private:
-    Irccd &m_irccd;
-    std::vector<std::unique_ptr<Module>> m_modules;
-
-public:
-    JsPluginLoader(Irccd &irccd) noexcept;
-
-    ~JsPluginLoader() noexcept;
-
-    void addModule(std::unique_ptr<Module> module);
-
-    /**
-     * \copydoc PluginLoader::find
-     */
-    std::shared_ptr<Plugin> open(const std::string &id,
-                                 const std::string &path) noexcept override;
-};
-
-} // !irccd
-
-#endif // !IRCCD_PLUGIN_JS_HPP
--- a/libirccd-js/irccd/timer.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-js/irccd/timer.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -25,80 +25,80 @@
 
 namespace irccd {
 
-void Timer::run()
+void timer::run()
 {
-    while (m_state != Stopped) {
-        std::unique_lock<std::mutex> lock(m_mutex);
+    while (state_ != state::stopped) {
+        std::unique_lock<std::mutex> lock(mutex_);
 
         // Wait in case the timer is paused.
-        m_condition.wait(lock, [&] () {
-            return m_state == Running;
+        condition_.wait(lock, [&] () {
+            return state_ == state::running;
         });
 
-        if (m_state != Running)
+        if (state_ != state::running)
             continue;
 
         // Wait the timer delay or the interrupt.
-        m_condition.wait_for(lock, std::chrono::milliseconds(m_delay), [&] () {
-            return m_state != Running;
+        condition_.wait_for(lock, std::chrono::milliseconds(delay_), [&] () {
+            return state_ != state::running;
         });
 
-        if (m_state == Running) {
+        if (state_ == state::running) {
             // Signal process.
-            onSignal();
+            on_signal();
 
-            if (m_type == TimerType::Single)
-                m_state = Stopped;
+            if (type_ == type::single)
+                state_ = state::stopped;
         }
     }
 
-    onEnd();
+    on_end();
 }
 
-Timer::Timer(TimerType type, unsigned delay) noexcept
-    : m_type(type)
-    , m_delay(delay)
-    , m_thread(std::bind(&Timer::run, this))
+timer::timer(type type, unsigned delay) noexcept
+    : type_(type)
+    , delay_(delay)
+    , thread_(std::bind(&timer::run, this))
 {
 }
 
-Timer::~Timer()
+timer::~timer()
 {
-    assert(m_state != Running);
+    assert(state_ != state::running);
 
     try {
         {
-            std::lock_guard<std::mutex> lk(m_mutex);
+            std::lock_guard<std::mutex> lk(mutex_);
 
-            m_state = Stopped;
-            m_condition.notify_one();
+            state_ = state::stopped;
+            condition_.notify_one();
         }
 
-        m_thread.join();
+        thread_.join();
     } catch (...) {
     }
 }
 
-void Timer::start()
+void timer::start()
 {
-    assert(m_state != Running);
+    assert(state_ != state::running);
 
     {
-        std::lock_guard<std::mutex> lk(m_mutex);
-        m_state = Running;
+        std::lock_guard<std::mutex> lk(mutex_);
+        state_ = state::running;
     }
 
-    m_condition.notify_one();
+    condition_.notify_one();
 }
 
-void Timer::stop()
+void timer::stop()
 {
     {
-        std::lock_guard<std::mutex> lk(m_mutex);
-        m_state = Paused;
+        std::lock_guard<std::mutex> lk(mutex_);
+        state_ = state::paused;
     }
 
-    m_condition.notify_one();
+    condition_.notify_one();
 }
 
 } // !irccd
--- a/libirccd-js/irccd/timer.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-js/irccd/timer.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -36,15 +36,6 @@
 namespace irccd {
 
 /**
- * \enum TimerType
- * \brief Type of timer
- */
-enum class TimerType {
-    Single,             //!< The timer ends after execution
-    Repeat              //!< The timer loops
-};
-
-/**
  * \brief Timer class
  *
  * A timer is a thread object that emits a signal periodically or just one time. It is perfectly pausable and resumable
@@ -56,15 +47,23 @@
  * We use a condition variable to wait for the specified delay unless the timer
  * must be stopped.
  */
-class Timer {
+class timer {
 public:
     /**
+     * \brief Type of timer
+     */
+    enum class type {
+        single,             //!< The timer ends after execution
+        repeat              //!< The timer loops
+    };
+
+    /**
      * Signal: onSignal
      * ----------------------------------------------------------
      *
      * Called when the timeout expires.
      */
-    Signal<> onSignal;
+    Signal<> on_signal;
 
     /**
      * Signal: onEnd
@@ -72,23 +71,23 @@
      *
      * Called when the timeout ends.
      */
-    Signal<> onEnd;
+    Signal<> on_end;
 
 private:
-    enum {
-        Paused,
-        Running,
-        Stopped
+    enum class state {
+        paused,
+        running,
+        stopped
     };
 
-    TimerType m_type;
-    unsigned m_delay;
+    type type_;
+    unsigned delay_;
 
     // Thread management.
-    std::atomic<int> m_state{Paused};
-    std::mutex m_mutex;
-    std::condition_variable m_condition;
-    std::thread m_thread;
+    std::atomic<state> state_{state::paused};
+    std::mutex mutex_;
+    std::condition_variable condition_;
+    std::thread thread_;
 
     void run();
 
@@ -102,14 +101,14 @@
      * \param delay the delay in milliseconds
      * \post isRunning() returns false
      */
-    IRCCD_EXPORT Timer(TimerType type, unsigned delay) noexcept;
+    timer(type type, unsigned delay) noexcept;
 
     /**
      * Destructor, closes the thread.
      *
      * \pre stop() must have been called.
      */
-    IRCCD_EXPORT virtual ~Timer();
+    virtual ~timer();
 
     /**
      * Start the thread.
@@ -119,23 +118,23 @@
      * \pre onEnd() must have been called
      * \note Thread-safe
      */
-    IRCCD_EXPORT void start();
+    void start();
 
     /**
      * Stop the timer, may be used by the user to stop it.
      *
      * \note Thread-safe
      */
-    IRCCD_EXPORT void stop();
+    void stop();
 
     /**
      * Get the type of timer.
      *
      * \return the type.
      */
-    inline TimerType type() const noexcept
+    inline type get_type() const noexcept
     {
-        return m_type;
+        return type_;
     }
 
     /**
@@ -144,9 +143,9 @@
      * \return true if still alive
      * \note Thread-safe
      */
-    inline bool isRunning() const noexcept
+    inline bool is_running() const noexcept
     {
-        return m_state == Running;
+        return state_ == state::running;
     }
 };
 
--- a/libirccd-test/irccd/command-tester.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/command-tester.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -24,15 +24,15 @@
 
 namespace irccd {
 
-CommandTester::CommandTester(std::unique_ptr<Command> cmd,
-                             std::unique_ptr<Server> server)
+CommandTester::CommandTester(std::unique_ptr<command> cmd,
+                             std::unique_ptr<server> server)
     : m_irccdctl(std::make_unique<Client>())
 {
     // Be silent.
-    log::setLogger(std::make_unique<log::SilentLogger>());
-    log::setVerbose(false);
+    log::set_logger(std::make_unique<log::silent_logger>());
+    log::set_verbose(false);
 
-    auto tpt = std::make_unique<TransportServerIp>("*", 0);
+    auto tpt = std::make_unique<transport_server_ip>("*", 0);
     auto port = tpt->port();
 
     m_irccd.transports().add(std::move(tpt));
--- a/libirccd-test/irccd/command-tester.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/command-tester.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -28,18 +28,17 @@
 
 namespace irccd {
 
-class Command;
-class Server;
+class command;
+class server;
 
 class CommandTester : public testing::Test {
 protected:
-    Irccd m_irccd;
+    irccd m_irccd;
     Irccdctl m_irccdctl;
 
 public:
-    CommandTester(std::unique_ptr<Command> cmd = nullptr,
-                  std::unique_ptr<Server> server = nullptr);
-
+    CommandTester(std::unique_ptr<command> cmd = nullptr,
+                  std::unique_ptr<server> server = nullptr);
 
     template <typename Predicate>
     void poll(Predicate &&predicate)
--- a/libirccd-test/irccd/plugin-tester.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/plugin-tester.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,18 +16,18 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "mod-directory.hpp"
-#include "mod-elapsed-timer.hpp"
-#include "mod-file.hpp"
-#include "mod-irccd.hpp"
-#include "mod-logger.hpp"
-#include "mod-plugin.hpp"
-#include "mod-server.hpp"
-#include "mod-system.hpp"
-#include "mod-timer.hpp"
-#include "mod-unicode.hpp"
-#include "mod-util.hpp"
-#include "plugin-js.hpp"
+#include "js_directory_module.hpp"
+#include "js_elapsed_timer_module.hpp"
+#include "js_file_module.hpp"
+#include "js_irccd_module.hpp"
+#include "js_logger_module.hpp"
+#include "js_plugin_module.hpp"
+#include "js_server_module.hpp"
+#include "js_system_module.hpp"
+#include "js_timer_module.hpp"
+#include "js_unicode_module.hpp"
+#include "js_util_module.hpp"
+#include "js_plugin.hpp"
 #include "plugin-tester.hpp"
 #include "service.hpp"
 
@@ -35,21 +35,21 @@
 
 PluginTester::PluginTester()
 {
-    auto loader = std::make_unique<JsPluginLoader>(m_irccd);
+    auto loader = std::make_unique<js_plugin_loader>(m_irccd);
 
-    loader->addModule(std::make_unique<IrccdModule>());
-    loader->addModule(std::make_unique<DirectoryModule>());
-    loader->addModule(std::make_unique<ElapsedTimerModule>());
-    loader->addModule(std::make_unique<FileModule>());
-    loader->addModule(std::make_unique<LoggerModule>());
-    loader->addModule(std::make_unique<PluginModule>());
-    loader->addModule(std::make_unique<ServerModule>());
-    loader->addModule(std::make_unique<SystemModule>());
-    loader->addModule(std::make_unique<TimerModule>());
-    loader->addModule(std::make_unique<UnicodeModule>());
-    loader->addModule(std::make_unique<UtilModule>());
+    loader->add_module(std::make_unique<js_irccd_module>());
+    loader->add_module(std::make_unique<js_directory_module>());
+    loader->add_module(std::make_unique<js_elapsed_timer_module>());
+    loader->add_module(std::make_unique<js_file_module>());
+    loader->add_module(std::make_unique<js_logger_module>());
+    loader->add_module(std::make_unique<js_plugin_module>());
+    loader->add_module(std::make_unique<js_server_module>());
+    loader->add_module(std::make_unique<js_system_module>());
+    loader->add_module(std::make_unique<js_timer_module>());
+    loader->add_module(std::make_unique<js_unicode_module>());
+    loader->add_module(std::make_unique<js_util_module>());
 
-    m_irccd.plugins().addLoader(std::move(loader));
+    m_irccd.plugins().add_loader(std::move(loader));
 }
 
 } // !irccd
--- a/libirccd-test/irccd/plugin-tester.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/plugin-tester.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -27,7 +27,7 @@
 
 class PluginTester : public testing::Test {
 protected:
-    Irccd m_irccd;
+    irccd m_irccd;
 
 public:
     PluginTester();
--- a/libirccd-test/irccd/plugin_test.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/plugin_test.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,18 +16,18 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <irccd/mod-directory.hpp>
-#include <irccd/mod-elapsed-timer.hpp>
-#include <irccd/mod-file.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-logger.hpp>
-#include <irccd/mod-plugin.hpp>
-#include <irccd/mod-server.hpp>
-#include <irccd/mod-system.hpp>
-#include <irccd/mod-timer.hpp>
-#include <irccd/mod-unicode.hpp>
-#include <irccd/mod-util.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_directory_module.hpp>
+#include <irccd/js_elapsed_timer_module.hpp>
+#include <irccd/js_file_module.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_logger_module.hpp>
+#include <irccd/js_plugin_module.hpp>
+#include <irccd/js_server_module.hpp>
+#include <irccd/js_system_module.hpp>
+#include <irccd/js_timer_module.hpp>
+#include <irccd/js_unicode_module.hpp>
+#include <irccd/js_util_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 
 #include "plugin_test.hpp"
@@ -36,19 +36,19 @@
 
 plugin_test::plugin_test(std::string name, std::string path)
 {
-    JsPluginLoader loader(irccd_);
+    js_plugin_loader loader(irccd_);
 
-    loader.addModule(std::make_unique<IrccdModule>());
-    loader.addModule(std::make_unique<DirectoryModule>());
-    loader.addModule(std::make_unique<ElapsedTimerModule>());
-    loader.addModule(std::make_unique<FileModule>());
-    loader.addModule(std::make_unique<LoggerModule>());
-    loader.addModule(std::make_unique<PluginModule>());
-    loader.addModule(std::make_unique<ServerModule>());
-    loader.addModule(std::make_unique<SystemModule>());
-    loader.addModule(std::make_unique<TimerModule>());
-    loader.addModule(std::make_unique<UnicodeModule>());
-    loader.addModule(std::make_unique<UtilModule>());
+    loader.add_module(std::make_unique<js_irccd_module>());
+    loader.add_module(std::make_unique<js_directory_module>());
+    loader.add_module(std::make_unique<js_elapsed_timer_module>());
+    loader.add_module(std::make_unique<js_file_module>());
+    loader.add_module(std::make_unique<js_logger_module>());
+    loader.add_module(std::make_unique<js_plugin_module>());
+    loader.add_module(std::make_unique<js_server_module>());
+    loader.add_module(std::make_unique<js_system_module>());
+    loader.add_module(std::make_unique<js_timer_module>());
+    loader.add_module(std::make_unique<js_unicode_module>());
+    loader.add_module(std::make_unique<js_util_module>());
 
     plugin_ = loader.open(name, path);
     irccd_.plugins().add(plugin_);
--- a/libirccd-test/irccd/server-tester.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/server-tester.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,7 @@
 namespace irccd {
 
 ServerTester::ServerTester(std::string name)
-    : Server(std::move(name))
+    : server(std::move(name))
 {
 }
 
--- a/libirccd-test/irccd/server-tester.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd-test/irccd/server-tester.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -32,7 +32,7 @@
 /**
  * \brief Useless server for testing purpose.
  */
-class IRCCD_EXPORT ServerTester : public Server {
+class IRCCD_EXPORT ServerTester : public server {
 public:
     /**
      * Create a server with named 'test' by default.
--- a/libirccd/CMakeLists.txt	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/CMakeLists.txt	Tue Sep 26 17:18:47 2017 +0200
@@ -22,9 +22,7 @@
     HEADERS
     ${libirccd_SOURCE_DIR}/irccd/command.hpp
     ${libirccd_SOURCE_DIR}/irccd/config.hpp
-    ${libirccd_SOURCE_DIR}/irccd/dynlib.hpp
     ${libirccd_SOURCE_DIR}/irccd/irccd.hpp
-    ${libirccd_SOURCE_DIR}/irccd/plugin-dynlib.hpp
     ${libirccd_SOURCE_DIR}/irccd/plugin.hpp
     ${libirccd_SOURCE_DIR}/irccd/rule.hpp
     ${libirccd_SOURCE_DIR}/irccd/server.hpp
@@ -38,7 +36,6 @@
     ${libirccd_SOURCE_DIR}/irccd/config.cpp
     ${libirccd_SOURCE_DIR}/irccd/irccd.cpp
     ${libirccd_SOURCE_DIR}/irccd/plugin.cpp
-    ${libirccd_SOURCE_DIR}/irccd/plugin-dynlib.cpp
     ${libirccd_SOURCE_DIR}/irccd/rule.cpp
     ${libirccd_SOURCE_DIR}/irccd/server.cpp
     ${libirccd_SOURCE_DIR}/irccd/service.cpp
--- a/libirccd/irccd/command.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/command.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -26,11 +26,9 @@
 
 namespace irccd {
 
-namespace command {
-
 namespace {
 
-void execSet(Irccd &, TransportClient &client, Plugin &plugin, const nlohmann::json &args)
+void exec_set(transport_client& client, plugin& plugin, const nlohmann::json& args)
 {
     assert(args.count("value") > 0);
 
@@ -45,12 +43,12 @@
         auto config = plugin.config();
 
         config[*var] = *value;
-        plugin.setConfig(config);
+        plugin.set_config(config);
         client.success("plugin-config");
     }
 }
 
-void execGet(Irccd &, TransportClient &client, Plugin &plugin, const nlohmann::json &args)
+void exec_get(transport_client& client, plugin& plugin, const nlohmann::json& args)
 {
     auto variables = nlohmann::json::object();
     auto var = args.find("variable");
@@ -58,7 +56,7 @@
     if (var != args.end() && var->is_string())
         variables[var->get<std::string>()] = plugin.config()[*var];
     else
-        for (const auto &pair : plugin.config())
+        for (const auto& pair : plugin.config())
             variables[pair.first] = pair.second;
 
     /*
@@ -72,19 +70,19 @@
     });
 }
 
-nlohmann::json toJson(const Rule &rule)
+nlohmann::json to_json(const rule& rule)
 {
-    auto join = [] (const auto &set) {
+    auto join = [] (const auto& set) {
         auto array = nlohmann::json::array();
 
-        for (const auto &entry : set)
+        for (const auto& entry : set)
             array.push_back(entry);
 
         return array;
     };
     auto str = [] (auto action) {
         switch (action) {
-        case RuleAction::Accept:
+        case rule::action_type::accept:
             return "accept";
         default:
             return "drop";
@@ -100,18 +98,18 @@
     };
 }
 
-Rule fromJson(const nlohmann::json &json)
+rule from_json(const nlohmann::json& json)
 {
-    auto toset = [] (auto object, auto name) -> RuleSet {
-        RuleSet result;
+    auto toset = [] (auto object, auto name) {
+        rule::set result;
 
-        for (const auto &s : object[name])
+        for (const auto& s : object[name])
             if (s.is_string())
                 result.insert(s.template get<std::string>());
 
         return result;
     };
-    auto toaction = [] (auto object, auto name) -> RuleAction {
+    auto toaction = [] (auto object, auto name) {
         auto v = object[name];
 
         if (!v.is_string())
@@ -119,9 +117,9 @@
 
         auto s = v.template get<std::string>();
         if (s == "accept")
-            return RuleAction::Accept;
+            return rule::action_type::accept;
         if (s == "drop")
-            return RuleAction::Drop;
+            return rule::action_type::drop;
 
         throw std::runtime_error("unknown action '"s + s + "' given");
     };
@@ -138,30 +136,29 @@
 
 } // !namespace
 
-PluginConfigCommand::PluginConfigCommand()
-    : Command("plugin-config")
+plugin_config_command::plugin_config_command()
+    : command("plugin-config")
 {
 }
 
-void PluginConfigCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void plugin_config_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    auto plugin = irccd.plugins().require(util::json::requireIdentifier(args, "plugin"));
+    auto plugin = irccd.plugins().require(util::json::require_identifier(args, "plugin"));
 
     if (args.count("value") > 0)
-        execSet(irccd, client, *plugin, args);
+        exec_set(client, *plugin, args);
     else
-        execGet(irccd, client, *plugin, args);
+        exec_get(client, *plugin, args);
 }
 
-
-PluginInfoCommand::PluginInfoCommand()
-    : Command("plugin-info")
+plugin_info_command::plugin_info_command()
+    : command("plugin-info")
 {
 }
 
-void PluginInfoCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void plugin_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    auto plugin = irccd.plugins().require(util::json::requireIdentifier(args, "plugin"));
+    auto plugin = irccd.plugins().require(util::json::require_identifier(args, "plugin"));
 
     client.success("plugin-info", {
         { "author",     plugin->author()    },
@@ -171,16 +168,16 @@
     });
 }
 
-PluginListCommand::PluginListCommand()
-    : Command("plugin-list")
+plugin_list_command::plugin_list_command()
+    : command("plugin-list")
 {
 }
 
-void PluginListCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &)
+void plugin_list_command::exec(irccd& irccd, transport_client& client, const nlohmann::json&)
 {
     auto list = nlohmann::json::array();
 
-    for (const auto &plugin : irccd.plugins().list())
+    for (const auto& plugin : irccd.plugins().list())
         list += plugin->name();
 
     client.success("plugin-list", {
@@ -188,75 +185,75 @@
     });
 }
 
-PluginLoadCommand::PluginLoadCommand()
-    : Command("plugin-load")
+plugin_load_command::plugin_load_command()
+    : command("plugin-load")
 {
 }
 
-void PluginLoadCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void plugin_load_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.plugins().load(util::json::requireIdentifier(args, "plugin"));
+    irccd.plugins().load(util::json::require_identifier(args, "plugin"));
     client.success("plugin-load");
 }
 
-PluginReloadCommand::PluginReloadCommand()
-    : Command("plugin-reload")
+plugin_reload_command::plugin_reload_command()
+    : command("plugin-reload")
 {
 }
 
-void PluginReloadCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void plugin_reload_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.plugins().require(util::json::requireIdentifier(args, "plugin"))->onReload(irccd);
+    irccd.plugins().require(util::json::require_identifier(args, "plugin"))->on_reload(irccd);
     client.success("plugin-reload");
 }
 
-PluginUnloadCommand::PluginUnloadCommand()
-    : Command("plugin-unload")
+plugin_unload_command::plugin_unload_command()
+    : command("plugin-unload")
 {
 }
 
-void PluginUnloadCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void plugin_unload_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.plugins().unload(util::json::requireIdentifier(args, "plugin"));
+    irccd.plugins().unload(util::json::require_identifier(args, "plugin"));
     client.success("plugin-unload");
 }
 
-ServerChannelModeCommand::ServerChannelModeCommand()
-    : Command("server-cmode")
+server_channel_mode_command::server_channel_mode_command()
+    : command("server-cmode")
 {
 }
 
-void ServerChannelModeCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_channel_mode_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->cmode(
-        util::json::requireString(args, "channel"),
-        util::json::requireString(args, "mode")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->cmode(
+        util::json::require_string(args, "channel"),
+        util::json::require_string(args, "mode")
     );
     client.success("server-cmode");
 }
 
-ServerChannelNoticeCommand::ServerChannelNoticeCommand()
-    : Command("server-cnotice")
+server_channel_notice_command::server_channel_notice_command()
+    : command("server-cnotice")
 {
 }
 
-void ServerChannelNoticeCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_channel_notice_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireString(args, "server"))->cnotice(
-        util::json::requireString(args, "channel"),
-        util::json::requireString(args, "message")
+    irccd.servers().require(util::json::require_string(args, "server"))->cnotice(
+        util::json::require_string(args, "channel"),
+        util::json::require_string(args, "message")
     );
     client.success("server-cnotice");
 }
 
-ServerConnectCommand::ServerConnectCommand()
-    : Command("server-connect")
+server_connect_command::server_connect_command()
+    : command("server-connect")
 {
 }
 
-void ServerConnectCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_connect_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    auto server = Server::fromJson(args);
+    auto server = server::from_json(args);
 
     if (irccd.servers().has(server->name()))
         client.error("server-connect", "server already exists");
@@ -266,12 +263,12 @@
     }
 }
 
-ServerDisconnectCommand::ServerDisconnectCommand()
-    : Command("server-disconnect")
+server_disconnect_command::server_disconnect_command()
+    : command("server-disconnect")
 {
 }
 
-void ServerDisconnectCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_disconnect_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
     auto it = args.find("server");
 
@@ -283,15 +280,15 @@
     client.success("server-disconnect");
 }
 
-ServerInfoCommand::ServerInfoCommand()
-    : Command("server-info")
+server_info_command::server_info_command()
+    : command("server-info")
 {
 }
 
-void ServerInfoCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
     auto response = nlohmann::json::object();
-    auto server = irccd.servers().require(util::json::requireIdentifier(args, "server"));
+    auto server = irccd.servers().require(util::json::require_identifier(args, "server"));
 
     // General stuff.
     response.push_back({"name", server->name()});
@@ -303,210 +300,210 @@
     response.push_back({"channels", server->channels()});
 
     // Optional stuff.
-    if (server->flags() & Server::Ipv6)
+    if (server->flags() & server::ipv6)
         response.push_back({"ipv6", true});
-    if (server->flags() & Server::Ssl)
+    if (server->flags() & server::ssl)
         response.push_back({"ssl", true});
-    if (server->flags() & Server::SslVerify)
+    if (server->flags() & server::ssl_verify)
         response.push_back({"sslVerify", true});
 
     client.success("server-info", response);
 }
 
-ServerInviteCommand::ServerInviteCommand()
-    : Command("server-invite")
+server_invite_command::server_invite_command()
+    : command("server-invite")
 {
 }
 
-void ServerInviteCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_invite_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->invite(
-        util::json::requireString(args, "target"),
-        util::json::requireString(args, "channel")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->invite(
+        util::json::require_string(args, "target"),
+        util::json::require_string(args, "channel")
     );
     client.success("server-invite");
 }
 
-ServerJoinCommand::ServerJoinCommand()
-    : Command("server-join")
+server_join_command::server_join_command()
+    : command("server-join")
 {
 }
 
-void ServerJoinCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_join_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->join(
-        util::json::requireString(args, "channel"),
-        util::json::getString(args, "password")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->join(
+        util::json::require_string(args, "channel"),
+        util::json::get_string(args, "password")
     );
     client.success("server-join");
 }
 
-ServerKickCommand::ServerKickCommand()
-    : Command("server-kick")
+server_kick_command::server_kick_command()
+    : command("server-kick")
 {
 }
 
-void ServerKickCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_kick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->kick(
-        util::json::requireString(args, "target"),
-        util::json::requireString(args, "channel"),
-        util::json::getString(args, "reason")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->kick(
+        util::json::require_string(args, "target"),
+        util::json::require_string(args, "channel"),
+        util::json::get_string(args, "reason")
     );
     client.success("server-kick");
 }
 
-ServerListCommand::ServerListCommand()
-    : Command("server-list")
+server_list_command::server_list_command()
+    : command("server-list")
 {
 }
 
-void ServerListCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &)
+void server_list_command::exec(irccd& irccd, transport_client& client, const nlohmann::json&)
 {
     auto json = nlohmann::json::object();
     auto list = nlohmann::json::array();
 
-    for (const auto &server : irccd.servers().servers())
+    for (const auto& server : irccd.servers().servers())
         list.push_back(server->name());
 
     json.push_back({"list", std::move(list)});
     client.success("server-list", json);
 }
 
-ServerMeCommand::ServerMeCommand()
-    : Command("server-me")
+server_me_command::server_me_command()
+    : command("server-me")
 {
 }
 
-void ServerMeCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_me_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->me(
-        util::json::requireString(args, "target"),
-        util::json::requireString(args, "message")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->me(
+        util::json::require_string(args, "target"),
+        util::json::require_string(args, "message")
     );
     client.success("server-me");
 }
 
-ServerMessageCommand::ServerMessageCommand()
-    : Command("server-message")
+server_message_command::server_message_command()
+    : command("server-message")
 {
 }
 
-void ServerMessageCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_message_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->message(
-        util::json::requireString(args, "target"),
-        util::json::requireString(args, "message")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->message(
+        util::json::require_string(args, "target"),
+        util::json::require_string(args, "message")
     );
     client.success("server-message");
 }
 
-ServerModeCommand::ServerModeCommand()
-    : Command("server-mode")
+server_mode_command::server_mode_command()
+    : command("server-mode")
 {
 }
 
-void ServerModeCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_mode_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->mode(
-        util::json::requireString(args, "mode")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->mode(
+        util::json::require_string(args, "mode")
     );
     client.success("server-mode");
 }
 
-ServerNickCommand::ServerNickCommand()
-    : Command("server-nick")
+server_nick_command::server_nick_command()
+    : command("server-nick")
 {
 }
 
-void ServerNickCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_nick_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->setNickname(
-        util::json::requireString(args, "nickname")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->set_nickname(
+        util::json::require_string(args, "nickname")
     );
     client.success("server-nick");
 }
 
-ServerNoticeCommand::ServerNoticeCommand()
-    : Command("server-notice")
+server_notice_command::server_notice_command()
+    : command("server-notice")
 {
 }
 
-void ServerNoticeCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_notice_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->notice(
-        util::json::requireString(args, "target"),
-        util::json::requireString(args, "message")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->notice(
+        util::json::require_string(args, "target"),
+        util::json::require_string(args, "message")
     );
     client.success("server-notice");
 }
 
-ServerPartCommand::ServerPartCommand()
-    : Command("server-part")
+server_part_command::server_part_command()
+    : command("server-part")
 {
 }
 
-void ServerPartCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_part_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->part(
-        util::json::requireString(args, "channel"),
-        util::json::getString(args, "reason")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->part(
+        util::json::require_string(args, "channel"),
+        util::json::get_string(args, "reason")
     );
     client.success("server-part");
 }
 
-ServerReconnectCommand::ServerReconnectCommand()
-    : Command("server-reconnect")
+server_reconnect_command::server_reconnect_command()
+    : command("server-reconnect")
 {
 }
 
-void ServerReconnectCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_reconnect_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
     auto server = args.find("server");
 
     if (server != args.end() && server->is_string())
         irccd.servers().require(*server)->reconnect();
     else
-        for (auto &server : irccd.servers().servers())
+        for (auto& server : irccd.servers().servers())
             server->reconnect();
 
     client.success("server-reconnect");
 }
 
-ServerTopicCommand::ServerTopicCommand()
-    : Command("server-topic")
+server_topic_command::server_topic_command()
+    : command("server-topic")
 {
 }
 
-void ServerTopicCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void server_topic_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    irccd.servers().require(util::json::requireIdentifier(args, "server"))->topic(
-        util::json::requireString(args, "channel"),
-        util::json::requireString(args, "topic")
+    irccd.servers().require(util::json::require_identifier(args, "server"))->topic(
+        util::json::require_string(args, "channel"),
+        util::json::require_string(args, "topic")
     );
     client.success("server-topic");
 }
 
-RuleEditCommand::RuleEditCommand()
-    : Command("rule-edit")
+rule_edit_command::rule_edit_command()
+    : command("rule-edit")
 {
 }
 
-void RuleEditCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void rule_edit_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    static const auto updateset = [] (auto &set, auto args, const auto &key) {
-        for (const auto &v : args["remove-"s + key]) {
+    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]) {
+        for (const auto& v : args["add-"s + key]) {
             if (v.is_string())
                 set.insert(v.template get<std::string>());
         }
     };
 
     // Create a copy to avoid incomplete edition in case of errors.
-    auto index = util::json::requireUint(args, "index");
+    auto index = util::json::require_uint(args, "index");
     auto rule = irccd.rules().require(index);
 
     updateset(rule.channels(), args, "channels");
@@ -523,9 +520,9 @@
         }
 
         if (action->get<std::string>() == "accept")
-            rule.setAction(RuleAction::Accept);
+            rule.set_action(rule::action_type::accept);
         else if (action->get<std::string>() == "drop")
-            rule.setAction(RuleAction::Drop);
+            rule.set_action(rule::action_type::drop);
         else {
             client.error("rule-edit", "invalid action '"s + action->get<std::string>() + "'");
             return;
@@ -537,39 +534,39 @@
     client.success("rule-edit");
 }
 
-RuleListCommand::RuleListCommand()
-    : Command("rule-list")
+rule_list_command::rule_list_command()
+    : command("rule-list")
 {
 }
 
-void RuleListCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &)
+void rule_list_command::exec(irccd& irccd, transport_client& client, const nlohmann::json&)
 {
     auto array = nlohmann::json::array();
 
     for (const auto& rule : irccd.rules().list())
-        array.push_back(toJson(rule));
+        array.push_back(to_json(rule));
 
     client.success("rule-list", {{ "list", std::move(array) }});
 }
 
-RuleInfoCommand::RuleInfoCommand()
-    : Command("rule-info")
+rule_info_command::rule_info_command()
+    : command("rule-info")
 {
 }
 
-void RuleInfoCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void rule_info_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    client.success("rule-info", toJson(irccd.rules().require(util::json::requireUint(args, "index"))));
+    client.success("rule-info", to_json(irccd.rules().require(util::json::require_uint(args, "index"))));
 }
 
-RuleRemoveCommand::RuleRemoveCommand()
-    : Command("rule-remove")
+rule_remove_command::rule_remove_command()
+    : command("rule-remove")
 {
 }
 
-void RuleRemoveCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void rule_remove_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    unsigned position = util::json::requireUint(args, "index");
+    unsigned position = util::json::require_uint(args, "index");
 
     if (irccd.rules().length() == 0)
         client.error("rule-remove", "rule list is empty");
@@ -581,15 +578,15 @@
     }
 }
 
-RuleMoveCommand::RuleMoveCommand()
-    : Command("rule-move")
+rule_move_command::rule_move_command()
+    : command("rule-move")
 {
 }
 
-void RuleMoveCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void rule_move_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    auto from = util::json::requireUint(args, "from");
-    auto to = util::json::requireUint(args, "to");
+    auto from = util::json::require_uint(args, "from");
+    auto to = util::json::require_uint(args, "to");
 
     /*
      * Examples of moves
@@ -635,15 +632,15 @@
     }
 }
 
-RuleAddCommand::RuleAddCommand()
-    : Command("rule-add")
+rule_add_command::rule_add_command()
+    : command("rule-add")
 {
 }
 
-void RuleAddCommand::exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args)
+void rule_add_command::exec(irccd& irccd, transport_client& client, const nlohmann::json& args)
 {
-    auto index = util::json::getUint(args, "index", irccd.rules().length());
-    auto rule = fromJson(args);
+    auto index = util::json::get_uint(args, "index", irccd.rules().length());
+    auto rule = from_json(args);
 
     if (index > irccd.rules().length())
         client.error("rule-add", "index is out of range");
@@ -653,6 +650,4 @@
     }
 }
 
-} // !command
-
 } // !irccd
--- a/libirccd/irccd/command.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/command.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -33,16 +33,16 @@
 
 namespace irccd {
 
-class Irccd;
-class Irccdctl;
-class TransportClient;
+class irccd;
+class irccdctl;
+class transport_client;
 
 /**
  * \brief Server side remote command
  */
-class Command {
+class command {
 private:
-    std::string m_name;
+    std::string name_;
 
 public:
     /**
@@ -51,25 +51,25 @@
      * \pre !name.empty()
      * \param name the command name
      */
-    inline Command(std::string name) noexcept
-        : m_name(std::move(name))
+    inline command(std::string name) noexcept
+        : name_(std::move(name))
     {
-        assert(!m_name.empty());
+        assert(!name_.empty());
     }
 
     /**
      * Default destructor virtual.
      */
-    virtual ~Command() = default;
+    virtual ~command() = default;
 
     /**
      * Return the command name, must not have spaces.
      *
      * \return the command name
      */
-    inline const std::string &name() const noexcept
+    inline const std::string& name() const noexcept
     {
-        return m_name;
+        return name_;
     }
 
     /**
@@ -85,474 +85,473 @@
      * \param client the client
      * \param args the client arguments
      */
-    IRCCD_EXPORT virtual void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) = 0;
+    virtual void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) = 0;
 };
 
-namespace command {
-
 /**
  * \brief Implementation of plugin-config transport command.
  */
-class PluginConfigCommand : public Command {
+class plugin_config_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT PluginConfigCommand();
+    plugin_config_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of plugin-info transport command.
  */
-class PluginInfoCommand : public Command {
+class plugin_info_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT PluginInfoCommand();
+    plugin_info_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of plugin-list transport command.
  */
-class PluginListCommand : public Command {
+class plugin_list_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT PluginListCommand();
+    plugin_list_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &request) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& request) override;
 };
 
 /**
  * \brief Implementation of plugin-load transport command.
  */
-class PluginLoadCommand : public Command {
+class plugin_load_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT PluginLoadCommand();
+    plugin_load_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of plugin-reload transport command.
  */
-class PluginReloadCommand : public Command {
+class plugin_reload_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT PluginReloadCommand();
+    plugin_reload_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of plugin-unload transport command.
  */
-class PluginUnloadCommand : public Command {
+class plugin_unload_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT PluginUnloadCommand();
+    plugin_unload_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-cmode transport command.
  */
-class ServerChannelModeCommand : public Command {
+class server_channel_mode_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerChannelModeCommand();
+    server_channel_mode_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-cnotice transport command.
  */
-class ServerChannelNoticeCommand : public Command {
+class server_channel_notice_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerChannelNoticeCommand();
+    server_channel_notice_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-connect transport command.
  */
-class ServerConnectCommand : public Command {
+class server_connect_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerConnectCommand();
+    server_connect_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-disconnect transport command.
  */
-class IRCCD_EXPORT ServerDisconnectCommand : public Command {
+class server_disconnect_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerDisconnectCommand();
+    server_disconnect_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-info transport command.
  */
-class IRCCD_EXPORT ServerInfoCommand : public Command {
+class server_info_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerInfoCommand();
+    server_info_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-invite transport command.
  */
-class ServerInviteCommand : public Command {
+class server_invite_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerInviteCommand();
+    server_invite_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-join transport command.
  */
-class ServerJoinCommand : public Command {
+class server_join_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerJoinCommand();
+    server_join_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-kick transport command.
  */
-class ServerKickCommand : public Command {
+class server_kick_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerKickCommand();
+    server_kick_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-list transport command.
  */
-class ServerListCommand : public Command {
+class server_list_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerListCommand();
+    server_list_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-me transport command.
  */
-class IRCCD_EXPORT ServerMeCommand : public Command {
+class server_me_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerMeCommand();
+    server_me_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-message transport command.
  */
-class IRCCD_EXPORT ServerMessageCommand : public Command {
+class server_message_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerMessageCommand();
+    server_message_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-mode transport command.
  */
-class IRCCD_EXPORT ServerModeCommand : public Command {
+class server_mode_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerModeCommand();
+    server_mode_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-nick transport command.
  */
-class IRCCD_EXPORT ServerNickCommand : public Command {
+class server_nick_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerNickCommand();
+    server_nick_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-notice transport command.
  */
-class IRCCD_EXPORT ServerNoticeCommand : public Command {
+class server_notice_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerNoticeCommand();
+    server_notice_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-part transport command.
  */
-class IRCCD_EXPORT ServerPartCommand : public Command {
+class server_part_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerPartCommand();
+    server_part_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-reconnect transport command.
  */
-class ServerReconnectCommand : public Command {
+class server_reconnect_command : public command {
 public:
     /**
      * Constructor.
      */
-    IRCCD_EXPORT ServerReconnectCommand();
+    server_reconnect_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    IRCCD_EXPORT void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of server-topic transport command.
  */
-class IRCCD_EXPORT ServerTopicCommand : public Command {
+class server_topic_command : public command {
 public:
     /**
      * Constructor.
      */
-    ServerTopicCommand();
+    server_topic_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
-class IRCCD_EXPORT RuleEditCommand : public Command {
+/**
+ * \brief Implementation of rule-edit transport command.
+ */
+class rule_edit_command : public command {
 public:
     /**
      * Constructor.
      */
-    RuleEditCommand();
+    rule_edit_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of rule-list transport command.
  */
-class IRCCD_EXPORT RuleListCommand : public Command {
+class rule_list_command : public command {
 public:
     /**
      * Constructor.
      */
-    RuleListCommand();
+    rule_list_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of rule-info transport command.
  */
-class IRCCD_EXPORT RuleInfoCommand : public Command {
+class rule_info_command : public command {
 public:
     /**
      * Constructor.
      */
-    RuleInfoCommand();
+    rule_info_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of rule-remove transport command.
  */
-class IRCCD_EXPORT RuleRemoveCommand : public Command {
+class rule_remove_command : public command {
 public:
     /**
      * Constructor.
      */
-    RuleRemoveCommand();
+    rule_remove_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of rule-move transport command.
  */
-class IRCCD_EXPORT RuleMoveCommand : public Command {
+class rule_move_command : public command {
 public:
     /**
      * Constructor.
      */
-    RuleMoveCommand();
+    rule_move_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
 /**
  * \brief Implementation of rule-add transport command.
  */
-class IRCCD_EXPORT RuleAddCommand : public Command {
+class rule_add_command : public command {
 public:
     /**
      * Constructor.
      */
-    RuleAddCommand();
+    rule_add_command();
 
     /**
-     * \copydoc Command::exec
+     * \copydoc command::exec
      */
-    void exec(Irccd &irccd, TransportClient &client, const nlohmann::json &args) override;
+    void exec(irccd& irccd, transport_client& client, const nlohmann::json& args) override;
 };
 
-} // !command
-
 } // !irccd
 
 #endif // !IRCCD_COMMAND_HPP
--- a/libirccd/irccd/config.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/config.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -41,43 +41,43 @@
 
 namespace {
 
-class IrccdLogFilter : public log::Filter {
+class irccd_log_filter : public log::filter {
 private:
-    std::string convert(const std::string &tmpl, std::string input) const
+    std::string convert(const std::string& tmpl, std::string input) const
     {
         if (tmpl.empty())
             return input;
 
-        util::Substitution params;
+        util::subst params;
 
-        params.flags &= ~(util::Substitution::IrcAttrs);
+        params.flags &= ~(util::subst_flags::irc_attrs);
         params.keywords.emplace("message", std::move(input));
 
         return util::format(tmpl, params);
     }
 
 public:
-    std::string m_debug;
-    std::string m_info;
-    std::string m_warning;
+    std::string debug_;
+    std::string info_;
+    std::string warning_;
 
-    std::string preDebug(std::string input) const override
+    std::string pre_debug(std::string input) const override
     {
-        return convert(m_debug, std::move(input));
+        return convert(debug_, std::move(input));
     }
 
-    std::string preInfo(std::string input) const override
+    std::string pre_info(std::string input) const override
     {
-        return convert(m_info, std::move(input));
+        return convert(info_, std::move(input));
     }
 
-    std::string preWarning(std::string input) const override
+    std::string pre_warning(std::string input) const override
     {
-        return convert(m_warning, std::move(input));
+        return convert(warning_, std::move(input));
     }
 };
 
-std::string get(const ini::Document &doc, const std::string &section, const std::string &key)
+std::string get(const ini::document& doc, const std::string& section, const std::string& key)
 {
     auto its = doc.find(section);
 
@@ -92,19 +92,19 @@
     return ito->value();
 }
 
-PluginConfig loadPluginConfig(const ini::Section &sc)
+plugin_config load_plugin_config(const ini::section& sc)
 {
-    PluginConfig config;
+    plugin_config config;
 
-    for (const auto &option : sc)
+    for (const auto& option : sc)
         config.emplace(option.key(), option.value());
 
     return config;
 }
 
-PluginPaths readPaths(const ini::Section& sc)
+plugin_paths read_paths(const ini::section& sc)
 {
-    PluginPaths paths;
+    plugin_paths paths;
 
     for (const auto& opt : sc)
         paths.emplace(opt.key(), opt.value());
@@ -112,7 +112,7 @@
     return paths;
 }
 
-std::unique_ptr<log::Logger> loadLogFile(const ini::Section &sc)
+std::unique_ptr<log::logger> load_log_file(const ini::section& sc)
 {
     /*
      * TODO: improve that with CMake options.
@@ -125,31 +125,31 @@
     std::string errors = "/var/log/irccd/errors.txt";
 #endif
 
-    ini::Section::const_iterator it;
+    ini::section::const_iterator it;
 
     if ((it = sc.find("path-logs")) != sc.end())
         normal = it->value();
     if ((it = sc.find("path-errors")) != sc.end())
         errors = it->value();
 
-    return std::make_unique<log::FileLogger>(std::move(normal), std::move(errors));
+    return std::make_unique<log::file_logger>(std::move(normal), std::move(errors));
 }
 
-std::unique_ptr<log::Logger> loadLogSyslog()
+std::unique_ptr<log::logger> load_log_syslog()
 {
 #if defined(HAVE_SYSLOG)
-    return std::make_unique<log::SyslogLogger>();
+    return std::make_unique<log::syslog_logger>();
 #else
     throw std::runtime_error("logs: syslog is not available on this platform");
 #endif // !HAVE_SYSLOG
 }
 
-std::shared_ptr<TransportServer> loadTransportIp(const ini::Section &sc)
+std::shared_ptr<transport_server> load_transport_ip(const ini::section& sc)
 {
     assert(sc.key() == "transport");
 
-    std::shared_ptr<TransportServer> transport;
-    ini::Section::const_iterator it;
+    std::shared_ptr<transport_server> transport;
+    ini::section::const_iterator it;
 
     // Port.
     int port;
@@ -158,8 +158,8 @@
         throw std::invalid_argument("transport: missing 'port' parameter");
 
     try {
-        port = util::toNumber<std::uint16_t>(it->value());
-    } catch (const std::exception &) {
+        port = util::to_number<std::uint16_t>(it->value());
+    } catch (const std::exception&) {
         throw std::invalid_argument("transport: invalid port number: {}"_format(it->value()));
     }
 
@@ -169,7 +169,7 @@
     if ((it = sc.find("address")) != sc.end())
         address = it->value();
 
-    std::uint8_t mode = TransportServerIp::v4;
+    std::uint8_t mode = transport_server_ip::v4;
 
     /*
      * Documentation stated family but code checked for 'domain' option.
@@ -181,11 +181,11 @@
     if ((it = sc.find("domain")) != sc.end() || (it = sc.find("family")) != sc.end()) {
         mode = 0;
 
-        for (const auto &v : *it) {
+        for (const auto& v : *it) {
             if (v == "ipv4")
-                mode |= TransportServerIp::v4;
+                mode |= transport_server_ip::v4;
             if (v == "ipv6")
-                mode |= TransportServerIp::v6;
+                mode |= transport_server_ip::v6;
         }
     }
 
@@ -193,7 +193,7 @@
     std::string pkey;
     std::string cert;
 
-    if ((it = sc.find("ssl")) != sc.end() && util::isBoolean(it->value())) {
+    if ((it = sc.find("ssl")) != sc.end() && util::is_boolean(it->value())) {
         if ((it = sc.find("certificate")) == sc.end())
             throw std::invalid_argument("transport: missing 'certificate' parameter");
 
@@ -209,26 +209,26 @@
         throw std::invalid_argument("transport: family must at least have ipv4 or ipv6");
 
     if (pkey.empty())
-        return std::make_shared<TransportServerIp>(address, port, mode);
+        return std::make_shared<transport_server_ip>(address, port, mode);
 
 #if defined(WITH_SSL)
-    return std::make_shared<TransportServerTls>(pkey, cert, address, port, mode);
+    return std::make_shared<transport_server_tls>(pkey, cert, address, port, mode);
 #else
     throw std::invalid_argument("transport: SSL disabled");
 #endif
 }
 
-std::shared_ptr<TransportServer> loadTransportUnix(const ini::Section &sc)
+std::shared_ptr<transport_server> load_transport_unix(const ini::section& sc)
 {
     assert(sc.key() == "transport");
 
 #if !defined(IRCCD_SYSTEM_WINDOWS)
-    ini::Section::const_iterator it = sc.find("path");
+    ini::section::const_iterator it = sc.find("path");
 
     if (it == sc.end())
         throw std::invalid_argument("transport: missing 'path' parameter");
 
-    return std::make_shared<TransportServerLocal>(it->value());
+    return std::make_shared<transport_server_local>(it->value());
 #else
     (void)sc;
 
@@ -236,120 +236,122 @@
 #endif
 }
 
-std::shared_ptr<TransportServer> loadTransport(const ini::Section &sc)
+std::shared_ptr<transport_server> load_transport(const ini::section& sc)
 {
     assert(sc.key() == "transport");
 
-    std::shared_ptr<TransportServer> transport;
-    ini::Section::const_iterator it = sc.find("type");
+    std::shared_ptr<transport_server> transport;
+    ini::section::const_iterator it = sc.find("type");
 
     if (it == sc.end())
         throw std::invalid_argument("transport: missing 'type' parameter");
 
     if (it->value() == "ip")
-        transport = loadTransportIp(sc);
+        transport = load_transport_ip(sc);
     else if (it->value() == "unix")
-        transport = loadTransportUnix(sc);
+        transport = load_transport_unix(sc);
     else
         throw std::invalid_argument("transport: invalid type given: {}"_format(it->value()));
 
     if ((it = sc.find("password")) != sc.end())
-        transport->setPassword(it->value());
+        transport->set_password(it->value());
 
     return transport;
 }
 
-Rule loadRule(const ini::Section &sc)
+rule load_rule(const ini::section& sc)
 {
     assert(sc.key() == "rule");
 
     // Simple converter from std::vector to std::unordered_set.
-    auto toSet = [] (const std::vector<std::string> &v) -> std::unordered_set<std::string> {
+    auto toset = [] (const auto& v) {
         return std::unordered_set<std::string>(v.begin(), v.end());
     };
 
-    RuleSet servers, channels, origins, plugins, events;
-    RuleAction action = RuleAction::Accept;
+    rule::set servers, channels, origins, plugins, events;
+    rule::action_type action = rule::action_type::accept;
 
     // Get the sets.
-    ini::Section::const_iterator it;
+    ini::section::const_iterator it;
 
     if ((it = sc.find("servers")) != sc.end())
-        servers = toSet(*it);
+        servers = toset(*it);
     if ((it = sc.find("channels")) != sc.end())
-        channels = toSet(*it);
+        channels = toset(*it);
     if ((it = sc.find("origins")) != sc.end())
-        origins = toSet(*it);
+        origins = toset(*it);
     if ((it = sc.find("plugins")) != sc.end())
-        plugins = toSet(*it);
+        plugins = toset(*it);
     if ((it = sc.find("channels")) != sc.end())
-        channels = toSet(*it);
+        channels = toset(*it);
 
     // Get the action.
     if ((it = sc.find("action")) == sc.end())
         throw std::invalid_argument("rule: missing 'action'' parameter");
 
     if (it->value() == "drop")
-        action = RuleAction::Drop;
+        action = rule::action_type::drop;
     else if (it->value() == "accept")
-        action = RuleAction::Accept;
+        action = rule::action_type::accept;
     else
         throw std::invalid_argument("rule: invalid action given: {}"_format(it->value()));
 
-    return Rule(std::move(servers),
-            std::move(channels),
-            std::move(origins),
-            std::move(plugins),
-            std::move(events),
-            action);
+    return {
+        std::move(servers),
+        std::move(channels),
+        std::move(origins),
+        std::move(plugins),
+        std::move(events),
+        action
+    };
 }
 
-std::shared_ptr<Server> loadServer(const ini::Section &sc, const Config &config)
+std::shared_ptr<server> load_server(const ini::section& sc, const config& config)
 {
     assert(sc.key() == "server");
 
     // Name.
-    ini::Section::const_iterator it;
+    ini::section::const_iterator it;
 
     if ((it = sc.find("name")) == sc.end())
         throw std::invalid_argument("server: missing 'name' parameter");
-    else if (!util::isIdentifierValid(it->value()))
+    else if (!util::is_identifier(it->value()))
         throw std::invalid_argument("server: invalid identifier: {}"_format(it->value()));
 
-    auto server = std::make_shared<Server>(it->value());
+    auto sv = std::make_shared<server>(it->value());
 
     // Host
     if ((it = sc.find("host")) == sc.end())
-        throw std::invalid_argument("server {}: missing host"_format(server->name()));
+        throw std::invalid_argument("server {}: missing host"_format(sv->name()));
 
-    server->setHost(it->value());
+    sv->set_host(it->value());
 
     // Optional password
     if ((it = sc.find("password")) != sc.end())
-        server->setPassword(it->value());
+        sv->set_password(it->value());
 
     // Optional flags
-    if ((it = sc.find("ipv6")) != sc.end() && util::isBoolean(it->value()))
-        server->setFlags(server->flags() | Server::Ipv6);
-    if ((it = sc.find("ssl")) != sc.end() && util::isBoolean(it->value()))
-        server->setFlags(server->flags() | Server::Ssl);
-    if ((it = sc.find("ssl-verify")) != sc.end() && util::isBoolean(it->value()))
-        server->setFlags(server->flags() | Server::SslVerify);
+    if ((it = sc.find("ipv6")) != sc.end() && util::is_boolean(it->value()))
+        sv->set_flags(sv->flags() | server::ipv6);
+    if ((it = sc.find("ssl")) != sc.end() && util::is_boolean(it->value()))
+        sv->set_flags(sv->flags() | server::ssl);
+    if ((it = sc.find("ssl-verify")) != sc.end() && util::is_boolean(it->value()))
+        sv->set_flags(sv->flags() | server::ssl_verify);
 
     // Optional identity
     if ((it = sc.find("identity")) != sc.end())
-        config.loadServerIdentity(*server, it->value());
+        config.load_server_identity(*sv, it->value());
 
     // Options
-    if ((it = sc.find("auto-rejoin")) != sc.end() && util::isBoolean(it->value()))
-        server->setFlags(server->flags() | Server::AutoRejoin);
-    if ((it = sc.find("join-invite")) != sc.end() && util::isBoolean(it->value()))
-        server->setFlags(server->flags() | Server::JoinInvite);
+    if ((it = sc.find("auto-rejoin")) != sc.end() && util::is_boolean(it->value()))
+        sv->set_flags(sv->flags() | server::auto_rejoin);
+    if ((it = sc.find("join-invite")) != sc.end() && util::is_boolean(it->value()))
+        sv->set_flags(sv->flags() | server::join_invite);
 
     // Channels
     if ((it = sc.find("channels")) != sc.end()) {
-        for (const std::string &s : *it) {
-            Channel channel;
+        for (const auto& s : *it) {
+            channel channel;
 
             if (auto pos = s.find(":") != std::string::npos) {
                 channel.name = s.substr(0, pos);
@@ -357,42 +359,40 @@
             } else
                 channel.name = s;
 
-            //server.channels.push_back(std::move(channel));
-            //server->join()
-            server->join(channel.name, channel.password);
+            sv->join(channel.name, channel.password);
         }
     }
     if ((it = sc.find("command-char")) != sc.end())
-        server->setCommandCharacter(it->value());
+        sv->set_command_char(it->value());
 
     // Reconnect and ping timeout
     try {
         if ((it = sc.find("port")) != sc.end())
-            server->setPort(util::toNumber<std::uint16_t>(it->value()));
+            sv->set_port(util::to_number<std::uint16_t>(it->value()));
         if ((it = sc.find("reconnect-tries")) != sc.end())
-            server->setReconnectTries(util::toNumber<std::int8_t>(it->value()));
+            sv->set_reconnect_tries(util::to_number<std::int8_t>(it->value()));
         if ((it = sc.find("reconnect-timeout")) != sc.end())
-            server->setReconnectDelay(util::toNumber<std::uint16_t>(it->value()));
+            sv->set_reconnect_delay(util::to_number<std::uint16_t>(it->value()));
         if ((it = sc.find("ping-timeout")) != sc.end())
-            server->setPingTimeout(util::toNumber<std::uint16_t>(it->value()));
-    } catch (const std::exception &) {
-        log::warning("server {}: invalid number for {}: {}"_format(server->name(), it->key(), it->value()));
+            sv->set_ping_timeout(util::to_number<std::uint16_t>(it->value()));
+    } catch (const std::exception&) {
+        log::warning("server {}: invalid number for {}: {}"_format(sv->name(), it->key(), it->value()));
     }
 
-    return server;
+    return sv;
 }
 
 } // !namespace
 
-Config Config::find()
+config config::find()
 {
     for (const auto& path : sys::config_filenames("irccd.conf")) {
         try {
             boost::system::error_code ec;
 
             if (boost::filesystem::exists(path, ec) && !ec)
-                return Config(path);
-        } catch (const std::exception &ex) {
+                return config(path);
+        } catch (const std::exception& ex) {
             log::warning() << path << ": " << ex.what() << std::endl;
         }
     }
@@ -400,9 +400,9 @@
     throw std::runtime_error("no configuration file found");
 }
 
-void Config::loadServerIdentity(Server &server, const std::string &identity) const
+void config::load_server_identity(server& server, const std::string& identity) const
 {
-    ini::Document::const_iterator sc = std::find_if(m_document.begin(), m_document.end(), [&] (const auto &sc) {
+    auto sc = std::find_if(document_.begin(), document_.end(), [&] (const auto& sc) {
         if (sc.key() != "identity")
             return false;
 
@@ -411,169 +411,169 @@
         return name != sc.end() && name->value() == identity;
     });
 
-    if (sc == m_document.end())
+    if (sc == document_.end())
         return;
 
-    ini::Section::const_iterator it;
+    ini::section::const_iterator it;
 
     if ((it = sc->find("username")) != sc->end())
-        server.setUsername(it->value());
+        server.set_username(it->value());
     if ((it = sc->find("realname")) != sc->end())
-        server.setRealname(it->value());
+        server.set_realname(it->value());
     if ((it = sc->find("nickname")) != sc->end())
-        server.setNickname(it->value());
+        server.set_nickname(it->value());
     if ((it = sc->find("ctcp-version")) != sc->end())
-        server.setCtcpVersion(it->value());
+        server.set_ctcp_version(it->value());
 }
 
-PluginConfig Config::findPluginConfig(const std::string &name) const
+plugin_config config::find_plugin_config(const std::string& name) const
 {
-    assert(util::isIdentifierValid(name));
+    assert(util::is_identifier(name));
 
     std::string fullname = std::string("plugin.") + name;
 
-    for (const auto &section : m_document) {
+    for (const auto& section : document_) {
         if (section.key() != fullname)
             continue;
 
-        return loadPluginConfig(section);
+        return load_plugin_config(section);
     }
 
-    return PluginConfig();
+    return plugin_config();
 }
 
-PluginFormats Config::findPluginFormats(const std::string &name) const
+plugin_formats config::find_plugin_formats(const std::string& name) const
 {
-    assert(util::isIdentifierValid(name));
+    assert(util::is_identifier(name));
 
-    auto section = m_document.find(std::string("format.") + name);
+    auto section = document_.find(std::string("format.") + name);
 
-    if (section == m_document.end())
-        return PluginFormats();
+    if (section == document_.end())
+        return plugin_formats();
 
-    PluginFormats formats;
+    plugin_formats formats;
 
-    for (const auto &opt : *section)
+    for (const auto& opt : *section)
         formats.emplace(opt.key(), opt.value());
 
     return formats;
 }
 
-PluginPaths Config::findPluginPaths(const std::string& name) const
+plugin_paths config::find_plugin_paths(const std::string& name) const
 {
-    assert(util::isIdentifierValid(name));
+    assert(util::is_identifier(name));
 
-    auto section = m_document.find(std::string("paths.") + name);
+    auto section = document_.find(std::string("paths.") + name);
 
-    if (section == m_document.end())
-        return PluginPaths();
+    if (section == document_.end())
+        return plugin_paths();
 
-    return readPaths(*section);
+    return read_paths(*section);
 }
 
-bool Config::isVerbose() const noexcept
+bool config::is_verbose() const noexcept
 {
-    return util::isBoolean(get(m_document, "logs", "verbose"));
+    return util::is_boolean(get(document_, "logs", "verbose"));
 }
 
-bool Config::isForeground() const noexcept
+bool config::is_foreground() const noexcept
 {
-    return util::isBoolean(get(m_document, "general", "foreground"));
+    return util::is_boolean(get(document_, "general", "foreground"));
 }
 
-std::string Config::pidfile() const
+std::string config::pidfile() const
 {
-    return get(m_document, "general", "pidfile");
+    return get(document_, "general", "pidfile");
 }
 
-std::string Config::uid() const
+std::string config::uid() const
 {
-    return get(m_document, "general", "uid");
+    return get(document_, "general", "uid");
 }
 
-std::string Config::gid() const
+std::string config::gid() const
 {
-    return get(m_document, "general", "gid");
+    return get(document_, "general", "gid");
 }
 
-void Config::loadLogs() const
+void config::load_logs() const
 {
-    ini::Document::const_iterator sc = m_document.find("logs");
+    ini::document::const_iterator sc = document_.find("logs");
 
-    if (sc == m_document.end())
+    if (sc == document_.end())
         return;
 
-    ini::Section::const_iterator it;
+    ini::section::const_iterator it;
 
     if ((it = sc->find("type")) != sc->end()) {
-        std::unique_ptr<log::Logger> iface;
+        std::unique_ptr<log::logger> iface;
 
         // Console is the default, no test case.
         if (it->value() == "file")
-            iface = loadLogFile(*sc);
+            iface = load_log_file(*sc);
         else if (it->value() == "syslog")
-            iface = loadLogSyslog();
+            iface = load_log_syslog();
         else if (it->value() != "console")
             throw std::runtime_error("logs: unknown log type: {}"_format(it->value()));
 
         if (iface)
-            log::setLogger(std::move(iface));
+            log::set_logger(std::move(iface));
     }
 }
 
-void Config::loadFormats() const
+void config::load_formats() const
 {
-    ini::Document::const_iterator sc = m_document.find("format");
+    ini::document::const_iterator sc = document_.find("format");
+    ini::section::const_iterator it;
 
-    if (sc == m_document.end())
+    if (sc == document_.end())
         return;
 
-    std::unique_ptr<IrccdLogFilter> filter = std::make_unique<IrccdLogFilter>();
-    ini::Section::const_iterator it;
+    auto filter = std::make_unique<irccd_log_filter>();
 
     if ((it = sc->find("debug")) != sc->cend())
-        filter->m_debug = it->value();
+        filter->debug_ = it->value();
     if ((it = sc->find("info")) != sc->cend())
-        filter->m_info = it->value();
+        filter->info_ = it->value();
     if ((it = sc->find("warning")) != sc->cend())
-        filter->m_warning = it->value();
+        filter->warning_ = it->value();
 
-    log::setFilter(std::move(filter));
+    log::set_filter(std::move(filter));
 }
 
-std::vector<std::shared_ptr<TransportServer>> Config::loadTransports() const
+std::vector<std::shared_ptr<transport_server>> config::load_transports() const
 {
-    std::vector<std::shared_ptr<TransportServer>> transports;
+    std::vector<std::shared_ptr<transport_server>> transports;
 
-    for (const auto &section : m_document)
+    for (const auto& section : document_)
         if (section.key() == "transport")
-            transports.push_back(loadTransport(section));
+            transports.push_back(load_transport(section));
 
     return transports;
 }
 
-std::vector<Rule> Config::loadRules() const
+std::vector<rule> config::load_rules() const
 {
-    std::vector<Rule> rules;
+    std::vector<rule> rules;
 
-    for (const auto &section : m_document)
+    for (const auto& section : document_)
         if (section.key() == "rule")
-            rules.push_back(loadRule(section));
+            rules.push_back(load_rule(section));
 
     return rules;
 }
 
-std::vector<std::shared_ptr<Server>> Config::loadServers() const
+std::vector<std::shared_ptr<server>> config::load_servers() const
 {
-    std::vector<std::shared_ptr<Server>> servers;
+    std::vector<std::shared_ptr<server>> servers;
 
-    for (const auto &section : m_document) {
+    for (const auto& section : document_) {
         if (section.key() != "server")
             continue;
 
         try {
-            servers.push_back(loadServer(section, *this));
-        } catch (const std::exception &ex) {
+            servers.push_back(load_server(section, *this));
+        } catch (const std::exception& ex) {
             log::warning(ex.what());
         }
     }
@@ -581,34 +581,34 @@
     return servers;
 }
 
-PluginPaths Config::loadPaths() const
+plugin_paths config::load_paths() const
 {
-    auto section = m_document.find("paths");
+    auto section = document_.find("paths");
 
-    if (section == m_document.end())
+    if (section == document_.end())
         return {};
 
-    return readPaths(*section);
+    return read_paths(*section);
 }
 
-void Config::loadPlugins(Irccd &irccd) const
+void config::load_plugins(irccd& irccd) const
 {
-    auto it = m_document.find("plugins");
+    auto it = document_.find("plugins");
 
-    irccd.plugins().setPaths(loadPaths());
+    irccd.plugins().set_paths(load_paths());
 
-    if (it != m_document.end()) {
-        for (const auto &option : *it) {
-            if (!util::isIdentifierValid(option.key()))
+    if (it != document_.end()) {
+        for (const auto& option : *it) {
+            if (!util::is_identifier(option.key()))
                 continue;
 
-            auto paths = findPluginPaths(option.key());
+            auto paths = find_plugin_paths(option.key());
 
             if (!paths.empty())
-                irccd.plugins().setPaths(std::move(paths));
+                irccd.plugins().set_paths(std::move(paths));
 
-            irccd.plugins().setConfig(option.key(), findPluginConfig(option.key()));
-            irccd.plugins().setFormats(option.key(), findPluginFormats(option.key()));
+            irccd.plugins().set_config(option.key(), find_plugin_config(option.key()));
+            irccd.plugins().set_formats(option.key(), find_plugin_formats(option.key()));
             irccd.plugins().load(option.key(), option.value());
         }
     }
--- a/libirccd/irccd/config.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/config.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -34,18 +34,18 @@
 
 namespace irccd {
 
-class Irccd;
-class Rule;
-class Server;
-class TransportServer;
+class irccd;
+class rule;
+class server;
+class transport_server;
 
 /**
  * \brief Read .ini configuration file for irccd
  */
-class Config {
+class config {
 private:
-    std::string m_path;
-    ini::Document m_document;
+    std::string path_;
+    ini::document document_;
 
 public:
     /**
@@ -54,16 +54,16 @@
      * \return the config
      * \throw std::exception on errors or if no config could be found
      */
-    IRCCD_EXPORT static Config find();
+    static config find();
 
     /**
      * Load the configuration from the specified path.
      *
      * \param path the path
      */
-    inline Config(std::string path)
-        : m_path(std::move(path))
-        , m_document(ini::readFile(m_path))
+    inline config(std::string path)
+        : path_(std::move(path))
+        , document_(ini::read_file(path_))
     {
     }
 
@@ -72,9 +72,9 @@
      *
      * \return the path
      */
-    inline const std::string &path() const noexcept
+    inline const std::string& path() const noexcept
     {
-        return m_path;
+        return path_;
     }
 
    /**
@@ -85,7 +85,7 @@
      * \param name the identity name
      * \return default identity if cannot be found
      */
-    IRCCD_EXPORT void loadServerIdentity(Server &server, const std::string &name) const;
+    void load_server_identity(server& server, const std::string& name) const;
 
      /**
      * Find a plugin configuration if defined in the configuration file.
@@ -93,7 +93,7 @@
      * \pre util::isValidIdentifier(name)
      * \return the configuration or empty if not found
      */
-    IRCCD_EXPORT PluginConfig findPluginConfig(const std::string &name) const;
+    plugin_config find_plugin_config(const std::string& name) const;
 
     /**
      * Find plugin formats if defined.
@@ -101,7 +101,7 @@
      * \pre util::isValidIdentifier(name)
      * \return the formats or empty one if not found
      */
-    IRCCD_EXPORT PluginFormats findPluginFormats(const std::string &name) const;
+    plugin_formats find_plugin_formats(const std::string& name) const;
 
     /**
      * Find plugin paths if defined.
@@ -109,80 +109,80 @@
      * \pre util::isValidIdentifier(name)
      * \param name the plugin name
      */
-    IRCCD_EXPORT PluginPaths findPluginPaths(const std::string& name) const;
+    plugin_paths find_plugin_paths(const std::string& name) const;
 
     /**
      * Get the path to the pidfile.
      *
      * \return the path or empty if not defined
      */
-    IRCCD_EXPORT std::string pidfile() const;
+    std::string pidfile() const;
 
     /**
      * Get the uid.
      *
      * \return the uid or empty one if no one is set
      */
-    IRCCD_EXPORT std::string uid() const;
+    std::string uid() const;
 
     /**
      * Get the gid.
      *
      * \return the gid or empty one if no one is set
      */
-    IRCCD_EXPORT std::string gid() const;
+    std::string gid() const;
 
     /**
      * Check if verbosity is enabled.
      *
      * \return true if verbosity was requested
      */
-    IRCCD_EXPORT bool isVerbose() const noexcept;
+    bool is_verbose() const noexcept;
 
     /**
      * Check if foreground is specified (= no daemonize).
      *
      * \return true if foreground was requested
      */
-    IRCCD_EXPORT bool isForeground() const noexcept;
+    bool is_foreground() const noexcept;
 
     /**
      * Load logging interface.
      */
-    IRCCD_EXPORT void loadLogs() const;
+    void load_logs() const;
 
     /**
      * Load formats for logging.
      */
-    IRCCD_EXPORT void loadFormats() const;
+    void load_formats() const;
 
     /**
      * Load transports.
      *
      * \return the set of transports
      */
-    IRCCD_EXPORT std::vector<std::shared_ptr<TransportServer>> loadTransports() const;
+    std::vector<std::shared_ptr<transport_server>> load_transports() const;
 
     /**
      * Load rules.
      *
      * \return the rules
      */
-    IRCCD_EXPORT std::vector<Rule> loadRules() const;
+    std::vector<rule> load_rules() const;
 
     /**
      * Get the list of servers defined.
      *
      * \return the list of servers
      */
-    IRCCD_EXPORT std::vector<std::shared_ptr<Server>> loadServers() const;
+    std::vector<std::shared_ptr<server>> load_servers() const;
 
     /**
      * Load default paths for plugins.
      *
      * \return the map of paths
      */
-    IRCCD_EXPORT PluginPaths loadPaths() const;
+    plugin_paths load_paths() const;
 
     /**
      * Get the list of defined plugins.
@@ -190,7 +190,7 @@
      * \param irccd the irccd instance
      * \return the list of plugins
      */
-    IRCCD_EXPORT void loadPlugins(Irccd &irccd) const;
+    void load_plugins(irccd& irccd) const;
 };
 
 } // !irccd
--- a/libirccd/irccd/irccd.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/irccd.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -22,79 +22,74 @@
 #include "service.hpp"
 #include "util.hpp"
 
-using namespace std;
-using namespace std::placeholders;
-using namespace std::string_literals;
-
 namespace irccd {
 
-Irccd::Irccd()
-    : m_commandService(std::make_shared<CommandService>())
-    , m_interruptService(std::make_shared<InterruptService>())
-    , m_servers(std::make_shared<ServerService>(*this))
-    , m_transports(std::make_shared<TransportService>(*this))
-    , m_ruleService(std::make_shared<RuleService>())
-    , m_plugins(std::make_shared<PluginService>(*this))
+irccd::irccd()
+    : command_service_(std::make_shared<command_service>())
+    , itr_service_(std::make_shared<interrupt_service>())
+    , server_service_(std::make_shared<server_service>(*this))
+    , tpt_service_(std::make_shared<transport_service>(*this))
+    , rule_service_(std::make_shared<rule_service>())
+    , plugin_service_(std::make_shared<plugin_service>(*this))
 {
 }
 
-void Irccd::post(std::function<void (Irccd &)> ev) noexcept
+void irccd::post(std::function<void (irccd&)> ev) noexcept
 {
-    std::lock_guard<mutex> lock(m_mutex);
+    std::lock_guard<std::mutex> lock(mutex_);
 
-    m_events.push_back(move(ev));
-    m_interruptService->interrupt();
+    events_.push_back(std::move(ev));
+    itr_service_->interrupt();
 }
 
-void Irccd::run()
+void irccd::run()
 {
-    while (m_running)
+    while (running_)
         util::poller::poll(250, *this);
 }
 
-void Irccd::prepare(fd_set &in, fd_set &out, net::Handle &max)
+void irccd::prepare(fd_set& in, fd_set& out, net::Handle& max)
 {
-    util::poller::prepare(in, out, max, *m_interruptService, *m_servers, *m_transports);
+    util::poller::prepare(in, out, max, *itr_service_, *server_service_, *tpt_service_);
 }
 
-void Irccd::sync(fd_set &in, fd_set &out)
+void irccd::sync(fd_set& in, fd_set& out)
 {
-    if (!m_running) {
+    if (!running_)
         return;
-    }
 
-    util::poller::sync(in, out, *m_interruptService, *m_servers, *m_transports);
+    util::poller::sync(in, out, *itr_service_, *server_service_, *tpt_service_);
 
-    if (!m_running) {
+    if (!running_)
         return;
-    }
 
     /*
      * Make a copy because the events can add other events while we are
      * iterating it. Also lock because the timers may alter these events too.
      */
-    std::vector<std::function<void (Irccd &)>> copy;
+    std::vector<std::function<void (irccd&)>> copy;
 
     {
-        std::lock_guard<mutex> lock(m_mutex);
+        std::lock_guard<std::mutex> lock(mutex_);
 
-        copy = move(m_events);
-        m_events.clear();
+        copy = std::move(events_);
+        events_.clear();
     }
 
     if (copy.size() > 0)
-        log::debug() << "irccd: dispatching " << copy.size() << " event" << (copy.size() > 1 ? "s" : "") << endl;
+        log::debug() << "irccd: dispatching " << copy.size() << " event"
+                     << (copy.size() > 1 ? "s" : "") << std::endl;
 
-    for (auto &ev : copy)
+    for (auto& ev : copy)
         ev(*this);
 }
 
-void Irccd::stop()
+void irccd::stop()
 {
-    log::debug() << "irccd: requesting to stop now" << endl;
+    log::debug() << "irccd: requesting to stop now" << std::endl;
 
-    m_running = false;
-    m_interruptService->interrupt();
+    running_ = false;
+    itr_service_->interrupt();
 }
 
 } // !irccd
--- a/libirccd/irccd/irccd.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/irccd.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -38,52 +38,52 @@
  */
 namespace irccd {
 
-class CommandService;
-class InterruptService;
-class PluginService;
-class RuleService;
-class ServerService;
-class TransportService;
+class command_service;
+class interrupt_service;
+class plugin_service;
+class rule_service;
+class server_service;
+class transport_service;
 
 /**
  * \brief Irccd main instance.
  */
-class Irccd {
+class irccd {
 private:
     // Main loop stuff.
-    std::atomic<bool> m_running{true};
-    std::mutex m_mutex;
-    std::vector<std::function<void (Irccd &)>> m_events;
+    std::atomic<bool> running_{true};
+    std::mutex mutex_;
+    std::vector<std::function<void (irccd&)>> events_;
 
     // Services.
-    std::shared_ptr<CommandService> m_commandService;
-    std::shared_ptr<InterruptService> m_interruptService;
-    std::shared_ptr<ServerService> m_servers;
-    std::shared_ptr<TransportService> m_transports;
-    std::shared_ptr<RuleService> m_ruleService;
-    std::shared_ptr<PluginService> m_plugins;
+    std::shared_ptr<command_service> command_service_;
+    std::shared_ptr<interrupt_service> itr_service_;
+    std::shared_ptr<server_service> server_service_;
+    std::shared_ptr<transport_service> tpt_service_;
+    std::shared_ptr<rule_service> rule_service_;
+    std::shared_ptr<plugin_service> plugin_service_;
 
     // Not copyable and not movable because services has references to irccd.
-    Irccd(const Irccd &) = delete;
-    Irccd(Irccd &&) = delete;
+    irccd(const irccd&) = delete;
+    irccd(irccd&&) = delete;
 
-    Irccd &operator=(const Irccd &) = delete;
-    Irccd &operator=(Irccd &&) = delete;
+    irccd& operator=(const irccd&) = delete;
+    irccd& operator=(irccd&&) = delete;
 
 public:
     /**
      * Prepare standard services.
      */
-    IRCCD_EXPORT Irccd();
+    irccd();
 
     /**
      * Access the command service.
      *
      * \return the service
      */
-    inline CommandService &commands() noexcept
+    inline command_service& commands() noexcept
     {
-        return *m_commandService;
+        return *command_service_;
     }
 
     /**
@@ -91,9 +91,9 @@
      *
      * \return the service
      */
-    inline ServerService &servers() noexcept
+    inline server_service& servers() noexcept
     {
-        return *m_servers;
+        return *server_service_;
     }
 
     /**
@@ -101,9 +101,9 @@
      *
      * \return the service
      */
-    inline TransportService &transports() noexcept
+    inline transport_service& transports() noexcept
     {
-        return *m_transports;
+        return *tpt_service_;
     }
 
     /**
@@ -111,9 +111,9 @@
      *
      * \return the service
      */
-    inline RuleService &rules() noexcept
+    inline rule_service& rules() noexcept
     {
-        return *m_ruleService;
+        return *rule_service_;
     }
 
     /**
@@ -121,9 +121,9 @@
      *
      * \return the service
      */
-    inline PluginService &plugins() noexcept
+    inline plugin_service& plugins() noexcept
     {
-        return *m_plugins;
+        return *plugin_service_;
     }
 
     /**
@@ -133,7 +133,7 @@
      * \param out the output set
      * \param max the maximum handle
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
+    void prepare(fd_set& in, fd_set& out, net::Handle& max);
 
     /**
      * Synchronize the services.
@@ -141,7 +141,7 @@
      * \param in the input set
      * \param out the output set
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
+    void sync(fd_set& in, fd_set& out);
 
     /**
      * Add an event to the queue. This will immediately signals the event loop
@@ -150,17 +150,17 @@
      * \param ev the event
      * \note Thread-safe
      */
-    IRCCD_EXPORT void post(std::function<void (Irccd &)> ev) noexcept;
+    void post(std::function<void (irccd&)> ev) noexcept;
 
     /**
      * Loop forever by calling prepare and sync indefinitely.
      */
-    IRCCD_EXPORT void run();
+    void run();
 
     /**
      * Request to stop, usually from a signal.
      */
-    IRCCD_EXPORT void stop();
+    void stop();
 };
 
 } // !irccd
--- a/libirccd/irccd/plugin-dynlib.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/plugin-dynlib.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -81,8 +81,8 @@
     OnWhois m_onWhois;
 
     // Configuration and formats.
-    PluginConfig m_config;
-    PluginFormats m_formats;
+    plugin_config m_config;
+    plugin_formats m_formats;
 
 public:
     /**
@@ -97,107 +97,107 @@
     /**
      * \copydoc Plugin::onCommand
      */
-    IRCCD_EXPORT void onCommand(Irccd &irccd, const MessageEvent &event) override;
+    IRCCD_EXPORT void onCommand(irccd &irccd, const MessageEvent &event) override;
 
     /**
      * \copydoc Plugin::onConnect
      */
-    IRCCD_EXPORT void onConnect(Irccd &irccd, const ConnectEvent &event) override;
+    IRCCD_EXPORT void onConnect(irccd &irccd, const ConnectEvent &event) override;
 
     /**
      * \copydoc Plugin::onChannelMode
      */
-    IRCCD_EXPORT void onChannelMode(Irccd &irccd, const ChannelModeEvent &event) override;
+    IRCCD_EXPORT void onChannelMode(irccd &irccd, const ChannelModeEvent &event) override;
 
     /**
      * \copydoc Plugin::onChannelNotice
      */
-    IRCCD_EXPORT void onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &event) override;
+    IRCCD_EXPORT void onChannelNotice(irccd &irccd, const ChannelNoticeEvent &event) override;
 
     /**
      * \copydoc Plugin::onInvite
      */
-    IRCCD_EXPORT void onInvite(Irccd &irccd, const InviteEvent &event) override;
+    IRCCD_EXPORT void onInvite(irccd &irccd, const InviteEvent &event) override;
 
     /**
      * \copydoc Plugin::onJoin
      */
-    IRCCD_EXPORT void onJoin(Irccd &irccd, const JoinEvent &event) override;
+    IRCCD_EXPORT void onJoin(irccd &irccd, const JoinEvent &event) override;
 
     /**
      * \copydoc Plugin::onKick
      */
-    IRCCD_EXPORT void onKick(Irccd &irccd, const KickEvent &event) override;
+    IRCCD_EXPORT void onKick(irccd &irccd, const KickEvent &event) override;
 
     /**
      * \copydoc Plugin::onLoad
      */
-    IRCCD_EXPORT void onLoad(Irccd &irccd) override;
+    IRCCD_EXPORT void onLoad(irccd &irccd) override;
 
     /**
      * \copydoc Plugin::onMessage
      */
-    IRCCD_EXPORT void onMessage(Irccd &irccd, const MessageEvent &event) override;
+    IRCCD_EXPORT void onMessage(irccd &irccd, const MessageEvent &event) override;
 
     /**
      * \copydoc Plugin::onMe
      */
-    IRCCD_EXPORT void onMe(Irccd &irccd, const MeEvent &event) override;
+    IRCCD_EXPORT void onMe(irccd &irccd, const MeEvent &event) override;
 
     /**
      * \copydoc Plugin::onMode
      */
-    IRCCD_EXPORT void onMode(Irccd &irccd, const ModeEvent &event) override;
+    IRCCD_EXPORT void onMode(irccd &irccd, const ModeEvent &event) override;
 
     /**
      * \copydoc Plugin::onNames
      */
-    IRCCD_EXPORT void onNames(Irccd &irccd, const NamesEvent &event) override;
+    IRCCD_EXPORT void onNames(irccd &irccd, const NamesEvent &event) override;
 
     /**
      * \copydoc Plugin::onNick
      */
-    IRCCD_EXPORT void onNick(Irccd &irccd, const NickEvent &event) override;
+    IRCCD_EXPORT void onNick(irccd &irccd, const NickEvent &event) override;
 
     /**
      * \copydoc Plugin::onNotice
      */
-    IRCCD_EXPORT void onNotice(Irccd &irccd, const NoticeEvent &event) override;
+    IRCCD_EXPORT void onNotice(irccd &irccd, const NoticeEvent &event) override;
 
     /**
      * \copydoc Plugin::onPart
      */
-    IRCCD_EXPORT void onPart(Irccd &irccd, const PartEvent &event) override;
+    IRCCD_EXPORT void onPart(irccd &irccd, const PartEvent &event) override;
 
     /**
      * \copydoc Plugin::onQuery
      */
-    IRCCD_EXPORT void onQuery(Irccd &irccd, const QueryEvent &event) override;
+    IRCCD_EXPORT void onQuery(irccd &irccd, const QueryEvent &event) override;
 
     /**
      * \copydoc Plugin::onQueryCommand
      */
-    IRCCD_EXPORT void onQueryCommand(Irccd &irccd, const QueryEvent &event) override;
+    IRCCD_EXPORT void onQueryCommand(irccd &irccd, const QueryEvent &event) override;
 
     /**
      * \copydoc Plugin::onReload
      */
-    IRCCD_EXPORT void onReload(Irccd &irccd) override;
+    IRCCD_EXPORT void onReload(irccd &irccd) override;
 
     /**
      * \copydoc Plugin::onTopic
      */
-    IRCCD_EXPORT void onTopic(Irccd &irccd, const TopicEvent &event) override;
+    IRCCD_EXPORT void onTopic(irccd &irccd, const TopicEvent &event) override;
 
     /**
      * \copydoc Plugin::onUnload
      */
-    IRCCD_EXPORT void onUnload(Irccd &irccd) override;
+    IRCCD_EXPORT void onUnload(irccd &irccd) override;
 
     /**
      * \copydoc Plugin::onWhois
      */
-    IRCCD_EXPORT void onWhois(Irccd &irccd, const WhoisEvent &event) override;
+    IRCCD_EXPORT void onWhois(irccd &irccd, const WhoisEvent &event) override;
 };
 
 /**
--- a/libirccd/irccd/plugin.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/plugin.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -29,14 +29,14 @@
 
 } // !namespace
 
-PluginLoader::PluginLoader(std::vector<std::string> directories,
-                           std::vector<std::string> extensions)
+plugin_loader::plugin_loader(std::vector<std::string> directories,
+                             std::vector<std::string> extensions)
     : directories_(std::move(directories))
     , extensions_(std::move(extensions))
 {
 }
 
-std::shared_ptr<Plugin> PluginLoader::find(const std::string& name) noexcept
+std::shared_ptr<plugin> plugin_loader::find(const std::string& name) noexcept
 {
     if (extensions_.empty())
         return nullptr;
@@ -51,7 +51,7 @@
                 filenames.push_back(dir + "/" + name + ext);
     }
 
-    std::shared_ptr<Plugin> plugin;
+    std::shared_ptr<plugin> plugin;
 
     for (const auto& candidate : filenames) {
         boost::system::error_code ec;
--- a/libirccd/irccd/plugin.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/plugin.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,7 @@
 
 /**
  * \file plugin.hpp
- * \brief Irccd plugins
+ * \brief irccd plugins
  */
 
 /**
@@ -40,22 +40,22 @@
 
 namespace irccd {
 
-class Irccd;
+class irccd;
 
 /**
  * \brief Configuration map extract from config file.
  */
-using PluginConfig = std::unordered_map<std::string, std::string>;
+using plugin_config = std::unordered_map<std::string, std::string>;
 
 /**
  * \brief Formats for plugins.
  */
-using PluginFormats = std::unordered_map<std::string, std::string>;
+using plugin_formats = std::unordered_map<std::string, std::string>;
 
 /**
  * \brief Paths for plugins.
  */
-using PluginPaths = std::unordered_map<std::string, std::string>;
+using plugin_paths = std::unordered_map<std::string, std::string>;
 
 /**
  * \ingroup plugins
@@ -63,17 +63,17 @@
  *
  * A plugin is identified by name and can be loaded and unloaded at runtime.
  */
-class Plugin : public std::enable_shared_from_this<Plugin> {
+class plugin : public std::enable_shared_from_this<plugin> {
 private:
     // Plugin information
-    std::string m_name;
-    std::string m_path;
+    std::string name_;
+    std::string path_;
 
     // Metadata
-    std::string m_author{"unknown"};
-    std::string m_license{"unknown"};
-    std::string m_summary{"unknown"};
-    std::string m_version{"unknown"};
+    std::string author_{"unknown"};
+    std::string license_{"unknown"};
+    std::string summary_{"unknown"};
+    std::string version_{"unknown"};
 
 public:
     /**
@@ -83,25 +83,25 @@
      * \param path the fully resolved path to the plugin
      * \throws std::runtime_error on errors
      */
-    inline Plugin(std::string name, std::string path) noexcept
-        : m_name(std::move(name))
-        , m_path(std::move(path))
+    inline plugin(std::string name, std::string path) noexcept
+        : name_(std::move(name))
+        , path_(std::move(path))
     {
     }
 
     /**
      * Temporary, close all timers.
      */
-    virtual ~Plugin() = default;
+    virtual ~plugin() = default;
 
     /**
      * Get the plugin name.
      *
      * \return the plugin name
      */
-    inline const std::string &name() const noexcept
+    inline const std::string& name() const noexcept
     {
-        return m_name;
+        return name_;
     }
 
     /**
@@ -110,9 +110,9 @@
      * \return the plugin path
      * \note some plugins may not exist on the disk
      */
-    inline const std::string &path() const noexcept
+    inline const std::string& path() const noexcept
     {
-        return m_path;
+        return path_;
     }
 
     /**
@@ -120,9 +120,9 @@
      *
      * \return the author
      */
-    inline const std::string &author() const noexcept
+    inline const std::string& author() const noexcept
     {
-        return m_author;
+        return author_;
     }
 
     /**
@@ -130,9 +130,9 @@
      *
      * \param author the author
      */
-    inline void setAuthor(std::string author) noexcept
+    inline void set_author(std::string author) noexcept
     {
-        m_author = std::move(author);
+        author_ = std::move(author);
     }
 
     /**
@@ -140,9 +140,9 @@
      *
      * \return the license
      */
-    inline const std::string &license() const noexcept
+    inline const std::string& license() const noexcept
     {
-        return m_license;
+        return license_;
     }
 
     /**
@@ -150,9 +150,9 @@
      *
      * \param license the license
      */
-    inline void setLicense(std::string license) noexcept
+    inline void set_license(std::string license) noexcept
     {
-        m_license = std::move(license);
+        license_ = std::move(license);
     }
 
     /**
@@ -160,9 +160,9 @@
      *
      * \return the summary
      */
-    inline const std::string &summary() const noexcept
+    inline const std::string& summary() const noexcept
     {
-        return m_summary;
+        return summary_;
     }
 
     /**
@@ -170,9 +170,9 @@
      *
      * \param summary the summary
      */
-    inline void setSummary(std::string summary) noexcept
+    inline void set_summary(std::string summary) noexcept
     {
-        m_summary = std::move(summary);
+        summary_ = std::move(summary);
     }
 
     /**
@@ -180,9 +180,9 @@
      *
      * \return the version
      */
-    inline const std::string &version() const noexcept
+    inline const std::string& version() const noexcept
     {
-        return m_version;
+        return version_;
     }
 
     /**
@@ -190,9 +190,9 @@
      *
      * \param version the version
      */
-    inline void setVersion(std::string version) noexcept
+    inline void set_version(std::string version) noexcept
     {
-        m_version = std::move(version);
+        version_ = std::move(version);
     }
 
     /**
@@ -200,7 +200,7 @@
      *
      * \return the config
      */
-    virtual PluginConfig config()
+    virtual plugin_config config()
     {
         return {};
     }
@@ -210,7 +210,7 @@
      *
      * \param config the configuration
      */
-    virtual void setConfig(PluginConfig config)
+    virtual void set_config(plugin_config config)
     {
         util::unused(config);
     }
@@ -220,7 +220,7 @@
      *
      * \return the format
      */
-    virtual PluginFormats formats()
+    virtual plugin_formats formats()
     {
         return {};
     }
@@ -230,7 +230,7 @@
      *
      * \param formats the formats
      */
-    virtual void setFormats(PluginFormats formats)
+    virtual void set_formats(plugin_formats formats)
     {
         util::unused(formats);
     }
@@ -240,7 +240,7 @@
      *
      * \return the paths
      */
-    virtual PluginPaths paths()
+    virtual plugin_paths paths()
     {
         return {};
     }
@@ -250,7 +250,7 @@
      *
      * \param paths the paths
      */
-    virtual void setPaths(PluginPaths paths)
+    virtual void set_paths(plugin_paths paths)
     {
         util::unused(paths);
     }
@@ -263,7 +263,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onCommand(Irccd &irccd, const MessageEvent &event)
+    virtual void on_command(irccd& irccd, const message_event& event)
     {
         util::unused(irccd, event);
     }
@@ -274,7 +274,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onConnect(Irccd &irccd, const ConnectEvent &event)
+    virtual void on_connect(irccd& irccd, const connect_event& event)
     {
         util::unused(irccd, event);
     }
@@ -285,7 +285,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onChannelMode(Irccd &irccd, const ChannelModeEvent &event)
+    virtual void on_channel_mode(irccd& irccd, const channel_mode_event& event)
     {
         util::unused(irccd, event);
     }
@@ -296,7 +296,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &event)
+    virtual void on_channel_notice(irccd& irccd, const channel_notice_event& event)
     {
         util::unused(irccd, event);
     }
@@ -307,7 +307,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onInvite(Irccd &irccd, const InviteEvent &event)
+    virtual void on_invite(irccd& irccd, const invite_event& event)
     {
         util::unused(irccd, event);
     }
@@ -318,7 +318,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onJoin(Irccd &irccd, const JoinEvent &event)
+    virtual void on_join(irccd& irccd, const join_event& event)
     {
         util::unused(irccd, event);
     }
@@ -329,7 +329,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onKick(Irccd &irccd, const KickEvent &event)
+    virtual void on_kick(irccd& irccd, const kick_event& event)
     {
         util::unused(irccd, event);
     }
@@ -339,7 +339,7 @@
      *
      * \param irccd the irccd instance
      */
-    virtual void onLoad(Irccd &irccd)
+    virtual void on_load(irccd& irccd)
     {
         util::unused(irccd);
     }
@@ -350,7 +350,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onMessage(Irccd &irccd, const MessageEvent &event)
+    virtual void on_message(irccd& irccd, const message_event& event)
     {
         util::unused(irccd, event);
     }
@@ -361,7 +361,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onMe(Irccd &irccd, const MeEvent &event)
+    virtual void on_me(irccd& irccd, const me_event& event)
     {
         util::unused(irccd, event);
     }
@@ -372,7 +372,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onMode(Irccd &irccd, const ModeEvent &event)
+    virtual void on_mode(irccd& irccd, const mode_event& event)
     {
         util::unused(irccd, event);
     }
@@ -383,7 +383,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onNames(Irccd &irccd, const NamesEvent &event)
+    virtual void on_names(irccd& irccd, const names_event& event)
     {
         util::unused(irccd, event);
     }
@@ -394,7 +394,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onNick(Irccd &irccd, const NickEvent &event)
+    virtual void on_nick(irccd& irccd, const nick_event& event)
     {
         util::unused(irccd, event);
     }
@@ -405,7 +405,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onNotice(Irccd &irccd, const NoticeEvent &event)
+    virtual void on_notice(irccd& irccd, const notice_event& event)
     {
         util::unused(irccd, event);
     }
@@ -416,7 +416,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onPart(Irccd &irccd, const PartEvent &event)
+    virtual void on_part(irccd& irccd, const part_event& event)
     {
         util::unused(irccd, event);
     }
@@ -427,7 +427,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onQuery(Irccd &irccd, const QueryEvent &event)
+    virtual void on_query(irccd& irccd, const query_event& event)
     {
         util::unused(irccd, event);
     }
@@ -438,7 +438,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onQueryCommand(Irccd &irccd, const QueryEvent &event)
+    virtual void on_query_command(irccd& irccd, const query_event& event)
     {
         util::unused(irccd, event);
     }
@@ -448,7 +448,7 @@
      *
      * \param irccd the irccd instance
      */
-    virtual void onReload(Irccd &irccd)
+    virtual void on_reload(irccd& irccd)
     {
         util::unused(irccd);
     }
@@ -459,7 +459,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onTopic(Irccd &irccd, const TopicEvent &event)
+    virtual void on_topic(irccd& irccd, const topic_event& event)
     {
         util::unused(irccd, event);
     }
@@ -469,7 +469,7 @@
      *
      * \param irccd the irccd instance
      */
-    virtual void onUnload(Irccd &irccd)
+    virtual void on_unload(irccd& irccd)
     {
         util::unused(irccd);
     }
@@ -480,7 +480,7 @@
      * \param irccd the irccd instance
      * \param event the event
      */
-    virtual void onWhois(Irccd &irccd, const WhoisEvent &event)
+    virtual void on_whois(irccd& irccd, const whois_event& event)
     {
         util::unused(irccd, event);
     }
@@ -489,16 +489,16 @@
 /**
  * \brief Abstract interface for searching plugins.
  *
- * This class is used to make loading of plugins extensible, the PluginService
+ * This class is used to make loading of plugins extensible, the plugin_service
  * knows some predefined plugins loaders and use them to search for available
  * plugins.
  *
  * This makes easier to implement new plugins or new ways of loading them.
  *
- * \see DynlibPluginLoader
- * \see JsPluginLoader
+ * \see dynlib_plugin_loader
+ * \see js_plugin_loader
  */
-class PluginLoader {
+class plugin_loader {
 private:
     std::vector<std::string> directories_;
     std::vector<std::string> extensions_;
@@ -516,8 +516,8 @@
      * \param directories directories to search
      * \param extensions the list of extensions supported
      */
-    PluginLoader(std::vector<std::string> directories = {},
-                 std::vector<std::string> extensions = {});
+    plugin_loader(std::vector<std::string> directories = {},
+                  std::vector<std::string> extensions = {});
 
     /**
      * Set directories where to search plugins.
@@ -547,8 +547,8 @@
      *
      * \param file the file
      */
-    virtual std::shared_ptr<Plugin> open(const std::string &id,
-                                         const std::string &file) noexcept = 0;
+    virtual std::shared_ptr<plugin> open(const std::string& id,
+                                         const std::string& file) noexcept = 0;
 
     /**
      * Search for a plugin named by this id.
@@ -556,7 +556,7 @@
      * \param id the plugin id
      * \return the plugin
      */
-    virtual std::shared_ptr<Plugin> find(const std::string &id) noexcept;
+    virtual std::shared_ptr<plugin> find(const std::string& id) noexcept;
 };
 
 } // !irccd
--- a/libirccd/irccd/rule.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/rule.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -18,111 +18,42 @@
 
 #include <algorithm>
 #include <cctype>
-#include <stdexcept>
 
-#include "logger.hpp"
 #include "rule.hpp"
-#include "util.hpp"
-
-using namespace std;
-
-namespace {
-
-const std::unordered_set<std::string> validEvents{
-    "onChannelMode"
-    "onChannelNotice",
-    "onCommand",
-    "onConnect",
-    "onInvite",
-    "onJoin",
-    "onKick",
-    "onMessage",
-    "onMode",
-    "onNames",
-    "onNick",
-    "onNotice",
-    "onPart",
-    "onQuery",
-    "onQueryCommand",
-    "onTopic",
-    "onWhois"
-};
-
-} // !namespace
 
 namespace irccd {
 
-bool Rule::matchMap(const RuleSet &map, const std::string &value) const noexcept
+bool rule::match_set(const set& set, const std::string& value) const noexcept
 {
-    return value.empty() || map.empty() || map.count(value) == 1;
+    return value.empty() || set.empty() || set.count(value) == 1;
 }
 
-Rule::Rule(RuleSet servers, RuleSet channels, RuleSet origins, RuleSet plugins, RuleSet events, RuleAction action)
-    : m_servers(std::move(servers))
-    , m_channels(std::move(channels))
-    , m_origins(std::move(origins))
-    , m_plugins(std::move(plugins))
-    , m_events(std::move(events))
-    , m_action(action)
+rule::rule(set servers, set channels, set origins, set plugins, set events, action_type action)
+    : servers_(std::move(servers))
+    , channels_(std::move(channels))
+    , origins_(std::move(origins))
+    , plugins_(std::move(plugins))
+    , events_(std::move(events))
+    , action_(action)
 {
-    for (const std::string &n : m_events)
-        if (validEvents.count(n) == 0)
-            throw std::invalid_argument(n + " is not a valid event name");
 }
 
-bool Rule::match(const std::string &server,
-                 const std::string &channel,
-                 const std::string &nick,
-                 const std::string &plugin,
-                 const std::string &event) const noexcept
+bool rule::match(const std::string& server,
+                 const std::string& channel,
+                 const std::string& nick,
+                 const std::string& plugin,
+                 const std::string& event) const noexcept
 {
     auto tolower = [] (auto str) {
         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
         return str;
     };
 
-    return matchMap(m_servers, tolower(server)) &&
-           matchMap(m_channels, tolower(channel)) &&
-           matchMap(m_origins, tolower(nick)) &&
-           matchMap(m_plugins, tolower(plugin)) &&
-           matchMap(m_events, event);
-}
-
-RuleAction Rule::action() const noexcept
-{
-    return m_action;
-}
-
-void Rule::setAction(RuleAction action) noexcept
-{
-    assert(action == RuleAction::Accept || action == RuleAction::Drop);
-
-    m_action = action;
-}
-
-const RuleSet &Rule::servers() const noexcept
-{
-    return m_servers;
-}
-
-const RuleSet &Rule::channels() const noexcept
-{
-    return m_channels;
-}
-
-const RuleSet &Rule::origins() const noexcept
-{
-    return m_origins;
-}
-
-const RuleSet &Rule::plugins() const noexcept
-{
-    return m_plugins;
-}
-
-const RuleSet &Rule::events() const noexcept
-{
-    return m_events;
+    return match_set(servers_, tolower(server)) &&
+           match_set(channels_, tolower(channel)) &&
+           match_set(origins_, tolower(nick)) &&
+           match_set(plugins_, tolower(plugin)) &&
+           match_set(events_, event);
 }
 
 } // !irccd
--- a/libirccd/irccd/rule.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/rule.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -24,47 +24,45 @@
  * \brief Rule description
  */
 
-#include <sstream>
+#include <cassert>
 #include <string>
 #include <unordered_set>
-#include <utility>
-#include <vector>
 
 #include "sysconfig.hpp"
 
 namespace irccd {
 
 /**
- * List of criterias.
- */
-using RuleSet = std::unordered_set<std::string>;
-
-/**
- * \enum RuleAction
- * \brief Rule action
- */
-enum class RuleAction {
-    Accept,         //!< The event is accepted (default)
-    Drop            //!< The event is dropped
-};
-
-/**
  * \brief Manage rule to activate or deactive events.
  */
-class Rule {
+class rule {
+public:
+    /**
+     * List of criterias.
+     */
+    using set = std::unordered_set<std::string>;
+
+    /**
+     * \brief Rule action type.
+     */
+    enum class action_type {
+        accept,         //!< The event is accepted (default)
+        drop            //!< The event is dropped
+    };
+
 private:
-    RuleSet m_servers;
-    RuleSet m_channels;
-    RuleSet m_origins;
-    RuleSet m_plugins;
-    RuleSet m_events;
-    RuleAction m_action{RuleAction::Accept};
+    set servers_;
+    set channels_;
+    set origins_;
+    set plugins_;
+    set events_;
+    action_type action_{action_type::accept};
 
     /*
-     * Check if a map contains the value and return true if it is
-     * or return true if value is empty (which means applicable).
+     * Check if a set contains the value and return true if it is or return
+     * true if value is empty (which means applicable).
      */
-    bool matchMap(const RuleSet &map, const std::string &value) const noexcept;
+    bool match_set(const set&, const std::string&) const noexcept;
 
 public:
     /**
@@ -78,12 +76,12 @@
      * \param action the rule action
      * \throw std::invalid_argument if events are invalid
      */
-    IRCCD_EXPORT Rule(RuleSet servers = RuleSet{},
-                      RuleSet channels = RuleSet{},
-                      RuleSet nicknames = RuleSet{},
-                      RuleSet plugins = RuleSet{},
-                      RuleSet events = RuleSet{},
-                      RuleAction action = RuleAction::Accept);
+    rule(set servers = {},
+         set channels = {},
+         set nicknames = {},
+         set plugins = {},
+         set events = {},
+         action_type action = action_type::accept);
 
     /**
      * Check if that rule apply for the given criterias.
@@ -95,41 +93,52 @@
      * \param event the event
      * \return true if match
      */
-    IRCCD_EXPORT bool match(const std::string &server,
-                            const std::string &channel,
-                            const std::string &nick,
-                            const std::string &plugin,
-                            const std::string &event) const noexcept;
+    bool match(const std::string& server,
+               const std::string& channel,
+               const std::string& nick,
+               const std::string& plugin,
+               const std::string& event) const noexcept;
 
     /**
      * Get the action.
      *
      * \return the action
      */
-    IRCCD_EXPORT RuleAction action() const noexcept;
+    inline action_type action() const noexcept
+    {
+        return action_;
+    }
 
     /**
      * Set the action.
      *
      * \pre action must be valid
      */
-    IRCCD_EXPORT void setAction(RuleAction action) noexcept;
+    inline void set_action(action_type action) noexcept
+    {
+        assert(action == action_type::accept || action == action_type::drop);
+
+        action_ = action;
+    }
 
     /**
      * Get the servers.
      *
      * \return the servers
      */
-    IRCCD_EXPORT const RuleSet &servers() const noexcept;
+    inline const set& servers() const noexcept
+    {
+        return servers_;
+    }
 
     /**
      * Overloaded function.
      *
      * \return the servers
      */
-    inline RuleSet &servers() noexcept
+    inline set& servers() noexcept
     {
-        return m_servers;
+        return servers_;
     }
 
     /**
@@ -137,17 +146,19 @@
      *
      * \return the channels
      */
-    IRCCD_EXPORT const RuleSet &channels() const noexcept;
-
+    inline const set& channels() const noexcept
+    {
+        return channels_;
+    }
 
     /**
      * Overloaded function.
      *
      * \return the channels
      */
-    inline RuleSet &channels() noexcept
+    inline set& channels() noexcept
     {
-        return m_channels;
+        return channels_;
     }
 
     /**
@@ -155,24 +166,29 @@
      *
      * \return the origins
      */
-    IRCCD_EXPORT const RuleSet &origins() const noexcept;
+    inline const set& origins() const noexcept
+    {
+        return origins_;
+    }
 
     /**
      * Get the plugins.
      *
      * \return the plugins
      */
-    IRCCD_EXPORT const RuleSet &plugins() const noexcept;
-
+    inline const set& plugins() const noexcept
+    {
+        return plugins_;
+    }
 
     /**
      * Overloaded function.
      *
      * \return the plugins
      */
-    inline RuleSet &plugins() noexcept
+    inline set& plugins() noexcept
     {
-        return m_plugins;
+        return plugins_;
     }
 
     /**
@@ -180,17 +196,19 @@
      *
      * \return the events
      */
-    IRCCD_EXPORT const RuleSet &events() const noexcept;
-
+    inline const set& events() const noexcept
+    {
+        return events_;
+    }
 
     /**
      * Overloaded function.
      *
      * \return the events
      */
-    inline RuleSet& events() noexcept
+    inline set& events() noexcept
     {
-        return m_events;
+        return events_;
     }
 };
 
--- a/libirccd/irccd/server.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/server.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -44,86 +44,86 @@
 namespace irccd {
 
 /*
- * Server::Session declaration.
+ * server::session declaration.
  * ------------------------------------------------------------------
  */
 
-class Server::Session {
+class server::session {
 public:
-    std::unique_ptr<irc_session_t, void (*)(irc_session_t *)> m_handle{nullptr, nullptr};
+    std::unique_ptr<irc_session_t, void (*)(irc_session_t *)> handle_{nullptr, nullptr};
 
-    inline operator const irc_session_t *() const noexcept
+    inline operator const irc_session_t*() const noexcept
     {
-        return m_handle.get();
+        return handle_.get();
     }
 
-    inline operator irc_session_t *() noexcept
+    inline operator irc_session_t*() noexcept
     {
-        return m_handle.get();
+        return handle_.get();
     }
 
-    inline bool isConnected() const noexcept
+    inline bool is_connected() const noexcept
     {
-        return irc_is_connected(m_handle.get());
+        return irc_is_connected(handle_.get());
     }
 };
 
 /*
- * Server::State declaration.
+ * server::state declaration.
  * ------------------------------------------------------------------
  */
 
-class Server::State {
+class server::state {
 public:
-    State() = default;
-    virtual ~State() = default;
-    virtual void prepare(Server &, fd_set &, fd_set &, net::Handle &) = 0;
+    state() = default;
+    virtual ~state() = default;
+    virtual void prepare(server&, fd_set&, fd_set&, net::Handle&) = 0;
     virtual std::string ident() const = 0;
 };
 
 /*
- * Server::DisconnectedState declaration.
+ * server::disconnected_state declaration.
  * ------------------------------------------------------------------
  */
 
-class Server::DisconnectedState : public Server::State {
+class server::disconnected_state : public server::state {
 private:
-    ElapsedTimer m_timer;
+    ElapsedTimer timer_;
 
 public:
-    void prepare(Server &, fd_set &, fd_set &, net::Handle &) override;
+    void prepare(server&, fd_set&, fd_set&, net::Handle&) override;
     std::string ident() const override;
 };
 
 /*
- * Server::ConnectingState declaration.
+ * server::connecting_state declaration.
  * ------------------------------------------------------------------
  */
 
-class Server::ConnectingState : public State {
+class server::connecting_state : public state {
 private:
     enum {
-        Disconnected,
-        Connecting
-    } m_state{Disconnected};
+        disconnected,
+        connecting
+    } state_{disconnected};
 
-    ElapsedTimer m_timer;
+    ElapsedTimer timer_;
 
-    bool connect(Server &server);
+    bool connect(server& server);
 
 public:
-    void prepare(Server &, fd_set &, fd_set &, net::Handle &) override;
+    void prepare(server&, fd_set&, fd_set&, net::Handle&) override;
     std::string ident() const override;
 };
 
 /*
- * Server::ConnectedState declaration.
+ * server::connected_state declaration.
  * ------------------------------------------------------------------
  */
 
-class Server::ConnectedState : public State {
+class server::connected_state : public state {
 public:
-    void prepare(Server &, fd_set &, fd_set &, net::Handle &) override;
+    void prepare(server&, fd_set&, fd_set&, net::Handle&) override;
     std::string ident() const override;
 };
 
@@ -135,24 +135,24 @@
  *
  * Make sure to build a C++ string with a not-null C string.
  */
-inline std::string strify(const char *s)
+inline std::string strify(const char* s)
 {
     return (s == nullptr) ? "" : std::string(s);
 }
 
 /*
- * cleanPrefix
+ * clean_prefix
  * ------------------------------------------------------------------
  *
  * Remove the user prefix only if it is present in the mode table, for example
  * removes @ from @irccd if and only if @ is a character mode (e.g. operator).
  */
-std::string cleanPrefix(const std::map<ChannelMode, char> &modes, std::string nickname)
+std::string clean_prefix(const std::map<channel_mode, char>& modes, std::string nickname)
 {
     if (nickname.length() == 0)
         return nickname;
 
-    for (const auto &pair : modes)
+    for (const auto& pair : modes)
         if (nickname[0] == pair.second)
             nickname.erase(0, 1);
 
@@ -160,32 +160,33 @@
 }
 
 /*
- * extractPrefixes
+ * extract_prefixes
  * ------------------------------------------------------------------
  *
  * Read modes from the IRC event numeric.
  */
-std::map<ChannelMode, char> extractPrefixes(const std::string &line)
+std::map<channel_mode, char> extract_prefixes(const std::string& line)
 {
+    // FIXME: what if line has different size?
     std::pair<char, char> table[16];
     std::string buf = line.substr(7);
-    std::map<ChannelMode, char> modes;
+    std::map<channel_mode, char> modes;
 
     for (int i = 0; i < 16; ++i)
         table[i] = std::make_pair(-1, -1);
 
     int j = 0;
-    bool readModes = true;
+    bool read_modes = true;
     for (size_t i = 0; i < buf.size(); ++i) {
         if (buf[i] == '(')
             continue;
         if (buf[i] == ')') {
             j = 0;
-            readModes = false;
+            read_modes = false;
             continue;
         }
 
-        if (readModes)
+        if (read_modes)
             table[j++].first = buf[i];
         else
             table[j++].second = buf[i];
@@ -193,7 +194,7 @@
 
     // Put these as a map of mode to prefix.
     for (int i = 0; i < 16; ++i) {
-        auto key = static_cast<ChannelMode>(table[i].first);
+        auto key = static_cast<channel_mode>(table[i].first);
         auto value = table[i].second;
 
         modes.emplace(key, value);
@@ -204,57 +205,68 @@
 
 } // !namespace
 
-void Server::removeJoinedChannel(const std::string &channel)
+void server::remove_joined_channel(const std::string& channel)
 {
-    m_jchannels.erase(std::remove(m_jchannels.begin(), m_jchannels.end(), channel), m_jchannels.end());
+    jchannels_.erase(std::remove(jchannels_.begin(), jchannels_.end(), channel), jchannels_.end());
 }
 
-void Server::handleConnect(const char *, const char **) noexcept
+void server::handle_connect(const char*, const char**) noexcept
 {
     // Reset the number of tried reconnection.
-    m_recocur = 1;
+    recocur_ = 1;
 
     // Reset the timer.
-    m_timer.reset();
+    timer_.reset();
 
     // Reset joined channels.
-    m_jchannels.clear();
+    jchannels_.clear();
 
     // Don't forget to change state and notify.
-    next(std::make_unique<ConnectedState>());
-    onConnect(ConnectEvent{shared_from_this()});
+    next(std::make_unique<connected_state>());
+    on_connect(connect_event{shared_from_this()});
 
     // Auto join listed channels.
-    for (const auto &channel : m_rchannels) {
-        log::info() << "server " << m_name << ": auto joining " << channel.name << std::endl;
+    for (const auto& channel : rchannels_) {
+        log::info() << "server " << name_ << ": auto joining " << channel.name << std::endl;
         join(channel.name, channel.password);
     }
 }
 
-void Server::handleChannel(const char *orig, const char **params) noexcept
+void server::handle_channel(const char* orig, const char** params) noexcept
 {
-    onMessage(MessageEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
+    on_message({shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
-void Server::handleChannelMode(const char *orig, const char **params) noexcept
+void server::handle_channel_mode(const char* orig, const char** params) noexcept
 {
-    onChannelMode(ChannelModeEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1]), strify(params[2])});
+    on_channel_mode({
+        shared_from_this(),
+        strify(orig),
+        strify(params[0]),
+        strify(params[1]),
+        strify(params[2])
+    });
 }
 
-void Server::handleChannelNotice(const char *orig, const char **params) noexcept
+void server::handle_channel_notice(const char* orig, const char** params) noexcept
 {
-    onChannelNotice(ChannelNoticeEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
+    on_channel_notice({
+        shared_from_this(),
+        strify(orig),
+        strify(params[0]),
+        strify(params[1])
+    });
 }
 
-void Server::handleCtcpAction(const char *orig, const char **params) noexcept
+void server::handle_ctcp_action(const char* orig, const char** params) noexcept
 {
-    onMe(MeEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
+    on_me({shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
-void Server::handleInvite(const char *orig, const char **params) noexcept
+void server::handle_invite(const char* orig, const char** params) noexcept
 {
     // If joininvite is set, join the channel.
-    if ((m_flags & JoinInvite) && isSelf(strify(params[0])))
+    if ((flags_ & join_invite) && is_self(strify(params[0])))
         join(strify(params[1]));
 
     /*
@@ -262,55 +274,61 @@
      * quit uncommon to need it so it is passed as the last argument to be
      * optional in the plugin.
      */
-    onInvite(InviteEvent{shared_from_this(), strify(orig), strify(params[1]), strify(params[0])});
+    on_invite({shared_from_this(), strify(orig), strify(params[1]), strify(params[0])});
 }
 
-void Server::handleJoin(const char *orig, const char **params) noexcept
+void server::handle_join(const char* orig, const char** params) noexcept
 {
-    if (isSelf(strify(orig)))
-        m_jchannels.push_back(strify(params[0]));
+    if (is_self(strify(orig)))
+        jchannels_.push_back(strify(params[0]));
 
-    onJoin(JoinEvent{shared_from_this(), strify(orig), strify(params[0])});
+    on_join({shared_from_this(), strify(orig), strify(params[0])});
 }
 
-void Server::handleKick(const char *orig, const char **params) noexcept
+void server::handle_kick(const char* orig, const char** params) noexcept
 {
-    if (isSelf(strify(params[1]))) {
+    if (is_self(strify(params[1]))) {
         // Remove the channel from the joined list.
-        removeJoinedChannel(strify(params[0]));
+        remove_joined_channel(strify(params[0]));
 
         // Rejoin the channel if the option has been set and I was kicked.
-        if (m_flags & AutoRejoin)
+        if (flags_ & auto_rejoin)
             join(strify(params[0]));
     }
 
-    onKick(KickEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1]), strify(params[2])});
-}
-
-void Server::handleMode(const char *orig, const char **params) noexcept
-{
-    onMode(ModeEvent{shared_from_this(), strify(orig), strify(params[1])});
+    on_kick({
+        shared_from_this(),
+        strify(orig),
+        strify(params[0]),
+        strify(params[1]),
+        strify(params[2])
+    });
 }
 
-void Server::handleNick(const char *orig, const char **params) noexcept
+void server::handle_mode(const char* orig, const char** params) noexcept
+{
+    on_mode({shared_from_this(), strify(orig), strify(params[1])});
+}
+
+void server::handle_nick(const char* orig, const char** params) noexcept
 {
     // Update our nickname.
-    if (isSelf(strify(orig)))
-        m_nickname = strify(params[0]);
+    if (is_self(strify(orig)))
+        nickname_ = strify(params[0]);
 
-    onNick(NickEvent{shared_from_this(), strify(orig), strify(params[0])});
+    on_nick({shared_from_this(), strify(orig), strify(params[0])});
 }
 
-void Server::handleNotice(const char *orig, const char **params) noexcept
+void server::handle_notice(const char* orig, const char** params) noexcept
 {
     /*
      * Like handleInvite, the notice provides the target nickname, we discard
      * it.
      */
-    onNotice(NoticeEvent{shared_from_this(), strify(orig), strify(params[1])});
+    on_notice({shared_from_this(), strify(orig), strify(params[1])});
 }
 
-void Server::handleNumeric(unsigned int event, const char **params, unsigned int c) noexcept
+void server::handle_numeric(unsigned int event, const char** params, unsigned int c) noexcept
 {
     if (event == LIBIRC_RFC_RPL_NAMREPLY) {
         /*
@@ -327,11 +345,11 @@
         if (c < 4 || params[2] == nullptr || params[3] == nullptr)
             return;
 
-        std::vector<std::string> users = util::split(params[3], " \t");
+        auto users = util::split(params[3], " \t");
 
         // The listing may add some prefixes, remove them if needed.
-        for (std::string u : users)
-            m_namesMap[params[2]].insert(cleanPrefix(m_modes, u));
+        for (auto u : users)
+            names_map_[params[2]].insert(clean_prefix(modes_, u));
     } else if (event == LIBIRC_RFC_RPL_ENDOFNAMES) {
         /*
          * Called when end of name listing has finished on a channel.
@@ -343,12 +361,16 @@
         if (c < 3 || params[1] == nullptr)
             return;
 
-        auto it = m_namesMap.find(params[1]);
-        if (it != m_namesMap.end()) {
-            onNames(NamesEvent{shared_from_this(), params[1], std::vector<std::string>(it->second.begin(), it->second.end())});
+        auto it = names_map_.find(params[1]);
+        if (it != names_map_.end()) {
+            on_names({
+                shared_from_this(),
+                params[1],
+                std::vector<std::string>(it->second.begin(), it->second.end())
+            });
 
             // Don't forget to remove the list.
-            m_namesMap.erase(it);
+            names_map_.erase(it);
         }
     } else if (event == LIBIRC_RFC_RPL_WHOISUSER) {
         /*
@@ -364,14 +386,14 @@
         if (c < 6 || !params[1] || !params[2] || !params[3] || !params[5])
             return;
 
-        Whois info;
+        class whois info;
 
         info.nick = strify(params[1]);
         info.user = strify(params[2]);
         info.host = strify(params[3]);
         info.realname = strify(params[5]);
 
-        m_whoisMap.emplace(info.nick, info);
+        whois_map_.emplace(info.nick, info);
     } else if (event == LIBIRC_RFC_RPL_WHOISCHANNELS) {
         /*
          * Called when we have received channels for one user.
@@ -383,13 +405,13 @@
         if (c < 3 || !params[1] || !params[2])
             return;
 
-        auto it = m_whoisMap.find(params[1]);
-        if (it != m_whoisMap.end()) {
-            std::vector<std::string> channels = util::split(params[2], " \t");
+        auto it = whois_map_.find(params[1]);
+        if (it != whois_map_.end()) {
+            auto channels = util::split(params[2], " \t");
 
             // Clean their prefixes.
             for (auto &s : channels)
-                s = cleanPrefix(m_modes, s);
+                s = clean_prefix(modes_, s);
 
             it->second.channels = std::move(channels);
         }
@@ -401,12 +423,12 @@
          * params[1] == nickname
          * params[2] == End of WHOIS list
          */
-        auto it = m_whoisMap.find(params[1]);
-        if (it != m_whoisMap.end()) {
-            onWhois(WhoisEvent{shared_from_this(), it->second});
+        auto it = whois_map_.find(params[1]);
+        if (it != whois_map_.end()) {
+            on_whois({shared_from_this(), it->second});
 
             // Don't forget to remove.
-            m_whoisMap.erase(it);
+            whois_map_.erase(it);
         }
     } else if (event == /* RPL_BOUNCE */ 5) {
         /*
@@ -414,80 +436,80 @@
          */
         for (unsigned int i = 0; i < c; ++i) {
             if (strncmp(params[i], "PREFIX", 6) == 0) {
-                m_modes = extractPrefixes(params[i]);
+                modes_ = extract_prefixes(params[i]);
                 break;
             }
         }
     }
 }
 
-void Server::handlePart(const char *orig, const char **params) noexcept
+void server::handle_part(const char* orig, const char** params) noexcept
 {
     // Remove the channel from the joined list if I left a channel.
-    if (isSelf(strify(orig)))
-        removeJoinedChannel(strify(params[0]));
+    if (is_self(strify(orig)))
+        remove_joined_channel(strify(params[0]));
 
-    onPart(PartEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
+    on_part({shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
-void Server::handlePing(const char *, const char **) noexcept
+void server::handle_ping(const char*, const char**) noexcept
 {
     // Reset the timer to detect disconnection.
-    m_timer.reset();
+    timer_.reset();
 }
 
-void Server::handleQuery(const char *orig, const char **params) noexcept
+void server::handle_query(const char* orig, const char** params) noexcept
 {
-    onQuery(QueryEvent{shared_from_this(), strify(orig), strify(params[1])});
+    on_query({shared_from_this(), strify(orig), strify(params[1])});
 }
 
-void Server::handleTopic(const char *orig, const char **params) noexcept
+void server::handle_topic(const char* orig, const char** params) noexcept
 {
-    onTopic(TopicEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
+    on_topic({shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
-std::shared_ptr<Server> Server::fromJson(const nlohmann::json &object)
+std::shared_ptr<server> server::from_json(const nlohmann::json& object)
 {
-    auto server = std::make_shared<Server>(util::json::requireIdentifier(object, "name"));
+    auto sv = std::make_shared<server>(util::json::require_identifier(object, "name"));
 
-    server->setHost(util::json::requireString(object, "host"));
-    server->setPassword(util::json::getString(object, "password"));
-    server->setNickname(util::json::getString(object, "nickname", server->nickname()));
-    server->setRealname(util::json::getString(object, "realname", server->realname()));
-    server->setUsername(util::json::getString(object, "username", server->username()));
-    server->setCtcpVersion(util::json::getString(object, "ctcpVersion", server->ctcpVersion()));
-    server->setCommandCharacter(util::json::getString(object, "commandChar", server->commandCharacter()));
+    sv->set_host(util::json::require_string(object, "host"));
+    sv->set_password(util::json::get_string(object, "password"));
+    sv->set_nickname(util::json::get_string(object, "nickname", sv->nickname()));
+    sv->set_realname(util::json::get_string(object, "realname", sv->realname()));
+    sv->set_username(util::json::get_string(object, "username", sv->username()));
+    sv->set_ctcp_version(util::json::get_string(object, "ctcpVersion", sv->ctcp_version()));
+    sv->set_command_char(util::json::get_string(object, "commandChar", sv->command_char()));
 
     if (object.find("port") != object.end())
-        server->setPort(util::json::getUintRange<std::uint16_t>(object, "port"));
-    if (util::json::getBool(object, "ipv6"))
-        server->setFlags(server->flags() | Server::Ipv6);
-    if (util::json::getBool(object, "ssl"))
-        server->setFlags(server->flags() | Server::Ssl);
-    if (util::json::getBool(object, "sslVerify"))
-        server->setFlags(server->flags() | Server::SslVerify);
-    if (util::json::getBool(object, "autoRejoin"))
-        server->setFlags(server->flags() | Server::AutoRejoin);
-    if (util::json::getBool(object, "joinInvite"))
-        server->setFlags(server->flags() | Server::JoinInvite);
+        sv->set_port(util::json::get_uint_range<std::uint16_t>(object, "port"));
+    if (util::json::get_bool(object, "ipv6"))
+        sv->set_flags(sv->flags() | server::ipv6);
+    if (util::json::get_bool(object, "ssl"))
+        sv->set_flags(sv->flags() | server::ssl);
+    if (util::json::get_bool(object, "sslVerify"))
+        sv->set_flags(sv->flags() | server::ssl_verify);
+    if (util::json::get_bool(object, "autoRejoin"))
+        sv->set_flags(sv->flags() | server::auto_rejoin);
+    if (util::json::get_bool(object, "joinInvite"))
+        sv->set_flags(sv->flags() | server::join_invite);
 
-    return server;
+    return sv;
 }
 
-Channel Server::splitChannel(const std::string &value)
+channel server::split_channel(const std::string& value)
 {
     auto pos = value.find(':');
 
     if (pos != std::string::npos)
-        return { value.substr(0, pos), value.substr(pos + 1) };
+        return {value.substr(0, pos), value.substr(pos + 1)};
 
-    return { value, "" };
+    return {value, ""};
 }
 
-Server::Server(std::string name)
-    : m_name(std::move(name))
-    , m_session(std::make_unique<Session>())
-    , m_state(std::make_unique<ConnectingState>())
+server::server(std::string name)
+    : name_(std::move(name))
+    , session_(std::make_unique<session>())
+    , state_(std::make_unique<connecting_state>())
 {
     irc_callbacks_t callbacks;
 
@@ -503,126 +525,126 @@
      *
      * While doing this, discard useless arguments.
      */
-    callbacks.event_channel = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleChannel(orig, params);
+    callbacks.event_channel = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_channel(orig, params);
     };
-    callbacks.event_channel_notice = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleChannelNotice(orig, params);
+    callbacks.event_channel_notice = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_channel_notice(orig, params);
     };
-    callbacks.event_connect = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleConnect(orig, params);
+    callbacks.event_connect = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_connect(orig, params);
     };
-    callbacks.event_ctcp_action = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleCtcpAction(orig, params);
+    callbacks.event_ctcp_action = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_ctcp_action(orig, params);
     };
-    callbacks.event_invite = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleInvite(orig, params);
+    callbacks.event_invite = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_invite(orig, params);
     };
-    callbacks.event_join = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleJoin(orig, params);
+    callbacks.event_join = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_join(orig, params);
     };
-    callbacks.event_kick = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleKick(orig, params);
+    callbacks.event_kick = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_kick(orig, params);
     };
-    callbacks.event_mode = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleChannelMode(orig, params);
+    callbacks.event_mode = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_channel_mode(orig, params);
     };
-    callbacks.event_nick = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleNick(orig, params);
+    callbacks.event_nick = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_nick(orig, params);
     };
-    callbacks.event_notice = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleNotice(orig, params);
+    callbacks.event_notice = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_notice(orig, params);
     };
-    callbacks.event_numeric = [] (irc_session_t *session, unsigned int event, const char *, const char **params, unsigned int count) {
-        static_cast<Server *>(irc_get_ctx(session))->handleNumeric(event, params, count);
+    callbacks.event_numeric = [] (auto session, auto event, auto, auto params, auto count) {
+        static_cast<server*>(irc_get_ctx(session))->handle_numeric(event, params, count);
     };
-    callbacks.event_part = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handlePart(orig, params);
+    callbacks.event_part = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_part(orig, params);
     };
-    callbacks.event_ping = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handlePing(orig, params);
+    callbacks.event_ping = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_ping(orig, params);
     };
-    callbacks.event_privmsg = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleQuery(orig, params);
+    callbacks.event_privmsg = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_query(orig, params);
     };
-    callbacks.event_topic = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleTopic(orig, params);
+    callbacks.event_topic = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_topic(orig, params);
     };
-    callbacks.event_umode = [] (irc_session_t *session, const char *, const char *orig, const char **params, unsigned) {
-        static_cast<Server *>(irc_get_ctx(session))->handleMode(orig, params);
+    callbacks.event_umode = [] (auto session, auto, auto orig, auto params, auto) {
+        static_cast<server*>(irc_get_ctx(session))->handle_mode(orig, params);
     };
 
-    m_session->m_handle = {irc_create_session(&callbacks), irc_destroy_session};
+    session_->handle_ = {irc_create_session(&callbacks), irc_destroy_session};
 
     // Save this to the session.
-    irc_set_ctx(*m_session, this);
-    irc_set_ctcp_version(*m_session, m_ctcpversion.c_str());
+    irc_set_ctx(*session_, this);
+    irc_set_ctcp_version(*session_, ctcpversion_.c_str());
 }
 
-Server::~Server()
+server::~server()
 {
-    irc_disconnect(*m_session);
+    irc_disconnect(*session_);
 }
 
-void Server::setNickname(std::string nickname)
+void server::set_nickname(std::string nickname)
 {
-    if (m_session->isConnected())
-        m_queue.push([=] () {
-            return irc_cmd_nick(*m_session, nickname.c_str()) == 0;
+    if (session_->is_connected())
+        queue_.push([=] () {
+            return irc_cmd_nick(*session_, nickname.c_str()) == 0;
         });
     else
-        m_nickname = std::move(nickname);
+        nickname_ = std::move(nickname);
 }
 
-void Server::setCtcpVersion(std::string ctcpversion)
+void server::set_ctcp_version(std::string ctcpversion)
 {
-    m_ctcpversion = std::move(ctcpversion);
-    irc_set_ctcp_version(*m_session, m_ctcpversion.c_str());
+    ctcpversion_ = std::move(ctcpversion);
+    irc_set_ctcp_version(*session_, ctcpversion_.c_str());
 }
 
-void Server::next(std::unique_ptr<State> state) noexcept
+void server::next(std::unique_ptr<state> state) noexcept
 {
-    m_stateNext = std::move(state);
+    state_next_ = std::move(state);
 }
 
-std::string Server::status() const noexcept
+std::string server::status() const noexcept
 {
-    return !m_state ? "null" : m_state->ident();
+    return state_ ? state_->ident() : "null";
 }
 
-void Server::update() noexcept
+void server::update() noexcept
 {
-    if (m_stateNext) {
-        log::debug("server {}: switch state {} -> {}"_format(m_name, m_state->ident(), m_stateNext->ident()));
+    if (state_next_) {
+        log::debug("server {}: switch state {} -> {}"_format(name_, state_->ident(), state_next_->ident()));
 
-        m_state = std::move(m_stateNext);
-        m_stateNext = nullptr;
+        state_ = std::move(state_next_);
+        state_next_ = nullptr;
 
         // Reset channels.
-        m_jchannels.clear();
+        jchannels_.clear();
     }
 }
 
-void Server::disconnect() noexcept
+void server::disconnect() noexcept
 {
     using namespace std::placeholders;
 
-    irc_disconnect(*m_session);
-    onDie();
+    irc_disconnect(*session_);
+    on_die();
 }
 
-void Server::reconnect() noexcept
+void server::reconnect() noexcept
 {
-    irc_disconnect(*m_session);
-    next(std::make_unique<ConnectingState>());
+    irc_disconnect(*session_);
+    next(std::make_unique<connecting_state>());
 }
 
-void Server::prepare(fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) noexcept
+void server::prepare(fd_set& setinput, fd_set& setoutput, net::Handle& maxfd) noexcept
 {
-    m_state->prepare(*this, setinput, setoutput, maxfd);
+    state_->prepare(*this, setinput, setoutput, maxfd);
 }
 
-void Server::sync(fd_set &setinput, fd_set &setoutput)
+void server::sync(fd_set &setinput, fd_set &setoutput)
 {
     /*
      * 1. Send maximum of command possible if available for write
@@ -632,200 +654,200 @@
      */
     bool done = false;
 
-    while (!m_queue.empty() && !done) {
-        if (m_queue.front()())
-            m_queue.pop();
+    while (!queue_.empty() && !done) {
+        if (queue_.front()())
+            queue_.pop();
         else
             done = true;
     }
 
     // 2. Read data.
-    irc_process_select_descriptors(*m_session, &setinput, &setoutput);
+    irc_process_select_descriptors(*session_, &setinput, &setoutput);
 }
 
-bool Server::isSelf(const std::string &nick) const noexcept
+bool server::is_self(const std::string& nick) const noexcept
 {
     char target[32]{0};
 
     irc_target_get_nick(nick.c_str(), target, sizeof (target));
 
-    return m_nickname == target;
+    return nickname_ == target;
 }
 
-void Server::cmode(std::string channel, std::string mode)
+void server::cmode(std::string channel, std::string mode)
 {
-    m_queue.push([=] () {
-        return irc_cmd_channel_mode(*m_session, channel.c_str(), mode.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_channel_mode(*session_, channel.c_str(), mode.c_str()) == 0;
     });
 }
 
-void Server::cnotice(std::string channel, std::string message)
+void server::cnotice(std::string channel, std::string message)
 {
-    m_queue.push([=] () {
-        return irc_cmd_notice(*m_session, channel.c_str(), message.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_notice(*session_, channel.c_str(), message.c_str()) == 0;
     });
 }
 
-void Server::invite(std::string target, std::string channel)
+void server::invite(std::string target, std::string channel)
 {
-    m_queue.push([=] () {
-        return irc_cmd_invite(*m_session, target.c_str(), channel.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_invite(*session_, target.c_str(), channel.c_str()) == 0;
     });
 }
 
-void Server::join(std::string channel, std::string password)
+void server::join(std::string channel, std::string password)
 {
     // 1. Add the channel or update it to the requested channels.
-    auto it = std::find_if(m_rchannels.begin(), m_rchannels.end(), [&] (const auto &c) {
+    auto it = std::find_if(rchannels_.begin(), rchannels_.end(), [&] (const auto& c) {
         return c.name == channel;
     });
 
-    if (it == m_rchannels.end())
-        m_rchannels.push_back({ channel, password });
+    if (it == rchannels_.end())
+        rchannels_.push_back({ channel, password });
     else
         *it = { channel, password };
 
     // 2. Join if not found and connected.
-    if (m_session->isConnected())
-        irc_cmd_join(*m_session, channel.c_str(), password.empty() ? nullptr : password.c_str());
+    if (session_->is_connected())
+        irc_cmd_join(*session_, channel.c_str(), password.empty() ? nullptr : password.c_str());
 }
 
-void Server::kick(std::string target, std::string channel, std::string reason)
+void server::kick(std::string target, std::string channel, std::string reason)
 {
-    m_queue.push([=] () {
-        return irc_cmd_kick(*m_session, target.c_str(), channel.c_str(), reason.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_kick(*session_, target.c_str(), channel.c_str(), reason.c_str()) == 0;
     });
 }
 
-void Server::me(std::string target, std::string message)
+void server::me(std::string target, std::string message)
 {
-    m_queue.push([=] () {
-        return irc_cmd_me(*m_session, target.c_str(), message.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_me(*session_, target.c_str(), message.c_str()) == 0;
     });
 }
 
-void Server::message(std::string target, std::string message)
+void server::message(std::string target, std::string message)
 {
-    m_queue.push([=] () {
-        return irc_cmd_msg(*m_session, target.c_str(), message.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_msg(*session_, target.c_str(), message.c_str()) == 0;
     });
 }
 
-void Server::mode(std::string mode)
+void server::mode(std::string mode)
 {
-    m_queue.push([=] () {
-        return irc_cmd_user_mode(*m_session, mode.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_user_mode(*session_, mode.c_str()) == 0;
     });
 }
 
-void Server::names(std::string channel)
+void server::names(std::string channel)
 {
-    m_queue.push([=] () {
-        return irc_cmd_names(*m_session, channel.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_names(*session_, channel.c_str()) == 0;
     });
 }
 
-void Server::notice(std::string target, std::string message)
+void server::notice(std::string target, std::string message)
 {
-    m_queue.push([=] () {
-        return irc_cmd_notice(*m_session, target.c_str(), message.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_notice(*session_, target.c_str(), message.c_str()) == 0;
     });
 }
 
-void Server::part(std::string channel, std::string reason)
+void server::part(std::string channel, std::string reason)
 {
-    m_queue.push([=] () -> bool {
+    queue_.push([=] () -> bool {
         if (reason.empty())
-            return irc_cmd_part(*m_session, channel.c_str()) == 0;
+            return irc_cmd_part(*session_, channel.c_str()) == 0;
 
-        return irc_send_raw(*m_session, "PART %s :%s", channel.c_str(), reason.c_str());
+        return irc_send_raw(*session_, "PART %s :%s", channel.c_str(), reason.c_str());
     });
 }
 
-void Server::send(std::string raw)
+void server::send(std::string raw)
 {
-    m_queue.push([=] () {
-        return irc_send_raw(*m_session, raw.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_send_raw(*session_, raw.c_str()) == 0;
     });
 }
 
-void Server::topic(std::string channel, std::string topic)
+void server::topic(std::string channel, std::string topic)
 {
-    m_queue.push([=] () {
-        return irc_cmd_topic(*m_session, channel.c_str(), topic.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_topic(*session_, channel.c_str(), topic.c_str()) == 0;
     });
 }
 
-void Server::whois(std::string target)
+void server::whois(std::string target)
 {
-    m_queue.push([=] () {
-        return irc_cmd_whois(*m_session, target.c_str()) == 0;
+    queue_.push([=] () {
+        return irc_cmd_whois(*session_, target.c_str()) == 0;
     });
 }
 
 /*
- * Server::DisconnectedState implementation
+ * server::disconnected_state implementation
  * ------------------------------------------------------------------
  */
 
-void Server::DisconnectedState::prepare(Server &server, fd_set &, fd_set &, net::Handle &)
+void server::disconnected_state::prepare(server& server, fd_set&, fd_set&, net::Handle&)
 {
-    if (server.m_recotries == 0) {
-        log::warning() << "server " << server.m_name << ": reconnection disabled, skipping" << std::endl;
-        server.onDie();
-    } else if (server.m_recotries > 0 && server.m_recocur > server.m_recotries) {
-        log::warning() << "server " << server.m_name << ": giving up" << std::endl;
-        server.onDie();
+    if (server.recotries_ == 0) {
+        log::warning() << "server " << server.name_ << ": reconnection disabled, skipping" << std::endl;
+        server.on_die();
+    } else if (server.recotries_ > 0 && server.recocur_ > server.recotries_) {
+        log::warning() << "server " << server.name_ << ": giving up" << std::endl;
+        server.on_die();
     } else {
-        if (m_timer.elapsed() > static_cast<unsigned>(server.m_recodelay * 1000)) {
-            irc_disconnect(*server.m_session);
+        if (timer_.elapsed() > static_cast<unsigned>(server.recodelay_ * 1000)) {
+            irc_disconnect(*server.session_);
 
-            server.m_recocur ++;
-            server.next(std::make_unique<ConnectingState>());
+            server.recocur_ ++;
+            server.next(std::make_unique<connecting_state>());
         }
     }
 }
 
-std::string Server::DisconnectedState::ident() const
+std::string server::disconnected_state::ident() const
 {
     return "Disconnected";
 }
 
 /*
- * Server::ConnectingState implementation
+ * server::connecting_state implementation
  * ------------------------------------------------------------------
  */
 
-bool Server::ConnectingState::connect(Server &server)
+bool server::connecting_state::connect(server& server)
 {
-    const char *password = server.m_password.empty() ? nullptr : server.m_password.c_str();
-    std::string host = server.m_host;
-    int code;
+    auto password = server.password_.empty() ? nullptr : server.password_.c_str();
+    auto host = server.host_;
 
     // libircclient requires # for SSL connection.
 #if defined(WITH_SSL)
-    if (server.m_flags & Server::Ssl)
+    if (server.flags_ & server::ssl)
         host.insert(0, 1, '#');
-    if (!(server.m_flags & Server::SslVerify))
-        irc_option_set(*server.m_session, LIBIRC_OPTION_SSL_NO_VERIFY);
+    if (!(server.flags_ & server::ssl_verify))
+        irc_option_set(*server.session_, LIBIRC_OPTION_SSL_NO_VERIFY);
 #endif
 
-    if (server.flags() & Server::Ipv6) {
-        code = irc_connect6(*server.m_session, host.c_str(), server.m_port, password,
-                            server.m_nickname.c_str(),
-                            server.m_username.c_str(),
-                            server.m_realname.c_str());
+    int code;
+    if (server.flags() & server::ipv6) {
+        code = irc_connect6(*server.session_, host.c_str(), server.port_, password,
+                            server.nickname_.c_str(),
+                            server.username_.c_str(),
+                            server.realname_.c_str());
     } else {
-        code = irc_connect(*server.m_session, host.c_str(), server.m_port, password,
-                           server.m_nickname.c_str(),
-                           server.m_username.c_str(),
-                           server.m_realname.c_str());
+        code = irc_connect(*server.session_, host.c_str(), server.port_, password,
+                           server.nickname_.c_str(),
+                           server.username_.c_str(),
+                           server.realname_.c_str());
     }
 
     return code == 0;
 }
 
-void Server::ConnectingState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd)
+void server::connecting_state::prepare(server& server, fd_set& setinput, fd_set& setoutput, net::Handle& maxfd)
 {
     /*
      * The connect function will either fail if the hostname wasn't resolved or
@@ -840,20 +862,20 @@
      *
      * Otherwise, the libircclient event_connect will change the state.
      */
-    if (m_state == Connecting) {
-        if (m_timer.elapsed() > static_cast<unsigned>(server.m_recodelay * 1000)) {
+    if (state_ == connecting) {
+        if (timer_.elapsed() > static_cast<unsigned>(server.recodelay_ * 1000)) {
             log::warning() << "server " << server.name() << ": timeout while connecting" << std::endl;
-            server.next(std::make_unique<DisconnectedState>());
-        } else if (!irc_is_connected(*server.m_session)) {
-            log::warning() << "server " << server.m_name << ": error while connecting: ";
-            log::warning() << irc_strerror(irc_errno(*server.m_session)) << std::endl;
+            server.next(std::make_unique<disconnected_state>());
+        } else if (!irc_is_connected(*server.session_)) {
+            log::warning() << "server " << server.name_ << ": error while connecting: ";
+            log::warning() << irc_strerror(irc_errno(*server.session_)) << std::endl;
 
-            if (server.m_recotries != 0)
-                log::warning("server {}: retrying in {} seconds"_format(server.m_name, server.m_recodelay));
+            if (server.recotries_ != 0)
+                log::warning("server {}: retrying in {} seconds"_format(server.name_, server.recodelay_));
 
-            server.next(std::make_unique<DisconnectedState>());
+            server.next(std::make_unique<disconnected_state>());
         } else
-            irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd));
+            irc_add_select_descriptors(*server.session_, &setinput, &setoutput, reinterpret_cast<int*>(&maxfd));
     } else {
         /*
          * This is needed if irccd is started before DHCP or if DNS cache is
@@ -862,49 +884,49 @@
 #if !defined(IRCCD_SYSTEM_WINDOWS)
         (void)res_init();
 #endif
-        log::info("server {}: trying to connect to {}, port {}"_format(server.m_name, server.m_host, server.m_port));
+        log::info("server {}: trying to connect to {}, port {}"_format(server.name_, server.host_, server.port_));
 
         if (!connect(server)) {
-            log::warning() << "server " << server.m_name << ": disconnected while connecting: ";
-            log::warning() << irc_strerror(irc_errno(*server.m_session)) << std::endl;
-            server.next(std::make_unique<DisconnectedState>());
+            log::warning() << "server " << server.name_ << ": disconnected while connecting: ";
+            log::warning() << irc_strerror(irc_errno(*server.session_)) << std::endl;
+            server.next(std::make_unique<disconnected_state>());
         } else {
-            m_state = Connecting;
+            state_ = connecting;
 
-            if (irc_is_connected(*server.m_session))
-                irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd));
+            if (irc_is_connected(*server.session_))
+                irc_add_select_descriptors(*server.session_, &setinput, &setoutput, reinterpret_cast<int*>(&maxfd));
         }
     }
 }
 
-std::string Server::ConnectingState::ident() const
+std::string server::connecting_state::ident() const
 {
     return "Connecting";
 }
 
 /*
- * Server::ConnectedState implementation
+ * server::connected_state implementation
  * ------------------------------------------------------------------
  */
 
-void Server::ConnectedState::prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd)
+void server::connected_state::prepare(server& server, fd_set& setinput, fd_set& setoutput, net::Handle& maxfd)
 {
-    if (!irc_is_connected(*server.m_session)) {
-        log::warning() << "server " << server.m_name << ": disconnected" << std::endl;
+    if (!irc_is_connected(*server.session_)) {
+        log::warning() << "server " << server.name_ << ": disconnected" << std::endl;
 
-        if (server.m_recodelay > 0)
-            log::warning("server {}: retrying in {} seconds"_format(server.m_name, server.m_recodelay));
+        if (server.recodelay_ > 0)
+            log::warning("server {}: retrying in {} seconds"_format(server.name_, server.recodelay_));
 
-        server.next(std::make_unique<DisconnectedState>());
-    } else if (server.m_timer.elapsed() >= server.m_timeout * 1000) {
-        log::warning() << "server " << server.m_name << ": ping timeout after "
-                   << (server.m_timer.elapsed() / 1000) << " seconds" << std::endl;
-        server.next(std::make_unique<DisconnectedState>());
+        server.next(std::make_unique<disconnected_state>());
+    } else if (server.timer_.elapsed() >= server.timeout_ * 1000) {
+        log::warning() << "server " << server.name_ << ": ping timeout after "
+                       << (server.timer_.elapsed() / 1000) << " seconds" << std::endl;
+        server.next(std::make_unique<disconnected_state>());
     } else
-        irc_add_select_descriptors(*server.m_session, &setinput, &setoutput, reinterpret_cast<int *>(&maxfd));
+        irc_add_select_descriptors(*server.session_, &setinput, &setoutput, reinterpret_cast<int*>(&maxfd));
 }
 
-std::string Server::ConnectedState::ident() const
+std::string server::connected_state::ident() const
 {
     return "Connected";
 }
--- a/libirccd/irccd/server.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/server.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -44,23 +44,23 @@
 
 namespace irccd {
 
-class Server;
+class server;
 
 /**
  * \brief Prefixes for nicknames.
  */
-enum class ChannelMode {
-    Creator         = 'O',                  //!< Channel creator
-    HalfOperator    = 'h',                  //!< Half operator
-    Operator        = 'o',                  //!< Channel operator
-    Protection      = 'a',                  //!< Unkillable
-    Voiced          = 'v'                   //!< Voice power
+enum class channel_mode {
+    creator         = 'O',                  //!< Channel creator
+    half_op         = 'h',                  //!< Half operator
+    op              = 'o',                  //!< Channel operator
+    protection      = 'a',                  //!< Unkillable
+    voiced          = 'v'                   //!< Voice power
 };
 
 /**
  * \brief A channel to join with an optional password.
  */
-class Channel {
+class channel {
 public:
     std::string name;                       //!< the channel to join
     std::string password;                   //!< the optional password
@@ -69,7 +69,7 @@
 /**
  * \brief Describe a whois information.
  */
-class Whois {
+class whois {
 public:
     std::string nick;                       //!< user's nickname
     std::string user;                       //!< user's user
@@ -81,9 +81,9 @@
 /**
  * \brief Channel event.
  */
-class ChannelModeEvent {
+class channel_mode_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string mode;                       //!< The mode.
@@ -93,9 +93,9 @@
 /**
  * \brief Channel notice event.
  */
-class ChannelNoticeEvent {
+class channel_notice_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string message;                    //!< The notice message.
@@ -104,17 +104,17 @@
 /**
  * \brief Connection success event.
  */
-class ConnectEvent {
+class connect_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
 };
 
 /**
  * \brief Invite event.
  */
-class InviteEvent {
+class invite_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string nickname;                   //!< The nickname (you).
@@ -123,9 +123,9 @@
 /**
  * \brief Join event.
  */
-class JoinEvent {
+class join_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
 };
@@ -133,9 +133,9 @@
 /**
  * \brief Kick event.
  */
-class KickEvent {
+class kick_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string target;                     //!< The target.
@@ -145,9 +145,9 @@
 /**
  * \brief Message event.
  */
-class MessageEvent {
+class message_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string message;                    //!< The message.
@@ -156,9 +156,9 @@
 /**
  * \brief CTCP action event.
  */
-class MeEvent {
+class me_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string message;                    //!< The message.
@@ -167,9 +167,9 @@
 /**
  * \brief Mode event.
  */
-class ModeEvent {
+class mode_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string mode;                       //!< The mode.
 };
@@ -177,9 +177,9 @@
 /**
  * \brief Names listing event.
  */
-class NamesEvent {
+class names_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string channel;                    //!< The channel.
     std::vector<std::string> names;         //!< The names.
 };
@@ -187,9 +187,9 @@
 /**
  * \brief Nick change event.
  */
-class NickEvent {
+class nick_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string nickname;                   //!< The new nickname.
 };
@@ -197,9 +197,9 @@
 /**
  * \brief Notice event.
  */
-class NoticeEvent {
+class notice_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string message;                    //!< The message.
 };
@@ -207,9 +207,9 @@
 /**
  * \brief Part event.
  */
-class PartEvent {
+class part_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string reason;                     //!< The reason.
@@ -218,9 +218,9 @@
 /**
  * \brief Query event.
  */
-class QueryEvent {
+class query_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string message;                    //!< The message.
 };
@@ -228,9 +228,9 @@
 /**
  * \brief Topic event.
  */
-class TopicEvent {
+class topic_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
+    std::shared_ptr<class server> server;   //!< The server.
     std::string origin;                     //!< The originator.
     std::string channel;                    //!< The channel.
     std::string topic;                      //!< The topic message.
@@ -239,10 +239,10 @@
 /**
  * \brief Whois event.
  */
-class WhoisEvent {
+class whois_event {
 public:
-    std::shared_ptr<Server> server;         //!< The server.
-    Whois whois;                            //!< The whois information.
+    std::shared_ptr<class server> server;   //!< The server.
+    class whois whois;                            //!< The whois information.
 };
 
 /**
@@ -261,90 +261,90 @@
  * Note: the server is set in non blocking mode, commands are placed in a queue
  * and sent when only when they are ready.
  */
-class Server : public std::enable_shared_from_this<Server> {
+class server : public std::enable_shared_from_this<server> {
 public:
     /**
      * Bridge for libircclient.
      */
-    class Session;
+    class session;
 
     /**
      * \brief Various options for server.
      */
     enum {
-        Ipv6        = (1 << 0),             //!< Connect using IPv6
-        Ssl         = (1 << 1),             //!< Use SSL
-        SslVerify   = (1 << 2),             //!< Verify SSL
-        AutoRejoin  = (1 << 3),             //!< Auto rejoin a kick
-        JoinInvite  = (1 << 4)              //!< Join a channel on invitation
+        ipv6        = (1 << 0),             //!< Connect using IPv6
+        ssl         = (1 << 1),             //!< Use SSL
+        ssl_verify  = (1 << 2),             //!< Verify SSL
+        auto_rejoin = (1 << 3),             //!< Auto rejoin a kick
+        join_invite = (1 << 4)              //!< Join a channel on invitation
     };
 
     /**
-     * Signal: onChannelMode
+     * Signal: on_channel_mode
      * ----------------------------------------------------------
      *
      * Triggered when someone changed the channel mode.
      */
-    Signal<ChannelModeEvent> onChannelMode;
+    Signal<channel_mode_event> on_channel_mode;
 
     /**
-     * Signal: onChannelNotice
+     * Signal: on_channel_notice
      * ----------------------------------------------------------
      *
      * Triggered when a notice has been sent on a channel.
      */
-    Signal<ChannelNoticeEvent> onChannelNotice;
+    Signal<channel_notice_event> on_channel_notice;
 
     /**
-     * Signal: onConnect
+     * Signal: on_connect
      * ----------------------------------------------------------
      *
      * Triggered when the server is successfully connected.
      */
-    Signal<ConnectEvent> onConnect;
+    Signal<connect_event> on_connect;
 
     /**
-     * Signal: onDie
+     * Signal: on_die
      * ----------------------------------------------------------
      *
      * The server is dead.
      */
-    Signal<> onDie;
+    Signal<> on_die;
 
     /**
-     * Signal: onInvite
+     * Signal: on_invite
      * ----------------------------------------------------------
      *
      * Triggered when an invite has been sent to you (the bot).
      */
-    Signal<InviteEvent> onInvite;
+    Signal<invite_event> on_invite;
 
     /**
-     * Signal: onJoin
+     * Signal: on_join
      * ----------------------------------------------------------
      *
      * Triggered when a user has joined the channel, it also includes you.
      */
-    Signal<JoinEvent> onJoin;
+    Signal<join_event> on_join;
 
     /**
-     * Signal: onKick
+     * Signal: on_kick
      * ----------------------------------------------------------
      *
      * Triggered when someone has been kicked from a channel.
      */
-    Signal<KickEvent> onKick;
+    Signal<kick_event> on_kick;
 
     /**
-     * ServerEvent: onMessage
+     * Signal: on_message
      * ----------------------------------------------------------
      *
      * Triggered when a message on a channel has been sent.
      */
-    Signal<MessageEvent> onMessage;
+    Signal<message_event> on_message;
 
     /**
-     * Signal: onMe
+     * Signal: on_me
      * ----------------------------------------------------------
      *
      * Triggered on a CTCP Action.
@@ -352,140 +352,140 @@
      * This is both used in a channel and in a private message so the target may
      * be a channel or your nickname.
      */
-    Signal<MeEvent> onMe;
+    Signal<me_event> on_me;
 
     /**
-     * Signal: onMode
+     * Signal: on_mode
      * ----------------------------------------------------------
      *
      * Triggered when the server changed your user mode.
      */
-    Signal<ModeEvent> onMode;
+    Signal<mode_event> on_mode;
 
     /**
-     * Signal: onNames
+     * Signal: on_names
      * ----------------------------------------------------------
      *
      * Triggered when names listing has finished on a channel.
      */
-    Signal<NamesEvent> onNames;
+    Signal<names_event> on_names;
 
     /**
-     * Signal: onNick
+     * Signal: on_nick
      * ----------------------------------------------------------
      *
      * Triggered when someone changed its nickname, it also includes you.
      */
-    Signal<NickEvent> onNick;
+    Signal<nick_event> on_nick;
 
     /**
-     * Signal: onNotice
+     * Signal: on_notice
      * ----------------------------------------------------------
      *
      * Triggered when someone has sent a notice to you.
      */
-    Signal<NoticeEvent> onNotice;
+    Signal<notice_event> on_notice;
 
     /**
-     * Signal: onPart
+     * Signal: on_part
      * ----------------------------------------------------------
      *
      * Triggered when someone has left the channel.
      */
-    Signal<PartEvent> onPart;
+    Signal<part_event> on_part;
 
     /**
-     * Signal: onQuery
+     * Signal: on_query
      * ----------------------------------------------------------
      *
      * Triggered when someone has sent you a private message.
      */
-    Signal<QueryEvent> onQuery;
+    Signal<query_event> on_query;
 
     /**
-     * Signal: onTopic
+     * Signal: on_topic
      * ----------------------------------------------------------
      *
      * Triggered when someone changed the channel topic.
      */
-    Signal<TopicEvent> onTopic;
+    Signal<topic_event> on_topic;
 
     /**
-     * Signal: onWhois
+     * Signal: on_whois
      * ----------------------------------------------------------
      *
      * Triggered when whois information has been received.
      */
-    Signal<WhoisEvent> onWhois;
+    Signal<whois_event> on_whois;
 
 private:
-    class State;
-    class ConnectedState;
-    class ConnectingState;
-    class DisconnectedState;
+    class state;
+    class connected_state;
+    class connecting_state;
+    class disconnected_state;
 
     // Requested and joined channels.
-    std::vector<Channel> m_rchannels;
-    std::vector<std::string> m_jchannels;
+    std::vector<channel> rchannels_;
+    std::vector<std::string> jchannels_;
 
     // Identifier.
-    std::string m_name;
+    std::string name_;
 
     // Connection information
-    std::string m_host;
-    std::string m_password;
-    std::uint16_t m_port{6667};
-    std::uint8_t m_flags{0};
+    std::string host_;
+    std::string password_;
+    std::uint16_t port_{6667};
+    std::uint8_t flags_{0};
 
     // Identity.
-    std::string m_nickname{"irccd"};
-    std::string m_username{"irccd"};
-    std::string m_realname{"IRC Client Daemon"};
-    std::string m_ctcpversion{"IRC Client Daemon"};
+    std::string nickname_{"irccd"};
+    std::string username_{"irccd"};
+    std::string realname_{"IRC Client Daemon"};
+    std::string ctcpversion_{"IRC Client Daemon"};
 
     // Settings.
-    std::string m_commandCharacter{"!"};
-    std::int8_t m_recotries{-1};
-    std::uint16_t m_recodelay{30};
-    std::uint16_t m_timeout{1000};
+    std::string command_char_{"!"};
+    std::int8_t recotries_{-1};
+    std::uint16_t recodelay_{30};
+    std::uint16_t timeout_{1000};
 
     // Queue of requests to send.
-    std::queue<std::function<bool ()>> m_queue;
+    std::queue<std::function<bool ()>> queue_;
 
     // libircclient session (bridge).
-    std::unique_ptr<Session> m_session;
+    std::unique_ptr<session> session_;
 
     // States.
-    std::unique_ptr<State> m_state;
-    std::unique_ptr<State> m_stateNext;
+    std::unique_ptr<state> state_;
+    std::unique_ptr<state> state_next_;
 
     // Misc.
-    ElapsedTimer m_timer;
-    std::map<ChannelMode, char> m_modes;
-    std::int8_t m_recocur{0};
-    std::map<std::string, std::set<std::string>> m_namesMap;
-    std::map<std::string, Whois> m_whoisMap;
+    ElapsedTimer timer_;
+    std::map<channel_mode, char> modes_;
+    std::int8_t recocur_{0};
+    std::map<std::string, std::set<std::string>> names_map_;
+    std::map<std::string, class whois> whois_map_;
 
     // Private helpers.
-    void removeJoinedChannel(const std::string &channel);
+    void remove_joined_channel(const std::string& channel);
 
     // Handle libircclient callbacks.
-    void handleChannel(const char *, const char **) noexcept;
-    void handleChannelMode(const char *, const char **) noexcept;
-    void handleChannelNotice(const char *, const char **) noexcept;
-    void handleConnect(const char *, const char **) noexcept;
-    void handleCtcpAction(const char *, const char **) noexcept;
-    void handleInvite(const char *, const char **) noexcept;
-    void handleJoin(const char *, const char **) noexcept;
-    void handleKick(const char *, const char **) noexcept;
-    void handleMode(const char *, const char **) noexcept;
-    void handleNick(const char *, const char **) noexcept;
-    void handleNotice(const char *, const char **) noexcept;
-    void handleNumeric(unsigned int, const char **, unsigned int) noexcept;
-    void handlePart(const char *, const char **) noexcept;
-    void handlePing(const char *, const char **) noexcept;
-    void handleQuery(const char *, const char **) noexcept;
-    void handleTopic(const char *, const char **) noexcept;
+    void handle_channel(const char*, const char**) noexcept;
+    void handle_channel_mode(const char*, const char**) noexcept;
+    void handle_channel_notice(const char*, const char**) noexcept;
+    void handle_connect(const char*, const char**) noexcept;
+    void handle_ctcp_action(const char*, const char**) noexcept;
+    void handle_invite(const char*, const char**) noexcept;
+    void handle_join(const char*, const char**) noexcept;
+    void handle_kick(const char*, const char**) noexcept;
+    void handle_mode(const char*, const char**) noexcept;
+    void handle_nick(const char*, const char**) noexcept;
+    void handle_notice(const char*, const char**) noexcept;
+    void handle_numeric(unsigned int, const char**, unsigned int) noexcept;
+    void handle_part(const char*, const char**) noexcept;
+    void handle_ping(const char*, const char**) noexcept;
+    void handle_query(const char*, const char**) noexcept;
+    void handle_topic(const char*, const char**) noexcept;
 
 public:
     /**
@@ -497,37 +497,37 @@
      * \return the server
      * \throw std::exception on failures
      */
-    IRCCD_EXPORT static std::shared_ptr<Server> fromJson(const nlohmann::json &object);
+    static std::shared_ptr<server> from_json(const nlohmann::json& object);
 
     /**
-     * Split a channel from the form channel:password into a ServerChannel
+     * Split a channel from the form channel:password into a server_channel
      * object.
      *
      * \param value the value
      * \return a channel
      */
-    IRCCD_EXPORT static Channel splitChannel(const std::string &value);
+    static channel split_channel(const std::string& value);
 
     /**
      * Construct a server.
      *
      * \param name the identifier
      */
-    IRCCD_EXPORT Server(std::string name);
+    server(std::string name);
 
     /**
      * Destructor. Close the connection if needed.
      */
-    IRCCD_EXPORT virtual ~Server();
+    virtual ~server();
 
     /**
      * Get the server identifier.
      *
      * \return the id
      */
-    inline const std::string &name() const noexcept
+    inline const std::string& name() const noexcept
     {
-        return m_name;
+        return name_;
     }
 
     /**
@@ -535,9 +535,9 @@
      *
      * \return the hostname
      */
-    inline const std::string &host() const noexcept
+    inline const std::string& host() const noexcept
     {
-        return m_host;
+        return host_;
     }
 
     /**
@@ -545,9 +545,9 @@
      *
      * \param host the hostname
      */
-    inline void setHost(std::string host) noexcept
+    inline void set_host(std::string host) noexcept
     {
-        m_host = std::move(host);
+        host_ = std::move(host);
     }
 
     /**
@@ -555,9 +555,9 @@
      *
      * \return the password
      */
-    inline const std::string &password() const noexcept
+    inline const std::string& password() const noexcept
     {
-        return m_password;
+        return password_;
     }
 
     /**
@@ -567,9 +567,9 @@
      *
      * \param password the password
      */
-    inline void setPassword(std::string password) noexcept
+    inline void set_password(std::string password) noexcept
     {
-        m_password = std::move(password);
+        password_ = std::move(password);
     }
 
     /**
@@ -579,7 +579,7 @@
      */
     inline std::uint16_t port() const noexcept
     {
-        return m_port;
+        return port_;
     }
 
     /**
@@ -587,9 +587,9 @@
      *
      * \param port the port
      */
-    inline void setPort(std::uint16_t port) noexcept
+    inline void set_port(std::uint16_t port) noexcept
     {
-        m_port = port;
+        port_ = port;
     }
 
     /**
@@ -599,20 +599,17 @@
      */
     inline std::uint8_t flags() const noexcept
     {
-        return m_flags;
+        return flags_;
     }
 
     /**
      * Set the flags.
      *
-     * \pre flags must be valid
      * \param flags the flags
      */
-    inline void setFlags(std::uint8_t flags) noexcept
+    inline void set_flags(std::uint8_t flags) noexcept
     {
-        assert(flags <= 0x1f);
-
-        m_flags = flags;
+        flags_ = flags;
     }
 
     /**
@@ -620,9 +617,9 @@
      *
      * \return the nickname
      */
-    inline const std::string &nickname() const noexcept
+    inline const std::string& nickname() const noexcept
     {
-        return m_nickname;
+        return nickname_;
     }
 
     /**
@@ -633,16 +630,16 @@
      *
      * \param nickname the nickname
      */
-    IRCCD_EXPORT virtual void setNickname(std::string nickname);
+    virtual void set_nickname(std::string nickname);
 
     /**
      * Get the username.
      *
      * \return the username
      */
-    inline const std::string &username() const noexcept
+    inline const std::string& username() const noexcept
     {
-        return m_username;
+        return username_;
     }
 
     /**
@@ -651,9 +648,9 @@
      * \param name the username
      * \note the username will be changed on the next connection
      */
-    inline void setUsername(std::string name) noexcept
+    inline void set_username(std::string name) noexcept
     {
-        m_username = std::move(name);
+        username_ = std::move(name);
     }
 
     /**
@@ -661,9 +658,9 @@
      *
      * \return the realname
      */
-    inline const std::string &realname() const noexcept
+    inline const std::string& realname() const noexcept
     {
-        return m_realname;
+        return realname_;
     }
 
     /**
@@ -672,9 +669,9 @@
      * \param realname the username
      * \note the username will be changed on the next connection
      */
-    inline void setRealname(std::string realname) noexcept
+    inline void set_realname(std::string realname) noexcept
     {
-        m_realname = std::move(realname);
+        realname_ = std::move(realname);
     }
 
     /**
@@ -682,9 +679,9 @@
      *
      * \return the CTCP version
      */
-    inline const std::string &ctcpVersion() const noexcept
+    inline const std::string& ctcp_version() const noexcept
     {
-        return m_ctcpversion;
+        return ctcpversion_;
     }
 
     /**
@@ -692,29 +689,29 @@
      *
      * \param ctcpversion the version
      */
-    IRCCD_EXPORT void setCtcpVersion(std::string ctcpversion);
+    void set_ctcp_version(std::string ctcpversion);
 
     /**
      * Get the command character.
      *
      * \return the character
      */
-    inline const std::string &commandCharacter() const noexcept
+    inline const std::string& command_char() const noexcept
     {
-        return m_commandCharacter;
+        return command_char_;
     }
 
     /**
      * Set the command character.
      *
-     * \pre !commandCharacter.empty()
-     * \param commandCharacter the command character
+     * \pre !command_char_.empty()
+     * \param command_char the command character
      */
-    inline void setCommandCharacter(std::string commandCharacter) noexcept
+    inline void set_command_char(std::string command_char) noexcept
     {
-        assert(!commandCharacter.empty());
+        assert(!command_char.empty());
 
-        m_commandCharacter = std::move(commandCharacter);
+        command_char_ = std::move(command_char);
     }
 
     /**
@@ -722,9 +719,9 @@
      *
      * \return the number of reconnections
      */
-    inline std::int8_t reconnectTries() const noexcept
+    inline std::int8_t reconnect_tries() const noexcept
     {
-        return m_recotries;
+        return recotries_;
     }
 
     /**
@@ -732,11 +729,11 @@
      *
      * A value less than 0 means infinite.
      *
-     * \param reconnectTries the number of reconnections
+     * \param reconnect_tries the number of reconnections
      */
-    inline void setReconnectTries(std::int8_t reconnectTries) noexcept
+    inline void set_reconnect_tries(std::int8_t reconnect_tries) noexcept
     {
-        m_recotries = reconnectTries;
+        recotries_ = reconnect_tries;
     }
 
     /**
@@ -744,19 +741,19 @@
      *
      * \return the number of seconds
      */
-    inline std::uint16_t reconnectDelay() const noexcept
+    inline std::uint16_t reconnect_delay() const noexcept
     {
-        return m_recodelay;
+        return recodelay_;
     }
 
     /**
      * Set the number of seconds before retrying.
      *
-     * \param reconnectDelay the number of seconds
+     * \param reconnect_delay the number of seconds
      */
-    inline void setReconnectDelay(std::uint16_t reconnectDelay) noexcept
+    inline void set_reconnect_delay(std::uint16_t reconnect_delay) noexcept
     {
-        m_recodelay = reconnectDelay;
+        recodelay_ = reconnect_delay;
     }
 
     /**
@@ -764,19 +761,19 @@
      *
      * \return the ping timeout
      */
-    inline std::uint16_t pingTimeout() const noexcept
+    inline std::uint16_t ping_timeout() const noexcept
     {
-        return m_timeout;
+        return timeout_;
     }
 
     /**
      * Set the ping timeout before considering a server as dead.
      *
-     * \param pingTimeout the delay in seconds
+     * \param ping_timeout the delay in seconds
      */
-    inline void setPingTimeout(std::uint16_t pingTimeout) noexcept
+    inline void set_ping_timeout(std::uint16_t ping_timeout) noexcept
     {
-        m_timeout = pingTimeout;
+        timeout_ = ping_timeout;
     }
 
     /**
@@ -784,9 +781,9 @@
      *
      * \return the channels
      */
-    inline const std::vector<std::string> &channels() const noexcept
+    inline const std::vector<std::string>& channels() const noexcept
     {
-        return m_jchannels;
+        return jchannels_;
     }
 
     /**
@@ -794,36 +791,36 @@
      *
      * \param state the new state
      */
-    IRCCD_EXPORT void next(std::unique_ptr<State> state) noexcept;
+    void next(std::unique_ptr<state> state) noexcept;
 
     /**
      * Get the state current id.
      *
      * \return the state id
      */
-    IRCCD_EXPORT std::string status() const noexcept;
+    std::string status() const noexcept;
 
     /**
      * Switch to next state if it has.
      */
-    IRCCD_EXPORT void update() noexcept;
+    void update() noexcept;
 
     /**
      * Force disconnection.
      */
-    IRCCD_EXPORT void disconnect() noexcept;
+    void disconnect() noexcept;
 
     /**
      * Asks for a reconnection.
      */
-    IRCCD_EXPORT virtual void reconnect() noexcept;
+    virtual void reconnect() noexcept;
 
     /**
      * Prepare the IRC session.
      *
      * \warning Not thread-safe
      */
-    IRCCD_EXPORT virtual void prepare(fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) noexcept;
+    virtual void prepare(fd_set& setinput, fd_set& setoutput, net::Handle& maxfd) noexcept;
 
     /**
      * Process incoming/outgoing data after selection.
@@ -832,7 +829,7 @@
      * \param setoutput
      * \throw any exception that have been throw from user functions
      */
-    IRCCD_EXPORT virtual void sync(fd_set &setinput, fd_set &setoutput);
+    virtual void sync(fd_set& setinput, fd_set& setoutput);
 
     /**
      * Determine if the nickname is the bot itself.
@@ -840,7 +837,7 @@
      * \param nick the nickname to check
      * \return true if it is the bot
      */
-    IRCCD_EXPORT bool isSelf(const std::string &nick) const noexcept;
+    bool is_self(const std::string& nick) const noexcept;
 
     /**
      * Change the channel mode.
@@ -848,7 +845,7 @@
      * \param channel the channel
      * \param mode the new mode
      */
-    IRCCD_EXPORT virtual void cmode(std::string channel, std::string mode);
+    virtual void cmode(std::string channel, std::string mode);
 
     /**
      * Send a channel notice.
@@ -856,7 +853,7 @@
      * \param channel the channel
      * \param message message notice
      */
-    IRCCD_EXPORT virtual void cnotice(std::string channel, std::string message);
+    virtual void cnotice(std::string channel, std::string message);
 
     /**
      * Invite a user to a channel.
@@ -864,7 +861,7 @@
      * \param target the target nickname
      * \param channel the channel
      */
-    IRCCD_EXPORT virtual void invite(std::string target, std::string channel);
+    virtual void invite(std::string target, std::string channel);
 
     /**
      * Join a channel, the password is optional and can be kept empty.
@@ -872,7 +869,7 @@
      * \param channel the channel to join
      * \param password the optional password
      */
-    IRCCD_EXPORT virtual void join(std::string channel, std::string password = "");
+    virtual void join(std::string channel, std::string password = "");
 
     /**
      * Kick someone from the channel. Please be sure to have the rights
@@ -882,7 +879,7 @@
      * \param channel from which channel
      * \param reason the optional reason
      */
-    IRCCD_EXPORT virtual void kick(std::string target, std::string channel, std::string reason = "");
+    virtual void kick(std::string target, std::string channel, std::string reason = "");
 
     /**
      * Send a CTCP Action as known as /me. The target may be either a
@@ -891,7 +888,7 @@
      * \param target the nickname or the channel
      * \param message the message
      */
-    IRCCD_EXPORT virtual void me(std::string target, std::string message);
+    virtual void me(std::string target, std::string message);
 
     /**
      * Send a message to the specified target or channel.
@@ -899,21 +896,21 @@
      * \param target the target
      * \param message the message
      */
-    IRCCD_EXPORT virtual void message(std::string target, std::string message);
+    virtual void message(std::string target, std::string message);
 
     /**
      * Change your user mode.
      *
      * \param mode the mode
      */
-    IRCCD_EXPORT virtual void mode(std::string mode);
+    virtual void mode(std::string mode);
 
     /**
      * Request the list of names.
      *
      * \param channel the channel
      */
-    IRCCD_EXPORT virtual void names(std::string channel);
+    virtual void names(std::string channel);
 
     /**
      * Send a private notice.
@@ -921,7 +918,7 @@
      * \param target the target
      * \param message the notice message
      */
-    IRCCD_EXPORT virtual void notice(std::string target, std::string message);
+    virtual void notice(std::string target, std::string message);
 
     /**
      * Part from a channel.
@@ -932,7 +929,7 @@
      * \param channel the channel to leave
      * \param reason the optional reason
      */
-    IRCCD_EXPORT virtual void part(std::string channel, std::string reason = "");
+    virtual void part(std::string channel, std::string reason = "");
 
     /**
      * Send a raw message to the IRC server. You don't need to add
@@ -941,7 +938,7 @@
      * \warning Use this function with care
      * \param raw the raw message (without `\r\n\r\n`)
      */
-    IRCCD_EXPORT virtual void send(std::string raw);
+    virtual void send(std::string raw);
 
     /**
      * Change the channel topic.
@@ -949,14 +946,14 @@
      * \param channel the channel
      * \param topic the desired topic
      */
-    IRCCD_EXPORT virtual void topic(std::string channel, std::string topic);
+    virtual void topic(std::string channel, std::string topic);
 
     /**
      * Request for whois information.
      *
      * \param target the target nickname
      */
-    IRCCD_EXPORT virtual void whois(std::string target);
+    virtual void whois(std::string target);
 };
 
 } // !irccd
--- a/libirccd/irccd/service.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/service.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -35,129 +35,129 @@
 namespace irccd {
 
 /*
- * CommandService.
+ * command_service.
  * ------------------------------------------------------------------
  */
 
-bool CommandService::contains(const std::string &name) const noexcept
+bool command_service::contains(const std::string& name) const noexcept
 {
     return find(name) != nullptr;
 }
 
-std::shared_ptr<Command> CommandService::find(const std::string &name) const noexcept
+std::shared_ptr<command> command_service::find(const std::string& name) const noexcept
 {
-    auto it = std::find_if(m_commands.begin(), m_commands.end(), [&] (const auto &cmd) {
+    auto it = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cmd) {
         return cmd->name() == name;
     });
 
-    return it == m_commands.end() ? nullptr : *it;
+    return it == commands_.end() ? nullptr : *it;
 }
 
-void CommandService::add(std::shared_ptr<Command> command)
+void command_service::add(std::shared_ptr<command> command)
 {
-    auto it = std::find_if(m_commands.begin(), m_commands.end(), [&] (const auto &cmd) {
+    auto it = std::find_if(commands_.begin(), commands_.end(), [&] (const auto& cmd) {
         return cmd->name() == command->name();
     });
 
-    if (it != m_commands.end())
+    if (it != commands_.end())
         *it = std::move(command);
     else
-        m_commands.push_back(std::move(command));
+        commands_.push_back(std::move(command));
 }
 
 /*
- * InterruptService.
+ * interrupt_service.
  * ------------------------------------------------------------------
  */
 
-InterruptService::InterruptService()
-    : m_in(AF_INET, 0)
-    , m_out(AF_INET, 0)
+interrupt_service::interrupt_service()
+    : in_(AF_INET, 0)
+    , out_(AF_INET, 0)
 {
     // Bind a socket to any port.
-    m_in.set(net::option::SockReuseAddress(true));
-    m_in.bind(net::ipv4::any(0));
-    m_in.listen(1);
+    in_.set(net::option::SockReuseAddress(true));
+    in_.bind(net::ipv4::any(0));
+    in_.listen(1);
 
     // Do the socket pair.
-    m_out.connect(net::ipv4::pton("127.0.0.1", net::ipv4::port(m_in.getsockname())));
-    m_in = m_in.accept();
-    m_out.set(net::option::SockBlockMode(false));
+    out_.connect(net::ipv4::pton("127.0.0.1", net::ipv4::port(in_.getsockname())));
+    in_ = in_.accept();
+    out_.set(net::option::SockBlockMode(false));
 }
 
-void InterruptService::prepare(fd_set &in, fd_set &, net::Handle &max)
+void interrupt_service::prepare(fd_set& in, fd_set&, net::Handle& max)
 {
-    FD_SET(m_in.handle(), &in);
+    FD_SET(in_.handle(), &in);
 
-    if (m_in.handle() > max)
-        max = m_in.handle();
+    if (in_.handle() > max)
+        max = in_.handle();
 }
 
-void InterruptService::sync(fd_set &in, fd_set &)
+void interrupt_service::sync(fd_set& in, fd_set&)
 {
-    if (FD_ISSET(m_in.handle(), &in)) {
+    if (FD_ISSET(in_.handle(), &in)) {
         static std::array<char, 32> tmp;
 
         try {
             log::debug("irccd: interrupt service recv");
-            m_in.recv(tmp.data(), 32);
-        } catch (const std::exception &ex) {
+            in_.recv(tmp.data(), 32);
+        } catch (const std::exception& ex) {
             log::warning() << "irccd: interrupt service error: " << ex.what() << std::endl;
         }
     }
 }
 
-void InterruptService::interrupt() noexcept
+void interrupt_service::interrupt() noexcept
 {
     try {
         static char byte;
 
         log::debug("irccd: interrupt service send");
-        m_out.send(&byte, 1);
-    } catch (const std::exception &ex) {
+        out_.send(&byte, 1);
+    } catch (const std::exception& ex) {
         log::warning() << "irccd: interrupt service error: " << ex.what() << std::endl;
     }
 }
 
 /*
- * PluginService.
+ * plugin_service.
  * ------------------------------------------------------------------
  */
 
-PluginService::PluginService(Irccd &irccd) noexcept
-    : m_irccd(irccd)
+plugin_service::plugin_service(irccd& irccd) noexcept
+    : irccd_(irccd)
 {
-    m_default_paths.emplace("cache", sys::cachedir());
-    m_default_paths.emplace("data", sys::datadir());
-    m_default_paths.emplace("config", sys::sysconfigdir());
+    default_paths_.emplace("cache", sys::cachedir());
+    default_paths_.emplace("data", sys::datadir());
+    default_paths_.emplace("config", sys::sysconfigdir());
 }
 
-PluginService::~PluginService()
+plugin_service::~plugin_service()
 {
-    for (const auto &plugin : m_plugins)
-        plugin->onUnload(m_irccd);
+    for (const auto& plugin : plugins_)
+        plugin->on_unload(irccd_);
 }
 
-bool PluginService::has(const std::string &name) const noexcept
+bool plugin_service::has(const std::string& name) const noexcept
 {
-    return std::count_if(m_plugins.cbegin(), m_plugins.cend(), [&] (const auto &plugin) {
+    return std::count_if(plugins_.cbegin(), plugins_.cend(), [&] (const auto& plugin) {
         return plugin->name() == name;
     }) > 0;
 }
 
-std::shared_ptr<Plugin> PluginService::get(const std::string &name) const noexcept
+std::shared_ptr<plugin> plugin_service::get(const std::string& name) const noexcept
 {
-    auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) {
+    auto it = std::find_if(plugins_.begin(), plugins_.end(), [&] (const auto& plugin) {
         return plugin->name() == name;
     });
 
-    if (it == m_plugins.end())
+    if (it == plugins_.end())
         return nullptr;
 
     return *it;
 }
 
-std::shared_ptr<Plugin> PluginService::require(const std::string &name) const
+std::shared_ptr<plugin> plugin_service::require(const std::string& name) const
 {
     auto plugin = get(name);
 
@@ -167,84 +167,84 @@
     return plugin;
 }
 
-void PluginService::add(std::shared_ptr<Plugin> plugin)
+void plugin_service::add(std::shared_ptr<plugin> plugin)
 {
-    m_plugins.push_back(std::move(plugin));
+    plugins_.push_back(std::move(plugin));
 }
 
-void PluginService::addLoader(std::unique_ptr<PluginLoader> loader)
+void plugin_service::add_loader(std::unique_ptr<plugin_loader> loader)
 {
-    m_loaders.push_back(std::move(loader));
+    loaders_.push_back(std::move(loader));
 }
 
-void PluginService::setConfig(const std::string &name, PluginConfig config)
+void plugin_service::set_config(const std::string& name, plugin_config config)
 {
-    m_config.emplace(name, std::move(config));
+    config_.emplace(name, std::move(config));
 }
 
-PluginConfig PluginService::config(const std::string &name) const
+plugin_config plugin_service::config(const std::string& name) const
 {
-    auto it = m_config.find(name);
+    auto it = config_.find(name);
 
-    if (it != m_config.end())
+    if (it != config_.end())
         return it->second;
 
-    return PluginConfig();
+    return plugin_config();
 }
 
-void PluginService::setFormats(const std::string &name, PluginFormats formats)
+void plugin_service::set_formats(const std::string& name, plugin_formats formats)
 {
-    m_formats.emplace(name, std::move(formats));
+    formats_.emplace(name, std::move(formats));
 }
 
-PluginFormats PluginService::formats(const std::string &name) const
+plugin_formats plugin_service::formats(const std::string& name) const
 {
-    auto it = m_formats.find(name);
+    auto it = formats_.find(name);
 
-    if (it != m_formats.end())
+    if (it != formats_.end())
         return it->second;
 
-    return PluginFormats();
+    return plugin_formats();
 }
 
-const PluginPaths& PluginService::paths() const noexcept
+const plugin_paths& plugin_service::paths() const noexcept
 {
-    return m_default_paths;
+    return default_paths_;
 }
 
-PluginPaths PluginService::paths(const std::string& name) const
+plugin_paths plugin_service::paths(const std::string& name) const
 {
-    auto result = m_default_paths;
-    auto overriden = m_paths.find(name);
+    auto result = default_paths_;
+    auto overriden = paths_.find(name);
 
     // For all default paths, append the plugin name.
     for (auto& pair : result)
         pair.second += "/plugin/"s + name;
 
     // Now, mere overriden paths.
-    if (overriden != m_paths.end())
+    if (overriden != paths_.end())
         for (const auto& pair : overriden->second)
             result[pair.first] = pair.second;
 
     return result;
 }
 
-void PluginService::setPaths(PluginPaths paths)
+void plugin_service::set_paths(plugin_paths paths)
 {
     // If the paths is empty or not complete, do not erase default items.
     for (const auto& pair : paths)
-        m_default_paths[pair.first] = pair.second;
+        default_paths_[pair.first] = pair.second;
 }
 
-void PluginService::setPaths(const std::string& name, PluginPaths paths)
+void plugin_service::set_paths(const std::string& name, plugin_paths paths)
 {
-    m_paths.emplace(name, std::move(paths));
+    paths_.emplace(name, std::move(paths));
 }
 
-std::shared_ptr<Plugin> PluginService::open(const std::string &id,
-                                            const std::string &path)
+std::shared_ptr<plugin> plugin_service::open(const std::string& id,
+                                             const std::string& path)
 {
-    for (const auto &loader : m_loaders) {
+    for (const auto& loader : loaders_) {
         auto plugin = loader->open(id, path);
 
         if (plugin)
@@ -254,9 +254,9 @@
     return nullptr;
 }
 
-std::shared_ptr<Plugin> PluginService::find(const std::string &id)
+std::shared_ptr<plugin> plugin_service::find(const std::string& id)
 {
-    for (const auto &loader : m_loaders) {
+    for (const auto& loader : loaders_) {
         auto plugin = loader->find(id);
 
         if (plugin)
@@ -266,13 +266,13 @@
     return nullptr;
 }
 
-void PluginService::load(std::string name, std::string path)
+void plugin_service::load(std::string name, std::string path)
 {
     if (has(name))
         return;
 
     try {
-        std::shared_ptr<Plugin> plugin;
+        std::shared_ptr<plugin> plugin;
 
         if (path.empty())
             plugin = find(name);
@@ -280,83 +280,83 @@
             plugin = open(name, std::move(path));
 
         if (plugin) {
-            plugin->setConfig(m_config[name]);
-            plugin->setFormats(m_formats[name]);
-            plugin->setPaths(paths(name));
-            plugin->onLoad(m_irccd);
+            plugin->set_config(config_[name]);
+            plugin->set_formats(formats_[name]);
+            plugin->set_paths(paths(name));
+            plugin->on_load(irccd_);
 
             add(std::move(plugin));
         }
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         log::warning("plugin {}: {}"_format(name, ex.what()));
     }
 }
 
-void PluginService::reload(const std::string &name)
+void plugin_service::reload(const std::string& name)
 {
     auto plugin = get(name);
 
     if (plugin)
-        plugin->onReload(m_irccd);
+        plugin->on_reload(irccd_);
 }
 
-void PluginService::unload(const std::string &name)
+void plugin_service::unload(const std::string& name)
 {
-    auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) {
+    auto it = std::find_if(plugins_.begin(), plugins_.end(), [&] (const auto& plugin) {
         return plugin->name() == name;
     });
 
-    if (it != m_plugins.end()) {
-        (*it)->onUnload(m_irccd);
-        m_plugins.erase(it);
+    if (it != plugins_.end()) {
+        (*it)->on_unload(irccd_);
+        plugins_.erase(it);
     }
 }
 
 /*
- * RuleService.
+ * rule_service.
  * ------------------------------------------------------------------
  */
 
-void RuleService::add(Rule rule)
+void rule_service::add(rule rule)
 {
-    m_rules.push_back(std::move(rule));
+    rules_.push_back(std::move(rule));
 }
 
-void RuleService::insert(Rule rule, unsigned position)
+void rule_service::insert(rule rule, unsigned position)
 {
-    assert(position <= m_rules.size());
+    assert(position <= rules_.size());
 
-    m_rules.insert(m_rules.begin() + position, std::move(rule));
+    rules_.insert(rules_.begin() + position, std::move(rule));
 }
 
-void RuleService::remove(unsigned position)
+void rule_service::remove(unsigned position)
 {
-    assert(position < m_rules.size());
+    assert(position < rules_.size());
 
-    m_rules.erase(m_rules.begin() + position);
+    rules_.erase(rules_.begin() + position);
 }
 
-const Rule &RuleService::require(unsigned position) const
+const rule &rule_service::require(unsigned position) const
 {
-    if (position >= m_rules.size())
+    if (position >= rules_.size())
         throw std::out_of_range("rule " + std::to_string(position) + " does not exist");
 
-    return m_rules[position];
+    return rules_[position];
 }
 
-Rule &RuleService::require(unsigned position)
+rule &rule_service::require(unsigned position)
 {
-    if (position >= m_rules.size())
+    if (position >= rules_.size())
         throw std::out_of_range("rule " + std::to_string(position) + " does not exist");
 
-    return m_rules[position];
+    return rules_[position];
 }
 
-bool RuleService::solve(const std::string &server,
-                        const std::string &channel,
-                        const std::string &origin,
-                        const std::string &plugin,
-                        const std::string &event) noexcept
+bool rule_service::solve(const std::string& server,
+                         const std::string& channel,
+                         const std::string& origin,
+                         const std::string& plugin,
+                         const std::string& event) noexcept
 {
     bool result = true;
 
@@ -364,60 +364,59 @@
            origin, plugin, event));
 
     int i = 0;
-    for (const Rule &rule : m_rules) {
+    for (const auto& rule : rules_) {
         log::debug() << "  candidate " << i++ << ":\n"
-                 << "    servers: " << util::join(rule.servers().begin(), rule.servers().end()) << "\n"
-                 << "    channels: " << util::join(rule.channels().begin(), rule.channels().end()) << "\n"
-                 << "    origins: " << util::join(rule.origins().begin(), rule.origins().end()) << "\n"
-                 << "    plugins: " << util::join(rule.plugins().begin(), rule.plugins().end()) << "\n"
-                 << "    events: " << util::join(rule.events().begin(), rule.events().end()) << "\n"
-                 << "    action: " << ((rule.action() == RuleAction::Accept) ? "accept" : "drop") << std::endl;
+                     << "    servers: " << util::join(rule.servers().begin(), rule.servers().end()) << "\n"
+                     << "    channels: " << util::join(rule.channels().begin(), rule.channels().end()) << "\n"
+                     << "    origins: " << util::join(rule.origins().begin(), rule.origins().end()) << "\n"
+                     << "    plugins: " << util::join(rule.plugins().begin(), rule.plugins().end()) << "\n"
+                     << "    events: " << util::join(rule.events().begin(), rule.events().end()) << "\n"
+                     << "    action: " << ((rule.action() == rule::action_type::accept) ? "accept" : "drop") << std::endl;
 
         if (rule.match(server, channel, origin, plugin, event))
-            result = rule.action() == RuleAction::Accept;
+            result = rule.action() == rule::action_type::accept;
     }
 
     return result;
 }
 
 /*
- * ServerService.
+ * server_service.
  * ------------------------------------------------------------------
  */
 
-class EventHandler {
+class event_handler {
 public:
     std::string server;
     std::string origin;
     std::string target;
-    std::function<std::string (Plugin &)> functionName;
-    std::function<void (Plugin &)> functionExec;
+    std::function<std::string (plugin &)> function_name;
+    std::function<void (plugin &)> function_exec;
 
-    void operator()(Irccd &irccd) const
+    void operator()(irccd& irccd) const
     {
-        for (auto &plugin : irccd.plugins().list()) {
-            auto eventname = functionName(*plugin);
+        for (auto& plugin : irccd.plugins().list()) {
+            auto eventname = function_name(*plugin);
             auto allowed = irccd.rules().solve(server, target, origin, plugin->name(), eventname);
 
             if (!allowed) {
                 log::debug() << "rule: event skipped on match" << std::endl;
                 continue;
-            } else
-                log::debug() << "rule: event allowed" << std::endl;
+            }
+
+            log::debug() << "rule: event allowed" << std::endl;
 
-            // TODO: server-event must not know which type of plugin.
-            // TODO: get generic error.
-            // TODO: this is the responsability of service-plugin.
+            // TODO: this is the responsability of plugin_service.
             try {
-                functionExec(*plugin);
-            } catch (const std::exception &ex) {
+                function_exec(*plugin);
+            } catch (const std::exception& ex) {
                 log::warning() << "plugin " << plugin->name() << ": error: " << ex.what() << std::endl;
             }
         }
     }
 };
 
-void ServerService::handleChannelMode(const ChannelModeEvent &ev)
+void server_service::handle_channel_mode(const channel_mode_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onChannelMode:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
@@ -425,7 +424,7 @@
     log::debug() << "  mode: " << ev.mode << "\n";
     log::debug() << "  argument: " << ev.argument << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onChannelMode"     },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -434,24 +433,24 @@
         { "argument",   ev.argument         }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onChannelMode";
         },
-        [=] (Plugin &plugin) {
-            plugin.onChannelMode(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_channel_mode(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleChannelNotice(const ChannelNoticeEvent &ev)
+void server_service::handle_channel_notice(const channel_notice_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onChannelNotice:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  channel: " << ev.channel << "\n";
     log::debug() << "  message: " << ev.message << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onChannelNotice"   },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -459,83 +458,83 @@
         { "message",    ev.message          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onChannelNotice";
         },
-        [=] (Plugin &plugin) {
-            plugin.onChannelNotice(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_channel_notice(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleConnect(const ConnectEvent &ev)
+void server_service::handle_connect(const connect_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onConnect" << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onConnect"         },
         { "server",     ev.server->name()   }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), /* origin */ "", /* channel */ "",
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), /* origin */ "", /* channel */ "",
+        [=] (plugin&) -> std::string {
             return "onConnect";
         },
-        [=] (Plugin &plugin) {
-            plugin.onConnect(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_connect(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleInvite(const InviteEvent &ev)
+void server_service::handle_invite(const invite_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onInvite:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  channel: " << ev.channel << "\n";
     log::debug() << "  target: " << ev.nickname << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onInvite"          },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
         { "channel",    ev.channel          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onInvite";
         },
-        [=] (Plugin &plugin) {
-            plugin.onInvite(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_invite(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleJoin(const JoinEvent &ev)
+void server_service::handle_join(const join_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onJoin:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  channel: " << ev.channel << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onJoin"            },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
         { "channel",    ev.channel          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onJoin";
         },
-        [=] (Plugin &plugin) {
-            plugin.onJoin(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_join(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleKick(const KickEvent &ev)
+void server_service::handle_kick(const kick_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onKick:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
@@ -543,7 +542,7 @@
     log::debug() << "  target: " << ev.target << "\n";
     log::debug() << "  reason: " << ev.reason << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onKick"            },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -552,24 +551,24 @@
         { "reason",     ev.reason           }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onKick";
         },
-        [=] (Plugin &plugin) {
-            plugin.onKick(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_kick(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleMessage(const MessageEvent &ev)
+void server_service::handle_message(const message_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onMessage:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  channel: " << ev.channel << "\n";
     log::debug() << "  message: " << ev.message << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onMessage"         },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -577,32 +576,36 @@
         { "message",    ev.message          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &plugin) -> std::string {
-            return util::parseMessage(ev.message, ev.server->commandCharacter(), plugin.name()).second == util::MessageType::Command ? "onCommand" : "onMessage";
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin& plugin) -> std::string {
+            return util::parse_message(
+                ev.message,
+                ev.server->command_char(),
+                plugin.name()
+            ).type == util::message_pack::type::command ? "onCommand" : "onMessage";
         },
-        [=] (Plugin &plugin) mutable {
+        [=] (plugin& plugin) mutable {
             auto copy = ev;
-            auto pack = util::parseMessage(copy.message, copy.server->commandCharacter(), plugin.name());
+            auto pack = util::parse_message(copy.message, copy.server->command_char(), plugin.name());
 
-            copy.message = pack.first;
+            copy.message = pack.message;
 
-            if (pack.second == util::MessageType::Command)
-                plugin.onCommand(m_irccd, copy);
+            if (pack.type == util::message_pack::type::command)
+                plugin.on_command(irccd_, copy);
             else
-                plugin.onMessage(m_irccd, copy);
+                plugin.on_message(irccd_, copy);
         }
     });
 }
 
-void ServerService::handleMe(const MeEvent &ev)
+void server_service::handle_me(const me_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onMe:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  target: " << ev.channel << "\n";
     log::debug() << "  message: " << ev.message << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onMe"              },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -610,40 +613,40 @@
         { "message",    ev.message          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onMe";
         },
-        [=] (Plugin &plugin) {
-            plugin.onMe(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_me(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleMode(const ModeEvent &ev)
+void server_service::handle_mode(const mode_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onMode\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  mode: " << ev.mode << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onMode"            },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
         { "mode",       ev.mode             }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, /* channel */ "",
+        [=] (plugin &) -> std::string {
             return "onMode";
         },
-        [=] (Plugin &plugin) {
-            plugin.onMode(m_irccd, ev);
+        [=] (plugin &plugin) {
+            plugin.on_mode(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleNames(const NamesEvent &ev)
+void server_service::handle_names(const names_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onNames:\n";
     log::debug() << "  channel: " << ev.channel << "\n";
@@ -651,80 +654,80 @@
 
     auto names = nlohmann::json::array();
 
-    for (const auto &v : ev.names)
+    for (const auto& v : ev.names)
         names.push_back(v);
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onNames"           },
         { "server",     ev.server->name()   },
         { "channel",    ev.channel          },
         { "names",      std::move(names)    }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), /* origin */ "", ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), /* origin */ "", ev.channel,
+        [=] (plugin&) -> std::string {
             return "onNames";
         },
-        [=] (Plugin &plugin) {
-            plugin.onNames(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_names(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleNick(const NickEvent &ev)
+void server_service::handle_nick(const nick_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onNick:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  nickname: " << ev.nickname << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onNick"            },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
         { "nickname",   ev.nickname         }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, /* channel */ "",
+        [=] (plugin&) -> std::string {
             return "onNick";
         },
-        [=] (Plugin &plugin) {
-            plugin.onNick(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_nick(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleNotice(const NoticeEvent &ev)
+void server_service::handle_notice(const notice_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onNotice:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  message: " << ev.message << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onNotice"          },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
         { "message",    ev.message          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, /* channel */ "",
+        [=] (plugin&) -> std::string {
             return "onNotice";
         },
-        [=] (Plugin &plugin) {
-            plugin.onNotice(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_notice(irccd_, ev);
         }
     });
 }
 
-void ServerService::handlePart(const PartEvent &ev)
+void server_service::handle_part(const part_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onPart:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  channel: " << ev.channel << "\n";
     log::debug() << "  reason: " << ev.reason << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onPart"            },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -732,55 +735,59 @@
         { "reason",     ev.reason           }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onPart";
         },
-        [=] (Plugin &plugin) {
-            plugin.onPart(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_part(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleQuery(const QueryEvent &ev)
+void server_service::handle_query(const query_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onQuery:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  message: " << ev.message << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onQuery"           },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
         { "message",    ev.message          }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
-        [=] (Plugin &plugin) -> std::string {
-            return util::parseMessage(ev.message, ev.server->commandCharacter(), plugin.name()).second == util::MessageType::Command ? "onQueryCommand" : "onQuery";
+    irccd_.post(event_handler{ev.server->name(), ev.origin, /* channel */ "",
+        [=] (plugin& plugin) -> std::string {
+            return util::parse_message(
+                ev.message,
+                ev.server->command_char(),
+                plugin.name()
+            ).type == util::message_pack::type::command ? "onQueryCommand" : "onQuery";
         },
-        [=] (Plugin &plugin) mutable {
+        [=] (plugin& plugin) mutable {
             auto copy = ev;
-            auto pack = util::parseMessage(copy.message, copy.server->commandCharacter(), plugin.name());
+            auto pack = util::parse_message(copy.message, copy.server->command_char(), plugin.name());
 
-            copy.message = pack.first;
+            copy.message = pack.message;
 
-            if (pack.second == util::MessageType::Command)
-                plugin.onQueryCommand(m_irccd, copy);
+            if (pack.type == util::message_pack::type::command)
+                plugin.on_query_command(irccd_, copy);
             else
-                plugin.onQuery(m_irccd, copy);
+                plugin.on_query(irccd_, copy);
         }
     });
 }
 
-void ServerService::handleTopic(const TopicEvent &ev)
+void server_service::handle_topic(const topic_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onTopic:\n";
     log::debug() << "  origin: " << ev.origin << "\n";
     log::debug() << "  channel: " << ev.channel << "\n";
     log::debug() << "  topic: " << ev.topic << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onTopic"           },
         { "server",     ev.server->name()   },
         { "origin",     ev.origin           },
@@ -788,17 +795,17 @@
         { "topic",      ev.topic            }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), ev.origin, ev.channel,
+        [=] (plugin&) -> std::string {
             return "onTopic";
         },
-        [=] (Plugin &plugin) {
-            plugin.onTopic(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_topic(irccd_, ev);
         }
     });
 }
 
-void ServerService::handleWhois(const WhoisEvent &ev)
+void server_service::handle_whois(const whois_event& ev)
 {
     log::debug() << "server " << ev.server->name() << ": event onWhois\n";
     log::debug() << "  nickname: " << ev.whois.nick << "\n";
@@ -807,7 +814,7 @@
     log::debug() << "  realname: " << ev.whois.realname << "\n";
     log::debug() << "  channels: " << util::join(ev.whois.channels.begin(), ev.whois.channels.end()) << std::endl;
 
-    m_irccd.transports().broadcast(nlohmann::json::object({
+    irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onWhois"           },
         { "server",     ev.server->name()   },
         { "nickname",   ev.whois.nick       },
@@ -816,93 +823,93 @@
         { "realname",   ev.whois.realname   }
     }));
 
-    m_irccd.post(EventHandler{ev.server->name(), /* origin */ "", /* channel */ "",
-        [=] (Plugin &) -> std::string {
+    irccd_.post(event_handler{ev.server->name(), /* origin */ "", /* channel */ "",
+        [=] (plugin&) -> std::string {
             return "onWhois";
         },
-        [=] (Plugin &plugin) {
-            plugin.onWhois(m_irccd, ev);
+        [=] (plugin& plugin) {
+            plugin.on_whois(irccd_, ev);
         }
     });
 }
 
-ServerService::ServerService(Irccd &irccd)
-    : m_irccd(irccd)
+server_service::server_service(irccd &irccd)
+    : irccd_(irccd)
 {
 }
 
-void ServerService::prepare(fd_set &in, fd_set &out, net::Handle &max)
+void server_service::prepare(fd_set& in, fd_set& out, net::Handle& max)
 {
-    for (auto &server : m_servers) {
+    for (auto& server : servers_) {
         server->update();
         server->prepare(in, out, max);
     }
 }
 
-void ServerService::sync(fd_set &in, fd_set &out)
+void server_service::sync(fd_set& in, fd_set& out)
 {
-    for (auto &server : m_servers)
+    for (auto& server : servers_)
         server->sync(in, out);
 }
 
-bool ServerService::has(const std::string &name) const noexcept
+bool server_service::has(const std::string& name) const noexcept
 {
-    return std::count_if(m_servers.cbegin(), m_servers.end(), [&] (const auto &server) {
+    return std::count_if(servers_.cbegin(), servers_.end(), [&] (const auto& server) {
         return server->name() == name;
     }) > 0;
 }
 
-void ServerService::add(std::shared_ptr<Server> server)
+void server_service::add(std::shared_ptr<server> server)
 {
     assert(!has(server->name()));
 
     using namespace std::placeholders;
 
-    std::weak_ptr<Server> ptr(server);
+    std::weak_ptr<class server> ptr(server);
 
-    server->onChannelMode.connect(std::bind(&ServerService::handleChannelMode, this, _1));
-    server->onChannelNotice.connect(std::bind(&ServerService::handleChannelNotice, this, _1));
-    server->onConnect.connect(std::bind(&ServerService::handleConnect, this, _1));
-    server->onInvite.connect(std::bind(&ServerService::handleInvite, this, _1));
-    server->onJoin.connect(std::bind(&ServerService::handleJoin, this, _1));
-    server->onKick.connect(std::bind(&ServerService::handleKick, this, _1));
-    server->onMessage.connect(std::bind(&ServerService::handleMessage, this, _1));
-    server->onMe.connect(std::bind(&ServerService::handleMe, this, _1));
-    server->onMode.connect(std::bind(&ServerService::handleMode, this, _1));
-    server->onNames.connect(std::bind(&ServerService::handleNames, this, _1));
-    server->onNick.connect(std::bind(&ServerService::handleNick, this, _1));
-    server->onNotice.connect(std::bind(&ServerService::handleNotice, this, _1));
-    server->onPart.connect(std::bind(&ServerService::handlePart, this, _1));
-    server->onQuery.connect(std::bind(&ServerService::handleQuery, this, _1));
-    server->onTopic.connect(std::bind(&ServerService::handleTopic, this, _1));
-    server->onWhois.connect(std::bind(&ServerService::handleWhois, this, _1));
-    server->onDie.connect([this, ptr] () {
-        m_irccd.post([=] (Irccd &) {
+    server->on_channel_mode.connect(std::bind(&server_service::handle_channel_mode, this, _1));
+    server->on_channel_notice.connect(std::bind(&server_service::handle_channel_notice, this, _1));
+    server->on_connect.connect(std::bind(&server_service::handle_connect, this, _1));
+    server->on_invite.connect(std::bind(&server_service::handle_invite, this, _1));
+    server->on_join.connect(std::bind(&server_service::handle_join, this, _1));
+    server->on_kick.connect(std::bind(&server_service::handle_kick, this, _1));
+    server->on_message.connect(std::bind(&server_service::handle_message, this, _1));
+    server->on_me.connect(std::bind(&server_service::handle_me, this, _1));
+    server->on_mode.connect(std::bind(&server_service::handle_mode, this, _1));
+    server->on_names.connect(std::bind(&server_service::handle_names, this, _1));
+    server->on_nick.connect(std::bind(&server_service::handle_nick, this, _1));
+    server->on_notice.connect(std::bind(&server_service::handle_notice, this, _1));
+    server->on_part.connect(std::bind(&server_service::handle_part, this, _1));
+    server->on_query.connect(std::bind(&server_service::handle_query, this, _1));
+    server->on_topic.connect(std::bind(&server_service::handle_topic, this, _1));
+    server->on_whois.connect(std::bind(&server_service::handle_whois, this, _1));
+    server->on_die.connect([this, ptr] () {
+        irccd_.post([=] (irccd&) {
             auto server = ptr.lock();
 
             if (server) {
                 log::info("server {}: removed"_format(server->name()));
-                m_servers.erase(std::find(m_servers.begin(), m_servers.end(), server));
+                servers_.erase(std::find(servers_.begin(), servers_.end(), server));
             }
         });
     });
 
-    m_servers.push_back(std::move(server));
+    servers_.push_back(std::move(server));
 }
 
-std::shared_ptr<Server> ServerService::get(const std::string &name) const noexcept
+std::shared_ptr<server> server_service::get(const std::string& name) const noexcept
 {
-    auto it = std::find_if(m_servers.begin(), m_servers.end(), [&] (const auto &server) {
+    auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
         return server->name() == name;
     });
 
-    if (it == m_servers.end())
+    if (it == servers_.end())
         return nullptr;
 
     return *it;
 }
 
-std::shared_ptr<Server> ServerService::require(const std::string &name) const
+std::shared_ptr<server> server_service::require(const std::string& name) const
 {
     auto server = get(name);
 
@@ -912,36 +919,36 @@
     return server;
 }
 
-void ServerService::remove(const std::string &name)
+void server_service::remove(const std::string& name)
 {
-    auto it = std::find_if(m_servers.begin(), m_servers.end(), [&] (const auto &server) {
+    auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
         return server->name() == name;
     });
 
-    if (it != m_servers.end()) {
+    if (it != servers_.end()) {
         (*it)->disconnect();
-        m_servers.erase(it);
+        servers_.erase(it);
     }
 }
 
-void ServerService::clear() noexcept
+void server_service::clear() noexcept
 {
-    for (auto &server : m_servers)
+    for (auto &server : servers_)
         server->disconnect();
 
-    m_servers.clear();
+    servers_.clear();
 }
 
 /*
- * TransportService.
+ * transport_service.
  * ------------------------------------------------------------------
  */
 
-void TransportService::handleCommand(std::weak_ptr<TransportClient> ptr, const nlohmann::json &object)
+void transport_service::handle_command(std::weak_ptr<transport_client> ptr, const nlohmann::json& object)
 {
     assert(object.is_object());
 
-    m_irccd.post([=] (Irccd &) {
+    irccd_.post([=] (irccd&) {
         // 0. Be sure the object still exists.
         auto tc = ptr.lock();
 
@@ -955,41 +962,41 @@
             return;
         }
 
-        auto cmd = m_irccd.commands().find(*name);
+        auto cmd = irccd_.commands().find(*name);
 
         if (!cmd)
             tc->error(*name, "command does not exist");
         else {
             try {
-                cmd->exec(m_irccd, *tc, object);
-            } catch (const std::exception &ex) {
+                cmd->exec(irccd_, *tc, object);
+            } catch (const std::exception& ex) {
                 tc->error(cmd->name(), ex.what());
             }
         }
     });
 }
 
-void TransportService::handleDie(std::weak_ptr<TransportClient> ptr)
+void transport_service::handle_die(std::weak_ptr<transport_client> ptr)
 {
-    m_irccd.post([=] (Irccd &) {
+    irccd_.post([=] (irccd &) {
         log::info("transport: client disconnected");
 
         auto tc = ptr.lock();
 
         if (tc)
-            m_clients.erase(std::find(m_clients.begin(), m_clients.end(), tc));
+            clients_.erase(std::find(clients_.begin(), clients_.end(), tc));
     });
 }
 
-TransportService::TransportService(Irccd &irccd) noexcept
-    : m_irccd(irccd)
+transport_service::transport_service(irccd& irccd) noexcept
+    : irccd_(irccd)
 {
 }
 
-void TransportService::prepare(fd_set &in, fd_set &out, net::Handle &max)
+void transport_service::prepare(fd_set& in, fd_set& out, net::Handle& max)
 {
     // Add transport servers.
-    for (const auto &transport : m_servers) {
+    for (const auto& transport : servers_) {
         FD_SET(transport->handle(), &in);
 
         if (transport->handle() > max)
@@ -997,58 +1004,58 @@
     }
 
     // Transport clients.
-    for (const auto &client : m_clients)
+    for (const auto& client : clients_)
         client->prepare(in, out, max);
 }
 
-void TransportService::sync(fd_set &in, fd_set &out)
+void transport_service::sync(fd_set& in, fd_set& out)
 {
     using namespace std::placeholders;
 
     // Transport clients.
-    for (const auto &client : m_clients) {
+    for (const auto& client : clients_) {
         try {
             client->sync(in, out);
-        } catch (const std::exception &ex) {
+        } catch (const std::exception& ex) {
             log::info() << "transport: client disconnected: " << ex.what() << std::endl;
-            handleDie(client);
+            handle_die(client);
         }
     }
 
     // Transport servers.
-    for (const auto &transport : m_servers) {
+    for (const auto& transport : servers_) {
         if (!FD_ISSET(transport->handle(), &in))
             continue;
 
         log::debug("transport: new client connected");
 
-        std::shared_ptr<TransportClient> client = transport->accept();
-        std::weak_ptr<TransportClient> ptr(client);
+        std::shared_ptr<transport_client> client = transport->accept();
+        std::weak_ptr<transport_client> ptr(client);
 
         try {
             // Connect signals.
-            client->onCommand.connect(std::bind(&TransportService::handleCommand, this, ptr, _1));
-            client->onDie.connect(std::bind(&TransportService::handleDie, this, ptr));
+            client->on_command.connect(std::bind(&transport_service::handle_command, this, ptr, _1));
+            client->on_die.connect(std::bind(&transport_service::handle_die, this, ptr));
 
             // Register it.
-            m_clients.push_back(std::move(client));
-        } catch (const std::exception &ex) {
+            clients_.push_back(std::move(client));
+        } catch (const std::exception& ex) {
             log::info() << "transport: client disconnected: " << ex.what() << std::endl;
         }
     }
 }
 
-void TransportService::add(std::shared_ptr<TransportServer> ts)
+void transport_service::add(std::shared_ptr<transport_server> ts)
 {
-    m_servers.push_back(std::move(ts));
+    servers_.push_back(std::move(ts));
 }
 
-void TransportService::broadcast(const nlohmann::json &json)
+void transport_service::broadcast(const nlohmann::json& json)
 {
     assert(json.is_object());
 
-    for (const auto &client : m_clients)
-        if (client->state() == TransportClient::Ready)
+    for (const auto& client : clients_)
+        if (client->state() == transport_client::state::ready)
             client->send(json);
 }
 
--- a/libirccd/irccd/service.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/service.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,7 @@
 
 /**
  * \file service.hpp
- * \brief Irccd services.
+ * \brief irccd services.
  */
 
 #include <memory>
@@ -40,7 +40,7 @@
 namespace irccd {
 
 /*
- * CommandService.
+ * command_service.
  * ------------------------------------------------------------------
  */
 
@@ -48,9 +48,9 @@
  * \brief Store remote commands.
  * \ingroup services
  */
-class CommandService {
+class command_service {
 private:
-    std::vector<std::shared_ptr<Command>> m_commands;
+    std::vector<std::shared_ptr<command>> commands_;
 
 public:
     /**
@@ -58,9 +58,9 @@
      *
      * \return the list of commands.
      */
-    inline const std::vector<std::shared_ptr<Command>> &commands() const noexcept
+    inline const std::vector<std::shared_ptr<command>>& commands() const noexcept
     {
-        return m_commands;
+        return commands_;
     }
 
     /**
@@ -69,7 +69,7 @@
      * \param name the command name
      * \return true if the command exists
      */
-    IRCCD_EXPORT bool contains(const std::string &name) const noexcept;
+    bool contains(const std::string& name) const noexcept;
 
     /**
      * Find a command by name.
@@ -77,7 +77,7 @@
      * \param name the command name
      * \return the command or empty one if not found
      */
-    IRCCD_EXPORT std::shared_ptr<Command> find(const std::string &name) const noexcept;
+    std::shared_ptr<command> find(const std::string& name) const noexcept;
 
     /**
      * Add a command or replace existing one.
@@ -85,11 +85,11 @@
      * \pre command != nullptr
      * \param command the command name
      */
-    IRCCD_EXPORT void add(std::shared_ptr<Command> command);
+    void add(std::shared_ptr<command> command);
 };
 
 /*
- * InterruptService.
+ * interrupt_service.
  * ------------------------------------------------------------------
  */
 
@@ -97,10 +97,10 @@
  * \brief Interrupt irccd event loop.
  * \ingroup services
  */
-class InterruptService {
+class interrupt_service {
 private:
-    net::TcpSocket m_in;
-    net::TcpSocket m_out;
+    net::TcpSocket in_;
+    net::TcpSocket out_;
 
 public:
     /**
@@ -108,26 +108,26 @@
      *
      * \throw std::runtime_error on errors
      */
-    IRCCD_EXPORT InterruptService();
+    interrupt_service();
 
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
+    void prepare(fd_set& in, fd_set& out, net::Handle& max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
+    void sync(fd_set& in, fd_set& out);
 
     /**
      * Request interruption.
      */
-    IRCCD_EXPORT void interrupt() noexcept;
+    void interrupt() noexcept;
 };
 
 /*
- * PluginService.
+ * plugin_service.
  * ------------------------------------------------------------------
  */
 
@@ -135,15 +135,15 @@
  * \brief Manage plugins.
  * \ingroup services
  */
-class PluginService {
+class plugin_service {
 private:
-    Irccd &m_irccd;
-    PluginPaths m_default_paths;
-    std::vector<std::shared_ptr<Plugin>> m_plugins;
-    std::vector<std::unique_ptr<PluginLoader>> m_loaders;
-    std::unordered_map<std::string, PluginConfig> m_config;
-    std::unordered_map<std::string, PluginFormats> m_formats;
-    std::unordered_map<std::string, PluginPaths> m_paths;
+    irccd& irccd_;
+    plugin_paths default_paths_;
+    std::vector<std::shared_ptr<plugin>> plugins_;
+    std::vector<std::unique_ptr<plugin_loader>> loaders_;
+    std::unordered_map<std::string, plugin_config> config_;
+    std::unordered_map<std::string, plugin_formats> formats_;
+    std::unordered_map<std::string, plugin_paths> paths_;
 
 public:
     /**
@@ -151,21 +151,21 @@
      *
      * \param irccd the irccd instance
      */
-    IRCCD_EXPORT PluginService(Irccd &irccd) noexcept;
+    plugin_service(irccd& irccd) noexcept;
 
     /**
      * Destroy plugins.
      */
-    IRCCD_EXPORT ~PluginService();
+    ~plugin_service();
 
     /**
      * Get the list of plugins.
      *
      * \return the list of plugins
      */
-    inline const std::vector<std::shared_ptr<Plugin>> &list() const noexcept
+    inline const std::vector<std::shared_ptr<plugin>>& list() const noexcept
     {
-        return m_plugins;
+        return plugins_;
     }
 
     /**
@@ -174,7 +174,7 @@
      * \param name the plugin id
      * \return true if has plugin
      */
-    IRCCD_EXPORT bool has(const std::string &name) const noexcept;
+    bool has(const std::string& name) const noexcept;
 
     /**
      * Get a loaded plugin or null if not found.
@@ -182,7 +182,7 @@
      * \param name the plugin id
      * \return the plugin or empty one if not found
      */
-    IRCCD_EXPORT std::shared_ptr<Plugin> get(const std::string &name) const noexcept;
+    std::shared_ptr<plugin> get(const std::string& name) const noexcept;
 
     /**
      * Find a loaded plugin.
@@ -191,7 +191,7 @@
      * \return the plugin
      * \throws std::out_of_range if not found
      */
-    IRCCD_EXPORT std::shared_ptr<Plugin> require(const std::string &name) const;
+    std::shared_ptr<plugin> require(const std::string& name) const;
 
     /**
      * Add the specified plugin to the registry.
@@ -200,14 +200,14 @@
      * \param plugin the plugin
      * \note the plugin is only added to the list, no action is performed on it
      */
-    IRCCD_EXPORT void add(std::shared_ptr<Plugin> plugin);
+    void add(std::shared_ptr<plugin> plugin);
 
     /**
      * Add a loader.
      *
      * \param loader the loader
      */
-    IRCCD_EXPORT void addLoader(std::unique_ptr<PluginLoader> loader);
+    void add_loader(std::unique_ptr<plugin_loader> loader);
 
     /**
      * Configure a plugin.
@@ -217,7 +217,7 @@
      * \param name the plugin name
      * \param config the new configuration
      */
-    IRCCD_EXPORT void setConfig(const std::string &name, PluginConfig config);
+    void set_config(const std::string& name, plugin_config config);
 
     /**
      * Get a configuration for a plugin.
@@ -225,7 +225,7 @@
      * \param name the plugin name
      * \return the configuration or default one if not found
      */
-    IRCCD_EXPORT PluginConfig config(const std::string &name) const;
+    plugin_config config(const std::string& name) const;
 
     /**
      * Add formatting for a plugin.
@@ -233,7 +233,7 @@
      * \param name the plugin name
      * \param formats the formats
      */
-    IRCCD_EXPORT void setFormats(const std::string &name, PluginFormats formats);
+    void set_formats(const std::string& name, plugin_formats formats);
 
     /**
      * Get formats for a plugin.
@@ -241,14 +241,14 @@
      * \param name the plugin name
      * \return the formats
      */
-    IRCCD_EXPORT PluginFormats formats(const std::string &name) const;
+    plugin_formats formats(const std::string& name) const;
 
     /**
      * Get the default paths for plugins.
      *
      * \return the paths
      */
-    IRCCD_EXPORT const PluginPaths& paths() const noexcept;
+    const plugin_paths& paths() const noexcept;
 
     /**
      * Get the paths for the specified plugin.
@@ -256,14 +256,14 @@
      * \param name the plugin
      * \return the paths
      */
-    IRCCD_EXPORT PluginPaths paths(const std::string& name) const;
+    plugin_paths paths(const std::string& name) const;
 
     /**
      * Set default paths.
      *
      * \param paths the default paths (for all plugins)
      */
-    IRCCD_EXPORT void setPaths(PluginPaths paths);
+    void set_paths(plugin_paths paths);
 
     /**
      * Override paths for the specified plugin.
@@ -271,20 +271,20 @@
      * \param name the plugin name
      * \param paths the paths
      */
-    void setPaths(const std::string& name, PluginPaths paths);
+    void set_paths(const std::string& name, plugin_paths paths);
 
     /**
      * Generic function for opening the plugin at the given path.
      *
-     * This function will search for every PluginLoader and call open() on it,
+     * This function will search for every pluginLoader and call open() on it,
      * the first one that success will be returned.
      *
      * \param id the plugin id
      * \param path the path to the file
      * \return the plugin or nullptr on failures
      */
-    IRCCD_EXPORT std::shared_ptr<Plugin> open(const std::string &id,
-                                              const std::string &path);
+    std::shared_ptr<plugin> open(const std::string& id,
+                                 const std::string& path);
 
     /**
      * Generic function for finding a plugin.
@@ -292,7 +292,7 @@
      * \param id the plugin id
      * \return the plugin or nullptr on failures
      */
-    IRCCD_EXPORT std::shared_ptr<Plugin> find(const std::string &id);
+    std::shared_ptr<plugin> find(const std::string& id);
 
     /**
      * Convenient wrapper that loads a plugin, call onLoad and add it to the
@@ -303,14 +303,14 @@
      * \param name the name
      * \param path the optional path (searched if empty)
      */
-    IRCCD_EXPORT void load(std::string name, std::string path = "");
+    void load(std::string name, std::string path = "");
 
     /**
      * Unload a plugin and remove it.
      *
      * \param name the plugin id
      */
-    IRCCD_EXPORT void unload(const std::string &name);
+    void unload(const std::string& name);
 
     /**
      * Reload a plugin by calling onReload.
@@ -318,11 +318,11 @@
      * \param name the plugin name
      * \throw std::exception on failures
      */
-    IRCCD_EXPORT void reload(const std::string &name);
+    void reload(const std::string& name);
 };
 
 /*
- * RuleService.
+ * rule_service.
  * ------------------------------------------------------------------
  */
 
@@ -330,9 +330,9 @@
  * \brief Store and solve rules.
  * \ingroup services
  */
-class RuleService {
+class rule_service {
 private:
-    std::vector<Rule> m_rules;
+    std::vector<rule> rules_;
 
 public:
     /**
@@ -340,9 +340,9 @@
      *
      * \return the list of rules
      */
-    inline const std::vector<Rule> &list() const noexcept
+    inline const std::vector<rule>& list() const noexcept
     {
-        return m_rules;
+        return rules_;
     }
 
     /**
@@ -352,7 +352,7 @@
      */
     inline std::size_t length() const noexcept
     {
-        return m_rules.size();
+        return rules_.size();
     }
 
     /**
@@ -360,7 +360,7 @@
      *
      * \param rule the rule to append
      */
-    IRCCD_EXPORT void add(Rule rule);
+    void add(rule rule);
 
     /**
      * Insert a new rule at the specified position.
@@ -368,7 +368,7 @@
      * \param rule the rule
      * \param position the position
      */
-    IRCCD_EXPORT void insert(Rule rule, unsigned position);
+    void insert(rule rule, unsigned position);
 
     /**
      * Remove a new rule from the specified position.
@@ -376,7 +376,7 @@
      * \pre position must be valid
      * \param position the position
      */
-    IRCCD_EXPORT void remove(unsigned position);
+    void remove(unsigned position);
 
     /**
      * Get a rule at the specified index or throw an exception if not found.
@@ -385,14 +385,14 @@
      * \return the rule
      * \throw std::out_of_range if position is invalid
      */
-    IRCCD_EXPORT const Rule &require(unsigned position) const;
+    const rule& require(unsigned position) const;
 
     /**
      * Overloaded function.
      *
      * \copydoc require
      */
-    IRCCD_EXPORT Rule& require(unsigned position);
+    rule& require(unsigned position);
 
     /**
      * Resolve the action to execute with the specified list of rules.
@@ -404,15 +404,15 @@
      * \param event the event name (e.g onKick)
      * \return true if the plugin must be called
      */
-    IRCCD_EXPORT bool solve(const std::string &server,
-                            const std::string &channel,
-                            const std::string &origin,
-                            const std::string &plugin,
-                            const std::string &event) noexcept;
+    bool solve(const std::string& server,
+               const std::string& channel,
+               const std::string& origin,
+               const std::string& plugin,
+               const std::string& event) noexcept;
 };
 
 /*
- * ServerService.
+ * server_service.
  * ------------------------------------------------------------------
  */
 
@@ -420,52 +420,52 @@
  * \brief Manage IRC servers.
  * \ingroup services
  */
-class ServerService {
+class server_service {
 private:
-    Irccd &m_irccd;
-    std::vector<std::shared_ptr<Server>> m_servers;
+    irccd& irccd_;
+    std::vector<std::shared_ptr<server>> servers_;
 
-    void handleChannelMode(const ChannelModeEvent &);
-    void handleChannelNotice(const ChannelNoticeEvent &);
-    void handleConnect(const ConnectEvent &);
-    void handleInvite(const InviteEvent &);
-    void handleJoin(const JoinEvent &);
-    void handleKick(const KickEvent &);
-    void handleMessage(const MessageEvent &);
-    void handleMe(const MeEvent &);
-    void handleMode(const ModeEvent &);
-    void handleNames(const NamesEvent &);
-    void handleNick(const NickEvent &);
-    void handleNotice(const NoticeEvent &);
-    void handlePart(const PartEvent &);
-    void handleQuery(const QueryEvent &);
-    void handleTopic(const TopicEvent &);
-    void handleWhois(const WhoisEvent &);
+    void handle_channel_mode(const channel_mode_event&);
+    void handle_channel_notice(const channel_notice_event&);
+    void handle_connect(const connect_event&);
+    void handle_invite(const invite_event&);
+    void handle_join(const join_event&);
+    void handle_kick(const kick_event&);
+    void handle_message(const message_event&);
+    void handle_me(const me_event&);
+    void handle_mode(const mode_event&);
+    void handle_names(const names_event&);
+    void handle_nick(const nick_event&);
+    void handle_notice(const notice_event&);
+    void handle_part(const part_event&);
+    void handle_query(const query_event&);
+    void handle_topic(const topic_event&);
+    void handle_whois(const whois_event&);
 
 public:
     /**
      * Create the server service.
      */
-    IRCCD_EXPORT ServerService(Irccd &instance);
+    server_service(irccd& instance);
 
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
+    void prepare(fd_set& in, fd_set& out, net::Handle& max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
+    void sync(fd_set& in, fd_set& out);
 
     /**
      * Get the list of servers
      *
      * \return the servers
      */
-    inline const std::vector<std::shared_ptr<Server>> &servers() const noexcept
+    inline const std::vector<std::shared_ptr<server>>& servers() const noexcept
     {
-        return m_servers;
+        return servers_;
     }
 
     /**
@@ -474,7 +474,7 @@
      * \param name the name
      * \return true if exists
      */
-    IRCCD_EXPORT bool has(const std::string &name) const noexcept;
+    bool has(const std::string& name) const noexcept;
 
     /**
      * Add a new server to the application.
@@ -482,7 +482,7 @@
      * \pre hasServer must return false
      * \param sv the server
      */
-    IRCCD_EXPORT void add(std::shared_ptr<Server> sv);
+    void add(std::shared_ptr<server> sv);
 
     /**
      * Get a server or empty one if not found
@@ -490,7 +490,7 @@
      * \param name the server name
      * \return the server or empty one if not found
      */
-    IRCCD_EXPORT std::shared_ptr<Server> get(const std::string &name) const noexcept;
+    std::shared_ptr<server> get(const std::string& name) const noexcept;
 
     /**
      * Find a server by name.
@@ -499,7 +499,7 @@
      * \return the server
      * \throw std::out_of_range if the server does not exist
      */
-    IRCCD_EXPORT std::shared_ptr<Server> require(const std::string &name) const;
+    std::shared_ptr<server> require(const std::string& name) const;
 
     /**
      * Remove a server from the irccd instance.
@@ -508,37 +508,37 @@
      *
      * \param name the server name
      */
-    IRCCD_EXPORT void remove(const std::string &name);
+    void remove(const std::string& name);
 
     /**
      * Remove all servers.
      *
      * All servers will be disconnected.
      */
-    IRCCD_EXPORT void clear() noexcept;
+    void clear() noexcept;
 };
 
 /*
- * TransportService.
+ * transport_service.
  * ------------------------------------------------------------------
  */
 
-class TransportServer;
-class TransportClient;
+class transport_server;
+class transport_client;
 
 /**
  * \brief manage transport servers and clients.
  * \ingroup services
  */
-class TransportService {
+class transport_service {
 private:
-    Irccd &m_irccd;
+    irccd& irccd_;
 
-    std::vector<std::shared_ptr<TransportServer>> m_servers;
-    std::vector<std::shared_ptr<TransportClient>> m_clients;
+    std::vector<std::shared_ptr<transport_server>> servers_;
+    std::vector<std::shared_ptr<transport_client>> clients_;
 
-    void handleCommand(std::weak_ptr<TransportClient>, const nlohmann::json &);
-    void handleDie(std::weak_ptr<TransportClient>);
+    void handle_command(std::weak_ptr<transport_client>, const nlohmann::json&);
+    void handle_die(std::weak_ptr<transport_client>);
 
 public:
     /**
@@ -546,24 +546,24 @@
      *
      * \param irccd the irccd instance
      */
-    IRCCD_EXPORT TransportService(Irccd &irccd) noexcept;
+    transport_service(irccd& irccd) noexcept;
 
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max);
+    void prepare(fd_set& in, fd_set& out, net::Handle& max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out);
+    void sync(fd_set& in, fd_set& out);
 
     /**
      * Add a transport server.
      *
      * \param ts the transport server
      */
-    IRCCD_EXPORT void add(std::shared_ptr<TransportServer> ts);
+    void add(std::shared_ptr<transport_server> ts);
 
     /**
      * Send data to all clients.
@@ -571,7 +571,7 @@
      * \pre object.is_object()
      * \param object the json object
      */
-    IRCCD_EXPORT void broadcast(const nlohmann::json &object);
+    void broadcast(const nlohmann::json& object);
 };
 
 } // !irccd
--- a/libirccd/irccd/transport.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/transport.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -24,23 +24,23 @@
 namespace irccd {
 
 /*
- * TransportClient
+ * transport_client
  * ------------------------------------------------------------------
  */
 
-void TransportClient::error(const std::string &msg)
+void transport_client::error(const std::string& msg)
 {
-    m_state = Closing;
+    state_ = state::closing;
 
     send({{ "error", msg }});
 }
 
-void TransportClient::flush() noexcept
+void transport_client::flush() noexcept
 {
-    for (std::size_t pos; (pos = m_input.find("\r\n\r\n")) != std::string::npos; ) {
-        auto message = m_input.substr(0, pos);
+    for (std::size_t pos; (pos = input_.find("\r\n\r\n")) != std::string::npos; ) {
+        auto message = input_.substr(0, pos);
 
-        m_input.erase(m_input.begin(), m_input.begin() + pos + 4);
+        input_.erase(input_.begin(), input_.begin() + pos + 4);
 
         try {
             auto document = nlohmann::json::parse(message);
@@ -48,23 +48,23 @@
             if (!document.is_object())
                 error("invalid argument");
             else
-                onCommand(document);
-        } catch (const std::exception &ex) {
+                on_command(document);
+        } catch (const std::exception& ex) {
             error(ex.what());
         }
     }
 }
 
-void TransportClient::authenticate() noexcept
+void transport_client::authenticate() noexcept
 {
-    auto pos = m_input.find("\r\n\r\n");
+    auto pos = input_.find("\r\n\r\n");
 
     if (pos == std::string::npos)
         return;
 
-    auto msg = m_input.substr(0, pos);
+    auto msg = input_.substr(0, pos);
 
-    m_input.erase(m_input.begin(), m_input.begin() + pos + 4);
+    input_.erase(input_.begin(), input_.begin() + pos + 4);
 
     try {
         auto doc = nlohmann::json::parse(msg);
@@ -80,22 +80,22 @@
         auto pw = doc.find("password");
         auto result = true;
 
-        if (pw == doc.end() || !pw->is_string() || *pw != m_parent.password()) {
-            m_state = Closing;
+        if (pw == doc.end() || !pw->is_string() || *pw != parent_.password()) {
+            state_ = state::closing;
             result = false;
         } else
-            m_state = Ready;
+            state_ = state::ready;
 
         send({
             { "response", "auth" },
             { "result", result }
         });
-    } catch (const std::exception &ex) {
+    } catch (const std::exception& ex) {
         error(ex.what());
     }
 }
 
-void TransportClient::recv() noexcept
+void transport_client::recv() noexcept
 {
     try {
         std::string buffer;
@@ -104,45 +104,45 @@
         buffer.resize(recv(&buffer[0], buffer.size()));
 
         if (buffer.empty())
-            onDie();
+            on_die();
 
-        m_input += std::move(buffer);
+        input_ += std::move(buffer);
     } catch (const std::exception &) {
-        onDie();
+        on_die();
     }
 }
 
-void TransportClient::send() noexcept
+void transport_client::send() noexcept
 {
     try {
-        auto ns = send(&m_output[0], m_output.size());
+        auto ns = send(&output_[0], output_.size());
 
         if (ns == 0)
-            onDie();
+            on_die();
 
-        m_output.erase(0, ns);
-    } catch (const std::exception &ex) {
-        onDie();
+        output_.erase(0, ns);
+    } catch (const std::exception&) {
+        on_die();
     }
 }
 
-unsigned TransportClient::recv(void *buffer, unsigned length)
+unsigned transport_client::recv(void* buffer, unsigned length)
 {
-    return m_socket.recv(buffer, length);
+    return socket_.recv(buffer, length);
 }
 
-unsigned TransportClient::send(const void *buffer, unsigned length)
+unsigned transport_client::send(const void* buffer, unsigned length)
 {
-    return m_socket.send(buffer, length);
+    return socket_.send(buffer, length);
 }
 
-TransportClient::TransportClient(TransportServer &parent, net::TcpSocket socket)
-    : m_parent(parent)
-    , m_socket(std::move(socket))
+transport_client::transport_client(transport_server& parent, net::TcpSocket socket)
+    : parent_(parent)
+    , socket_(std::move(socket))
 {
-    assert(m_socket.isOpen());
+    assert(socket_.isOpen());
 
-    m_socket.set(net::option::SockBlockMode(false));
+    socket_.set(net::option::SockBlockMode(false));
 
     // Send some information.
     auto object = nlohmann::json::object({
@@ -162,65 +162,65 @@
     send(object);
 }
 
-void TransportClient::prepare(fd_set &in, fd_set &out, net::Handle &max)
+void transport_client::prepare(fd_set& in, fd_set& out, net::Handle& max)
 {
-    if (m_socket.handle() > max)
-        max = m_socket.handle();
+    if (socket_.handle() > max)
+        max = socket_.handle();
 
-    switch (m_state) {
-    case Greeting:
-        FD_SET(m_socket.handle(), &in);
-        FD_SET(m_socket.handle(), &out);
+    switch (state_) {
+    case state::greeting:
+        FD_SET(socket_.handle(), &in);
+        FD_SET(socket_.handle(), &out);
         break;
-    case Authenticating:
-        FD_SET(m_socket.handle(), &in);
+    case state::authenticating:
+        FD_SET(socket_.handle(), &in);
         break;
-    case Ready:
-        FD_SET(m_socket.handle(), &in);
+    case state::ready:
+        FD_SET(socket_.handle(), &in);
 
-        if (!m_output.empty())
-            FD_SET(m_socket.handle(), &out);
+        if (!output_.empty())
+            FD_SET(socket_.handle(), &out);
         break;
-    case Closing:
-        if (!m_output.empty())
-            FD_SET(m_socket.handle(), &out);
+    case state::closing:
+        if (!output_.empty())
+            FD_SET(socket_.handle(), &out);
         else
-            onDie();
+            on_die();
         break;
     default:
         break;
     }
 }
 
-void TransportClient::sync(fd_set &in, fd_set &out)
+void transport_client::sync(fd_set& in, fd_set& out)
 {
-    switch (m_state) {
-    case Greeting:
-        if (FD_ISSET(m_socket.handle(), &in))
+    switch (state_) {
+    case state::greeting:
+        if (FD_ISSET(socket_.handle(), &in))
             recv();
-        else if (FD_ISSET(m_socket.handle(), &out))
+        else if (FD_ISSET(socket_.handle(), &out))
             send();
 
-        if (m_output.empty())
-            m_state = m_parent.password().empty() ? Ready : Authenticating;
+        if (output_.empty())
+            state_ = parent_.password().empty() ? state::ready : state::authenticating;
 
         break;
-    case Authenticating:
-        if (FD_ISSET(m_socket.handle(), &in))
+    case state::authenticating:
+        if (FD_ISSET(socket_.handle(), &in))
             recv();
 
         authenticate();
         break;
-    case Ready:
-        if (FD_ISSET(m_socket.handle(), &in))
+    case state::ready:
+        if (FD_ISSET(socket_.handle(), &in))
             recv();
-        if (FD_ISSET(m_socket.handle(), &out))
+        if (FD_ISSET(socket_.handle(), &out))
             send();
 
         flush();
         break;
-    case Closing:
-        if (FD_ISSET(m_socket.handle(), &out))
+    case state::closing:
+        if (FD_ISSET(socket_.handle(), &out))
             send();
         break;
     default:
@@ -228,15 +228,15 @@
     }
 }
 
-void TransportClient::send(const nlohmann::json &json)
+void transport_client::send(const nlohmann::json& json)
 {
     assert(json.is_object());
 
-    m_output += json.dump();
-    m_output += "\r\n\r\n";
+    output_ += json.dump();
+    output_ += "\r\n\r\n";
 }
 
-void TransportClient::success(const std::string &cmd, nlohmann::json extra)
+void transport_client::success(const std::string& cmd, nlohmann::json extra)
 {
     assert(extra.is_object() || extra.is_null());
 
@@ -246,11 +246,11 @@
     extra["command"] = cmd;
     extra["status"] = true;
 
-    m_output += extra.dump();
-    m_output += "\r\n\r\n";
+    output_ += extra.dump();
+    output_ += "\r\n\r\n";
 }
 
-void TransportClient::error(const std::string &cmd, const std::string &error, nlohmann::json extra)
+void transport_client::error(const std::string& cmd, const std::string& error, nlohmann::json extra)
 {
     assert(extra.is_object() || extra.is_null());
 
@@ -261,141 +261,145 @@
     extra["status"] = false;
     extra["error"] = error;
 
-    m_output += extra.dump();
-    m_output += "\r\n\r\n";
+    output_ += extra.dump();
+    output_ += "\r\n\r\n";
 }
 
 /*
- * TransportClientTls
+ * transport_client_tls
  * ------------------------------------------------------------------
  */
 
 #if defined(WITH_SSL)
 
-void TransportClientTls::handshake()
+void transport_client_tls::handshake()
 {
     try {
-        m_ssl.handshake();
-        m_handshake = HandshakeReady;
-    } catch (const net::WantReadError &) {
-        m_handshake = HandshakeRead;
-    } catch (const net::WantWriteError &) {
-        m_handshake = HandshakeWrite;
-    } catch (const std::exception &) {
-        onDie();
+        ssl_.handshake();
+        handshake_ = handshake::ready;
+    } catch (const net::WantReadError&) {
+        handshake_ = handshake::read;
+    } catch (const net::WantWriteError&) {
+        handshake_ = handshake::write;
+    } catch (const std::exception&) {
+        on_die();
     }
 }
 
-TransportClientTls::TransportClientTls(const std::string &pkey,
-                                       const std::string &cert,
-                                       TransportServer &server,
-                                       net::TcpSocket socket)
-    : TransportClient(server, std::move(socket))
-    , m_ssl(m_socket)
+transport_client_tls::transport_client_tls(const std::string& pkey,
+                                           const std::string& cert,
+                                           transport_server& parent,
+                                           net::TcpSocket socket)
+    : transport_client(parent, std::move(socket))
+    , ssl_(socket_)
 {
-    m_ssl.setPrivateKey(pkey);
-    m_ssl.setCertificate(cert);
+    ssl_.setPrivateKey(pkey);
+    ssl_.setCertificate(cert);
 
     handshake();
 }
 
-unsigned TransportClientTls::recv(void *buffer, unsigned length)
+unsigned transport_client_tls::recv(void* buffer, unsigned length)
 {
     unsigned nread = 0;
 
     try {
-        nread = m_ssl.recv(buffer, length);
-    } catch (const net::WantReadError &) {
-        m_handshake = HandshakeRead;
-    } catch (const net::WantWriteError &) {
-        m_handshake = HandshakeWrite;
+        nread = ssl_.recv(buffer, length);
+    } catch (const net::WantReadError&) {
+        handshake_ = handshake::read;
+    } catch (const net::WantWriteError&) {
+        handshake_ = handshake::write;
+    } catch (const std::exception&) {
+        on_die();
     }
 
     return nread;
 }
 
-unsigned TransportClientTls::send(const void *buffer, unsigned length)
+unsigned transport_client_tls::send(const void* buffer, unsigned length)
 {
     unsigned nsent = 0;
 
     try {
-        nsent = m_ssl.send(buffer, length);
-    } catch (const net::WantReadError &) {
-        m_handshake = HandshakeRead;
+        nsent = ssl_.send(buffer, length);
+    } catch (const net::WantReadError&) {
+        handshake_ = handshake::read;
     } catch (const net::WantWriteError &) {
-        m_handshake = HandshakeWrite;
+        handshake_ = handshake::write;
+    } catch (const std::exception&) {
+        on_die();
     }
 
     return nsent;
 }
 
-void TransportClientTls::prepare(fd_set &in, fd_set &out, net::Handle &max)
+void transport_client_tls::prepare(fd_set& in, fd_set& out, net::Handle& max)
 {
-    if (m_socket.handle() > max)
-        max = m_socket.handle();
+    if (socket_.handle() > max)
+        max = socket_.handle();
 
-    switch (m_handshake) {
-    case HandshakeRead:
-        FD_SET(m_socket.handle(), &in);
+    switch (handshake_) {
+    case handshake::read:
+        FD_SET(socket_.handle(), &in);
         break;
-    case HandshakeWrite:
-        FD_SET(m_socket.handle(), &out);
+    case handshake::write:
+        FD_SET(socket_.handle(), &out);
         break;
     default:
-        TransportClient::prepare(in, out, max);
+        transport_client::prepare(in, out, max);
         break;
     }
 }
 
-void TransportClientTls::sync(fd_set &in, fd_set &out)
+void transport_client_tls::sync(fd_set& in, fd_set& out)
 {
-    switch (m_handshake) {
-    case HandshakeRead:
-    case HandshakeWrite:
+    switch (handshake_) {
+    case handshake::read:
+    case handshake::write:
         handshake();
         break;
     default:
-        TransportClient::sync(in, out);
+        transport_client::sync(in, out);
     }
 }
 
 #endif  // !WITH_SSL
 
 /*
- * TransportServerIp
+ * transport_server_ip
  * ------------------------------------------------------------------
  */
 
-TransportServerIp::TransportServerIp(const std::string &address,
-                                     std::uint16_t port,
-                                     std::uint8_t mode)
-    : TransportServer(net::TcpSocket((mode & v6) ? AF_INET6 : AF_INET, 0))
+transport_server_ip::transport_server_ip(const std::string& address,
+                                         std::uint16_t port,
+                                         std::uint8_t mode)
+    : transport_server(net::TcpSocket((mode & v6) ? AF_INET6 : AF_INET, 0))
 {
     assert((mode & v6) || (mode & v4));
 
-    m_socket.set(net::option::SockReuseAddress(true));
+    socket_.set(net::option::SockReuseAddress(true));
 
     if (mode & v6) {
         // Disable or enable IPv4 when using IPv6.
-        m_socket.set(net::option::Ipv6Only(!(mode & v4)));
+        socket_.set(net::option::Ipv6Only(!(mode & v4)));
 
         if (address == "*")
-            m_socket.bind(net::ipv6::any(port));
+            socket_.bind(net::ipv6::any(port));
         else
-            m_socket.bind(net::ipv6::pton(address, port));
+            socket_.bind(net::ipv6::pton(address, port));
     } else {
         if (address == "*")
-            m_socket.bind(net::ipv4::any(port));
+            socket_.bind(net::ipv4::any(port));
         else
-            m_socket.bind(net::ipv4::pton(address, port));
+            socket_.bind(net::ipv4::pton(address, port));
     }
 
-    m_socket.listen();
+    socket_.listen();
 }
 
-std::uint16_t TransportServerIp::port() const
+std::uint16_t transport_server_ip::port() const
 {
-    auto addr = m_socket.getsockname();
+    auto addr = socket_.getsockname();
 
     return addr.domain() == AF_INET
         ? ntohs(addr.as<sockaddr_in>().sin_port)
@@ -403,48 +407,48 @@
 }
 
 /*
- * TransportServerTls
+ * transport_server_tls
  * ------------------------------------------------------------------
  */
 
 #if defined(WITH_SSL)
 
-TransportServerTls::TransportServerTls(const std::string &pkey,
-                                       const std::string &cert,
-                                       const std::string &address,
-                                       std::uint16_t port,
-                                       std::uint8_t mode)
-    : TransportServerIp(address, port, mode)
-    , m_privatekey(pkey)
-    , m_cert(cert)
+transport_server_tls::transport_server_tls(const std::string& pkey,
+                                           const std::string& cert,
+                                           const std::string& address,
+                                           std::uint16_t port,
+                                           std::uint8_t mode)
+    : transport_server_ip(address, port, mode)
+    , privatekey_(pkey)
+    , cert_(cert)
 {
 }
 
-std::unique_ptr<TransportClient> TransportServerTls::accept()
+std::unique_ptr<transport_client> transport_server_tls::accept()
 {
-    return std::make_unique<TransportClientTls>(m_privatekey, m_cert, *this, m_socket.accept());
+    return std::make_unique<transport_client_tls>(privatekey_, cert_, *this, socket_.accept());
 }
 
 #endif  // !WITH_SSL
 
 /*
- * TransportServerLocal
+ * transport_server_local
  * ------------------------------------------------------------------
  */
 
 #if !defined(IRCCD_SYSTEM_WINDOWS)
 
-TransportServerLocal::TransportServerLocal(std::string path)
-    : TransportServer(net::TcpSocket(AF_LOCAL, 0))
-    , m_path(std::move(path))
+transport_server_local::transport_server_local(std::string path)
+    : transport_server(net::TcpSocket(AF_LOCAL, 0))
+    , path_(std::move(path))
 {
-    m_socket.bind(net::local::create(m_path, true));
-    m_socket.listen();
+    socket_.bind(net::local::create(path_, true));
+    socket_.listen();
 }
 
-TransportServerLocal::~TransportServerLocal()
+transport_server_local::~transport_server_local()
 {
-    ::remove(m_path.c_str());
+    ::remove(path_.c_str());
 }
 
 #endif
--- a/libirccd/irccd/transport.hpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccd/irccd/transport.hpp	Tue Sep 26 17:18:47 2017 +0200
@@ -36,53 +36,53 @@
 
 namespace irccd {
 
-class TransportServer;
+class transport_server;
 
 /**
  * \brief Client connected to irccd.
  *
  * This class emits a warning upon clients request through onCommand signal.
  */
-class TransportClient {
+class transport_client {
 public:
     /**
      * \brief Client state
      */
-    enum State {
-        Greeting,               //!< client is getting irccd info
-        Authenticating,         //!< client requires authentication
-        Ready,                  //!< client is ready to use
-        Closing                 //!< client must disconnect
+    enum class state {
+        greeting,               //!< client is getting irccd info
+        authenticating,         //!< client requires authentication
+        ready,                  //!< client is ready to use
+        closing                 //!< client must disconnect
     };
 
     /**
-     * Signal: onCommand
+     * Signal: on_command
      * ----------------------------------------------------------
      *
      * Arguments:
      *   - the command
      */
-    Signal<const nlohmann::json &> onCommand;
+    Signal<const nlohmann::json&> on_command;
 
     /**
-     * Signal: onDie
+     * Signal: on_die
      * ----------------------------------------------------------
      *
      * The client has disconnected.
      */
-    Signal<> onDie;
+    Signal<> on_die;
 
 private:
-    void error(const std::string &msg);
+    void error(const std::string& msg);
     void flush() noexcept;
     void authenticate() noexcept;
 
 protected:
-    State m_state{Greeting};    //!< current client state
-    TransportServer &m_parent;  //!< parent transport server
-    net::TcpSocket m_socket;    //!< socket
-    std::string m_input;        //!< input buffer
-    std::string m_output;       //!< output buffer
+    state state_{state::greeting};      //!< current client state
+    transport_server& parent_;          //!< parent transport server
+    net::TcpSocket socket_;             //!< socket
+    std::string input_;                 //!< input buffer
+    std::string output_;                //!< output buffer
 
     /**
      * Fill the input buffer with available data.
@@ -101,7 +101,7 @@
      * \param length the buffer length
      * \return the number of bytes received
      */
-    IRCCD_EXPORT virtual unsigned recv(void *buffer, unsigned length);
+    virtual unsigned recv(void* buffer, unsigned length);
 
     /**
      * Try to send some data into the given buffer.
@@ -110,7 +110,7 @@
      * \param length the buffer length
      * \return the number of bytes sent
      */
-    IRCCD_EXPORT virtual unsigned send(const void *buffer, unsigned length);
+    virtual unsigned send(const void* buffer, unsigned length);
 
 public:
     /**
@@ -120,21 +120,21 @@
      * \param parent the parent server
      * \param socket the new socket
      */
-    IRCCD_EXPORT TransportClient(TransportServer &parent, net::TcpSocket socket);
+    transport_client(transport_server& parent, net::TcpSocket socket);
 
     /**
      * Virtual destructor defaulted.
      */
-    virtual ~TransportClient() = default;
+    virtual ~transport_client() = default;
 
     /**
      * Get the client state.
      *
      * \return the client state
      */
-    inline State state() const noexcept
+    inline enum state state() const noexcept
     {
-        return m_state;
+        return state_;
     }
 
     /**
@@ -143,17 +143,17 @@
      * \pre json.is_object()
      * \param json the json object
      */
-    IRCCD_EXPORT void send(const nlohmann::json &json);
+    void send(const nlohmann::json& json);
 
     /**
      * \copydoc Service::prepare
      */
-    IRCCD_EXPORT virtual void prepare(fd_set &in, fd_set &out, net::Handle &max);
+    virtual void prepare(fd_set& in, fd_set& out, net::Handle& max);
 
     /**
      * \copydoc Service::sync
      */
-    IRCCD_EXPORT virtual void sync(fd_set &in, fd_set &out);
+    virtual void sync(fd_set& in, fd_set& out);
 
     /**
      * Send a successful command to the client with optional extra data
@@ -162,7 +162,7 @@
      * \param cmd the command name
      * \param extra the optional extra data
      */
-    IRCCD_EXPORT void success(const std::string &cmd, nlohmann::json extra = nullptr);
+    void success(const std::string& cmd, nlohmann::json extra = nullptr);
 
     /**
      * Send an error status to the client.
@@ -172,9 +172,9 @@
      * \param error the error string
      * \param extra the optional extra data
      */
-    IRCCD_EXPORT void error(const std::string &cmd,
-                            const std::string &error,
-                            nlohmann::json extra = nullptr);
+    void error(const std::string& cmd,
+               const std::string& error,
+               nlohmann::json extra = nullptr);
 };
 
 /*
@@ -187,15 +187,15 @@
 /**
  * \brief TLS version of transport client.
  */
-class TransportClientTls : public TransportClient {
+class transport_client_tls : public transport_client {
 private:
-    enum {
-        HandshakeWrite,
-        HandshakeRead,
-        HandshakeReady
-    } m_handshake{HandshakeReady};
+    enum class handshake {
+        write,
+        read,
+        ready
+    } handshake_{handshake::ready};
 
-    net::TlsSocket m_ssl;
+    net::TlsSocket ssl_;
 
     void handshake();
 
@@ -203,12 +203,12 @@
     /**
      * \copydoc TransportClient::recv
      */
-    unsigned recv(void *buffer, unsigned length) override;
+    unsigned recv(void* buffer, unsigned length) override;
 
     /**
      * \copydoc TransportClient::send
      */
-    unsigned send(const void *buffer, unsigned length) override;
+    unsigned send(const void* buffer, unsigned length) override;
 
 public:
     /**
@@ -221,20 +221,20 @@
      * \param parent the parent server
      * \param socket the new socket
      */
-    IRCCD_EXPORT TransportClientTls(const std::string &pkey,
-                                    const std::string &cert,
-                                    TransportServer &server,
-                                    net::TcpSocket socket);
+    transport_client_tls(const std::string& pkey,
+                         const std::string& cert,
+                         transport_server& server,
+                         net::TcpSocket socket);
 
     /**
      * \copydoc TransportClient::prepare
      */
-    IRCCD_EXPORT void prepare(fd_set &in, fd_set &out, net::Handle &max) override;
+    void prepare(fd_set& in, fd_set& out, net::Handle& max) override;
 
     /**
      * \copydoc TransportClient::sync
      */
-    IRCCD_EXPORT void sync(fd_set &in, fd_set &out) override;
+    void sync(fd_set& in, fd_set& out) override;
 };
 
 #endif  // !WITH_SSL
@@ -252,32 +252,32 @@
  *
  * The transport class supports the following domains:
  *
- * | Domain                | Class                 |
- * |-----------------------|-----------------------|
- * | IPv4, IPv6            | TransportServerIp     |
- * | Unix (not on Windows) | TransportServerUnix   |
+ * | Domain                | Class                  |
+ * |-----------------------|------------------------|
+ * | IPv4, IPv6            | transport_server_ip    |
+ * | Unix (not on Windows) | transport_server_local |
  *
  * Note: IPv4 and IPv6 can be combined, using TransportServer::IPv6 and its
  * option.
  */
-class TransportServer {
+class transport_server {
 private:
-    TransportServer(const TransportServer &) = delete;
-    TransportServer(TransportServer &&) = delete;
+    transport_server(const transport_server&) = delete;
+    transport_server(transport_server&&) = delete;
 
-    TransportServer &operator=(const TransportServer &) = delete;
-    TransportServer &operator=(TransportServer &&) = delete;
+    transport_server& operator=(const transport_server&) = delete;
+    transport_server& operator=(transport_server&&) = delete;
 
 protected:
-    net::TcpSocket m_socket;
-    std::string m_password;
+    net::TcpSocket socket_;
+    std::string password_;
 
 public:
     /**
      * Default constructor.
      */
-    inline TransportServer(net::TcpSocket socket)
-        : m_socket(std::move(socket))
+    inline transport_server(net::TcpSocket socket)
+        : socket_(std::move(socket))
     {
     }
 
@@ -288,7 +288,7 @@
      */
     inline net::Handle handle() const noexcept
     {
-        return m_socket.handle();
+        return socket_.handle();
     }
 
     /**
@@ -296,9 +296,9 @@
      *
      * \return the password
      */
-    inline const std::string &password() const noexcept
+    inline const std::string& password() const noexcept
     {
-        return m_password;
+        return password_;
     }
 
     /**
@@ -306,36 +306,36 @@
      *
      * \return the password
      */
-    inline void setPassword(std::string password) noexcept
+    inline void set_password(std::string password) noexcept
     {
-        m_password = std::move(password);
+        password_ = std::move(password);
     }
 
     /**
      * Destructor defaulted.
      */
-    virtual ~TransportServer() = default;
+    virtual ~transport_server() = default;
 
     /**
      * Accept a new client depending on the domain.
      *
      * \return the new client
      */
-    virtual std::unique_ptr<TransportClient> accept()
+    virtual std::unique_ptr<transport_client> accept()
     {
-        return std::make_unique<TransportClient>(*this, m_socket.accept());
+        return std::make_unique<transport_client>(*this, socket_.accept());
     }
 };
 
 /**
  * \brief Create IP transport.
  */
-class TransportServerIp : public TransportServer {
+class transport_server_ip : public transport_server {
 public:
     /**
      * \brief Domain to use.
      */
-    enum Mode {
+    enum mode {
         v4 = (1 << 0),      //!< IPv6
         v6 = (1 << 1)       //!< IPv4
     };
@@ -347,9 +347,9 @@
      * \param port the port number
      * \param mode the domains to use (can be OR'ed)
      */
-    IRCCD_EXPORT TransportServerIp(const std::string &address,
-                                   std::uint16_t port,
-                                   std::uint8_t mode = v4);
+    transport_server_ip(const std::string& address,
+                        std::uint16_t port,
+                        std::uint8_t mode = v4);
 
     /**
      * Get the associated port.
@@ -364,10 +364,10 @@
 /**
  * \brief TLS over IP transport.
  */
-class TransportServerTls : public TransportServerIp {
+class transport_server_tls : public transport_server_ip {
 private:
-    std::string m_privatekey;
-    std::string m_cert;
+    std::string privatekey_;
+    std::string cert_;
 
 public:
     /**
@@ -379,16 +379,16 @@
      * \param port the port number
      * \param mode the domains to use (can be OR'ed)
      */
-    IRCCD_EXPORT TransportServerTls(const std::string &pkey,
-                                    const std::string &cert,
-                                    const std::string &address,
-                                    std::uint16_t port,
-                                    std::uint8_t mode = v4);
+    transport_server_tls(const std::string& pkey,
+                         const std::string& cert,
+                         const std::string& address,
+                         std::uint16_t port,
+                         std::uint8_t mode = mode::v4);
 
     /**
      * \copydoc TransportServer::accept
      */
-    IRCCD_EXPORT std::unique_ptr<TransportClient> accept() override;
+    std::unique_ptr<transport_client> accept() override;
 };
 
 #endif // !WITH_SSL
@@ -398,9 +398,9 @@
 /**
  * \brief Implementation of transports for Unix sockets.
  */
-class TransportServerLocal : public TransportServer {
+class transport_server_local : public transport_server {
 private:
-    std::string m_path;
+    std::string path_;
 
 public:
     /**
@@ -408,12 +408,12 @@
      *
      * \param path the path
      */
-    IRCCD_EXPORT TransportServerLocal(std::string path);
+    transport_server_local(std::string path);
 
     /**
      * Destroy the transport and remove the file.
      */
-    IRCCD_EXPORT ~TransportServerLocal();
+    ~transport_server_local();
 };
 
 #endif // !IRCCD_SYSTEM_WINDOWS
--- a/libirccdctl/irccd/client.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/libirccdctl/irccd/client.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -104,7 +104,7 @@
         std::string msg;
 
         do {
-            msg = util::nextNetwork(cnx.m_input);
+            msg = util::next_network(cnx.m_input);
 
             if (!msg.empty())
                 parse(cnx, msg);
@@ -151,7 +151,7 @@
     {
         cnt.recv();
 
-        auto msg = util::nextNetwork(cnt.m_input);
+        auto msg = util::next_network(cnt.m_input);
 
         if (msg.empty())
             return;
@@ -277,7 +277,7 @@
 
     void verify(Client &cnx) const
     {
-        auto msg = util::nextNetwork(cnx.m_input);
+        auto msg = util::next_network(cnx.m_input);
 
         if (msg.empty())
             return;
--- a/tests/cmd-plugin-config/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-plugin-config/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -22,35 +22,32 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-struct CustomPlugin : public Plugin {
-    PluginConfig m_config;
+struct CustomPlugin : public plugin {
+    plugin_config m_config;
 
     CustomPlugin(std::string name = "test")
-        : Plugin(std::move(name), "")
+        : plugin(std::move(name), "")
     {
     }
 
-    PluginConfig config() override
+    plugin_config config() override
     {
         return m_config;
     }
 
-    void setConfig(PluginConfig config) override
+    void set_config(plugin_config config) override
     {
         m_config = std::move(config);
     }
 };
 
-
-
 class PluginConfigCommandTest : public CommandTester {
 public:
     PluginConfigCommandTest()
-        : CommandTester(std::make_unique<PluginConfigCommand>())
+        : CommandTester(std::make_unique<plugin_config_command>())
     {
     }
 };
@@ -85,7 +82,7 @@
         auto plugin = std::make_unique<CustomPlugin>("test");
         auto json = nlohmann::json();
 
-        plugin->setConfig({
+        plugin->set_config({
             { "x1", "10" },
             { "x2", "20" }
         });
@@ -118,7 +115,7 @@
         auto plugin = std::make_unique<CustomPlugin>("test");
         auto json = nlohmann::json();
 
-        plugin->setConfig({
+        plugin->set_config({
             { "x1", "10" },
             { "x2", "20" }
         });
--- a/tests/cmd-plugin-info/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-plugin-info/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,14 +23,13 @@
 #include <plugin.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
 class PluginInfoCommandTest : public CommandTester {
 public:
     PluginInfoCommandTest()
-        : CommandTester(std::make_unique<PluginInfoCommand>())
+        : CommandTester(std::make_unique<plugin_info_command>())
     {
     }
 };
@@ -38,15 +37,15 @@
 TEST_F(PluginInfoCommandTest, basic)
 {
     try {
-        auto plugin = std::make_unique<Plugin>("test", "");
+        auto plg = std::make_unique<plugin>("test", "");
         auto response = nlohmann::json();
 
-        plugin->setAuthor("Francis Beaugrand");
-        plugin->setLicense("GPL");
-        plugin->setSummary("Completely useless plugin");
-        plugin->setVersion("0.0.0.0.0.0.0.0.1-beta5");
+        plg->set_author("Francis Beaugrand");
+        plg->set_license("GPL");
+        plg->set_summary("Completely useless plugin");
+        plg->set_version("0.0.0.0.0.0.0.0.1-beta5");
 
-        m_irccd.plugins().add(std::move(plugin));
+        m_irccd.plugins().add(std::move(plg));
         m_irccdctl.client().onMessage.connect([&] (auto msg) {
             response = std::move(msg);
         });
--- a/tests/cmd-plugin-list/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-plugin-list/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,17 +23,16 @@
 #include <plugin.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
 class PluginListCommandTest : public CommandTester {
 public:
     PluginListCommandTest()
-        : CommandTester(std::make_unique<PluginListCommand>())
+        : CommandTester(std::make_unique<plugin_list_command>())
     {
-        m_irccd.plugins().add(std::make_unique<Plugin>("t1", ""));
-        m_irccd.plugins().add(std::make_unique<Plugin>("t2", ""));
+        m_irccd.plugins().add(std::make_unique<plugin>("t1", ""));
+        m_irccd.plugins().add(std::make_unique<plugin>("t2", ""));
     }
 };
 
--- a/tests/cmd-plugin-load/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-plugin-load/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,30 +23,29 @@
 #include <plugin.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-class CustomLoader : public PluginLoader {
+class CustomLoader : public plugin_loader {
 public:
-    std::shared_ptr<Plugin> open(const std::string &,
+    std::shared_ptr<plugin> open(const std::string &,
                                  const std::string &) noexcept override
     {
         return nullptr;
     }
 
-    std::shared_ptr<Plugin> find(const std::string &id) noexcept override
+    std::shared_ptr<plugin> find(const std::string &id) noexcept override
     {
-        return std::make_unique<Plugin>(id, "");
+        return std::make_unique<plugin>(id, "");
     }
 };
 
 class PluginLoadCommandTest : public CommandTester {
 public:
     PluginLoadCommandTest()
-        : CommandTester(std::make_unique<PluginLoadCommand>())
+        : CommandTester(std::make_unique<plugin_load_command>())
     {
-        m_irccd.plugins().addLoader(std::make_unique<CustomLoader>());
+        m_irccd.plugins().add_loader(std::make_unique<CustomLoader>());
     }
 };
 
--- a/tests/cmd-plugin-reload/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-plugin-reload/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,20 +23,19 @@
 #include <plugin.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
 bool called = false;
 
-class CustomPlugin : public Plugin {
+class CustomPlugin : public plugin {
 public:
     CustomPlugin()
-        : Plugin("test", "")
+        : plugin("test", "")
     {
     }
 
-    void onReload(Irccd &) override
+    void on_reload(irccd::irccd &) override
     {
         called = true;
     }
@@ -45,7 +44,7 @@
 class PluginReloadCommandTest : public CommandTester {
 public:
     PluginReloadCommandTest()
-        : CommandTester(std::make_unique<PluginReloadCommand>())
+        : CommandTester(std::make_unique<plugin_reload_command>())
     {
         called = false;
     }
--- a/tests/cmd-plugin-unload/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-plugin-unload/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,20 +23,19 @@
 #include <plugin.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
 bool called = false;
 
-class CustomPlugin : public Plugin {
+class CustomPlugin : public plugin {
 public:
     CustomPlugin()
-        : Plugin("test", "")
+        : plugin("test", "")
     {
     }
 
-    void onUnload(Irccd &) override
+    void on_unload(irccd::irccd &) override
     {
         called = true;
     }
@@ -45,7 +44,7 @@
 class PluginUnloadCommandTest : public CommandTester {
 public:
     PluginUnloadCommandTest()
-        : CommandTester(std::make_unique<PluginUnloadCommand>())
+        : CommandTester(std::make_unique<plugin_unload_command>())
     {
         called = false;
     }
--- a/tests/cmd-rule-add/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-rule-add/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class RuleAddCommandTest : public CommandTester {
 protected:
@@ -42,9 +41,9 @@
 
 public:
     RuleAddCommandTest()
-        : CommandTester(std::make_unique<RuleAddCommand>())
+        : CommandTester(std::make_unique<rule_add_command>())
     {
-        m_irccd.commands().add(std::make_unique<RuleListCommand>());
+        m_irccd.commands().add(std::make_unique<rule_list_command>());
         m_irccdctl.client().onMessage.connect([&] (auto result) {
             m_result = result;
         });
--- a/tests/cmd-rule-edit/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-rule-edit/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class RuleEditCommandTest : public CommandTester {
 protected:
@@ -42,16 +41,16 @@
 
 public:
     RuleEditCommandTest()
-        : CommandTester(std::make_unique<RuleEditCommand>())
+        : CommandTester(std::make_unique<rule_edit_command>())
     {
-        m_irccd.commands().add(std::make_unique<RuleInfoCommand>());
-        m_irccd.rules().add(Rule(
+        m_irccd.commands().add(std::make_unique<rule_info_command>());
+        m_irccd.rules().add(rule(
             { "s1", "s2" },
             { "c1", "c2" },
             { "o1", "o2" },
             { "p1", "p2" },
             { "onMessage", "onCommand" },
-            RuleAction::Drop
+            rule::action_type::drop
         ));
         m_irccdctl.client().onMessage.connect([&] (auto result) {
             m_result = result;
--- a/tests/cmd-rule-info/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-rule-info/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class RuleInfoCommandTest : public CommandTester {
 protected:
@@ -42,23 +41,23 @@
 
 public:
     RuleInfoCommandTest()
-        : CommandTester(std::make_unique<RuleInfoCommand>())
+        : CommandTester(std::make_unique<rule_info_command>())
     {
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s1", "s2" },
             { "c1", "c2" },
             { "o1", "o2" },
             { "p1", "p2" },
             { "onMessage", "onCommand" },
-            RuleAction::Drop
+            rule::action_type::drop
         ));
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s1", },
             { "c1", },
             { "o1", },
             { "p1", },
             { "onMessage", },
-            RuleAction::Accept
+            rule::action_type::accept
         ));
         m_irccdctl.client().onMessage.connect([&] (auto result) {
             m_result = result;
--- a/tests/cmd-rule-list/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-rule-list/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class RuleListCommandTest : public CommandTester {
 protected:
@@ -42,23 +41,23 @@
 
 public:
     RuleListCommandTest()
-        : CommandTester(std::make_unique<RuleListCommand>())
+        : CommandTester(std::make_unique<rule_list_command>())
     {
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s1", "s2" },
             { "c1", "c2" },
             { "o1", "o2" },
             { "p1", "p2" },
             { "onMessage", "onCommand" },
-            RuleAction::Drop
+            rule::action_type::drop
         ));
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s1", },
             { "c1", },
             { "o1", },
             { "p1", },
             { "onMessage", },
-            RuleAction::Accept
+            rule::action_type::accept
         ));
         m_irccdctl.client().request({{ "command", "rule-list" }});
         m_irccdctl.client().onMessage.connect([&] (auto result) {
--- a/tests/cmd-rule-move/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-rule-move/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class RuleMoveCommandTest : public CommandTester {
 protected:
@@ -42,32 +41,32 @@
 
 public:
     RuleMoveCommandTest()
-        : CommandTester(std::make_unique<RuleMoveCommand>())
+        : CommandTester(std::make_unique<rule_move_command>())
     {
-        m_irccd.commands().add(std::make_unique<RuleListCommand>());
-        m_irccd.rules().add(Rule(
+        m_irccd.commands().add(std::make_unique<rule_list_command>());
+        m_irccd.rules().add(rule(
             { "s0" },
             { "c0" },
             { "o0" },
             { "p0" },
             { "onMessage" },
-            RuleAction::Drop
+            rule::action_type::drop
         ));
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s1", },
             { "c1", },
             { "o1", },
             { "p1", },
             { "onMessage", },
-            RuleAction::Accept
+            rule::action_type::accept
         ));
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s2", },
             { "c2", },
             { "o2", },
             { "p2", },
             { "onMessage", },
-            RuleAction::Accept
+            rule::action_type::accept
         ));
         m_irccdctl.client().onMessage.connect([&] (auto result) {
             m_result = result;
--- a/tests/cmd-rule-remove/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-rule-remove/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class RuleRemoveCommandTest : public CommandTester {
 protected:
@@ -42,24 +41,24 @@
 
 public:
     RuleRemoveCommandTest()
-        : CommandTester(std::make_unique<RuleRemoveCommand>())
+        : CommandTester(std::make_unique<rule_remove_command>())
     {
-        m_irccd.commands().add(std::make_unique<RuleListCommand>());
-        m_irccd.rules().add(Rule(
+        m_irccd.commands().add(std::make_unique<rule_list_command>());
+        m_irccd.rules().add(rule(
             { "s1", "s2" },
             { "c1", "c2" },
             { "o1", "o2" },
             { "p1", "p2" },
             { "onMessage", "onCommand" },
-            RuleAction::Drop
+            rule::action_type::drop
         ));
-        m_irccd.rules().add(Rule(
+        m_irccd.rules().add(rule(
             { "s1", },
             { "c1", },
             { "o1", },
             { "p1", },
             { "onMessage", },
-            RuleAction::Accept
+            rule::action_type::accept
         ));
         m_irccdctl.client().onMessage.connect([&] (auto result) {
             m_result = result;
--- a/tests/cmd-server-cmode/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-cmode/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string channel;
-std::string mode;
+std::string cmd_channel;
+std::string cmd_mode;
 
 } // !namespace
 
@@ -34,15 +33,15 @@
 public:
     void cmode(std::string channel, std::string mode)
     {
-        ::channel = channel;
-        ::mode = mode;
+        ::cmd_channel = channel;
+        ::cmd_mode = mode;
     }
 };
 
 class ServerChannelModeCommandTest : public CommandTester {
 public:
     ServerChannelModeCommandTest()
-        : CommandTester(std::make_unique<ServerChannelModeCommand>(),
+        : CommandTester(std::make_unique<server_channel_mode_command>(),
                         std::make_unique<ServerChannelModeTest>())
     {
         m_irccdctl.client().request({
@@ -58,11 +57,11 @@
 {
     try {
         poll([&] () {
-            return !channel.empty() && !mode.empty();
+            return !cmd_channel.empty() && !cmd_mode.empty();
         });
 
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("+c", mode);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("+c", cmd_mode);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-cnotice/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-cnotice/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string channel;
-std::string message;
+std::string cmd_channel;
+std::string cmd_message;
 
 } // !namespace
 
@@ -34,15 +33,15 @@
 public:
     virtual void cnotice(std::string channel, std::string message) override
     {
-        ::channel = channel;
-        ::message = message;
+        ::cmd_channel = channel;
+        ::cmd_message = message;
     }
 };
 
 class ServerChannelNoticeCommandTest : public CommandTester {
 public:
     ServerChannelNoticeCommandTest()
-        : CommandTester(std::make_unique<ServerChannelNoticeCommand>(),
+        : CommandTester(std::make_unique<server_channel_notice_command>(),
                         std::make_unique<ServerChannelNoticeTest>())
     {
         m_irccdctl.client().request({
@@ -58,11 +57,11 @@
 {
     try {
         poll([&] () {
-            return !channel.empty() && !message.empty();
+            return !cmd_channel.empty() && !cmd_message.empty();
         });
 
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("silence", message);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("silence", cmd_message);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-connect/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-connect/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -22,7 +22,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -33,7 +32,7 @@
 class ServerConnectCommandTest : public CommandTester {
 public:
     ServerConnectCommandTest()
-        : CommandTester(std::make_unique<ServerConnectCommand>())
+        : CommandTester(std::make_unique<server_connect_command>())
     {
         message = nullptr;
 
@@ -101,12 +100,12 @@
         ASSERT_EQ("francis", s->nickname());
         ASSERT_EQ("the_francis", s->realname());
         ASSERT_EQ("frc", s->username());
-        ASSERT_EQ("::", s->commandCharacter());
-        ASSERT_EQ("ultra bot", s->ctcpVersion());
-        ASSERT_TRUE(s->flags() & Server::Ssl);
-        ASSERT_TRUE(s->flags() & Server::SslVerify);
-        ASSERT_TRUE(s->flags() & Server::AutoRejoin);
-        ASSERT_TRUE(s->flags() & Server::JoinInvite);
+        ASSERT_EQ("::", s->command_char());
+        ASSERT_EQ("ultra bot", s->ctcp_version());
+        ASSERT_TRUE(s->flags() & server::ssl);
+        ASSERT_TRUE(s->flags() & server::ssl_verify);
+        ASSERT_TRUE(s->flags() & server::auto_rejoin);
+        ASSERT_TRUE(s->flags() & server::join_invite);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-disconnect/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-disconnect/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,12 +23,11 @@
 #include <server.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 class ServerDisconnectCommandTest : public CommandTester {
 public:
     ServerDisconnectCommandTest()
-        : CommandTester(std::make_unique<ServerDisconnectCommand>())
+        : CommandTester(std::make_unique<server_disconnect_command>())
     {
     }
 };
--- a/tests/cmd-server-info/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-info/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -22,7 +22,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -33,7 +32,7 @@
 class ServerInfoCommandTest : public CommandTester {
 public:
     ServerInfoCommandTest()
-        : CommandTester(std::make_unique<ServerInfoCommand>())
+        : CommandTester(std::make_unique<server_info_command>())
     {
         message = nullptr;
 
@@ -48,16 +47,16 @@
     try {
         auto server = std::make_unique<ServerTester>();
 
-        server->setHost("example.org");
-        server->setPort(8765);
-        server->setPassword("none");
-        server->setNickname("pascal");
-        server->setUsername("psc");
-        server->setRealname("Pascal le grand frere");
-        server->setCtcpVersion("yeah");
-        server->setCommandCharacter("@");
-        server->setReconnectTries(80);
-        server->setPingTimeout(20000);
+        server->set_host("example.org");
+        server->set_port(8765);
+        server->set_password("none");
+        server->set_nickname("pascal");
+        server->set_username("psc");
+        server->set_realname("Pascal le grand frere");
+        server->set_ctcp_version("yeah");
+        server->set_command_char("@");
+        server->set_reconnect_tries(80);
+        server->set_ping_timeout(20000);
 
         m_irccd.servers().add(std::move(server));
         m_irccdctl.client().request({
--- a/tests/cmd-server-invite/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-invite/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string target;
-std::string channel;
+std::string cmd_target;
+std::string cmd_channel;
 
 } // !namespace
 
@@ -34,15 +33,15 @@
 public:
     void invite(std::string target, std::string channel) override
     {
-        ::target = target;
-        ::channel = channel;
+        ::cmd_target = target;
+        ::cmd_channel = channel;
     }
 };
 
 class ServerInviteCommandTest : public CommandTester {
 public:
     ServerInviteCommandTest()
-        : CommandTester(std::make_unique<ServerInviteCommand>(),
+        : CommandTester(std::make_unique<server_invite_command>(),
                         std::make_unique<ServerInviteTest>())
     {
         m_irccdctl.client().request({
@@ -58,11 +57,11 @@
 {
     try {
         poll([&] () {
-            return !target.empty() && !channel.empty();
+            return !cmd_target.empty() && !cmd_channel.empty();
         });
 
-        ASSERT_EQ("francis", target);
-        ASSERT_EQ("#music", channel);
+        ASSERT_EQ("francis", cmd_target);
+        ASSERT_EQ("#music", cmd_channel);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-join/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-join/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string channel;
-std::string password;
+std::string cmd_channel;
+std::string cmd_password;
 
 } // !namespace
 
@@ -34,21 +33,19 @@
 public:
     void join(std::string channel, std::string password) override
     {
-        ::channel = channel;
-        ::password = password;
+        ::cmd_channel = channel;
+        ::cmd_password = password;
     }
 };
 
 class ServerJoinCommandTest : public CommandTester {
 public:
     ServerJoinCommandTest()
-        : CommandTester(std::make_unique<ServerJoinCommand>(),
+        : CommandTester(std::make_unique<server_join_command>(),
                         std::make_unique<ServerJoinTest>())
     {
-        channel.clear();
-        password.clear();
-
-
+        cmd_channel.clear();
+        cmd_password.clear();
     }
 };
 
@@ -63,11 +60,11 @@
         });
 
         poll([&] () {
-            return !channel.empty();
+            return !cmd_channel.empty();
         });
 
-        ASSERT_EQ("#music", channel);
-        ASSERT_EQ("plop", password);
+        ASSERT_EQ("#music", cmd_channel);
+        ASSERT_EQ("plop", cmd_password);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
@@ -83,11 +80,11 @@
         });
 
         poll([&] () {
-            return !channel.empty();
+            return !cmd_channel.empty();
         });
 
-        ASSERT_EQ("#music", channel);
-        ASSERT_EQ("", password);
+        ASSERT_EQ("#music", cmd_channel);
+        ASSERT_EQ("", cmd_password);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-kick/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-kick/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,13 +21,12 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string target;
-std::string channel;
-std::string reason;
+std::string cmd_target;
+std::string cmd_channel;
+std::string cmd_reason;
 
 } // !namespace
 
@@ -35,21 +34,21 @@
 public:
     void kick(std::string target, std::string channel, std::string reason) override
     {
-        ::target = target;
-        ::channel = channel;
-        ::reason = reason;
+        ::cmd_target = target;
+        ::cmd_channel = channel;
+        ::cmd_reason = reason;
     }
 };
 
 class ServerKickCommandTest : public CommandTester {
 public:
     ServerKickCommandTest()
-        : CommandTester(std::make_unique<ServerKickCommand>(),
+        : CommandTester(std::make_unique<server_kick_command>(),
                         std::make_unique<ServerKickTest>())
     {
-        target.clear();
-        channel.clear();
-        reason.clear();
+        cmd_target.clear();
+        cmd_channel.clear();
+        cmd_reason.clear();
     }
 };
 
@@ -65,12 +64,12 @@
         });
 
         poll([&] () {
-            return !target.empty() && !channel.empty();
+            return !cmd_target.empty() && !cmd_channel.empty();
         });
 
-        ASSERT_EQ("francis", target);
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("too noisy", reason);
+        ASSERT_EQ("francis", cmd_target);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("too noisy", cmd_reason);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
@@ -87,12 +86,12 @@
         });
 
         poll([&] () {
-            return !target.empty() && !channel.empty();
+            return !cmd_target.empty() && !cmd_channel.empty();
         });
 
-        ASSERT_EQ("francis", target);
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("", reason);
+        ASSERT_EQ("francis", cmd_target);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("", cmd_reason);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-list/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-list/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -22,7 +22,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -33,7 +32,7 @@
 class ServerListCommandTest : public CommandTester {
 public:
     ServerListCommandTest()
-        : CommandTester(std::make_unique<ServerListCommand>())
+        : CommandTester(std::make_unique<server_list_command>())
     {
         m_irccd.servers().add(std::make_unique<ServerTester>("s1"));
         m_irccd.servers().add(std::make_unique<ServerTester>("s2"));
--- a/tests/cmd-server-me/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-me/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -42,7 +41,7 @@
 class ServerMeCommandTest : public CommandTester {
 public:
     ServerMeCommandTest()
-        : CommandTester(std::make_unique<ServerMeCommand>(),
+        : CommandTester(std::make_unique<server_me_command>(),
                         std::make_unique<ServerMeTest>())
     {
         m_irccdctl.client().request({
--- a/tests/cmd-server-message/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-message/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -42,7 +41,7 @@
 class ServerMessageCommandTest : public CommandTester {
 public:
     ServerMessageCommandTest()
-        : CommandTester(std::make_unique<ServerMessageCommand>(),
+        : CommandTester(std::make_unique<server_message_command>(),
                         std::make_unique<ServerMessageTest>())
     {
         m_irccdctl.client().request({
--- a/tests/cmd-server-mode/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-mode/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -40,7 +39,7 @@
 class ServerModeCommandTest : public CommandTester {
 public:
     ServerModeCommandTest()
-        : CommandTester(std::make_unique<ServerModeCommand>(),
+        : CommandTester(std::make_unique<server_mode_command>(),
                         std::make_unique<ServerModeTest>())
     {
         m_irccdctl.client().request({
--- a/tests/cmd-server-nick/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-nick/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,7 +21,6 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -31,7 +30,7 @@
 
 class ServerNickTest : public ServerTester {
 public:
-    void setNickname(std::string nick) override
+    void set_nickname(std::string nick) override
     {
         ::nick = nick;
     }
@@ -40,7 +39,7 @@
 class ServerNickCommandTest : public CommandTester {
 public:
     ServerNickCommandTest()
-        : CommandTester(std::make_unique<ServerNickCommand>(),
+        : CommandTester(std::make_unique<server_nick_command>(),
                         std::make_unique<ServerNickTest>())
     {
         m_irccdctl.client().request({
--- a/tests/cmd-server-notice/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-notice/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string channel;
-std::string message;
+std::string cmd_channel;
+std::string cmd_message;
 
 } // !namespace
 
@@ -34,15 +33,15 @@
 public:
     void notice(std::string channel, std::string message) override
     {
-        ::channel = channel;
-        ::message = message;
+        ::cmd_channel = channel;
+        ::cmd_message = message;
     }
 };
 
 class ServerNoticeCommandTest : public CommandTester {
 public:
     ServerNoticeCommandTest()
-        : CommandTester(std::make_unique<ServerNoticeCommand>(),
+        : CommandTester(std::make_unique<server_notice_command>(),
                         std::make_unique<ServerNoticeTest>())
     {
         m_irccdctl.client().request({
@@ -58,11 +57,11 @@
 {
     try {
         poll([&] () {
-            return !channel.empty() && !message.empty();
+            return !cmd_channel.empty() && !cmd_message.empty();
         });
 
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("quiet!", message);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("quiet!", cmd_message);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-part/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-part/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string channel;
-std::string reason;
+std::string cmd_channel;
+std::string cmd_reason;
 
 } // !namespace
 
@@ -34,19 +33,19 @@
 public:
     void part(std::string channel, std::string reason) override
     {
-        ::channel = channel;
-        ::reason = reason;
+        ::cmd_channel = channel;
+        ::cmd_reason = reason;
     }
 };
 
 class ServerPartCommandTest : public CommandTester {
 public:
     ServerPartCommandTest()
-        : CommandTester(std::make_unique<ServerPartCommand>(),
+        : CommandTester(std::make_unique<server_part_command>(),
                         std::make_unique<ServerPartTest>())
     {
-        channel.clear();
-        reason.clear();
+        cmd_channel.clear();
+        cmd_reason.clear();
     }
 };
 
@@ -61,11 +60,11 @@
         });
 
         poll([&] () {
-            return !channel.empty();
+            return !cmd_channel.empty();
         });
 
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("too noisy", reason);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("too noisy", cmd_reason);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
@@ -81,11 +80,11 @@
         });
 
         poll([&] () {
-            return !channel.empty();
+            return !cmd_channel.empty();
         });
 
-        ASSERT_EQ("#staff", channel);
-        ASSERT_TRUE(reason.empty());
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_TRUE(cmd_reason.empty());
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/cmd-server-reconnect/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-reconnect/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -22,7 +22,6 @@
 #include <service.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
@@ -52,7 +51,7 @@
 class ServerReconnectCommandTest : public CommandTester {
 public:
     ServerReconnectCommandTest()
-        : CommandTester(std::make_unique<ServerReconnectCommand>())
+        : CommandTester(std::make_unique<server_reconnect_command>())
     {
         m_irccd.servers().add(std::make_unique<ServerReconnectTest>("s1", s1));
         m_irccd.servers().add(std::make_unique<ServerReconnectTest>("s2", s2));
--- a/tests/cmd-server-topic/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/cmd-server-topic/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,12 +21,11 @@
 #include <server-tester.hpp>
 
 using namespace irccd;
-using namespace irccd::command;
 
 namespace {
 
-std::string channel;
-std::string topic;
+std::string cmd_channel;
+std::string cmd_topic;
 
 } // !namespace
 
@@ -34,15 +33,15 @@
 public:
     void topic(std::string channel, std::string topic) override
     {
-        ::channel = channel;
-        ::topic = topic;
+        ::cmd_channel = channel;
+        ::cmd_topic = topic;
     }
 };
 
 class ServerTopicCommandTest : public CommandTester {
 public:
     ServerTopicCommandTest()
-        : CommandTester(std::make_unique<ServerTopicCommand>(),
+        : CommandTester(std::make_unique<server_topic_command>(),
                         std::make_unique<ServerTopicTest>())
     {
         m_irccdctl.client().request({
@@ -58,11 +57,11 @@
 {
     try {
         poll([&] () {
-            return !channel.empty() && !topic.empty();
+            return !cmd_channel.empty() && !cmd_topic.empty();
         });
 
-        ASSERT_EQ("#staff", channel);
-        ASSERT_EQ("new version", topic);
+        ASSERT_EQ("#staff", cmd_channel);
+        ASSERT_EQ("new version", cmd_topic);
     } catch (const std::exception &ex) {
         FAIL() << ex.what();
     }
--- a/tests/js-elapsedtimer/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-elapsedtimer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * main.cpp -- test Irccd.ElapsedTimer API
+ * main.cpp -- test irccd.ElapsedTimer API
  *
  * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
  *
@@ -21,9 +21,9 @@
 #include <thread>
 
 #include <irccd/irccd.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-elapsed-timer.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_elapsed_timer_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 
 using namespace irccd;
@@ -31,14 +31,14 @@
 
 class TestElapsedTimer : public testing::Test {
 protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
     TestElapsedTimer()
-        : m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+        : m_plugin(std::make_shared<js_plugin>("empty", SOURCEDIR "/empty.js"))
     {
-        IrccdModule().load(m_irccd, m_plugin);
-        ElapsedTimerModule().load(m_irccd, m_plugin);
+        js_irccd_module().load(m_irccd, m_plugin);
+        js_elapsed_timer_module().load(m_irccd, m_plugin);
     }
 };
 
--- a/tests/js-file/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-file/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -21,23 +21,23 @@
 #include <gtest/gtest.h>
 
 #include <irccd/irccd.hpp>
-#include <irccd/mod-file.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_file_module.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 
 using namespace irccd;
 
 class TestJsFile : public testing::Test {
 protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
     TestJsFile()
-        : m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+        : m_plugin(std::make_shared<js_plugin>("empty", SOURCEDIR "/empty.js"))
     {
-        IrccdModule().load(m_irccd, m_plugin);
-        FileModule().load(m_irccd, m_plugin);
+        js_irccd_module().load(m_irccd, m_plugin);
+        js_file_module().load(m_irccd, m_plugin);
     }
 };
 
--- a/tests/js-irccd/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-irccd/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -19,8 +19,8 @@
 #include <gtest/gtest.h>
 
 #include <irccd/irccd.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 #include <irccd/sysconfig.hpp>
 
@@ -28,13 +28,13 @@
 
 class TestJsIrccd : public testing::Test {
 protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
     TestJsIrccd()
-        : m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+        : m_plugin(std::make_shared<js_plugin>("empty", SOURCEDIR "/empty.js"))
     {
-        IrccdModule().load(m_irccd, m_plugin);
+        js_irccd_module().load(m_irccd, m_plugin);
     }
 };
 
@@ -98,7 +98,7 @@
 {
     try {
         duk_push_c_function(m_plugin->context(), [] (duk_context *ctx) -> duk_ret_t {
-            dukx_throw(ctx, SystemError(EINVAL, "hey"));
+            dukx_throw(ctx, system_error(EINVAL, "hey"));
 
             return 0;
         }, 0);
--- a/tests/js-logger/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-logger/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,105 +16,86 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Logger Javascript API"
+#include <boost/test/unit_test.hpp>
 
-#include <irccd/irccd.hpp>
 #include <irccd/logger.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-logger.hpp>
-#include <irccd/mod-plugin.hpp>
-#include <irccd/plugin-js.hpp>
-#include <irccd/service.hpp>
-#include <irccd/sysconfig.hpp>
+#include <irccd/js_logger_module.hpp>
+#include <irccd/js_plugin_module.hpp>
+
+#include <js_test.hpp>
+
+namespace irccd {
 
-using namespace irccd;
+class logger_test : public js_test<js_logger_module, js_plugin_module> {
+protected:
+    std::string line_info;
+    std::string line_warning;
+    std::string line_debug;
 
-namespace {
+    class my_logger : public log::logger {
+    private:
+        logger_test& test_;
 
-std::string lineInfo;
-std::string lineWarning;
-std::string lineDebug;
+    public:
+        inline my_logger(logger_test& test) noexcept
+            : test_(test)
+        {
+        }
+
+        void info(const std::string& line) override
+        {
+            test_.line_info = line;
+        }
 
-} // !namespace
+        void warning(const std::string& line) override
+        {
+            test_.line_warning = line;
+        }
 
-class LoggerIfaceTest : public log::Logger {
-public:
-    void info(const std::string &line) override
+        void debug(const std::string& line) override
+        {
+            test_.line_debug = line;
+        }
+    };
+
+    logger_test()
     {
-        lineInfo = line;
-    }
-
-    void warning(const std::string &line) override
-    {
-        lineWarning = line;
-    }
-
-    void debug(const std::string &line) override
-    {
-        lineDebug = line;
+        log::set_verbose(true);
+        log::set_logger(std::make_unique<my_logger>(*this));
     }
 };
 
-class TestJsLogger : public testing::Test {
-protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+BOOST_FIXTURE_TEST_SUITE(js_logger_suite, logger_test)
 
-    TestJsLogger()
-        : m_plugin(std::make_shared<JsPlugin>("test", SOURCEDIR "/empty.js"))
-    {
-        IrccdModule().load(m_irccd, m_plugin);
-        PluginModule().load(m_irccd, m_plugin);
-        LoggerModule().load(m_irccd, m_plugin);
-    }
-};
+BOOST_AUTO_TEST_CASE(info)
+{
+    if (duk_peval_string(plugin_->context(), "Irccd.Logger.info(\"hello!\");") != 0)
+        throw dukx_exception(plugin_->context(), -1);
 
-TEST_F(TestJsLogger, info)
-{
-    try {
-        if (duk_peval_string(m_plugin->context(), "Irccd.Logger.info(\"hello!\");") != 0)
-            throw dukx_exception(m_plugin->context(), -1);
-
-        ASSERT_EQ("plugin test: hello!", lineInfo);
-    } catch (const std::exception &ex) {
-        FAIL() << ex.what();
-    }
+    BOOST_TEST("plugin test: hello!" == line_info);
 }
 
-TEST_F(TestJsLogger, warning)
+BOOST_AUTO_TEST_CASE(warning)
 {
-    try {
-        if (duk_peval_string(m_plugin->context(), "Irccd.Logger.warning(\"FAIL!\");") != 0)
-            throw dukx_exception(m_plugin->context(), -1);
+    if (duk_peval_string(plugin_->context(), "Irccd.Logger.warning(\"FAIL!\");") != 0)
+        throw dukx_exception(plugin_->context(), -1);
 
-        ASSERT_EQ("plugin test: FAIL!", lineWarning);
-    } catch (const std::exception &ex) {
-        FAIL() << ex.what();
-    }
+    BOOST_TEST("plugin test: FAIL!" == line_warning);
 }
 
 #if !defined(NDEBUG)
 
-TEST_F(TestJsLogger, debug)
+BOOST_AUTO_TEST_CASE(debug)
 {
-    try {
-        if (duk_peval_string(m_plugin->context(), "Irccd.Logger.debug(\"starting\");") != 0)
-            throw dukx_exception(m_plugin->context(), -1);
+    if (duk_peval_string(plugin_->context(), "Irccd.Logger.debug(\"starting\");") != 0)
+        throw dukx_exception(plugin_->context(), -1);
 
-        ASSERT_EQ("plugin test: starting", lineDebug);
-    } catch (const std::exception &ex) {
-        FAIL() << ex.what();
-    }
+    BOOST_TEST("plugin test: starting" == line_debug);
 }
 
 #endif
 
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
+BOOST_AUTO_TEST_SUITE_END()
 
-    log::setVerbose(true);
-    log::setLogger(std::make_unique<LoggerIfaceTest>());
-
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/js-system/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-system/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -19,10 +19,10 @@
 #include <gtest/gtest.h>
 
 #include <irccd/irccd.hpp>
-#include <irccd/mod-file.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-system.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_file_module.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_system_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 #include <irccd/sysconfig.hpp>
 #include <irccd/system.hpp>
@@ -31,15 +31,15 @@
 
 class TestJsSystem : public testing::Test {
 protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
     TestJsSystem()
-        : m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+        : m_plugin(std::make_shared<js_plugin>("empty", SOURCEDIR "/empty.js"))
     {
-        IrccdModule().load(m_irccd, m_plugin);
-        FileModule().load(m_irccd, m_plugin);
-        SystemModule().load(m_irccd, m_plugin);
+        js_irccd_module().load(m_irccd, m_plugin);
+        js_file_module().load(m_irccd, m_plugin);
+        js_system_module().load(m_irccd, m_plugin);
     }
 };
 
--- a/tests/js-timer/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-timer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,96 +16,50 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Timer Javascript API"
+#include <boost/test/unit_test.hpp>
+#include <boost/timer/timer.hpp>
 
-#include <irccd/elapsed-timer.hpp>
-#include <irccd/irccd.hpp>
-#include <irccd/logger.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-plugin.hpp>
-#include <irccd/mod-timer.hpp>
-#include <irccd/plugin-js.hpp>
-#include <irccd/service.hpp>
-#include <irccd/system.hpp>
-
-using namespace irccd;
+#include <irccd/js_plugin_module.hpp>
+#include <irccd/js_timer_module.hpp>
 
-class TestJsTimer : public testing::Test {
-protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+#include <js_test.hpp>
+
+namespace irccd {
 
-    void open(const std::string &file)
-    {
-        m_plugin = std::make_shared<JsPlugin>("timer", file);
-
-        IrccdModule().load(m_irccd, m_plugin);
-        PluginModule().load(m_irccd, m_plugin);
-        TimerModule().load(m_irccd, m_plugin);
-
-        m_plugin->onLoad(m_irccd);
-        m_irccd.plugins().add(m_plugin);
-    }
+class fixture : public js_test<js_plugin_module, js_timer_module> {
+public:
+    using js_test::js_test;
 };
 
-TEST_F(TestJsTimer, single)
+BOOST_AUTO_TEST_SUITE(js_timer_suite)
+
+BOOST_AUTO_TEST_CASE(single)
 {
-    open(DIRECTORY "/timer-single.js");
-
-    ElapsedTimer timer;
+    fixture f(DIRECTORY "/timer-single.js");
 
-    while (timer.elapsed() < 3000)
-        util::poller::poll(512, m_irccd);
+    boost::timer::cpu_timer timer;
 
-    ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "count"));
-    ASSERT_EQ(1, duk_get_int(m_plugin->context(), -1));
+    while (timer.elapsed().wall / 1000000LL < 3000)
+        util::poller::poll(512, f.irccd_);
+
+    BOOST_TEST(duk_get_global_string(f.plugin_->context(), "count"));
+    BOOST_TEST(duk_get_int(f.plugin_->context(), -1) == 1);
 }
 
-TEST_F(TestJsTimer, repeat)
+BOOST_AUTO_TEST_CASE(repeat)
 {
-    open(DIRECTORY "/timer-repeat.js");
+    fixture f(DIRECTORY "/timer-repeat.js");
 
-    ElapsedTimer timer;
+    boost::timer::cpu_timer timer;
 
-    while (timer.elapsed() < 3000)
-        util::poller::poll(512, m_irccd);
+    while (timer.elapsed().wall / 1000000LL < 3000)
+        util::poller::poll(512, f.irccd_);
 
-    ASSERT_TRUE(duk_get_global_string(m_plugin->context(), "count"));
-    ASSERT_GE(duk_get_int(m_plugin->context(), -1), 5);
+    BOOST_TEST(duk_get_global_string(f.plugin_->context(), "count"));
+    BOOST_TEST(duk_get_int(f.plugin_->context(), -1) >= 5);
 }
 
-#if 0
-
-/*
- * XXX: currently disabled because it will break single-shot timers.
- */
-
-TEST(Basic, pending)
-{
-    /*
-     * This test ensure that if pending actions on a stopped timer are never executed.
-     */
-    Irccd irccd;
-    ElapsedTimer timer;
-
-    auto plugin = std::make_shared<Plugin>("timer", DIRECTORY "/timer-pending.js");
+BOOST_AUTO_TEST_SUITE_END()
 
-    irccd.addPlugin(plugin);
-    irccd.poll();
-    irccd.dispatch();
-
-    ASSERT_EQ(0, plugin->context().getGlobal<int>("count"));
-}
-
-#endif
-
-int main(int argc, char **argv)
-{
-    // Needed for some components.
-    sys::setProgramName("irccd");
-    log::setLogger(std::make_unique<log::SilentLogger>());
-    log::setVerbose(true);
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/js-unicode/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-unicode/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -23,9 +23,9 @@
 #include <gtest/gtest.h>
 
 #include <irccd/irccd.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-unicode.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_unicode_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 #include <irccd/system.hpp>
 
@@ -33,14 +33,14 @@
 
 class TestJsUnicode : public testing::Test {
 protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
     TestJsUnicode()
-        : m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+        : m_plugin(std::make_shared<js_plugin>("empty", SOURCEDIR "/empty.js"))
     {
-        IrccdModule().load(m_irccd, m_plugin);
-        UnicodeModule().load(m_irccd, m_plugin);
+        js_irccd_module().load(m_irccd, m_plugin);
+        js_unicode_module().load(m_irccd, m_plugin);
     }
 };
 
--- a/tests/js-util/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js-util/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -19,9 +19,9 @@
 #include <gtest/gtest.h>
 
 #include <irccd/irccd.hpp>
-#include <irccd/mod-irccd.hpp>
-#include <irccd/mod-util.hpp>
-#include <irccd/plugin-js.hpp>
+#include <irccd/js_irccd_module.hpp>
+#include <irccd/js_util_module.hpp>
+#include <irccd/js_plugin.hpp>
 #include <irccd/service.hpp>
 #include <irccd/system.hpp>
 
@@ -29,14 +29,14 @@
 
 class TestJsUtil : public testing::Test {
 protected:
-    Irccd m_irccd;
-    std::shared_ptr<JsPlugin> m_plugin;
+    irccd::irccd m_irccd;
+    std::shared_ptr<js_plugin> m_plugin;
 
     TestJsUtil()
-        : m_plugin(std::make_shared<JsPlugin>("empty", SOURCEDIR "/empty.js"))
+        : m_plugin(std::make_shared<js_plugin>("empty", SOURCEDIR "/empty.js"))
     {
-        IrccdModule().load(m_irccd, m_plugin);
-        UtilModule().load(m_irccd, m_plugin);
+        js_irccd_module().load(m_irccd, m_plugin);
+        js_util_module().load(m_irccd, m_plugin);
     }
 };
 
--- a/tests/js/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/js/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,16 +16,17 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <gtest/gtest.h>
+#define BOOST_TEST_MODULE "Javascript"
+#include <boost/test/unit_test.hpp>
 
 #include <duktape.hpp>
 #include <fs.hpp>
 
 namespace irccd {
 
-class Test : public testing::Test {
+class test {
 protected:
-    UniqueContext m_ctx;
+    UniqueContext ctx_;
 };
 
 /*
@@ -33,37 +34,34 @@
  * ------------------------------------------------------------------
  */
 
-TEST_F(Test, no_file)
+BOOST_FIXTURE_TEST_SUITE(test_suite, test)
+
+BOOST_AUTO_TEST_CASE(no_file)
 {
-    ASSERT_THROW(dukx_peval_file(m_ctx, "nonexistent"), Exception);
+    BOOST_REQUIRE_THROW(dukx_peval_file(ctx_, "nonexistent"), Exception);
 
     try {
-        dukx_peval_file(m_ctx, "nonexistent");
+        dukx_peval_file(ctx_, "nonexistent");
     } catch (const Exception& ex) {
-        ASSERT_EQ("Error", ex.name);
-        ASSERT_EQ("nonexistent", ex.fileName);
+        BOOST_REQUIRE_EQUAL("Error", ex.name);
+        BOOST_REQUIRE_EQUAL("nonexistent", ex.fileName);
     }
 }
 
-TEST_F(Test, syntax_error)
+BOOST_AUTO_TEST_CASE(syntax_error)
 {
-    ASSERT_THROW(dukx_peval_file(m_ctx, SOURCEDIR "/syntax-error.js"), Exception);
+    BOOST_REQUIRE_THROW(dukx_peval_file(ctx_, SOURCEDIR "/syntax-error.js"), Exception);
 
     try {
-        dukx_peval_file(m_ctx, SOURCEDIR "/syntax-error.js");
+        dukx_peval_file(ctx_, SOURCEDIR "/syntax-error.js");
     } catch (const Exception& ex) {
-        ASSERT_EQ("SyntaxError", ex.name);
-        ASSERT_EQ("syntax-error.js", fs::baseName(ex.fileName));
-        ASSERT_EQ(6, ex.lineNumber);
-        ASSERT_EQ("empty expression not allowed (line 6)", ex.message);
+        BOOST_REQUIRE_EQUAL("SyntaxError", ex.name);
+        BOOST_REQUIRE_EQUAL("syntax-error.js", fs::baseName(ex.fileName));
+        BOOST_REQUIRE_EQUAL(6, ex.lineNumber);
+        BOOST_REQUIRE_EQUAL("empty expression not allowed (line 6)", ex.message);
     }
 }
 
-} // !irccd
+BOOST_AUTO_TEST_SUITE_END()
 
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}
+} // !irccd
--- a/tests/logger/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/logger/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -32,7 +32,7 @@
 
 } // !namespace
 
-class MyInterface : public log::Logger {
+class MyInterface : public log::logger {
 public:
     void debug(const std::string &line) override
     {
@@ -50,19 +50,19 @@
     }
 };
 
-class MyFilter : public log::Filter {
+class MyFilter : public log::filter {
 public:
-    std::string preDebug(std::string input) const override
+    std::string pre_debug(std::string input) const override
     {
         return std::reverse(input.begin(), input.end()), input;
     }
 
-    std::string preInfo(std::string input) const override
+    std::string pre_info(std::string input) const override
     {
         return std::reverse(input.begin(), input.end()), input;
     }
 
-    std::string preWarning(std::string input) const override
+    std::string pre_warning(std::string input) const override
     {
         return std::reverse(input.begin(), input.end()), input;
     }
@@ -95,9 +95,9 @@
 
 int main(int argc, char **argv)
 {
-    log::setVerbose(true);
-    log::setLogger(std::make_unique<MyInterface>());
-    log::setFilter(std::make_unique<MyFilter>());
+    log::set_verbose(true);
+    log::set_logger(std::make_unique<MyInterface>());
+    log::set_filter(std::make_unique<MyFilter>());
 
     testing::InitGoogleTest(&argc, argv);
 
--- a/tests/plugin-ask/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/plugin-ask/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -26,13 +26,13 @@
 
 using namespace irccd;
 
-class server_test : public Server {
+class server_test : public server {
 private:
     std::string last_;
 
 public:
     inline server_test()
-        : Server("test")
+        : server("test")
     {
     }
 
@@ -72,7 +72,7 @@
      * answers in that amount of tries.
      */
     for (int i = 0; i < 1000; ++i) {
-        plugin_->on_command(irccd_, MessageEvent{server_, "tester", "#dummy", ""});
+        plugin_->on_command(irccd_, {server_, "tester", "#dummy", ""});
 
         if (server_->last() == "#dummy:tester, YES")
             yes = true;
--- a/tests/plugin-auth/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/plugin-auth/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -26,13 +26,13 @@
 
 using namespace irccd;
 
-class server_test : public Server {
+class server_test : public server {
 private:
     std::string last_;
 
 public:
     inline server_test(std::string name)
-        : Server(std::move(name))
+        : server(std::move(name))
     {
     }
 
@@ -76,21 +76,21 @@
 
 TEST_F(auth_test, nickserv1)
 {
-    plugin_->on_connect(irccd_, ConnectEvent{nickserv1_});
+    plugin_->on_connect(irccd_, {nickserv1_});
 
     ASSERT_EQ("NickServ:identify plopation", nickserv1_->last());
 }
 
 TEST_F(auth_test, nickserv2)
 {
-    plugin_->on_connect(irccd_, ConnectEvent{nickserv2_});
+    plugin_->on_connect(irccd_, {nickserv2_});
 
     ASSERT_EQ("NickServ:identify jean something", nickserv2_->last());
 }
 
 TEST_F(auth_test, quakenet)
 {
-    plugin_->on_connect(irccd_, ConnectEvent{quakenet_});
+    plugin_->on_connect(irccd_, {quakenet_});
 
     ASSERT_EQ("Q@CServe.quakenet.org:AUTH mario hello", quakenet_->last());
 }
--- a/tests/plugin-hangman/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/plugin-hangman/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -29,13 +29,13 @@
 
 using namespace irccd;
 
-class ServerTest : public Server {
+class ServerTest : public server {
 private:
     std::string m_last;
 
 public:
     inline ServerTest()
-        : Server("test")
+        : server("test")
     {
     }
 
@@ -53,13 +53,13 @@
 class HangmanTest : public PluginTester {
 protected:
     std::shared_ptr<ServerTest> m_server;
-    std::shared_ptr<Plugin> m_plugin;
+    std::shared_ptr<plugin> m_plugin;
 
 public:
     HangmanTest()
         : m_server(std::make_shared<ServerTest>())
     {
-        m_irccd.plugins().setFormats("hangman", {
+        m_irccd.plugins().set_formats("hangman", {
             { "asked", "asked=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{letter}" },
             { "dead", "dead=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{word}" },
             { "found", "found=#{plugin}:#{command}:#{server}:#{channel}:#{origin}:#{nickname}:#{word}" },
@@ -72,14 +72,14 @@
         });
     }
 
-    void load(PluginConfig config = PluginConfig())
+    void load(plugin_config config = {})
     {
         // Add file if not there.
         if (config.count("file") == 0)
             config.emplace("file", SOURCEDIR "/words.conf");
 
-        m_irccd.plugins().setConfig("hangman", config);
-        m_irccd.plugins().load("hangman", PLUGINDIR "/hangman.js");
+        m_irccd.plugins().set_config("hangman", config);
+        m_irccd.plugins().load("hangman", CMAKE_SOURCE_DIR "/plugins/hangman/hangman.js");
         m_plugin = m_irccd.plugins().require("hangman");
     }
 };
@@ -88,9 +88,9 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "s"});
 
     ASSERT_EQ("#hangman:asked=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s", m_server->last());
 }
@@ -99,17 +99,17 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "a"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "b"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "c"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "d"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "e"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "f"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "g"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "h"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "i"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "j"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "a"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "b"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "c"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "d"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "e"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "f"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "g"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "h"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "i"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "j"});
 
     ASSERT_EQ("#hangman:dead=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:sky", m_server->last());
 }
@@ -118,8 +118,8 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "s"});
 
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
 }
@@ -128,7 +128,7 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
 
     ASSERT_EQ("#hangman:start=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:_ _ _", m_server->last());
 }
@@ -137,10 +137,10 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "k"});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "y"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "k"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "y"});
 
     ASSERT_EQ("#hangman:win=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:sky", m_server->last());
 }
@@ -149,8 +149,8 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "sky"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "sky"});
 
     ASSERT_EQ("#hangman:win=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:sky", m_server->last());
 }
@@ -159,8 +159,8 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "x"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "x"});
 
     ASSERT_EQ("#hangman:wrong-letter=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:x", m_server->last());
 }
@@ -169,8 +169,8 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "cheese"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "cheese"});
 
     ASSERT_EQ("#hangman:wrong-word=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:cheese", m_server->last());
 }
@@ -180,10 +180,10 @@
     // Disable collaborative mode.
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "s"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "k"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "k"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s k _", m_server->last());
 }
 
@@ -192,12 +192,12 @@
     // Enable collaborative mode.
     load({{ "collaborative", "true" }});
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "s"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "k"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "k"});
     ASSERT_EQ("#hangman:wrong-player=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:k", m_server->last());
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "francis!francis@localhost", "#hangman", "k"});
+    m_plugin->on_message(m_irccd, {m_server, "francis!francis@localhost", "#hangman", "k"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:francis!francis@localhost:francis:s k _", m_server->last());
 }
 
@@ -205,12 +205,12 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#HANGMAN", "s"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#HANGMAN", "s"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#HaNGMaN", "k"});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#HaNGMaN", "k"});
     ASSERT_EQ("#hangman:wrong-player=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:k", m_server->last());
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "francis!francis@localhost", "#hAngmAn", "k"});
+    m_plugin->on_message(m_irccd, {m_server, "francis!francis@localhost", "#hAngmAn", "k"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:francis!francis@localhost:francis:s k _", m_server->last());
 }
 
@@ -219,13 +219,13 @@
     load();
 
     // Query mode is never collaborative.
-    m_plugin->onQueryCommand(m_irccd, QueryEvent{m_server, "jean!jean@localhost", ""});
+    m_plugin->on_query_command(m_irccd, {m_server, "jean!jean@localhost", ""});
     ASSERT_EQ("jean:start=hangman:!hangman:test:jean:jean!jean@localhost:jean:_ _ _", m_server->last());
-    m_plugin->onQuery(m_irccd, QueryEvent{m_server, "jean!jean@localhost", "s"});
+    m_plugin->on_query(m_irccd, {m_server, "jean!jean@localhost", "s"});
     ASSERT_EQ("jean:found=hangman:!hangman:test:jean:jean!jean@localhost:jean:s _ _", m_server->last());
-    m_plugin->onQuery(m_irccd, QueryEvent{m_server, "jean!jean@localhost", "k"});
+    m_plugin->on_query(m_irccd, {m_server, "jean!jean@localhost", "k"});
     ASSERT_EQ("jean:found=hangman:!hangman:test:jean:jean!jean@localhost:jean:s k _", m_server->last());
-    m_plugin->onQueryCommand(m_irccd, QueryEvent{m_server, "jean!jean@localhost", "sky"});
+    m_plugin->on_query_command(m_irccd, {m_server, "jean!jean@localhost", "sky"});
     ASSERT_EQ("jean:win=hangman:!hangman:test:jean:jean!jean@localhost:jean:sky", m_server->last());
 }
 
@@ -233,9 +233,9 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
-    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "y"});
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_message(m_irccd, {m_server, "jean!jean@localhost", "#hangman", "y"});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
     ASSERT_EQ("#hangman:running=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:_ _ y", m_server->last());
 }
 
@@ -259,20 +259,20 @@
     };
     std::unordered_set<unsigned> found;
 
-    m_plugin->setFormats({
+    m_plugin->set_formats({
         { "start", "#{word}" }
     });
 
     unsigned last, current;
 
     // 1. Initial game + finish.
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
     last = m_server->last().length();
     found.insert(last);
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", words[last]});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", words[last]});
 
     // 2. Current must not be the last one.
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
     current = m_server->last().length();
 
     ASSERT_NE(last, current);
@@ -280,10 +280,10 @@
 
     found.insert(current);
     last = current;
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", words[current]});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", words[current]});
 
     // 3. Last word must be the one that is kept into the map.
-    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->on_command(m_irccd, {m_server, "jean!jean@localhost", "#hangman", ""});
     current = m_server->last().length();
 
     ASSERT_NE(last, current);
--- a/tests/plugin-history/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/plugin-history/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -28,13 +28,13 @@
 
 using namespace irccd;
 
-class server_test : public Server {
+class server_test : public server {
 private:
     std::string last_;
 
 public:
     inline server_test()
-        : Server("test")
+        : server("test")
     {
     }
 
@@ -81,7 +81,7 @@
 {
     load({{ "file", SOURCEDIR "/broken-conf.json" }});
 
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "seen francis"});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#history", "seen francis"});
     ASSERT_EQ("#history:error=history:!history:test:#history:jean!jean@localhost:jean", server_->last());
 }
 
@@ -92,8 +92,8 @@
     remove(BINARYDIR "/seen.json");
     load({{ "file", BINARYDIR "/seen.json" }});
 
-    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "hello"});
-    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#history", "seen jean"});
+    plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#history", "hello"});
+    plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#history", "seen jean"});
 
     ASSERT_TRUE(std::regex_match(server_->last(), rule));
 }
@@ -105,8 +105,8 @@
     remove(BINARYDIR "/said.json");
     load({{ "file", BINARYDIR "/said.json" }});
 
-    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "hello"});
-    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#history", "said jean"});
+    plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#history", "hello"});
+    plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#history", "said jean"});
 
     ASSERT_TRUE(std::regex_match(server_->last(), rule));
 }
@@ -116,8 +116,8 @@
     remove(BINARYDIR "/unknown.json");
     load({{ "file", BINARYDIR "/unknown.json" }});
 
-    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#history", "hello"});
-    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#history", "seen nobody"});
+    plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#history", "hello"});
+    plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#history", "seen nobody"});
 
     ASSERT_EQ("#history:unknown=history:!history:test:#history:destructor!dst@localhost:destructor:nobody", server_->last());
 }
@@ -129,11 +129,11 @@
     remove(BINARYDIR "/case.json");
     load({{"file", BINARYDIR "/case.json"}});
 
-    plugin_->on_message(irccd_, MessageEvent{server_, "JeaN!JeaN@localhost", "#history", "hello"});
+    plugin_->on_message(irccd_, {server_, "JeaN!JeaN@localhost", "#history", "hello"});
 
-    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#HISTORY", "said JEAN"});
+    plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#HISTORY", "said JEAN"});
     ASSERT_TRUE(std::regex_match(server_->last(), rule));
-    plugin_->on_command(irccd_, MessageEvent{server_, "destructor!dst@localhost", "#HiSToRy", "said JeaN"});
+    plugin_->on_command(irccd_, {server_, "destructor!dst@localhost", "#HiSToRy", "said JeaN"});
     ASSERT_TRUE(std::regex_match(server_->last(), rule));
 }
 
--- a/tests/plugin-logger/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/plugin-logger/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -32,7 +32,7 @@
 
 class logger_test : public plugin_test {
 protected:
-    std::shared_ptr<Server> server_;
+    std::shared_ptr<server> server_;
 
     std::string last() const
     {
@@ -44,7 +44,7 @@
 public:
     logger_test()
         : plugin_test(PLUGIN_NAME, PLUGIN_PATH)
-        , server_(std::make_shared<Server>("test"))
+        , server_(std::make_shared<server>("test"))
     {
         remove(BINARYDIR "/log.txt");
 
@@ -77,7 +77,7 @@
 {
     load();
 
-    plugin_->on_channel_mode(irccd_, ChannelModeEvent{server_, "jean!jean@localhost", "#staff", "+o", "jean"});
+    plugin_->on_channel_mode(irccd_, {server_, "jean!jean@localhost", "#staff", "+o", "jean"});
 
     ASSERT_EQ("cmode=test:#staff:jean!jean@localhost:jean:+o:jean\n", last());
 }
@@ -86,7 +86,7 @@
 {
     load();
 
-    plugin_->on_channel_notice(irccd_, ChannelNoticeEvent{server_, "jean!jean@localhost", "#staff", "bonjour!"});
+    plugin_->on_channel_notice(irccd_, {server_, "jean!jean@localhost", "#staff", "bonjour!"});
 
     ASSERT_EQ("cnotice=test:#staff:jean!jean@localhost:jean:bonjour!\n", last());
 }
@@ -95,7 +95,7 @@
 {
     load();
 
-    plugin_->on_join(irccd_, JoinEvent{server_, "jean!jean@localhost", "#staff"});
+    plugin_->on_join(irccd_, {server_, "jean!jean@localhost", "#staff"});
 
     ASSERT_EQ("join=test:#staff:jean!jean@localhost:jean\n", last());
 }
@@ -104,7 +104,7 @@
 {
     load();
 
-    plugin_->on_kick(irccd_, KickEvent{server_, "jean!jean@localhost", "#staff", "badboy", "please do not flood"});
+    plugin_->on_kick(irccd_, {server_, "jean!jean@localhost", "#staff", "badboy", "please do not flood"});
 
     ASSERT_EQ("kick=test:#staff:jean!jean@localhost:jean:badboy:please do not flood\n", last());
 }
@@ -113,7 +113,7 @@
 {
     load();
 
-    plugin_->on_me(irccd_, MeEvent{server_, "jean!jean@localhost", "#staff", "is drinking water"});
+    plugin_->on_me(irccd_, {server_, "jean!jean@localhost", "#staff", "is drinking water"});
 
     ASSERT_EQ("me=test:#staff:jean!jean@localhost:jean:is drinking water\n", last());
 }
@@ -122,7 +122,7 @@
 {
     load();
 
-    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "hello guys"});
+    plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#staff", "hello guys"});
 
     ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
@@ -131,7 +131,7 @@
 {
     load();
 
-    plugin_->on_mode(irccd_, ModeEvent{server_, "jean!jean@localhost", "+i"});
+    plugin_->on_mode(irccd_, {server_, "jean!jean@localhost", "+i"});
 
     ASSERT_EQ("mode=test:jean!jean@localhost:jean:+i:\n", last());
 }
@@ -140,7 +140,7 @@
 {
     load();
 
-    plugin_->on_notice(irccd_, NoticeEvent{server_, "jean!jean@localhost", "tu veux voir mon chat ?"});
+    plugin_->on_notice(irccd_, {server_, "jean!jean@localhost", "tu veux voir mon chat ?"});
 
     ASSERT_EQ("notice=test:jean!jean@localhost:jean:tu veux voir mon chat ?\n", last());
 }
@@ -149,7 +149,7 @@
 {
     load();
 
-    plugin_->on_part(irccd_, PartEvent{server_, "jean!jean@localhost", "#staff", "too noisy here"});
+    plugin_->on_part(irccd_, {server_, "jean!jean@localhost", "#staff", "too noisy here"});
 
     ASSERT_EQ("part=test:#staff:jean!jean@localhost:jean:too noisy here\n", last());
 }
@@ -158,7 +158,7 @@
 {
     load();
 
-    plugin_->on_query(irccd_, QueryEvent{server_, "jean!jean@localhost", "much irccd, wow"});
+    plugin_->on_query(irccd_, {server_, "jean!jean@localhost", "much irccd, wow"});
 
     ASSERT_EQ("query=test:jean!jean@localhost:jean:much irccd, wow\n", last());
 }
@@ -167,7 +167,7 @@
 {
     load();
 
-    plugin_->on_topic(irccd_, TopicEvent{server_, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah"});
+    plugin_->on_topic(irccd_, {server_, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah"});
 
     ASSERT_EQ("topic=test:#staff:jean!jean@localhost:jean:oh yeah yeaaaaaaaah\n", last());
 }
@@ -176,7 +176,7 @@
 {
     load();
 
-    plugin_->on_message(irccd_, MessageEvent{server_, "jean!jean@localhost", "#STAFF", "hello guys"});
+    plugin_->on_message(irccd_, {server_, "jean!jean@localhost", "#STAFF", "hello guys"});
 
     ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
@@ -184,7 +184,7 @@
 int main(int argc, char** argv)
 {
     testing::InitGoogleTest(&argc, argv);
-    log::setLogger(std::make_unique<log::SilentLogger>());
+    log::set_logger(std::make_unique<log::silent_logger>());
 
     return RUN_ALL_TESTS();
 }
--- a/tests/plugin-plugin/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/plugin-plugin/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -31,13 +31,13 @@
 
 using namespace irccd;
 
-class server_test : public Server {
+class server_test : public server {
 private:
     std::string last_;
 
 public:
     inline server_test()
-        : Server("test")
+        : server("test")
     {
     }
 
@@ -87,26 +87,26 @@
 
 TEST_F(plugin_test_suite, formatUsage)
 {
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", ""});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", ""});
     ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "fail"});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "fail"});
     ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "info"});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "info"});
     ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 }
 
 TEST_F(plugin_test_suite, formatInfo)
 {
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "info fake"});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "info fake"});
 
     ASSERT_EQ("#staff:info=plugin:!plugin:test:#staff:jean!jean@localhost:jean:jean:BEER:fake:Fake White Beer 2000:0.0.0.0.0.1", server_->last());
 }
 
 TEST_F(plugin_test_suite, formatNotFound)
 {
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "info doesnotexistsihope"});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "info doesnotexistsihope"});
 
     ASSERT_EQ("#staff:not-found=plugin:!plugin:test:#staff:jean!jean@localhost:jean:doesnotexistsihope", server_->last());
 }
@@ -116,7 +116,7 @@
     for (int i = 0; i < 100; ++i)
         irccd_.plugins().add(std::make_shared<plugin>("plugin-n-{}"_format(i), ""));
 
-    plugin_->on_command(irccd_, MessageEvent{server_, "jean!jean@localhost", "#staff", "list"});
+    plugin_->on_command(irccd_, {server_, "jean!jean@localhost", "#staff", "list"});
 
     ASSERT_EQ("#staff:too-long=plugin:!plugin:test:#staff:jean!jean@localhost:jean", server_->last());
 }
@@ -124,7 +124,7 @@
 int main(int argc, char **argv)
 {
     testing::InitGoogleTest(&argc, argv);
-    log::setLogger(std::make_unique<log::SilentLogger>());
+    log::set_logger(std::make_unique<log::silent_logger>());
 
     return RUN_ALL_TESTS();
 }
--- a/tests/rules/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/rules/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -66,55 +66,55 @@
  */
 class RulesTest : public testing::Test {
 protected:
-    RuleService m_rules;
+    rule_service m_rules;
 
     RulesTest()
     {
         // #1
         {
             m_rules.add({
-                RuleSet{                }, // Servers
-                RuleSet{ "#staff"       }, // Channels
-                RuleSet{                }, // Origins
-                RuleSet{                }, // Plugins
-                RuleSet{ "onCommand"    }, // Events
-                RuleAction::Drop
+                rule::set{                }, // Servers
+                rule::set{ "#staff"       }, // Channels
+                rule::set{                }, // Origins
+                rule::set{                }, // Plugins
+                rule::set{ "onCommand"    }, // Events
+                rule::action_type::drop
             });
         }
 
         // #2
         {
             m_rules.add({
-                RuleSet{ "unsafe"       },
-                RuleSet{ "#staff"       },
-                RuleSet{                },
-                RuleSet{                },
-                RuleSet{ "onCommand"    },
-                RuleAction::Accept
+                rule::set{ "unsafe"       },
+                rule::set{ "#staff"       },
+                rule::set{                },
+                rule::set{                },
+                rule::set{ "onCommand"    },
+                rule::action_type::accept
             });
         }
 
         // #3-1
         {
             m_rules.add({
-                RuleSet{},
-                RuleSet{},
-                RuleSet{},
-                RuleSet{"game"},
-                RuleSet{},
-                RuleAction::Drop
+                rule::set{},
+                rule::set{},
+                rule::set{},
+                rule::set{"game"},
+                rule::set{},
+                rule::action_type::drop
             });
         }
 
         // #3-2
         {
             m_rules.add({
-                RuleSet{ "malikania", "localhost"   },
-                RuleSet{ "#games"                   },
-                RuleSet{                            },
-                RuleSet{ "game"                     },
-                RuleSet{ "onCommand", "onMessage"   },
-                RuleAction::Accept
+                rule::set{ "malikania", "localhost"   },
+                rule::set{ "#games"                   },
+                rule::set{                            },
+                rule::set{ "game"                     },
+                rule::set{ "onCommand", "onMessage"   },
+                rule::action_type::accept
             });
         }
     }
@@ -122,7 +122,7 @@
 
 TEST_F(RulesTest, basicMatch1)
 {
-    Rule m;
+    rule m;
 
     /*
      * [rule]
@@ -133,7 +133,7 @@
 
 TEST_F(RulesTest, basicMatch2)
 {
-    Rule m(RuleSet{"freenode"});
+    rule m(rule::set{"freenode"});
 
     /*
      * [rule]
@@ -147,7 +147,7 @@
 
 TEST_F(RulesTest, basicMatch3)
 {
-    Rule m(RuleSet{"freenode"}, RuleSet{"#staff"});
+    rule m(rule::set{"freenode"}, rule::set{"#staff"});
 
     /*
      * [rule]
@@ -162,7 +162,7 @@
 
 TEST_F(RulesTest, basicMatch4)
 {
-    Rule m(RuleSet{"malikania"}, RuleSet{"#staff"}, RuleSet{"a"});
+    rule m(rule::set{"malikania"}, rule::set{"#staff"}, rule::set{"a"});
 
     /*
      * [rule]
@@ -178,7 +178,7 @@
 
 TEST_F(RulesTest, complexMatch1)
 {
-    Rule m(RuleSet{"malikania", "freenode"});
+    rule m(rule::set{"malikania", "freenode"});
 
     /*
      * [rule]
@@ -238,7 +238,7 @@
 
 int main(int argc, char **argv)
 {
-    irccd::log::setLogger(std::make_unique<irccd::log::SilentLogger>());
+    irccd::log::set_logger(std::make_unique<irccd::log::silent_logger>());
     testing::InitGoogleTest(&argc, argv);
 
     return RUN_ALL_TESTS();
--- a/tests/service-plugin/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/service-plugin/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -25,9 +25,9 @@
 
 TEST(service_plugin, default_paths)
 {
-    Irccd irccd;
+    irccd irccd;
 
-    irccd.plugins().setPaths({
+    irccd.plugins().set_paths({
         { "cache",  "/var/cache/irccd"          },
         { "config", "/etc/irccd"                },
         { "data",   "/usr/local/share/irccd"    }
@@ -42,14 +42,14 @@
 
 TEST(service_plugin, override_cache)
 {
-    Irccd irccd;
+    irccd irccd;
 
-    irccd.plugins().setPaths({
+    irccd.plugins().set_paths({
         { "cache",  "/var/cache/irccd"          },
         { "config", "/etc/irccd"                },
         { "data",   "/usr/local/share/irccd"    }
     });
-    irccd.plugins().setPaths("ask", {
+    irccd.plugins().set_paths("ask", {
         { "cache",  "/opt/cache/ask"            }
     });
 
@@ -62,14 +62,14 @@
 
 TEST(service_plugin, override_config)
 {
-    Irccd irccd;
+    irccd irccd;
 
-    irccd.plugins().setPaths({
+    irccd.plugins().set_paths({
         { "cache",  "/var/cache/irccd"          },
         { "config", "/etc/irccd"                },
         { "data",   "/usr/local/share/irccd"    }
     });
-    irccd.plugins().setPaths("ask", {
+    irccd.plugins().set_paths("ask", {
         { "config", "/opt/config/ask"           }
     });
 
@@ -82,14 +82,14 @@
 
 TEST(service_plugin, override_data)
 {
-    Irccd irccd;
+    irccd irccd;
 
-    irccd.plugins().setPaths({
+    irccd.plugins().set_paths({
         { "cache",  "/var/cache/irccd"          },
         { "config", "/etc/irccd"                },
         { "data",   "/usr/local/share/irccd"    }
     });
-    irccd.plugins().setPaths("ask", {
+    irccd.plugins().set_paths("ask", {
         { "data",   "/opt/data/ask"             }
     });
 
@@ -102,14 +102,14 @@
 
 TEST(service_plugin, override_all)
 {
-    Irccd irccd;
+    irccd irccd;
 
-    irccd.plugins().setPaths({
+    irccd.plugins().set_paths({
         { "cache",  "/var/cache/irccd"          },
         { "config", "/etc/irccd"                },
         { "data",   "/usr/local/share/irccd"    }
     });
-    irccd.plugins().setPaths("ask", {
+    irccd.plugins().set_paths("ask", {
         { "cache",  "/opt/cache/ask"            },
         { "config", "/opt/config/ask"           },
         { "data",   "/opt/data/ask"             }
@@ -124,14 +124,14 @@
 
 TEST(service_plugin, extra_paths)
 {
-    Irccd irccd;
+    irccd irccd;
 
-    irccd.plugins().setPaths({
+    irccd.plugins().set_paths({
         { "cache",  "/var/cache/irccd"          },
         { "config", "/etc/irccd"                },
         { "data",   "/usr/local/share/irccd"    }
     });
-    irccd.plugins().setPaths("ask", {
+    irccd.plugins().set_paths("ask", {
         { "extra",  "/opt/magic"                }
     });
 
--- a/tests/timer/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/timer/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -25,16 +25,16 @@
 using namespace std::chrono_literals;
 
 /* --------------------------------------------------------
- * Timer object itself
+ * timer object itself
  * -------------------------------------------------------- */
 
 TEST(Basic, single)
 {
-    Timer timer(TimerType::Single, 1000);
+    timer timer(timer::type::single, 1000);
     ElapsedTimer elapsed;
     int count = 0;
 
-    timer.onSignal.connect([&] () {
+    timer.on_signal.connect([&] () {
         count = elapsed.elapsed();
     });
 
@@ -45,15 +45,14 @@
 
     ASSERT_GE(count, 900);
     ASSERT_LE(count, 1100);
-
 }
 
 TEST(Basic, repeat)
 {
-    Timer timer(TimerType::Repeat, 500);
+    timer timer(timer::type::repeat, 500);
     int max = 0;
 
-    timer.onSignal.connect([&] () {
+    timer.on_signal.connect([&] () {
         max ++;
     });
 
@@ -69,10 +68,10 @@
 
 TEST(Basic, restart)
 {
-    Timer timer(TimerType::Repeat, 500);
+    timer timer(timer::type::repeat, 500);
     int max = 0;
 
-    timer.onSignal.connect([&] () {
+    timer.on_signal.connect([&] () {
         max ++;
     });
 
--- a/tests/util/main.cpp	Fri Aug 11 13:45:42 2017 +0200
+++ b/tests/util/main.cpp	Tue Sep 26 17:18:47 2017 +0200
@@ -16,89 +16,105 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <cstdint>
+#define BOOST_TEST_MODULE "util"
+#include <boost/test/unit_test.hpp>
 
-#include <gtest/gtest.h>
+#include <cstdint>
 
 #include <irccd/util.hpp>
 #include <irccd/system.hpp>
 
+namespace std {
+
+std::ostream& operator<<(std::ostream& out, const std::vector<std::string>& list)
+{
+    for (const auto& s : list)
+        out << s << " ";
+
+    return out;
+}
+
+} // !std
+
 namespace irccd {
 
-/* --------------------------------------------------------
+BOOST_AUTO_TEST_SUITE(format)
+
+/*
  * util::format function
- * -------------------------------------------------------- */
+ * --------------------------------------------------------
+ */
 
-TEST(Format, nothing)
+BOOST_AUTO_TEST_CASE(nothing)
 {
     std::string expected = "hello world!";
     std::string result = util::format("hello world!");
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Format, escape)
+BOOST_AUTO_TEST_CASE(escape)
 {
-    util::Substitution params;
+    util::subst params;
 
     params.keywords.emplace("target", "hello");
 
-    ASSERT_EQ("$@#", util::format("$@#"));
-    ASSERT_EQ(" $ @ # ", util::format(" $ @ # "));
-    ASSERT_EQ("#", util::format("#"));
-    ASSERT_EQ(" # ", util::format(" # "));
-    ASSERT_EQ("#@", util::format("#@"));
-    ASSERT_EQ("##", util::format("##"));
-    ASSERT_EQ("#!", util::format("#!"));
-    ASSERT_EQ("#{target}", util::format("##{target}"));
-    ASSERT_EQ("@hello", util::format("@#{target}", params));
-    ASSERT_EQ("hello#", util::format("#{target}#", params));
-    ASSERT_ANY_THROW(util::format("#{failure"));
+    BOOST_REQUIRE_EQUAL("$@#", util::format("$@#"));
+    BOOST_REQUIRE_EQUAL(" $ @ # ", util::format(" $ @ # "));
+    BOOST_REQUIRE_EQUAL("#", util::format("#"));
+    BOOST_REQUIRE_EQUAL(" # ", util::format(" # "));
+    BOOST_REQUIRE_EQUAL("#@", util::format("#@"));
+    BOOST_REQUIRE_EQUAL("##", util::format("##"));
+    BOOST_REQUIRE_EQUAL("#!", util::format("#!"));
+    BOOST_REQUIRE_EQUAL("#{target}", util::format("##{target}"));
+    BOOST_REQUIRE_EQUAL("@hello", util::format("@#{target}", params));
+    BOOST_REQUIRE_EQUAL("hello#", util::format("#{target}#", params));
+    BOOST_REQUIRE_THROW(util::format("#{failure"), std::exception);
 }
 
-TEST(Format, disableDate)
+BOOST_AUTO_TEST_CASE(disable_date)
 {
-    util::Substitution params;
+    util::subst params;
 
-    params.flags &= ~(util::Substitution::Date);
+    params.flags &= ~(util::subst_flags::date);
 
-    ASSERT_EQ("%H:%M", util::format("%H:%M", params));
+    BOOST_REQUIRE_EQUAL("%H:%M", util::format("%H:%M", params));
 }
 
-TEST(Format, disableKeywords)
+BOOST_AUTO_TEST_CASE(disable_keywords)
 {
-    util::Substitution params;
+    util::subst params;
 
     params.keywords.emplace("target", "hello");
-    params.flags &= ~(util::Substitution::Keywords);
+    params.flags &= ~(util::subst_flags::keywords);
 
-    ASSERT_EQ("#{target}", util::format("#{target}", params));
+    BOOST_REQUIRE_EQUAL("#{target}", util::format("#{target}", params));
 }
 
-TEST(Format, disableEnv)
+BOOST_AUTO_TEST_CASE(disable_env)
 {
-    util::Substitution params;
+    util::subst params;
 
-    params.flags &= ~(util::Substitution::Env);
+    params.flags &= ~(util::subst_flags::env);
 
-    ASSERT_EQ("${HOME}", util::format("${HOME}", params));
+    BOOST_REQUIRE_EQUAL("${HOME}", util::format("${HOME}", params));
 }
 
-TEST(Format, keywordSimple)
+BOOST_AUTO_TEST_CASE(keyword_simple)
 {
-    util::Substitution params;
+    util::subst params;
 
     params.keywords.insert({"target", "irccd"});
 
     std::string expected = "hello irccd!";
     std::string result = util::format("hello #{target}!", params);
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Format, keywordMultiple)
+BOOST_AUTO_TEST_CASE(keyword_multiple)
 {
-    util::Substitution params;
+    util::subst params;
 
     params.keywords.insert({"target", "irccd"});
     params.keywords.insert({"source", "nightmare"});
@@ -106,30 +122,30 @@
     std::string expected = "hello irccd from nightmare!";
     std::string result = util::format("hello #{target} from #{source}!", params);
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Format, keywordAdjTwice)
+BOOST_AUTO_TEST_CASE(keyword_adj_twice)
 {
-    util::Substitution params;
+    util::subst params;
 
     params.keywords.insert({"target", "irccd"});
 
     std::string expected = "hello irccdirccd!";
     std::string result = util::format("hello #{target}#{target}!", params);
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Format, keywordMissing)
+BOOST_AUTO_TEST_CASE(keyword_missing)
 {
     std::string expected = "hello !";
     std::string result = util::format("hello #{target}!");
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Format, envSimple)
+BOOST_AUTO_TEST_CASE(env_simple)
 {
     std::string home = sys::env("HOME");
 
@@ -137,282 +153,311 @@
         std::string expected = "my home is " + home;
         std::string result = util::format("my home is ${HOME}");
 
-        ASSERT_EQ(expected, result);
+        BOOST_REQUIRE_EQUAL(expected, result);
     }
 }
 
-TEST(Format, envMissing)
+BOOST_AUTO_TEST_CASE(env_missing)
 {
     std::string expected = "value is ";
     std::string result = util::format("value is ${HOPE_THIS_VAR_NOT_EXIST}");
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-/* --------------------------------------------------------
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
  * util::split function
- * -------------------------------------------------------- */
+ * --------------------------------------------------------
+ */
 
-using List = std::vector<std::string>;
+BOOST_AUTO_TEST_SUITE(split)
 
-TEST(Split, simple)
+using list = std::vector<std::string>;
+
+BOOST_AUTO_TEST_CASE(simple)
 {
-    List expected { "a", "b" };
-    List result = util::split("a;b", ";");
+    list expected { "a", "b" };
+    list result = util::split("a;b", ";");
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Split, cut)
+BOOST_AUTO_TEST_CASE(cut)
 {
-    List expected { "msg", "#staff", "foo bar baz" };
-    List result = util::split("msg;#staff;foo bar baz", ";", 3);
+    list expected { "msg", "#staff", "foo bar baz" };
+    list result = util::split("msg;#staff;foo bar baz", ";", 3);
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-/* --------------------------------------------------------
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
  * util::strip function
- * -------------------------------------------------------- */
+ * --------------------------------------------------------
+ */
 
-TEST(Strip, left)
+BOOST_AUTO_TEST_SUITE(strip)
+
+BOOST_AUTO_TEST_CASE(left)
 {
     std::string value = "   123";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("123", result);
+    BOOST_REQUIRE_EQUAL("123", result);
 }
 
-TEST(Strip, right)
+BOOST_AUTO_TEST_CASE(right)
 {
     std::string value = "123   ";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("123", result);
+    BOOST_REQUIRE_EQUAL("123", result);
 }
 
-TEST(Strip, both)
+BOOST_AUTO_TEST_CASE(both)
 {
     std::string value = "   123   ";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("123", result);
+    BOOST_REQUIRE_EQUAL("123", result);
 }
 
-TEST(Strip, none)
+BOOST_AUTO_TEST_CASE(none)
 {
     std::string value = "without";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("without", result);
+    BOOST_REQUIRE_EQUAL("without", result);
 }
 
-TEST(Strip, betweenEmpty)
+BOOST_AUTO_TEST_CASE(betweenEmpty)
 {
     std::string value = "one list";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("one list", result);
+    BOOST_REQUIRE_EQUAL("one list", result);
 }
 
-TEST(Strip, betweenLeft)
+BOOST_AUTO_TEST_CASE(betweenLeft)
 {
     std::string value = "  space at left";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("space at left", result);
+    BOOST_REQUIRE_EQUAL("space at left", result);
 }
 
-TEST(Strip, betweenRight)
+BOOST_AUTO_TEST_CASE(betweenRight)
 {
     std::string value = "space at right  ";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("space at right", result);
+    BOOST_REQUIRE_EQUAL("space at right", result);
 }
 
-TEST(Strip, betweenBoth)
+BOOST_AUTO_TEST_CASE(betweenBoth)
 {
     std::string value = "  space at both  ";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("space at both", result);
+    BOOST_REQUIRE_EQUAL("space at both", result);
 }
 
-TEST(Strip, empty)
+BOOST_AUTO_TEST_CASE(empty)
 {
     std::string value = "    ";
     std::string result = util::strip(value);
 
-    ASSERT_EQ("", result);
-}
+    BOOST_REQUIRE_EQUAL("", result);
+} 
+
+BOOST_AUTO_TEST_SUITE_END()
 
-/* --------------------------------------------------------
+/*
  * util::join function
- * -------------------------------------------------------- */
+ * --------------------------------------------------------
+ */
 
-TEST(Join, empty)
+BOOST_AUTO_TEST_SUITE(join)
+
+BOOST_AUTO_TEST_CASE(empty)
 {
     std::string expected = "";
     std::string result = util::join<int>({});
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Join, one)
+BOOST_AUTO_TEST_CASE(one)
 {
     std::string expected = "1";
     std::string result = util::join({1});
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Join, two)
+BOOST_AUTO_TEST_CASE(two)
 {
     std::string expected = "1:2";
     std::string result = util::join({1, 2});
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Join, delimiterString)
+BOOST_AUTO_TEST_CASE(delimiterString)
 {
     std::string expected = "1;;2;;3";
     std::string result = util::join({1, 2, 3}, ";;");
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-TEST(Join, delimiterChar)
+BOOST_AUTO_TEST_CASE(delimiterChar)
 {
     std::string expected = "1@2@3@4";
     std::string result = util::join({1, 2, 3, 4}, '@');
 
-    ASSERT_EQ(expected, result);
+    BOOST_REQUIRE_EQUAL(expected, result);
 }
 
-/* --------------------------------------------------------
- * util::isIdentifierValid function
- * -------------------------------------------------------- */
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::is_identifier function
+ * --------------------------------------------------------
+ */
 
-TEST(IsIdentifierValid, correct)
+BOOST_AUTO_TEST_SUITE(is_identifier_valid)
+
+BOOST_AUTO_TEST_CASE(correct)
 {
-    ASSERT_TRUE(util::isIdentifierValid("localhost"));
-    ASSERT_TRUE(util::isIdentifierValid("localhost2"));
-    ASSERT_TRUE(util::isIdentifierValid("localhost2-4_"));
+    BOOST_REQUIRE(util::is_identifier("localhost"));
+    BOOST_REQUIRE(util::is_identifier("localhost2"));
+    BOOST_REQUIRE(util::is_identifier("localhost2-4_"));
 }
 
-TEST(IsIdentifierValid, incorrect)
+BOOST_AUTO_TEST_CASE(incorrect)
 {
-    ASSERT_FALSE(util::isIdentifierValid(""));
-    ASSERT_FALSE(util::isIdentifierValid("localhost with spaces"));
-    ASSERT_FALSE(util::isIdentifierValid("localhost*"));
-    ASSERT_FALSE(util::isIdentifierValid("&&"));
-    ASSERT_FALSE(util::isIdentifierValid("@'"));
-    ASSERT_FALSE(util::isIdentifierValid("##"));
-    ASSERT_FALSE(util::isIdentifierValid("===++"));
+    BOOST_REQUIRE(!util::is_identifier(""));
+    BOOST_REQUIRE(!util::is_identifier("localhost with spaces"));
+    BOOST_REQUIRE(!util::is_identifier("localhost*"));
+    BOOST_REQUIRE(!util::is_identifier("&&"));
+    BOOST_REQUIRE(!util::is_identifier("@'"));
+    BOOST_REQUIRE(!util::is_identifier("##"));
+    BOOST_REQUIRE(!util::is_identifier("===++"));
 }
 
-/* --------------------------------------------------------
- * util::isBoolean function
- * -------------------------------------------------------- */
+BOOST_AUTO_TEST_SUITE_END()
 
-TEST(IsBoolean, correct)
+/*
+ * util::is_boolean function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(is_boolean)
+
+BOOST_AUTO_TEST_CASE(correct)
 {
     // true
-    ASSERT_TRUE(util::isBoolean("true"));
-    ASSERT_TRUE(util::isBoolean("True"));
-    ASSERT_TRUE(util::isBoolean("TRUE"));
-    ASSERT_TRUE(util::isBoolean("TruE"));
+    BOOST_REQUIRE(util::is_boolean("true"));
+    BOOST_REQUIRE(util::is_boolean("True"));
+    BOOST_REQUIRE(util::is_boolean("TRUE"));
+    BOOST_REQUIRE(util::is_boolean("TruE"));
 
     // yes
-    ASSERT_TRUE(util::isBoolean("yes"));
-    ASSERT_TRUE(util::isBoolean("Yes"));
-    ASSERT_TRUE(util::isBoolean("YES"));
-    ASSERT_TRUE(util::isBoolean("YeS"));
+    BOOST_REQUIRE(util::is_boolean("yes"));
+    BOOST_REQUIRE(util::is_boolean("Yes"));
+    BOOST_REQUIRE(util::is_boolean("YES"));
+    BOOST_REQUIRE(util::is_boolean("YeS"));
 
     // on
-    ASSERT_TRUE(util::isBoolean("on"));
-    ASSERT_TRUE(util::isBoolean("On"));
-    ASSERT_TRUE(util::isBoolean("oN"));
-    ASSERT_TRUE(util::isBoolean("ON"));
+    BOOST_REQUIRE(util::is_boolean("on"));
+    BOOST_REQUIRE(util::is_boolean("On"));
+    BOOST_REQUIRE(util::is_boolean("oN"));
+    BOOST_REQUIRE(util::is_boolean("ON"));
 
     // 1
-    ASSERT_TRUE(util::isBoolean("1"));
+    BOOST_REQUIRE(util::is_boolean("1"));
+}
+
+BOOST_AUTO_TEST_CASE(incorrect)
+{
+    BOOST_REQUIRE(!util::is_boolean("false"));
+    BOOST_REQUIRE(!util::is_boolean("lol"));
+    BOOST_REQUIRE(!util::is_boolean(""));
+    BOOST_REQUIRE(!util::is_boolean("0"));
 }
 
-TEST(IsBoolean, incorrect)
+BOOST_AUTO_TEST_SUITE_END()
+
+/*
+ * util::is_number function
+ * --------------------------------------------------------
+ */
+
+BOOST_AUTO_TEST_SUITE(is_number)
+
+BOOST_AUTO_TEST_CASE(correct)
 {
-    ASSERT_FALSE(util::isBoolean("false"));
-    ASSERT_FALSE(util::isBoolean("lol"));
-    ASSERT_FALSE(util::isBoolean(""));
-    ASSERT_FALSE(util::isBoolean("0"));
+    BOOST_REQUIRE(util::is_number("123"));
+    BOOST_REQUIRE(util::is_number("-123"));
+    BOOST_REQUIRE(util::is_number("123.67"));
 }
 
-/* --------------------------------------------------------
- * util::isNumber function
- * -------------------------------------------------------- */
-
-TEST(IsNumber, correct)
+BOOST_AUTO_TEST_CASE(incorrect)
 {
-    ASSERT_TRUE(util::isNumber("123"));
-    ASSERT_TRUE(util::isNumber("-123"));
-    ASSERT_TRUE(util::isNumber("123.67"));
+    BOOST_REQUIRE(!util::is_number("lol"));
+    BOOST_REQUIRE(!util::is_number("this is not a number"));
 }
 
-TEST(IsNumber, incorrect)
-{
-    ASSERT_FALSE(util::isNumber("lol"));
-    ASSERT_FALSE(util::isNumber("this is not a number"));
-}
+BOOST_AUTO_TEST_SUITE_END()
 
 /*
- * util::toNumber function
+ * util::to_number function
  * ------------------------------------------------------------------
  */
 
-TEST(ToNumber, correct)
+BOOST_AUTO_TEST_SUITE(to_number)
+
+BOOST_AUTO_TEST_CASE(correct)
 {
     /* unsigned */
-    ASSERT_EQ(50u, util::toNumber<std::uint8_t>("50"));
-    ASSERT_EQ(5000u, util::toNumber<std::uint16_t>("5000"));
-    ASSERT_EQ(50000u, util::toNumber<std::uint32_t>("50000"));
-    ASSERT_EQ(500000u, util::toNumber<std::uint64_t>("500000"));
+    BOOST_REQUIRE_EQUAL(50u, util::to_number<std::uint8_t>("50"));
+    BOOST_REQUIRE_EQUAL(5000u, util::to_number<std::uint16_t>("5000"));
+    BOOST_REQUIRE_EQUAL(50000u, util::to_number<std::uint32_t>("50000"));
+    BOOST_REQUIRE_EQUAL(500000u, util::to_number<std::uint64_t>("500000"));
 
     /* signed */
-    ASSERT_EQ(-50, util::toNumber<std::int8_t>("-50"));
-    ASSERT_EQ(-500, util::toNumber<std::int16_t>("-500"));
-    ASSERT_EQ(-5000, util::toNumber<std::int32_t>("-5000"));
-    ASSERT_EQ(-50000, util::toNumber<std::int64_t>("-50000"));
+    BOOST_REQUIRE_EQUAL(-50, util::to_number<std::int8_t>("-50"));
+    BOOST_REQUIRE_EQUAL(-500, util::to_number<std::int16_t>("-500"));
+    BOOST_REQUIRE_EQUAL(-5000, util::to_number<std::int32_t>("-5000"));
+    BOOST_REQUIRE_EQUAL(-50000, util::to_number<std::int64_t>("-50000"));
 }
 
-TEST(ToNumber, incorrect)
+BOOST_AUTO_TEST_CASE(incorrect)
 {
     /* unsigned */
-    ASSERT_THROW(util::toNumber<std::uint8_t>("300"), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::uint16_t>("80000"), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::uint8_t>("-125"), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::uint16_t>("-25000"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::uint8_t>("300"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::uint16_t>("80000"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::uint8_t>("-125"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::uint16_t>("-25000"), std::out_of_range);
 
     /* signed */
-    ASSERT_THROW(util::toNumber<std::int8_t>("300"), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::int16_t>("80000"), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::int8_t>("-300"), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::int16_t>("-80000"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::int8_t>("300"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::int16_t>("80000"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::int8_t>("-300"), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::int16_t>("-80000"), std::out_of_range);
 
     /* not numbers */
-    ASSERT_THROW(util::toNumber<std::uint8_t>("nonono"), std::invalid_argument);
+    BOOST_REQUIRE_THROW(util::to_number<std::uint8_t>("nonono"), std::invalid_argument);
 
     /* custom ranges */
-    ASSERT_THROW(util::toNumber<std::uint8_t>("50", 0, 10), std::out_of_range);
-    ASSERT_THROW(util::toNumber<std::int8_t>("-50", -10, 10), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::uint8_t>("50", 0, 10), std::out_of_range);
+    BOOST_REQUIRE_THROW(util::to_number<std::int8_t>("-50", -10, 10), std::out_of_range);
 }
 
+BOOST_AUTO_TEST_SUITE_END()
+
 } // !irccd
-
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}