Software /
code /
verse
File
plugins/archive.lua @ 485:c9a144591649
component: Avoid adding to the global stream metatable
This allows component and client connections to be made side-by-side.
Previous to this change, loading this connection module would break the
ability to make client connections, due to overriding stream methods such as
:reopen() and :reset().
A next step would be to share the methods that the two connection modules have
in common.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Thu, 23 Mar 2023 18:56:32 +0000 |
parent | 462:51c3da615ff4 |
child | 490:6b2f31da9610 |
line wrap: on
line source
-- This implements XEP-0313: Message Archive Management -- http://xmpp.org/extensions/xep-0313.html -- (ie not XEP-0136) local verse = require "verse"; local st = require "util.stanza"; local xmlns_mam = "urn:xmpp:mam:2" local xmlns_forward = "urn:xmpp:forward:0"; local xmlns_delay = "urn:xmpp:delay"; local new_id = require "util.id".short; local parse_datetime = require "util.datetime".parse; local datetime = require "util.datetime".datetime; local dataform = require"util.dataforms".new; local rsm = require "util.rsm"; local NULL = {}; local query_form = dataform { { name = "FORM_TYPE"; type = "hidden"; value = xmlns_mam; }; { name = "with"; type = "jid-single"; }; { name = "start"; type = "text-single" }; { name = "end"; type = "text-single"; }; }; function verse.plugins.archive(stream) function stream:query_archive(where, query_params, callback) local queryid = new_id(); local query_st = st.iq{ id = queryid, type="set", to = where } :tag("query", { xmlns = xmlns_mam, queryid = queryid }); local qstart, qend = tonumber(query_params["start"]), tonumber(query_params["end"]); query_params["start"] = qstart and datetime(qstart); query_params["end"] = qend and datetime(qend); query_st:add_child(query_form:form(query_params, "submit")); -- query_st:up(); query_st:add_child(rsm.generate(query_params)); local results = {}; local function handle_archived_message(message) local result_tag = message:get_child("result", xmlns_mam); if result_tag and result_tag.attr.queryid == queryid then local forwarded = result_tag:get_child("forwarded", xmlns_forward); local id = result_tag.attr.id; local delay = forwarded:get_child("delay", xmlns_delay); local stamp = delay and parse_datetime(delay.attr.stamp) or nil; local message = forwarded:get_child("message", "jabber:client") results[#results+1] = { id = id, stamp = stamp, message = message }; return true end end self:hook("message", handle_archived_message, 1); self:send_iq(query_st, function(reply) self:unhook("message", handle_archived_message); if reply.attr.type == "error" then self:warn(table.concat({reply:get_error()}, " ")) callback(false, reply:get_error()) return true; end local finished = reply:get_child("fin", xmlns_mam) if finished then results.complete = finished.attr.complete == "true" or finished.attr.complete == "1"; local rset = rsm.get(finished); for k,v in pairs(rset or NULL) do results[k]=v; end end callback(results); return true end); end local default_attrs = { always = true, [true] = "always", never = false, [false] = "never", roster = "roster", } local function prefs_decode(stanza) -- from XML local prefs = {}; local default = stanza.attr.default; if default then prefs[false] = default_attrs[default]; end local always = stanza:get_child("always"); if always then for rule in always:childtags("jid") do local jid = rule:get_text(); prefs[jid] = true; end end local never = stanza:get_child("never"); if never then for rule in never:childtags("jid") do local jid = rule:get_text(); prefs[jid] = false; end end return prefs; end local function prefs_encode(prefs) -- into XML local default default, prefs[false] = prefs[false], nil; if default ~= nil then default = default_attrs[default]; end local reply = st.stanza("prefs", { xmlns = xmlns_mam, default = default }) local always = st.stanza("always"); local never = st.stanza("never"); for k,v in pairs(prefs) do (v and always or never):tag("jid"):text(k):up(); end return reply:add_child(always):add_child(never); end function stream:archive_prefs_get(callback) self:send_iq(st.iq{ type="get" }:tag("prefs", { xmlns = xmlns_mam }), function(result) if result and result.attr.type == "result" and result.tags[1] then local prefs = prefs_decode(result.tags[1]); callback(prefs, result); else callback(nil, result); end end); end function stream:archive_prefs_set(prefs, callback) self:send_iq(st.iq{ type="set" }:add_child(prefs_encode(prefs)), callback); end end