xbot/registration_thread.cpp

165 lines
4.3 KiB
C++
Raw Normal View History

2023-11-25 09:22:55 -08:00
#include "registration_thread.hpp"
RegistrationThread::RegistrationThread(
Connection * connection_,
std::string password,
std::string username,
std::string realname,
std::string nickname
)
: connection_{connection_}
, password_{password}
, username_{username}
, realname_{realname}
, nickname_{nickname}
, stage_{Stage::LsReply}
{}
auto RegistrationThread::priority() const -> priority_type
{
return 2;
}
auto RegistrationThread::on_connect() -> Thread::callback_result
{
write_irc(*connection_, "CAP", "LS", "302");
write_irc(*connection_, "PASS", password_);
write_irc(*connection_, "USER", username_, "*", "*", realname_);
write_irc(*connection_, "NICK", nickname_);
return {};
}
auto RegistrationThread::send_req() -> Thread::callback_result
{
std::string request;
char const* want[] = { "extended-join", "account-notify", "draft/chathistory", "batch", "soju.im/no-implicit-names", "chghost", "setname", "account-tag", "solanum.chat/oper", "solanum.chat/identify-msg", "solanum.chat/realhost", "server-time", "invite-notify", "extended-join" };
for (auto cap : want)
{
if (caps.contains(cap))
{
request.append(cap);
request.push_back(' ');
outstanding.insert(cap);
}
}
if (not outstanding.empty())
{
request.pop_back();
write_irc(*connection_, "CAP", "REQ", request);
stage_ = Stage::AckReply;
return {ThreadOutcome::Continue, EventOutcome::Consume};
}
else
{
write_irc(*connection_, "CAP", "END");
return {ThreadOutcome::Finish, EventOutcome::Consume};
}
}
auto RegistrationThread::capack(IrcMsg const& msg) -> Thread::callback_result
{
auto const n = msg.args.size();
if ("CAP" == msg.command && n >= 2 && "*" == msg.args[0] && "ACK" == msg.args[1])
{
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);
}
);
if (outstanding.empty())
{
write_irc(*connection_, "CAP", "END");
return {ThreadOutcome::Finish, EventOutcome::Consume};
}
else
{
return {ThreadOutcome::Continue, EventOutcome::Consume};
}
}
else
{
return {};
}
}
auto RegistrationThread::capls(IrcMsg const& msg) -> Thread::callback_result
{
auto const n = msg.args.size();
if ("CAP" == msg.command && n >= 2 && "*" == msg.args[0] && "LS" == msg.args[1])
{
std::string_view const* kvs;
bool last;
if (3 == n)
{
kvs = &msg.args[2];
last = true;
}
else if (4 == n && "*" == msg.args[2])
{
kvs = &msg.args[3];
last = false;
}
else
{
return {};
}
auto in = std::istringstream{std::string{*kvs}};
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});
}
}
);
if (last)
{
return send_req();
}
return {ThreadOutcome::Continue, EventOutcome::Consume};
}
else
{
return {};
}
}
auto RegistrationThread::on_msg(IrcMsg const& msg) -> Thread::callback_result
{
switch (stage_)
{
case Stage::LsReply: return capls(msg);
case Stage::AckReply: return capack(msg);
default: return {};
}
}
auto RegistrationThread::on_event(Event const& event) -> Thread::callback_result
{
if (auto const irc_event = dynamic_cast<IrcMsgEvent const*>(&event))
{
return on_msg(irc_event->irc);
}
if (auto const connect_event = dynamic_cast<ConnectEvent const*>(&event))
{
return on_connect();
}
return {};
}