view mod_pubsub_text_interface/mod_pubsub_text_interface.lua @ 4738:5aee8d86629a

mod_bookmarks2: Fix handling of nick and password elements This form of child retrieval fails when the stanza elements internally don't have an 'xmlns' attribute, which can happen sometimes for some reason, including when they have been constructed via the stanza builder API. When that is the case then the explicit namespace arguemnt does not match the nil value of the internal attribute. Calling `:get_child()` without the namespace argument does the right thing here, with both nil and the parent namespace as valid values for the internal attribute.
author Kim Alvefur <zash@zash.se>
date Wed, 03 Nov 2021 21:11:55 +0100
parents 25ce28711fac
children d7652471ae3e
line wrap: on
line source

local st = require "util.stanza";
local jid = require "util.jid";
local id = require "util.id";

local pubsub = module:depends "pubsub".service;

local xmlns_quick_resp = "urn:xmpp:tmp:quick-response";
local name = module:get_option_string("name", "PubSub Service on "..module.host);
local help = name..[[

Commands:

- `help` - this help message
- `list` - list available nodes
- `subscriptions` - list nodes you are subscribed to
- `subscribe node` - subscribe to a node
- `unsubscribe node` - unsubscribe from a node]];
if pubsub.get_last_item then -- COMPAT not available in 0.10
	help = help ..  "\n- `last node` - send the last item (again)"
end

module:hook("message/host", function (event)
	local stanza = event.stanza;
	local body = stanza:get_child_text("body");
	if not body then return end -- bail out

	local from = stanza.attr.from;

	local reply = st.reply(stanza);
	reply.attr.id = id.medium();

	local command, node_arg = body:match("^(%a+)%s+(.*)");
	command = (command or body):lower();

	if command == "help" then
		reply:body(help):up();
		reply:tag("response", { xmlns = xmlns_quick_resp, value = "list", }):up();
		reply:tag("response", { xmlns = xmlns_quick_resp, value = "subscriptions", }):up();
	elseif command == "list" then
		local ok, nodes = pubsub:get_nodes(from);
		if ok then
			local list = {};
			for node, node_obj in pairs(nodes) do
				table.insert(list, ("- `%s` %s"):format(node, node_obj.config.title or ""));
			end
			reply:body(table.concat(list, "\n"));
		else
			reply:body(nodes);
		end
	elseif command == "subscriptions" then
		local ok, subs = pubsub:get_subscriptions(nil, from, from);
		if not ok then
			reply:body(subs);
		elseif #subs == 0 then
			reply:body("You are not subscribed to anything from this pubsub service");
		else
			local response = {};
			for i = 1, #subs do
				response[i] = string.format("- `%s`", subs[i].node);
				reply:tag("response", { xmlns = xmlns_quick_resp, value = "unsubscribe "..subs[i].node, }):up();
				reply:tag("response", { xmlns = xmlns_quick_resp, value = "last "..subs[i].node, }):up();
			end
			reply:body(table.concat(response, "\n"));
		end
	elseif command == "subscribe" then
		local ok, err = pubsub:add_subscription(node_arg, from, jid.bare(from), { ["pubsub#include_body"] = true });
		reply:body(ok and "OK" or err);
	elseif command == "unsubscribe" then
		local ok, err = pubsub:remove_subscription(node_arg, from, jid.bare(from));
		reply:body(ok and "OK" or err);
	elseif command == "last" and pubsub.get_last_item then
		local ok, item_id, item = pubsub:get_last_item(node_arg, from);
		if not ok then
			reply:body(item_id); -- err message
		elseif not item_id then
			reply:body("node is empty");
		else
			pubsub.config.broadcaster("items", node_arg, {
				[from] = { ["pubsub#include_body"] = true }
			}, item, nil, pubsub.nodes[node_arg]);
			reply:body("OK");
		end
	else
		reply:body("Unknown command. `help` to list commands."):up();
		reply:tag("response", { xmlns = xmlns_quick_resp, value = "help", }):up();
	end
	reply:reset();

	if stanza:get_child("no-copy", "urn:xmpp:hints") then
		reply:tag("no-copy", { xmlns = "urn:xmpp:hints" }):up();
	end

	if stanza:get_child("no-store", "urn:xmpp:hints") then
		reply:tag("no-store", { xmlns = "urn:xmpp:hints" }):up();
	end

	module:send(reply);
	return true;
end);