comparison mod_admin_message/mod_admin_message.lua @ 1594:620cc035ae1e

mod_admin_message: New IM-based administration console This module provides a console over XMPP. All the commands of the mod_admin_telnet module are available to Prosody admins from an XMPP client.
author Mikael Berthe <mikael@lilotux.net>
date Sun, 25 Jan 2015 19:52:39 +0100
parents
children 9ed6d44b9fed
comparison
equal deleted inserted replaced
1593:d9f3c66ea938 1594:620cc035ae1e
1 -- Prosody IM
2 --
3 -- mod_admin_message -- Console-over-XMPP implementation.
4 --
5 -- This module depends on Prosody's admin_telnet module
6 --
7 -- Copyright (C) 2008-2010 Matthew Wild
8 -- Copyright (C) 2008-2010 Waqas Hussain
9 -- Copyright (C) 2012-2013 Mikael Berthe
10 --
11 -- This project is MIT/X11 licensed. Please see the
12 -- COPYING file in the source package for more information.
13 --
14
15 local st = require "util.stanza";
16 local um_is_admin = require "core.usermanager".is_admin;
17
18 local admin_telnet = module:depends("admin_telnet");
19 local telnet_def_env = module:shared("/*/admin_telnet/env");
20 local telnet_commands = module:shared("/*/admin_telnet/commands");
21 local default_env_mt = { __index = telnet_def_env };
22
23 local host = module.host;
24
25 -- Create our own session. print() will store the results in a text
26 -- string. send(), quit(), disconnect() are no-op.
27 local function new_session ()
28 local session = {
29 send = function () end;
30 quit = function () end;
31 disconnect = function () end;
32 };
33
34 session.print = function (...)
35 local t = {};
36 for i=1,select("#", ...) do
37 t[i] = tostring(select(i, ...));
38 end
39 local text = "| "..table.concat(t, "\t");
40 if session.fulltext then
41 session.fulltext = session.fulltext .. "\n" .. text;
42 else
43 session.fulltext = text;
44 end
45 end
46
47 session.env = setmetatable({}, default_env_mt);
48
49 -- Load up environment with helper objects
50 for name, t in pairs(telnet_def_env) do
51 if type(t) == "table" then
52 session.env[name] = setmetatable({ session = session },
53 { __index = t });
54 end
55 end
56
57 return session;
58 end
59
60 local function on_message(event)
61 -- Check the type of the incoming stanza to avoid loops:
62 if event.stanza.attr.type == "error" then
63 return; -- We do not want to reply to these, so leave.
64 end
65
66 local userjid = event.stanza.attr.from;
67 local bodytag = event.stanza:get_child("body");
68 local body = bodytag and bodytag:get_text() or "";
69 if not body or body == "" then
70 -- We do not reply to empty messages (chatstates, etc.)
71 return true;
72 end
73
74 -- Check the requester is an admin user
75 if not um_is_admin(userjid, module.host) then
76 module:log("info", "Ignored request from non-admin: %s",
77 userjid);
78 return;
79 end
80
81 -- Create a session in order to use an admin_telnet-like environment
82 local session = new_session();
83
84 -- Process the message using admin_telnet's onincoming function
85 admin_telnet.console:process_line(session, body.."\n");
86
87 -- Strip trailing blank line
88 session.fulltext = tostring(session.fulltext):gsub("\n\|%s*$", "")
89
90 -- Send the reply stanza
91 local reply_stanza = st.message({ from = host, to = userjid,
92 type = "chat" });
93 reply_stanza = reply_stanza:body(session.fulltext);
94 module:send(reply_stanza);
95
96 return true;
97 end
98
99 local function on_presence(event)
100
101 local send_presence = false;
102
103 local userjid = event.stanza.attr.from;
104
105 -- Check the requester is an admin user
106 if not um_is_admin(userjid, module.host) then
107 module:log("info", "Ignored presence from non-admin: %s",
108 userjid);
109 return;
110 end
111
112 if (event.stanza.attr.type == "subscribe") then
113 module:log("info", "Subscription request from %s", userjid);
114 send_presence = true;
115 -- Send a subscription ack
116 local presence_stanza = st.presence({ from = host,
117 to = userjid, type = "subscribed",
118 id = event.stanza.attr.id });
119 module:send(presence_stanza);
120 elseif (event.stanza.attr.type == "probe") then
121 send_presence = true;
122 elseif (event.stanza.attr.type == "unsubscribe") then
123 -- For information only...
124 module:log("info", "Unsubscription request from %s", userjid);
125 end
126
127 if (send_presence == true) then
128 -- Send a presence stanza
129 module:send(st.presence({ from = host, to = userjid }));
130 end
131 return true;
132 end
133
134 module:hook("message/bare", on_message);
135 module:hook("presence/bare", on_presence);