# HG changeset patch # User Florian Zeitz # Date 1264130758 -3600 # Node ID a9898f13c89e15aabd8756cfe7b5a0ec0c7d493c # Parent 7a2d33e8ad1f5aa64c21ea3630dfd847abd31374 mod_adhoc: Major refactoring. Actuall data exchange happens here now mod_adhoc_cmd_*: Update to work with aforementioned change diff -r 7a2d33e8ad1f -r a9898f13c89e mod_adhoc/adhoc/adhoc.lib.lua --- a/mod_adhoc/adhoc/adhoc.lib.lua Fri Jan 15 10:17:57 2010 +0100 +++ b/mod_adhoc/adhoc/adhoc.lib.lua Fri Jan 22 04:25:58 2010 +0100 @@ -16,4 +16,42 @@ 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 nil; + local dataIn = {}; + dataIn.to = stanza.attr.to; + dataIn.from = stanza.attr.from; + dataIn.action = stanza.tags[1].attr.action or nil; + dataIn.form = stanza.tags[1]:child_with_ns("jabber:x:data"); + + local data, sessid = command:handler(dataIn, sessionid); + local stanza = st.reply(stanza); + if data.status == "completed" then + cmdtag = command:cmdtag("completed", sessid); + elseif data.status == "canceled" then + cmdtag = command:cmdtag("canceled", sessid); + elseif data.status == "error" then + stanza = st.error_reply(stanza, data.error.type, data.error.condition, data.error.message); + cmdtag = command:cmdtag("canceled", sessid); + else + cmdtag = command:cmdtag("executing", sessid); + end + + for name, content in pairs(data) do + if name == "info" then + cmdtag:tag("note", {type="info"}):text(content); + elseif name == "error" then + cmdtag:tag("note", {type="error"}):text(content.message); + elseif name == "form" then + cmdtag:add_child(data.form:form()); + elseif name == "other" then + cmdtag:add_child(content); + end + end + stanza:add_child(cmdtag); + origin.send(stanza); + + return true; +end + return _M; diff -r 7a2d33e8ad1f -r a9898f13c89e mod_adhoc/adhoc/mod_adhoc.lua --- a/mod_adhoc/adhoc/mod_adhoc.lua Fri Jan 15 10:17:57 2010 +0100 +++ b/mod_adhoc/adhoc/mod_adhoc.lua Fri Jan 22 04:25:58 2010 +0100 @@ -6,6 +6,7 @@ local st = require "util.stanza"; local is_admin = require "core.usermanager".is_admin; +local adhoc_handle_cmd = module:require "adhoc".handle_cmd; local commands = {}; module:add_feature("http://jabber.org/protocol/commands"); @@ -15,7 +16,7 @@ local privileged = is_admin(event.stanza.attr.from) or is_admin(stanza.attr.from, stanza.attr.to); -- TODO: Is this correct, or should is_admin be changed? if stanza.attr.type == "get" and stanza.tags[1].attr.node and stanza.tags[1].attr.node == "http://jabber.org/protocol/commands" then reply = st.reply(stanza); - reply:tag("query", {xmlns="http://jabber.org/protocol/disco#items", node="http://jabber.org/protocol/commands"}) + reply:tag("query", {xmlns="http://jabber.org/protocol/disco#items", node="http://jabber.org/protocol/commands"}); for i = 1, #commands do -- module:log("info", "adding command %s", commands[i].name); if (commands[i].permission == "admin" and privileged) or (commands[i].permission == "user") then @@ -43,7 +44,7 @@ return true end -- User has permission now execute the command - return commands[i].handler(commands[i], origin, stanza); + return adhoc_handle_cmd(commands[i], origin, stanza); end end end diff -r 7a2d33e8ad1f -r a9898f13c89e mod_adhoc_cmd_admin/mod_adhoc_cmd_admin.lua --- a/mod_adhoc_cmd_admin/mod_adhoc_cmd_admin.lua Fri Jan 15 10:17:57 2010 +0100 +++ b/mod_adhoc_cmd_admin/mod_adhoc_cmd_admin.lua Fri Jan 22 04:25:58 2010 +0100 @@ -18,6 +18,7 @@ local st, jid, uuid = require "util.stanza", require "util.jid", require "util.uuid"; local dataforms_new = require "util.dataforms".new; +module:log("debug", module:get_name()); local adhoc_new = module:require "adhoc".new; local sessions = {}; @@ -75,129 +76,103 @@ { name = "announcement", type = "text-multi", required = true, label = "Announcement" }; }; -function add_user_command_handler(item, origin, stanza) - if stanza.tags[1].attr.sessionid and sessions[stanza.tags[1].attr.sessionid] then - if stanza.tags[1].attr.action == "cancel" then - origin.send(st.reply(stanza):add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; +function add_user_command_handler(self, data, sessid) + if sessid and sessions[sessid] then + if data.action == "cancel" then + sessions[sessid] = nil; + return { status = "canceled" }, sessid; end - local form = stanza.tags[1]:child_with_ns("jabber:x:data"); - local fields = add_user_layout:data(form); + local fields = add_user_layout:data(data.form); local username, host, resource = jid.split(fields.accountjid); - if (fields["password"] == fields["password-verify"]) and username and host and host == stanza.attr.to then + if (fields["password"] == fields["password-verify"]) and username and host and host == data.to then if usermanager_user_exists(username, host) then - origin.send(st.error_reply(stanza, "cancel", "conflict", "Account already exists"):up() - :add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid) - :tag("note", {type="error"}):text("Account already exists"))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return { status = "error", error = { type = "cancel", condition = "conflict", message = "Account already exists" } }, sessid; else if usermanager_create_user(username, fields.password, host) then - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", stanza.tags[1].attr.sessionid) - :tag("note", {type="info"}):text("Account successfully created"))); - sessions[stanza.tags[1].attr.sessionid] = nil; - module:log("debug", "Created new account " .. username.."@"..host); - return true; + sessions[sessid] = nil; + module:log("info", "Created new account " .. username.."@"..host); + return { status = "completed", info = "Account successfully created" }, sessid; else - origin.send(st.error_reply(stanza, "wait", "internal-server-error", - "Failed to write data to disk"):up() - :add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid) - :tag("note", {type="error"}):text("Failed to write data to disk"))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return { status = "error", error = { type = "wait", condition = "internal-server-error", + message = "Failed to write data to disk" } }, sessid; end end else module:log("debug", fields.accountjid .. " " .. fields.password .. " " .. fields["password-verify"]); - origin.send(st.error_reply(stanza, "cancel", "conflict", - "Invalid data.\nPassword mismatch, or empty username"):up() - :add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid) - :tag("note", {type="error"}):text("Invalid data.\nPassword mismatch, or empty username"))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return { status = "error", error = { type = "cancel", condition = "conflict", + message = "Invalid data.\nPassword mismatch, or empty username" } }, sessid; end else local sessionid=uuid.generate(); sessions[sessionid] = "executing"; - origin.send(st.reply(stanza):add_child(item:cmdtag("executing", sessionid):add_child(add_user_layout:form()))); + return { status = "executing", form = add_user_layout }, sessionid; end - return true; end -function change_user_password_command_handler(item, origin, stanza) - if stanza.tags[1].attr.sessionid and sessions[stanza.tags[1].attr.sessionid] then - if stanza.tags[1].attr.action == "cancel" then - origin.send(st.reply(stanza):add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; +function change_user_password_command_handler(self, data, sessid) + if sessid and sessions[sessid] then + if data.action == "cancel" then + sessions[sessid] = nil; + return { status = "canceled" }, sessid; end - local form = stanza.tags[1]:child_with_ns("jabber:x:data"); - local fields = change_user_password_layout:data(form); + local fields = change_user_password_layout:data(data.form); local username, host, resource = jid.split(fields.accountjid); if usermanager_user_exists(username, host) and usermanager_create_user(username, fields.password, host) then - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", stanza.tags[1].attr.sessionid) - :tag("note", {type="info"}) - :text("Password successfully changed"))); + return { status = "completed", info = "Password successfully changed" }, sessid; else - origin.send(st.error_reply(stanza, "cancel", "item-not-found", "User does not exist") - :add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid) - :tag("note", {type="error"}):text("User does not exist"))); + sessions[sessid] = nil; + return { status = "error", error = { type = "cancel", condition = "item-not-found", message = "User does not exist" } }, sessid; end - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return { status = "canceled" }, sessid; else local sessionid=uuid.generate(); sessions[sessionid] = "executing"; - origin.send(st.reply(stanza):add_child(item:cmdtag("executing", sessionid):add_child(change_user_password_layout:form()))); + return { status = "executing", form = change_user_password_layout }, sessionid; end - return true; end -function delete_user_command_handler(item, origin, stanza) - if stanza.tags[1].attr.sessionid and sessions[stanza.tags[1].attr.sessionid] then - if stanza.tags[1].attr.action == "cancel" then - origin.send(st.reply(stanza):add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; +function delete_user_command_handler(self, data, sessid) + if sessid and sessions[sessid] then + if data.action == "cancel" then + sessions[sessid] = nil; + return { status = "canceled" }, sessid; end - local form = stanza.tags[1]:child_with_ns("jabber:x:data"); - local fields = delete_user_layout:data(form); + local fields = delete_user_layout:data(data.form); local failed = {}; local succeeded = {}; for _, aJID in ipairs(fields.accountjids) do local username, host, resource = jid.split(aJID); if usermanager_user_exists(username, host) and usermanager_create_user(username, nil, host) then - module:log("debug", "User" .. aJID .. "has been deleted"); + module:log("debug", "User " .. aJID .. " has been deleted"); succeeded[#succeeded+1] = aJID; else - module:log("debug", "Tried to delete not existing user "..aJID); + module:log("debug", "Tried to delete non-existant user "..aJID); failed[#failed+1] = aJID; end end - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", stanza.tags[1].attr.sessionid) - :tag("note", {type="info"}) - :text((#succeeded ~= 0 and "The following accounts were successfully deleted:\n"..t_concat(succeeded, "\n").."\n" or "") - ..(#failed ~= 0 and "The following accounts could not be deleted:\n"..t_concat(failed, "\n") or "")))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return {status = "completed", info = (#succeeded ~= 0 and + "The following accounts were successfully deleted:\n"..t_concat(succeeded, "\n").."\n" or "").. + (#failed ~= 0 and + "The following accounts could not be deleted:\n"..t_concat(failed, "\n") or "") }, sessid; else local sessionid=uuid.generate(); sessions[sessionid] = "executing"; - origin.send(st.reply(stanza):add_child(item:cmdtag("executing", sessionid):add_child(delete_user_layout:form()))); + return { status = "executing", form = delete_user_layout }, sessionid; end - return true; end -function get_user_password_handler(item, origin, stanza) - if stanza.tags[1].attr.sessionid and sessions[stanza.tags[1].attr.sessionid] then - if stanza.tags[1].attr.action == "cancel" then - origin.send(st.reply(stanza):add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; +function get_user_password_handler(self, data, sessid) + if sessid and sessions[sessid] then + if data.action == "cancel" then + sessions[sessid] = nil; + return { status = "canceled" }, sessid; end - local form = stanza.tags[1]:child_with_ns("jabber:x:data"); - local fields = get_user_password_layout:data(form); + local fields = get_user_password_layout:data(data.form); local accountjid = st.stanza("field", {var="accountjid", label = "JID", type="jid-single"}); local password = st.stanza("field", {var="password", label = "Password", type="text-single"}); local user, host, resource = jid.split(fields.accountjid); @@ -205,38 +180,30 @@ accountjid:tag("value"):text(fields.accountjid):up(); password:tag("value"):text(usermanager_get_password(user, host)):up(); else - origin.send(st.error_reply(stanza, "cancel", "item-not-found", "User does not exist") - :add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid) - :tag("note", {type="error"}):text("User does not exist"))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return { status = "error", error = { type = "cancel", condition = "item-not-found", message = "User does not exist" } }, sessid; end - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", stanza.tags[1].attr.sessionid) - :tag("x", {xmlns="jabber:x:data", type="result"}) + sessions[sessid] = nil; + return { status = "completed", other = st.stanza("x", {xmlns="jabber:x:data", type="result"}) :tag("field", {type="hidden", var="FORM_TYPE"}) :tag("value"):text("http://jabber.org/protocol/admin"):up():up() :add_child(accountjid) - :add_child(password))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + :add_child(password) }, sessid; else local sessionid=uuid.generate(); sessions[sessionid] = "executing"; - origin.send(st.reply(stanza):add_child(item:cmdtag("executing", sessionid):add_child(get_user_password_layout:form()))); + return { status = "executing", form = get_user_password_layout }, sessionid; end - return true; end -function get_online_users_command_handler(item, origin, stanza) - if stanza.tags[1].attr.sessionid and sessions[stanza.tags[1].attr.sessionid] then - if stanza.tags[1].attr.action == "cancel" then - origin.send(st.reply(stanza):add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; +function get_online_users_command_handler(self, data, sessid) + if sessid and sessions[sessid] then + if data.action == "cancel" then + sessions[sessid] = nil; + return { status = "canceled" }, sessid; end - local form = stanza.tags[1]:child_with_ns("jabber:x:data"); - local fields = add_user_layout:data(form); + local fields = add_user_layout:data(data.form); local max_items = nil if fields.max_items ~= "all" then @@ -244,62 +211,53 @@ end local count = 0; local field = st.stanza("field", {label="The list of all online users", var="onlineuserjids", type="text-multi"}); - for username, user in pairs(hosts[stanza.attr.to].sessions or {}) do + for username, user in pairs(hosts[data.to].sessions or {}) do if (max_items ~= nil) and (count >= max_items) then break; end - field:tag("value"):text(username.."@"..stanza.attr.to):up(); + field:tag("value"):text(username.."@"..data.to):up(); count = count + 1; end - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", stanza.tags[1].attr.sessionid) - :tag("x", {xmlns="jabber:x:data", type="result"}) + sessions[sessid] = nil; + return { status = "completed", other = st.stanza("x", {xmlns="jabber:x:data", type="result"}) :tag("field", {type="hidden", var="FORM_TYPE"}) :tag("value"):text("http://jabber.org/protocol/admin"):up():up() - :add_child(field))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + :add_child(field) }, sessid; else local sessionid=uuid.generate(); sessions[sessionid] = "executing"; - origin.send(st.reply(stanza):add_child(item:cmdtag("executing", sessionid):add_child(get_online_users_layout:form()))); + return { status = "executing", form = get_online_users_layout }, sessionid; end - - return true; end -function announce_handler(item, origin, stanza) - if stanza.tags[1].attr.sessionid and sessions[stanza.tags[1].attr.sessionid] then - if stanza.tags[1].attr.action == "cancel" then - origin.send(st.reply(stanza):add_child(item:cmdtag("canceled", stanza.tags[1].attr.sessionid))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; +function announce_handler(self, data, sessid) + if sessid and sessions[sessid] then + if data.action == "cancel" then + sessions[sessid] = nil; + return { status = "canceled" }, sessid; end - local form = stanza.tags[1]:child_with_ns("jabber:x:data"); - local fields = add_user_layout:data(form); + local fields = announce_layout:data(data.form); module:log("info", "Sending server announcement to all online users"); - local host_session = hosts[stanza.attr.to]; - local message = st.message({type = "headline", from = stanza.attr.to}, fields.announcement):up() + local host_session = hosts[data.to]; + local message = st.message({type = "headline", from = data.to}, fields.announcement):up() :tag("subject"):text(fields.subject or "Announcement"); local c = 0; for user in pairs(host_session.sessions) do c = c + 1; - message.attr.to = user.."@"..stanza.attr.to; + message.attr.to = user.."@"..data.to; core_post_stanza(host_session, message); end module:log("info", "Announcement sent to %d online users", c); - - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", stanza.tags[1].attr.sessionid) - :tag("note"):text("Announcement sent."))); - sessions[stanza.tags[1].attr.sessionid] = nil; - return true; + sessions[sessid] = nil; + return { status = "completed", info = "Announcement sent." }, sessid; else local sessionid=uuid.generate(); sessions[sessionid] = "executing"; - origin.send(st.reply(stanza):add_child(item:cmdtag("executing", sessionid):add_child(announce_layout:form()))); + return { status = "executing", form = announce_layout }, sessionid; end return true; diff -r 7a2d33e8ad1f -r a9898f13c89e mod_adhoc_cmd_ping/mod_adhoc_cmd_ping.lua --- a/mod_adhoc_cmd_ping/mod_adhoc_cmd_ping.lua Fri Jan 15 10:17:57 2010 +0100 +++ b/mod_adhoc_cmd_ping/mod_adhoc_cmd_ping.lua Fri Jan 22 04:25:58 2010 +0100 @@ -7,10 +7,9 @@ local st = require "util.stanza"; local adhoc_new = module:require "adhoc".new; -function ping_command_handler (item, origin, stanza) +function ping_command_handler (self, data, sessid) local now = os.date("%Y-%m-%dT%X"); - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", now):tag("note", {type="info"}):text("Pong\n" .. now))); - return true; + return { info = "Pong\n"..now, status = "completed" }, now; end local descriptor = adhoc_new("Ping", "ping", ping_command_handler); diff -r 7a2d33e8ad1f -r a9898f13c89e mod_adhoc_cmd_uptime/mod_adhoc_cmd_uptime.lua --- a/mod_adhoc_cmd_uptime/mod_adhoc_cmd_uptime.lua Fri Jan 15 10:17:57 2010 +0100 +++ b/mod_adhoc_cmd_uptime/mod_adhoc_cmd_uptime.lua Fri Jan 22 04:25:58 2010 +0100 @@ -23,9 +23,8 @@ minutes, (minutes ~= 1 and "s") or "", os.date("%c", prosody.start_time)); end -function uptime_command_handler (item, origin, stanza) - origin.send(st.reply(stanza):add_child(item:cmdtag("completed", uuid.generate()):tag("note", {type="info"}):text(uptime()))); - return true; +function uptime_command_handler (self, data, sessid) + return { info = uptime(), status = "completed" }, uuid.generate(); end local descriptor = adhoc_new("Get uptime", "uptime", uptime_command_handler);