# HG changeset patch # User Matthew Wild # Date 1282841536 -3600 # Node ID 151c8cc776dfd9fbabacde32c89a3ba595db3df8 # Parent 9f8cacfca7c74a732a75d2a0d67666f3516d461b verse.plugins.adhoc: XEP-0050 Ad-hoc commands plugin diff -r 9f8cacfca7c7 -r 151c8cc776df libs/adhoc.lib.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/adhoc.lib.lua Thu Aug 26 17:52:16 2010 +0100 @@ -0,0 +1,85 @@ +-- 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 "util.stanza", require "util.uuid"; + +local xmlns_cmd = "http://jabber.org/protocol/commands"; + +local states = {} + +local _M = {}; + +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) + return { name = name, node = node, handler = handler, cmdtag = _cmdtag, permission = (permission or "user") }; +end + +function _M.handle_cmd(command, origin, stanza) + local sessionid = stanza.tags[1].attr.sessionid or uuid.generate(); + local dataIn = {}; + dataIn.to = stanza.attr.to; + dataIn.from = stanza.attr.from; + dataIn.action = stanza.tags[1].attr.action or "execute"; + dataIn.form = stanza.tags[1]:child_with_ns("jabber:x:data"); + + local data, state = command:handler(dataIn, states[sessionid]); + states[sessionid] = state; + local stanza = st.reply(stanza); + if data.status == "completed" then + states[sessionid] = nil; + cmdtag = command:cmdtag("completed", sessionid); + elseif data.status == "canceled" then + states[sessionid] = nil; + cmdtag = command:cmdtag("canceled", sessionid); + elseif data.status == "error" then + states[sessionid] = nil; + stanza = st.error_reply(stanza, data.error.type, data.error.condition, data.error.message); + origin.send(stanza); + return true; + else + cmdtag = command:cmdtag("executing", sessionid); + end + + for name, content in pairs(data) do + if name == "info" then + cmdtag:tag("note", {type="info"}):text(content):up(); + elseif name == "warn" then + cmdtag:tag("note", {type="warn"}):text(content):up(); + elseif name == "error" then + cmdtag:tag("note", {type="error"}):text(content.message):up(); + elseif name =="actions" then + local actions = st.stanza("actions"); + 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 "'..command.name.. + '" at node "'..command.node..'" provided an invalid action "'..action..'"'); + end + end + cmdtag:add_child(actions); + elseif name == "form" then + cmdtag:add_child((content.layout or content):form(content.data)); + elseif name == "result" then + cmdtag:add_child((content.layout or content):form(content.data, "result")); + elseif name == "other" then + cmdtag:add_child(content); + end + end + stanza:add_child(cmdtag); + origin.send(stanza); + + return true; +end + +return _M; diff -r 9f8cacfca7c7 -r 151c8cc776df plugins/adhoc.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/adhoc.lua Thu Aug 26 17:52:16 2010 +0100 @@ -0,0 +1,46 @@ +local adhoc = require "lib.adhoc"; + +local xmlns_commands = "http://jabber.org/protocol/commands"; + +local commands = {}; + +function verse.plugins.adhoc(stream) + stream:add_disco_feature(xmlns_commands); + + local function has_affiliation(jid, aff) + if not(aff) or aff == "user" then return true; end + -- TODO: Support 'roster', and callback etc. + end + + function stream:add_adhoc_command(name, node, handler, permission) + commands[node] = adhoc.new(name, node, handler, permission); + stream:add_disco_item({ jid = stream.jid, node = node, name = name }, xmlns_commands); + return commands[node]; + end + + local function handle_command(stanza) + local command_tag = stanza.tags[1]; + local node = command_tag.attr.node; + + local handler = commands[node]; + if not handler then return; end + + if not has_affiliation(stanza.attr.from, handler.permission) then + stream:send(verse.error_reply(stanza, "auth", "forbidden", "You don't have permission to execute this command"):up() + :add_child(handler:cmdtag("canceled") + :tag("note", {type="error"}):text("You don't have permission to execute this command"))); + return true + end + + -- User has permission now execute the command + return adhoc.handle_cmd(handler, { send = function (d) return stream:send(d) end }, stanza); + end + + stream:hook("iq/"..xmlns_commands, function (stanza) + local type = stanza.attr.type; + local name = stanza.tags[1].name; + if type == "set" and name == "command" then + return handle_command(stanza); + end + end); +end diff -r 9f8cacfca7c7 -r 151c8cc776df squishy --- a/squishy Thu Aug 26 17:48:57 2010 +0100 +++ b/squishy Thu Aug 26 17:52:16 2010 +0100 @@ -18,6 +18,8 @@ Module "util.events" "util/events.lua" Module "util.sha1" "util/sha1.lua" +Module "lib.adhoc" "libs/adhoc.lib.lua" + -- Verse plugins Module "verse.plugins.tls" "plugins/tls.lua" Module "verse.plugins.sasl" "plugins/sasl.lua" @@ -33,6 +35,7 @@ Module "verse.plugins.jingle_s5b" "plugins/jingle_s5b.lua" Module "verse.plugins.disco" "plugins/disco.lua" Module "verse.plugins.pep" "plugins/pep.lua" +Module "verse.plugins.adhoc" "plugins/adhoc.lua" if GetOption "bosh" ~= false then Module "net.httpclient_listener" "net/httpclient_listener.lua"