165 lines
4.3 KiB
C++
165 lines
4.3 KiB
C++
#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 {};
|
|
}
|