--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_map/README.markdown Mon Feb 25 15:52:46 2019 +0100
@@ -0,0 +1,52 @@
+---
+labels:
+- 'Stage-Experimental'
+summary: Prototype MAM summary
+---
+
+This is a prototype for an experimental archive summary API recently
+added in [Prosody trunk](https://hg.prosody.im/trunk/rev/2c5546cc5c70).
+
+# Protocol
+
+::: {.alert .alert-danger}
+This is not a finished protocol, but a prototype meant for testing.
+:::
+
+A basic query:
+
+``` {.xml}
+<iq id="lx7" type="get">
+ <summary xmlns="xmpp:prosody.im/mod_map"/>
+</iq>
+```
+
+Answered like:
+
+``` {.xml}
+<?xml version="1.0"?>
+<iq type="result" id="lx7">
+ <summary xmlns="xmpp:prosody.im/mod_map">
+ <item jid="juliet@capulet.lit">
+ <count>3</count>
+ </item>
+ </summary>
+</iq>
+```
+
+It can also take dataform and RSM parameters similar to a [filtered MAM
+query](https://xmpp.org/extensions/xep-0313.html#filter).
+
+E.g if the last message you received had an id `09af3-cc343-b409f` then
+the following query would tell you who sent you messages since:
+
+``` {.xml}
+<iq id="lx8" type="get">
+ <summary xmlns="xmpp:prosody.im/mod_map">
+ <set xmlns="http://jabber.org/protocol/rsm">
+ <max>10</max>
+ <after>09af3-cc343-b409f</after>
+ </set>
+ </summary>
+</iq>
+```
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_map/mod_map.lua Mon Feb 25 15:52:46 2019 +0100
@@ -0,0 +1,67 @@
+
+local st = require "util.stanza";
+local jid_bare = require "util.jid".bare;
+local rsm = require "util.rsm";
+local dataform = require "util.dataforms".new;
+
+local archive = module:open_store("archive", "archive");
+
+local query_form = dataform {
+ { name = "with"; type = "jid-single"; };
+ { name = "start"; type = "text-single" };
+ { name = "end"; type = "text-single"; };
+};
+
+if not archive.summary then
+ module:log("error", "The archive:summary() API is not supported by %s", archive._provided_by);
+ return
+end
+
+module:hook("iq-get/self/xmpp:prosody.im/mod_map:summary", function(event)
+ local origin, stanza = event.origin, event.stanza;
+
+ local query = stanza.tags[1];
+
+ -- Search query parameters
+ local qwith, qstart, qend;
+ local form = query:get_child("x", "jabber:x:data");
+ if form then
+ local err;
+ form, err = query_form:data(form);
+ if err then
+ origin.send(st.error_reply(stanza, "modify", "bad-request", select(2, next(err))));
+ return true;
+ end
+ qwith, qstart, qend = form["with"], form["start"], form["end"];
+ qwith = qwith and jid_bare(qwith); -- dataforms does jidprep
+ end
+
+ local qset = rsm.get(query);
+ local qmax = qset and qset.max;
+ local before, after = qset and qset.before, qset and qset.after;
+ if type(before) ~= "string" then before = nil; end
+
+ local summary = archive:summary(origin.username, {
+ start = qstart; ["end"] = qend; -- Time range
+ with = qwith;
+ limit = qmax;
+ before = before; after = after;
+ });
+ if not summary then
+ module:send(st.error_reply(stanza, "wait", "internal-server-error"));
+ return true;
+ end
+
+ local reply = st.reply(stanza);
+ reply:tag("summary", { xmlns = "xmpp:prosody.im/mod_map" });
+ for jid, count in pairs(summary) do
+ reply:tag("item", { jid = jid });
+ if type(count) == "number" then
+ reply:text_tag("count", ("%d"):format(count));
+ end
+ reply:up();
+ end
+
+ module:send(reply);
+ return true;
+end);