changeset 732:e53b013c8938

Irccd: server style and cleanup
author David Demelier <markand@malikania.fr>
date Thu, 19 Jul 2018 12:54:00 +0200
parents 9d13aabfd63a
children bd12709b1975
files libirccd-js/irccd/js/server_jsapi.cpp libirccd-test/irccd/test/debug_server.cpp libirccd/irccd/daemon/command/server_connect_command.cpp libirccd/irccd/daemon/command/server_info_command.cpp libirccd/irccd/daemon/command/server_list_command.cpp libirccd/irccd/daemon/server.cpp libirccd/irccd/daemon/server.hpp libirccd/irccd/daemon/server_util.cpp libirccd/irccd/daemon/service/server_service.cpp plugins/links/links.cpp tests/src/libirccd/command-server-connect/main.cpp tests/src/libirccd/command-server-info/main.cpp
diffstat 12 files changed, 416 insertions(+), 287 deletions(-) [+]
line wrap: on
line diff
--- a/libirccd-js/irccd/js/server_jsapi.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd-js/irccd/js/server_jsapi.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -86,15 +86,17 @@
     const auto server = self(ctx);
 
     duk_push_object(ctx);
-    dukx_push(ctx, server->get_name());
+    dukx_push(ctx, server->get_id());
     duk_put_prop_string(ctx, -2, "name");
     dukx_push(ctx, server->get_host());
     duk_put_prop_string(ctx, -2, "host");
     duk_push_int(ctx, server->get_port());
     duk_put_prop_string(ctx, -2, "port");
-    duk_push_boolean(ctx, server->get_flags() & server::ssl);
+    duk_push_boolean(ctx,
+        (server->get_options() & server::options::ssl) == server::options::ssl);
     duk_put_prop_string(ctx, -2, "ssl");
-    duk_push_boolean(ctx, server->get_flags() & server::ssl_verify);
+    duk_push_boolean(ctx,
+        (server->get_options() & server::options::ssl_verify) == server::options::ssl_verify);
     duk_put_prop_string(ctx, -2, "sslVerify");
     dukx_push(ctx, server->get_command_char());
     duk_put_prop_string(ctx, -2, "commandChar");
@@ -575,7 +577,7 @@
 duk_ret_t Server_prototype_toString(duk_context* ctx)
 {
     return wrap(ctx, [] (auto ctx) {
-        dukx_push(ctx, self(ctx)->get_name());
+        dukx_push(ctx, self(ctx)->get_id());
 
         return 1;
     });
@@ -728,7 +730,7 @@
 
     for (const auto& server : dukx_type_traits<irccd>::self(ctx).servers().servers()) {
         dukx_push(ctx, server);
-        duk_put_prop_string(ctx, -2, server->get_name().c_str());
+        duk_put_prop_string(ctx, -2, server->get_id().c_str());
     }
 
     return 1;
--- a/libirccd-test/irccd/test/debug_server.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd-test/irccd/test/debug_server.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -24,42 +24,42 @@
 
 void debug_server::connect() noexcept
 {
-    std::cout << get_name() << ": connect" << std::endl;
+    std::cout << get_id() << ": connect" << std::endl;
 }
 
 void debug_server::disconnect() noexcept
 {
-    std::cout << get_name() << ": disconnect" << std::endl;
+    std::cout << get_id() << ": disconnect" << std::endl;
 }
 
 void debug_server::reconnect() noexcept
 {
-    std::cout << get_name() << ": reconnect" << std::endl;
+    std::cout << get_id() << ": reconnect" << std::endl;
 }
 
 void debug_server::invite(std::string target, std::string channel)
 {
-    std::cout << get_name() << ": invite " << target << " " << channel << std::endl;
+    std::cout << get_id() << ": invite " << target << " " << channel << std::endl;
 }
 
 void debug_server::join(std::string channel, std::string password)
 {
-    std::cout << get_name() << ": join " << channel << " " << password << std::endl;
+    std::cout << get_id() << ": join " << channel << " " << password << std::endl;
 }
 
 void debug_server::kick(std::string target, std::string channel, std::string reason)
 {
-    std::cout << get_name() << ": kick " << target << " " << channel << " " << reason << std::endl;
+    std::cout << get_id() << ": kick " << target << " " << channel << " " << reason << std::endl;
 }
 
 void debug_server::me(std::string target, std::string message)
 {
-    std::cout << get_name() << ": me " << target << " " << message << std::endl;
+    std::cout << get_id() << ": me " << target << " " << message << std::endl;
 }
 
 void debug_server::message(std::string target, std::string message)
 {
-    std::cout << get_name() << ": message " << target << " " << message << std::endl;
+    std::cout << get_id() << ": message " << target << " " << message << std::endl;
 }
 
 void debug_server::mode(std::string channel,
@@ -68,7 +68,7 @@
           std::string user,
           std::string mask)
 {
-    std::cout << get_name() << ": mode "
+    std::cout << get_id() << ": mode "
               << channel << " "
               << mode << " "
               << limit << " "
@@ -78,32 +78,32 @@
 
 void debug_server::names(std::string channel)
 {
-    std::cout << get_name() << ": names " << channel << std::endl;
+    std::cout << get_id() << ": names " << channel << std::endl;
 }
 
 void debug_server::notice(std::string target, std::string message)
 {
-    std::cout << get_name() << ": notice " << target << " " << message << std::endl;
+    std::cout << get_id() << ": notice " << target << " " << message << std::endl;
 }
 
 void debug_server::part(std::string channel, std::string reason)
 {
-    std::cout << get_name() << ": part " << channel << " " << reason << std::endl;
+    std::cout << get_id() << ": part " << channel << " " << reason << std::endl;
 }
 
 void debug_server::send(std::string raw)
 {
-    std::cout << get_name() << ": send " << raw << std::endl;
+    std::cout << get_id() << ": send " << raw << std::endl;
 }
 
 void debug_server::topic(std::string channel, std::string topic)
 {
-    std::cout << get_name() << ": topic " << channel << " " << topic << std::endl;
+    std::cout << get_id() << ": topic " << channel << " " << topic << std::endl;
 }
 
 void debug_server::whois(std::string target)
 {
-    std::cout << get_name() << ": whois " << target << std::endl;
+    std::cout << get_id() << ": whois " << target << std::endl;
 }
 
 } // !irccd
--- a/libirccd/irccd/daemon/command/server_connect_command.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/command/server_connect_command.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -35,7 +35,7 @@
 {
     auto server = server_util::from_json(irccd.get_service(), args);
 
-    if (irccd.servers().has(server->get_name()))
+    if (irccd.servers().has(server->get_id()))
         throw server_error(server_error::already_exists);
 
     irccd.servers().add(std::move(server));
--- a/libirccd/irccd/daemon/command/server_info_command.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/command/server_info_command.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -48,7 +48,7 @@
 
     // General stuff.
     response.push_back({"command", "server-info"});
-    response.push_back({"name", server->get_name()});
+    response.push_back({"name", server->get_id()});
     response.push_back({"host", server->get_host()});
     response.push_back({"port", server->get_port()});
     response.push_back({"nickname", server->get_nickname()});
@@ -57,11 +57,11 @@
     response.push_back({"channels", server->get_channels()});
 
     // Optional stuff.
-    if (server->get_flags() & server::ipv6)
+    if ((server->get_options() & server::options::ipv6) == server::options::ipv6)
         response.push_back({"ipv6", true});
-    if (server->get_flags() & server::ssl)
+    if ((server->get_options() & server::options::ssl) == server::options::ssl)
         response.push_back({"ssl", true});
-    if (server->get_flags() & server::ssl_verify)
+    if ((server->get_options() & server::options::ssl_verify) == server::options::ssl_verify)
         response.push_back({"sslVerify", true});
 
     client.write(response);
--- a/libirccd/irccd/daemon/command/server_list_command.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/command/server_list_command.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -36,7 +36,7 @@
     auto list = nlohmann::json::array();
 
     for (const auto& server : irccd.servers().servers())
-        list.push_back(server->get_name());
+        list.push_back(server->get_id());
 
     client.write({
         { "command",    "server-list"   },
--- a/libirccd/irccd/daemon/server.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/server.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -53,7 +53,7 @@
  * 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 clean_prefix(const std::map<channel_mode, char>& modes, std::string nickname)
+auto clean_prefix(const std::map<channel_mode, char>& modes, std::string nickname) -> std::string
 {
     if (nickname.length() == 0)
         return nickname;
@@ -71,7 +71,7 @@
  *
  * Read modes from the IRC event numeric.
  */
-std::map<channel_mode, char> isupport_extract_prefixes(const std::string& line)
+auto isupport_extract_prefixes(const std::string& line) -> std::map<channel_mode, char>
 {
     // FIXME: what if line has different size?
     std::pair<char, char> table[16];
@@ -117,21 +117,6 @@
     jchannels_.erase(std::remove(jchannels_.begin(), jchannels_.end(), channel), jchannels_.end());
 }
 
-server::server(boost::asio::io_service& service, std::string name, std::string host)
-    : name_(std::move(name))
-    , host_(std::move(host))
-    , service_(service)
-    , timer_(service)
-{
-    assert(!host_.empty());
-
-    // Initialize nickname and username.
-    auto user = sys::username();
-
-    nickname_ = user.empty() ? "irccd" : user;
-    username_ = user.empty() ? "irccd" : user;
-}
-
 void server::dispatch_connect(const irc::message&)
 {
     state_ = state::connected;
@@ -187,7 +172,7 @@
 void server::dispatch_invite(const irc::message& msg)
 {
     // If join-invite is set, join the channel.
-    if ((flags_ & join_invite) && is_self(msg.arg(0)))
+    if ((flags_ & options::join_invite) == options::join_invite && is_self(msg.arg(0)))
         join(msg.arg(1));
 
     on_invite({shared_from_this(), msg.prefix(), msg.arg(1), msg.arg(0)});
@@ -218,7 +203,7 @@
         remove_joined_channel(msg.arg(0));
 
         // Rejoin the channel if the option has been set and I was kicked.
-        if (flags_ & auto_rejoin)
+        if ((flags_ & options::auto_rejoin) == options::auto_rejoin)
             join(msg.arg(0));
     }
 
@@ -483,12 +468,81 @@
     }
 }
 
+server::server(boost::asio::io_service& service, std::string id, std::string host)
+    : id_(std::move(id))
+    , host_(std::move(host))
+    , service_(service)
+    , timer_(service)
+{
+    assert(!host_.empty());
+
+    // Initialize nickname and username.
+    auto user = sys::username();
+
+    nickname_ = user.empty() ? "irccd" : user;
+    username_ = user.empty() ? "irccd" : user;
+}
+
 server::~server()
 {
     conn_ = nullptr;
     state_ = state::disconnected;
 }
 
+auto server::get_state() const noexcept -> state
+{
+    return state_;
+}
+
+auto server::get_id() const noexcept -> const std::string&
+{
+    return id_;
+}
+
+auto server::get_host() const noexcept -> const std::string&
+{
+    return host_;
+}
+
+auto server::get_password() const noexcept -> const std::string&
+{
+    return password_;
+}
+
+void server::set_password(std::string password) noexcept
+{
+    password_ = std::move(password);
+}
+
+auto server::get_port() const noexcept -> std::uint16_t
+{
+    return port_;
+}
+
+void server::set_port(std::uint16_t port) noexcept
+{
+    port_ = port;
+}
+
+auto server::get_options() const noexcept -> options
+{
+    return flags_;
+}
+
+void server::set_options(options flags) noexcept
+{
+#if !defined(IRCCD_HAVE_SSL)
+    assert(!(flags & ssl));
+#endif
+
+    flags_ = flags;
+}
+
+auto server::get_nickname() const noexcept -> const std::string&
+{
+    return nickname_;
+}
+
 void server::set_nickname(std::string nickname)
 {
     if (state_ == state::connected)
@@ -497,11 +551,88 @@
         nickname_ = std::move(nickname);
 }
 
+auto server::get_username() const noexcept -> const std::string&
+{
+    return username_;
+}
+
+void server::set_username(std::string name) noexcept
+{
+    username_ = std::move(name);
+}
+
+auto server::get_realname() const noexcept -> const std::string&
+{
+    return realname_;
+}
+
+void server::set_realname(std::string realname) noexcept
+{
+    realname_ = std::move(realname);
+}
+
+auto server::get_ctcp_version() const noexcept -> const std::string&
+{
+    return ctcpversion_;
+}
+
 void server::set_ctcp_version(std::string ctcpversion)
 {
     ctcpversion_ = std::move(ctcpversion);
 }
 
+auto server::get_command_char() const noexcept -> const std::string&
+{
+    return command_char_;
+}
+
+void server::set_command_char(std::string command_char) noexcept
+{
+    assert(!command_char.empty());
+
+    command_char_ = std::move(command_char);
+}
+
+auto server::get_reconnect_tries() const noexcept -> std::int8_t
+{
+    return recotries_;
+}
+
+void server::set_reconnect_tries(std::int8_t reconnect_tries) noexcept
+{
+    recotries_ = reconnect_tries;
+}
+
+auto server::get_reconnect_delay() const noexcept -> std::uint16_t
+{
+    return recodelay_;
+}
+
+void server::set_reconnect_delay(std::uint16_t reconnect_delay) noexcept
+{
+    recodelay_ = reconnect_delay;
+}
+
+auto server::get_ping_timeout() const noexcept -> std::uint16_t
+{
+    return timeout_;
+}
+
+void server::set_ping_timeout(std::uint16_t ping_timeout) noexcept
+{
+    timeout_ = ping_timeout;
+}
+
+auto server::get_channels() const noexcept -> const std::vector<std::string>&
+{
+    return jchannels_;
+}
+
+auto server::is_self(const std::string& target) const noexcept -> bool
+{
+    return nickname_ == irc::user::parse(target).nick();
+}
+
 void server::connect() noexcept
 {
     assert(state_ == state::disconnected || state_ == state::waiting);
@@ -514,7 +645,7 @@
     (void)res_init();
 #endif
 
-    if (flags_ & ssl) {
+    if ((flags_ & options::ssl) == options::ssl) {
 #if defined(IRCCD_HAVE_SSL)
         conn_ = std::make_shared<irc::tls_connection>(service_);
 #else
@@ -522,7 +653,7 @@
          * If SSL is not compiled in, the caller is responsible of not setting
          * the flag.
          */
-        assert(!(flags_ & ssl));
+        assert((flags_ & options::ssl) != options::ssl);
 #endif
     } else
         conn_ = std::make_shared<irc::ip_connection>(service_);
@@ -537,6 +668,7 @@
 {
     conn_ = nullptr;
     state_ = state::disconnected;
+    queue_.clear();
     on_disconnect({shared_from_this()});
 }
 
@@ -546,11 +678,6 @@
     connect();
 }
 
-bool server::is_self(const std::string& target) const noexcept
-{
-    return nickname_ == irc::user::parse(target).nick();
-}
-
 void server::invite(std::string target, std::string channel)
 {
     assert(!target.empty());
@@ -692,7 +819,7 @@
 {
 }
 
-const std::error_category& server_category()
+auto server_category() -> const std::error_category&
 {
     static const class category : public std::error_category {
     public:
@@ -753,7 +880,7 @@
     return category;
 }
 
-std::error_code make_error_code(server_error::error e)
+auto make_error_code(server_error::error e) -> std::error_code
 {
     return {static_cast<int>(e), server_category()};
 }
--- a/libirccd/irccd/daemon/server.hpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/server.hpp	Thu Jul 19 12:54:00 2018 +0200
@@ -237,7 +237,8 @@
     /**
      * \brief Various options for server.
      */
-    enum {
+    enum class options : std::uint8_t {
+        none        = 0,                    //!< No options
         ipv6        = (1 << 0),             //!< Connect using IPv6
         ssl         = (1 << 1),             //!< Use SSL
         ssl_verify  = (1 << 2),             //!< Verify SSL
@@ -248,7 +249,7 @@
     /**
      * \brief Describe current server state.
      */
-    enum class state {
+    enum class state : std::uint8_t {
         disconnected,       //!< not connected at all,
         connecting,         //!< network connection in progress,
         identifying,        //!< sending nick, user and password commands,
@@ -395,13 +396,13 @@
     std::vector<std::string> jchannels_;
 
     // Identifier.
-    std::string name_;
+    std::string id_;
 
     // Connection information.
     std::string host_;
     std::string password_;
     std::uint16_t port_{6667};
-    std::uint8_t flags_{0};
+    options flags_{options::none};
 
     // Identity.
     std::string nickname_;
@@ -427,7 +428,7 @@
     std::map<std::string, std::set<std::string>> names_map_;
     std::map<std::string, whois_info> whois_map_;
 
-    void remove_joined_channel(const std::string& channel);
+    void remove_joined_channel(const std::string&);
 
     void dispatch_connect(const irc::message&);
     void dispatch_endofnames(const irc::message&);
@@ -463,9 +464,7 @@
      * \param name the identifier
      * \param host the hostname
      */
-    server(boost::asio::io_service& service,
-           std::string name,
-           std::string host = "localhost");
+    server(boost::asio::io_service& service, std::string id, std::string host = "localhost");
 
     /**
      * Destructor. Close the connection if needed.
@@ -477,50 +476,28 @@
      *
      * \return the state
      */
-    inline state get_state() const noexcept
-    {
-        return state_;
-    }
+    auto get_state() const noexcept -> state;
 
     /**
      * Get the server identifier.
      *
      * \return the id
      */
-    inline const std::string& get_name() const noexcept
-    {
-        return name_;
-    }
+    auto get_id() const noexcept -> const std::string&;
 
     /**
      * Get the hostname.
      *
      * \return the hostname
      */
-    inline const std::string& get_host() const noexcept
-    {
-        return host_;
-    }
-
-    /**
-     * Set the hostname.
-     *
-     * \param host the hostname
-     */
-    inline void set_host(std::string host) noexcept
-    {
-        host_ = std::move(host);
-    }
+    auto get_host() const noexcept -> const std::string&;
 
     /**
      * Get the password.
      *
      * \return the password
      */
-    inline const std::string& get_password() const noexcept
-    {
-        return password_;
-    }
+    auto get_password() const noexcept -> const std::string&;
 
     /**
      * Set the password.
@@ -529,70 +506,48 @@
      *
      * \param password the password
      */
-    inline void set_password(std::string password) noexcept
-    {
-        password_ = std::move(password);
-    }
+    void set_password(std::string password) noexcept;
 
     /**
      * Get the port.
      *
      * \return the port
      */
-    inline std::uint16_t get_port() const noexcept
-    {
-        return port_;
-    }
+    auto get_port() const noexcept -> std::uint16_t;
 
     /**
      * Set the port.
      *
      * \param port the port
      */
-    inline void set_port(std::uint16_t port) noexcept
-    {
-        port_ = port;
-    }
+    void set_port(std::uint16_t port) noexcept;
 
     /**
-     * Get the flags.
+     * Get the options flags.
      *
      * \return the flags
      */
-    inline std::uint8_t get_flags() const noexcept
-    {
-        return flags_;
-    }
+    auto get_options() const noexcept -> options;
 
     /**
-     * Set the flags.
+     * Set the options flags.
      *
      * \param flags the flags
      */
-    inline void set_flags(std::uint8_t flags) noexcept
-    {
-#if !defined(IRCCD_HAVE_SSL)
-        assert(!(flags & ssl));
-#endif
-
-        flags_ = flags;
-    }
+    void set_options(options flags) noexcept;
 
     /**
      * Get the nickname.
      *
      * \return the nickname
      */
-    inline const std::string& get_nickname() const noexcept
-    {
-        return nickname_;
-    }
+    auto get_nickname() const noexcept -> const std::string&;
 
     /**
      * Set the nickname.
      *
      * If the server is connected, send a nickname command to the IRC server,
-     * otherwise change it locally.
+     * otherwise change it instantly.
      *
      * \param nickname the nickname
      */
@@ -603,10 +558,7 @@
      *
      * \return the username
      */
-    inline const std::string& get_username() const noexcept
-    {
-        return username_;
-    }
+    auto get_username() const noexcept -> const std::string&;
 
     /**
      * Set the username.
@@ -614,20 +566,14 @@
      * \param name the username
      * \note the username will be changed on the next connection
      */
-    inline void set_username(std::string name) noexcept
-    {
-        username_ = std::move(name);
-    }
+    void set_username(std::string name) noexcept;
 
     /**
      * Get the realname.
      *
      * \return the realname
      */
-    inline const std::string& get_realname() const noexcept
-    {
-        return realname_;
-    }
+    auto get_realname() const noexcept -> const std::string&;
 
     /**
      * Set the realname.
@@ -635,20 +581,14 @@
      * \param realname the username
      * \note the username will be changed on the next connection
      */
-    inline void set_realname(std::string realname) noexcept
-    {
-        realname_ = std::move(realname);
-    }
+    void set_realname(std::string realname) noexcept;
 
     /**
      * Get the CTCP version.
      *
      * \return the CTCP version
      */
-    inline const std::string& get_ctcp_version() const noexcept
-    {
-        return ctcpversion_;
-    }
+    auto get_ctcp_version() const noexcept -> const std::string&;
 
     /**
      * Set the CTCP version.
@@ -662,10 +602,7 @@
      *
      * \return the character
      */
-    inline const std::string& get_command_char() const noexcept
-    {
-        return command_char_;
-    }
+    auto get_command_char() const noexcept -> const std::string&;
 
     /**
      * Set the command character.
@@ -673,22 +610,14 @@
      * \pre !command_char_.empty()
      * \param command_char the command character
      */
-    inline void set_command_char(std::string command_char) noexcept
-    {
-        assert(!command_char.empty());
-
-        command_char_ = std::move(command_char);
-    }
+    void set_command_char(std::string command_char) noexcept;
 
     /**
      * Get the number of reconnections before giving up.
      *
      * \return the number of reconnections
      */
-    inline std::int8_t get_reconnect_tries() const noexcept
-    {
-        return recotries_;
-    }
+    auto get_reconnect_tries() const noexcept -> std::int8_t;
 
     /**
      * Set the number of reconnections to test before giving up.
@@ -697,60 +626,42 @@
      *
      * \param reconnect_tries the number of reconnections
      */
-    inline void set_reconnect_tries(std::int8_t reconnect_tries) noexcept
-    {
-        recotries_ = reconnect_tries;
-    }
+    void set_reconnect_tries(std::int8_t reconnect_tries) noexcept;
 
     /**
      * Get the reconnection delay before retrying.
      *
      * \return the number of seconds
      */
-    inline std::uint16_t get_reconnect_delay() const noexcept
-    {
-        return recodelay_;
-    }
+    auto get_reconnect_delay() const noexcept -> std::uint16_t;
 
     /**
      * Set the number of seconds before retrying.
      *
      * \param reconnect_delay the number of seconds
      */
-    inline void set_reconnect_delay(std::uint16_t reconnect_delay) noexcept
-    {
-        recodelay_ = reconnect_delay;
-    }
+    void set_reconnect_delay(std::uint16_t reconnect_delay) noexcept;
 
     /**
      * Get the ping timeout.
      *
      * \return the ping timeout
      */
-    inline std::uint16_t get_ping_timeout() const noexcept
-    {
-        return timeout_;
-    }
+    auto get_ping_timeout() const noexcept -> std::uint16_t;
 
     /**
      * Set the ping timeout before considering a server as dead.
      *
      * \param ping_timeout the delay in seconds
      */
-    inline void set_ping_timeout(std::uint16_t ping_timeout) noexcept
-    {
-        timeout_ = ping_timeout;
-    }
+    void set_ping_timeout(std::uint16_t ping_timeout) noexcept;
 
     /**
      * Get the list of channels joined.
      *
      * \return the channels
      */
-    inline const std::vector<std::string>& get_channels() const noexcept
-    {
-        return jchannels_;
-    }
+    auto get_channels() const noexcept -> const std::vector<std::string>&;
 
     /**
      * Determine if the nickname is the bot itself.
@@ -758,7 +669,7 @@
      * \param nick the nickname to check
      * \return true if it is the bot
      */
-    bool is_self(const std::string& nick) const noexcept;
+    auto is_self(const std::string& nick) const noexcept -> bool;
 
     /**
      * Start connecting.
@@ -887,6 +798,97 @@
 };
 
 /**
+ * \cond IRCCD_HIDDEN_SYMBOLS
+ */
+
+/**
+ * Apply bitwise XOR.
+ *
+ * \param v1 the first value
+ * \param v2 the second value
+ * \return the new value
+ */
+inline auto operator^(server::options v1, server::options v2) noexcept -> server::options
+{
+    return static_cast<server::options>(static_cast<unsigned>(v1) ^ static_cast<unsigned>(v2));
+}
+
+/**
+ * Apply bitwise AND.
+ *
+ * \param v1 the first value
+ * \param v2 the second value
+ * \return the new value
+ */
+inline auto operator&(server::options v1, server::options v2) noexcept -> server::options
+{
+    return static_cast<server::options>(static_cast<unsigned>(v1) & static_cast<unsigned>(v2));
+}
+
+/**
+ * Apply bitwise OR.
+ *
+ * \param v1 the first value
+ * \param v2 the second value
+ * \return the new value
+ */
+inline auto operator|(server::options v1, server::options v2) noexcept -> server::options
+{
+    return static_cast<server::options>(static_cast<unsigned>(v1) | static_cast<unsigned>(v2));
+}
+
+/**
+ * Apply bitwise NOT.
+ *
+ * \param v the value
+ * \return the complement
+ */
+inline auto operator~(server::options v) noexcept -> server::options
+{
+    return static_cast<server::options>(~static_cast<unsigned>(v));
+}
+
+/**
+ * Assign bitwise OR.
+ *
+ * \param v1 the first value
+ * \param v2 the second value
+ * \return the new value
+ */
+inline auto operator|=(server::options& v1, server::options v2) noexcept -> server::options&
+{
+    return v1 = v1 | v2;
+}
+
+/**
+ * Assign bitwise AND.
+ *
+ * \param v1 the first value
+ * \param v2 the second value
+ * \return the new value
+ */
+inline auto operator&=(server::options& v1, server::options v2) noexcept -> server::options&
+{
+    return v1 = v1 & v2;
+}
+
+/**
+ * Assign bitwise XOR.
+ *
+ * \param v1 the first value
+ * \param v2 the second value
+ * \return the new value
+ */
+inline auto operator^=(server::options& v1, server::options v2) noexcept -> server::options&
+{
+    return v1 = v1 ^ v2;
+}
+
+/**
+ * \endcond
+ */
+
+/**
  * \brief Server error.
  */
 class server_error : public std::system_error {
@@ -973,14 +975,14 @@
  *
  * \return the singleton
  */
-const std::error_category& server_category();
+auto server_category() -> const std::error_category&;
 
 /**
  * Create a boost::system::error_code from server_error::error enum.
  *
  * \param e the error code
  */
-std::error_code make_error_code(server_error::error e);
+auto make_error_code(server_error::error e) -> std::error_code;
 
 } // !irccd
 
--- a/libirccd/irccd/daemon/server_util.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/server_util.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -77,15 +77,15 @@
     const auto join_invite = sc.get("join-invite");
 
     if (string_util::is_boolean(ipv6.value()))
-        sv.set_flags(sv.get_flags() | server::ipv6);
+        sv.set_options(sv.get_options() | server::options::ipv6);
     if (string_util::is_boolean(ssl.value()))
-        sv.set_flags(sv.get_flags() | server::ssl);
+        sv.set_options(sv.get_options() | server::options::ssl);
     if (string_util::is_boolean(ssl_verify.value()))
-        sv.set_flags(sv.get_flags() | server::ssl_verify);
+        sv.set_options(sv.get_options() | server::options::ssl_verify);
     if (string_util::is_boolean(auto_rejoin.value()))
-        sv.set_flags(sv.get_flags() | server::auto_rejoin);
+        sv.set_options(sv.get_options() | server::options::auto_rejoin);
     if (string_util::is_boolean(join_invite.value()))
-        sv.set_flags(sv.get_flags() | server::join_invite);
+        sv.set_options(sv.get_options() | server::options::join_invite);
 }
 
 void from_config_load_numeric_parameters(server& sv, const ini::section& sc)
@@ -162,20 +162,20 @@
     const auto ssl_verify = parser.get<bool>("sslVerify");
 
     if (ipv6.value_or(false))
-        sv.set_flags(sv.get_flags() | server::ipv6);
+        sv.set_options(sv.get_options() | server::options::ipv6);
     if (auto_rejoin.value_or(false))
-        sv.set_flags(sv.get_flags() | server::auto_rejoin);
+        sv.set_options(sv.get_options() | server::options::auto_rejoin);
     if (join_invite.value_or(false))
-        sv.set_flags(sv.get_flags() | server::join_invite);
+        sv.set_options(sv.get_options() | server::options::join_invite);
 
     if (ssl.value_or(false))
 #if !defined(IRCCD_HAVE_SSL)
         throw server_error(server_error::ssl_disabled);
 #else
-        sv.set_flags(sv.get_flags() | server::ssl);
+        sv.set_options(sv.get_options() | server::options::ssl);
 #endif
     if (ssl_verify.value_or(false))
-        sv.set_flags(sv.get_flags() | server::ssl_verify);
+        sv.set_options(sv.get_options() | server::options::ssl_verify);
 }
 
 } // !namespace
--- a/libirccd/irccd/daemon/service/server_service.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/libirccd/irccd/daemon/service/server_service.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -65,11 +65,11 @@
 {
     irccd_.get_log().debug(*ev.server) << "event onConnect" << std::endl;
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onConnect"             },
-        { "server",     ev.server->get_name()   }
+        { "event",      "onConnect"         },
+        { "server",     ev.server->get_id() }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), /* origin */ "", /* channel */ "",
+    dispatch(irccd_, ev.server->get_id(), /* origin */ "", /* channel */ "",
         [=] (plugin&) -> std::string {
             return "onConnect";
         },
@@ -83,11 +83,11 @@
 {
     irccd_.get_log().debug(*ev.server) << "event onDisconnect" << std::endl;
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onDisconnect"          },
-        { "server",     ev.server->get_name()   }
+        { "event",      "onDisconnect"      },
+        { "server",     ev.server->get_id() }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), /* origin */ "", /* channel */ "",
+    dispatch(irccd_, ev.server->get_id(), /* origin */ "", /* channel */ "",
         [=] (plugin&) -> std::string {
             return "onDisconnect";
         },
@@ -110,13 +110,13 @@
     irccd_.get_log().debug(*ev.server) << "  target: " << ev.nickname << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onInvite"              },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              }
+        { "event",      "onInvite"          },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin&) -> std::string {
             return "onInvite";
         },
@@ -133,13 +133,13 @@
     irccd_.get_log().debug(*ev.server) << "  channel: " << ev.channel << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onJoin"                },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              }
+        { "event",      "onJoin"            },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin&) -> std::string {
             return "onJoin";
         },
@@ -158,15 +158,15 @@
     irccd_.get_log().debug(*ev.server) << "  reason: " << ev.reason << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onKick"                },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              },
-        { "target",     ev.target               },
-        { "reason",     ev.reason               }
+        { "event",      "onKick"            },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "target",     ev.target           },
+        { "reason",     ev.reason           }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin&) -> std::string {
             return "onKick";
         },
@@ -184,19 +184,19 @@
     irccd_.get_log().debug(*ev.server) << "  message: " << ev.message << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onMessage"             },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              },
-        { "message",    ev.message              }
+        { "event",      "onMessage"         },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "message",    ev.message          }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin& plugin) -> std::string {
             return server_util::parse_message(
                 ev.message,
                 ev.server->get_command_char(),
-                plugin.get_name()
+                plugin.get_id()
             ).type == server_util::message_pack::type::command ? "onCommand" : "onMessage";
         },
         [=] (plugin& plugin) mutable {
@@ -204,7 +204,7 @@
             auto pack = server_util::parse_message(
                 copy.message,
                 copy.server->get_command_char(),
-                plugin.get_name()
+                plugin.get_id()
             );
 
             copy.message = pack.message;
@@ -225,14 +225,14 @@
     irccd_.get_log().debug(*ev.server) << "  message: " << ev.message << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onMe"                  },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "target",     ev.channel              },
-        { "message",    ev.message              }
+        { "event",      "onMe"              },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "target",     ev.channel          },
+        { "message",    ev.message          }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin&) -> std::string {
             return "onMe";
         },
@@ -253,17 +253,17 @@
     irccd_.get_log().debug(*ev.server) << "  mask: " << ev.mask << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onMode"                },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              },
-        { "mode",       ev.mode                 },
-        { "limit",      ev.limit                },
-        { "user",       ev.user                 },
-        { "mask",       ev.mask                 }
+        { "event",      "onMode"            },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "mode",       ev.mode             },
+        { "limit",      ev.limit            },
+        { "user",       ev.user             },
+        { "mask",       ev.mask             }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, /* channel */ "",
+    dispatch(irccd_, ev.server->get_id(), ev.origin, /* channel */ "",
         [=] (plugin &) -> std::string {
             return "onMode";
         },
@@ -285,13 +285,13 @@
         names.push_back(v);
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onNames"               },
-        { "server",     ev.server->get_name()   },
-        { "channel",    ev.channel              },
-        { "names",      std::move(names)        }
+        { "event",      "onNames"           },
+        { "server",     ev.server->get_id() },
+        { "channel",    ev.channel          },
+        { "names",      std::move(names)    }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), /* origin */ "", ev.channel,
+    dispatch(irccd_, ev.server->get_id(), /* origin */ "", ev.channel,
         [=] (plugin&) -> std::string {
             return "onNames";
         },
@@ -308,13 +308,13 @@
     irccd_.get_log().debug(*ev.server) << "  nickname: " << ev.nickname << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onNick"                },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "nickname",   ev.nickname             }
+        { "event",      "onNick"            },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "nickname",   ev.nickname         }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, /* channel */ "",
+    dispatch(irccd_, ev.server->get_id(), ev.origin, /* channel */ "",
         [=] (plugin&) -> std::string {
             return "onNick";
         },
@@ -332,14 +332,14 @@
     irccd_.get_log().debug(*ev.server) << "  message: " << ev.message << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onNotice"              },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              },
-        { "message",    ev.message              }
+        { "event",      "onNotice"          },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "message",    ev.message          }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, /* channel */ "",
+    dispatch(irccd_, ev.server->get_id(), ev.origin, /* channel */ "",
         [=] (plugin&) -> std::string {
             return "onNotice";
         },
@@ -357,14 +357,14 @@
     irccd_.get_log().debug(*ev.server) << "  reason: " << ev.reason << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onPart"                },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              },
-        { "reason",     ev.reason               }
+        { "event",      "onPart"            },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "reason",     ev.reason           }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin&) -> std::string {
             return "onPart";
         },
@@ -382,14 +382,14 @@
     irccd_.get_log().debug(*ev.server) << "  topic: " << ev.topic << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onTopic"               },
-        { "server",     ev.server->get_name()   },
-        { "origin",     ev.origin               },
-        { "channel",    ev.channel              },
-        { "topic",      ev.topic                }
+        { "event",      "onTopic"           },
+        { "server",     ev.server->get_id() },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "topic",      ev.topic            }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), ev.origin, ev.channel,
+    dispatch(irccd_, ev.server->get_id(), ev.origin, ev.channel,
         [=] (plugin&) -> std::string {
             return "onTopic";
         },
@@ -409,15 +409,15 @@
     irccd_.get_log().debug(*ev.server) << "  channels: " << string_util::join(ev.whois.channels, ", ") << std::endl;
 
     irccd_.transports().broadcast(nlohmann::json::object({
-        { "event",      "onWhois"               },
-        { "server",     ev.server->get_name()   },
-        { "nickname",   ev.whois.nick           },
-        { "username",   ev.whois.user           },
-        { "host",       ev.whois.host           },
-        { "realname",   ev.whois.realname       }
+        { "event",      "onWhois"           },
+        { "server",     ev.server->get_id() },
+        { "nickname",   ev.whois.nick       },
+        { "username",   ev.whois.user       },
+        { "host",       ev.whois.host       },
+        { "realname",   ev.whois.realname   }
     }));
 
-    dispatch(irccd_, ev.server->get_name(), /* origin */ "", /* channel */ "",
+    dispatch(irccd_, ev.server->get_id(), /* origin */ "", /* channel */ "",
         [=] (plugin&) -> std::string {
             return "onWhois";
         },
@@ -435,13 +435,13 @@
 bool server_service::has(const std::string& name) const noexcept
 {
     return std::count_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
-        return server->get_name() == name;
+        return server->get_id() == name;
     }) > 0;
 }
 
 void server_service::add(std::shared_ptr<server> server)
 {
-    assert(!has(server->get_name()));
+    assert(!has(server->get_id()));
 
     server->on_connect.connect(boost::bind(&server_service::handle_connect, this, _1));
     server->on_disconnect.connect(boost::bind(&server_service::handle_disconnect, this, _1));
@@ -465,7 +465,7 @@
 std::shared_ptr<server> server_service::get(const std::string& name) const noexcept
 {
     const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
-        return server->get_name() == name;
+        return server->get_id() == name;
     });
 
     if (it == servers_.end())
@@ -490,7 +490,7 @@
 void server_service::remove(const std::string& name)
 {
     const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
-        return server->get_name() == name;
+        return server->get_id() == name;
     });
 
     if (it != servers_.end()) {
@@ -524,7 +524,7 @@
         try {
             auto server = server_util::from_config(irccd_.get_service(), cfg, section);
 
-            if (has(server->get_name()))
+            if (has(server->get_id()))
                 throw server_error(server_error::already_exists);
 
             add(std::move(server));
@@ -543,8 +543,7 @@
 
 auto loggable_traits<server>::get_component(const server& sv) -> std::string_view
 {
-    // TODO: get id instead.
-    return sv.get_name();
+    return sv.get_id();
 }
 
 } // !logger
--- a/plugins/links/links.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/plugins/links/links.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -167,7 +167,7 @@
     subst.keywords.emplace("channel", channel_);
     subst.keywords.emplace("nickname", irc::user::parse(origin_).nick());
     subst.keywords.emplace("origin", origin_);
-    subst.keywords.emplace("server", server_->get_name());
+    subst.keywords.emplace("server", server_->get_id());
     subst.keywords.emplace("title", title);
 
     server_->message(channel_, format(formats::info, subst));
--- a/tests/src/libirccd/command-server-connect/main.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/tests/src/libirccd/command-server-connect/main.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -42,7 +42,7 @@
     const auto s = daemon_->servers().get("local");
 
     BOOST_TEST(s);
-    BOOST_TEST(s->get_name() == "local");
+    BOOST_TEST(s->get_id() == "local");
     BOOST_TEST(s->get_host() == "irc.example.org");
     BOOST_TEST(s->get_port() == 6667U);
 }
@@ -71,7 +71,7 @@
     const auto s = daemon_->servers().get("local2");
 
     BOOST_TEST(s);
-    BOOST_TEST(s->get_name() == "local2");
+    BOOST_TEST(s->get_id() == "local2");
     BOOST_TEST(s->get_host() == "irc.example2.org");
     BOOST_TEST(s->get_port() == 18000U);
     BOOST_TEST(s->get_password() == "nonono");
@@ -80,10 +80,10 @@
     BOOST_TEST(s->get_username() == "frc");
     BOOST_TEST(s->get_command_char() == "::");
     BOOST_TEST(s->get_ctcp_version() == "ultra bot");
-    BOOST_TEST(s->get_flags() & server::ssl);
-    BOOST_TEST(s->get_flags() & server::ssl_verify);
-    BOOST_TEST(s->get_flags() & server::auto_rejoin);
-    BOOST_TEST(s->get_flags() & server::join_invite);
+    BOOST_TEST(static_cast<bool>(s->get_options() & server::options::ssl));
+    BOOST_TEST(static_cast<bool>(s->get_options() & server::options::ssl_verify));
+    BOOST_TEST(static_cast<bool>(s->get_options() & server::options::auto_rejoin));
+    BOOST_TEST(static_cast<bool>(s->get_options() & server::options::join_invite));
 }
 
 #endif // !IRCCD_HAVE_SSL
--- a/tests/src/libirccd/command-server-info/main.cpp	Thu Jul 19 07:22:36 2018 +0200
+++ b/tests/src/libirccd/command-server-info/main.cpp	Thu Jul 19 12:54:00 2018 +0200
@@ -33,9 +33,8 @@
 
 BOOST_AUTO_TEST_CASE(basic)
 {
-    auto server = std::make_unique<journal_server>(service_, "test");
+    auto server = std::make_unique<journal_server>(service_, "test", "example.org");
 
-    server->set_host("example.org");
     server->set_port(8765);
     server->set_password("none");
     server->set_nickname("pascal");