Software /
code /
prosody
Comparison
plugins/mod_admin_adhoc.lua @ 3487:b5c92275910b
mod_admin_adhoc: New module with merged functonality of mod_adhoc_cmd_admin and mod_adhoc_cmd_modules (of prosody-modules fame)
author | Florian Zeitz <florob@babelmonkeys.de> |
---|---|
date | Thu, 02 Sep 2010 23:09:49 +0200 |
child | 3540:bc139431830b |
comparison
equal
deleted
inserted
replaced
3486:8a46bb70016f | 3487:b5c92275910b |
---|---|
1 -- Copyright (C) 2009-2010 Florian Zeitz | |
2 -- | |
3 -- This file is MIT/X11 licensed. Please see the | |
4 -- COPYING file in the source package for more information. | |
5 -- | |
6 | |
7 local _G = _G; | |
8 | |
9 local prosody = _G.prosody; | |
10 local hosts = prosody.hosts; | |
11 local t_concat = table.concat; | |
12 | |
13 require "util.iterators"; | |
14 local usermanager_user_exists = require "core.usermanager".user_exists; | |
15 local usermanager_create_user = require "core.usermanager".create_user; | |
16 local usermanager_get_password = require "core.usermanager".get_password; | |
17 local usermanager_set_password = require "core.usermanager".set_password; | |
18 local is_admin = require "core.usermanager".is_admin; | |
19 local rm_load_roster = require "core.rostermanager".load_roster; | |
20 local st, jid, uuid = require "util.stanza", require "util.jid", require "util.uuid"; | |
21 local timer_add_task = require "util.timer".add_task; | |
22 local dataforms_new = require "util.dataforms".new; | |
23 local array = require "util.array"; | |
24 local modulemanager = require "modulemanager"; | |
25 | |
26 local adhoc_new = module:require "adhoc".new; | |
27 | |
28 function add_user_command_handler(self, data, state) | |
29 local add_user_layout = dataforms_new{ | |
30 title = "Adding a User"; | |
31 instructions = "Fill out this form to add a user."; | |
32 | |
33 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
34 { name = "accountjid", type = "jid-single", required = true, label = "The Jabber ID for the account to be added" }; | |
35 { name = "password", type = "text-private", label = "The password for this account" }; | |
36 { name = "password-verify", type = "text-private", label = "Retype password" }; | |
37 }; | |
38 | |
39 if state then | |
40 if data.action == "cancel" then | |
41 return { status = "canceled" }; | |
42 end | |
43 local fields = add_user_layout:data(data.form); | |
44 if not fields.accountjid then | |
45 return { status = "completed", error = { message = "You need to specify a JID." } }; | |
46 end | |
47 local username, host, resource = jid.split(fields.accountjid); | |
48 if data.to ~= host then | |
49 return { status = "completed", error = { message = "Trying to add a user on " .. host .. " but command was sent to " .. data.to}}; | |
50 end | |
51 if (fields["password"] == fields["password-verify"]) and username and host then | |
52 if usermanager_user_exists(username, host) then | |
53 return { status = "completed", error = { message = "Account already exists" } }; | |
54 else | |
55 if usermanager_create_user(username, fields.password, host) then | |
56 module:log("info", "Created new account " .. username.."@"..host); | |
57 return { status = "completed", info = "Account successfully created" }; | |
58 else | |
59 return { status = "completed", error = { message = "Failed to write data to disk" } }; | |
60 end | |
61 end | |
62 else | |
63 module:log("debug", (fields.accountjid or "<nil>") .. " " .. (fields.password or "<nil>") .. " " | |
64 .. (fields["password-verify"] or "<nil>")); | |
65 return { status = "completed", error = { message = "Invalid data.\nPassword mismatch, or empty username" } }; | |
66 end | |
67 else | |
68 return { status = "executing", form = add_user_layout }, "executing"; | |
69 end | |
70 end | |
71 | |
72 function change_user_password_command_handler(self, data, state) | |
73 local change_user_password_layout = dataforms_new{ | |
74 title = "Changing a User Password"; | |
75 instructions = "Fill out this form to change a user's password."; | |
76 | |
77 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
78 { name = "accountjid", type = "jid-single", required = true, label = "The Jabber ID for this account" }; | |
79 { name = "password", type = "text-private", required = true, label = "The password for this account" }; | |
80 }; | |
81 | |
82 if state then | |
83 if data.action == "cancel" then | |
84 return { status = "canceled" }; | |
85 end | |
86 local fields = change_user_password_layout:data(data.form); | |
87 if not fields.accountjid or fields.accountjid == "" or not fields.password then | |
88 return { status = "completed", error = { message = "Please specify username and password" } }; | |
89 end | |
90 local username, host, resource = jid.split(fields.accountjid); | |
91 if data.to ~= host then | |
92 return { status = "completed", error = { message = "Trying to change the password of a user on " .. host .. " but command was sent to " .. data.to}}; | |
93 end | |
94 if usermanager_user_exists(username, host) and usermanager_set_password(username, fields.password, host) then | |
95 return { status = "completed", info = "Password successfully changed" }; | |
96 else | |
97 return { status = "completed", error = { message = "User does not exist" } }; | |
98 end | |
99 else | |
100 return { status = "executing", form = change_user_password_layout }, "executing"; | |
101 end | |
102 end | |
103 | |
104 function delete_user_command_handler(self, data, state) | |
105 local delete_user_layout = dataforms_new{ | |
106 title = "Deleting a User"; | |
107 instructions = "Fill out this form to delete a user."; | |
108 | |
109 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
110 { name = "accountjids", type = "jid-multi", label = "The Jabber ID(s) to delete" }; | |
111 }; | |
112 | |
113 if state then | |
114 if data.action == "cancel" then | |
115 return { status = "canceled" }; | |
116 end | |
117 local fields = delete_user_layout:data(data.form); | |
118 local failed = {}; | |
119 local succeeded = {}; | |
120 for _, aJID in ipairs(fields.accountjids) do | |
121 local username, host, resource = jid.split(aJID); | |
122 if (host == data.to) and usermanager_user_exists(username, host) and disconnect_user(aJID) and usermanager_create_user(username, nil, host) then | |
123 module:log("debug", "User " .. aJID .. " has been deleted"); | |
124 succeeded[#succeeded+1] = aJID; | |
125 else | |
126 module:log("debug", "Tried to delete non-existant user "..aJID); | |
127 failed[#failed+1] = aJID; | |
128 end | |
129 end | |
130 return {status = "completed", info = (#succeeded ~= 0 and | |
131 "The following accounts were successfully deleted:\n"..t_concat(succeeded, "\n").."\n" or "").. | |
132 (#failed ~= 0 and | |
133 "The following accounts could not be deleted:\n"..t_concat(failed, "\n") or "") }; | |
134 else | |
135 return { status = "executing", form = delete_user_layout }, "executing"; | |
136 end | |
137 end | |
138 | |
139 function disconnect_user(match_jid) | |
140 local node, hostname, givenResource = jid.split(match_jid); | |
141 local host = hosts[hostname]; | |
142 local sessions = host.sessions[node] and host.sessions[node].sessions; | |
143 for resource, session in pairs(sessions or {}) do | |
144 if not givenResource or (resource == givenResource) then | |
145 module:log("debug", "Disconnecting "..node.."@"..hostname.."/"..resource); | |
146 session:close(); | |
147 end | |
148 end | |
149 return true; | |
150 end | |
151 | |
152 function end_user_session_handler(self, data, state) | |
153 local end_user_session_layout = dataforms_new{ | |
154 title = "Ending a User Session"; | |
155 instructions = "Fill out this form to end a user's session."; | |
156 | |
157 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
158 { name = "accountjids", type = "jid-multi", label = "The Jabber ID(s) for which to end sessions" }; | |
159 }; | |
160 | |
161 if state then | |
162 if data.action == "cancel" then | |
163 return { status = "canceled" }; | |
164 end | |
165 | |
166 local fields = end_user_session_layout:data(data.form); | |
167 local failed = {}; | |
168 local succeeded = {}; | |
169 for _, aJID in ipairs(fields.accountjids) do | |
170 local username, host, resource = jid.split(aJID); | |
171 if (host == data.to) and usermanager_user_exists(username, host) and disconnect_user(aJID) then | |
172 succeeded[#succeeded+1] = aJID; | |
173 else | |
174 failed[#failed+1] = aJID; | |
175 end | |
176 end | |
177 return {status = "completed", info = (#succeeded ~= 0 and | |
178 "The following accounts were successfully disconnected:\n"..t_concat(succeeded, "\n").."\n" or "").. | |
179 (#failed ~= 0 and | |
180 "The following accounts could not be disconnected:\n"..t_concat(failed, "\n") or "") }; | |
181 else | |
182 return { status = "executing", form = end_user_session_layout }, "executing"; | |
183 end | |
184 end | |
185 | |
186 local end_user_session_layout = dataforms_new{ | |
187 title = "Ending a User Session"; | |
188 instructions = "Fill out this form to end a user's session."; | |
189 | |
190 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
191 { name = "accountjids", type = "jid-multi", label = "The Jabber ID(s) for which to end sessions" }; | |
192 }; | |
193 | |
194 | |
195 function get_user_password_handler(self, data, state) | |
196 local get_user_password_layout = dataforms_new{ | |
197 title = "Getting User's Password"; | |
198 instructions = "Fill out this form to get a user's password."; | |
199 | |
200 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
201 { name = "accountjid", type = "jid-single", required = true, label = "The Jabber ID for which to retrieve the password" }; | |
202 }; | |
203 | |
204 local get_user_password_result_layout = dataforms_new{ | |
205 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
206 { name = "accountjid", type = "jid-single", label = "JID" }; | |
207 { name = "password", type = "text-single", label = "Password" }; | |
208 }; | |
209 | |
210 if state then | |
211 if data.action == "cancel" then | |
212 return { status = "canceled" }; | |
213 end | |
214 local fields = get_user_password_layout:data(data.form); | |
215 if not fields.accountjid then | |
216 return { status = "completed", error = { message = "Please specify a JID." } }; | |
217 end | |
218 local user, host, resource = jid.split(fields.accountjid); | |
219 local accountjid = ""; | |
220 local password = ""; | |
221 if host ~= data.to then | |
222 return { status = "completed", error = { message = "Tried to get password for a user on " .. host .. " but command was sent to " .. data.to } }; | |
223 elseif usermanager_user_exists(user, host) then | |
224 accountjid = fields.accountjid; | |
225 password = usermanager_get_password(user, host); | |
226 else | |
227 return { status = "completed", error = { message = "User does not exist" } }; | |
228 end | |
229 return { status = "completed", result = { layout = get_user_password_result_layout, values = {accountjid = accountjid, password = password} } }; | |
230 else | |
231 return { status = "executing", form = get_user_password_layout }, "executing"; | |
232 end | |
233 end | |
234 | |
235 function get_user_roster_handler(self, data, state) | |
236 local get_user_roster_layout = dataforms_new{ | |
237 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
238 { name = "accountjid", type = "jid-single", required = true, label = "The Jabber ID for which to retrieve the roster" }; | |
239 }; | |
240 | |
241 local get_user_roster_result_layout = dataforms_new{ | |
242 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
243 { name = "accountjid", type = "jid-single", label = "This is the roster for" }; | |
244 { name = "roster", type = "text-multi", label = "Roster XML" }; | |
245 }; | |
246 | |
247 if state then | |
248 if data.action == "cancel" then | |
249 return { status = "canceled" }; | |
250 end | |
251 | |
252 local fields = get_user_roster_layout:data(data.form); | |
253 | |
254 if not fields.accountjid then | |
255 return { status = "completed", error = { message = "Please specify a JID" } }; | |
256 end | |
257 | |
258 local user, host, resource = jid.split(fields.accountjid); | |
259 if host ~= data.to then | |
260 return { status = "completed", error = { message = "Tried to get roster for a user on " .. host .. " but command was sent to " .. data.to } }; | |
261 elseif not usermanager_user_exists(user, host) then | |
262 return { status = "completed", error = { message = "User does not exist" } }; | |
263 end | |
264 local roster = rm_load_roster(user, host); | |
265 | |
266 local query = st.stanza("query", { xmlns = "jabber:iq:roster" }); | |
267 for jid in pairs(roster) do | |
268 if jid ~= "pending" and jid then | |
269 query:tag("item", { | |
270 jid = jid, | |
271 subscription = roster[jid].subscription, | |
272 ask = roster[jid].ask, | |
273 name = roster[jid].name, | |
274 }); | |
275 for group in pairs(roster[jid].groups) do | |
276 query:tag("group"):text(group):up(); | |
277 end | |
278 query:up(); | |
279 end | |
280 end | |
281 | |
282 local query_text = query:__tostring(); -- TODO: Use upcoming pretty_print() function | |
283 query_text = query_text:gsub("><", ">\n<"); | |
284 | |
285 local result = get_user_roster_result_layout:form({ accountjid = user.."@"..host, roster = query_text }, "result"); | |
286 result:add_child(query); | |
287 return { status = "completed", other = result }; | |
288 else | |
289 return { status = "executing", form = get_user_roster_layout }, "executing"; | |
290 end | |
291 end | |
292 | |
293 function get_user_stats_handler(self, data, state) | |
294 local get_user_stats_layout = dataforms_new{ | |
295 title = "Get User Statistics"; | |
296 instructions = "Fill out this form to gather user statistics."; | |
297 | |
298 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
299 { name = "accountjid", type = "jid-single", required = true, label = "The Jabber ID for statistics" }; | |
300 }; | |
301 | |
302 local get_user_stats_result_layout = dataforms_new{ | |
303 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
304 { name = "ipaddresses", type = "text-multi", label = "IP Addresses" }; | |
305 { name = "rostersize", type = "text-single", label = "Roster size" }; | |
306 { name = "onlineresources", type = "text-multi", label = "Online Resources" }; | |
307 }; | |
308 | |
309 if state then | |
310 if data.action == "cancel" then | |
311 return { status = "canceled" }; | |
312 end | |
313 | |
314 local fields = get_user_stats_layout:data(data.form); | |
315 | |
316 if not fields.accountjid then | |
317 return { status = "completed", error = { message = "Please specify a JID." } }; | |
318 end | |
319 | |
320 local user, host, resource = jid.split(fields.accountjid); | |
321 if host ~= data.to then | |
322 return { status = "completed", error = { message = "Tried to get stats for a user on " .. host .. " but command was sent to " .. data.to } }; | |
323 elseif not usermanager_user_exists(user, host) then | |
324 return { status = "completed", error = { message = "User does not exist" } }; | |
325 end | |
326 local roster = rm_load_roster(user, host); | |
327 local rostersize = 0; | |
328 local IPs = ""; | |
329 local resources = ""; | |
330 for jid in pairs(roster) do | |
331 if jid ~= "pending" and jid then | |
332 rostersize = rostersize + 1; | |
333 end | |
334 end | |
335 for resource, session in pairs((hosts[host].sessions[user] and hosts[host].sessions[user].sessions) or {}) do | |
336 resources = resources .. "\n" .. resource; | |
337 IPs = IPs .. "\n" .. session.ip; | |
338 end | |
339 return { status = "completed", result = {layout = get_user_stats_result_layout, values = {ipaddresses = IPs, rostersize = tostring(rostersize), | |
340 onlineresources = resources}} }; | |
341 else | |
342 return { status = "executing", form = get_user_stats_layout }, "executing"; | |
343 end | |
344 end | |
345 | |
346 function get_online_users_command_handler(self, data, state) | |
347 local get_online_users_layout = dataforms_new{ | |
348 title = "Getting List of Online Users"; | |
349 instructions = "How many users should be returned at most?"; | |
350 | |
351 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
352 { name = "max_items", type = "list-single", label = "Maximum number of users", | |
353 value = { "25", "50", "75", "100", "150", "200", "all" } }; | |
354 { name = "details", type = "boolean", label = "Show details" }; | |
355 }; | |
356 | |
357 local get_online_users_result_layout = dataforms_new{ | |
358 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
359 { name = "onlineuserjids", type = "text-multi", label = "The list of all online users" }; | |
360 }; | |
361 | |
362 if state then | |
363 if data.action == "cancel" then | |
364 return { status = "canceled" }; | |
365 end | |
366 | |
367 local fields = get_online_users_layout:data(data.form); | |
368 | |
369 local max_items = nil | |
370 if fields.max_items ~= "all" then | |
371 max_items = tonumber(fields.max_items); | |
372 end | |
373 local count = 0; | |
374 local users = {}; | |
375 for username, user in pairs(hosts[data.to].sessions or {}) do | |
376 if (max_items ~= nil) and (count >= max_items) then | |
377 break; | |
378 end | |
379 users[#users+1] = username.."@"..data.to; | |
380 count = count + 1; | |
381 if fields.details then | |
382 for resource, session in pairs(user.sessions or {}) do | |
383 local status, priority = "unavailable", tostring(session.priority or "-"); | |
384 if session.presence then | |
385 status = session.presence:child_with_name("show"); | |
386 if status then | |
387 status = status:get_text() or "[invalid!]"; | |
388 else | |
389 status = "available"; | |
390 end | |
391 end | |
392 users[#users+1] = " - "..resource..": "..status.."("..priority..")"; | |
393 end | |
394 end | |
395 end | |
396 return { status = "completed", result = {layout = get_online_users_result_layout, values = {onlineuserjids=t_concat(users, "\n")}} }; | |
397 else | |
398 return { status = "executing", form = get_online_users_layout }, "executing"; | |
399 end | |
400 end | |
401 | |
402 function list_modules_handler(self, data, state) | |
403 local result = dataforms_new { | |
404 title = "List of loaded modules"; | |
405 | |
406 { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/modules#list" }; | |
407 { name = "modules", type = "text-multi", label = "The following modules are loaded:" }; | |
408 }; | |
409 | |
410 local modules = array.collect(keys(hosts[data.to].modules)):sort():concat("\n"); | |
411 | |
412 return { status = "completed", result = { layout = result; values = { modules = modules } } }; | |
413 end | |
414 | |
415 function load_module_handler(self, data, state) | |
416 local layout = dataforms_new { | |
417 title = "Load module"; | |
418 instructions = "Specify the module to be loaded"; | |
419 | |
420 { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/modules#load" }; | |
421 { name = "module", type = "text-single", required = true, label = "Module to be loaded:"}; | |
422 }; | |
423 if state then | |
424 if data.action == "cancel" then | |
425 return { status = "canceled" }; | |
426 end | |
427 local fields = layout:data(data.form); | |
428 if (not fields.module) or (fields.module == "") then | |
429 return { status = "completed", error = { | |
430 message = "Please specify a module." | |
431 } }; | |
432 end | |
433 if modulemanager.is_loaded(data.to, fields.module) then | |
434 return { status = "completed", info = "Module already loaded" }; | |
435 end | |
436 local ok, err = modulemanager.load(data.to, fields.module); | |
437 if ok then | |
438 return { status = "completed", info = 'Module "'..fields.module..'" successfully loaded on host "'..data.to..'".' }; | |
439 else | |
440 return { status = "completed", error = { message = 'Failed to load module "'..fields.module..'" on host "'..data.to.. | |
441 '". Error was: "'..tostring(err or "<unspecified>")..'"' } }; | |
442 end | |
443 else | |
444 local modules = array.collect(keys(hosts[data.to].modules)):sort(); | |
445 return { status = "executing", form = layout }, "executing"; | |
446 end | |
447 end | |
448 | |
449 -- TODO: Allow reloading multiple modules (depends on list-multi) | |
450 function reload_modules_handler(self, data, state) | |
451 local layout = dataforms_new { | |
452 title = "Reload module"; | |
453 instructions = "Select the module to be reloaded"; | |
454 | |
455 { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/modules#reload" }; | |
456 { name = "module", type = "list-single", required = true, label = "Module to be reloaded:"}; | |
457 }; | |
458 if state then | |
459 if data.action == "cancel" then | |
460 return { status = "canceled" }; | |
461 end | |
462 local fields = layout:data(data.form); | |
463 if (not fields.module) or (fields.module == "") then | |
464 return { status = "completed", error = { | |
465 message = "Please specify a module. (This means your client misbehaved, as this field is required)" | |
466 } }; | |
467 end | |
468 local ok, err = modulemanager.reload(data.to, fields.module); | |
469 if ok then | |
470 return { status = "completed", info = 'Module "'..fields.module..'" successfully reloaded on host "'..data.to..'".' }; | |
471 else | |
472 return { status = "completed", error = { message = 'Failed to reload module "'..fields.module..'" on host "'..data.to.. | |
473 '". Error was: "'..tostring(err)..'"' } }; | |
474 end | |
475 else | |
476 local modules = array.collect(keys(hosts[data.to].modules)):sort(); | |
477 return { status = "executing", form = { layout = layout; values = { module = modules } } }, "executing"; | |
478 end | |
479 end | |
480 | |
481 function send_to_online(message, server) | |
482 if server then | |
483 sessions = { [server] = hosts[server] }; | |
484 else | |
485 sessions = hosts; | |
486 end | |
487 | |
488 local c = 0; | |
489 for domain, session in pairs(sessions) do | |
490 for user in pairs(session.sessions or {}) do | |
491 c = c + 1; | |
492 message.attr.from = domain; | |
493 message.attr.to = user.."@"..domain; | |
494 core_post_stanza(session, message); | |
495 end | |
496 end | |
497 | |
498 return c; | |
499 end | |
500 | |
501 function shut_down_service_handler(self, data, state) | |
502 local shut_down_service_layout = dataforms_new{ | |
503 title = "Shutting Down the Service"; | |
504 instructions = "Fill out this form to shut down the service."; | |
505 | |
506 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/admin" }; | |
507 { name = "delay", type = "list-single", label = "Time delay before shutting down", | |
508 value = { {label = "30 seconds", value = "30"}, | |
509 {label = "60 seconds", value = "60"}, | |
510 {label = "90 seconds", value = "90"}, | |
511 {label = "2 minutes", value = "120"}, | |
512 {label = "3 minutes", value = "180"}, | |
513 {label = "4 minutes", value = "240"}, | |
514 {label = "5 minutes", value = "300"}, | |
515 }; | |
516 }; | |
517 { name = "announcement", type = "text-multi", label = "Announcement" }; | |
518 }; | |
519 | |
520 if state then | |
521 if data.action == "cancel" then | |
522 return { status = "canceled" }; | |
523 end | |
524 | |
525 local fields = shut_down_service_layout:data(data.form); | |
526 | |
527 if fields.announcement and #fields.announcement > 0 then | |
528 local message = st.message({type = "headline"}, fields.announcement):up() | |
529 :tag("subject"):text("Server is shutting down"); | |
530 send_to_online(message); | |
531 end | |
532 | |
533 timer_add_task(tonumber(fields.delay or "5"), prosody.shutdown); | |
534 | |
535 return { status = "completed", info = "Server is about to shut down" }; | |
536 else | |
537 return { status = "executing", form = shut_down_service_layout }, "executing"; | |
538 end | |
539 | |
540 return true; | |
541 end | |
542 | |
543 -- TODO: Allow unloading multiple modules (depends on list-multi) | |
544 function unload_modules_handler(self, data, state) | |
545 local layout = dataforms_new { | |
546 title = "Unload module"; | |
547 instructions = "Select the module to be unloaded"; | |
548 | |
549 { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/modules#unload" }; | |
550 { name = "module", type = "list-single", required = true, label = "Module to be unloaded:"}; | |
551 }; | |
552 if state then | |
553 if data.action == "cancel" then | |
554 return { status = "canceled" }; | |
555 end | |
556 local fields = layout:data(data.form); | |
557 if (not fields.module) or (fields.module == "") then | |
558 return { status = "completed", error = { | |
559 message = "Please specify a module. (This means your client misbehaved, as this field is required)" | |
560 } }; | |
561 end | |
562 local ok, err = modulemanager.unload(data.to, fields.module); | |
563 if ok then | |
564 return { status = "completed", info = 'Module "'..fields.module..'" successfully unloaded on host "'..data.to..'".' }; | |
565 else | |
566 return { status = "completed", error = { message = 'Failed to unload module "'..fields.module..'" on host "'..data.to.. | |
567 '". Error was: "'..tostring(err)..'"' } }; | |
568 end | |
569 else | |
570 local modules = array.collect(keys(hosts[data.to].modules)):sort(); | |
571 return { status = "executing", form = { layout = layout; values = { module = modules } } }, "executing"; | |
572 end | |
573 end | |
574 | |
575 local add_user_desc = adhoc_new("Add User", "http://jabber.org/protocol/admin#add-user", add_user_command_handler, "admin"); | |
576 local change_user_password_desc = adhoc_new("Change User Password", "http://jabber.org/protocol/admin#change-user-password", change_user_password_command_handler, "admin"); | |
577 local delete_user_desc = adhoc_new("Delete User", "http://jabber.org/protocol/admin#delete-user", delete_user_command_handler, "admin"); | |
578 local end_user_session_desc = adhoc_new("End User Session", "http://jabber.org/protocol/admin#end-user-session", end_user_session_handler, "admin"); | |
579 local get_user_password_desc = adhoc_new("Get User Password", "http://jabber.org/protocol/admin#get-user-password", get_user_password_handler, "admin"); | |
580 local get_user_roster_desc = adhoc_new("Get User Roster","http://jabber.org/protocol/admin#get-user-roster", get_user_roster_handler, "admin"); | |
581 local get_user_stats_desc = adhoc_new("Get User Statistics","http://jabber.org/protocol/admin#user-stats", get_user_stats_handler, "admin"); | |
582 local get_online_users_desc = adhoc_new("Get List of Online Users", "http://jabber.org/protocol/admin#get-online-users", get_online_users_command_handler, "admin"); | |
583 local list_modules_desc = adhoc_new("List loaded modules", "http://prosody.im/protocol/modules#list", list_modules_handler, "admin"); | |
584 local load_module_desc = adhoc_new("Load module", "http://prosody.im/protocol/modules#load", load_module_handler, "admin"); | |
585 local reload_modules_desc = adhoc_new("Reload module", "http://prosody.im/protocol/modules#reload", reload_modules_handler, "admin"); | |
586 local shut_down_service_desc = adhoc_new("Shut Down Service", "http://jabber.org/protocol/admin#shutdown", shut_down_service_handler, "admin"); | |
587 local unload_modules_desc = adhoc_new("Unload module", "http://prosody.im/protocol/modules#unload", unload_modules_handler, "admin"); | |
588 | |
589 module:add_item("adhoc", add_user_desc); | |
590 module:add_item("adhoc", change_user_password_desc); | |
591 module:add_item("adhoc", delete_user_desc); | |
592 module:add_item("adhoc", end_user_session_desc); | |
593 module:add_item("adhoc", get_user_password_desc); | |
594 module:add_item("adhoc", get_user_roster_desc); | |
595 module:add_item("adhoc", get_user_stats_desc); | |
596 module:add_item("adhoc", get_online_users_desc); | |
597 module:add_item("adhoc", list_modules_desc); | |
598 module:add_item("adhoc", load_module_desc); | |
599 module:add_item("adhoc", reload_modules_desc); | |
600 module:add_item("adhoc", shut_down_service_desc); | |
601 module:add_item("adhoc", unload_modules_desc); |