summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.rst1
-rw-r--r--louloulibs/xmpp/xmpp_component.hpp1
-rw-r--r--src/database/database.cpp32
-rw-r--r--src/database/database.hpp2
-rw-r--r--src/xmpp/biboumi_component.cpp37
-rw-r--r--tests/end_to_end/__main__.py26
6 files changed, 82 insertions, 17 deletions
diff --git a/README.rst b/README.rst
index 054ff75..ee41c81 100644
--- a/README.rst
+++ b/README.rst
@@ -29,6 +29,7 @@ Usage
-----
Read `the documentation`_.
+
Authors
-------
Florent Le Coz (louiz’) <louiz@louiz.org>
diff --git a/louloulibs/xmpp/xmpp_component.hpp b/louloulibs/xmpp/xmpp_component.hpp
index 8359d05..b556ce2 100644
--- a/louloulibs/xmpp/xmpp_component.hpp
+++ b/louloulibs/xmpp/xmpp_component.hpp
@@ -30,6 +30,7 @@
#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"
/**
* An XMPP component, communicating with an XMPP server using the protocole
diff --git a/src/database/database.cpp b/src/database/database.cpp
index be0da8e..e995d95 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -6,6 +6,7 @@
#include <irc/iid.hpp>
#include <uuid.h>
#include <utils/get_first_non_empty.hpp>
+#include <utils/time.hpp>
using namespace std::string_literals;
@@ -136,14 +137,30 @@ void Database::store_muc_message(const std::string& owner, const Iid& iid,
line.update();
}
-std::vector<db::MucLogLine> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit)
+std::vector<db::MucLogLine> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server,
+ int limit, const std::string& start, const std::string& end)
{
- if (limit == -1)
- limit = 1024;
- const auto& res = litesql::select<db::MucLogLine>(*Database::db,
- db::MucLogLine::Owner == owner &&
- db::MucLogLine::IrcChanName == chan_name &&
- db::MucLogLine::IrcServerName == server).orderBy(db::MucLogLine::Id, false).limit(limit).all();
+ auto request = litesql::select<db::MucLogLine>(*Database::db,
+ db::MucLogLine::Owner == owner &&
+ db::MucLogLine::IrcChanName == chan_name &&
+ db::MucLogLine::IrcServerName == server);
+ request.orderBy(db::MucLogLine::Id, false);
+
+ if (limit >= 0)
+ request.limit(limit);
+ if (!start.empty())
+ {
+ const auto start_time = utils::parse_datetime(start);
+ if (start_time != -1)
+ request.where(db::MucLogLine::Date >= start_time);
+ }
+ if (!end.empty())
+ {
+ const auto end_time = utils::parse_datetime(end);
+ if (end_time != -1)
+ request.where(db::MucLogLine::Date <= end_time);
+ }
+ const auto& res = request.all();
return {res.crbegin(), res.crend()};
}
@@ -152,7 +169,6 @@ void Database::close()
Database::db.reset(nullptr);
}
-
std::string Database::gen_uuid()
{
char uuid_str[37];
diff --git a/src/database/database.hpp b/src/database/database.hpp
index e7fdd5f..6823574 100644
--- a/src/database/database.hpp
+++ b/src/database/database.hpp
@@ -49,7 +49,7 @@ public:
const std::string& server,
const std::string& channel);
static std::vector<db::MucLogLine> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server,
- int limit);
+ int limit=-1, const std::string& before="", const std::string& after="");
static void store_muc_message(const std::string& owner, const Iid& iid,
time_point date, const std::string& body, const std::string& nick);
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index a49f52e..a2fda60 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -550,13 +550,36 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
Iid iid(to.local, {'#', '&'});
if (iid.type == Iid::Type::Channel && to.resource.empty())
{
- const auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), -1);
- for (const db::MucLogLine& line: lines)
- {
- const auto queryid = query->get_tag("queryid");
- if (!line.nick.value().empty())
- this->send_archived_message(line, to.full(), from.full(), queryid);
- }
+ std::string start;
+ std::string end;
+ const XmlNode* x = query->get_child("x", DATAFORM_NS);
+ if (x)
+ {
+ const XmlNode* value;
+ const auto fields = x->get_children("field", DATAFORM_NS);
+ for (const auto& field: fields)
+ {
+ if (field->get_tag("var") == "start")
+ {
+ value = field->get_child("value", DATAFORM_NS);
+ if (value)
+ start = value->get_inner();
+ }
+ else if (field->get_tag("var") == "end")
+ {
+ value = field->get_child("value", DATAFORM_NS);
+ if (value)
+ end = value->get_inner();
+ }
+ }
+ }
+ const auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), -1, start, end);
+ for (const db::MucLogLine& line: lines)
+ {
+ const auto queryid = query->get_tag("queryid");
+ if (!line.nick.value().empty())
+ this->send_archived_message(line, to.full(), from.full(), queryid);
+ }
this->send_iq_result_full_jid(id, from.full(), to.full());
return true;
}
diff --git a/tests/end_to_end/__main__.py b/tests/end_to_end/__main__.py
index 57e91c9..e1779de 100644
--- a/tests/end_to_end/__main__.py
+++ b/tests/end_to_end/__main__.py
@@ -1086,8 +1086,32 @@ if __name__ == '__main__':
),
partial(expect_stanza,
- "/iq[@type='result'][@id='id1'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']")
+ "/iq[@type='result'][@id='id1'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']"),
+ # Retrieve an empty archive by specifying an early “end” date
+ partial(send_stanza, """<iq to='#foo%{irc_server_one}' from='{jid_one}/{resource_one}' type='set' id='id2'>
+ <query xmlns='urn:xmpp:mam:1' queryid='qid2'>
+ <x xmlns='jabber:x:data' type='submit'>
+ <field var='FORM_TYPE' type='hidden'> <value>urn:xmpp:mam:1</value></field>
+ <field var='end'><value>2000-06-07T00:00:00Z</value></field>
+ </x>
+ </query></iq>"""),
+
+ partial(expect_stanza,
+ "/iq[@type='result'][@id='id2'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']"),
+
+ # Retrieve an empty archive by specifying a late “start” date
+ # (note that this test will break in ~1000 years)
+ partial(send_stanza, """<iq to='#foo%{irc_server_one}' from='{jid_one}/{resource_one}' type='set' id='id3'>
+ <query xmlns='urn:xmpp:mam:1' queryid='qid3'>
+ <x xmlns='jabber:x:data' type='submit'>
+ <field var='FORM_TYPE' type='hidden'> <value>urn:xmpp:mam:1</value></field>
+ <field var='start'><value>3016-06-07T00:00:00Z</value></field>
+ </x>
+ </query></iq>"""),
+
+ partial(expect_stanza,
+ "/iq[@type='result'][@id='id3'][@from='#foo%{irc_server_one}'][@to='{jid_one}/{resource_one}']"),
]),
)