#include "self_thread.hpp" #include "connection.hpp" #include #include #include using namespace std::literals; auto SelfThread::on_welcome(IrcMsg const& irc) -> void { nickname_ = irc.args[0]; } auto SelfThread::on_nick(IrcMsg const& irc) -> void { if (is_my_mask(irc.source)) { nickname_ = irc.args[0]; } } auto SelfThread::on_umodeis(IrcMsg const& irc) -> void { mode_ = irc.args[1]; } auto SelfThread::on_join(IrcMsg const& irc) -> void { if (is_my_mask(irc.source)) { channels_.insert(std::string{irc.args[0]}); } } auto SelfThread::on_kick(IrcMsg const& irc) -> void { if (is_my_nick(irc.args[1])) { channels_.erase(std::string{irc.args[0]}); } } auto SelfThread::on_part(IrcMsg const& irc) -> void { if (is_my_mask(irc.source)) { channels_.erase(std::string{irc.args[0]}); } } auto SelfThread::on_mode(IrcMsg const& irc) -> void { if (is_my_nick(irc.args[0])) { auto polarity = true; for (char const c : irc.args[1]) { switch (c) { case '+': polarity = true; break; case '-': polarity = false; break; default: if (polarity) { mode_ += c; } else { auto const ix = mode_.find(c); if (ix != std::string::npos) { mode_.erase(ix, 1); } } break; } } } } auto SelfThread::on_isupport(const IrcMsg &msg) -> void { auto const hi = msg.args.size() - 1; for (int i = 1; i < hi; ++i) { auto &entry = msg.args[i]; // Leading minus means to stop support if (entry.starts_with("-")) { auto const key = std::string{entry.substr(1)}; if (auto cursor = isupport_.find(key); cursor != isupport_.end()) { isupport_.erase(cursor); } } else if (auto const cursor = entry.find('='); cursor != entry.npos) { isupport_.emplace(entry.substr(0, cursor), entry.substr(cursor+1)); } else { isupport_.emplace(entry, std::string{}); } } } auto SelfThread::start(Connection& connection) -> std::shared_ptr { auto thread = std::make_shared(connection); connection.sig_ircmsg.connect([thread](auto cmd, auto& msg) { switch (cmd) { case IrcCommand::JOIN: thread->on_join(msg); break; case IrcCommand::KICK: thread->on_kick(msg); break; case IrcCommand::MODE: thread->on_mode(msg); break; case IrcCommand::NICK: thread->on_nick(msg); break; case IrcCommand::PART: thread->on_part(msg); break; case IrcCommand::RPL_ISUPPORT: thread->on_isupport(msg); break; case IrcCommand::RPL_UMODEIS: thread->on_umodeis(msg); break; case IrcCommand::RPL_WELCOME: thread->on_welcome(msg); break; default: break; } }); connection.sig_authenticate.connect([thread](auto msg) { thread->on_authenticate(msg); }); return thread; } auto SelfThread::get_my_nickname() const -> std::string const& { return nickname_; } auto SelfThread::get_my_mode() const -> std::string const& { return mode_; } auto SelfThread::get_my_channels() const -> std::unordered_set const& { return channels_; } auto SelfThread::is_my_nick(std::string_view nick) const -> bool { return nick == nickname_; } auto SelfThread::is_my_mask(std::string_view mask) const -> bool { auto const bang = mask.find('!'); return bang != std::string_view::npos && nickname_ == mask.substr(0, bang); } auto SelfThread::on_authenticate(const std::string_view body) -> void { if (not sasl_mechanism_) { BOOST_LOG_TRIVIAL(warning) << "Unexpected AUTHENTICATE from server"sv; connection_.send_authenticate_abort(); return; } if (auto reply = sasl_mechanism_->step(body)) { connection_.send_authenticate_encoded(*reply); // Clean up completed SASL transactions if (sasl_mechanism_->is_complete()) { sasl_mechanism_.reset(); } } } auto SelfThread::start_sasl(std::unique_ptr mechanism) -> void { if (sasl_mechanism_) { connection_.send_authenticate("*"sv); // abort SASL } sasl_mechanism_ = std::move(mechanism); connection_.send_authenticate(sasl_mechanism_->mechanism_name()); }