From 0ec82c104ded01a44ed36d20e25220fa41887fd0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Feb 2015 12:18:34 +0100 Subject: Add louloulibs as a submodule --- louloulibs | 1 + 1 file changed, 1 insertion(+) create mode 160000 louloulibs (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs new file mode 160000 index 0000000..b6af145 --- /dev/null +++ b/louloulibs @@ -0,0 +1 @@ +Subproject commit b6af145bfb9561a1bb1ecb940f50163c5ce4dbbb -- cgit v1.2.3 From e6569a1090be063f34624474f0d4578f37a169ae Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 27 Feb 2015 12:40:50 +0100 Subject: Only use include_directory() if the directory path is defined --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index b6af145..d6a3724 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit b6af145bfb9561a1bb1ecb940f50163c5ce4dbbb +Subproject commit d6a3724c6a0127a49a9e7adb1090bb7438c8d0f2 -- cgit v1.2.3 From e4c696861d86b62305ca0ec8136e79f147837b94 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 2 Mar 2015 11:06:40 +0100 Subject: Update louloulibs to last revision --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index d6a3724..5f3a1bb 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit d6a3724c6a0127a49a9e7adb1090bb7438c8d0f2 +Subproject commit 5f3a1bb54df4de5f332282bbdf791bdce07c71c4 -- cgit v1.2.3 From d88ec5fdf10ecb168355bc38dc81d83ff59a0234 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 2 Mar 2015 11:32:18 +0100 Subject: Update to latest louloulibs revision --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index 5f3a1bb..d0b8695 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit 5f3a1bb54df4de5f332282bbdf791bdce07c71c4 +Subproject commit d0b8695ceb13e0c6d72821fe605de36e494afcdf -- cgit v1.2.3 From c243fea660723eba00b65e639b76d0783cb59064 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 4 Mar 2015 05:56:44 +0100 Subject: Update to latest louloulibs revision --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index d0b8695..99757a4 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit d0b8695ceb13e0c6d72821fe605de36e494afcdf +Subproject commit 99757a44b49619ff59cae9e6d983a3b7c20c56bf -- cgit v1.2.3 From ad0465b32051e224f6a234f3ed36494905e59cbf Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 20 Apr 2015 20:33:02 +0200 Subject: Decode incoming JIDs local part according to xep 0106 This let users send message to nicks such as Q@CServe.quakenet.org fix #3047 --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index 99757a4..88d2b13 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit 99757a44b49619ff59cae9e6d983a3b7c20c56bf +Subproject commit 88d2b136e5f133f0d0dc01f59449284f663d53ea -- cgit v1.2.3 From 0d706741c6b3a8bdf6b4f8ca0b1ac00cb27bd8b8 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 20 Apr 2015 20:35:32 +0200 Subject: Update louloulibs submodule to the correct revision --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index 88d2b13..b53ae92 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit 88d2b136e5f133f0d0dc01f59449284f663d53ea +Subproject commit b53ae922f48f1465a7fa61136f65ec39e38a452e -- cgit v1.2.3 From a8225dc54c019788722bda3bda8d55151c1ccdef Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 21 Apr 2015 15:35:10 +0200 Subject: Properly check for connecting or connected status before reconnecting Note, in our context, is_connecting() includes the resolving part as well as the actual connection (if we are using c-ares) fix #3048 --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index b53ae92..6c812cd 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit b53ae922f48f1465a7fa61136f65ec39e38a452e +Subproject commit 6c812cd86e31569db61cac4e30f77e296d207191 -- cgit v1.2.3 From 71fec776c4d7b99b76a44deae6f333d9cffa1496 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 7 May 2015 17:42:37 +0200 Subject: Update to latest louloulibs fix #3042 --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index 6c812cd..eaa4fbb 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit 6c812cd86e31569db61cac4e30f77e296d207191 +Subproject commit eaa4fbba814b56b4fe7ffb62984fddfbb9280291 -- cgit v1.2.3 From fbeb5af364db54c8a82f5ea30b83df441988ea4b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 13 May 2015 20:17:43 +0200 Subject: Update to latest louloulibs revision, and add test for hostname validity fix #2694 --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index eaa4fbb..89398b5 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit eaa4fbba814b56b4fe7ffb62984fddfbb9280291 +Subproject commit 89398b5d886744c3812b65195308cae57eca2b53 -- cgit v1.2.3 From 897b281e67dc82700db9fd9c2dedc5e01e5871ee Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 27 May 2015 23:44:23 +0200 Subject: Avoid some potential race conditions by blocking the signals we manage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They are atomically unblocked in the ppoll/epoll_pwait calls, avoiding any race condition on the check of the “stop” or “reload” booleans. --- louloulibs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs index 89398b5..0f3c118 160000 --- a/louloulibs +++ b/louloulibs @@ -1 +1 @@ -Subproject commit 89398b5d886744c3812b65195308cae57eca2b53 +Subproject commit 0f3c1183e2bf0941ae2bffd3f31577bce4f3001c -- cgit v1.2.3 From e1a7114c8daa10589c830ce972cf461c3540111b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 28 May 2015 23:42:52 +0200 Subject: louloulibs is directly included, instead of being a submodule Because this is a nightmare to manage --- louloulibs | 1 - louloulibs/xmpp/adhoc_command.cpp | 105 +++++ louloulibs/xmpp/adhoc_command.hpp | 43 ++ louloulibs/xmpp/adhoc_commands_handler.cpp | 133 ++++++ louloulibs/xmpp/adhoc_commands_handler.hpp | 74 +++ louloulibs/xmpp/adhoc_session.cpp | 37 ++ louloulibs/xmpp/adhoc_session.hpp | 70 +++ louloulibs/xmpp/body.hpp | 12 + louloulibs/xmpp/jid.cpp | 101 ++++ louloulibs/xmpp/jid.hpp | 36 ++ louloulibs/xmpp/roster.cpp | 21 + louloulibs/xmpp/roster.hpp | 71 +++ louloulibs/xmpp/xmpp_component.cpp | 716 +++++++++++++++++++++++++++++ louloulibs/xmpp/xmpp_component.hpp | 240 ++++++++++ louloulibs/xmpp/xmpp_parser.cpp | 169 +++++++ louloulibs/xmpp/xmpp_parser.hpp | 126 +++++ louloulibs/xmpp/xmpp_stanza.cpp | 274 +++++++++++ louloulibs/xmpp/xmpp_stanza.hpp | 160 +++++++ 18 files changed, 2388 insertions(+), 1 deletion(-) delete mode 160000 louloulibs create mode 100644 louloulibs/xmpp/adhoc_command.cpp create mode 100644 louloulibs/xmpp/adhoc_command.hpp create mode 100644 louloulibs/xmpp/adhoc_commands_handler.cpp create mode 100644 louloulibs/xmpp/adhoc_commands_handler.hpp create mode 100644 louloulibs/xmpp/adhoc_session.cpp create mode 100644 louloulibs/xmpp/adhoc_session.hpp create mode 100644 louloulibs/xmpp/body.hpp create mode 100644 louloulibs/xmpp/jid.cpp create mode 100644 louloulibs/xmpp/jid.hpp create mode 100644 louloulibs/xmpp/roster.cpp create mode 100644 louloulibs/xmpp/roster.hpp create mode 100644 louloulibs/xmpp/xmpp_component.cpp create mode 100644 louloulibs/xmpp/xmpp_component.hpp create mode 100644 louloulibs/xmpp/xmpp_parser.cpp create mode 100644 louloulibs/xmpp/xmpp_parser.hpp create mode 100644 louloulibs/xmpp/xmpp_stanza.cpp create mode 100644 louloulibs/xmpp/xmpp_stanza.hpp (limited to 'louloulibs/xmpp') diff --git a/louloulibs b/louloulibs deleted file mode 160000 index 0f3c118..0000000 --- a/louloulibs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0f3c1183e2bf0941ae2bffd3f31577bce4f3001c diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp new file mode 100644 index 0000000..24145f5 --- /dev/null +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -0,0 +1,105 @@ +#include +#include +#include + +using namespace std::string_literals; + +AdhocCommand::AdhocCommand(std::vector&& callbacks, const std::string& name, const bool admin_only): + name(name), + callbacks(std::move(callbacks)), + admin_only(admin_only) +{ +} + +AdhocCommand::~AdhocCommand() +{ +} + +bool AdhocCommand::is_admin_only() const +{ + return this->admin_only; +} + +void PingStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) +{ + XmlNode note("note"); + note["type"] = "info"; + note.set_inner("Pong"); + note.close(); + command_node.add_child(std::move(note)); +} + +void HelloStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) +{ + XmlNode x("jabber:x:data:x"); + x["type"] = "form"; + XmlNode title("title"); + title.set_inner("Configure your name."); + title.close(); + x.add_child(std::move(title)); + XmlNode instructions("instructions"); + instructions.set_inner("Please provide your name."); + instructions.close(); + x.add_child(std::move(instructions)); + XmlNode name_field("field"); + name_field["var"] = "name"; + name_field["type"] = "text-single"; + name_field["label"] = "Your name"; + XmlNode required("required"); + required.close(); + name_field.add_child(std::move(required)); + name_field.close(); + x.add_child(std::move(name_field)); + x.close(); + command_node.add_child(std::move(x)); +} + +void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) +{ + // Find out if the name was provided in the form. + XmlNode* x = command_node.get_child("x", "jabber:x:data"); + if (x) + { + XmlNode* name_field = nullptr; + for (XmlNode* field: x->get_children("field", "jabber:x:data")) + if (field->get_tag("var") == "name") + { + name_field = field; + break; + } + if (name_field) + { + XmlNode* value = name_field->get_child("value", "jabber:x:data"); + if (value) + { + XmlNode note("note"); + note["type"] = "info"; + note.set_inner("Hello "s + value->get_inner() + "!"s); + note.close(); + command_node.delete_all_children(); + command_node.add_child(std::move(note)); + return; + } + } + } + command_node.delete_all_children(); + XmlNode error(ADHOC_NS":error"); + error["type"] = "modify"; + XmlNode condition(STANZA_NS":bad-request"); + condition.close(); + error.add_child(std::move(condition)); + error.close(); + command_node.add_child(std::move(error)); + session.terminate(); +} + +void Reload(XmppComponent*, AdhocSession&, XmlNode& command_node) +{ + ::reload_process(); + command_node.delete_all_children(); + XmlNode note("note"); + note["type"] = "info"; + note.set_inner("Configuration reloaded."); + note.close(); + command_node.add_child(std::move(note)); +} diff --git a/louloulibs/xmpp/adhoc_command.hpp b/louloulibs/xmpp/adhoc_command.hpp new file mode 100644 index 0000000..1ff2bcf --- /dev/null +++ b/louloulibs/xmpp/adhoc_command.hpp @@ -0,0 +1,43 @@ +#ifndef ADHOC_COMMAND_HPP +# define ADHOC_COMMAND_HPP + +/** + * Describe an ad-hoc command. + * + * Can only have zero or one step for now. When execution is requested, it + * can return a result immediately, or provide a form to be filled, and + * provide a result once the filled form is received. + */ + +#include + +#include +#include + +class AdhocCommand +{ + friend class AdhocSession; +public: + AdhocCommand(std::vector&& callback, const std::string& name, const bool admin_only); + ~AdhocCommand(); + + const std::string name; + + bool is_admin_only() const; + +private: + /** + * A command may have one or more steps. Each step is a different + * callback, inserting things into a XmlNode and calling + * methods of an AdhocSession. + */ + std::vector callbacks; + const bool admin_only; +}; + +void PingStep1(XmppComponent*, AdhocSession& session, XmlNode& command_node); +void HelloStep1(XmppComponent*, AdhocSession& session, XmlNode& command_node); +void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node); +void Reload(XmppComponent*, AdhocSession& session, XmlNode& command_node); + +#endif // ADHOC_COMMAND_HPP diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp new file mode 100644 index 0000000..46c8a32 --- /dev/null +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -0,0 +1,133 @@ +#include +#include + +#include +#include +#include +#include + +#include + +using namespace std::string_literals; + +const std::map& AdhocCommandsHandler::get_commands() const +{ + return this->commands; +} + +std::map& AdhocCommandsHandler::get_commands() +{ + return this->commands; +} + +XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, XmlNode command_node) +{ + std::string action = command_node.get_tag("action"); + if (action.empty()) + action = "execute"; + command_node.del_tag("action"); + + Jid jid(executor_jid); + + const std::string node = command_node.get_tag("node"); + auto command_it = this->commands.find(node); + if (command_it == this->commands.end()) + { + XmlNode error(ADHOC_NS":error"); + error["type"] = "cancel"; + XmlNode condition(STANZA_NS":item-not-found"); + condition.close(); + error.add_child(std::move(condition)); + error.close(); + command_node.add_child(std::move(error)); + } + else if (command_it->second.is_admin_only() && + Config::get("admin", "") != jid.local + "@" + jid.domain) + { + XmlNode error(ADHOC_NS":error"); + error["type"] = "cancel"; + XmlNode condition(STANZA_NS":forbidden"); + condition.close(); + error.add_child(std::move(condition)); + error.close(); + command_node.add_child(std::move(error)); + } + else + { + std::string sessionid = command_node.get_tag("sessionid"); + if (sessionid.empty()) + { // create a new session, with a new id + sessionid = XmppComponent::next_id(); + command_node["sessionid"] = sessionid; + this->sessions.emplace(std::piecewise_construct, + std::forward_as_tuple(sessionid, executor_jid), + std::forward_as_tuple(command_it->second, executor_jid)); + TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 3600s, + std::bind(&AdhocCommandsHandler::remove_session, this, sessionid, executor_jid), + "adhocsession"s + sessionid + executor_jid)); + } + auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid)); + if (session_it == this->sessions.end()) + { + XmlNode error(ADHOC_NS":error"); + error["type"] = "modify"; + XmlNode condition(STANZA_NS":bad-request"); + condition.close(); + error.add_child(std::move(condition)); + error.close(); + command_node.add_child(std::move(error)); + } + else if (action == "execute" || action == "next" || action == "complete") + { + // execute the step + AdhocSession& session = session_it->second; + const AdhocStep& step = session.get_next_step(); + step(this->xmpp_component, session, command_node); + if (session.remaining_steps() == 0 || + session.is_terminated()) + { + this->sessions.erase(session_it); + command_node["status"] = "completed"; + TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid); + } + else + { + command_node["status"] = "executing"; + XmlNode actions("actions"); + XmlNode next("next"); + next.close(); + actions.add_child(std::move(next)); + actions.close(); + command_node.add_child(std::move(actions)); + } + } + else if (action == "cancel") + { + this->sessions.erase(session_it); + command_node["status"] = "canceled"; + TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid); + } + else // unsupported action + { + XmlNode error(ADHOC_NS":error"); + error["type"] = "modify"; + XmlNode condition(STANZA_NS":bad-request"); + condition.close(); + error.add_child(std::move(condition)); + error.close(); + command_node.add_child(std::move(error)); + } + } + return command_node; +} + +void AdhocCommandsHandler::remove_session(const std::string& session_id, const std::string& initiator_jid) +{ + auto session_it = this->sessions.find(std::make_pair(session_id, initiator_jid)); + if (session_it != this->sessions.end()) + { + this->sessions.erase(session_it); + return ; + } + log_error("Tried to remove ad-hoc session for [" << session_id << ", " << initiator_jid << "] but none found"); +} diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp new file mode 100644 index 0000000..1083c44 --- /dev/null +++ b/louloulibs/xmpp/adhoc_commands_handler.hpp @@ -0,0 +1,74 @@ +#ifndef ADHOC_COMMANDS_HANDLER_HPP +# define ADHOC_COMMANDS_HANDLER_HPP + +/** + * Manage a list of available AdhocCommands and the list of ongoing + * AdhocCommandSessions. + */ + +#include +#include + +#include +#include +#include + +class AdhocCommandsHandler +{ +public: + explicit AdhocCommandsHandler(XmppComponent* xmpp_component): + xmpp_component(xmpp_component), + commands{} + { } + ~AdhocCommandsHandler() = default; + /** + * Returns the list of available commands. + */ + const std::map& get_commands() const; + /** + * This one can be used to add new commands. + */ + std::map& get_commands(); + /** + * Find the requested command, create a new session or use an existing + * one, and process the request (provide a new form, an error, or a + * result). + * + * Returns a (moved) XmlNode that will be inserted in the iq response. It + * should be a node containing one or more useful children. If + * it contains an node, the iq response will have an error type. + * + * Takes a copy of the node so we can actually edit it and use + * it as our return value. + */ + XmlNode handle_request(const std::string& executor_jid, XmlNode command_node); + /** + * Remove the session from the list. This is done to avoid filling the + * memory with waiting session (for example due to a client that starts + * multi-steps command but never finishes them). + */ + void remove_session(const std::string& session_id, const std::string& initiator_jid); +private: + /** + * A pointer to the XmppComponent, to access to basically anything in the + * gateway. + */ + XmppComponent* xmpp_component; + /** + * The list of all available commands. + */ + std::map commands; + /** + * The list of all currently on-going commands. + * + * Of the form: {{session_id, owner_jid}, session}. + */ + std::map, AdhocSession> sessions; + + AdhocCommandsHandler(const AdhocCommandsHandler&) = delete; + AdhocCommandsHandler(AdhocCommandsHandler&&) = delete; + AdhocCommandsHandler& operator=(const AdhocCommandsHandler&) = delete; + AdhocCommandsHandler& operator=(AdhocCommandsHandler&&) = delete; +}; + +#endif // ADHOC_COMMANDS_HANDLER_HPP diff --git a/louloulibs/xmpp/adhoc_session.cpp b/louloulibs/xmpp/adhoc_session.cpp new file mode 100644 index 0000000..fc60bb7 --- /dev/null +++ b/louloulibs/xmpp/adhoc_session.cpp @@ -0,0 +1,37 @@ +#include +#include + +#include + +AdhocSession::AdhocSession(const AdhocCommand& command, const std::string& jid): + command(command), + owner_jid(jid), + current_step(0), + terminated(false) +{ +} + +AdhocSession::~AdhocSession() +{ +} + +const AdhocStep& AdhocSession::get_next_step() +{ + assert(this->current_step < this->command.callbacks.size()); + return this->command.callbacks[this->current_step++]; +} + +size_t AdhocSession::remaining_steps() const +{ + return this->command.callbacks.size() - this->current_step; +} + +bool AdhocSession::is_terminated() const +{ + return this->terminated; +} + +void AdhocSession::terminate() +{ + this->terminated = true; +} diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp new file mode 100644 index 0000000..ddfb2fe --- /dev/null +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -0,0 +1,70 @@ +#ifndef ADHOC_SESSION_HPP +# define ADHOC_SESSION_HPP + +#include + +#include +#include + +class XmppComponent; + +class AdhocCommand; +class AdhocSession; + +/** + * A function executed as an ad-hoc command step. It takes a + * XmlNode and modifies it accordingly (inserting for example an + * node, or a data form…). + * TODO fix this: + * It also must call one of step_passed(), cancel() etc on the AdhocSession object. + */ +typedef std::function AdhocStep; + +class AdhocSession +{ +public: + explicit AdhocSession(const AdhocCommand& command, const std::string& jid); + ~AdhocSession(); + /** + * Return the function to be executed, found in our AdhocCommand, for the + * current_step. And increment the current_step. + */ + const AdhocStep& get_next_step(); + /** + * Return the number of remaining steps. + */ + size_t remaining_steps() const; + /** + * This may be modified by an AdhocStep, to indicate that this session + * should no longer exist, because we encountered an error, and we can't + * execute any more step of it. + */ + void terminate(); + bool is_terminated() const; + +private: + /** + * A reference of the command concerned by this session. Used for example + * to get the next step of that command, things like that. + */ + const AdhocCommand& command; + /** + * The full JID of the XMPP user that created this session by executing + * the first step of a command. Only that JID must be allowed to access + * this session. + */ + const std::string& owner_jid; + /** + * The current step we are at. It starts at zero. It is used to index the + * associated AdhocCommand::callbacks vector. + */ + size_t current_step; + bool terminated; + + AdhocSession(const AdhocSession&) = delete; + AdhocSession(AdhocSession&&) = delete; + AdhocSession& operator=(const AdhocSession&) = delete; + AdhocSession& operator=(AdhocSession&&) = delete; +}; + +#endif // ADHOC_SESSION_HPP diff --git a/louloulibs/xmpp/body.hpp b/louloulibs/xmpp/body.hpp new file mode 100644 index 0000000..6ac678e --- /dev/null +++ b/louloulibs/xmpp/body.hpp @@ -0,0 +1,12 @@ +#ifndef XMPP_BODY_HPP_INCLUDED +#define XMPP_BODY_HPP_INCLUDED + +namespace Xmpp +{ +// Contains: +// - an XMPP-valid UTF-8 body +// - an XML node representing the XHTML-IM body, or null + typedef std::tuple> body; +} + +#endif /* XMPP_BODY_HPP_INCLUDED */ diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp new file mode 100644 index 0000000..e6fee45 --- /dev/null +++ b/louloulibs/xmpp/jid.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +#include +#ifdef LIBIDN_FOUND + #include +#endif + +#include + +Jid::Jid(const std::string& jid) +{ + std::string::size_type slash = jid.find('/'); + if (slash != std::string::npos) + { + this->resource = jid.substr(slash + 1); + } + + std::string::size_type at = jid.find('@'); + if (at != std::string::npos && at < slash) + { + this->local = jid.substr(0, at); + at++; + } + else + at = 0; + + 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 + using CacheType = std::map; + static CacheType cache; + std::pair cached = cache.insert({original, {}}); + if (std::get<1>(cached) == false) + { // Insertion failed: the result is already in the cache, return it + return std::get<0>(cached)->second; + } + + 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 ""; + } + std::replace_if(std::begin(domain), domain + ::strlen(domain), + [](const char c) -> bool + { + return !((c >= 'a' && c <= 'z') || c == '-' || + (c >= '0' && c <= '9') || c == '.'); + }, '-'); + + // If there is no resource, stop here + if (jid.resource.empty()) + { + std::get<0>(cached)->second = std::string(local) + "@" + domain; + return std::get<0>(cached)->second; + } + + // Otherwise, also process the resource part + char resource[max_jid_part_len] = {}; + memcpy(resource, jid.resource.data(), jid.resource.size()); + rc = static_cast(::stringprep(resource, max_jid_part_len, + static_cast(0), stringprep_xmpp_resourceprep)); + if (rc != STRINGPREP_OK) + { + log_error(error_msg + stringprep_strerror(rc)); + return ""; + } + std::get<0>(cached)->second = std::string(local) + "@" + domain + "/" + resource; + return std::get<0>(cached)->second; + +#else + (void)original; + return ""; +#endif +} diff --git a/louloulibs/xmpp/jid.hpp b/louloulibs/xmpp/jid.hpp new file mode 100644 index 0000000..b6975a2 --- /dev/null +++ b/louloulibs/xmpp/jid.hpp @@ -0,0 +1,36 @@ +#ifndef JID_INCLUDED +# define JID_INCLUDED + +#include + +/** + * Parse a JID into its different subart + */ +class Jid +{ +public: + explicit Jid(const std::string& jid); + + std::string domain; + std::string local; + std::string resource; + +private: + Jid(const Jid&) = delete; + Jid(Jid&&) = delete; + Jid& operator=(const Jid&) = delete; + 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/louloulibs/xmpp/roster.cpp b/louloulibs/xmpp/roster.cpp new file mode 100644 index 0000000..a14a384 --- /dev/null +++ b/louloulibs/xmpp/roster.cpp @@ -0,0 +1,21 @@ +#include + +RosterItem::RosterItem(const std::string& jid, const std::string& name, + std::vector& groups): + jid(jid), + name(name), + groups(groups) +{ +} + +RosterItem::RosterItem(const std::string& jid, const std::string& name): + jid(jid), + name(name), + groups{} +{ +} + +void Roster::clear() +{ + this->items.clear(); +} diff --git a/louloulibs/xmpp/roster.hpp b/louloulibs/xmpp/roster.hpp new file mode 100644 index 0000000..0aebca5 --- /dev/null +++ b/louloulibs/xmpp/roster.hpp @@ -0,0 +1,71 @@ +#ifndef ROSTER_HPP_INCLUDED +#define ROSTER_HPP_INCLUDED + +#include +#include +#include + +class RosterItem +{ +public: + RosterItem(const std::string& jid, const std::string& name, + std::vector& groups); + RosterItem(const std::string& jid, const std::string& name); + RosterItem() = default; + ~RosterItem() = default; + RosterItem(const RosterItem&) = default; + RosterItem(RosterItem&&) = default; + RosterItem& operator=(const RosterItem&) = default; + RosterItem& operator=(RosterItem&&) = default; + + std::string jid; + std::string name; + std::vector groups; + +private: +}; + +/** + * Keep track of the last known stat of a JID's roster + */ +class Roster +{ +public: + Roster() = default; + ~Roster() = default; + + void clear(); + + template + RosterItem* add_item(ArgsType&&... args) + { + this->items.emplace_back(std::forward(args)...); + auto it = this->items.end() - 1; + return &*it; + } + RosterItem* get_item(const std::string& jid) + { + auto it = std::find_if(this->items.begin(), this->items.end(), + [this, &jid](const auto& item) + { + return item.jid == jid; + }); + if (it != this->items.end()) + return &*it; + return nullptr; + } + const std::vector& get_items() const + { + return this->items; + } + +private: + std::vector items; + + Roster(const Roster&) = delete; + Roster(Roster&&) = delete; + Roster& operator=(const Roster&) = delete; + Roster& operator=(Roster&&) = delete; +}; + +#endif /* ROSTER_HPP_INCLUDED */ diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp new file mode 100644 index 0000000..1048f86 --- /dev/null +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -0,0 +1,716 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#ifdef SYSTEMD_FOUND +# include +#endif + +using namespace std::string_literals; + +static std::set kickable_errors{ + "gone", + "internal-server-error", + "item-not-found", + "jid-malformed", + "recipient-unavailable", + "redirect", + "remote-server-not-found", + "remote-server-timeout", + "service-unavailable", + "malformed-error" + }; + +XmppComponent::XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret): + TCPSocketHandler(poller), + ever_auth(false), + first_connection_try(true), + secret(secret), + authenticated(false), + doc_open(false), + served_hostname(hostname), + stanza_handlers{}, + adhoc_commands_handler(this) +{ + this->parser.add_stream_open_callback(std::bind(&XmppComponent::on_remote_stream_open, this, + std::placeholders::_1)); + this->parser.add_stanza_callback(std::bind(&XmppComponent::on_stanza, this, + std::placeholders::_1)); + this->parser.add_stream_close_callback(std::bind(&XmppComponent::on_remote_stream_close, this, + std::placeholders::_1)); + this->stanza_handlers.emplace("handshake", + std::bind(&XmppComponent::handle_handshake, this,std::placeholders::_1)); + this->stanza_handlers.emplace("error", + std::bind(&XmppComponent::handle_error, this,std::placeholders::_1)); +} + +void XmppComponent::start() +{ + this->connect("127.0.0.1", Config::get("port", "5347"), false); +} + +bool XmppComponent::is_document_open() const +{ + return this->doc_open; +} + +void XmppComponent::send_stanza(const Stanza& stanza) +{ + std::string str = stanza.to_string(); + log_debug("XMPP SENDING: " << str); + this->send_data(std::move(str)); +} + +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 SYSTEMD_FOUND + sd_notifyf(0, "STATUS=Failed to connect to the XMPP server: %s", reason.data()); +#endif +} + +void XmppComponent::on_connected() +{ + log_info("connected to XMPP server"); + this->first_connection_try = true; + XmlNode node("", nullptr); + node.set_name("stream:stream"); + node["xmlns"] = COMPONENT_NS; + node["xmlns:stream"] = STREAM_NS; + node["to"] = this->served_hostname; + this->send_stanza(node); + this->doc_open = true; + // We may have some pending data to send: this happens when we try to send + // some data before we are actually connected. We send that data right now, if any + this->send_pending_data(); +} + +void XmppComponent::on_connection_close(const std::string& error) +{ + if (error.empty()) + { + log_info("XMPP server closed connection"); + } + else + { + log_info("XMPP server closed connection: " << error); + } +} + +void XmppComponent::parse_in_buffer(const size_t size) +{ + if (!this->in_buf.empty()) + { // This may happen if the parser could not allocate enough space for + // us. We try to feed it the data that was read into our in_buf + // instead. If this fails again we are in trouble. + this->parser.feed(this->in_buf.data(), this->in_buf.size(), false); + this->in_buf.clear(); + } + else + { // Just tell the parser to parse the data that was placed into the + // buffer it provided to us with GetBuffer + this->parser.parse(size, false); + } +} + +void XmppComponent::on_remote_stream_open(const XmlNode& node) +{ + log_debug("XMPP DOCUMENT OPEN: " << node.to_string()); + this->stream_id = node.get_tag("id"); + if (this->stream_id.empty()) + { + log_error("Error: no attribute 'id' found"); + this->send_stream_error("bad-format", "missing 'id' attribute"); + this->close_document(); + return ; + } + + // Try to authenticate + char digest[HASH_LENGTH * 2 + 1]; + sha1nfo sha1; + sha1_init(&sha1); + sha1_write(&sha1, this->stream_id.data(), this->stream_id.size()); + sha1_write(&sha1, this->secret.data(), this->secret.size()); + const uint8_t* result = sha1_result(&sha1); + for (int i=0; i < HASH_LENGTH; i++) + sprintf(digest + (i*2), "%02x", result[i]); + digest[HASH_LENGTH * 2] = '\0'; + + Stanza handshake(COMPONENT_NS":handshake"); + handshake.set_inner(digest); + handshake.close(); + this->send_stanza(handshake); +} + +void XmppComponent::on_remote_stream_close(const XmlNode& node) +{ + log_debug("XMPP DOCUMENT CLOSE " << node.to_string()); + this->doc_open = false; +} + +void XmppComponent::reset() +{ + this->parser.reset(); +} + +void XmppComponent::on_stanza(const Stanza& stanza) +{ + log_debug("XMPP RECEIVING: " << stanza.to_string()); + std::function handler; + try + { + handler = this->stanza_handlers.at(stanza.get_name()); + } + catch (const std::out_of_range& exception) + { + log_warning("No handler for stanza of type " << stanza.get_name()); + return; + } + handler(stanza); +} + +void XmppComponent::send_stream_error(const std::string& name, const std::string& explanation) +{ + XmlNode node("stream:error", nullptr); + XmlNode error(name, nullptr); + error["xmlns"] = STREAM_NS; + if (!explanation.empty()) + error.set_inner(explanation); + error.close(); + node.add_child(std::move(error)); + node.close(); + this->send_stanza(node); +} + +void XmppComponent::send_stanza_error(const std::string& kind, const std::string& to, const std::string& from, + const std::string& id, const std::string& error_type, + const std::string& defined_condition, const std::string& text, + const bool fulljid) +{ + Stanza node(kind); + if (!to.empty()) + node["to"] = to; + if (!from.empty()) + { + if (fulljid) + node["from"] = from; + else + node["from"] = from + "@" + this->served_hostname; + } + if (!id.empty()) + node["id"] = id; + node["type"] = "error"; + XmlNode error("error"); + error["type"] = error_type; + XmlNode inner_error(defined_condition); + inner_error["xmlns"] = STANZA_NS; + inner_error.close(); + error.add_child(std::move(inner_error)); + if (!text.empty()) + { + XmlNode text_node("text"); + text_node["xmlns"] = STANZA_NS; + text_node.set_inner(text); + text_node.close(); + error.add_child(std::move(text_node)); + } + error.close(); + node.add_child(std::move(error)); + node.close(); + this->send_stanza(node); +} + +void XmppComponent::close_document() +{ + log_debug("XMPP SENDING: "); + this->send_data(""); + this->doc_open = false; +} + +void XmppComponent::handle_handshake(const Stanza& stanza) +{ + (void)stanza; + this->authenticated = true; + this->ever_auth = true; + log_info("Authenticated with the XMPP server"); +#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. + uint64_t usec; + if (sd_watchdog_enabled(0, &usec) > 0) + { + TimedEventsManager::instance().add_event(TimedEvent( + std::chrono::duration_cast(std::chrono::microseconds(usec / 2)), + []() { sd_notify(0, "WATCHDOG=1"); })); + } +#endif + this->after_handshake(); +} + +void XmppComponent::handle_error(const Stanza& stanza) +{ + XmlNode* text = stanza.get_child("text", STREAMS_NS); + std::string error_message("Unspecified error"); + if (text) + error_message = text->get_inner(); + log_error("Stream error received from the XMPP server: " << error_message); +#ifdef SYSTEMD_FOUND + if (!this->ever_auth) + sd_notifyf(0, "STATUS=Failed to authenticate to the XMPP server: %s", error_message.data()); +#endif + +} + +void* XmppComponent::get_receive_buffer(const size_t size) const +{ + return this->parser.get_buffer(size); +} + +void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, const std::string& type, const bool fulljid) +{ + XmlNode node("message"); + node["to"] = to; + if (fulljid) + node["from"] = from; + else + node["from"] = from + "@" + this->served_hostname; + if (!type.empty()) + node["type"] = type; + XmlNode body_node("body"); + body_node.set_inner(std::get<0>(body)); + body_node.close(); + node.add_child(std::move(body_node)); + if (std::get<1>(body)) + { + XmlNode html("html"); + html["xmlns"] = XHTMLIM_NS; + // Pass the ownership of the pointer to this xmlnode + html.add_child(std::get<1>(body).release()); + html.close(); + node.add_child(std::move(html)); + } + node.close(); + this->send_stanza(node); +} + +void XmppComponent::send_user_join(const std::string& from, + const std::string& nick, + const std::string& realjid, + const std::string& affiliation, + const std::string& role, + const std::string& to, + const bool self) +{ + XmlNode node("presence"); + node["to"] = to; + node["from"] = from + "@" + this->served_hostname + "/" + nick; + + XmlNode x("x"); + x["xmlns"] = MUC_USER_NS; + + XmlNode item("item"); + if (!affiliation.empty()) + item["affiliation"] = affiliation; + if (!role.empty()) + item["role"] = role; + 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)); + + if (self) + { + XmlNode status("status"); + status["code"] = "110"; + status.close(); + x.add_child(std::move(status)); + } + x.close(); + node.add_child(std::move(x)); + node.close(); + this->send_stanza(node); +} + +void XmppComponent::send_invalid_room_error(const std::string& muc_name, + const std::string& nick, + const std::string& to) +{ + Stanza presence("presence"); + if (!muc_name.empty()) + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + else + presence["from"] = this->served_hostname; + presence["to"] = to; + presence["type"] = "error"; + XmlNode x("x"); + x["xmlns"] = MUC_NS; + x.close(); + presence.add_child(std::move(x)); + XmlNode error("error"); + error["by"] = muc_name + "@" + this->served_hostname; + error["type"] = "cancel"; + XmlNode item_not_found("item-not-found"); + item_not_found["xmlns"] = STANZA_NS; + item_not_found.close(); + error.add_child(std::move(item_not_found)); + XmlNode text("text"); + text["xmlns"] = STANZA_NS; + text["xml:lang"] = "en"; + text.set_inner(muc_name + + " is not a valid IRC channel name. A correct room jid is of the form: #%@" + + this->served_hostname); + text.close(); + error.add_child(std::move(text)); + error.close(); + presence.add_child(std::move(error)); + presence.close(); + this->send_stanza(presence); +} + +void XmppComponent::send_invalid_user_error(const std::string& user_name, const std::string& to) +{ + Stanza message("message"); + message["from"] = user_name + "@" + this->served_hostname; + message["to"] = to; + message["type"] = "error"; + XmlNode x("x"); + x["xmlns"] = MUC_NS; + x.close(); + message.add_child(std::move(x)); + XmlNode error("error"); + error["type"] = "cancel"; + XmlNode item_not_found("item-not-found"); + item_not_found["xmlns"] = STANZA_NS; + item_not_found.close(); + error.add_child(std::move(item_not_found)); + XmlNode text("text"); + text["xmlns"] = STANZA_NS; + text["xml:lang"] = "en"; + text.set_inner(user_name + + " is not a valid IRC user name. A correct user jid is of the form: !@" + + this->served_hostname); + text.close(); + error.add_child(std::move(text)); + error.close(); + message.add_child(std::move(error)); + message.close(); + this->send_stanza(message); +} + +void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to) +{ + XmlNode message("message"); + message["to"] = to; + message["from"] = from + "@" + this->served_hostname; + message["type"] = "groupchat"; + XmlNode subject("subject"); + subject.set_inner(std::get<0>(topic)); + subject.close(); + message.add_child(std::move(subject)); + message.close(); + this->send_stanza(message); +} + +void XmppComponent::send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& xmpp_body, const std::string& jid_to) +{ + Stanza message("message"); + message["to"] = jid_to; + if (!nick.empty()) + message["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + else // Message from the room itself + message["from"] = muc_name + "@" + this->served_hostname; + message["type"] = "groupchat"; + XmlNode body("body"); + body.set_inner(std::get<0>(xmpp_body)); + body.close(); + message.add_child(std::move(body)); + if (std::get<1>(xmpp_body)) + { + XmlNode html("html"); + html["xmlns"] = XHTMLIM_NS; + // Pass the ownership of the pointer to this xmlnode + html.add_child(std::get<1>(xmpp_body).release()); + html.close(); + message.add_child(std::move(html)); + } + message.close(); + this->send_stanza(message); +} + +void XmppComponent::send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self) +{ + Stanza presence("presence"); + presence["to"] = jid_to; + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + presence["type"] = "unavailable"; + const std::string message_str = std::get<0>(message); + XmlNode x("x"); + x["xmlns"] = MUC_USER_NS; + if (self) + { + XmlNode status("status"); + status["code"] = "110"; + status.close(); + x.add_child(std::move(status)); + } + x.close(); + presence.add_child(std::move(x)); + if (!message_str.empty()) + { + XmlNode status("status"); + status.set_inner(message_str); + status.close(); + presence.add_child(std::move(status)); + } + presence.close(); + this->send_stanza(presence); +} + +void XmppComponent::send_nick_change(const std::string& muc_name, + const std::string& old_nick, + const std::string& new_nick, + const std::string& affiliation, + const std::string& role, + const std::string& jid_to, + const bool self) +{ + Stanza presence("presence"); + presence["to"] = jid_to; + presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick; + presence["type"] = "unavailable"; + XmlNode x("x"); + x["xmlns"] = MUC_USER_NS; + XmlNode item("item"); + item["nick"] = new_nick; + item.close(); + x.add_child(std::move(item)); + XmlNode status("status"); + status["code"] = "303"; + status.close(); + x.add_child(std::move(status)); + if (self) + { + XmlNode status2("status"); + status2["code"] = "110"; + status2.close(); + x.add_child(std::move(status2)); + } + x.close(); + presence.add_child(std::move(x)); + presence.close(); + this->send_stanza(presence); + + this->send_user_join(muc_name, new_nick, "", affiliation, role, jid_to, self); +} + +void XmppComponent::kick_user(const std::string& muc_name, + const std::string& target, + const std::string& txt, + const std::string& author, + const std::string& jid_to) +{ + Stanza presence("presence"); + presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; + presence["to"] = jid_to; + presence["type"] = "unavailable"; + XmlNode x("x"); + x["xmlns"] = MUC_USER_NS; + XmlNode item("item"); + item["affiliation"] = "none"; + item["role"] = "none"; + XmlNode actor("actor"); + actor["nick"] = author; + actor["jid"] = author; // backward compatibility with old clients + actor.close(); + item.add_child(std::move(actor)); + XmlNode reason("reason"); + reason.set_inner(txt); + reason.close(); + item.add_child(std::move(reason)); + item.close(); + x.add_child(std::move(item)); + XmlNode status("status"); + status["code"] = "307"; + status.close(); + x.add_child(std::move(status)); + x.close(); + presence.add_child(std::move(x)); + presence.close(); + this->send_stanza(presence); +} + +void XmppComponent::send_presence_error(const std::string& muc_name, + const std::string& nickname, + const std::string& jid_to, + const std::string& type, + const std::string& condition, + const std::string& error_code, + const std::string& /* text */) +{ + Stanza presence("presence"); + presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname; + presence["to"] = jid_to; + presence["type"] = "error"; + XmlNode x("x"); + x["xmlns"] = MUC_NS; + x.close(); + presence.add_child(std::move(x)); + XmlNode error("error"); + error["by"] = muc_name + "@" + this->served_hostname; + error["type"] = type; + if (!error_code.empty()) + error["code"] = error_code; + XmlNode subnode(condition); + subnode["xmlns"] = STANZA_NS; + subnode.close(); + error.add_child(std::move(subnode)); + error.close(); + presence.add_child(std::move(error)); + presence.close(); + this->send_stanza(presence); +} + +void XmppComponent::send_affiliation_role_change(const std::string& muc_name, + const std::string& target, + const std::string& affiliation, + const std::string& role, + const std::string& jid_to) +{ + Stanza presence("presence"); + presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; + presence["to"] = jid_to; + XmlNode x("x"); + x["xmlns"] = MUC_USER_NS; + XmlNode item("item"); + item["affiliation"] = affiliation; + item["role"] = role; + item.close(); + x.add_child(std::move(item)); + x.close(); + presence.add_child(std::move(x)); + presence.close(); + this->send_stanza(presence); +} + +void XmppComponent::send_version(const std::string& id, const std::string& jid_to, const std::string& jid_from, + const std::string& version) +{ + Stanza iq("iq"); + iq["type"] = "result"; + iq["id"] = id; + iq["to"] = jid_to; + iq["from"] = jid_from; + XmlNode query("query"); + query["xmlns"] = VERSION_NS; + if (version.empty()) + { + XmlNode name("name"); + name.set_inner("biboumi"); + name.close(); + query.add_child(std::move(name)); + XmlNode version("version"); + version.set_inner(SOFTWARE_VERSION); + version.close(); + query.add_child(std::move(version)); + XmlNode os("os"); + os.set_inner(SYSTEM_NAME); + os.close(); + query.add_child(std::move(os)); + } + else + { + XmlNode name("name"); + name.set_inner(version); + name.close(); + query.add_child(std::move(name)); + } + query.close(); + iq.add_child(std::move(query)); + iq.close(); + this->send_stanza(iq); +} + +void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid) +{ + Stanza iq("iq"); + iq["type"] = "result"; + iq["id"] = id; + iq["to"] = requester_jid; + iq["from"] = this->served_hostname; + XmlNode query("query"); + query["xmlns"] = DISCO_ITEMS_NS; + query["node"] = ADHOC_NS; + for (const auto& kv: this->adhoc_commands_handler.get_commands()) + { + XmlNode item("item"); + item["jid"] = this->served_hostname; + item["node"] = kv.first; + item["name"] = kv.second.name; + item.close(); + query.add_child(std::move(item)); + } + query.close(); + iq.add_child(std::move(query)); + iq.close(); + this->send_stanza(iq); +} + +void XmppComponent::send_iq_version_request(const std::string& from, + const std::string& jid_to) +{ + Stanza iq("iq"); + iq["type"] = "get"; + iq["id"] = "version_"s + XmppComponent::next_id(); + iq["from"] = from + "@" + this->served_hostname; + iq["to"] = jid_to; + XmlNode query("query"); + query["xmlns"] = VERSION_NS; + query.close(); + iq.add_child(std::move(query)); + iq.close(); + this->send_stanza(iq); +} + +void XmppComponent::send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from_local_part) +{ + Stanza iq("iq"); + if (!from_local_part.empty()) + iq["from"] = from_local_part + "@" + this->served_hostname; + else + iq["from"] = this->served_hostname; + iq["to"] = to_jid; + iq["id"] = id; + iq["type"] = "result"; + iq.close(); + this->send_stanza(iq); +} + +std::string XmppComponent::next_id() +{ + char uuid_str[37]; + uuid_t uuid; + uuid_generate(uuid); + uuid_unparse(uuid, uuid_str); + return uuid_str; +} diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp new file mode 100644 index 0000000..1bea54e --- /dev/null +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -0,0 +1,240 @@ +#ifndef XMPP_COMPONENT_INCLUDED +# define XMPP_COMPONENT_INCLUDED + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define STREAM_NS "http://etherx.jabber.org/streams" +#define COMPONENT_NS "jabber:component:accept" +#define MUC_NS "http://jabber.org/protocol/muc" +#define MUC_USER_NS MUC_NS"#user" +#define MUC_ADMIN_NS MUC_NS"#admin" +#define DISCO_NS "http://jabber.org/protocol/disco" +#define DISCO_ITEMS_NS DISCO_NS"#items" +#define DISCO_INFO_NS DISCO_NS"#info" +#define XHTMLIM_NS "http://jabber.org/protocol/xhtml-im" +#define STANZA_NS "urn:ietf:params:xml:ns:xmpp-stanzas" +#define STREAMS_NS "urn:ietf:params:xml:ns:xmpp-streams" +#define VERSION_NS "jabber:iq:version" +#define ADHOC_NS "http://jabber.org/protocol/commands" +#define PING_NS "urn:xmpp:ping" + +/** + * An XMPP component, communicating with an XMPP server using the protocole + * described in XEP-0114: Jabber Component Protocol + * + * TODO: implement XEP-0225: Component Connections + */ +class XmppComponent: public TCPSocketHandler +{ +public: + explicit XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret); + virtual ~XmppComponent() = default; + + void on_connection_failed(const std::string& reason) override final; + void on_connected() override final; + void on_connection_close(const std::string& error) override final; + void parse_in_buffer(const size_t size) override final; + + /** + * Returns a unique id, to be used in the 'id' element of our iq stanzas. + */ + static std::string next_id(); + bool is_document_open() const; + /** + * Connect to the XMPP server. + */ + void start(); + /** + * Reset the component so we can use the component on a new XMPP stream + */ + void reset(); + /** + * Serialize the stanza and add it to the out_buf to be sent to the + * server. + */ + void send_stanza(const Stanza& stanza); + /** + * Handle the opening of the remote stream + */ + void on_remote_stream_open(const XmlNode& node); + /** + * Handle the closing of the remote stream + */ + void on_remote_stream_close(const XmlNode& node); + /** + * Handle received stanzas + */ + void on_stanza(const Stanza& stanza); + /** + * Send an error stanza. Message being the name of the element inside the + * stanza, and explanation being a short human-readable sentence + * describing the error. + */ + void send_stream_error(const std::string& message, const std::string& explanation); + /** + * Send error stanza, described in http://xmpp.org/rfcs/rfc6120.html#stanzas-error + */ + void send_stanza_error(const std::string& kind, const std::string& to, const std::string& from, + const std::string& id, const std::string& error_type, + const std::string& defined_condition, const std::string& text, + const bool fulljid=true); + /** + * Send the closing signal for our document (not closing the connection though). + */ + void close_document(); + /** + * Send a message from from@served_hostname, with the given body + * + * If fulljid is false, the provided 'from' doesn't contain the + * server-part of the JID and must be added. + */ + void send_message(const std::string& from, Xmpp::body&& body, + const std::string& to, const std::string& type, + const bool fulljid=false); + /** + * Send a join from a new participant + */ + void send_user_join(const std::string& from, + const std::string& nick, + const std::string& realjid, + const std::string& affiliation, + const std::string& role, + const std::string& to, + const bool self); + /** + * Send an error to indicate that the user tried to join an invalid room + */ + void send_invalid_room_error(const std::string& muc_jid, + const std::string& nick, + const std::string& to); + /** + * Send an error to indicate that the user tried to send a message to an + * invalid user. + */ + void send_invalid_user_error(const std::string& user_name, + const std::string& to); + /** + * Send the MUC topic to the user + */ + void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to); + /** + * Send a (non-private) message to the MUC + */ + void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to); + /** + * Send an unavailable presence for this nick + */ + void send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self); + /** + * Indicate that a participant changed his nick + */ + void send_nick_change(const std::string& muc_name, + const std::string& old_nick, + const std::string& new_nick, + const std::string& affiliation, + const std::string& role, + const std::string& jid_to, + const bool self); + /** + * An user is kicked from a room + */ + void kick_user(const std::string& muc_name, + const std::string& target, + const std::string& reason, + const std::string& author, + const std::string& jid_to); + /** + * Send a generic presence error + */ + void send_presence_error(const std::string& muc_name, + const std::string& nickname, + const std::string& jid_to, + const std::string& type, + const std::string& condition, + const std::string& error_code, + const std::string& text); + /** + * Send a presence from the MUC indicating a change in the role and/or + * affiliation of a participant + */ + void send_affiliation_role_change(const std::string& muc_name, + const std::string& target, + const std::string& affiliation, + const std::string& role, + const std::string& jid_to); + /** + * Send a result IQ with the gateway disco informations. + */ + void send_self_disco_info(const std::string& id, const std::string& jid_to); + /** + * Send a result IQ with the given version, or the gateway version if the + * passed string is empty. + */ + void send_version(const std::string& id, const std::string& jid_to, const std::string& jid_from, + const std::string& version=""); + /** + * Send the list of all available ad-hoc commands to that JID. The list is + * different depending on what JID made the request. + */ + void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid); + /** + * Send an iq version request + */ + void send_iq_version_request(const std::string& from, + const std::string& jid_to); + /** + * Send an empty iq of type result + */ + void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from); + + void handle_handshake(const Stanza& stanza); + void handle_error(const Stanza& stanza); + + virtual void after_handshake() {} + + /** + * Whether or not we ever succeeded our authentication to the XMPP server + */ + bool ever_auth; + /** + * Whether or not this is the first consecutive try on connecting to the + * XMPP server. We use this to delay the connection attempt for a few + * seconds, if it is not the first try. + */ + bool first_connection_try; + +private: + /** + * Return a buffer provided by the XML parser, to read data directly into + * it, and avoiding some unnecessary copy. + */ + void* get_receive_buffer(const size_t size) const override final; + XmppParser parser; + std::string stream_id; + std::string secret; + bool authenticated; + /** + * Whether or not OUR XMPP document is open + */ + bool doc_open; +protected: + std::string served_hostname; + + std::unordered_map> stanza_handlers; + AdhocCommandsHandler adhoc_commands_handler; + + XmppComponent(const XmppComponent&) = delete; + XmppComponent(XmppComponent&&) = delete; + XmppComponent& operator=(const XmppComponent&) = delete; + XmppComponent& operator=(XmppComponent&&) = delete; +}; + +#endif // XMPP_COMPONENT_INCLUDED diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp new file mode 100644 index 0000000..6bb0d28 --- /dev/null +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -0,0 +1,169 @@ +#include +#include + +#include + +/** + * Expat handlers. Called by the Expat library, never by ourself. + * They just forward the call to the XmppParser corresponding methods. + */ + +static void start_element_handler(void* user_data, const XML_Char* name, const XML_Char** atts) +{ + static_cast(user_data)->start_element(name, atts); +} + +static void end_element_handler(void* user_data, const XML_Char* name) +{ + static_cast(user_data)->end_element(name); +} + +static void character_data_handler(void *user_data, const XML_Char *s, int len) +{ + static_cast(user_data)->char_data(s, len); +} + +/** + * XmppParser class + */ + +XmppParser::XmppParser(): + level(0), + current_node(nullptr) +{ + this->init_xml_parser(); +} + +void XmppParser::init_xml_parser() +{ + // Create the expat parser + this->parser = XML_ParserCreateNS("UTF-8", ':'); + XML_SetUserData(this->parser, static_cast(this)); + + // Install Expat handlers + XML_SetElementHandler(this->parser, &start_element_handler, &end_element_handler); + XML_SetCharacterDataHandler(this->parser, &character_data_handler); +} + +XmppParser::~XmppParser() +{ + if (this->current_node) + delete this->current_node; + XML_ParserFree(this->parser); +} + +int XmppParser::feed(const char* data, const int len, const bool is_final) +{ + int res = XML_Parse(this->parser, data, len, is_final); + if (res == XML_STATUS_ERROR && + (XML_GetErrorCode(this->parser) != XML_ERROR_FINISHED)) + log_error("Xml_Parse encountered an error: " << + XML_ErrorString(XML_GetErrorCode(this->parser))) + return res; +} + +int XmppParser::parse(const int len, const bool is_final) +{ + int res = XML_ParseBuffer(this->parser, len, is_final); + if (res == XML_STATUS_ERROR) + log_error("Xml_Parsebuffer encountered an error: " << + XML_ErrorString(XML_GetErrorCode(this->parser))); + return res; +} + +void XmppParser::reset() +{ + XML_ParserFree(this->parser); + this->init_xml_parser(); + if (this->current_node) + delete this->current_node; + this->current_node = nullptr; + this->level = 0; +} + +void* XmppParser::get_buffer(const size_t size) const +{ + return XML_GetBuffer(this->parser, static_cast(size)); +} + +void XmppParser::start_element(const XML_Char* name, const XML_Char** attribute) +{ + level++; + + XmlNode* new_node = new XmlNode(name, this->current_node); + if (this->current_node) + this->current_node->add_child(new_node); + this->current_node = new_node; + for (size_t i = 0; attribute[i]; i += 2) + this->current_node->set_attribute(attribute[i], attribute[i+1]); + if (this->level == 1) + this->stream_open_event(*this->current_node); +} + +void XmppParser::end_element(const XML_Char* name) +{ + (void)name; + level--; + this->current_node->close(); + if (level == 1) + { + this->stanza_event(*this->current_node); + } + if (level == 0) + { + this->stream_close_event(*this->current_node); + delete this->current_node; + this->current_node = nullptr; + } + else + this->current_node = this->current_node->get_parent(); + if (level == 1) + this->current_node->delete_all_children(); +} + +void XmppParser::char_data(const XML_Char* data, int len) +{ + if (this->current_node->has_children()) + this->current_node->get_last_child()->add_to_tail(std::string(data, len)); + else + this->current_node->add_to_inner(std::string(data, len)); +} + +void XmppParser::stanza_event(const Stanza& stanza) const +{ + for (const auto& callback: this->stanza_callbacks) + { + try { + callback(stanza); + } catch (const std::exception& e) { + log_debug("Unhandled exception: " << e.what()); + } + } +} + +void XmppParser::stream_open_event(const XmlNode& node) const +{ + for (const auto& callback: this->stream_open_callbacks) + callback(node); +} + +void XmppParser::stream_close_event(const XmlNode& node) const +{ + for (const auto& callback: this->stream_close_callbacks) + callback(node); +} + +void XmppParser::add_stanza_callback(std::function&& callback) +{ + this->stanza_callbacks.emplace_back(std::move(callback)); +} + +void XmppParser::add_stream_open_callback(std::function&& callback) +{ + this->stream_open_callbacks.emplace_back(std::move(callback)); +} + +void XmppParser::add_stream_close_callback(std::function&& callback) +{ + this->stream_close_callbacks.emplace_back(std::move(callback)); +} diff --git a/louloulibs/xmpp/xmpp_parser.hpp b/louloulibs/xmpp/xmpp_parser.hpp new file mode 100644 index 0000000..79c9f8f --- /dev/null +++ b/louloulibs/xmpp/xmpp_parser.hpp @@ -0,0 +1,126 @@ +#ifndef XMPP_PARSER_INCLUDED +# define XMPP_PARSER_INCLUDED + +#include + +#include + +#include + +/** + * A SAX XML parser that builds XML nodes and spawns events when a complete + * stanza is received (an element of level 2), or when the document is + * opened/closed (an element of level 1) + * + * After a stanza_event has been spawned, we delete the whole stanza. This + * means that even with a very long document (in XMPP the document is + * potentially infinite), the memory is never exhausted as long as each + * stanza is reasonnably short. + * + * The element names generated by expat contain the namespace of the + * element, a colon (':') and then the actual name of the element. To get + * an element "x" with a namespace of "http://jabber.org/protocol/muc", you + * just look for an XmlNode named "http://jabber.org/protocol/muc:x" + * + * TODO: enforce the size-limit for the stanza (limit the number of childs + * it can contain). For example forbid the parser going further than level + * 20 (arbitrary number here), and each XML node to have more than 15 childs + * (arbitrary number again). + */ +class XmppParser +{ +public: + explicit XmppParser(); + ~XmppParser(); + +public: + /** + * Init the XML parser and install the callbacks + */ + void init_xml_parser(); + /** + * Feed the parser with some XML data + */ + int feed(const char* data, const int len, const bool is_final); + /** + * Parse the data placed in the parser buffer + */ + int parse(const int size, const bool is_final); + /** + * Reset the parser, so it can be used from scratch afterward + */ + void reset(); + /** + * Get a buffer provided by the xml parser. + */ + void* get_buffer(const size_t size) const; + /** + * Add one callback for the various events that this parser can spawn. + */ + void add_stanza_callback(std::function&& callback); + void add_stream_open_callback(std::function&& callback); + void add_stream_close_callback(std::function&& callback); + + /** + * Called when a new XML element has been opened. We instanciate a new + * XmlNode and set it as our current node. The parent of this new node is + * the previous "current" node. We have all the element's attributes in + * this event. + * + * We spawn a stream_event with this node if this is a level-1 element. + */ + void start_element(const XML_Char* name, const XML_Char** attribute); + /** + * Called when an XML element has been closed. We close the current_node, + * set our current_node as the parent of the current_node, and if that was + * a level-2 element we spawn a stanza_event with this node. + * + * And we then delete the stanza (and everything under it, its children, + * attribute, etc). + */ + void end_element(const XML_Char* name); + /** + * Some inner or tail data has been parsed + */ + void char_data(const XML_Char* data, int len); + /** + * Calls all the stanza_callbacks one by one. + */ + void stanza_event(const Stanza& stanza) const; + /** + * Calls all the stream_open_callbacks one by one. Note: the passed node is not + * closed yet. + */ + void stream_open_event(const XmlNode& node) const; + /** + * Calls all the stream_close_callbacks one by one. + */ + void stream_close_event(const XmlNode& node) const; + +private: + /** + * Expat structure. + */ + XML_Parser parser; + /** + * The current depth in the XML document + */ + size_t level; + /** + * The deepest XML node opened but not yet closed (to which we are adding + * new children, inner or tail) + */ + XmlNode* current_node; + /** + * A list of callbacks to be called on an *_event, receiving the + * concerned Stanza/XmlNode. + */ + std::vector> stanza_callbacks; + std::vector> stream_open_callbacks; + std::vector> stream_close_callbacks; + + XmppParser(const XmppParser&) = delete; + XmppParser& operator=(const XmppParser&) = delete; +}; + +#endif // XMPP_PARSER_INCLUDED diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp new file mode 100644 index 0000000..01d1d2e --- /dev/null +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -0,0 +1,274 @@ +#include + +#include +#include + +#include +#include + +#include + +std::string xml_escape(const std::string& data) +{ + std::string res; + res.reserve(data.size()); + for (size_t pos = 0; pos != data.size(); ++pos) + { + switch(data[pos]) + { + case '&': + res += "&"; + break; + case '<': + res += "<"; + break; + case '>': + res += ">"; + break; + case '\"': + res += """; + break; + case '\'': + res += "'"; + break; + default: + res += data[pos]; + break; + } + } + return res; +} + +std::string xml_unescape(const std::string& data) +{ + std::string res; + res.reserve(data.size()); + const char* str = data.c_str(); + while (str && *str && static_cast(str - data.c_str()) < data.size()) + { + if (*str == '&') + { + if (strncmp(str+1, "amp;", 4) == 0) + { + res += "&"; + str += 4; + } + else if (strncmp(str+1, "lt;", 3) == 0) + { + res += "<"; + str += 3; + } + else if (strncmp(str+1, "gt;", 3) == 0) + { + res += ">"; + str += 3; + } + else if (strncmp(str+1, "quot;", 5) == 0) + { + res += "\""; + str += 5; + } + else if (strncmp(str+1, "apos;", 5) == 0) + { + res += "'"; + str += 5; + } + else + res += "&"; + } + else + res += *str; + str++; + } + return res; +} + +XmlNode::XmlNode(const std::string& name, XmlNode* parent): + parent(parent), + closed(false) +{ + // split the namespace and the name + auto n = name.rfind(":"); + if (n == std::string::npos) + this->name = name; + else + { + this->name = name.substr(n+1); + this->attributes["xmlns"] = name.substr(0, n); + } +} + +XmlNode::XmlNode(const std::string& name): + XmlNode(name, nullptr) +{ +} + +XmlNode::~XmlNode() +{ + this->delete_all_children(); +} + +void XmlNode::delete_all_children() +{ + for (auto& child: this->children) + { + delete child; + } + this->children.clear(); +} + +void XmlNode::set_attribute(const std::string& name, const std::string& value) +{ + this->attributes[name] = value; +} + +void XmlNode::set_tail(const std::string& data) +{ + this->tail = data; +} + +void XmlNode::add_to_tail(const std::string& data) +{ + this->tail += data; +} + +void XmlNode::set_inner(const std::string& data) +{ + this->inner = data; +} + +void XmlNode::add_to_inner(const std::string& data) +{ + this->inner += data; +} + +std::string XmlNode::get_inner() const +{ + return this->inner; +} + +std::string XmlNode::get_tail() const +{ + return this->tail; +} + +XmlNode* XmlNode::get_child(const std::string& name, const std::string& xmlns) const +{ + for (auto& child: this->children) + { + if (child->name == name && child->get_tag("xmlns") == xmlns) + return child; + } + return nullptr; +} + +std::vector XmlNode::get_children(const std::string& name, const std::string& xmlns) const +{ + std::vector res; + for (auto& child: this->children) + { + if (child->name == name && child->get_tag("xmlns") == xmlns) + res.push_back(child); + } + return res; +} + +XmlNode* XmlNode::add_child(XmlNode* child) +{ + child->parent = this; + this->children.push_back(child); + return child; +} + +XmlNode* XmlNode::add_child(XmlNode&& child) +{ + XmlNode* new_node = new XmlNode(std::move(child)); + return this->add_child(new_node); +} + +XmlNode* XmlNode::get_last_child() const +{ + return this->children.back(); +} + +void XmlNode::close() +{ + if (this->closed) + throw std::runtime_error("Closing an already closed XmlNode"); + this->closed = true; +} + +XmlNode* XmlNode::get_parent() const +{ + return this->parent; +} + +void XmlNode::set_name(const std::string& name) +{ + this->name = name; +} + +const std::string XmlNode::get_name() const +{ + return this->name; +} + +std::string XmlNode::to_string() const +{ + std::string res("<"); + res += this->name; + for (const auto& it: this->attributes) + res += " " + it.first + "='" + sanitize(it.second) + "'"; + if (this->closed && !this->has_children() && this->inner.empty()) + res += "/>"; + else + { + res += ">" + sanitize(this->inner); + for (const auto& child: this->children) + res += child->to_string(); + if (this->closed) + { + res += "get_name() + ">"; + } + } + res += sanitize(this->tail); + return res; +} + +bool XmlNode::has_children() const +{ + return !this->children.empty(); +} + +const std::string XmlNode::get_tag(const std::string& name) const +{ + try + { + const auto& value = this->attributes.at(name); + return value; + } + catch (const std::out_of_range& e) + { + return ""; + } +} + +bool XmlNode::del_tag(const std::string& name) +{ + if (this->attributes.erase(name) != 0) + return true; + return false; +} + +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/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp new file mode 100644 index 0000000..f1a6a0f --- /dev/null +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -0,0 +1,160 @@ +#ifndef XMPP_STANZA_INCLUDED +# define XMPP_STANZA_INCLUDED + +#include +#include +#include + +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 + * - A parent XML node (in the case of the first-level nodes, the parent is + nullptr) + * - zero, one or more children XML nodes + * - A name + * - A map of attributes + * - inner data (text inside the node) + * - tail data (text just after the node) + */ +class XmlNode +{ +public: + explicit XmlNode(const std::string& name, XmlNode* parent); + explicit XmlNode(const std::string& name); + XmlNode(XmlNode&& node): + name(std::move(node.name)), + parent(node.parent), + closed(node.closed), + attributes(std::move(node.attributes)), + children(std::move(node.children)), + inner(std::move(node.inner)), + tail(std::move(node.tail)) + { + node.parent = nullptr; + } + /** + * The copy constructor do not copy the parent attribute. The children + * nodes are all copied recursively. + */ + XmlNode(const XmlNode& node): + name(node.name), + parent(nullptr), + closed(node.closed), + attributes(node.attributes), + children{}, + inner(node.inner), + tail(node.tail) + { + for (XmlNode* child: node.children) + { + XmlNode* child_copy = new XmlNode(*child); + this->add_child(child_copy); + } + } + + ~XmlNode(); + + void delete_all_children(); + void set_attribute(const std::string& name, const std::string& value); + /** + * Set the content of the tail, that is the text just after this node + */ + void set_tail(const std::string& data); + /** + * Append the given data to the content of the tail. This exists because + * the expat library may provide the complete text of an element in more + * than one call + */ + void add_to_tail(const std::string& data); + /** + * Set the content of the inner, that is the text inside this node. + */ + void set_inner(const std::string& data); + /** + * Append the given data to the content of the inner. For the reason + * described in add_to_tail comment. + */ + void add_to_inner(const std::string& data); + /** + * Get the content of inner + */ + std::string get_inner() const; + /** + * Get the content of the tail + */ + std::string get_tail() const; + /** + * Get a pointer to the first child element with that name and that xml namespace + */ + XmlNode* get_child(const std::string& name, const std::string& xmlns) const; + /** + * Get a vector of all the children that have that name and that xml namespace. + */ + std::vector get_children(const std::string& name, const std::string& xmlns) const; + /** + * Add a node child to this node. Assign this node to the child’s parent. + * Returns a pointer to the newly added child. + */ + XmlNode* add_child(XmlNode* child); + XmlNode* add_child(XmlNode&& child); + /** + * Returns the last of the children. If the node doesn't have any child, + * the behaviour is undefined. The user should make sure this is the case + * by calling has_children() for example. + */ + XmlNode* get_last_child() const; + /** + * Mark this node as closed, nothing else + */ + void close(); + XmlNode* get_parent() const; + void set_name(const std::string& name); + const std::string get_name() const; + /** + * Serialize the stanza into a string + */ + std::string to_string() const; + /** + * Whether or not this node has at least one child (if not, this is a leaf + * node) + */ + bool has_children() const; + /** + * Gets the value for the given attribute, returns an empty string if the + * node as no such attribute. + */ + const std::string get_tag(const std::string& name) const; + /** + * Remove the attribute of the node. Does nothing if that attribute is not + * present. Returns true if the tag was removed, false if it was absent. + */ + bool del_tag(const std::string& name); + /** + * Use this to set an attribute's value, like node["id"] = "12"; + */ + std::string& operator[](const std::string& name); + +private: + std::string name; + XmlNode* parent; + bool closed; + std::unordered_map attributes; + std::vector children; + std::string inner; + std::string tail; + + XmlNode& operator=(const XmlNode&) = delete; + XmlNode& operator=(XmlNode&&) = delete; +}; + +/** + * An XMPP stanza is just an XML node of level 2 in the XMPP document (the + * level 1 ones are the , and the ones above 2 are just the + * content of the stanzas) + */ +typedef XmlNode Stanza; + +#endif // XMPP_STANZA_INCLUDED -- cgit v1.2.3 From 7f7c429ae4c49e856a43816138991135ffb7f840 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 9 Jun 2015 14:52:46 +0200 Subject: Do not send the admin-only adhoc commands to non-admin users They were not able to execute them anyway, so this was just a little usability issue. --- louloulibs/xmpp/xmpp_component.cpp | 4 +++- louloulibs/xmpp/xmpp_component.hpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 1048f86..8e89208 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -651,7 +651,7 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t this->send_stanza(iq); } -void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid) +void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const bool with_admin_only) { Stanza iq("iq"); iq["type"] = "result"; @@ -663,6 +663,8 @@ void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::s query["node"] = ADHOC_NS; for (const auto& kv: this->adhoc_commands_handler.get_commands()) { + if (kv.second.is_admin_only() && !with_admin_only) + continue; XmlNode item("item"); item["jid"] = this->served_hostname; item["node"] = kv.first; diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index 1bea54e..e45bb36 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -184,7 +184,8 @@ public: * Send the list of all available ad-hoc commands to that JID. The list is * different depending on what JID made the request. */ - void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid); + void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, + const bool with_admin_only); /** * Send an iq version request */ -- cgit v1.2.3 From a42af9e700bcf54777b53b5d0ca999b3b0c107e9 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 9 Jul 2015 13:49:08 +0200 Subject: Fix the log_* macros to not have two ; at the end of lines --- louloulibs/xmpp/xmpp_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index 6bb0d28..fbe525a 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -58,7 +58,7 @@ int XmppParser::feed(const char* data, const int len, const bool is_final) if (res == XML_STATUS_ERROR && (XML_GetErrorCode(this->parser) != XML_ERROR_FINISHED)) log_error("Xml_Parse encountered an error: " << - XML_ErrorString(XML_GetErrorCode(this->parser))) + XML_ErrorString(XML_GetErrorCode(this->parser))); return res; } -- cgit v1.2.3 From e8f22efe34415db0e1e5cb94635b089b18efe055 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 04:42:12 +0200 Subject: XmlNodes are now always closed Remove the close() method and closed attribute. Remove all the calls to close(). (Save one bool per XmlNode, yay, and save a few ifs and some useless function calls. At best it should be unnoticeably faster and lighter and save a few keystrokes in the future) --- louloulibs/xmpp/adhoc_command.cpp | 10 ---- louloulibs/xmpp/adhoc_commands_handler.cpp | 10 ---- louloulibs/xmpp/xmpp_component.cpp | 78 +++--------------------------- louloulibs/xmpp/xmpp_parser.cpp | 1 - louloulibs/xmpp/xmpp_stanza.cpp | 17 ++----- louloulibs/xmpp/xmpp_stanza.hpp | 7 --- 6 files changed, 9 insertions(+), 114 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index 24145f5..c17f1d9 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -25,7 +25,6 @@ void PingStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) XmlNode note("note"); note["type"] = "info"; note.set_inner("Pong"); - note.close(); command_node.add_child(std::move(note)); } @@ -35,22 +34,17 @@ void HelloStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) x["type"] = "form"; XmlNode title("title"); title.set_inner("Configure your name."); - title.close(); x.add_child(std::move(title)); XmlNode instructions("instructions"); instructions.set_inner("Please provide your name."); - instructions.close(); x.add_child(std::move(instructions)); XmlNode name_field("field"); name_field["var"] = "name"; name_field["type"] = "text-single"; name_field["label"] = "Your name"; XmlNode required("required"); - required.close(); name_field.add_child(std::move(required)); - name_field.close(); x.add_child(std::move(name_field)); - x.close(); command_node.add_child(std::move(x)); } @@ -75,7 +69,6 @@ void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) XmlNode note("note"); note["type"] = "info"; note.set_inner("Hello "s + value->get_inner() + "!"s); - note.close(); command_node.delete_all_children(); command_node.add_child(std::move(note)); return; @@ -86,9 +79,7 @@ void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) XmlNode error(ADHOC_NS":error"); error["type"] = "modify"; XmlNode condition(STANZA_NS":bad-request"); - condition.close(); error.add_child(std::move(condition)); - error.close(); command_node.add_child(std::move(error)); session.terminate(); } @@ -100,6 +91,5 @@ void Reload(XmppComponent*, AdhocSession&, XmlNode& command_node) XmlNode note("note"); note["type"] = "info"; note.set_inner("Configuration reloaded."); - note.close(); command_node.add_child(std::move(note)); } diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 46c8a32..458a22c 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -36,9 +36,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, Xm XmlNode error(ADHOC_NS":error"); error["type"] = "cancel"; XmlNode condition(STANZA_NS":item-not-found"); - condition.close(); error.add_child(std::move(condition)); - error.close(); command_node.add_child(std::move(error)); } else if (command_it->second.is_admin_only() && @@ -47,9 +45,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, Xm XmlNode error(ADHOC_NS":error"); error["type"] = "cancel"; XmlNode condition(STANZA_NS":forbidden"); - condition.close(); error.add_child(std::move(condition)); - error.close(); command_node.add_child(std::move(error)); } else @@ -72,9 +68,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, Xm XmlNode error(ADHOC_NS":error"); error["type"] = "modify"; XmlNode condition(STANZA_NS":bad-request"); - condition.close(); error.add_child(std::move(condition)); - error.close(); command_node.add_child(std::move(error)); } else if (action == "execute" || action == "next" || action == "complete") @@ -95,9 +89,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, Xm command_node["status"] = "executing"; XmlNode actions("actions"); XmlNode next("next"); - next.close(); actions.add_child(std::move(next)); - actions.close(); command_node.add_child(std::move(actions)); } } @@ -112,9 +104,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, Xm XmlNode error(ADHOC_NS":error"); error["type"] = "modify"; XmlNode condition(STANZA_NS":bad-request"); - condition.close(); error.add_child(std::move(condition)); - error.close(); command_node.add_child(std::move(error)); } } diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 8e89208..19111ba 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -89,12 +89,9 @@ void XmppComponent::on_connected() { log_info("connected to XMPP server"); this->first_connection_try = true; - XmlNode node("", nullptr); - node.set_name("stream:stream"); - node["xmlns"] = COMPONENT_NS; - node["xmlns:stream"] = STREAM_NS; - node["to"] = this->served_hostname; - this->send_stanza(node); + this->send_data(""); this->doc_open = true; // We may have some pending data to send: this happens when we try to send // some data before we are actually connected. We send that data right now, if any @@ -152,10 +149,9 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node) sprintf(digest + (i*2), "%02x", result[i]); digest[HASH_LENGTH * 2] = '\0'; - Stanza handshake(COMPONENT_NS":handshake"); - handshake.set_inner(digest); - handshake.close(); - this->send_stanza(handshake); + this->send_data(""); + this->send_data(digest); + this->send_data(""); } void XmppComponent::on_remote_stream_close(const XmlNode& node) @@ -192,9 +188,7 @@ void XmppComponent::send_stream_error(const std::string& name, const std::string error["xmlns"] = STREAM_NS; if (!explanation.empty()) error.set_inner(explanation); - error.close(); node.add_child(std::move(error)); - node.close(); this->send_stanza(node); } @@ -220,19 +214,15 @@ void XmppComponent::send_stanza_error(const std::string& kind, const std::string error["type"] = error_type; XmlNode inner_error(defined_condition); inner_error["xmlns"] = STANZA_NS; - inner_error.close(); error.add_child(std::move(inner_error)); if (!text.empty()) { XmlNode text_node("text"); text_node["xmlns"] = STANZA_NS; text_node.set_inner(text); - text_node.close(); error.add_child(std::move(text_node)); } - error.close(); node.add_child(std::move(error)); - node.close(); this->send_stanza(node); } @@ -295,7 +285,6 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con node["type"] = type; XmlNode body_node("body"); body_node.set_inner(std::get<0>(body)); - body_node.close(); node.add_child(std::move(body_node)); if (std::get<1>(body)) { @@ -303,10 +292,8 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con html["xmlns"] = XHTMLIM_NS; // Pass the ownership of the pointer to this xmlnode html.add_child(std::get<1>(body).release()); - html.close(); node.add_child(std::move(html)); } - node.close(); this->send_stanza(node); } @@ -336,19 +323,15 @@ void XmppComponent::send_user_join(const std::string& from, if (!preped_jid.empty()) item["jid"] = preped_jid; } - item.close(); x.add_child(std::move(item)); if (self) { XmlNode status("status"); status["code"] = "110"; - status.close(); x.add_child(std::move(status)); } - x.close(); node.add_child(std::move(x)); - node.close(); this->send_stanza(node); } @@ -365,14 +348,12 @@ void XmppComponent::send_invalid_room_error(const std::string& muc_name, presence["type"] = "error"; XmlNode x("x"); x["xmlns"] = MUC_NS; - x.close(); presence.add_child(std::move(x)); XmlNode error("error"); error["by"] = muc_name + "@" + this->served_hostname; error["type"] = "cancel"; XmlNode item_not_found("item-not-found"); item_not_found["xmlns"] = STANZA_NS; - item_not_found.close(); error.add_child(std::move(item_not_found)); XmlNode text("text"); text["xmlns"] = STANZA_NS; @@ -380,11 +361,8 @@ void XmppComponent::send_invalid_room_error(const std::string& muc_name, text.set_inner(muc_name + " is not a valid IRC channel name. A correct room jid is of the form: #%@" + this->served_hostname); - text.close(); error.add_child(std::move(text)); - error.close(); presence.add_child(std::move(error)); - presence.close(); this->send_stanza(presence); } @@ -396,13 +374,11 @@ void XmppComponent::send_invalid_user_error(const std::string& user_name, const message["type"] = "error"; XmlNode x("x"); x["xmlns"] = MUC_NS; - x.close(); message.add_child(std::move(x)); XmlNode error("error"); error["type"] = "cancel"; XmlNode item_not_found("item-not-found"); item_not_found["xmlns"] = STANZA_NS; - item_not_found.close(); error.add_child(std::move(item_not_found)); XmlNode text("text"); text["xmlns"] = STANZA_NS; @@ -410,11 +386,8 @@ void XmppComponent::send_invalid_user_error(const std::string& user_name, const text.set_inner(user_name + " is not a valid IRC user name. A correct user jid is of the form: !@" + this->served_hostname); - text.close(); error.add_child(std::move(text)); - error.close(); message.add_child(std::move(error)); - message.close(); this->send_stanza(message); } @@ -426,9 +399,7 @@ void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, cons message["type"] = "groupchat"; XmlNode subject("subject"); subject.set_inner(std::get<0>(topic)); - subject.close(); message.add_child(std::move(subject)); - message.close(); this->send_stanza(message); } @@ -443,7 +414,6 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str message["type"] = "groupchat"; XmlNode body("body"); body.set_inner(std::get<0>(xmpp_body)); - body.close(); message.add_child(std::move(body)); if (std::get<1>(xmpp_body)) { @@ -451,10 +421,8 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str html["xmlns"] = XHTMLIM_NS; // Pass the ownership of the pointer to this xmlnode html.add_child(std::get<1>(xmpp_body).release()); - html.close(); message.add_child(std::move(html)); } - message.close(); this->send_stanza(message); } @@ -471,19 +439,15 @@ void XmppComponent::send_muc_leave(const std::string& muc_name, std::string&& ni { XmlNode status("status"); status["code"] = "110"; - status.close(); x.add_child(std::move(status)); } - x.close(); presence.add_child(std::move(x)); if (!message_str.empty()) { XmlNode status("status"); status.set_inner(message_str); - status.close(); presence.add_child(std::move(status)); } - presence.close(); this->send_stanza(presence); } @@ -503,22 +467,17 @@ void XmppComponent::send_nick_change(const std::string& muc_name, x["xmlns"] = MUC_USER_NS; XmlNode item("item"); item["nick"] = new_nick; - item.close(); x.add_child(std::move(item)); XmlNode status("status"); status["code"] = "303"; - status.close(); x.add_child(std::move(status)); if (self) { XmlNode status2("status"); status2["code"] = "110"; - status2.close(); x.add_child(std::move(status2)); } - x.close(); presence.add_child(std::move(x)); - presence.close(); this->send_stanza(presence); this->send_user_join(muc_name, new_nick, "", affiliation, role, jid_to, self); @@ -542,21 +501,15 @@ void XmppComponent::kick_user(const std::string& muc_name, XmlNode actor("actor"); actor["nick"] = author; actor["jid"] = author; // backward compatibility with old clients - actor.close(); item.add_child(std::move(actor)); XmlNode reason("reason"); reason.set_inner(txt); - reason.close(); item.add_child(std::move(reason)); - item.close(); x.add_child(std::move(item)); XmlNode status("status"); status["code"] = "307"; - status.close(); x.add_child(std::move(status)); - x.close(); presence.add_child(std::move(x)); - presence.close(); this->send_stanza(presence); } @@ -574,7 +527,6 @@ void XmppComponent::send_presence_error(const std::string& muc_name, presence["type"] = "error"; XmlNode x("x"); x["xmlns"] = MUC_NS; - x.close(); presence.add_child(std::move(x)); XmlNode error("error"); error["by"] = muc_name + "@" + this->served_hostname; @@ -583,11 +535,8 @@ void XmppComponent::send_presence_error(const std::string& muc_name, error["code"] = error_code; XmlNode subnode(condition); subnode["xmlns"] = STANZA_NS; - subnode.close(); error.add_child(std::move(subnode)); - error.close(); presence.add_child(std::move(error)); - presence.close(); this->send_stanza(presence); } @@ -605,11 +554,8 @@ void XmppComponent::send_affiliation_role_change(const std::string& muc_name, XmlNode item("item"); item["affiliation"] = affiliation; item["role"] = role; - item.close(); x.add_child(std::move(item)); - x.close(); presence.add_child(std::move(x)); - presence.close(); this->send_stanza(presence); } @@ -627,27 +573,21 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t { XmlNode name("name"); name.set_inner("biboumi"); - name.close(); query.add_child(std::move(name)); XmlNode version("version"); version.set_inner(SOFTWARE_VERSION); - version.close(); query.add_child(std::move(version)); XmlNode os("os"); os.set_inner(SYSTEM_NAME); - os.close(); query.add_child(std::move(os)); } else { XmlNode name("name"); name.set_inner(version); - name.close(); query.add_child(std::move(name)); } - query.close(); iq.add_child(std::move(query)); - iq.close(); this->send_stanza(iq); } @@ -669,12 +609,9 @@ void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::s item["jid"] = this->served_hostname; item["node"] = kv.first; item["name"] = kv.second.name; - item.close(); query.add_child(std::move(item)); } - query.close(); iq.add_child(std::move(query)); - iq.close(); this->send_stanza(iq); } @@ -688,9 +625,7 @@ void XmppComponent::send_iq_version_request(const std::string& from, iq["to"] = jid_to; XmlNode query("query"); query["xmlns"] = VERSION_NS; - query.close(); iq.add_child(std::move(query)); - iq.close(); this->send_stanza(iq); } @@ -704,7 +639,6 @@ void XmppComponent::send_iq_result(const std::string& id, const std::string& to_ iq["to"] = to_jid; iq["id"] = id; iq["type"] = "result"; - iq.close(); this->send_stanza(iq); } diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index fbe525a..3903b73 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -104,7 +104,6 @@ void XmppParser::end_element(const XML_Char* name) { (void)name; level--; - this->current_node->close(); if (level == 1) { this->stanza_event(*this->current_node); diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index 01d1d2e..c66b4be 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -84,8 +84,7 @@ std::string xml_unescape(const std::string& data) } XmlNode::XmlNode(const std::string& name, XmlNode* parent): - parent(parent), - closed(false) + parent(parent) { // split the namespace and the name auto n = name.rfind(":"); @@ -191,13 +190,6 @@ XmlNode* XmlNode::get_last_child() const return this->children.back(); } -void XmlNode::close() -{ - if (this->closed) - throw std::runtime_error("Closing an already closed XmlNode"); - this->closed = true; -} - XmlNode* XmlNode::get_parent() const { return this->parent; @@ -219,17 +211,14 @@ std::string XmlNode::to_string() const res += this->name; for (const auto& it: this->attributes) res += " " + it.first + "='" + sanitize(it.second) + "'"; - if (this->closed && !this->has_children() && this->inner.empty()) + if (!this->has_children() && this->inner.empty()) res += "/>"; else { res += ">" + sanitize(this->inner); for (const auto& child: this->children) res += child->to_string(); - if (this->closed) - { - res += "get_name() + ">"; - } + res += "get_name() + ">"; } res += sanitize(this->tail); return res; diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index f1a6a0f..3d5b0c5 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -27,7 +27,6 @@ public: XmlNode(XmlNode&& node): name(std::move(node.name)), parent(node.parent), - closed(node.closed), attributes(std::move(node.attributes)), children(std::move(node.children)), inner(std::move(node.inner)), @@ -42,7 +41,6 @@ public: XmlNode(const XmlNode& node): name(node.name), parent(nullptr), - closed(node.closed), attributes(node.attributes), children{}, inner(node.inner), @@ -106,10 +104,6 @@ public: * by calling has_children() for example. */ XmlNode* get_last_child() const; - /** - * Mark this node as closed, nothing else - */ - void close(); XmlNode* get_parent() const; void set_name(const std::string& name); const std::string get_name() const; @@ -140,7 +134,6 @@ public: private: std::string name; XmlNode* parent; - bool closed; std::unordered_map attributes; std::vector children; std::string inner; -- cgit v1.2.3 From d7e1214cbcff2d34f45687eff7c083a89bf04802 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 04:53:12 +0200 Subject: XmlNode::to_string uses an ostringstream instead of a string On my poor benchmark, it was infinitesimally faster. --- louloulibs/xmpp/xmpp_stanza.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index c66b4be..aec91a7 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -5,6 +5,7 @@ #include #include +#include #include @@ -207,21 +208,21 @@ const std::string XmlNode::get_name() const std::string XmlNode::to_string() const { - std::string res("<"); - res += this->name; + std::ostringstream res; + res << "<" << this->name; for (const auto& it: this->attributes) - res += " " + it.first + "='" + sanitize(it.second) + "'"; + res << " " << it.first << "='" << sanitize(it.second) + "'"; if (!this->has_children() && this->inner.empty()) - res += "/>"; + res << "/>"; else { - res += ">" + sanitize(this->inner); + res << ">" + sanitize(this->inner); for (const auto& child: this->children) - res += child->to_string(); - res += "get_name() + ">"; + res << child->to_string(); + res << "get_name() << ">"; } - res += sanitize(this->tail); - return res; + res << sanitize(this->tail); + return res.str(); } bool XmlNode::has_children() const -- cgit v1.2.3 From 38564d77c7679dd4de4562d321146322b6211d61 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 04:56:06 +0200 Subject: Little cleanup of the XmlNode class Use map instead of unordered map (it's not slower, and it's shorter). Use the default move constructor. --- louloulibs/xmpp/xmpp_stanza.hpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 3d5b0c5..ee6b25b 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -1,7 +1,7 @@ #ifndef XMPP_STANZA_INCLUDED # define XMPP_STANZA_INCLUDED -#include +#include #include #include @@ -24,18 +24,9 @@ class XmlNode public: explicit XmlNode(const std::string& name, XmlNode* parent); explicit XmlNode(const std::string& name); - XmlNode(XmlNode&& node): - name(std::move(node.name)), - parent(node.parent), - attributes(std::move(node.attributes)), - children(std::move(node.children)), - inner(std::move(node.inner)), - tail(std::move(node.tail)) - { - node.parent = nullptr; - } + XmlNode(XmlNode&& node) = default; /** - * The copy constructor do not copy the parent attribute. The children + * The copy constructor does not copy the parent attribute. The children * nodes are all copied recursively. */ XmlNode(const XmlNode& node): @@ -134,7 +125,7 @@ public: private: std::string name; XmlNode* parent; - std::unordered_map attributes; + std::map attributes; std::vector children; std::string inner; std::string tail; -- cgit v1.2.3 From f3b3d937ae274d0eec4a737d11ba19a7f4ceef03 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 14:47:57 +0200 Subject: =?UTF-8?q?Use=20unique=5Fptr=20to=20store=20the=20XmlNode?= =?UTF-8?q?=E2=80=99s=20children?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also fix some constness things --- louloulibs/xmpp/adhoc_command.cpp | 8 ++++---- louloulibs/xmpp/xmpp_component.cpp | 6 +++--- louloulibs/xmpp/xmpp_parser.cpp | 19 ++++++++++--------- louloulibs/xmpp/xmpp_parser.hpp | 5 +++++ louloulibs/xmpp/xmpp_stanza.cpp | 36 ++++++++++++++---------------------- louloulibs/xmpp/xmpp_stanza.hpp | 18 ++++++++---------- 6 files changed, 44 insertions(+), 48 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index c17f1d9..b8b07c6 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -51,11 +51,11 @@ void HelloStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) { // Find out if the name was provided in the form. - XmlNode* x = command_node.get_child("x", "jabber:x:data"); + const XmlNode* x = command_node.get_child("x", "jabber:x:data"); if (x) { - XmlNode* name_field = nullptr; - for (XmlNode* field: x->get_children("field", "jabber:x:data")) + const XmlNode* name_field = nullptr; + for (const XmlNode* field: x->get_children("field", "jabber:x:data")) if (field->get_tag("var") == "name") { name_field = field; @@ -63,7 +63,7 @@ void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) } if (name_field) { - XmlNode* value = name_field->get_child("value", "jabber:x:data"); + const XmlNode* value = name_field->get_child("value", "jabber:x:data"); if (value) { XmlNode note("note"); diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 19111ba..8cd722d 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -256,7 +256,7 @@ void XmppComponent::handle_handshake(const Stanza& stanza) void XmppComponent::handle_error(const Stanza& stanza) { - XmlNode* text = stanza.get_child("text", STREAMS_NS); + const XmlNode* text = stanza.get_child("text", STREAMS_NS); std::string error_message("Unspecified error"); if (text) error_message = text->get_inner(); @@ -291,7 +291,7 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con XmlNode html("html"); html["xmlns"] = XHTMLIM_NS; // Pass the ownership of the pointer to this xmlnode - html.add_child(std::get<1>(body).release()); + html.add_child(std::move(std::get<1>(body))); node.add_child(std::move(html)); } this->send_stanza(node); @@ -420,7 +420,7 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str XmlNode html("html"); html["xmlns"] = XHTMLIM_NS; // Pass the ownership of the pointer to this xmlnode - html.add_child(std::get<1>(xmpp_body).release()); + html.add_child(std::move(std::get<1>(xmpp_body))); message.add_child(std::move(html)); } this->send_stanza(message); diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index 3903b73..c1fd63a 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -29,7 +29,8 @@ static void character_data_handler(void *user_data, const XML_Char *s, int len) XmppParser::XmppParser(): level(0), - current_node(nullptr) + current_node(nullptr), + root(nullptr) { this->init_xml_parser(); } @@ -47,8 +48,6 @@ void XmppParser::init_xml_parser() XmppParser::~XmppParser() { - if (this->current_node) - delete this->current_node; XML_ParserFree(this->parser); } @@ -75,9 +74,8 @@ void XmppParser::reset() { XML_ParserFree(this->parser); this->init_xml_parser(); - if (this->current_node) - delete this->current_node; this->current_node = nullptr; + this->root.reset(nullptr); this->level = 0; } @@ -90,10 +88,13 @@ void XmppParser::start_element(const XML_Char* name, const XML_Char** attribute) { level++; - XmlNode* new_node = new XmlNode(name, this->current_node); + auto new_node = std::make_unique(name, this->current_node); + auto new_node_ptr = new_node.get(); if (this->current_node) - this->current_node->add_child(new_node); - this->current_node = new_node; + this->current_node->add_child(std::move(new_node)); + else + this->root = std::move(new_node); + this->current_node = new_node_ptr; for (size_t i = 0; attribute[i]; i += 2) this->current_node->set_attribute(attribute[i], attribute[i+1]); if (this->level == 1) @@ -111,8 +112,8 @@ void XmppParser::end_element(const XML_Char* name) if (level == 0) { this->stream_close_event(*this->current_node); - delete this->current_node; this->current_node = nullptr; + this->root.reset(); } else this->current_node = this->current_node->get_parent(); diff --git a/louloulibs/xmpp/xmpp_parser.hpp b/louloulibs/xmpp/xmpp_parser.hpp index 79c9f8f..4de639d 100644 --- a/louloulibs/xmpp/xmpp_parser.hpp +++ b/louloulibs/xmpp/xmpp_parser.hpp @@ -111,6 +111,11 @@ private: * new children, inner or tail) */ XmlNode* current_node; + /** + * The root node has no parent, so we keep it here: the XmppParser object + * is its owner. + */ + std::unique_ptr root; /** * A list of callbacks to be called on an *_event, receiving the * concerned Stanza/XmlNode. diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index aec91a7..3ba8483 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -103,17 +103,8 @@ XmlNode::XmlNode(const std::string& name): { } -XmlNode::~XmlNode() -{ - this->delete_all_children(); -} - void XmlNode::delete_all_children() { - for (auto& child: this->children) - { - delete child; - } this->children.clear(); } @@ -152,43 +143,44 @@ std::string XmlNode::get_tail() const return this->tail; } -XmlNode* XmlNode::get_child(const std::string& name, const std::string& xmlns) const +const XmlNode* XmlNode::get_child(const std::string& name, const std::string& xmlns) const { - for (auto& child: this->children) + for (const auto& child: this->children) { if (child->name == name && child->get_tag("xmlns") == xmlns) - return child; + return child.get(); } return nullptr; } -std::vector XmlNode::get_children(const std::string& name, const std::string& xmlns) const +std::vector XmlNode::get_children(const std::string& name, const std::string& xmlns) const { - std::vector res; - for (auto& child: this->children) + std::vector res; + for (const auto& child: this->children) { if (child->name == name && child->get_tag("xmlns") == xmlns) - res.push_back(child); + res.push_back(child.get()); } return res; } -XmlNode* XmlNode::add_child(XmlNode* child) +XmlNode* XmlNode::add_child(std::unique_ptr child) { child->parent = this; - this->children.push_back(child); - return child; + auto ret = child.get(); + this->children.push_back(std::move(child)); + return ret; } XmlNode* XmlNode::add_child(XmlNode&& child) { - XmlNode* new_node = new XmlNode(std::move(child)); - return this->add_child(new_node); + auto new_node = std::make_unique(std::move(child)); + return this->add_child(std::move(new_node)); } XmlNode* XmlNode::get_last_child() const { - return this->children.back(); + return this->children.back().get(); } XmlNode* XmlNode::get_parent() const diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index ee6b25b..4a54379 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -4,6 +4,7 @@ #include #include #include +#include std::string xml_escape(const std::string& data); std::string xml_unescape(const std::string& data); @@ -37,14 +38,11 @@ public: inner(node.inner), tail(node.tail) { - for (XmlNode* child: node.children) - { - XmlNode* child_copy = new XmlNode(*child); - this->add_child(child_copy); - } + for (const auto& child: node.children) + this->add_child(std::make_unique(*child)); } - ~XmlNode(); + ~XmlNode() = default; void delete_all_children(); void set_attribute(const std::string& name, const std::string& value); @@ -78,16 +76,16 @@ public: /** * Get a pointer to the first child element with that name and that xml namespace */ - XmlNode* get_child(const std::string& name, const std::string& xmlns) const; + const XmlNode* get_child(const std::string& name, const std::string& xmlns) const; /** * Get a vector of all the children that have that name and that xml namespace. */ - std::vector get_children(const std::string& name, const std::string& xmlns) const; + std::vector get_children(const std::string& name, const std::string& xmlns) const; /** * Add a node child to this node. Assign this node to the child’s parent. * Returns a pointer to the newly added child. */ - XmlNode* add_child(XmlNode* child); + XmlNode* add_child(std::unique_ptr child); XmlNode* add_child(XmlNode&& child); /** * Returns the last of the children. If the node doesn't have any child, @@ -126,7 +124,7 @@ private: std::string name; XmlNode* parent; std::map attributes; - std::vector children; + std::vector> children; std::string inner; std::string tail; -- cgit v1.2.3 From c3309d0acfedaed867ae1bc14cd7a65fe5be1419 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 1 Sep 2015 20:01:44 +0200 Subject: Trivial cleanup --- louloulibs/xmpp/xmpp_component.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 8cd722d..2214ecf 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -101,13 +101,9 @@ void XmppComponent::on_connected() void XmppComponent::on_connection_close(const std::string& error) { if (error.empty()) - { - log_info("XMPP server closed connection"); - } + log_info("XMPP server closed connection"); else - { - log_info("XMPP server closed connection: " << error); - } + log_info("XMPP server closed connection: " << error); } void XmppComponent::parse_in_buffer(const size_t size) -- cgit v1.2.3 From 19666d2ffd3ce36b7edd4044143fe535ef85dbd9 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 18 Sep 2015 21:52:11 +0200 Subject: Store the target jid in the AdhocSession objects --- louloulibs/xmpp/adhoc_commands_handler.cpp | 4 ++-- louloulibs/xmpp/adhoc_commands_handler.hpp | 2 +- louloulibs/xmpp/adhoc_session.cpp | 6 ++++-- louloulibs/xmpp/adhoc_session.hpp | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 6 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 458a22c..714c440 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -20,7 +20,7 @@ std::map& AdhocCommandsHandler::get_comma return this->commands; } -XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, XmlNode command_node) +XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node) { std::string action = command_node.get_tag("action"); if (action.empty()) @@ -57,7 +57,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, Xm command_node["sessionid"] = sessionid; this->sessions.emplace(std::piecewise_construct, std::forward_as_tuple(sessionid, executor_jid), - std::forward_as_tuple(command_it->second, executor_jid)); + std::forward_as_tuple(command_it->second, executor_jid, to)); TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 3600s, std::bind(&AdhocCommandsHandler::remove_session, this, sessionid, executor_jid), "adhocsession"s + sessionid + executor_jid)); diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp index 1083c44..cf9ca17 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.hpp +++ b/louloulibs/xmpp/adhoc_commands_handler.hpp @@ -41,7 +41,7 @@ public: * Takes a copy of the node so we can actually edit it and use * it as our return value. */ - XmlNode handle_request(const std::string& executor_jid, XmlNode command_node); + XmlNode handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node); /** * Remove the session from the list. This is done to avoid filling the * memory with waiting session (for example due to a client that starts diff --git a/louloulibs/xmpp/adhoc_session.cpp b/louloulibs/xmpp/adhoc_session.cpp index fc60bb7..bf8d292 100644 --- a/louloulibs/xmpp/adhoc_session.cpp +++ b/louloulibs/xmpp/adhoc_session.cpp @@ -3,9 +3,11 @@ #include -AdhocSession::AdhocSession(const AdhocCommand& command, const std::string& jid): +AdhocSession::AdhocSession(const AdhocCommand& command, const std::string& owner_jid, + const std::string& to_jid): command(command), - owner_jid(jid), + owner_jid(owner_jid), + to_jid(to_jid), current_step(0), terminated(false) { diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp index ddfb2fe..da7913f 100644 --- a/louloulibs/xmpp/adhoc_session.hpp +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -23,7 +23,8 @@ typedef std::function AdhocStep; class AdhocSession { public: - explicit AdhocSession(const AdhocCommand& command, const std::string& jid); + explicit AdhocSession(const AdhocCommand& command, const std::string& owner_jid, + const std::string& to_jid); ~AdhocSession(); /** * Return the function to be executed, found in our AdhocCommand, for the @@ -41,6 +42,15 @@ public: */ void terminate(); bool is_terminated() const; + std::string get_target_jid() const + { + return this->to_jid; + } + std::string get_owner_jid() const + { + return this->owner_jid; + } + private: /** @@ -54,6 +64,10 @@ private: * this session. */ const std::string& owner_jid; + /** + * The 'to' attribute in the request stanza. This is the target of the current session. + */ + const std::string& to_jid; /** * The current step we are at. It starts at zero. It is used to index the * associated AdhocCommand::callbacks vector. -- cgit v1.2.3 From 45e8fe56a688ec03201cdfc3dfea6ae186af682d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 18 Sep 2015 21:55:21 +0200 Subject: Add an AdhocCommandsHandler to store commands specific to IRC servers --- louloulibs/xmpp/xmpp_component.cpp | 8 ++++---- louloulibs/xmpp/xmpp_component.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 2214ecf..3017c0b 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -587,22 +587,22 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t this->send_stanza(iq); } -void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const bool with_admin_only) +void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const std::string& from_jid, const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler) { Stanza iq("iq"); iq["type"] = "result"; iq["id"] = id; iq["to"] = requester_jid; - iq["from"] = this->served_hostname; + iq["from"] = from_jid; XmlNode query("query"); query["xmlns"] = DISCO_ITEMS_NS; query["node"] = ADHOC_NS; - for (const auto& kv: this->adhoc_commands_handler.get_commands()) + for (const auto& kv: adhoc_handler.get_commands()) { if (kv.second.is_admin_only() && !with_admin_only) continue; XmlNode item("item"); - item["jid"] = this->served_hostname; + item["jid"] = from_jid; item["node"] = kv.first; item["name"] = kv.second.name; query.add_child(std::move(item)); diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index e45bb36..06236fe 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -184,8 +184,8 @@ public: * Send the list of all available ad-hoc commands to that JID. The list is * different depending on what JID made the request. */ - void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, - const bool with_admin_only); + void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const std::string& from_jid, + const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler); /** * Send an iq version request */ -- cgit v1.2.3 From 1031989fe26f219ccb4b9a602a599e30f18cb9d2 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 18 Sep 2015 21:56:23 +0200 Subject: XmlNode::add_child can also take a copy of a node --- louloulibs/xmpp/xmpp_stanza.cpp | 6 ++++++ louloulibs/xmpp/xmpp_stanza.hpp | 1 + 2 files changed, 7 insertions(+) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index 3ba8483..4c0f5c7 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -178,6 +178,12 @@ XmlNode* XmlNode::add_child(XmlNode&& child) return this->add_child(std::move(new_node)); } +XmlNode* XmlNode::add_child(const XmlNode& child) +{ + auto new_node = std::make_unique(child); + return this->add_child(std::move(new_node)); +} + XmlNode* XmlNode::get_last_child() const { return this->children.back().get(); diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 4a54379..9cf7d8d 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -87,6 +87,7 @@ public: */ XmlNode* add_child(std::unique_ptr child); XmlNode* add_child(XmlNode&& child); + XmlNode* add_child(const XmlNode& child); /** * Returns the last of the children. If the node doesn't have any child, * the behaviour is undefined. The user should make sure this is the case -- cgit v1.2.3 From 450de4c33615fc8cd14bf3a7854ee615ed53df1c Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 26 Oct 2015 20:28:36 +0100 Subject: =?UTF-8?q?Style,=20add=20a=20few=20=E2=80=9Cthis->=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louloulibs/xmpp/xmpp_parser.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index c1fd63a..f44d49a 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -86,7 +86,7 @@ void* XmppParser::get_buffer(const size_t size) const void XmppParser::start_element(const XML_Char* name, const XML_Char** attribute) { - level++; + this->level++; auto new_node = std::make_unique(name, this->current_node); auto new_node_ptr = new_node.get(); @@ -101,15 +101,14 @@ void XmppParser::start_element(const XML_Char* name, const XML_Char** attribute) this->stream_open_event(*this->current_node); } -void XmppParser::end_element(const XML_Char* name) +void XmppParser::end_element(const XML_Char*) { - (void)name; - level--; - if (level == 1) + this->level--; + if (this->level == 1) { this->stanza_event(*this->current_node); } - if (level == 0) + if (this->level == 0) { this->stream_close_event(*this->current_node); this->current_node = nullptr; @@ -117,7 +116,7 @@ void XmppParser::end_element(const XML_Char* name) } else this->current_node = this->current_node->get_parent(); - if (level == 1) + if (this->level == 1) this->current_node->delete_all_children(); } -- cgit v1.2.3 From 4e32fe213cccdc6cdc1dcba498fd74b8b97703ea Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 26 Oct 2015 20:35:10 +0100 Subject: Refactor XmppParser::end_element to make it clearer Both for me, and apparently for clang static analyzer, who reported a (imo) false positive. --- louloulibs/xmpp/xmpp_parser.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index f44d49a..25f2876 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -104,20 +104,24 @@ void XmppParser::start_element(const XML_Char* name, const XML_Char** attribute) void XmppParser::end_element(const XML_Char*) { this->level--; - if (this->level == 1) - { - this->stanza_event(*this->current_node); - } if (this->level == 0) - { + { // End of the whole stream this->stream_close_event(*this->current_node); this->current_node = nullptr; this->root.reset(); } else - this->current_node = this->current_node->get_parent(); - if (this->level == 1) - this->current_node->delete_all_children(); + { + auto parent = this->current_node->get_parent(); + if (this->level == 1) + { // End of a stanza + this->stanza_event(*this->current_node); + // Note: deleting all the children of our parent deletes ourself, + // so current_node is an invalid pointer after this line + this->current_node->get_parent()->delete_all_children(); + } + this->current_node = parent; + } } void XmppParser::char_data(const XML_Char* data, int len) -- cgit v1.2.3 From 284af79128c4bae9fa76f2dd5916ebfd81ecf718 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 3 Dec 2015 21:08:04 +0100 Subject: =?UTF-8?q?Provide=20a=20=E2=80=9Cvar=E2=80=9D=20map=20in=20AdhocS?= =?UTF-8?q?ession=20objects,=20to=20save=20values=20between=20each=20step?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louloulibs/xmpp/adhoc_session.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp index da7913f..05afc91 100644 --- a/louloulibs/xmpp/adhoc_session.hpp +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -5,6 +5,7 @@ #include #include +#include class XmppComponent; @@ -75,6 +76,15 @@ private: size_t current_step; bool terminated; +public: + /** + * A map to store various things that we may want to remember between two + * steps of the same session. A step can insert any value associated to + * any key in there. + */ + std::map vars; + +private: AdhocSession(const AdhocSession&) = delete; AdhocSession(AdhocSession&&) = delete; AdhocSession& operator=(const AdhocSession&) = delete; -- cgit v1.2.3 From 756b297045c5ec3ce051b48379a692d80398ef47 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 3 Dec 2015 21:09:03 +0100 Subject: Small cleanup --- louloulibs/xmpp/adhoc_session.cpp | 4 ---- louloulibs/xmpp/adhoc_session.hpp | 7 ++----- louloulibs/xmpp/jid.cpp | 2 -- 3 files changed, 2 insertions(+), 11 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_session.cpp b/louloulibs/xmpp/adhoc_session.cpp index bf8d292..dda4bea 100644 --- a/louloulibs/xmpp/adhoc_session.cpp +++ b/louloulibs/xmpp/adhoc_session.cpp @@ -13,10 +13,6 @@ AdhocSession::AdhocSession(const AdhocCommand& command, const std::string& owner { } -AdhocSession::~AdhocSession() -{ -} - const AdhocStep& AdhocSession::get_next_step() { assert(this->current_step < this->command.callbacks.size()); diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp index 05afc91..7f07dc1 100644 --- a/louloulibs/xmpp/adhoc_session.hpp +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -16,17 +16,15 @@ class AdhocSession; * A function executed as an ad-hoc command step. It takes a * XmlNode and modifies it accordingly (inserting for example an * node, or a data form…). - * TODO fix this: - * It also must call one of step_passed(), cancel() etc on the AdhocSession object. */ -typedef std::function AdhocStep; +using AdhocStep = std::function; class AdhocSession { public: explicit AdhocSession(const AdhocCommand& command, const std::string& owner_jid, const std::string& to_jid); - ~AdhocSession(); + ~AdhocSession() = default; /** * Return the function to be executed, found in our AdhocCommand, for the * current_step. And increment the current_step. @@ -52,7 +50,6 @@ public: return this->owner_jid; } - private: /** * A reference of the command concerned by this session. Used for example diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp index e6fee45..dcd7012 100644 --- a/louloulibs/xmpp/jid.cpp +++ b/louloulibs/xmpp/jid.cpp @@ -30,8 +30,6 @@ 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) -- cgit v1.2.3 From 700a6c7bc39aa48af5037ecbb9778b20fb6f87df Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 3 Dec 2015 21:09:26 +0100 Subject: JID class provides bare() and full() methods --- louloulibs/xmpp/jid.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/jid.hpp b/louloulibs/xmpp/jid.hpp index b6975a2..e2ee586 100644 --- a/louloulibs/xmpp/jid.hpp +++ b/louloulibs/xmpp/jid.hpp @@ -15,6 +15,15 @@ public: std::string local; std::string resource; + std::string bare() const + { + return this->local + "@" + this->domain; + } + std::string full() const + { + return this->local + "@" + this->domain + "/" + this->resource; + } + private: Jid(const Jid&) = delete; Jid(Jid&&) = delete; -- cgit v1.2.3 From 1f6eea62f46789c0d3ebe7da133ccad2e59c89c8 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Thu, 3 Dec 2015 21:14:24 +0100 Subject: Add an ad-hoc command to disconnect a user from one or more IRC server fix #3077 --- louloulibs/xmpp/xmpp_stanza.cpp | 5 +++++ louloulibs/xmpp/xmpp_stanza.hpp | 2 ++ 2 files changed, 7 insertions(+) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index 4c0f5c7..d1c2e0f 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -260,3 +260,8 @@ std::string sanitize(const std::string& data) else return xml_escape(utils::remove_invalid_xml_chars(utils::convert_to_utf8(data, "ISO-8859-1"))); } + +std::ostream& operator<<(std::ostream& os, const XmlNode& node) +{ + return os << node.to_string(); +} diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 9cf7d8d..b1ba54a 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -140,4 +140,6 @@ private: */ typedef XmlNode Stanza; +std::ostream& operator<<(std::ostream& os, const XmlNode& node); + #endif // XMPP_STANZA_INCLUDED -- cgit v1.2.3 From 8ddbe8d3e6a5a5001537379aa4f1a418c6cb6d23 Mon Sep 17 00:00:00 2001 From: Stuart Mumford Date: Fri, 11 Dec 2015 15:19:40 +0000 Subject: Make the XMPP server address configurable. fix #3145 --- louloulibs/xmpp/xmpp_component.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 3017c0b..ce9552f 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -61,7 +61,7 @@ XmppComponent::XmppComponent(std::shared_ptr poller, const std::string& void XmppComponent::start() { - this->connect("127.0.0.1", Config::get("port", "5347"), false); + this->connect(Config::get("xmpp_server_ip", "127.0.0.1"), Config::get("port", "5347"), false); } bool XmppComponent::is_document_open() const -- cgit v1.2.3 From 9714d02018904b0c207a3f4d7de0be1a6a22774b Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 21 Dec 2015 21:15:03 +0100 Subject: Also store a reference instead of a pointer, in AdhocCommandsHandler --- louloulibs/xmpp/adhoc_command.cpp | 14 ++++++-------- louloulibs/xmpp/adhoc_command.hpp | 8 ++++---- louloulibs/xmpp/adhoc_commands_handler.hpp | 7 +++---- louloulibs/xmpp/adhoc_session.hpp | 2 +- louloulibs/xmpp/xmpp_component.cpp | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index b8b07c6..8a8bcff 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -20,7 +20,7 @@ bool AdhocCommand::is_admin_only() const return this->admin_only; } -void PingStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) +void PingStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) { XmlNode note("note"); note["type"] = "info"; @@ -28,7 +28,7 @@ void PingStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) command_node.add_child(std::move(note)); } -void HelloStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) +void HelloStep1(XmppComponent&, AdhocSession&, XmlNode& command_node) { XmlNode x("jabber:x:data:x"); x["type"] = "form"; @@ -48,11 +48,10 @@ void HelloStep1(XmppComponent*, AdhocSession&, XmlNode& command_node) command_node.add_child(std::move(x)); } -void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) +void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) { // Find out if the name was provided in the form. - const XmlNode* x = command_node.get_child("x", "jabber:x:data"); - if (x) + if (const XmlNode* x = command_node.get_child("x", "jabber:x:data")) { const XmlNode* name_field = nullptr; for (const XmlNode* field: x->get_children("field", "jabber:x:data")) @@ -63,8 +62,7 @@ void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) } if (name_field) { - const XmlNode* value = name_field->get_child("value", "jabber:x:data"); - if (value) + if (const XmlNode* value = name_field->get_child("value", "jabber:x:data")) { XmlNode note("note"); note["type"] = "info"; @@ -84,7 +82,7 @@ void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node) session.terminate(); } -void Reload(XmppComponent*, AdhocSession&, XmlNode& command_node) +void Reload(XmppComponent&, AdhocSession&, XmlNode& command_node) { ::reload_process(); command_node.delete_all_children(); diff --git a/louloulibs/xmpp/adhoc_command.hpp b/louloulibs/xmpp/adhoc_command.hpp index 1ff2bcf..a2e033a 100644 --- a/louloulibs/xmpp/adhoc_command.hpp +++ b/louloulibs/xmpp/adhoc_command.hpp @@ -35,9 +35,9 @@ private: const bool admin_only; }; -void PingStep1(XmppComponent*, AdhocSession& session, XmlNode& command_node); -void HelloStep1(XmppComponent*, AdhocSession& session, XmlNode& command_node); -void HelloStep2(XmppComponent*, AdhocSession& session, XmlNode& command_node); -void Reload(XmppComponent*, AdhocSession& session, XmlNode& command_node); +void PingStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); +void HelloStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); +void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); +void Reload(XmppComponent&, AdhocSession& session, XmlNode& command_node); #endif // ADHOC_COMMAND_HPP diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp index cf9ca17..0614b2f 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.hpp +++ b/louloulibs/xmpp/adhoc_commands_handler.hpp @@ -16,7 +16,7 @@ class AdhocCommandsHandler { public: - explicit AdhocCommandsHandler(XmppComponent* xmpp_component): + explicit AdhocCommandsHandler(XmppComponent& xmpp_component): xmpp_component(xmpp_component), commands{} { } @@ -50,10 +50,9 @@ public: void remove_session(const std::string& session_id, const std::string& initiator_jid); private: /** - * A pointer to the XmppComponent, to access to basically anything in the - * gateway. + * To access basically anything in the gateway. */ - XmppComponent* xmpp_component; + XmppComponent& xmpp_component; /** * The list of all available commands. */ diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp index 7f07dc1..e98b6a8 100644 --- a/louloulibs/xmpp/adhoc_session.hpp +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -17,7 +17,7 @@ class AdhocSession; * XmlNode and modifies it accordingly (inserting for example an * node, or a data form…). */ -using AdhocStep = std::function; +using AdhocStep = std::function; class AdhocSession { diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index ce9552f..a82892d 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -45,7 +45,7 @@ XmppComponent::XmppComponent(std::shared_ptr poller, const std::string& doc_open(false), served_hostname(hostname), stanza_handlers{}, - adhoc_commands_handler(this) + adhoc_commands_handler(*this) { this->parser.add_stream_open_callback(std::bind(&XmppComponent::on_remote_stream_open, this, std::placeholders::_1)); -- cgit v1.2.3 From 9ac0d3a5766494c9c0c2074c4a21542eea195a29 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Tue, 22 Dec 2015 21:37:29 +0100 Subject: A few cleanups, and make a few things more modern --- louloulibs/xmpp/xmpp_parser.cpp | 6 +++--- louloulibs/xmpp/xmpp_parser.hpp | 2 +- louloulibs/xmpp/xmpp_stanza.cpp | 10 ++++++++-- louloulibs/xmpp/xmpp_stanza.hpp | 9 +++++---- 4 files changed, 17 insertions(+), 10 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index 25f2876..69de145 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -124,12 +124,12 @@ void XmppParser::end_element(const XML_Char*) } } -void XmppParser::char_data(const XML_Char* data, int len) +void XmppParser::char_data(const XML_Char* data, const size_t len) { if (this->current_node->has_children()) - this->current_node->get_last_child()->add_to_tail(std::string(data, len)); + this->current_node->get_last_child()->add_to_tail({data, len}); else - this->current_node->add_to_inner(std::string(data, len)); + this->current_node->add_to_inner({data, len}); } void XmppParser::stanza_event(const Stanza& stanza) const diff --git a/louloulibs/xmpp/xmpp_parser.hpp b/louloulibs/xmpp/xmpp_parser.hpp index 4de639d..3474b13 100644 --- a/louloulibs/xmpp/xmpp_parser.hpp +++ b/louloulibs/xmpp/xmpp_parser.hpp @@ -82,7 +82,7 @@ public: /** * Some inner or tail data has been parsed */ - void char_data(const XML_Char* data, int len); + void char_data(const XML_Char* data, const size_t len); /** * Calls all the stanza_callbacks one by one. */ diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index d1c2e0f..f247436 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -199,6 +199,11 @@ void XmlNode::set_name(const std::string& name) this->name = name; } +void XmlNode::set_name(std::string&& name) +{ + this->name = std::move(name); +} + const std::string XmlNode::get_name() const { return this->name; @@ -228,7 +233,7 @@ bool XmlNode::has_children() const return !this->children.empty(); } -const std::string XmlNode::get_tag(const std::string& name) const +const std::string& XmlNode::get_tag(const std::string& name) const { try { @@ -237,7 +242,8 @@ const std::string XmlNode::get_tag(const std::string& name) const } catch (const std::out_of_range& e) { - return ""; + static const std::string def{}; + return def; } } diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index b1ba54a..bdc937f 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -96,6 +96,7 @@ public: XmlNode* get_last_child() const; XmlNode* get_parent() const; void set_name(const std::string& name); + void set_name(std::string&& name); const std::string get_name() const; /** * Serialize the stanza into a string @@ -110,7 +111,7 @@ public: * Gets the value for the given attribute, returns an empty string if the * node as no such attribute. */ - const std::string get_tag(const std::string& name) const; + const std::string& get_tag(const std::string& name) const; /** * Remove the attribute of the node. Does nothing if that attribute is not * present. Returns true if the tag was removed, false if it was absent. @@ -133,13 +134,13 @@ private: XmlNode& operator=(XmlNode&&) = delete; }; +std::ostream& operator<<(std::ostream& os, const XmlNode& node); + /** * An XMPP stanza is just an XML node of level 2 in the XMPP document (the * level 1 ones are the , and the ones above 2 are just the * content of the stanzas) */ -typedef XmlNode Stanza; - -std::ostream& operator<<(std::ostream& os, const XmlNode& node); +using Stanza = XmlNode; #endif // XMPP_STANZA_INCLUDED -- cgit v1.2.3 From 79cdf170d2ab6c5378cfbf61d5c8888a4c666190 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 28 Dec 2015 21:25:48 +0100 Subject: Use the configured encoding value when decoding received messages --- louloulibs/xmpp/xmpp_stanza.cpp | 16 ++++++++-------- louloulibs/xmpp/xmpp_stanza.hpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index f247436..407e631 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -84,6 +84,14 @@ std::string xml_unescape(const std::string& data) return res; } +std::string sanitize(const std::string& data, const std::string& encoding) +{ + 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, encoding.data()))); +} + XmlNode::XmlNode(const std::string& name, XmlNode* parent): parent(parent) { @@ -259,14 +267,6 @@ 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"))); -} - std::ostream& operator<<(std::ostream& os, const XmlNode& node) { return os << node.to_string(); diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index bdc937f..77ab206 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -8,7 +8,7 @@ std::string xml_escape(const std::string& data); std::string xml_unescape(const std::string& data); -std::string sanitize(const std::string& data); +std::string sanitize(const std::string& data, const std::string& encoding = "ISO-8859-1"); /** * Represent an XML node. It has -- cgit v1.2.3 From 218260362f0ccb4fd5b51765d4bd331389f39baa Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Wed, 10 Feb 2016 20:22:51 +0100 Subject: Remove unused xml_unescape() function --- louloulibs/xmpp/xmpp_stanza.cpp | 44 ----------------------------------------- 1 file changed, 44 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_stanza.cpp b/louloulibs/xmpp/xmpp_stanza.cpp index 407e631..ac6ce9b 100644 --- a/louloulibs/xmpp/xmpp_stanza.cpp +++ b/louloulibs/xmpp/xmpp_stanza.cpp @@ -40,50 +40,6 @@ std::string xml_escape(const std::string& data) return res; } -std::string xml_unescape(const std::string& data) -{ - std::string res; - res.reserve(data.size()); - const char* str = data.c_str(); - while (str && *str && static_cast(str - data.c_str()) < data.size()) - { - if (*str == '&') - { - if (strncmp(str+1, "amp;", 4) == 0) - { - res += "&"; - str += 4; - } - else if (strncmp(str+1, "lt;", 3) == 0) - { - res += "<"; - str += 3; - } - else if (strncmp(str+1, "gt;", 3) == 0) - { - res += ">"; - str += 3; - } - else if (strncmp(str+1, "quot;", 5) == 0) - { - res += "\""; - str += 5; - } - else if (strncmp(str+1, "apos;", 5) == 0) - { - res += "'"; - str += 5; - } - else - res += "&"; - } - else - res += *str; - str++; - } - return res; -} - std::string sanitize(const std::string& data, const std::string& encoding) { if (utils::is_valid_utf8(data.data())) -- cgit v1.2.3 From 37fd6ff18a6e51ee5c4127b7e1269e3944d71b44 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Mon, 22 Feb 2016 17:01:10 +0100 Subject: log the handshake + stream opening/close in a more consistent way --- louloulibs/xmpp/xmpp_component.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index a82892d..c5906e5 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -89,9 +89,10 @@ void XmppComponent::on_connected() { log_info("connected to XMPP server"); this->first_connection_try = true; - this->send_data(""); + auto data = ""; + log_debug("XMPP SENDING: " << data); + this->send_data(std::move(data)); this->doc_open = true; // We may have some pending data to send: this happens when we try to send // some data before we are actually connected. We send that data right now, if any @@ -124,7 +125,7 @@ void XmppComponent::parse_in_buffer(const size_t size) void XmppComponent::on_remote_stream_open(const XmlNode& node) { - log_debug("XMPP DOCUMENT OPEN: " << node.to_string()); + log_debug("XMPP RECEIVING: " << node.to_string()); this->stream_id = node.get_tag("id"); if (this->stream_id.empty()) { @@ -145,14 +146,14 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node) sprintf(digest + (i*2), "%02x", result[i]); digest[HASH_LENGTH * 2] = '\0'; - this->send_data(""); - this->send_data(digest); - this->send_data(""); + auto data = ""s + digest + ""; + log_debug("XMPP SENDING: " << data); + this->send_data(std::move(data)); } void XmppComponent::on_remote_stream_close(const XmlNode& node) { - log_debug("XMPP DOCUMENT CLOSE " << node.to_string()); + log_debug("XMPP RECEIVING: " << node.to_string()); this->doc_open = false; } -- cgit v1.2.3 From 04d28f968b227067e77e365d317fc251d3c965f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 19 Apr 2016 02:43:26 +0200 Subject: Forward the topic authors, handle the author from 333 messages fix #2 --- louloulibs/xmpp/xmpp_component.cpp | 7 +++++-- louloulibs/xmpp/xmpp_component.hpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index c5906e5..8a0ca52 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -388,11 +388,14 @@ void XmppComponent::send_invalid_user_error(const std::string& user_name, const this->send_stanza(message); } -void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to) +void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to, const std::string& who) { XmlNode message("message"); message["to"] = to; - message["from"] = from + "@" + this->served_hostname; + if (who.empty()) + message["from"] = from + "@" + this->served_hostname; + else + message["from"] = from + "@" + this->served_hostname + "/" + who; message["type"] = "groupchat"; XmlNode subject("subject"); subject.set_inner(std::get<0>(topic)); diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index 06236fe..07322dd 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -124,7 +124,7 @@ public: /** * Send the MUC topic to the user */ - void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to); + void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to, const std::string& who); /** * Send a (non-private) message to the MUC */ -- cgit v1.2.3 From 1e56c59e8241dbfc6a2526c371cc2e894f9d0f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 25 Apr 2016 11:29:52 +0200 Subject: Include the Configure ad-hoc command on biboumi's JID for fixed_irc_server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because a jid like “freenode.example.org” is both the JID for the configured IRC server, and biboumi’s JID. fix #3175 --- louloulibs/xmpp/adhoc_command.cpp | 4 ---- louloulibs/xmpp/adhoc_command.hpp | 6 +++++- louloulibs/xmpp/xmpp_component.cpp | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_command.cpp b/louloulibs/xmpp/adhoc_command.cpp index 8a8bcff..99701d7 100644 --- a/louloulibs/xmpp/adhoc_command.cpp +++ b/louloulibs/xmpp/adhoc_command.cpp @@ -11,10 +11,6 @@ AdhocCommand::AdhocCommand(std::vector&& callbacks, const std::string { } -AdhocCommand::~AdhocCommand() -{ -} - bool AdhocCommand::is_admin_only() const { return this->admin_only; diff --git a/louloulibs/xmpp/adhoc_command.hpp b/louloulibs/xmpp/adhoc_command.hpp index a2e033a..1c4e4de 100644 --- a/louloulibs/xmpp/adhoc_command.hpp +++ b/louloulibs/xmpp/adhoc_command.hpp @@ -19,7 +19,11 @@ class AdhocCommand friend class AdhocSession; public: AdhocCommand(std::vector&& callback, const std::string& name, const bool admin_only); - ~AdhocCommand(); + ~AdhocCommand() = default; + AdhocCommand(const AdhocCommand&) = default; + AdhocCommand(AdhocCommand&&) = default; + AdhocCommand& operator=(AdhocCommand&&) = delete; + AdhocCommand& operator=(const AdhocCommand&) = delete; const std::string name; diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 8a0ca52..b92d9a3 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -591,7 +591,9 @@ void XmppComponent::send_version(const std::string& id, const std::string& jid_t this->send_stanza(iq); } -void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const std::string& from_jid, const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler) +void XmppComponent::send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, + const std::string& from_jid, + const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler) { Stanza iq("iq"); iq["type"] = "result"; -- cgit v1.2.3 From af42073830087d97385e507f27f601e8769541b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 4 May 2016 14:16:40 +0200 Subject: Style fix Move all constructors at the top of classes --- louloulibs/xmpp/adhoc_commands_handler.hpp | 11 ++++++----- louloulibs/xmpp/adhoc_session.hpp | 12 ++++++------ louloulibs/xmpp/jid.hpp | 11 +++++------ louloulibs/xmpp/xmpp_component.hpp | 10 +++++----- louloulibs/xmpp/xmpp_parser.cpp | 4 ++-- louloulibs/xmpp/xmpp_parser.hpp | 16 +++++++++------- louloulibs/xmpp/xmpp_stanza.hpp | 8 ++++---- 7 files changed, 37 insertions(+), 35 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp index 0614b2f..65b094d 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.hpp +++ b/louloulibs/xmpp/adhoc_commands_handler.hpp @@ -21,6 +21,12 @@ public: commands{} { } ~AdhocCommandsHandler() = default; + + AdhocCommandsHandler(const AdhocCommandsHandler&) = delete; + AdhocCommandsHandler(AdhocCommandsHandler&&) = delete; + AdhocCommandsHandler& operator=(const AdhocCommandsHandler&) = delete; + AdhocCommandsHandler& operator=(AdhocCommandsHandler&&) = delete; + /** * Returns the list of available commands. */ @@ -63,11 +69,6 @@ private: * Of the form: {{session_id, owner_jid}, session}. */ std::map, AdhocSession> sessions; - - AdhocCommandsHandler(const AdhocCommandsHandler&) = delete; - AdhocCommandsHandler(AdhocCommandsHandler&&) = delete; - AdhocCommandsHandler& operator=(const AdhocCommandsHandler&) = delete; - AdhocCommandsHandler& operator=(AdhocCommandsHandler&&) = delete; }; #endif // ADHOC_COMMANDS_HANDLER_HPP diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp index e98b6a8..0966c4e 100644 --- a/louloulibs/xmpp/adhoc_session.hpp +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -25,6 +25,12 @@ public: explicit AdhocSession(const AdhocCommand& command, const std::string& owner_jid, const std::string& to_jid); ~AdhocSession() = default; + + AdhocSession(const AdhocSession&) = delete; + AdhocSession(AdhocSession&&) = delete; + AdhocSession& operator=(const AdhocSession&) = delete; + AdhocSession& operator=(AdhocSession&&) = delete; + /** * Return the function to be executed, found in our AdhocCommand, for the * current_step. And increment the current_step. @@ -80,12 +86,6 @@ public: * any key in there. */ std::map vars; - -private: - AdhocSession(const AdhocSession&) = delete; - AdhocSession(AdhocSession&&) = delete; - AdhocSession& operator=(const AdhocSession&) = delete; - AdhocSession& operator=(AdhocSession&&) = delete; }; #endif // ADHOC_SESSION_HPP diff --git a/louloulibs/xmpp/jid.hpp b/louloulibs/xmpp/jid.hpp index e2ee586..5ff5a4f 100644 --- a/louloulibs/xmpp/jid.hpp +++ b/louloulibs/xmpp/jid.hpp @@ -11,6 +11,11 @@ class Jid public: explicit Jid(const std::string& jid); + Jid(const Jid&) = delete; + Jid(Jid&&) = delete; + Jid& operator=(const Jid&) = delete; + Jid& operator=(Jid&&) = delete; + std::string domain; std::string local; std::string resource; @@ -23,12 +28,6 @@ public: { return this->local + "@" + this->domain + "/" + this->resource; } - -private: - Jid(const Jid&) = delete; - Jid(Jid&&) = delete; - Jid& operator=(const Jid&) = delete; - Jid& operator=(Jid&&) = delete; }; /** diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index 07322dd..913e337 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -38,6 +38,11 @@ public: explicit XmppComponent(std::shared_ptr poller, const std::string& hostname, const std::string& secret); virtual ~XmppComponent() = default; + XmppComponent(const XmppComponent&) = delete; + XmppComponent(XmppComponent&&) = delete; + XmppComponent& operator=(const XmppComponent&) = delete; + XmppComponent& operator=(XmppComponent&&) = delete; + void on_connection_failed(const std::string& reason) override final; void on_connected() override final; void on_connection_close(const std::string& error) override final; @@ -231,11 +236,6 @@ protected: std::unordered_map> stanza_handlers; AdhocCommandsHandler adhoc_commands_handler; - - XmppComponent(const XmppComponent&) = delete; - XmppComponent(XmppComponent&&) = delete; - XmppComponent& operator=(const XmppComponent&) = delete; - XmppComponent& operator=(XmppComponent&&) = delete; }; #endif // XMPP_COMPONENT_INCLUDED diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index 69de145..dc12000 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -118,7 +118,7 @@ void XmppParser::end_element(const XML_Char*) this->stanza_event(*this->current_node); // Note: deleting all the children of our parent deletes ourself, // so current_node is an invalid pointer after this line - this->current_node->get_parent()->delete_all_children(); + parent->delete_all_children(); } this->current_node = parent; } @@ -139,7 +139,7 @@ void XmppParser::stanza_event(const Stanza& stanza) const try { callback(stanza); } catch (const std::exception& e) { - log_debug("Unhandled exception: " << e.what()); + log_error("Unhandled exception: " << e.what()); } } } diff --git a/louloulibs/xmpp/xmpp_parser.hpp b/louloulibs/xmpp/xmpp_parser.hpp index 3474b13..93c6c53 100644 --- a/louloulibs/xmpp/xmpp_parser.hpp +++ b/louloulibs/xmpp/xmpp_parser.hpp @@ -32,12 +32,12 @@ class XmppParser public: explicit XmppParser(); ~XmppParser(); + XmppParser(const XmppParser&) = delete; + XmppParser& operator=(const XmppParser&) = delete; + XmppParser(XmppParser&&) = delete; + XmppParser& operator=(XmppParser&&) = delete; public: - /** - * Init the XML parser and install the callbacks - */ - void init_xml_parser(); /** * Feed the parser with some XML data */ @@ -98,6 +98,11 @@ public: void stream_close_event(const XmlNode& node) const; private: + /** + * Init the XML parser and install the callbacks + */ + void init_xml_parser(); + /** * Expat structure. */ @@ -123,9 +128,6 @@ private: std::vector> stanza_callbacks; std::vector> stream_open_callbacks; std::vector> stream_close_callbacks; - - XmppParser(const XmppParser&) = delete; - XmppParser& operator=(const XmppParser&) = delete; }; #endif // XMPP_PARSER_INCLUDED diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 77ab206..28b8414 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -25,7 +25,6 @@ class XmlNode public: explicit XmlNode(const std::string& name, XmlNode* parent); explicit XmlNode(const std::string& name); - XmlNode(XmlNode&& node) = default; /** * The copy constructor does not copy the parent attribute. The children * nodes are all copied recursively. @@ -42,6 +41,10 @@ public: this->add_child(std::make_unique(*child)); } + XmlNode(XmlNode&& node) = default; + XmlNode& operator=(const XmlNode&) = delete; + XmlNode& operator=(XmlNode&&) = delete; + ~XmlNode() = default; void delete_all_children(); @@ -129,9 +132,6 @@ private: std::vector> children; std::string inner; std::string tail; - - XmlNode& operator=(const XmlNode&) = delete; - XmlNode& operator=(XmlNode&&) = delete; }; std::ostream& operator<<(std::ostream& os, const XmlNode& node); -- cgit v1.2.3 From fdddd447b3976f26a4146ebf91abfc04736a006b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 13 May 2016 01:22:49 +0200 Subject: =?UTF-8?q?Use=20=E2=80=9Cusing=E2=80=9D=20instead=20of=20typedef?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louloulibs/xmpp/body.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/body.hpp b/louloulibs/xmpp/body.hpp index 6ac678e..df86feb 100644 --- a/louloulibs/xmpp/body.hpp +++ b/louloulibs/xmpp/body.hpp @@ -6,7 +6,7 @@ namespace Xmpp // Contains: // - an XMPP-valid UTF-8 body // - an XML node representing the XHTML-IM body, or null - typedef std::tuple> body; + using body = std::tuple>; } #endif /* XMPP_BODY_HPP_INCLUDED */ -- cgit v1.2.3 From a641a26327e04016dfd62e1cb1f2141b9364631b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 2 Jun 2016 16:03:28 +0200 Subject: Check the length of the JID parts when copying into the jidprep buffer We trust the XMPP server, but maybe not enough to not check that --- louloulibs/xmpp/jid.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/jid.cpp b/louloulibs/xmpp/jid.cpp index dcd7012..7b62f3e 100644 --- a/louloulibs/xmpp/jid.cpp +++ b/louloulibs/xmpp/jid.cpp @@ -47,7 +47,7 @@ std::string jidprep(const std::string& original) Jid jid(original); char local[max_jid_part_len] = {}; - memcpy(local, jid.local.data(), jid.local.size()); + memcpy(local, jid.local.data(), std::min(max_jid_part_len, jid.local.size())); Stringprep_rc rc = static_cast(::stringprep(local, max_jid_part_len, static_cast(0), stringprep_xmpp_nodeprep)); if (rc != STRINGPREP_OK) @@ -57,7 +57,7 @@ std::string jidprep(const std::string& original) } char domain[max_jid_part_len] = {}; - memcpy(domain, jid.domain.data(), jid.domain.size()); + memcpy(domain, jid.domain.data(), std::min(max_jid_part_len, jid.domain.size())); rc = static_cast(::stringprep(domain, max_jid_part_len, static_cast(0), stringprep_nameprep)); if (rc != STRINGPREP_OK) @@ -81,7 +81,7 @@ std::string jidprep(const std::string& original) // Otherwise, also process the resource part char resource[max_jid_part_len] = {}; - memcpy(resource, jid.resource.data(), jid.resource.size()); + memcpy(resource, jid.resource.data(), std::min(max_jid_part_len, jid.resource.size())); rc = static_cast(::stringprep(resource, max_jid_part_len, static_cast(0), stringprep_xmpp_resourceprep)); if (rc != STRINGPREP_OK) -- cgit v1.2.3 From 5a2e61161792cf51209f240e40e28036195f35be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 13 Jun 2016 19:59:17 +0200 Subject: Show off, with some variadic templates, for the logger module --- louloulibs/xmpp/adhoc_commands_handler.cpp | 2 +- louloulibs/xmpp/xmpp_component.cpp | 20 ++++++++++---------- louloulibs/xmpp/xmpp_parser.cpp | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 714c440..17c4e67 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -119,5 +119,5 @@ void AdhocCommandsHandler::remove_session(const std::string& session_id, const s this->sessions.erase(session_it); return ; } - log_error("Tried to remove ad-hoc session for [" << session_id << ", " << initiator_jid << "] but none found"); + log_error("Tried to remove ad-hoc session for [", session_id, ", ", initiator_jid, "] but none found"); } diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index b92d9a3..1be7a06 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -72,14 +72,14 @@ bool XmppComponent::is_document_open() const void XmppComponent::send_stanza(const Stanza& stanza) { std::string str = stanza.to_string(); - log_debug("XMPP SENDING: " << str); + log_debug("XMPP SENDING: ", str); this->send_data(std::move(str)); } void XmppComponent::on_connection_failed(const std::string& reason) { this->first_connection_try = false; - log_error("Failed to connect to the XMPP server: " << reason); + log_error("Failed to connect to the XMPP server: ", reason); #ifdef SYSTEMD_FOUND sd_notifyf(0, "STATUS=Failed to connect to the XMPP server: %s", reason.data()); #endif @@ -91,7 +91,7 @@ void XmppComponent::on_connected() this->first_connection_try = true; auto data = ""; - log_debug("XMPP SENDING: " << data); + log_debug("XMPP SENDING: ", data); this->send_data(std::move(data)); this->doc_open = true; // We may have some pending data to send: this happens when we try to send @@ -104,7 +104,7 @@ void XmppComponent::on_connection_close(const std::string& error) if (error.empty()) log_info("XMPP server closed connection"); else - log_info("XMPP server closed connection: " << error); + log_info("XMPP server closed connection: ", error); } void XmppComponent::parse_in_buffer(const size_t size) @@ -125,7 +125,7 @@ void XmppComponent::parse_in_buffer(const size_t size) void XmppComponent::on_remote_stream_open(const XmlNode& node) { - log_debug("XMPP RECEIVING: " << node.to_string()); + log_debug("XMPP RECEIVING: ", node.to_string()); this->stream_id = node.get_tag("id"); if (this->stream_id.empty()) { @@ -147,13 +147,13 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node) digest[HASH_LENGTH * 2] = '\0'; auto data = ""s + digest + ""; - log_debug("XMPP SENDING: " << data); + log_debug("XMPP SENDING: ", data); this->send_data(std::move(data)); } void XmppComponent::on_remote_stream_close(const XmlNode& node) { - log_debug("XMPP RECEIVING: " << node.to_string()); + log_debug("XMPP RECEIVING: ", node.to_string()); this->doc_open = false; } @@ -164,7 +164,7 @@ void XmppComponent::reset() void XmppComponent::on_stanza(const Stanza& stanza) { - log_debug("XMPP RECEIVING: " << stanza.to_string()); + log_debug("XMPP RECEIVING: ", stanza.to_string()); std::function handler; try { @@ -172,7 +172,7 @@ void XmppComponent::on_stanza(const Stanza& stanza) } catch (const std::out_of_range& exception) { - log_warning("No handler for stanza of type " << stanza.get_name()); + log_warning("No handler for stanza of type ", stanza.get_name()); return; } handler(stanza); @@ -257,7 +257,7 @@ void XmppComponent::handle_error(const Stanza& stanza) std::string error_message("Unspecified error"); if (text) error_message = text->get_inner(); - log_error("Stream error received from the XMPP server: " << error_message); + log_error("Stream error received from the XMPP server: ", error_message); #ifdef SYSTEMD_FOUND if (!this->ever_auth) sd_notifyf(0, "STATUS=Failed to authenticate to the XMPP server: %s", error_message.data()); diff --git a/louloulibs/xmpp/xmpp_parser.cpp b/louloulibs/xmpp/xmpp_parser.cpp index dc12000..0488be9 100644 --- a/louloulibs/xmpp/xmpp_parser.cpp +++ b/louloulibs/xmpp/xmpp_parser.cpp @@ -56,7 +56,7 @@ int XmppParser::feed(const char* data, const int len, const bool is_final) int res = XML_Parse(this->parser, data, len, is_final); if (res == XML_STATUS_ERROR && (XML_GetErrorCode(this->parser) != XML_ERROR_FINISHED)) - log_error("Xml_Parse encountered an error: " << + log_error("Xml_Parse encountered an error: ", XML_ErrorString(XML_GetErrorCode(this->parser))); return res; } @@ -65,7 +65,7 @@ int XmppParser::parse(const int len, const bool is_final) { int res = XML_ParseBuffer(this->parser, len, is_final); if (res == XML_STATUS_ERROR) - log_error("Xml_Parsebuffer encountered an error: " << + log_error("Xml_Parsebuffer encountered an error: ", XML_ErrorString(XML_GetErrorCode(this->parser))); return res; } @@ -139,7 +139,7 @@ void XmppParser::stanza_event(const Stanza& stanza) const try { callback(stanza); } catch (const std::exception& e) { - log_error("Unhandled exception: " << e.what()); + log_error("Unhandled exception: ", e.what()); } } } -- cgit v1.2.3 From b2e7edeea8bf08b6b7e75d60af3af0c30fdaa4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 24 Jun 2016 11:23:01 +0200 Subject: =?UTF-8?q?Properly=20set=20the=20=E2=80=9Cfrom=E2=80=9D=20of=20th?= =?UTF-8?q?e=20ping=20results=20to=20the=20correct=20full=20JID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- louloulibs/xmpp/xmpp_component.cpp | 10 ++++++++++ louloulibs/xmpp/xmpp_component.hpp | 2 ++ 2 files changed, 12 insertions(+) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index 1be7a06..e87cdf7 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -631,6 +631,16 @@ void XmppComponent::send_iq_version_request(const std::string& from, this->send_stanza(iq); } +void XmppComponent::send_iq_result_full_jid(const std::string& id, const std::string& to_jid, const std::string& from_full_jid) +{ + Stanza iq("iq"); + iq["from"] = from_full_jid; + iq["to"] = to_jid; + iq["id"] = id; + iq["type"] = "result"; + this->send_stanza(iq); +} + void XmppComponent::send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from_local_part) { Stanza iq("iq"); diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index 913e337..ae4d76b 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -200,6 +200,8 @@ public: * Send an empty iq of type result */ void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from); + void send_iq_result_full_jid(const std::string& id, const std::string& to_jid, + const std::string& from_full_jid); void handle_handshake(const Stanza& stanza); void handle_error(const Stanza& stanza); -- cgit v1.2.3 From 81f8f45b371d1a0ef72c2768fbd1f9188fe83616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 4 Jul 2016 17:53:53 +0200 Subject: Replace all include guards by #pragma once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s $CURRENT_YEAR --- louloulibs/xmpp/adhoc_command.hpp | 5 +---- louloulibs/xmpp/adhoc_commands_handler.hpp | 5 +---- louloulibs/xmpp/adhoc_session.hpp | 5 +---- louloulibs/xmpp/body.hpp | 6 +++--- louloulibs/xmpp/jid.hpp | 6 +++--- louloulibs/xmpp/roster.hpp | 6 +++--- louloulibs/xmpp/xmpp_component.hpp | 6 +++--- louloulibs/xmpp/xmpp_parser.hpp | 6 +++--- louloulibs/xmpp/xmpp_stanza.hpp | 6 +++--- 9 files changed, 21 insertions(+), 30 deletions(-) (limited to 'louloulibs/xmpp') diff --git a/louloulibs/xmpp/adhoc_command.hpp b/louloulibs/xmpp/adhoc_command.hpp index 1c4e4de..7c4de47 100644 --- a/louloulibs/xmpp/adhoc_command.hpp +++ b/louloulibs/xmpp/adhoc_command.hpp @@ -1,5 +1,4 @@ -#ifndef ADHOC_COMMAND_HPP -# define ADHOC_COMMAND_HPP +#pragma once /** * Describe an ad-hoc command. @@ -43,5 +42,3 @@ void PingStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); void HelloStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); void Reload(XmppComponent&, AdhocSession& session, XmlNode& command_node); - -#endif // ADHOC_COMMAND_HPP diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp index 65b094d..91eb5bd 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.hpp +++ b/louloulibs/xmpp/adhoc_commands_handler.hpp @@ -1,5 +1,4 @@ -#ifndef ADHOC_COMMANDS_HANDLER_HPP -# define ADHOC_COMMANDS_HANDLER_HPP +#pragma once /** * Manage a list of available AdhocCommands and the list of ongoing @@ -70,5 +69,3 @@ private: */ std::map, AdhocSession> sessions; }; - -#endif // ADHOC_COMMANDS_HANDLER_HPP diff --git a/louloulibs/xmpp/adhoc_session.hpp b/louloulibs/xmpp/adhoc_session.hpp index 0966c4e..0de8d13 100644 --- a/louloulibs/xmpp/adhoc_session.hpp +++ b/louloulibs/xmpp/adhoc_session.hpp @@ -1,5 +1,4 @@ -#ifndef ADHOC_SESSION_HPP -# define ADHOC_SESSION_HPP +#pragma once #include @@ -87,5 +86,3 @@ public: */ std::map vars; }; - -#endif // ADHOC_SESSION_HPP diff --git a/louloulibs/xmpp/body.hpp b/louloulibs/xmpp/body.hpp index df86feb..068d1a4 100644 --- a/louloulibs/xmpp/body.hpp +++ b/louloulibs/xmpp/body.hpp @@ -1,5 +1,5 @@ -#ifndef XMPP_BODY_HPP_INCLUDED -#define XMPP_BODY_HPP_INCLUDED +#pragma once + namespace Xmpp { @@ -9,4 +9,4 @@ namespace Xmpp using body = std::tuple>; } -#endif /* XMPP_BODY_HPP_INCLUDED */ + diff --git a/louloulibs/xmpp/jid.hpp b/louloulibs/xmpp/jid.hpp index 5ff5a4f..08327ef 100644 --- a/louloulibs/xmpp/jid.hpp +++ b/louloulibs/xmpp/jid.hpp @@ -1,5 +1,5 @@ -#ifndef JID_INCLUDED -# define JID_INCLUDED +#pragma once + #include @@ -41,4 +41,4 @@ public: */ std::string jidprep(const std::string& original); -#endif // JID_INCLUDED + diff --git a/louloulibs/xmpp/roster.hpp b/louloulibs/xmpp/roster.hpp index 0aebca5..aa1b449 100644 --- a/louloulibs/xmpp/roster.hpp +++ b/louloulibs/xmpp/roster.hpp @@ -1,5 +1,5 @@ -#ifndef ROSTER_HPP_INCLUDED -#define ROSTER_HPP_INCLUDED +#pragma once + #include #include @@ -68,4 +68,4 @@ private: Roster& operator=(Roster&&) = delete; }; -#endif /* ROSTER_HPP_INCLUDED */ + diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index ae4d76b..5fc6d2e 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -1,5 +1,5 @@ -#ifndef XMPP_COMPONENT_INCLUDED -# define XMPP_COMPONENT_INCLUDED +#pragma once + #include #include @@ -240,4 +240,4 @@ protected: AdhocCommandsHandler adhoc_commands_handler; }; -#endif // XMPP_COMPONENT_INCLUDED + diff --git a/louloulibs/xmpp/xmpp_parser.hpp b/louloulibs/xmpp/xmpp_parser.hpp index 93c6c53..9d67228 100644 --- a/louloulibs/xmpp/xmpp_parser.hpp +++ b/louloulibs/xmpp/xmpp_parser.hpp @@ -1,5 +1,5 @@ -#ifndef XMPP_PARSER_INCLUDED -# define XMPP_PARSER_INCLUDED +#pragma once + #include @@ -130,4 +130,4 @@ private: std::vector> stream_close_callbacks; }; -#endif // XMPP_PARSER_INCLUDED + diff --git a/louloulibs/xmpp/xmpp_stanza.hpp b/louloulibs/xmpp/xmpp_stanza.hpp index 28b8414..4ca758e 100644 --- a/louloulibs/xmpp/xmpp_stanza.hpp +++ b/louloulibs/xmpp/xmpp_stanza.hpp @@ -1,5 +1,5 @@ -#ifndef XMPP_STANZA_INCLUDED -# define XMPP_STANZA_INCLUDED +#pragma once + #include #include @@ -143,4 +143,4 @@ std::ostream& operator<<(std::ostream& os, const XmlNode& node); */ using Stanza = XmlNode; -#endif // XMPP_STANZA_INCLUDED + -- cgit v1.2.3