File

plugins/adhoc/adhoc.lib.lua @ 13262:9a86e7cbdd79

mod_storage_internal: Fix fast trimming of archive with exactly one item This method would previously never delete the first (and only) item since it works out which item should become the first item after the trim operation, which doesn't make sense when all should be removed. This also works as an optimization for when all the last item should be trimmed, thus items should be removed.
author Kim Alvefur <zash@zash.se>
date Sun, 24 Sep 2023 13:41:54 +0200
parent 13020:3174308d127e
line wrap: on
line source

-- Copyright (C) 2009-2010 Florian Zeitz
--
-- This file is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--

local st, uuid = require "prosody.util.stanza", require "prosody.util.uuid";

local xmlns_cmd = "http://jabber.org/protocol/commands";

local states = {}

local _M = {};

local function _cmdtag(desc, status, sessionid, action)
	local cmd = st.stanza("command", { xmlns = xmlns_cmd, node = desc.node, status = status });
	if sessionid then cmd.attr.sessionid = sessionid; end
	if action then cmd.attr.action = action; end

	return cmd;
end

function _M.new(name, node, handler, permission)
	if not permission then
		error "adhoc.new() expects a permission argument, none given"
	elseif permission == "user" then
		error "the permission mode 'user' has been renamed 'any', please update your code"
	end
	if permission == "admin" then
		module:default_permission("prosody:admin", "adhoc:"..node);
		permission = "check";
	elseif permission == "global_admin" then
		module:default_permission("prosody:operator", "adhoc:"..node);
		permission = "check";
	end
	return { name = name, node = node, handler = handler, cmdtag = _cmdtag, permission = permission };
end

function _M.handle_cmd(command, origin, stanza)
	local cmdtag = stanza.tags[1]
	local sessionid = cmdtag.attr.sessionid or uuid.generate();
	local dataIn = {
		origin = origin;
		stanza = stanza;
		to = stanza.attr.to;
		from = stanza.attr.from;
		action = cmdtag.attr.action or "execute";
		form = cmdtag:get_child("x", "jabber:x:data");
	};

	local data, state = command:handler(dataIn, states[sessionid]);
	states[sessionid] = state;
	local cmdreply;
	if data.status == "completed" then
		states[sessionid] = nil;
		cmdreply = command:cmdtag("completed", sessionid);
	elseif data.status == "canceled" then
		states[sessionid] = nil;
		cmdreply = command:cmdtag("canceled", sessionid);
	elseif data.status == "error" then
		states[sessionid] = nil;
		local reply = st.error_reply(stanza, data.error);
		origin.send(reply);
		return true;
	else
		cmdreply = command:cmdtag("executing", sessionid);
		data.actions = data.actions or { "complete" };
	end

	for name, content in pairs(data) do
		if name == "info" then
			cmdreply:tag("note", {type="info"}):text(content):up();
		elseif name == "warn" then
			cmdreply:tag("note", {type="warn"}):text(content):up();
		elseif name == "error" then
			cmdreply:tag("note", {type="error"}):text(content.message):up();
		elseif name == "actions" then
			local actions = st.stanza("actions", { execute = content.default });
			for _, action in ipairs(content) do
				if (action == "prev") or (action == "next") or (action == "complete") then
					actions:tag(action):up();
				else
					module:log("error", "Command %q at node %q provided an invalid action %q",
						command.name, command.node, action);
				end
			end
			cmdreply:add_child(actions);
		elseif name == "form" then
			cmdreply:add_child((content.layout or content):form(content.values));
		elseif name == "result" then
			cmdreply:add_child((content.layout or content):form(content.values, "result"));
		elseif name == "other" then
			cmdreply:add_child(content);
		end
	end
	local reply = st.reply(stanza);
	reply:add_child(cmdreply);
	origin.send(reply);

	return true;
end

return _M;