From b11126a19dbaadf4c32fb8dbec22754ad0712c26 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sun, 8 Dec 2013 20:14:12 +0100 Subject: Provide a JID for IRC users, and add a stringprep dependency for this --- src/xmpp/jid.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/xmpp/jid.hpp | 10 ++++++++++ src/xmpp/xmpp_component.cpp | 13 +++++++++++-- src/xmpp/xmpp_component.hpp | 5 ++++- 4 files changed, 71 insertions(+), 3 deletions(-) (limited to 'src/xmpp') diff --git a/src/xmpp/jid.cpp b/src/xmpp/jid.cpp index 29a5302..4f9917b 100644 --- a/src/xmpp/jid.cpp +++ b/src/xmpp/jid.cpp @@ -1,4 +1,12 @@ #include +#include +#include + +#ifdef LIBIDN_FOUND + #include +#endif + +#include Jid::Jid(const std::string& jid) { @@ -19,3 +27,41 @@ Jid::Jid(const std::string& jid) this->domain = jid.substr(at, slash - at); } + +#include + +static constexpr size_t max_jid_part_len = 1023; + +std::string jidprep(const std::string& original) +{ +#ifdef LIBIDN_FOUND + // TODO: cache the result + const std::string error_msg("Failed to convert " + original + " into a valid JID:"); + Jid jid(original); + + char local[max_jid_part_len] = {}; + memcpy(local, jid.local.data(), jid.local.size()); + Stringprep_rc rc = static_cast(::stringprep(local, max_jid_part_len, + static_cast(0), stringprep_xmpp_nodeprep)); + if (rc != STRINGPREP_OK) + { + log_error(error_msg + stringprep_strerror(rc)); + return ""; + } + + char domain[max_jid_part_len] = {}; + memcpy(domain, jid.domain.data(), jid.domain.size()); + rc = static_cast(::stringprep(domain, max_jid_part_len, + static_cast(0), stringprep_nameprep)); + if (rc != STRINGPREP_OK) + { + log_error(error_msg + stringprep_strerror(rc)); + return ""; + } + + return std::string(local) + "@" + domain; +#else + (void)original; + return ""; +#endif +} diff --git a/src/xmpp/jid.hpp b/src/xmpp/jid.hpp index 3027497..b6975a2 100644 --- a/src/xmpp/jid.hpp +++ b/src/xmpp/jid.hpp @@ -22,5 +22,15 @@ private: Jid& operator=(Jid&&) = delete; }; +/** + * Prepare the given UTF-8 string according to the XMPP node stringprep + * identifier profile. This is used to send properly-formed JID to the XMPP + * server. + * + * If the stringprep library is not found, we return an empty string. When + * this function is used, the result must always be checked for an empty + * value, and if this is the case it must not be used as a JID. + */ +std::string jidprep(const std::string& original); #endif // JID_INCLUDED diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index 5e65595..6424d74 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -267,7 +267,10 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con this->send_stanza(node); } -void XmppComponent::send_user_join(const std::string& from, const std::string& nick, const std::string& to) +void XmppComponent::send_user_join(const std::string& from, + const std::string& nick, + const std::string& realjid, + const std::string& to) { XmlNode node("presence"); node["to"] = to; @@ -280,6 +283,12 @@ void XmppComponent::send_user_join(const std::string& from, const std::string& n XmlNode item("item"); item["affiliation"] = "member"; item["role"] = "participant"; + if (!realjid.empty()) + { + const std::string preped_jid = jidprep(realjid); + if (!preped_jid.empty()) + item["jid"] = preped_jid; + } item.close(); x.add_child(std::move(item)); x.close(); @@ -408,7 +417,7 @@ void XmppComponent::send_nick_change(const std::string& muc_name, const std::str if (self) this->send_self_join(muc_name, new_nick, jid_to); else - this->send_user_join(muc_name, new_nick, jid_to); + this->send_user_join(muc_name, new_nick, "", jid_to); } void XmppComponent::kick_user(const std::string& muc_name, diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index bf85536..15f8f2f 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -62,7 +62,10 @@ public: /** * Send a join from a new participant */ - void send_user_join(const std::string& from, const std::string& nick, const std::string& to); + void send_user_join(const std::string& from, + const std::string& nick, + const std::string& realjid, + const std::string& to); /** * Send the self join to the user */ -- cgit v1.2.3