diff options
Diffstat (limited to 'louloulibs/xmpp')
-rw-r--r-- | louloulibs/xmpp/adhoc_commands_handler.cpp | 7 | ||||
-rw-r--r-- | louloulibs/xmpp/adhoc_commands_handler.hpp | 4 | ||||
-rw-r--r-- | louloulibs/xmpp/auth.cpp | 21 | ||||
-rw-r--r-- | louloulibs/xmpp/auth.hpp | 6 | ||||
-rw-r--r-- | louloulibs/xmpp/jid.hpp | 7 | ||||
-rw-r--r-- | louloulibs/xmpp/roster.cpp | 21 | ||||
-rw-r--r-- | louloulibs/xmpp/roster.hpp | 71 | ||||
-rw-r--r-- | louloulibs/xmpp/xmpp_component.cpp | 99 | ||||
-rw-r--r-- | louloulibs/xmpp/xmpp_component.hpp | 34 |
9 files changed, 112 insertions, 158 deletions
diff --git a/louloulibs/xmpp/adhoc_commands_handler.cpp b/louloulibs/xmpp/adhoc_commands_handler.cpp index 17c4e67..540cac0 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.cpp +++ b/louloulibs/xmpp/adhoc_commands_handler.cpp @@ -15,9 +15,12 @@ const std::map<const std::string, const AdhocCommand>& AdhocCommandsHandler::get return this->commands; } -std::map<const std::string, const AdhocCommand>& AdhocCommandsHandler::get_commands() +void AdhocCommandsHandler::add_command(std::string name, AdhocCommand command) { - return this->commands; + const auto found = this->commands.find(name); + if (found != this->commands.end()) + throw std::runtime_error("Trying to add an ad-hoc command that already exist: "s + name); + this->commands.emplace(std::make_pair(std::move(name), std::move(command))); } XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, const std::string& to, XmlNode command_node) diff --git a/louloulibs/xmpp/adhoc_commands_handler.hpp b/louloulibs/xmpp/adhoc_commands_handler.hpp index 91eb5bd..e37d913 100644 --- a/louloulibs/xmpp/adhoc_commands_handler.hpp +++ b/louloulibs/xmpp/adhoc_commands_handler.hpp @@ -31,9 +31,9 @@ public: */ const std::map<const std::string, const AdhocCommand>& get_commands() const; /** - * This one can be used to add new commands. + * Add a command into the list, associated with the given name */ - std::map<const std::string, const AdhocCommand>& get_commands(); + void add_command(std::string name, AdhocCommand command); /** * 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 diff --git a/louloulibs/xmpp/auth.cpp b/louloulibs/xmpp/auth.cpp new file mode 100644 index 0000000..c20f95d --- /dev/null +++ b/louloulibs/xmpp/auth.cpp @@ -0,0 +1,21 @@ +#include <xmpp/auth.hpp> + +#include <utils/sha1.hpp> + +#include <iomanip> +#include <sstream> + +std::string get_handshake_digest(const std::string& stream_id, const std::string& secret) +{ + sha1nfo sha1; + sha1_init(&sha1); + sha1_write(&sha1, stream_id.data(), stream_id.size()); + sha1_write(&sha1, secret.data(), secret.size()); + const uint8_t* result = sha1_result(&sha1); + + std::ostringstream digest; + for (int i = 0; i < HASH_LENGTH; i++) + digest << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(result[i]); + + return digest.str(); +} diff --git a/louloulibs/xmpp/auth.hpp b/louloulibs/xmpp/auth.hpp new file mode 100644 index 0000000..34a2116 --- /dev/null +++ b/louloulibs/xmpp/auth.hpp @@ -0,0 +1,6 @@ +#pragma once + +#include <string> + +std::string get_handshake_digest(const std::string& stream_id, const std::string& secret); + diff --git a/louloulibs/xmpp/jid.hpp b/louloulibs/xmpp/jid.hpp index 08327ef..85e835c 100644 --- a/louloulibs/xmpp/jid.hpp +++ b/louloulibs/xmpp/jid.hpp @@ -26,7 +26,12 @@ public: } std::string full() const { - return this->local + "@" + this->domain + "/" + this->resource; + std::string res = this->domain; + if (!this->local.empty()) + res = this->local + "@" + this->domain; + if (!this->resource.empty()) + res += "/" + this->resource; + return res; } }; diff --git a/louloulibs/xmpp/roster.cpp b/louloulibs/xmpp/roster.cpp deleted file mode 100644 index a14a384..0000000 --- a/louloulibs/xmpp/roster.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include <xmpp/roster.hpp> - -RosterItem::RosterItem(const std::string& jid, const std::string& name, - std::vector<std::string>& 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 deleted file mode 100644 index aa1b449..0000000 --- a/louloulibs/xmpp/roster.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - - -#include <algorithm> -#include <string> -#include <vector> - -class RosterItem -{ -public: - RosterItem(const std::string& jid, const std::string& name, - std::vector<std::string>& 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<std::string> groups; - -private: -}; - -/** - * Keep track of the last known stat of a JID's roster - */ -class Roster -{ -public: - Roster() = default; - ~Roster() = default; - - void clear(); - - template <typename... ArgsType> - RosterItem* add_item(ArgsType&&... args) - { - this->items.emplace_back(std::forward<ArgsType>(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<RosterItem>& get_items() const - { - return this->items; - } - -private: - std::vector<RosterItem> items; - - Roster(const Roster&) = delete; - Roster(Roster&&) = delete; - Roster& operator=(const Roster&) = delete; - Roster& operator=(Roster&&) = delete; -}; - - diff --git a/louloulibs/xmpp/xmpp_component.cpp b/louloulibs/xmpp/xmpp_component.cpp index e87cdf7..fa8b0a5 100644 --- a/louloulibs/xmpp/xmpp_component.cpp +++ b/louloulibs/xmpp/xmpp_component.cpp @@ -5,16 +5,18 @@ #include <xmpp/xmpp_component.hpp> #include <config/config.hpp> +#include <utils/time.hpp> +#include <xmpp/auth.hpp> #include <xmpp/jid.hpp> -#include <utils/sha1.hpp> #include <stdexcept> #include <iostream> #include <set> -#include <stdio.h> +#include <uuid/uuid.h> -#include <uuid.h> +#include <cstdlib> +#include <set> #include <louloulibs.h> #ifdef SYSTEMD_FOUND @@ -136,17 +138,7 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node) } // 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'; - - auto data = "<handshake xmlns='" COMPONENT_NS "'>"s + digest + "</handshake>"; + auto data = "<handshake xmlns='" COMPONENT_NS "'>"s + get_handshake_digest(this->stream_id, this->secret) + "</handshake>"; log_debug("XMPP SENDING: ", data); this->send_data(std::move(data)); } @@ -230,9 +222,8 @@ void XmppComponent::close_document() this->doc_open = false; } -void XmppComponent::handle_handshake(const Stanza& stanza) +void XmppComponent::handle_handshake(const Stanza&) { - (void)stanza; this->authenticated = true; this->ever_auth = true; log_info("Authenticated with the XMPP server"); @@ -270,7 +261,8 @@ 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) +void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, const std::string& to, + const std::string& type, const bool fulljid, const bool nocopy) { XmlNode node("message"); node["to"] = to; @@ -291,6 +283,18 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con html.add_child(std::move(std::get<1>(body))); node.add_child(std::move(html)); } + + if (nocopy) + { + XmlNode private_node("private"); + private_node["xmlns"] = "urn:xmpp:carbons:2"; + node.add_child(std::move(private_node)); + + XmlNode nocopy("no-copy"); + nocopy["xmlns"] = "urn:xmpp:hints"; + node.add_child(std::move(nocopy)); + } + this->send_stanza(node); } @@ -363,31 +367,6 @@ void XmppComponent::send_invalid_room_error(const std::string& muc_name, 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; - 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; - 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: <nick>!<server>@" + - this->served_hostname); - error.add_child(std::move(text)); - message.add_child(std::move(error)); - this->send_stanza(message); -} - void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to, const std::string& who) { XmlNode message("message"); @@ -426,6 +405,29 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str this->send_stanza(message); } +void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, std::time_t timestamp) +{ + Stanza message("message"); + message["to"] = jid_to; + if (!nick.empty()) + message["from"] = muc_name + "@" + this->served_hostname + "/" + nick; + else + message["from"] = muc_name + "@" + this->served_hostname; + message["type"] = "groupchat"; + + XmlNode body("body"); + body.set_inner(body_txt); + message.add_child(std::move(body)); + + XmlNode delay("delay"); + delay["xmlns"] = DELAY_NS; + delay["from"] = muc_name + "@" + this->served_hostname; + delay["stamp"] = utils::to_string(timestamp); + + message.add_child(std::move(delay)); + 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"); @@ -483,11 +485,8 @@ void XmppComponent::send_nick_change(const std::string& muc_name, 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) +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, const bool self) { Stanza presence("presence"); presence["from"] = muc_name + "@" + this->served_hostname + "/" + target; @@ -509,6 +508,12 @@ void XmppComponent::kick_user(const std::string& muc_name, XmlNode status("status"); status["code"] = "307"; x.add_child(std::move(status)); + if (self) + { + XmlNode status("status"); + status["code"] = "110"; + x.add_child(std::move(status)); + } presence.add_child(std::move(x)); this->send_stanza(presence); } diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp index 5fc6d2e..5f5f937 100644 --- a/louloulibs/xmpp/xmpp_component.hpp +++ b/louloulibs/xmpp/xmpp_component.hpp @@ -9,6 +9,7 @@ #include <unordered_map> #include <memory> #include <string> +#include <ctime> #include <map> #define STREAM_NS "http://etherx.jabber.org/streams" @@ -25,6 +26,13 @@ #define VERSION_NS "jabber:iq:version" #define ADHOC_NS "http://jabber.org/protocol/commands" #define PING_NS "urn:xmpp:ping" +#define DELAY_NS "urn:xmpp:delay" +#define MAM_NS "urn:xmpp:mam:1" +#define FORWARD_NS "urn:xmpp:forward:0" +#define CLIENT_NS "jabber:client" +#define DATAFORM_NS "jabber:x:data" +#define RSM_NS "http://jabber.org/protocol/rsm" +#define MUC_TRAFFIC_NS "http://jabber.org/protocol/muc#traffic" /** * An XMPP component, communicating with an XMPP server using the protocole @@ -101,9 +109,8 @@ public: * 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); + void send_message(const std::string& from, Xmpp::body&& body, const std::string& to, + const std::string& type, const bool fulljid, const bool nocopy=false); /** * Send a join from a new participant */ @@ -121,12 +128,6 @@ public: 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, const std::string& who); @@ -135,6 +136,11 @@ public: */ void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to); /** + * Send a message, with a <delay/> element, part of a MUC history + */ + void send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body, + const std::string& jid_to, const std::time_t timestamp); + /** * 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); @@ -151,11 +157,8 @@ public: /** * 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); + 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, const bool self); /** * Send a generic presence error */ @@ -208,6 +211,9 @@ public: virtual void after_handshake() {} + const std::string& get_served_hostname() const + { return this->served_hostname; } + /** * Whether or not we ever succeeded our authentication to the XMPP server */ |