#include "registration_thread.hpp" #include "connection.hpp" #include "irc_parse_thread.hpp" #include "ircmsg.hpp" #include "write_irc.hpp" #include #include #include 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} { } auto RegistrationThread::on_connect() -> void { send_cap_ls(connection_); send_pass(connection_, password_); send_user(connection_, username_, realname_); send_nick(connection_, nickname_); connection_.remove_listener(connect_handle_); } auto RegistrationThread::send_req() -> void { std::string request; char const* const want[] = { "account-notify", "account-tag", "batch", "chghost", "draft/chathistory", "extended-join", "invite-notify", "server-time", "setname", "soju.im/no-implicit-names", "solanum.chat/identify-msg", "solanum.chat/oper", "solanum.chat/realhost", }; for (auto cap : want) { if (caps.contains(cap)) { request.append(cap); request.push_back(' '); outstanding.insert(cap); } } connection_.remove_listener(message_handle_); if (not outstanding.empty()) { request.pop_back(); send_cap_req(connection_, request); listen_for_cap_ack(); } else { send_cap_end(connection_); } } auto RegistrationThread::on_msg_cap_ack(IrcMsg const& msg) -> void { auto in = std::istringstream{std::string{msg.args[2]}}; std::for_each( std::istream_iterator{in}, std::istream_iterator{}, [this](std::string x) { outstanding.erase(x); } ); if (outstanding.empty()) { send_cap_end(connection_); connection_.remove_listener(message_handle_); } } auto RegistrationThread::on_msg_cap_ls(IrcMsg const& msg) -> void { 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]) { kvs = &msg.args[3]; last = false; } else { return; } auto in = std::istringstream{std::string{*kvs}}; std::for_each( std::istream_iterator{in}, std::istream_iterator{}, [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) { send_req(); } } auto RegistrationThread::start( Connection& connection, std::string password, std::string username, std::string realname, std::string nickname ) -> std::shared_ptr { auto const thread = std::make_shared(connection, password, username, realname, nickname); thread->listen_for_cap_ls(); thread->connect_handle_ = connection.add_listener([thread](ConnectEvent const&) { thread->on_connect(); }); return thread; } auto RegistrationThread::listen_for_cap_ack() -> void { message_handle_ = connection_.add_listener([thread = shared_from_this()](IrcMsgEvent const& event) { if (IrcCommand::CAP == event.command && event.irc.args.size() >= 2 && "*" == event.irc.args[0] && "ACK" == event.irc.args[1]) { thread->on_msg_cap_ack(event.irc); } }); } auto RegistrationThread::listen_for_cap_ls() -> void { message_handle_ = connection_.add_listener([thread = shared_from_this()](IrcMsgEvent const& event) { if (IrcCommand::CAP == event.command && event.irc.args.size() >= 2 && "*" == event.irc.args[0] && "LS" == event.irc.args[1]) { thread->on_msg_cap_ls(event.irc); } }); }