#include "registration.hpp" #include "connection.hpp" #include "ircmsg.hpp" #include #include #include Registration::Registration( Settings settings, std::shared_ptr client ) : settings_{std::move(settings)} , client_{std::move(client)} { } auto Registration::on_connect() -> void { auto &connection = client_->get_connection(); client_->list_caps(); caps_slot_ = client_->sig_cap_ls.connect([self = shared_from_this()](auto &caps) { self->caps_slot_.disconnect(); self->on_cap_list(caps); }); slot_ = connection.sig_ircmsg.connect( [self = shared_from_this()](const auto cmd, auto &msg) { self->on_ircmsg(cmd, msg); } ); if (not settings_.password.empty()) { connection.send_pass(settings_.password); } connection.send_user(settings_.username, settings_.realname); connection.send_nick(settings_.nickname); } auto Registration::on_cap_list(const std::unordered_map &caps) -> void { std::string request; static const char * const want [] { "account-notify", "account-tag", "batch", "chghost", "draft/chathistory", "extended-join", "invite-notify", "server-time", "setname", "soju.im/no-implicit-names", "solanum.chat/identify-msg", "solanum.chat/oper", "solanum.chat/realhost", }; for (const auto cap : want) { if (caps.contains(cap)) { request.append(cap); request.push_back(' '); } } bool do_sasl = settings_.sasl_mechanism && caps.contains("sasl"); if (do_sasl) { request.append("sasl "); } if (not request.empty()) { request.pop_back(); // trailing space client_->get_connection().send_cap_req(request); } if (do_sasl) { client_->start_sasl(std::move(settings_.sasl_mechanism)); } else { client_->get_connection().send_cap_end(); } } auto Registration::start( Settings settings, std::shared_ptr client ) -> std::shared_ptr { const auto thread = std::make_shared(std::move(settings), std::move(client)); thread->slot_ = thread->client_->get_connection().sig_connect.connect([thread]() { thread->slot_.disconnect(); thread->on_connect(); }); return thread; } auto Registration::randomize_nick() -> void { std::string new_nick; new_nick += settings_.nickname.substr(0, 8); std::random_device rd; std::mt19937 gen{rd()}; std::uniform_int_distribution<> distrib(0, 35); for (int i = 0; i < 8; ++i) { const auto x = distrib(gen); new_nick += x < 10 ? '0' + x : 'A' + (x-10); } client_->get_connection().send_nick(new_nick); } auto Registration::on_ircmsg(const IrcCommand cmd, const IrcMsg &msg) -> void { switch (cmd) { default: break; case IrcCommand::ERR_NICKNAMEINUSE: case IrcCommand::ERR_ERRONEUSNICKNAME: case IrcCommand::ERR_UNAVAILRESOURCE: randomize_nick(); break; case IrcCommand::RPL_WELCOME: slot_.disconnect(); caps_slot_.disconnect(); break; case IrcCommand::RPL_SASLSUCCESS: case IrcCommand::ERR_SASLFAIL: client_->get_connection().send_cap_end(); break; } }