File

plugins/archive.lua @ 445:b119dc4d8bc2

plugins.smacks: Don't warn about zero stanzas acked It's only if the count somehow goes backwards that something is really wrong. An ack for zero stanzas is fine and we don't need to do anything.
author Kim Alvefur <zash@zash.se>
date Thu, 10 Jun 2021 11:58:23 +0200
parent 428:bde804b01f28
child 457:73d4eb93657b
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 uuid = require "util.uuid".generate;
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 = uuid();
		local query_st = st.iq{ 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
				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