| 1 | -- This implements XEP-0313: Message Archive Management |
| 2 | -- http://xmpp.org/extensions/xep-0313.html |
| 3 | -- (ie not XEP-0136) |
| 4 | |
| 5 | local verse = require "verse"; |
| 6 | local st = require "prosody.util.stanza"; |
| 7 | local xmlns_mam = "urn:xmpp:mam:2" |
| 8 | local xmlns_forward = "urn:xmpp:forward:0"; |
| 9 | local xmlns_delay = "urn:xmpp:delay"; |
| 10 | local new_id = require "prosody.util.id".short; |
| 11 | local parse_datetime = require "prosody.util.datetime".parse; |
| 12 | local datetime = require "prosody.util.datetime".datetime; |
| 13 | local dataform = require"prosody.util.dataforms".new; |
| 14 | local rsm = require "prosody.util.rsm"; |
| 15 | local NULL = {}; |
| 16 | |
| 17 | local query_form = dataform { |
| 18 | { name = "FORM_TYPE"; type = "hidden"; value = xmlns_mam; }; |
| 19 | { name = "with"; type = "jid-single"; }; |
| 20 | { name = "start"; type = "text-single" }; |
| 21 | { name = "end"; type = "text-single"; }; |
| 22 | }; |
| 23 | |
| 24 | function verse.plugins.archive(stream) |
| 25 | function stream:query_archive(where, query_params, callback) |
| 26 | local queryid = new_id(); |
| 27 | local query_st = st.iq{ id = queryid, type="set", to = where } |
| 28 | :tag("query", { xmlns = xmlns_mam, queryid = queryid }); |
| 29 | |
| 30 | |
| 31 | local qstart, qend = tonumber(query_params["start"]), tonumber(query_params["end"]); |
| 32 | query_params["start"] = qstart and datetime(qstart); |
| 33 | query_params["end"] = qend and datetime(qend); |
| 34 | |
| 35 | query_st:add_child(query_form:form(query_params, "submit")); |
| 36 | -- query_st:up(); |
| 37 | query_st:add_child(rsm.generate(query_params)); |
| 38 | |
| 39 | local results = {}; |
| 40 | local function handle_archived_message(message) |
| 41 | |
| 42 | local result_tag = message:get_child("result", xmlns_mam); |
| 43 | if result_tag and result_tag.attr.queryid == queryid then |
| 44 | local forwarded = result_tag:get_child("forwarded", xmlns_forward); |
| 45 | |
| 46 | local id = result_tag.attr.id; |
| 47 | local delay = forwarded:get_child("delay", xmlns_delay); |
| 48 | local stamp = delay and parse_datetime(delay.attr.stamp) or nil; |
| 49 | |
| 50 | local message = forwarded:get_child("message", "jabber:client") |
| 51 | |
| 52 | results[#results+1] = { id = id, stamp = stamp, message = message }; |
| 53 | return true |
| 54 | end |
| 55 | end |
| 56 | |
| 57 | self:hook("message", handle_archived_message, 1); |
| 58 | self:send_iq(query_st, function(reply) |
| 59 | self:unhook("message", handle_archived_message); |
| 60 | if reply.attr.type == "error" then |
| 61 | self:warn(table.concat({reply:get_error()}, " ")) |
| 62 | callback(false, reply:get_error()) |
| 63 | return true; |
| 64 | end |
| 65 | local finished = reply:get_child("fin", xmlns_mam) |
| 66 | if finished then |
| 67 | results.complete = finished.attr.complete == "true" or finished.attr.complete == "1"; |
| 68 | local rset = rsm.get(finished); |
| 69 | for k,v in pairs(rset or NULL) do results[k]=v; end |
| 70 | end |
| 71 | callback(results); |
| 72 | return true |
| 73 | end); |
| 74 | end |
| 75 | |
| 76 | local default_attrs = { |
| 77 | always = true, [true] = "always", |
| 78 | never = false, [false] = "never", |
| 79 | roster = "roster", |
| 80 | } |
| 81 | |
| 82 | local function prefs_decode(stanza) -- from XML |
| 83 | local prefs = {}; |
| 84 | local default = stanza.attr.default; |
| 85 | |
| 86 | if default then |
| 87 | prefs[false] = default_attrs[default]; |
| 88 | end |
| 89 | |
| 90 | local always = stanza:get_child("always"); |
| 91 | if always then |
| 92 | for rule in always:childtags("jid") do |
| 93 | local jid = rule:get_text(); |
| 94 | prefs[jid] = true; |
| 95 | end |
| 96 | end |
| 97 | |
| 98 | local never = stanza:get_child("never"); |
| 99 | if never then |
| 100 | for rule in never:childtags("jid") do |
| 101 | local jid = rule:get_text(); |
| 102 | prefs[jid] = false; |
| 103 | end |
| 104 | end |
| 105 | return prefs; |
| 106 | end |
| 107 | |
| 108 | local function prefs_encode(prefs) -- into XML |
| 109 | local default |
| 110 | default, prefs[false] = prefs[false], nil; |
| 111 | if default ~= nil then |
| 112 | default = default_attrs[default]; |
| 113 | end |
| 114 | local reply = st.stanza("prefs", { xmlns = xmlns_mam, default = default }) |
| 115 | local always = st.stanza("always"); |
| 116 | local never = st.stanza("never"); |
| 117 | for k,v in pairs(prefs) do |
| 118 | (v and always or never):tag("jid"):text(k):up(); |
| 119 | end |
| 120 | return reply:add_child(always):add_child(never); |
| 121 | end |
| 122 | |
| 123 | function stream:archive_prefs_get(callback) |
| 124 | self:send_iq(st.iq{ type="get" }:tag("prefs", { xmlns = xmlns_mam }), |
| 125 | function(result) |
| 126 | if result and result.attr.type == "result" and result.tags[1] then |
| 127 | local prefs = prefs_decode(result.tags[1]); |
| 128 | callback(prefs, result); |
| 129 | else |
| 130 | callback(nil, result); |
| 131 | end |
| 132 | end); |
| 133 | end |
| 134 | |
| 135 | function stream:archive_prefs_set(prefs, callback) |
| 136 | self:send_iq(st.iq{ type="set" }:add_child(prefs_encode(prefs)), callback); |
| 137 | end |
| 138 | end |