summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--cmake/Modules/FindLibidn.cmake36
-rw-r--r--config.h.cmake1
-rw-r--r--src/bridge/bridge.cpp6
-rw-r--r--src/bridge/bridge.hpp5
-rw-r--r--src/irc/irc_client.cpp8
-rw-r--r--src/irc/irc_message.cpp2
-rw-r--r--src/test.cpp5
-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
12 files changed, 137 insertions, 11 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8a8ae9c..ac93ff1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,6 +20,7 @@ find_package(Cryptopp REQUIRED)
find_package(Iconv REQUIRED)
include(FindEXPAT)
find_package(EXPAT REQUIRED)
+find_package(Libidn)
include_directories("src/")
include_directories(${EXPAT_INCLUDE_DIRS})
@@ -28,6 +29,12 @@ include_directories(${ICONV_INCLUDE_DIRS})
# coming from these headers.
include_directories(SYSTEM ${CRYPTO++_INCLUDE_DIRS})
+if(LIBIDN_FOUND)
+ include_directories(${LIBIDN_INCLUDE_DIRS})
+else()
+ message("Building without stringprep support.")
+endif()
+
set(POLLER "POLL" CACHE STRING
"Choose the poller between POLL and EPOLL (Linux-only)")
if((NOT ${POLLER} MATCHES "POLL") AND
@@ -35,6 +42,7 @@ if((NOT ${POLLER} MATCHES "POLL") AND
message(FATAL_ERROR "POLLER must be either POLL or EPOLL")
endif()
+
#
## utils
#
@@ -83,6 +91,9 @@ file(GLOB source_xmpp
add_library(xmpp STATIC ${source_xmpp})
target_link_libraries(xmpp bridge network utils logger
${CRYPTO++_LIBRARIES} ${EXPAT_LIBRARIES} pthread)
+if(LIBIDN_FOUND)
+ target_link_libraries(xmpp ${LIBIDN_LIBRARIES})
+endif()
#
## bridge
diff --git a/cmake/Modules/FindLibidn.cmake b/cmake/Modules/FindLibidn.cmake
new file mode 100644
index 0000000..4c0b2c5
--- /dev/null
+++ b/cmake/Modules/FindLibidn.cmake
@@ -0,0 +1,36 @@
+# - Find libidn
+# Find the libidn library, and more particularly the stringprep header.
+#
+# This module defines the following variables:
+# LIBIDN_FOUND - True if library and include directory are found
+# If set to TRUE, the following are also defined:
+# LIBIDN_INCLUDE_DIRS - The directory where to find the header file
+# LIBIDN_LIBRARIES - Where to find the library file
+#
+# For conveniance, these variables are also set. They have the same values
+# than the variables above. The user can thus choose his/her prefered way
+# to way to write them.
+# LIBIDN_INCLUDE_DIR
+# LIBIDN_LIBRARY
+#
+# This file is in the public domain
+
+find_path(LIBIDN_INCLUDE_DIRS NAMES stringprep.h
+ DOC "The libidn include directory")
+
+# The library containing the stringprep module is libidn
+find_library(LIBIDN_LIBRARIES NAMES idn
+ DOC "The libidn library")
+
+# Use some standard module to handle the QUIETLY and REQUIRED arguments, and
+# set LIBIDN_FOUND to TRUE if these two variables are set.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libidn REQUIRED_VARS LIBIDN_LIBRARIES LIBIDN_INCLUDE_DIRS)
+
+# Compatibility for all the ways of writing these variables
+if(LIBIDN_FOUND)
+ set(LIBIDN_INCLUDE_DIR ${LIBIDN_INCLUDE_DIRS})
+ set(LIBIDN_LIBRARY ${LIBIDN_LIBRARIES})
+endif()
+
+mark_as_advanced(LIBIDN_INCLUDE_DIRS LIBIDN_LIBRARIES) \ No newline at end of file
diff --git a/config.h.cmake b/config.h.cmake
index e17cc80..8ee0fd3 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -1,2 +1,3 @@
#cmakedefine ICONV_SECOND_ARGUMENT_IS_CONST
+#cmakedefine LIBIDN_FOUND
#cmakedefine POLLER ${POLLER}
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp
index 2ad6af8..973e095 100644
--- a/src/bridge/bridge.cpp
+++ b/src/bridge/bridge.cpp
@@ -167,9 +167,11 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho
this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid);
}
-void Bridge::send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick)
+void Bridge::send_user_join(const std::string& hostname,
+ const std::string& chan_name,
+ const IrcUser* user)
{
- this->xmpp->send_user_join(chan_name + "%" + hostname, nick, this->user_jid);
+ this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, this->user_jid);
}
void Bridge::send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick)
diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp
index 1443191..bbbca95 100644
--- a/src/bridge/bridge.hpp
+++ b/src/bridge/bridge.hpp
@@ -3,6 +3,7 @@
#include <irc/irc_client.hpp>
#include <bridge/colors.hpp>
+#include <irc/irc_user.hpp>
#include <irc/iid.hpp>
#include <unordered_map>
@@ -56,7 +57,9 @@ public:
/**
* Send the presence of a new user in the MUC.
*/
- void send_user_join(const std::string& hostname, const std::string& chan_name, const std::string nick);
+ void send_user_join(const std::string& hostname,
+ const std::string& chan_name,
+ const IrcUser* user);
/**
* Send the self presence of an user when the MUC is fully joined.
*/
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index 0d4d102..0f29a2b 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -193,11 +193,11 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message)
std::vector<std::string> nicks = utils::split(message.arguments[3], ' ');
for (const std::string& nick: nicks)
{
- IrcUser* user = channel->add_user(nick);
+ const IrcUser* user = channel->add_user(nick);
if (user->nick != channel->get_self()->nick)
{
log_debug("Adding user [" << nick << "] to chan " << chan_name);
- this->bridge->send_user_join(this->hostname, chan_name, user->nick);
+ this->bridge->send_user_join(this->hostname, chan_name, user);
}
}
}
@@ -214,8 +214,8 @@ void IrcClient::on_channel_join(const IrcMessage& message)
}
else
{
- IrcUser* user = channel->add_user(nick);
- this->bridge->send_user_join(this->hostname, chan_name, user->nick);
+ const IrcUser* user = channel->add_user(nick);
+ this->bridge->send_user_join(this->hostname, chan_name, user);
}
}
diff --git a/src/irc/irc_message.cpp b/src/irc/irc_message.cpp
index 18fa3ec..eb3eb47 100644
--- a/src/irc/irc_message.cpp
+++ b/src/irc/irc_message.cpp
@@ -9,7 +9,7 @@ IrcMessage::IrcMessage(std::string&& line)
if (line[0] == ':')
{
pos = line.find(" ");
- this->prefix = line.substr(1, pos);
+ this->prefix = line.substr(1, pos - 1);
line = line.substr(pos + 1, std::string::npos);
}
// command
diff --git a/src/test.cpp b/src/test.cpp
index ac1a85d..a8c0276 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -148,6 +148,11 @@ int main()
assert(jid2.domain == "ツ.coucou");
assert(jid2.resource == "coucou@coucou/coucou");
+ // Nodeprep
+ const std::string& badjid("~louiz@EpiK-7D9D1FDE.poez.io");
+ const std::string correctjid = jidprep(badjid);
+ assert(correctjid == "~louiz@epik-7d9d1fde.poez.io");
+
/**
* Config
*/
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
*/