2023-11-26 16:48:21 -08:00
|
|
|
#include "self_thread.hpp"
|
|
|
|
|
|
|
|
#include "connection.hpp"
|
|
|
|
|
2025-01-25 12:25:38 -08:00
|
|
|
#include <mybase64.hpp>
|
|
|
|
|
2025-01-24 14:48:15 -08:00
|
|
|
#include <boost/container/flat_map.hpp>
|
2025-01-25 12:25:38 -08:00
|
|
|
#include <boost/log/trivial.hpp>
|
|
|
|
|
|
|
|
using namespace std::literals;
|
2025-01-24 14:48:15 -08:00
|
|
|
|
2024-03-03 12:53:59 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-24 14:48:15 -08:00
|
|
|
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];
|
2025-01-25 12:25:38 -08:00
|
|
|
|
|
|
|
// Leading minus means to stop support
|
2025-01-24 14:48:15 -08:00
|
|
|
if (entry.starts_with("-")) {
|
2025-01-25 12:25:38 -08:00
|
|
|
auto const key = std::string{entry.substr(1)};
|
2025-01-24 14:48:15 -08:00
|
|
|
if (auto cursor = isupport_.find(key); cursor != isupport_.end()) {
|
|
|
|
isupport_.erase(cursor);
|
|
|
|
}
|
2025-01-25 12:25:38 -08:00
|
|
|
} else if (auto const cursor = entry.find('='); cursor != entry.npos) {
|
2025-01-24 14:48:15 -08:00
|
|
|
isupport_.emplace(entry.substr(0, cursor), entry.substr(cursor+1));
|
|
|
|
} else {
|
|
|
|
isupport_.emplace(entry, std::string{});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-26 16:48:21 -08:00
|
|
|
auto SelfThread::start(Connection& connection) -> std::shared_ptr<SelfThread>
|
|
|
|
{
|
|
|
|
auto thread = std::make_shared<SelfThread>(connection);
|
|
|
|
|
2025-01-22 23:49:48 -08:00
|
|
|
connection.sig_ircmsg.connect([thread](auto cmd, auto& msg)
|
2023-11-26 16:48:21 -08:00
|
|
|
{
|
2025-01-22 23:49:48 -08:00
|
|
|
switch (cmd)
|
2023-11-26 16:48:21 -08:00
|
|
|
{
|
2025-01-24 14:48:15 -08:00
|
|
|
case IrcCommand::JOIN: thread->on_join(msg); break;
|
|
|
|
case IrcCommand::KICK: thread->on_kick(msg); break;
|
|
|
|
case IrcCommand::MODE: thread->on_mode(msg); break;
|
2025-01-25 12:25:38 -08:00
|
|
|
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;
|
2023-11-26 16:48:21 -08:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2025-01-25 12:25:38 -08:00
|
|
|
connection.sig_authenticate.connect([thread](auto msg) {
|
|
|
|
thread->on_authenticate(msg);
|
|
|
|
});
|
|
|
|
|
2023-11-26 16:48:21 -08:00
|
|
|
return thread;
|
|
|
|
}
|
2024-03-03 12:27:36 -08:00
|
|
|
|
|
|
|
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<std::string> 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);
|
|
|
|
}
|
2025-01-25 12:25:38 -08:00
|
|
|
|
|
|
|
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<SaslMechanism> mechanism) -> void
|
|
|
|
{
|
|
|
|
if (sasl_mechanism_) {
|
|
|
|
connection_.send_authenticate("*"sv); // abort SASL
|
|
|
|
}
|
|
|
|
|
|
|
|
sasl_mechanism_ = std::move(mechanism);
|
|
|
|
connection_.send_authenticate(sasl_mechanism_->mechanism_name());
|
|
|
|
}
|