diff --git a/examples/src/connect.cpp b/examples/src/connect.cpp index 10c0161..b664a65 100644 --- a/examples/src/connect.cpp +++ b/examples/src/connect.cpp @@ -8,6 +8,8 @@ #include #include +namespace iq = larra::xmpp::iq; + auto Coroutine() -> boost::asio::awaitable { SPDLOG_INFO("Connecting client..."); @@ -15,20 +17,28 @@ auto Coroutine() -> boost::asio::awaitable { auto client = co_await larra::xmpp::client::CreateClient>( larra::xmpp::PlainUserAccount{.jid = {.username = "test1", .server = "localhost"}, .password = "test1"}, {.useTls = larra::xmpp::client::Options::kNever}); -/* + + // TODO(unknown): + // rfc6120 7.1 + // After a client authenticates with a server, + // it MUST bind a specific resource to the stream so that the server can properly address the client. + + co_await std::visit( + [](auto& client) -> boost::asio::awaitable { + co_await client.UpdateListOfContacts(); + }, + client); + + // rfc6120 2.2 + // Upon authenticating with a server and binding a resource (thus becoming a connected resource as defined in [XMPP‑CORE]), + // a client SHOULD request the roster before sending initial presence co_await std::visit( [](auto& client) -> boost::asio::awaitable { SPDLOG_INFO("Send presence: Available"); co_await client.Send(larra::xmpp::presence::c2s::Available{}); }, client); - */ - std::visit( - [](auto& client) -> boost::asio::awaitable { - co_await client.UpdateListOfContacts(); - }, - client); } catch(const std::exception& err) { SPDLOG_ERROR("{}", err.what()); co_return; diff --git a/library/include/larra/client/client.hpp b/library/include/larra/client/client.hpp index 8dd0ece..c1f033f 100644 --- a/library/include/larra/client/client.hpp +++ b/library/include/larra/client/client.hpp @@ -79,10 +79,16 @@ struct Client { auto UpdateListOfContacts() -> boost::asio::awaitable { SPDLOG_INFO("Send IQ: Get::Roster"); - co_await this->Send(::iq::GetRoster{}); + co_await std::visit( + [&](auto&& query) -> boost::asio::awaitable { + co_await this->Send(query); + }, ::iq::MakeGetRoster(jid)); + - ::iq::ResultRoster roster = co_await connection.template Read<::iq::ResultRoster>(); - for (const auto& jid : roster.payload.items) { + //IqRoster roster = co_await connection.template Read(); + //const auto& roster_result = std::get<::iq::ResultRoster>(roster); + ::iq::ResultRoster roster_result = co_await connection.template Read<::iq::ResultRoster>(); + for (const auto& jid : roster_result.payload.items) { SPDLOG_INFO("\t'{}'", ToString(jid)); } co_return; diff --git a/library/include/larra/iq.hpp b/library/include/larra/iq.hpp index bd7b291..5efd612 100644 --- a/library/include/larra/iq.hpp +++ b/library/include/larra/iq.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include namespace larra::xmpp { @@ -11,6 +12,8 @@ namespace iq { template struct BaseImplWithPayload { std::string id; + std::optional from{}; + std::optional to{}; PayloadType payload; static const inline std::string kName = Name; static constexpr auto kDefaultName = "iq"; @@ -19,16 +22,32 @@ struct BaseImplWithPayload { [[nodiscard]] constexpr auto Id(this Self&& self, std::string id) -> std::decay_t { return utils::FieldSetHelper::With<"id", BaseImplWithPayload>(std::forward(self), std::move(id)); } + template + [[nodiscard]] constexpr auto To(this Self&& self, std::string to) -> std::decay_t { + return utils::FieldSetHelper::With<"to", BaseImplWithPayload>(std::forward(self), std::move(to)); + } + template + [[nodiscard]] constexpr auto From(this Self&& self, std::string from) -> std::decay_t { + return utils::FieldSetHelper::With<"from", BaseImplWithPayload>(std::forward(self), std::move(from)); + } template [[nodiscard]] constexpr auto Payload(this Self&& self, NewPayloadType value) { return utils::FieldSetHelper::With<"payload", BaseImplWithPayload, false>(std::forward(self), std::move(value)); } friend constexpr auto operator<<(xmlpp::Element* element, const BaseImplWithPayload& self) { element->set_attribute("id", self.id); + + if (self.to) { + element->set_attribute("to", *self.to); + } + if (self.from) { + element->set_attribute("from", *self.from); + } element->set_attribute("type", kName); using S = Serialization; S::Serialize(element->add_child_element(S::kDefaultName, S::kPrefix), self.payload); } + [[nodiscard]] static constexpr auto Parse(xmlpp::Element* element) -> BaseImplWithPayload { auto node = element->get_attribute("type"); if(!node) { @@ -41,6 +60,9 @@ struct BaseImplWithPayload { if(!idNode) { throw std::runtime_error("Not found attribute id for parse Iq"); } + auto from = element->get_attribute("from"); + auto to = element->get_attribute("to"); + using S = Serialization; auto payload = element->get_first_child(S::kDefaultName); @@ -51,7 +73,11 @@ struct BaseImplWithPayload { if(!payload2) { throw std::runtime_error("Invalid payload for parse Iq"); } - return {.id = idNode->get_value(), .payload = S::Parse(payload2)}; + return { + .id = idNode->get_value(), + .from = (from ? std::optional{from->get_value()} : std::nullopt), + .to = (to ? std::optional{to->get_value()} : std::nullopt), + .payload = S::Parse(payload2)}; } }; static constexpr auto kGetName = "get"; diff --git a/library/include/larra/roster.hpp b/library/include/larra/roster.hpp index 660e055..b7b835d 100644 --- a/library/include/larra/roster.hpp +++ b/library/include/larra/roster.hpp @@ -16,6 +16,7 @@ struct Roster { std::vector items; friend constexpr auto operator<<(xmlpp::Element* element, const Roster& roster) { + element->set_attribute("xmlns", "jabber:iq:roster"); } [[nodiscard]] static constexpr auto Parse(xmlpp::Element* element) -> Roster { const auto& item_nodes = element->get_children("item"); @@ -41,21 +42,15 @@ struct Roster { | std::ranges::to>()}; } -/* - friend constexpr auto operator<<(std::iostream& io, const Roster& roster) { - for (const auto& jid : roster.items) { - io << ToString(jid) << ' '; - } - } - */ - }; using GetRoster = Get; using ResultRoster = Result; +using IqRoster = Iq; + +auto MakeGetRoster(const BareJid& jid) { + IqRoster iq_roster{std::in_place_type, GetRoster{.id="1", .from=ToString(jid), .payload=Roster{}}}; + return iq_roster; +} } // namespace larra::xmpp::iq - -namespace larra::xmpp { - using IqRoster = Iq; -}