summaryrefslogtreecommitdiff
path: root/louloulibs/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'louloulibs/xmpp')
-rw-r--r--louloulibs/xmpp/adhoc_commands_handler.cpp7
-rw-r--r--louloulibs/xmpp/adhoc_commands_handler.hpp4
-rw-r--r--louloulibs/xmpp/auth.cpp21
-rw-r--r--louloulibs/xmpp/auth.hpp6
-rw-r--r--louloulibs/xmpp/jid.hpp7
-rw-r--r--louloulibs/xmpp/roster.cpp21
-rw-r--r--louloulibs/xmpp/roster.hpp71
-rw-r--r--louloulibs/xmpp/xmpp_component.cpp99
-rw-r--r--louloulibs/xmpp/xmpp_component.hpp34
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
*/