summaryrefslogtreecommitdiff
path: root/src/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/jid.cpp46
-rw-r--r--src/xmpp/jid.hpp10
-rw-r--r--src/xmpp/xmpp_component.cpp13
-rw-r--r--src/xmpp/xmpp_component.hpp5
4 files changed, 71 insertions, 3 deletions
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 <xmpp/jid.hpp>
+#include <config.h>
+#include <cstring>
+
+#ifdef LIBIDN_FOUND
+ #include <stringprep.h>
+#endif
+
+#include <logger/logger.hpp>
Jid::Jid(const std::string& jid)
{
@@ -19,3 +27,41 @@ Jid::Jid(const std::string& jid)
this->domain = jid.substr(at, slash - at);
}
+
+#include <iostream>
+
+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_rc>(::stringprep(local, max_jid_part_len,
+ static_cast<Stringprep_profile_flags>(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_rc>(::stringprep(domain, max_jid_part_len,
+ static_cast<Stringprep_profile_flags>(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
*/