// This Source Code Form is subject to the terms of the Mozilla Public // License, version 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include "node.hh" #pragma GCC visibility push(default) #include "ns.hh" #pragma GCC visibility pop std::string get_name(xmpp_stanza_t *stanza) { const char *result = NULL; result = xmpp_stanza_get_name(stanza); if (result) return result; else return {}; } std::optional get_attribute(xmpp_stanza_t *stanza, const char *name) { const char *result = NULL; result = xmpp_stanza_get_attribute(stanza, name); if (result) return result; else return {}; } std::string get_text(xmpp_stanza_t *stanza) { const char *result = NULL; result = xmpp_stanza_get_text_ptr(stanza); if (result) return result; else return {}; } std::chrono::system_clock::time_point get_time(const std::string& text) { std::tm tm = {}; if (strptime(text.data(), "%FT%T%z", &tm)) { throw std::invalid_argument("Bad time format"); } else { return std::chrono::system_clock::from_time_t(std::mktime(&tm)); } } const std::regex jid::pattern( "^((?:([^@/<>'\"]+)@)?([^@/<>'\"]+))(?:/([^<>'\"]*))?$"); jid::jid(xmpp_ctx_t *, std::string s) : full(s) { auto as_sv = [](std::ssub_match m) { if(!m.matched) return std::string_view(); return std::string_view { &*m.first, static_cast(m.length()) }; }; std::smatch match; if (std::regex_search(full, match, pattern)) { bare = as_sv(match[1]); local = as_sv(match[2]); domain = as_sv(match[3]); resource = as_sv(match[4]); } else { bare = full; domain = bare; } } bool jid::is_bare() const { return !resource.empty(); } xml::node::node() {} void xml::node::bind(xmpp_ctx_t *context, xmpp_stanza_t *stanza) { name = get_name(stanza); id = get_attribute(stanza, "id"); ns = get_attribute(stanza, "xmlns"); int count = xmpp_stanza_get_attribute_count(stanza); std::vector attrvec(count * 2, nullptr); const char **attrs = attrvec.data(); xmpp_stanza_get_attributes(stanza, attrs, count * 2); for (int i = 0; i < count; i++) { const char *key = attrs[(2*i)]; const char *value = attrs[(2*i)+1]; attributes.emplace(key, value); } text = get_text(stanza); for (xmpp_stanza_t *child = xmpp_stanza_get_children(stanza); child; child = xmpp_stanza_get_next(child)) { if (xmpp_stanza_is_text(child)) text += get_text(child); else children.emplace_back(context, child); } } void xml::message::bind(xmpp_ctx_t *context, xmpp_stanza_t *stanza) { auto result = get_attribute(stanza, "from"); if (result) from = jid(context, *result); result = get_attribute(stanza, "to"); if (result) to = jid(context, *result); type = get_attribute(stanza, "type"); node::bind(context, stanza); } std::optional xml::presence::show() { auto child = get_children("show"); if (child.size() > 0) return child.front().get().text; return {}; } std::optional xml::presence::status() { auto child = get_children("status"); if (child.size() > 0) return child.front().get().text; return {}; } void xml::presence::bind(xmpp_ctx_t *context, xmpp_stanza_t *stanza) { auto result = get_attribute(stanza, "from"); if (result) from = jid(context, *result); result = get_attribute(stanza, "to"); if (result) to = jid(context, *result); type = get_attribute(stanza, "type"); node::bind(context, stanza); } void xml::iq::bind(xmpp_ctx_t *context, xmpp_stanza_t *stanza) { auto result = get_attribute(stanza, "from"); if (result) from = jid(context, *result); result = get_attribute(stanza, "to"); if (result) to = jid(context, *result); type = get_attribute(stanza, "type"); node::bind(context, stanza); } void xml::error::bind(xmpp_ctx_t *context, xmpp_stanza_t *stanza) { auto result = get_attribute(stanza, "from"); if (result) from = jid(context, *result); result = get_attribute(stanza, "to"); if (result) to = jid(context, *result); node::bind(context, stanza); }