summaryrefslogtreecommitdiff
path: root/src/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/adhoc_commands_handler.cpp2
-rw-r--r--src/xmpp/biboumi_adhoc_commands.cpp10
-rw-r--r--src/xmpp/biboumi_component.cpp101
-rw-r--r--src/xmpp/body.hpp4
-rw-r--r--src/xmpp/xmpp_component.cpp23
-rw-r--r--src/xmpp/xmpp_component.hpp11
6 files changed, 123 insertions, 28 deletions
diff --git a/src/xmpp/adhoc_commands_handler.cpp b/src/xmpp/adhoc_commands_handler.cpp
index e4dcd5c..bb48781 100644
--- a/src/xmpp/adhoc_commands_handler.cpp
+++ b/src/xmpp/adhoc_commands_handler.cpp
@@ -83,7 +83,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co
XmlSubNode next(actions, "next");
}
}
- else if (action == "cancel")
+ else if (session_it != this->sessions.end() && action == "cancel")
{
this->sessions.erase(session_it);
command_node["status"] = "canceled";
diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp
index 60af506..bcdac39 100644
--- a/src/xmpp/biboumi_adhoc_commands.cpp
+++ b/src/xmpp/biboumi_adhoc_commands.cpp
@@ -159,7 +159,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman
{
XmlSubNode value(persistent, "value");
value.set_name("value");
- if (options.col<Database::Persistent>())
+ if (options.col<Database::GlobalPersistent>())
value.set_inner("true");
else
value.set_inner("false");
@@ -193,7 +193,7 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session,
}
else if (field->get_tag("var") == "persistent" &&
value)
- options.col<Database::Persistent>() = to_bool(value->get_inner());
+ options.col<Database::GlobalPersistent>() = to_bool(value->get_inner());
}
options.save(Database::db);
@@ -409,7 +409,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
else if (field->get_tag("var") == "pass" && value)
options.col<Database::Pass>() = value->get_inner();
- else if (field->get_tag("var") == "after_connect_command")
+ else if (field->get_tag("var") == "after_connect_command" && value)
options.col<Database::AfterConnectionCommand>() = value->get_inner();
else if (field->get_tag("var") == "username" && value)
@@ -430,7 +430,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
options.col<Database::EncodingIn>() = value->get_inner();
}
-
+ Database::invalidate_encoding_in_cache();
options.save(Database::db);
command_node.delete_all_children();
@@ -599,7 +599,7 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const
}
}
-
+ Database::invalidate_encoding_in_cache(requester.bare(), iid.get_server(), iid.get_local());
options.save(Database::db);
}
return true;
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index 0e1d270..481ebb9 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -7,6 +7,7 @@
#include <xmpp/adhoc_command.hpp>
#include <xmpp/biboumi_adhoc_commands.hpp>
#include <bridge/list_element.hpp>
+#include <utils/encoding.hpp>
#include <config/config.hpp>
#include <utils/time.hpp>
#include <xmpp/jid.hpp>
@@ -24,6 +25,7 @@
#include <database/database.hpp>
#include <bridge/result_set_management.hpp>
+#include <bridge/history_limit.hpp>
using namespace std::string_literals;
@@ -155,8 +157,32 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
bridge->send_irc_nick_change(iid, to.resource, from.resource);
const XmlNode* x = stanza.get_child("x", MUC_NS);
const XmlNode* password = x ? x->get_child("password", MUC_NS): nullptr;
+ const XmlNode* history = x ? x->get_child("history", MUC_NS): nullptr;
+ HistoryLimit history_limit;
+ if (history)
+ {
+ const auto seconds = history->get_tag("seconds");
+ if (!seconds.empty())
+ {
+ const auto now = std::chrono::system_clock::now();
+ std::time_t timestamp = std::chrono::system_clock::to_time_t(now);
+ int int_seconds = std::atoi(seconds.data());
+ timestamp -= int_seconds;
+ history_limit.since = utils::to_string(timestamp);
+ }
+ const auto since = history->get_tag("since");
+ if (!since.empty())
+ history_limit.since = since;
+ const auto maxstanzas = history->get_tag("maxstanzas");
+ if (!maxstanzas.empty())
+ history_limit.stanzas = std::atoi(maxstanzas.data());
+ // Ignore any other value, because this is too complex to implement,
+ // so I won’t do it.
+ if (history->get_tag("maxchars") == "0")
+ history_limit.stanzas = 0;
+ }
bridge->join_irc_channel(iid, to.resource, password ? password->get_inner(): "",
- from.resource);
+ from.resource, history_limit);
}
else if (type == "unavailable")
{
@@ -281,6 +307,7 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
{
if (body && !body->get_inner().empty())
{
+ const auto fixed_irc_server = Config::get("fixed_irc_server", "");
// a message for nick!server
if (iid.type == Iid::Type::User && !iid.get_local().empty())
{
@@ -296,9 +323,11 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
bridge->set_preferred_from_jid(user_iid.get_local(), to_str);
}
else if (iid.type == Iid::Type::Server)
+ bridge->send_raw_message(iid.get_server(), body->get_inner());
+ else if (iid.type == Iid::Type::None && !fixed_irc_server.empty())
{ // Message sent to the server JID
// Convert the message body into a raw IRC message
- bridge->send_raw_message(iid.get_server(), body->get_inner());
+ bridge->send_raw_message(fixed_irc_server, body->get_inner());
}
}
}
@@ -408,7 +437,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
// Depending on the 'to' jid in the request, we use one adhoc
// command handler or an other
- Iid iid(to.local, {});
+ Iid iid(to.local, {'#', '&'});
AdhocCommandsHandler* adhoc_handler;
if (to.local.empty())
adhoc_handler = &this->adhoc_commands_handler;
@@ -416,8 +445,13 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
{
if (iid.type == Iid::Type::Server)
adhoc_handler = &this->irc_server_adhoc_commands_handler;
- else
+ else if (iid.type == Iid::Type::Channel && to.resource.empty())
adhoc_handler = &this->irc_channel_adhoc_commands_handler;
+ else
+ {
+ error_name = "feature-not-implemented";
+ return;
+ }
}
// Execute the command, if any, and get a result XmlNode that we
// insert in our response
@@ -467,7 +501,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
stanza_error.disable();
}
}
- else if (iid.type == Iid::Type::Channel)
+ else if (iid.type == Iid::Type::Channel && to.resource.empty())
{
if (node.empty())
{
@@ -526,7 +560,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
this->irc_server_adhoc_commands_handler);
stanza_error.disable();
}
- else if (iid.type == Iid::Type::Channel)
+ else if (iid.type == Iid::Type::Channel && to.resource.empty())
{ // Get the channel's adhoc commands
this->send_adhoc_commands_list(id, from, to_str,
(Config::get("admin", "") ==
@@ -534,6 +568,8 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
this->irc_channel_adhoc_commands_handler);
stanza_error.disable();
}
+ else // “to” is a MUC user, not the room itself
+ error_name = "feature-not-implemented";
}
else if (node.empty() && iid.type == Iid::Type::Server)
{ // Disco on an IRC server: get the list of channels
@@ -685,19 +721,46 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
if (max)
limit = std::atoi(max->get_inner().data());
}
- // If the archive is really big, and the client didn’t specify any
- // limit, we avoid flooding it: we set an arbitrary max limit.
- if (limit == -1 && start.empty() && end.empty())
+ // Do send more than 100 messages, even if the client asked for more,
+ // or if it didn’t specify any limit.
+ // 101 is just a trick to know if there are more available messages.
+ // If our query returns 101 message, we know it’s incomplete, but we
+ // still send only 100
+ if ((limit == -1 && start.empty() && end.empty())
+ || limit > 100)
+ limit = 101;
+ auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end);
+ bool complete = true;
+ if (lines.size() > 100)
{
- limit = 100;
+ complete = false;
+ lines.erase(lines.begin(), std::prev(lines.end(), 100));
}
- const auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end);
for (const Database::MucLogLine& line: lines)
{
if (!line.col<Database::Nick>().empty())
this->send_archived_message(line, to.full(), from.full(), query_id);
}
- this->send_iq_result_full_jid(id, from.full(), to.full());
+ {
+ auto fin_ptr = std::make_unique<XmlNode>("fin");
+ {
+ XmlNode& fin = *(fin_ptr.get());
+ fin["xmlns"] = MAM_NS;
+ if (complete)
+ fin["complete"] = "true";
+ XmlSubNode set(fin, "set");
+ set["xmlns"] = RSM_NS;
+ if (!lines.empty())
+ {
+ XmlSubNode first(set, "first");
+ first["index"] = "0";
+ first.set_inner(lines[0].col<Database::Uuid>());
+ XmlSubNode last(set, "last");
+ last.set_inner(lines[lines.size() - 1].col<Database::Uuid>());
+ }
+ }
+ this->send_iq_result_full_jid(id, from.full(), to.full(), std::move(fin_ptr));
+ }
return true;
}
return false;
@@ -739,7 +802,7 @@ bool BiboumiComponent::handle_room_configuration_form_request(const std::string&
{
Iid iid(to.local, {'#', '&'});
- if (iid.type != Iid::Type::Channel)
+ if (iid.type != Iid::Type::Channel || !to.resource.empty())
return false;
Stanza iq("iq");
@@ -761,7 +824,7 @@ bool BiboumiComponent::handle_room_configuration_form(const XmlNode& query, cons
{
Iid iid(to.local, {'#', '&'});
- if (iid.type != Iid::Type::Channel)
+ if (iid.type != Iid::Type::Channel || !to.resource.empty())
return false;
Jid requester(from);
@@ -958,7 +1021,9 @@ void BiboumiComponent::send_iq_room_list_result(const std::string& id, const std
for (auto it = begin; it != end; ++it)
{
XmlSubNode item(query, "item");
- item["jid"] = it->channel + "@" + this->served_hostname;
+ std::string channel_name = it->channel;
+ xep0106::encode(channel_name);
+ item["jid"] = channel_name + "@" + this->served_hostname;
}
if ((rs_info.max >= 0 || !rs_info.after.empty() || !rs_info.before.empty()))
@@ -1052,6 +1117,9 @@ void BiboumiComponent::on_irc_client_connected(const std::string& irc_hostname,
const auto local_jid = irc_hostname + "@" + this->served_hostname;
if (Database::has_roster_item(local_jid, jid))
this->send_presence_to_contact(local_jid, jid, "");
+#else
+ (void)irc_hostname;
+ (void)jid;
#endif
}
@@ -1061,6 +1129,9 @@ void BiboumiComponent::on_irc_client_disconnected(const std::string& irc_hostnam
const auto local_jid = irc_hostname + "@" + this->served_hostname;
if (Database::has_roster_item(local_jid, jid))
this->send_presence_to_contact(irc_hostname + "@" + this->served_hostname, jid, "unavailable");
+#else
+ (void)irc_hostname;
+ (void)jid;
#endif
}
diff --git a/src/xmpp/body.hpp b/src/xmpp/body.hpp
index 068d1a4..f693cdd 100644
--- a/src/xmpp/body.hpp
+++ b/src/xmpp/body.hpp
@@ -1,5 +1,9 @@
#pragma once
+#include <tuple>
+#include <memory>
+
+class XmlNode;
namespace Xmpp
{
diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp
index 42a5392..9be9e34 100644
--- a/src/xmpp/xmpp_component.cpp
+++ b/src/xmpp/xmpp_component.cpp
@@ -269,7 +269,8 @@ void* XmppComponent::get_receive_buffer(const size_t size) const
}
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)
+ const std::string& type, const bool fulljid, const bool nocopy,
+ const bool muc_private)
{
Stanza message("message");
{
@@ -277,7 +278,12 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con
if (fulljid)
message["from"] = from;
else
- message["from"] = from + "@" + this->served_hostname;
+ {
+ if (!from.empty())
+ message["from"] = from + "@" + this->served_hostname;
+ else
+ message["from"] = this->served_hostname;
+ }
if (!type.empty())
message["type"] = type;
XmlSubNode body_node(message, "body");
@@ -296,6 +302,11 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con
XmlSubNode nocopy(message, "no-copy");
nocopy["xmlns"] = "urn:xmpp:hints";
}
+ if (muc_private)
+ {
+ XmlSubNode x(message, "x");
+ x["xmlns"] = MUC_USER_NS;
+ }
}
this->send_stanza(message);
}
@@ -387,7 +398,8 @@ 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)
+#ifdef USE_DATABASE
+void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, Database::time_point::rep timestamp)
{
Stanza message("message");
message["to"] = jid_to;
@@ -410,6 +422,7 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std:
this->send_stanza(message);
}
+#endif
void XmppComponent::send_muc_leave(const std::string& muc_name, const std::string& nick, Xmpp::body&& message,
const std::string& jid_to, const bool self, const bool user_requested)
@@ -629,13 +642,15 @@ 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)
+void XmppComponent::send_iq_result_full_jid(const std::string& id, const std::string& to_jid, const std::string& from_full_jid, std::unique_ptr<XmlNode> inner)
{
Stanza iq("iq");
iq["from"] = from_full_jid;
iq["to"] = to_jid;
iq["id"] = id;
iq["type"] = "result";
+ if (inner)
+ iq.add_child(std::move(inner));
this->send_stanza(iq);
}
diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp
index 22d5c48..1daa6fb 100644
--- a/src/xmpp/xmpp_component.hpp
+++ b/src/xmpp/xmpp_component.hpp
@@ -1,8 +1,10 @@
#pragma once
+#include "biboumi.h"
#include <xmpp/adhoc_commands_handler.hpp>
#include <network/tcp_client_socket_handler.hpp>
+#include <database/database.hpp>
#include <xmpp/xmpp_parser.hpp>
#include <xmpp/body.hpp>
@@ -112,7 +114,8 @@ public:
* 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, const bool nocopy=false);
+ const std::string& type, const bool fulljid, const bool nocopy=false,
+ const bool muc_private=false);
/**
* Send a join from a new participant
*/
@@ -132,11 +135,13 @@ public:
*/
void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to,
std::string uuid);
+#ifdef USE_DATABASE
/**
* 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);
+ const std::string& jid_to, Database::time_point::rep timestamp);
+#endif
/**
* Send an unavailable presence for this nick
*/
@@ -202,7 +207,7 @@ public:
*/
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);
+ const std::string& from_full_jid, std::unique_ptr<XmlNode> inner=nullptr);
void handle_handshake(const Stanza& stanza);
void handle_error(const Stanza& stanza);