summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--src/bridge/bridge.cpp38
-rw-r--r--src/bridge/bridge.hpp2
-rw-r--r--src/bridge/list_element.hpp19
-rw-r--r--src/irc/irc_client.cpp5
-rw-r--r--src/irc/irc_client.hpp4
-rw-r--r--src/logger/logger.hpp2
-rw-r--r--src/xmpp/adhoc_command.cpp2
-rw-r--r--src/xmpp/xmpp_component.cpp40
-rw-r--r--src/xmpp/xmpp_component.hpp8
-rw-r--r--src/xmpp/xmpp_stanza.cpp15
-rw-r--r--src/xmpp/xmpp_stanza.hpp1
12 files changed, 130 insertions, 14 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6272811..df634b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,8 +82,8 @@ if(LIBIDN_FOUND)
include_directories(${LIBIDN_INCLUDE_DIRS})
endif()
-if(SYSTEMDDAEMON_FOUND)
- include_directories(${SYSTEMDDAEMON_INCLUDE_DIRS})
+if(SYSTEMD_FOUND)
+ include_directories(${SYSTEMD_INCLUDE_DIRS})
endif()
if(BOTAN_FOUND)
@@ -198,8 +198,8 @@ target_link_libraries(${PROJECT_NAME}
bridge
utils
config)
-if(SYSTEMDDAEMON_FOUND)
- target_link_libraries(xmpp ${SYSTEMDDAEMON_LIBRARIES})
+if(SYSTEMD_FOUND)
+ target_link_libraries(xmpp ${SYSTEMD_LIBRARIES})
endif()
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp
index e312345..1a205bd 100644
--- a/src/bridge/bridge.cpp
+++ b/src/bridge/bridge.cpp
@@ -1,5 +1,6 @@
#include <bridge/bridge.hpp>
#include <bridge/colors.hpp>
+#include <bridge/list_element.hpp>
#include <xmpp/xmpp_component.hpp>
#include <xmpp/xmpp_stanza.hpp>
#include <irc/irc_message.hpp>
@@ -286,6 +287,43 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick)
irc->send_nick_command(new_nick);
}
+void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq_id,
+ const std::string& to_jid)
+{
+ IrcClient* irc = this->get_irc_client(iid.get_server());
+
+ if (!irc)
+ return;
+
+ irc->send_list_command();
+ irc_responder_callback_t cb = [this, iid, iq_id, to_jid](const std::string& irc_hostname,
+ const IrcMessage& message) -> bool
+ {
+ static std::vector<ListElement> list;
+
+ if (irc_hostname != iid.get_server())
+ return false;
+ if (message.command == "263" || message.command == "RPL_TRYAGAIN")
+ { // TODO send an error iq
+ return true;
+ }
+ else if (message.command == "322" || message.command == "RPL_LIST")
+ { // Add element to list
+ if (message.arguments.size() == 4)
+ list.emplace_back(message.arguments[1], message.arguments[2],
+ message.arguments[3]);
+ return false;
+ }
+ else if (message.command == "323" || message.command == "RPL_LISTEND")
+ { // Send the iq response with the content of the list
+ this->xmpp->send_iq_room_list_result(iq_id, to_jid, std::to_string(iid), list);
+ return true;
+ }
+ return false;
+ };
+ this->add_waiting_irc(std::move(cb));
+}
+
void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason,
const std::string& iq_id, const std::string& to_jid)
{
diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp
index b1f79d5..8f71846 100644
--- a/src/bridge/bridge.hpp
+++ b/src/bridge/bridge.hpp
@@ -72,6 +72,8 @@ public:
void send_irc_version_request(const std::string& irc_hostname, const std::string& target,
const std::string& iq_id, const std::string& to_jid,
const std::string& from_jid);
+ void send_irc_channel_list_request(const Iid& iid, const std::string& iq_id,
+ const std::string& to_jid);
void forward_affiliation_role_change(const Iid& iid, const std::string& nick,
const std::string& affiliation, const std::string& role);
/**
diff --git a/src/bridge/list_element.hpp b/src/bridge/list_element.hpp
new file mode 100644
index 0000000..bd28185
--- /dev/null
+++ b/src/bridge/list_element.hpp
@@ -0,0 +1,19 @@
+#ifndef LIST_ELEMENT_HPP_INCLUDED
+#define LIST_ELEMENT_HPP_INCLUDED
+
+#include <string>
+
+struct ListElement
+{
+ ListElement(const std::string& channel, const std::string& nb_users,
+ const std::string& topic):
+ channel(channel),
+ nb_users(nb_users),
+ topic(topic){}
+
+ std::string channel;
+ std::string nb_users;
+ std::string topic;
+};
+
+#endif /* LIST_ELEMENT_HPP_INCLUDED */
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index f83b48c..dedb5de 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -196,6 +196,11 @@ void IrcClient::send_kick_command(const std::string& chan_name, const std::strin
this->send_message(IrcMessage("KICK", {chan_name, target, reason}));
}
+void IrcClient::send_list_command()
+{
+ this->send_message(IrcMessage("LIST", {}));
+}
+
void IrcClient::send_topic_command(const std::string& chan_name, const std::string& topic)
{
this->send_message(IrcMessage("TOPIC", {chan_name, topic}));
diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp
index 578fce2..86edbab 100644
--- a/src/irc/irc_client.hpp
+++ b/src/irc/irc_client.hpp
@@ -104,6 +104,10 @@ public:
* Send the KICK irc command
*/
void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason);
+ /**
+ * Send the LIST irc command
+ */
+ void send_list_command();
void send_topic_command(const std::string& chan_name, const std::string& topic);
/**
* Send the QUIT irc command
diff --git a/src/logger/logger.hpp b/src/logger/logger.hpp
index 7560505..b1ae20d 100644
--- a/src/logger/logger.hpp
+++ b/src/logger/logger.hpp
@@ -19,7 +19,7 @@
#include "config.h"
-#ifdef SYSTEMDDAEMON_FOUND
+#ifdef SYSTEMD_FOUND
# include <systemd/sd-daemon.h>
#else
# define SD_DEBUG "[DEBUG]: "
diff --git a/src/xmpp/adhoc_command.cpp b/src/xmpp/adhoc_command.cpp
index c20976a..c4e8a44 100644
--- a/src/xmpp/adhoc_command.cpp
+++ b/src/xmpp/adhoc_command.cpp
@@ -200,7 +200,7 @@ void DisconnectUserStep2(XmppComponent* xmpp_component, AdhocSession& session, X
session.terminate();
}
-void Reload(XmppComponent*, AdhocSession& session, XmlNode& command_node)
+void Reload(XmppComponent*, AdhocSession&, XmlNode& command_node)
{
::reload_process();
command_node.delete_all_children();
diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp
index 1df1e5d..0e2531d 100644
--- a/src/xmpp/xmpp_component.cpp
+++ b/src/xmpp/xmpp_component.cpp
@@ -4,6 +4,7 @@
#include <logger/logger.hpp>
#include <xmpp/xmpp_component.hpp>
+#include <bridge/list_element.hpp>
#include <config/config.hpp>
#include <xmpp/jid.hpp>
#include <utils/sha1.hpp>
@@ -17,7 +18,7 @@
#include <uuid.h>
-#ifdef SYSTEMDDAEMON_FOUND
+#ifdef SYSTEMD_FOUND
# include <systemd/sd-daemon.h>
#endif
@@ -89,7 +90,7 @@ void XmppComponent::on_connection_failed(const std::string& reason)
{
this->first_connection_try = false;
log_error("Failed to connect to the XMPP server: " << reason);
-#ifdef SYSTEMDDAEMON_FOUND
+#ifdef SYSTEMD_FOUND
sd_notifyf(0, "STATUS=Failed to connect to the XMPP server: %s", reason.data());
#endif
}
@@ -279,7 +280,7 @@ void XmppComponent::handle_handshake(const Stanza& stanza)
this->authenticated = true;
this->ever_auth = true;
log_info("Authenticated with the XMPP server");
-#ifdef SYSTEMDDAEMON_FOUND
+#ifdef SYSTEMD_FOUND
sd_notify(0, "READY=1");
// Install an event that sends a keepalive to systemd. If biboumi crashes
// or hangs for too long, systemd will restart it.
@@ -556,12 +557,18 @@ void XmppComponent::handle_iq(const Stanza& stanza)
}
else if ((query = stanza.get_child("query", DISCO_ITEMS_NS)))
{
+ Iid iid(to.local);
const std::string node = query->get_tag("node");
if (node == ADHOC_NS)
{
this->send_adhoc_commands_list(id, from);
stanza_error.disable();
}
+ else if (node.empty() && !iid.is_user && !iid.is_channel)
+ { // Disco on an IRC server: get the list of channels
+ bridge->send_irc_channel_list_request(iid, id, from);
+ stanza_error.disable();
+ }
}
else if ((query = stanza.get_child("ping", PING_NS)))
{
@@ -626,7 +633,7 @@ void XmppComponent::handle_error(const Stanza& stanza)
if (text)
error_message = text->get_inner();
log_error("Stream error received from the XMPP server: " << error_message);
-#ifdef SYSTEMDDAEMON_FOUND
+#ifdef SYSTEMD_FOUND
if (!this->ever_auth)
sd_notifyf(0, "STATUS=Failed to authenticate to the XMPP server: %s", error_message.data());
#endif
@@ -1152,6 +1159,31 @@ void XmppComponent::send_iq_result(const std::string& id, const std::string& to_
this->send_stanza(iq);
}
+void XmppComponent::send_iq_room_list_result(const std::string& id,
+ const std::string to_jid,
+ const std::string& from,
+ const std::vector<ListElement>& rooms_list)
+{
+ Stanza iq("iq");
+ iq["from"] = from + "@" + this->served_hostname;
+ iq["to"] = to_jid;
+ iq["id"] = id;
+ iq["type"] = "result";
+ XmlNode query("query");
+ query["xmlns"] = DISCO_ITEMS_NS;
+ for (const auto& room: rooms_list)
+ {
+ XmlNode item("item");
+ item["jid"] = room.channel + "%" + from + "@" + this->served_hostname;
+ item.close();
+ query.add_child(std::move(item));
+ }
+ query.close();
+ iq.add_child(std::move(query));
+ iq.close();
+ this->send_stanza(iq);
+}
+
std::string XmppComponent::next_id()
{
char uuid_str[37];
diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp
index 951d5a3..a0b06a6 100644
--- a/src/xmpp/xmpp_component.hpp
+++ b/src/xmpp/xmpp_component.hpp
@@ -26,6 +26,8 @@
#define ADHOC_NS "http://jabber.org/protocol/commands"
#define PING_NS "urn:xmpp:ping"
+class ListElement;
+
/**
* A callback called when the waited iq result is received (it is matched
* against the iq id)
@@ -229,6 +231,12 @@ public:
*/
void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from);
/**
+ * Send the channels list in one big stanza
+ */
+ void send_iq_room_list_result(const std::string& id, const std::string to_jid,
+ const std::string& from,
+ const std::vector<ListElement>& rooms_list);
+ /**
* Handle the various stanza types
*/
void handle_handshake(const Stanza& stanza);
diff --git a/src/xmpp/xmpp_stanza.cpp b/src/xmpp/xmpp_stanza.cpp
index 4290fc7..df19105 100644
--- a/src/xmpp/xmpp_stanza.cpp
+++ b/src/xmpp/xmpp_stanza.cpp
@@ -218,13 +218,12 @@ std::string XmlNode::to_string() const
std::string res("<");
res += this->name;
for (const auto& it: this->attributes)
- res += " " + utils::remove_invalid_xml_chars(it.first) + "='" +
- utils::remove_invalid_xml_chars(it.second) + "'";
+ res += " " + it.first + "='" + sanitize(it.second) + "'";
if (this->closed && !this->has_children() && this->inner.empty())
res += "/>";
else
{
- res += ">" + utils::remove_invalid_xml_chars(this->inner);
+ res += ">" + sanitize(this->inner);
for (const auto& child: this->children)
res += child->to_string();
if (this->closed)
@@ -232,7 +231,7 @@ std::string XmlNode::to_string() const
res += "</" + this->get_name() + ">";
}
}
- res += utils::remove_invalid_xml_chars(this->tail);
+ res += sanitize(this->tail);
return res;
}
@@ -265,3 +264,11 @@ std::string& XmlNode::operator[](const std::string& name)
{
return this->attributes[name];
}
+
+std::string sanitize(const std::string& data)
+{
+ if (utils::is_valid_utf8(data.data()))
+ return xml_escape(utils::remove_invalid_xml_chars(data));
+ else
+ return xml_escape(utils::remove_invalid_xml_chars(utils::convert_to_utf8(data, "ISO-8859-1")));
+}
diff --git a/src/xmpp/xmpp_stanza.hpp b/src/xmpp/xmpp_stanza.hpp
index 9229ae6..f1a6a0f 100644
--- a/src/xmpp/xmpp_stanza.hpp
+++ b/src/xmpp/xmpp_stanza.hpp
@@ -7,6 +7,7 @@
std::string xml_escape(const std::string& data);
std::string xml_unescape(const std::string& data);
+std::string sanitize(const std::string& data);
/**
* Represent an XML node. It has