xbot/registration_thread.cpp

192 lines
4.7 KiB
C++
Raw Normal View History

2023-11-25 09:22:55 -08:00
#include "registration_thread.hpp"
2023-11-27 19:09:45 -08:00
#include "connection.hpp"
#include "ircmsg.hpp"
2025-01-25 12:25:38 -08:00
#include "sasl_mechanism.hpp"
2023-11-27 19:09:45 -08:00
2023-11-25 20:09:20 -08:00
#include <memory>
#include <unordered_map>
2023-11-27 19:09:45 -08:00
#include <unordered_set>
2023-11-25 20:09:20 -08:00
2023-11-25 09:22:55 -08:00
RegistrationThread::RegistrationThread(
2023-11-26 15:40:40 -08:00
Connection& connection,
2025-01-25 12:25:38 -08:00
const Settings &settings,
std::shared_ptr<SelfThread> self
2023-11-25 09:22:55 -08:00
)
2023-11-25 20:09:20 -08:00
: connection_{connection}
2025-01-25 12:25:38 -08:00
, settings_{settings}
, self_{std::move(self)}
2023-11-27 14:12:20 -08:00
{
}
2023-11-25 09:22:55 -08:00
2023-11-25 20:09:20 -08:00
auto RegistrationThread::on_connect() -> void
2023-11-25 09:22:55 -08:00
{
2025-01-23 21:23:32 -08:00
connection_.send_cap_ls();
2025-01-25 12:25:38 -08:00
connection_.send_pass(settings_.password);
connection_.send_user(settings_.username, settings_.realname);
connection_.send_nick(settings_.nickname);
2023-11-25 09:22:55 -08:00
}
2023-11-25 20:09:20 -08:00
auto RegistrationThread::send_req() -> void
2023-11-25 09:22:55 -08:00
{
std::string request;
2025-01-25 12:25:38 -08:00
std::vector<char const*> want {
2023-11-25 20:09:20 -08:00
"account-notify",
2023-11-29 13:54:34 -08:00
"account-tag",
2023-11-25 20:09:20 -08:00
"batch",
"chghost",
2023-11-29 13:54:34 -08:00
"draft/chathistory",
"extended-join",
"invite-notify",
"server-time",
2023-11-25 20:09:20 -08:00
"setname",
2023-11-29 13:54:34 -08:00
"soju.im/no-implicit-names",
2023-11-25 20:09:20 -08:00
"solanum.chat/identify-msg",
2023-11-29 13:54:34 -08:00
"solanum.chat/oper",
2023-11-25 20:09:20 -08:00
"solanum.chat/realhost",
};
2025-01-25 12:25:38 -08:00
if (settings_.sasl_mechanism == "PLAIN") {
want.push_back("sasl");
}
2025-01-22 20:33:17 -08:00
for (auto const cap : want)
2023-11-25 09:22:55 -08:00
{
if (caps.contains(cap))
{
request.append(cap);
request.push_back(' ');
outstanding.insert(cap);
}
}
2025-01-22 23:49:48 -08:00
2023-11-25 09:22:55 -08:00
if (not outstanding.empty())
{
request.pop_back();
2025-01-23 21:23:32 -08:00
connection_.send_cap_req(request);
2025-01-22 23:49:48 -08:00
2023-11-27 14:12:20 -08:00
listen_for_cap_ack();
2023-11-25 09:22:55 -08:00
}
else
{
2025-01-23 21:23:32 -08:00
connection_.send_cap_end();
2023-11-25 09:22:55 -08:00
}
}
2023-11-27 14:12:20 -08:00
auto RegistrationThread::on_msg_cap_ack(IrcMsg const& msg) -> void
2023-11-25 09:22:55 -08:00
{
2023-11-27 14:12:20 -08:00
auto in = std::istringstream{std::string{msg.args[2]}};
std::for_each(
std::istream_iterator<std::string>{in},
std::istream_iterator<std::string>{},
[this](std::string x) {
outstanding.erase(x);
2023-11-25 09:22:55 -08:00
}
2023-11-27 14:12:20 -08:00
);
if (outstanding.empty())
{
2025-01-22 23:49:48 -08:00
message_handle_.disconnect();
2025-01-25 12:25:38 -08:00
if (settings_.sasl_mechanism.empty()) {
connection_.send_cap_end();
} else {
self_->start_sasl(std::make_unique<SaslPlain>(settings_.sasl_authcid, settings_.sasl_authzid, settings_.sasl_password));
connection_.sig_ircmsg.connect_extended([thread = shared_from_this()](auto &slot, auto cmd, auto &msg) {
switch (cmd) {
default: break;
case IrcCommand::RPL_SASLSUCCESS:
case IrcCommand::ERR_SASLFAIL:
thread->connection_.send_cap_end();
slot.disconnect();
}
});
}
2023-11-25 09:22:55 -08:00
}
}
2023-11-27 14:12:20 -08:00
auto RegistrationThread::on_msg_cap_ls(IrcMsg const& msg) -> void
2023-11-25 09:22:55 -08:00
{
2023-11-27 14:12:20 -08:00
std::string_view const* kvs;
bool last;
if (3 == msg.args.size())
{
kvs = &msg.args[2];
last = true;
}
else if (4 == msg.args.size() && "*" == msg.args[2])
2023-11-25 09:22:55 -08:00
{
2023-11-27 14:12:20 -08:00
kvs = &msg.args[3];
last = false;
}
else
{
return;
}
2023-11-25 09:22:55 -08:00
2023-11-27 14:12:20 -08:00
auto in = std::istringstream{std::string{*kvs}};
2023-11-25 09:22:55 -08:00
2023-11-27 14:12:20 -08:00
std::for_each(
std::istream_iterator<std::string>{in},
std::istream_iterator<std::string>{},
[this](std::string x) {
auto const eq = x.find('=');
if (eq == x.npos)
{
caps.emplace(x, std::string{});
}
else
{
caps.emplace(std::string{x, 0, eq}, std::string{x, eq+1, x.npos});
2023-11-25 09:22:55 -08:00
}
}
2023-11-27 14:12:20 -08:00
);
2023-11-25 09:22:55 -08:00
2023-11-27 14:12:20 -08:00
if (last)
2023-11-25 09:22:55 -08:00
{
2025-01-22 23:49:48 -08:00
message_handle_.disconnect();
2023-11-27 14:12:20 -08:00
send_req();
2023-11-25 09:22:55 -08:00
}
}
2023-11-27 14:12:20 -08:00
auto RegistrationThread::start(
2023-11-26 15:40:40 -08:00
Connection& connection,
2025-01-25 12:25:38 -08:00
const Settings &settings,
std::shared_ptr<SelfThread> self
2023-11-27 14:12:20 -08:00
) -> std::shared_ptr<RegistrationThread>
2023-11-25 09:22:55 -08:00
{
2025-01-25 12:25:38 -08:00
auto const thread = std::make_shared<RegistrationThread>(connection, std::move(settings), std::move(self));
2023-11-27 14:12:20 -08:00
thread->listen_for_cap_ls();
2025-01-23 12:46:52 -08:00
thread->connect_handle_ = connection.sig_connect.connect([thread]()
2023-11-27 14:12:20 -08:00
{
2025-01-23 12:46:52 -08:00
thread->connect_handle_.disconnect();
2023-11-27 14:12:20 -08:00
thread->on_connect();
});
return thread;
}
auto RegistrationThread::listen_for_cap_ack() -> void
{
2025-01-22 23:49:48 -08:00
message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, IrcMsg const& msg)
2023-11-25 09:22:55 -08:00
{
2025-01-25 12:25:38 -08:00
if (IrcCommand::CAP == cmd && msg.args.size() >= 2 && "ACK" == msg.args[1])
2023-11-26 15:08:55 -08:00
{
2025-01-22 23:49:48 -08:00
thread->on_msg_cap_ack(msg);
2023-11-26 15:08:55 -08:00
}
2023-11-25 20:09:20 -08:00
});
2023-11-27 14:12:20 -08:00
}
auto RegistrationThread::listen_for_cap_ls() -> void
{
2025-01-22 23:49:48 -08:00
message_handle_ = connection_.sig_ircmsg.connect([thread = shared_from_this()](IrcCommand cmd, IrcMsg const& msg)
2023-11-25 09:22:55 -08:00
{
2025-01-25 12:25:38 -08:00
if (IrcCommand::CAP == cmd && msg.args.size() >= 2 && "LS" == msg.args[1])
2023-11-27 14:12:20 -08:00
{
2025-01-22 23:49:48 -08:00
thread->on_msg_cap_ls(msg);
2023-11-27 14:12:20 -08:00
}
2023-11-25 20:09:20 -08:00
});
2023-11-25 09:22:55 -08:00
}