File

plugins/adhoc/adhoc.lib.lua @ 13069:45caa4e43775

mod_http: Fix reliance on previous tostring() format of util.set a863e4237b91 unintentionally changed the format of HTTP CORS headers, which were apparently relying on the output of tostring(), which it shouldn't have. Explicitly serializing it this time.
author Kim Alvefur <zash@zash.se>
date Mon, 10 Apr 2023 11:50:27 +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;