diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mod_admin_shell.lua | 111 | ||||
-rw-r--r-- | plugins/mod_admin_socket.lua | 7 | ||||
-rw-r--r-- | plugins/mod_authz_internal.lua | 4 | ||||
-rw-r--r-- | plugins/mod_cron.lua | 4 | ||||
-rw-r--r-- | plugins/mod_flags.lua | 157 | ||||
-rw-r--r-- | plugins/mod_pep.lua | 3 | ||||
-rw-r--r-- | plugins/mod_pubsub/commands.lib.lua | 255 | ||||
-rw-r--r-- | plugins/mod_pubsub/mod_pubsub.lua | 46 | ||||
-rw-r--r-- | plugins/mod_roster.lua | 174 |
9 files changed, 688 insertions, 73 deletions
diff --git a/plugins/mod_admin_shell.lua b/plugins/mod_admin_shell.lua index c32048c3..4f8e6094 100644 --- a/plugins/mod_admin_shell.lua +++ b/plugins/mod_admin_shell.lua @@ -25,6 +25,8 @@ local _G = _G; local prosody = _G.prosody; local unpack = table.unpack; +local cache = require "prosody.util.cache"; +local new_short_id = require "prosody.util.id".short; local iterators = require "prosody.util.iterators"; local keys, values = iterators.keys, iterators.values; local jid_bare, jid_split, jid_join, jid_resource, jid_compare = import("prosody.util.jid", "bare", "prepped_split", "join", "resource", "compare"); @@ -170,6 +172,48 @@ local function send_repl_output(session, line, attr) return session.send(st.stanza("repl-output", attr):text(tostring(line))); end +local function request_repl_input(session, input_type) + if input_type ~= "password" then + return promise.reject("internal error - unsupported input type "..tostring(input_type)); + end + local pending_inputs = session.pending_inputs; + if not pending_inputs then + pending_inputs = cache.new(5, function (input_id, input_promise) --luacheck: ignore 212/input_id + input_promise.reject(); + end); + session.pending_inputs = pending_inputs; + end + + local input_id = new_short_id(); + local p = promise.new(function (resolve, reject) + pending_inputs:set(input_id, { resolve = resolve, reject = reject }); + end):finally(function () + pending_inputs:set(input_id, nil); + end); + session.send(st.stanza("repl-request-input", { type = input_type, id = input_id })); + module:log("warn", "REQUESTED INPUT %s", input_type); + return p; +end + +module:hook("admin-disconnected", function (event) + local pending_inputs = event.session.pending_inputs; + if not pending_inputs then return; end + for input_promise in pending_inputs:values() do + input_promise.reject(); + end +end); + +module:hook("admin/repl-requested-input", function (event) + local input_id = event.stanza.attr.id; + local input_promise = event.origin.pending_inputs:get(input_id); + if not input_promise then + event.origin.send(st.stanza("repl-result", { type = "error" }):text("Internal error - unexpected input")); + return true; + end + input_promise.resolve(event.stanza:get_text()); + return true; +end); + function console:new_session(admin_session) local session = { send = function (t) @@ -185,6 +229,9 @@ function console:new_session(admin_session) write = function (t) return send_repl_output(admin_session, t, { eol = "0" }); end; + request_input = function (input_type) + return request_repl_input(admin_session, input_type); + end; serialize = tostring; disconnect = function () admin_session:close(); end; is_connected = function () @@ -266,25 +313,33 @@ local function handle_line(event) end end - local taskok, message = chunk(); + local function send_result(taskok, message) + if not message then + if type(taskok) ~= "string" and useglobalenv then + taskok = session.serialize(taskok); + end + result:text("Result: "..tostring(taskok)); + elseif (not taskok) and message then + result.attr.type = "error"; + result:text("Error: "..tostring(message)); + else + result:text("OK: "..tostring(message)); + end - if promise.is_promise(taskok) then - taskok, message = async.wait_for(taskok); + event.origin.send(result); end - if not message then - if type(taskok) ~= "string" and useglobalenv then - taskok = session.serialize(taskok); - end - result:text("Result: "..tostring(taskok)); - elseif (not taskok) and message then - result.attr.type = "error"; - result:text("Error: "..tostring(message)); + local taskok, message = chunk(); + + if promise.is_promise(taskok) then + taskok:next(function (resolved_message) + send_result(true, resolved_message); + end, function (rejected_message) + send_result(nil, rejected_message); + end); else - result:text("OK: "..tostring(message)); + send_result(taskok, message); end - - event.origin.send(result); end module:hook("admin/repl-input", function (event) @@ -1670,12 +1725,13 @@ function def_env.user:create(jid, password, role) role = module:get_option_string("default_provisioned_role", "prosody:member"); end - local ok, err = um.create_user_with_role(username, password, host, role); - if not ok then - return nil, "Could not create user: "..err; - end - - return true, ("Created %s with role '%s'"):format(jid, role); + return promise.resolve(password or self.session.request_input("password")):next(function (password_) + local ok, err = um.create_user_with_role(username, password_, host, role); + if not ok then + return promise.reject("Could not create user: "..err); + end + return ("Created %s with role '%s'"):format(jid, role); + end); end describe_command [[user:disable(jid) - Disable the specified user account, preventing login]] @@ -1734,12 +1790,15 @@ function def_env.user:password(jid, password) elseif not um.user_exists(username, host) then return nil, "No such user"; end - local ok, err = um.set_password(username, password, host, nil); - if ok then - return true, "User password changed"; - else - return nil, "Could not change password for user: "..err; - end + + return promise.resolve(password or self.session.request_input("password")):next(function (password_) + local ok, err = um.set_password(username, password_, host, nil); + if ok then + return "User password changed"; + else + return promise.reject("Could not change password for user: "..err); + end + end); end describe_command [[user:roles(jid, host) - Show current roles for an user]] diff --git a/plugins/mod_admin_socket.lua b/plugins/mod_admin_socket.lua index ad6aa5d7..b7b6d5f5 100644 --- a/plugins/mod_admin_socket.lua +++ b/plugins/mod_admin_socket.lua @@ -54,7 +54,12 @@ end); local conn, sock; -local listeners = adminstream.server(sessions, fire_admin_event).listeners; +local admin_server = adminstream.server(sessions, fire_admin_event); +local listeners = admin_server.listeners; + +module:hook_object_event(admin_server.events, "disconnected", function (event) + return module:fire_event("admin-disconnected", event); +end); local function accept_connection() module:log("debug", "accepting..."); diff --git a/plugins/mod_authz_internal.lua b/plugins/mod_authz_internal.lua index 07091a04..6006b447 100644 --- a/plugins/mod_authz_internal.lua +++ b/plugins/mod_authz_internal.lua @@ -18,8 +18,8 @@ local is_component = hosts[host].type == "component"; local host_user_role, server_user_role, public_user_role; if is_component then host_user_role = module:get_option_string("host_user_role", "prosody:registered"); - server_user_role = module:get_option_string("server_user_role"); - public_user_role = module:get_option_string("public_user_role"); + server_user_role = module:get_option_string("server_user_role", "prosody:guest"); + public_user_role = module:get_option_string("public_user_role", "prosody:guest"); end local role_store = module:open_store("account_roles"); diff --git a/plugins/mod_cron.lua b/plugins/mod_cron.lua index 29c1aa93..67b68514 100644 --- a/plugins/mod_cron.lua +++ b/plugins/mod_cron.lua @@ -8,6 +8,10 @@ local cron_spread_factor = module:get_option_number("cron_spread_factor", 0); local active_hosts = {} +if prosody.process_type == "prosodyctl" then + return; -- Yes, it happens... +end + function module.add_host(host_module) local last_run_times = host_module:open_store("cron", "map"); diff --git a/plugins/mod_flags.lua b/plugins/mod_flags.lua new file mode 100644 index 00000000..694b608b --- /dev/null +++ b/plugins/mod_flags.lua @@ -0,0 +1,157 @@ +local jid_node = require "prosody.util.jid".node; + +local flags = module:open_store("account_flags", "keyval+"); + +-- API + +function add_flag(username, flag, comment) + local flag_data = { + when = os.time(); + comment = comment; + }; + + local ok, err = flags:set_key(username, flag, flag_data); + if not ok then + return nil, err; + end + + module:fire_event("user-flag-added/"..flag, { + user = username; + flag = flag; + data = flag_data; + }); + + return true; +end + +function remove_flag(username, flag) + local ok, err = flags:set_key(username, flag, nil); + if not ok then + return nil, err; + end + + module:fire_event("user-flag-removed/"..flag, { + user = username; + flag = flag; + }); + + return true; +end + +function has_flag(username, flag) -- luacheck: ignore 131/has_flag + local ok, err = flags:get_key(username, flag); + if not ok and err then + error("Failed to check flags for user: "..err); + end + return not not ok; +end + +function get_flag_info(username, flag) -- luacheck: ignore 131/get_flag_info + return flags:get_key(username, flag); +end + +-- Shell commands + +local function get_username(jid) + return (assert(jid_node(jid), "please supply a valid user JID")); +end + +module:add_item("shell-command", { + section = "flags"; + section_desc = "View and manage flags on user accounts"; + name = "list"; + desc = "List flags for the given user account"; + args = { + { name = "jid", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid) --luacheck: ignore 212/self + local c = 0; + + local user_flags, err = flags:get(get_username(jid)); + + if not user_flags and err then + return false, "Unable to list flags: "..err; + end + + if user_flags then + local print = self.session.print; + + for flag_name, flag_data in pairs(user_flags) do + print(flag_name, os.date("%Y-%m-%d %R", flag_data.when), flag_data.comment); + c = c + 1; + end + end + + return true, ("%d flags listed"):format(c); + end; +}); + +module:add_item("shell-command", { + section = "flags"; + section_desc = "View and manage flags on user accounts"; + name = "add"; + desc = "Add a flag to the given user account, with optional comment"; + args = { + { name = "jid", type = "string" }; + { name = "flag", type = "string" }; + { name = "comment", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, flag, comment) --luacheck: ignore 212/self + local username = get_username(jid); + + local ok, err = add_flag(username, flag, comment); + if not ok then + return false, "Failed to add flag: "..err; + end + + return true, "Flag added"; + end; +}); + +module:add_item("shell-command", { + section = "flags"; + section_desc = "View and manage flags on user accounts"; + name = "remove"; + desc = "Remove a flag from the given user account"; + args = { + { name = "jid", type = "string" }; + { name = "flag", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, flag) --luacheck: ignore 212/self + local username = get_username(jid); + + local ok, err = remove_flag(username, flag); + if not ok then + return false, "Failed to remove flag: "..err; + end + + return true, "Flag removed"; + end; +}); + +module:add_item("shell-command", { + section = "flags"; + section_desc = "View and manage flags on user accounts"; + name = "find"; + desc = "Find all user accounts with a given flag on the specified host"; + args = { + { name = "host", type = "string" }; + { name = "flag", type = "string" }; + }; + host_selector = "host"; + handler = function(self, host, flag) --luacheck: ignore 212/self 212/host + local users_with_flag = flags:get_key_from_all(flag); + + local print = self.session.print; + local c = 0; + for user, flag_data in pairs(users_with_flag) do + print(user, os.date("%Y-%m-%d %R", flag_data.when), flag_data.comment); + c = c + 1; + end + + return true, ("%d accounts listed"):format(c); + end; +}); diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 33eee2ec..b0dfe423 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -531,3 +531,6 @@ module:hook_global("user-deleted", function(event) recipients[username] = nil; end); +module:require("mod_pubsub/commands").add_commands(function (service_jid) + return get_pep_service((jid_split(service_jid))); +end); diff --git a/plugins/mod_pubsub/commands.lib.lua b/plugins/mod_pubsub/commands.lib.lua new file mode 100644 index 00000000..59bddec8 --- /dev/null +++ b/plugins/mod_pubsub/commands.lib.lua @@ -0,0 +1,255 @@ +local it = require "prosody.util.iterators"; +local st = require "prosody.util.stanza"; + +local pubsub_lib = module:require("mod_pubsub/pubsub"); + +local function add_commands(get_service) + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "create_node"; + desc = "Create a node with the specified name"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name) --luacheck: ignore 212/self + return get_service(service_jid):create(node_name, true); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "list_nodes"; + desc = "List nodes on a pubsub service"; + args = { + { name = "service_jid", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + local nodes = select(2, assert(service:get_nodes(true))); + local count = 0; + for node_name in pairs(nodes) do + count = count + 1; + self.session.print(node_name); + end + return true, ("%d nodes"):format(count); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "list_items"; + desc = "List items on a pubsub node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + local items = select(2, assert(service:get_items(node_name, true))); + + local count = 0; + for item_name in pairs(items) do + count = count + 1; + self.session.print(item_name); + end + return true, ("%d items"):format(count); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "get_item"; + desc = "Show item content on a pubsub node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + { name = "item_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name, item_name) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + local items = select(2, assert(service:get_items(node_name, true))); + + if not items[item_name] then + return false, "Item not found"; + end + + self.session.print(items[item_name]); + + return true; + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "get_node_config"; + desc = "Get the current configuration for a node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + { name = "option_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name, option_name) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + local config = select(2, assert(service:get_node_config(node_name, true))); + + local config_form = pubsub_lib.node_config_form:form(config, "submit"); + + local count = 0; + if option_name then + count = 1; + local field = config_form:get_child_with_attr("field", nil, "var", option_name); + if not field then + return false, "option not found"; + end + self.session.print(field:get_child_text("value")); + else + local opts = {}; + for field in config_form:childtags("field") do + opts[field.attr.var] = field:get_child_text("value"); + end + for k, v in it.sorted_pairs(opts) do + count = count + 1; + self.session.print(k, v); + end + end + + return true, ("Showing %d config options"):format(count); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "set_node_config_option"; + desc = "Set a config option on a pubsub node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + { name = "option_name", type = "string" }; + { name = "option_value", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name, option_name, option_value) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + local config = select(2, assert(service:get_node_config(node_name, true))); + + local new_config_form = st.stanza("x", { xmlns = "jabber:x:data" }) + :tag("field", { var = option_name }) + :text_tag("value", option_value) + :up(); + + local new_config = pubsub_lib.node_config_form:data(new_config_form, config); + + assert(service:set_node_config(node_name, true, new_config)); + + local applied_config = select(2, assert(service:get_node_config(node_name, true))); + + local applied_config_form = pubsub_lib.node_config_form:form(applied_config, "submit"); + local applied_field = applied_config_form:get_child_with_attr("field", nil, "var", option_name); + if not applied_field then + return false, "Unknown config field: "..option_name; + end + return true, "Applied config: "..applied_field:get_child_text("value"); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "delete_item"; + desc = "Delete a single item from a node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + { name = "item_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name, item_name) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + return assert(service:retract(node_name, true, item_name)); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "delete_all_items"; + desc = "Delete all items from a node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + { name = "notify_subscribers", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name, notify_subscribers) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + return assert(service:purge(node_name, true, notify_subscribers == "true")); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "create_node"; + desc = "Create a new node"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + return assert(service:create(node_name, true)); + end; + }); + + module:add_item("shell-command", { + section = "pubsub"; + section_desc = "Manage publish/subscribe nodes"; + name = "delete_node"; + desc = "Delete a node entirely"; + args = { + { name = "service_jid", type = "string" }; + { name = "node_name", type = "string" }; + }; + host_selector = "service_jid"; + + handler = function (self, service_jid, node_name) --luacheck: ignore 212/self + -- luacheck: ignore 431/service + local service = get_service(service_jid); + return assert(service:delete(node_name, true)); + end; + }); +end + +return { + add_commands = add_commands; +} diff --git a/plugins/mod_pubsub/mod_pubsub.lua b/plugins/mod_pubsub/mod_pubsub.lua index c17d9e63..9cb63178 100644 --- a/plugins/mod_pubsub/mod_pubsub.lua +++ b/plugins/mod_pubsub/mod_pubsub.lua @@ -185,7 +185,10 @@ module:hook("host-disco-items", function (event) return; end for node, node_obj in pairs(ret) do - reply:tag("item", { jid = module.host, node = node, name = node_obj.config.title }):up(); + local ok, meta = service:get_node_metadata(node, stanza.attr.from); + if ok then + reply:tag("item", { jid = module.host, node = node, name = meta.title }):up(); + end end end); @@ -205,7 +208,7 @@ local function get_affiliation(jid, _, action) -- Only one affiliation is allowed to create nodes by default return "owner"; end - if module:may(":service-admin", bare_jid) then + if module:could(":service-admin", bare_jid) then return admin_aff; end end @@ -274,41 +277,4 @@ local function get_service(service_jid) return assert(assert(prosody.hosts[service_jid], "Unknown pubsub service").modules.pubsub, "Not a pubsub service").service; end -module:add_item("shell-command", { - section = "pubsub"; - section_desc = "Manage publish/subscribe nodes"; - name = "create_node"; - desc = "Create a node with the specified name"; - args = { - { name = "service_jid", type = "string" }; - { name = "node_name", type = "string" }; - }; - host_selector = "service_jid"; - - handler = function (self, service_jid, node_name) --luacheck: ignore 212/self - return get_service(service_jid):create(node_name, true); - end; -}); - -module:add_item("shell-command", { - section = "pubsub"; - section_desc = "Manage publish/subscribe nodes"; - name = "list_nodes"; - desc = "List nodes on a pubsub service"; - args = { - { name = "service_jid", type = "string" }; - }; - host_selector = "service_jid"; - - handler = function (self, service_jid) --luacheck: ignore 212/self - -- luacheck: ignore 431/service - local service = get_service(service_jid); - local nodes = select(2, assert(service:get_nodes(true))); - local count = 0; - for node_name in pairs(nodes) do - count = count + 1; - self.session.print(node_name); - end - return true, ("%d nodes"):format(count); - end; -}); +module:require("commands").add_commands(get_service); diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua index 82016d27..5ffdfe1a 100644 --- a/plugins/mod_roster.lua +++ b/plugins/mod_roster.lua @@ -15,10 +15,11 @@ local jid_prep = require "prosody.util.jid".prep; local tonumber = tonumber; local pairs = pairs; -local rm_load_roster = require "prosody.core.rostermanager".load_roster; -local rm_remove_from_roster = require "prosody.core.rostermanager".remove_from_roster; -local rm_add_to_roster = require "prosody.core.rostermanager".add_to_roster; -local rm_roster_push = require "prosody.core.rostermanager".roster_push; +local rostermanager = require "prosody.core.rostermanager"; +local rm_load_roster = rostermanager.load_roster; +local rm_remove_from_roster = rostermanager.remove_from_roster; +local rm_add_to_roster = rostermanager.add_to_roster; +local rm_roster_push = rostermanager.roster_push; module:add_feature("jabber:iq:roster"); @@ -147,3 +148,168 @@ module:hook_global("user-deleted", function(event) end end end, 300); + +-- API/commands + +-- Make a *one-way* subscription. User will see when contact is online, +-- contact will not see when user is online. +function subscribe(user_jid, contact_jid) + local user_username, user_host = jid_split(user_jid); + local contact_username, contact_host = jid_split(contact_jid); + + -- Update user's roster to say subscription request is pending. Bare hosts (e.g. components) don't have rosters. + if user_username ~= nil then + rostermanager.set_contact_pending_out(user_username, user_host, contact_jid); + end + + if prosody.hosts[contact_host] then -- Sending to a local host? + -- Update contact's roster to say subscription request is pending... + rostermanager.set_contact_pending_in(contact_username, contact_host, user_jid); + -- Update contact's roster to say subscription request approved... + rostermanager.subscribed(contact_username, contact_host, user_jid); + -- Update user's roster to say subscription request approved. Bare hosts (e.g. components) don't have rosters. + if user_username ~= nil then + rostermanager.process_inbound_subscription_approval(user_username, user_host, contact_jid); + end + else + -- Send a subscription request + local sub_request = st.presence({ from = user_jid, to = contact_jid, type = "subscribe" }); + module:send(sub_request); + end + + return true; +end + +-- Make a mutual subscription between jid1 and jid2. Each JID will see +-- when the other one is online. +function subscribe_both(jid1, jid2) + local ok1, err1 = subscribe(jid1, jid2); + local ok2, err2 = subscribe(jid2, jid1); + return ok1 and ok2, err1 or err2; +end + +-- Unsubscribes user from contact (not contact from user, if subscribed). +function unsubscribe(user_jid, contact_jid) + local user_username, user_host = jid_split(user_jid); + local contact_username, contact_host = jid_split(contact_jid); + + -- Update user's roster to say subscription is cancelled... + rostermanager.unsubscribe(user_username, user_host, contact_jid); + if prosody.hosts[contact_host] then -- Local host? + -- Update contact's roster to say subscription is cancelled... + rostermanager.unsubscribed(contact_username, contact_host, user_jid); + end + return true; +end + +-- Cancel any subscription in either direction. +function unsubscribe_both(jid1, jid2) + local ok1 = unsubscribe(jid1, jid2); + local ok2 = unsubscribe(jid2, jid1); + return ok1 and ok2; +end + +module:add_item("shell-command", { + section = "roster"; + section_desc = "View and manage user rosters (contact lists)"; + name = "show"; + desc = "Show a user's current roster"; + args = { + { name = "jid", type = "string" }; + { name = "sub", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, sub) --luacheck: ignore 212/self + local print = self.session.print; + local it = require "prosody.util.iterators"; + + local roster = assert(rm_load_roster(jid_split(jid))); + + local function sort_func(a, b) + if type(a) == "string" and type(b) == "string" then + return a < b; + else + return a == false; + end + end + + local count = 0; + if sub == "pending" then + local pending_subs = roster[false].pending or {}; + for pending_jid in it.sorted_pairs(pending_subs) do + print(pending_jid); + end + else + for contact, item in it.sorted_pairs(roster, sort_func) do + if contact and (not sub or sub == item.subscription) then + count = count + 1; + print(contact, ("sub=%s\task=%s"):format(item.subscription or "none", item.ask or "none")); + end + end + end + + return true, ("Showing %d entries"):format(count); + end; +}); + +module:add_item("shell-command", { + section = "roster"; + section_desc = "View and manage user rosters (contact lists)"; + name = "subscribe"; + desc = "Subscribe a user to another JID"; + args = { + { name = "jid", type = "string" }; + { name = "contact", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, contact) --luacheck: ignore 212/self + return subscribe(jid, contact); + end; +}); + +module:add_item("shell-command", { + section = "roster"; + section_desc = "View and manage user rosters (contact lists)"; + name = "subscribe_both"; + desc = "Subscribe a user and a contact JID to each other"; + args = { + { name = "jid", type = "string" }; + { name = "contact", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, contact) --luacheck: ignore 212/self + return subscribe_both(jid, contact); + end; +}); + + +module:add_item("shell-command", { + section = "roster"; + section_desc = "View and manage user rosters (contact lists)"; + name = "unsubscribe"; + desc = "Unsubscribe a user from another JID"; + args = { + { name = "jid", type = "string" }; + { name = "contact", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, contact) --luacheck: ignore 212/self + return unsubscribe(jid, contact); + end; +}); + +module:add_item("shell-command", { + section = "roster"; + section_desc = "View and manage user rosters (contact lists)"; + name = "unsubscribe_both"; + desc = "Unubscribe a user and a contact JID from each other"; + args = { + { name = "jid", type = "string" }; + { name = "contact", type = "string" }; + }; + host_selector = "jid"; + handler = function(self, jid, contact) --luacheck: ignore 212/self + return unsubscribe_both(jid, contact); + end; +}); + |