push cap logic into client
This commit is contained in:
parent
b9d88bbd0c
commit
a9d6eb3811
102
client.cpp
102
client.cpp
@ -152,6 +152,9 @@ auto Client::start(Connection &connection) -> std::shared_ptr<Client>
|
|||||||
case IrcCommand::RPL_ENDOFMOTD:
|
case IrcCommand::RPL_ENDOFMOTD:
|
||||||
thread->on_registered();
|
thread->on_registered();
|
||||||
break;
|
break;
|
||||||
|
case IrcCommand::CAP:
|
||||||
|
thread->on_cap(msg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -285,4 +288,103 @@ auto Client::casemap_compare(std::string_view lhs, std::string_view rhs) const -
|
|||||||
auto Client::shutdown() -> void
|
auto Client::shutdown() -> void
|
||||||
{
|
{
|
||||||
sig_registered.disconnect_all_slots();
|
sig_registered.disconnect_all_slots();
|
||||||
|
sig_cap_ls.disconnect_all_slots();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Client::list_caps() -> void
|
||||||
|
{
|
||||||
|
caps_available_.clear();
|
||||||
|
connection_.send_cap_ls();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Client::on_cap(const IrcMsg &msg) -> void
|
||||||
|
{
|
||||||
|
if ("ACK" == msg.args[1] && msg.args.size() == 3) {
|
||||||
|
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) {
|
||||||
|
caps_.insert(std::move(x));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if ("NAK" == msg.args[1] && msg.args.size() == 3) {
|
||||||
|
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) {
|
||||||
|
caps_.erase(x);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if ("LS" == msg.args[1]) {
|
||||||
|
const std::string_view *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
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "Malformed CAP LS";
|
||||||
|
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) {
|
||||||
|
const auto eq = x.find('=');
|
||||||
|
if (eq == x.npos)
|
||||||
|
{
|
||||||
|
caps_available_.emplace(x, std::string{});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
caps_available_.emplace(std::string{x, 0, eq}, std::string{x, eq + 1, x.npos});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (last)
|
||||||
|
{
|
||||||
|
sig_cap_ls(caps_available_);
|
||||||
|
}
|
||||||
|
} else if ("NEW" == msg.args[1] && msg.args.size() == 3) {
|
||||||
|
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) {
|
||||||
|
const auto eq = x.find('=');
|
||||||
|
if (eq == x.npos)
|
||||||
|
{
|
||||||
|
caps_available_.emplace(x, std::string{});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
caps_available_.emplace(std::string{x, 0, eq}, std::string{x, eq + 1, x.npos});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if ("DEL" == msg.args[1] && msg.args.size() == 3) {
|
||||||
|
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) {
|
||||||
|
caps_available_.erase(x);
|
||||||
|
caps_.erase(x);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@ -35,6 +35,9 @@ class Client
|
|||||||
Casemap casemap_;
|
Casemap casemap_;
|
||||||
std::string channel_prefix_;
|
std::string channel_prefix_;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> caps_available_;
|
||||||
|
std::unordered_set<std::string> caps_;
|
||||||
|
|
||||||
auto on_welcome(const IrcMsg &irc) -> void;
|
auto on_welcome(const IrcMsg &irc) -> void;
|
||||||
auto on_isupport(const IrcMsg &irc) -> void;
|
auto on_isupport(const IrcMsg &irc) -> void;
|
||||||
auto on_nick(const IrcMsg &irc) -> void;
|
auto on_nick(const IrcMsg &irc) -> void;
|
||||||
@ -43,11 +46,13 @@ class Client
|
|||||||
auto on_kick(const IrcMsg &irc) -> void;
|
auto on_kick(const IrcMsg &irc) -> void;
|
||||||
auto on_part(const IrcMsg &irc) -> void;
|
auto on_part(const IrcMsg &irc) -> void;
|
||||||
auto on_mode(const IrcMsg &irc) -> void;
|
auto on_mode(const IrcMsg &irc) -> void;
|
||||||
|
auto on_cap(const IrcMsg &irc) -> void;
|
||||||
auto on_authenticate(std::string_view) -> void;
|
auto on_authenticate(std::string_view) -> void;
|
||||||
auto on_registered() -> void;
|
auto on_registered() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
boost::signals2::signal<void()> sig_registered;
|
boost::signals2::signal<void()> sig_registered;
|
||||||
|
boost::signals2::signal<void(const std::unordered_map<std::string, std::string> &)> sig_cap_ls;
|
||||||
|
|
||||||
Client(Connection &connection)
|
Client(Connection &connection)
|
||||||
: connection_{connection}
|
: connection_{connection}
|
||||||
@ -71,6 +76,8 @@ public:
|
|||||||
auto get_my_mode() const -> const std::string &;
|
auto get_my_mode() const -> const std::string &;
|
||||||
auto get_my_channels() const -> const std::unordered_set<std::string> &;
|
auto get_my_channels() const -> const std::unordered_set<std::string> &;
|
||||||
|
|
||||||
|
auto list_caps() -> void;
|
||||||
|
|
||||||
auto is_my_nick(std::string_view nick) const -> bool;
|
auto is_my_nick(std::string_view nick) const -> bool;
|
||||||
auto is_my_mask(std::string_view mask) const -> bool;
|
auto is_my_mask(std::string_view mask) const -> bool;
|
||||||
auto is_channel(std::string_view name) const -> bool;
|
auto is_channel(std::string_view name) const -> bool;
|
||||||
|
115
registration.cpp
115
registration.cpp
@ -7,7 +7,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
Registration::Registration(
|
Registration::Registration(
|
||||||
const Settings &settings,
|
const Settings &settings,
|
||||||
@ -20,7 +19,11 @@ Registration::Registration(
|
|||||||
|
|
||||||
auto Registration::on_connect() -> void
|
auto Registration::on_connect() -> void
|
||||||
{
|
{
|
||||||
client_->get_connection().send_cap_ls();
|
client_->list_caps();
|
||||||
|
caps_slot_ = client_->sig_cap_ls.connect([self = shared_from_this()](auto &caps) {
|
||||||
|
self->on_cap_list(caps);
|
||||||
|
});
|
||||||
|
|
||||||
slot_ = client_->get_connection().sig_ircmsg.connect(
|
slot_ = client_->get_connection().sig_ircmsg.connect(
|
||||||
[self = shared_from_this()](const auto cmd, auto &msg)
|
[self = shared_from_this()](const auto cmd, auto &msg)
|
||||||
{
|
{
|
||||||
@ -36,10 +39,10 @@ auto Registration::on_connect() -> void
|
|||||||
client_->get_connection().send_nick(settings_.nickname);
|
client_->get_connection().send_nick(settings_.nickname);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Registration::send_req() -> void
|
auto Registration::on_cap_list(const std::unordered_map<std::string, std::string> &caps) -> void
|
||||||
{
|
{
|
||||||
std::string request;
|
std::string request;
|
||||||
std::vector<const char *> want{
|
static const char * const want [] {
|
||||||
"account-notify",
|
"account-notify",
|
||||||
"account-tag",
|
"account-tag",
|
||||||
"batch",
|
"batch",
|
||||||
@ -55,100 +58,37 @@ auto Registration::send_req() -> void
|
|||||||
"solanum.chat/realhost",
|
"solanum.chat/realhost",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (not settings_.sasl_mechanism.empty())
|
|
||||||
{
|
|
||||||
want.push_back("sasl");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto cap : want)
|
for (const auto cap : want)
|
||||||
{
|
{
|
||||||
if (caps.contains(cap))
|
if (caps.contains(cap))
|
||||||
{
|
{
|
||||||
request.append(cap);
|
request.append(cap);
|
||||||
request.push_back(' ');
|
request.push_back(' ');
|
||||||
outstanding.insert(cap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not outstanding.empty())
|
bool do_sasl = not settings_.sasl_mechanism.empty() && caps.contains("sasl");
|
||||||
|
if (do_sasl) {
|
||||||
|
request.append("sasl ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not request.empty())
|
||||||
{
|
{
|
||||||
request.pop_back();
|
request.pop_back(); // trailing space
|
||||||
client_->get_connection().send_cap_req(request);
|
client_->get_connection().send_cap_req(request);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (do_sasl) {
|
||||||
|
client_->start_sasl(
|
||||||
|
std::make_unique<SaslPlain>(
|
||||||
|
settings_.sasl_authcid,
|
||||||
|
settings_.sasl_authzid,
|
||||||
|
settings_.sasl_password));
|
||||||
|
} else {
|
||||||
client_->get_connection().send_cap_end();
|
client_->get_connection().send_cap_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Registration::on_msg_cap_ack(const IrcMsg &msg) -> void
|
|
||||||
{
|
|
||||||
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())
|
|
||||||
{
|
|
||||||
|
|
||||||
if (settings_.sasl_mechanism.empty())
|
|
||||||
{
|
|
||||||
client_->get_connection().send_cap_end();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client_->start_sasl(std::make_unique<SaslPlain>(settings_.sasl_authcid, settings_.sasl_authzid, settings_.sasl_password));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Registration::on_msg_cap_ls(const IrcMsg &msg) -> void
|
|
||||||
{
|
|
||||||
const std::string_view *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<std::string>{in},
|
|
||||||
std::istream_iterator<std::string>{},
|
|
||||||
[this](std::string x) {
|
|
||||||
const auto 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 Registration::start(
|
auto Registration::start(
|
||||||
const Settings &settings,
|
const Settings &settings,
|
||||||
std::shared_ptr<Client> client
|
std::shared_ptr<Client> client
|
||||||
@ -187,20 +127,15 @@ auto Registration::on_ircmsg(const IrcCommand cmd, const IrcMsg &msg) -> void
|
|||||||
{
|
{
|
||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
case IrcCommand::CAP:
|
|
||||||
if (msg.args.size() >= 2 && "LS" == msg.args[1]) {
|
|
||||||
on_msg_cap_ls(msg);
|
|
||||||
} else if (msg.args.size() >= 2 && "ACK" == msg.args[1]) {
|
|
||||||
on_msg_cap_ack(msg);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IrcCommand::ERR_NICKNAMEINUSE:
|
case IrcCommand::ERR_NICKNAMEINUSE:
|
||||||
|
case IrcCommand::ERR_ERRONEUSNICKNAME:
|
||||||
|
case IrcCommand::ERR_UNAVAILRESOURCE:
|
||||||
randomize_nick();
|
randomize_nick();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrcCommand::RPL_WELCOME:
|
case IrcCommand::RPL_WELCOME:
|
||||||
slot_.disconnect();
|
slot_.disconnect();
|
||||||
|
caps_slot_.disconnect();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IrcCommand::RPL_SASLSUCCESS:
|
case IrcCommand::RPL_SASLSUCCESS:
|
||||||
|
@ -14,14 +14,11 @@ class Registration : public std::enable_shared_from_this<Registration>
|
|||||||
const Settings &settings_;
|
const Settings &settings_;
|
||||||
std::shared_ptr<Client> client_;
|
std::shared_ptr<Client> client_;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> caps;
|
|
||||||
std::unordered_set<std::string> outstanding;
|
|
||||||
|
|
||||||
boost::signals2::scoped_connection slot_;
|
boost::signals2::scoped_connection slot_;
|
||||||
|
boost::signals2::scoped_connection caps_slot_;
|
||||||
|
|
||||||
auto on_connect() -> void;
|
auto on_connect() -> void;
|
||||||
auto on_msg_cap_ls(const IrcMsg &msg) -> void;
|
auto on_cap_list(const std::unordered_map<std::string, std::string> &) -> void;
|
||||||
auto on_msg_cap_ack(const IrcMsg &msg) -> void;
|
|
||||||
|
|
||||||
auto on_ircmsg(IrcCommand, const IrcMsg &msg) -> void;
|
auto on_ircmsg(IrcCommand, const IrcMsg &msg) -> void;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user