summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlouiz’ <louiz@louiz.org>2017-08-27 22:30:44 +0200
committerlouiz’ <louiz@louiz.org>2017-08-27 22:37:46 +0200
commitfcaffb9e778ad5962e69dc23c1fc91eb59a27945 (patch)
tree99c8270467b67b2dab90235c3ff1147daf1b9422 /src
parent25243f53c2479e2fda0f1a05d1589c8214b70b4b (diff)
downloadbiboumi-fcaffb9e778ad5962e69dc23c1fc91eb59a27945.tar.gz
biboumi-fcaffb9e778ad5962e69dc23c1fc91eb59a27945.tar.bz2
biboumi-fcaffb9e778ad5962e69dc23c1fc91eb59a27945.tar.xz
biboumi-fcaffb9e778ad5962e69dc23c1fc91eb59a27945.zip
Add support for the "history" node on MUC join
Supports the "seconds", "maxstanzas", "since" and "maxchars" (but only =0) attributes. fix #3270
Diffstat (limited to 'src')
-rw-r--r--src/bridge/bridge.cpp16
-rw-r--r--src/bridge/bridge.hpp7
-rw-r--r--src/bridge/history_limit.hpp8
-rw-r--r--src/irc/irc_client.cpp2
-rw-r--r--src/irc/irc_client.hpp7
-rw-r--r--src/xmpp/biboumi_component.cpp28
6 files changed, 57 insertions, 11 deletions
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp
index b1685e0..3bc618f 100644
--- a/src/bridge/bridge.cpp
+++ b/src/bridge/bridge.cpp
@@ -167,10 +167,11 @@ IrcClient* Bridge::find_irc_client(const std::string& hostname) const
}
bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password,
- const std::string& resource)
+ const std::string& resource, HistoryLimit history_limit)
{
const auto& hostname = iid.get_server();
IrcClient* irc = this->make_irc_client(hostname, nickname);
+ irc->history_limit = history_limit;
this->add_resource_to_server(hostname, resource);
auto res_in_chan = this->is_resource_in_chan(ChannelKey{iid.get_local(), hostname}, resource);
if (!res_in_chan)
@@ -993,17 +994,20 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam
}
-void Bridge::send_room_history(const std::string& hostname, const std::string& chan_name)
+void Bridge::send_room_history(const std::string& hostname, const std::string& chan_name, const HistoryLimit& history_limit)
{
for (const auto& resource: this->resources_in_chan[ChannelKey{chan_name, hostname}])
- this->send_room_history(hostname, chan_name, resource);
+ this->send_room_history(hostname, chan_name, resource, history_limit);
}
-void Bridge::send_room_history(const std::string& hostname, std::string chan_name, const std::string& resource)
+void Bridge::send_room_history(const std::string& hostname, std::string chan_name, const std::string& resource, const HistoryLimit& history_limit)
{
#ifdef USE_DATABASE
const auto coptions = Database::get_irc_channel_options_with_server_and_global_default(this->user_jid, hostname, chan_name);
- const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, coptions.col<Database::MaxHistoryLength>());
+ auto limit = coptions.col<Database::MaxHistoryLength>();
+ if (history_limit.stanzas >= 0 && history_limit.stanzas < limit)
+ limit = history_limit.stanzas;
+ const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since);
chan_name.append(utils::empty_if_fixed_server("%" + hostname));
for (const auto& line: lines)
{
@@ -1257,7 +1261,7 @@ void Bridge::generate_channel_join_for_resource(const Iid& iid, const std::strin
this->send_user_join(iid.get_server(), iid.get_encoded_local(),
self, self->get_most_significant_mode(irc->get_sorted_user_modes()),
true, resource);
- this->send_room_history(iid.get_server(), iid.get_local(), resource);
+ this->send_room_history(iid.get_server(), iid.get_local(), resource, irc->history_limit);
this->send_topic(iid.get_server(), iid.get_encoded_local(), channel->topic, channel->topic_author, resource);
}
diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp
index c10631b..c2f0233 100644
--- a/src/bridge/bridge.hpp
+++ b/src/bridge/bridge.hpp
@@ -2,6 +2,7 @@
#include <bridge/result_set_management.hpp>
#include <bridge/list_element.hpp>
+#include <bridge/history_limit.hpp>
#include <irc/irc_message.hpp>
#include <irc/irc_client.hpp>
@@ -74,7 +75,7 @@ public:
* Try to join an irc_channel, does nothing and return true if the channel
* was already joined.
*/
- bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, const std::string& resource);
+ bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit);
void send_channel_message(const Iid& iid, const std::string& body);
void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG");
@@ -156,8 +157,8 @@ public:
/**
* Send the MUC history to the user
*/
- void send_room_history(const std::string& hostname, const std::string& chan_name);
- void send_room_history(const std::string& hostname, std::string chan_name, const std::string& resource);
+ void send_room_history(const std::string& hostname, const std::string& chan_name, const HistoryLimit& history_limit);
+ void send_room_history(const std::string& hostname, std::string chan_name, const std::string& resource, const HistoryLimit& history_limit);
/**
* Send a MUC message from some participant
*/
diff --git a/src/bridge/history_limit.hpp b/src/bridge/history_limit.hpp
new file mode 100644
index 0000000..9c75256
--- /dev/null
+++ b/src/bridge/history_limit.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+// Default values means no limit
+struct HistoryLimit
+{
+ int stanzas{-1};
+ std::string since{};
+};
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index 7776c8d..5f26bf0 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -784,7 +784,7 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message)
channel->joined = true;
this->bridge.send_user_join(this->hostname, chan_name, channel->get_self(),
channel->get_self()->get_most_significant_mode(this->sorted_user_modes), true);
- this->bridge.send_room_history(this->hostname, chan_name);
+ this->bridge.send_room_history(this->hostname, chan_name, this->history_limit);
this->bridge.send_topic(this->hostname, chan_name, channel->topic, channel->topic_author);
}
diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp
index aec6cd9..de5c520 100644
--- a/src/irc/irc_client.hpp
+++ b/src/irc/irc_client.hpp
@@ -5,6 +5,8 @@
#include <irc/irc_channel.hpp>
#include <irc/iid.hpp>
+#include <bridge/history_limit.hpp>
+
#include <network/tcp_client_socket_handler.hpp>
#include <network/resolver.hpp>
@@ -296,6 +298,11 @@ public:
const std::vector<char>& get_sorted_user_modes() const { return this->sorted_user_modes; }
std::set<char> get_chantypes() const { return this->chantypes; }
+
+ /**
+ * Store the history limit that the client asked when joining this room.
+ */
+ HistoryLimit history_limit;
private:
/**
* The hostname of the server we are connected to.
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index 6cddeb4..7c5b059 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -24,6 +24,7 @@
#include <database/database.hpp>
#include <bridge/result_set_management.hpp>
+#include <bridge/history_limit.hpp>
using namespace std::string_literals;
@@ -155,8 +156,33 @@ 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)
+ {
+ // TODO implement the "seconds"
+ 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")
{