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 15local st = require "util.stanza"; 16local um_is_admin = require "core.usermanager".is_admin; 17 18local admin_telnet = module:depends("admin_telnet"); 19local telnet_def_env = module:shared("/*/admin_telnet/env"); 20local telnet_commands = module:shared("/*/admin_telnet/commands"); 21local default_env_mt = { __index = telnet_def_env }; 22 23local 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. 27local 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; 58end 59 60local 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" }, session.fulltext); 93 module:send(reply_stanza); 94 95 return true; 96end 97 98local function on_presence(event) 99 100 local send_presence = false; 101 102 local userjid = event.stanza.attr.from; 103 104 -- Check the requester is an admin user 105 if not um_is_admin(userjid, module.host) then 106 module:log("info", "Ignored presence from non-admin: %s", 107 userjid); 108 return; 109 end 110 111 if (event.stanza.attr.type == "subscribe") then 112 module:log("info", "Subscription request from %s", userjid); 113 send_presence = true; 114 -- Send a subscription ack 115 local presence_stanza = st.presence({ from = host, 116 to = userjid, type = "subscribed", 117 id = event.stanza.attr.id }); 118 module:send(presence_stanza); 119 elseif (event.stanza.attr.type == "probe") then 120 send_presence = true; 121 elseif (event.stanza.attr.type == "unsubscribe") then 122 -- For information only... 123 module:log("info", "Unsubscription request from %s", userjid); 124 end 125 126 if (send_presence == true) then 127 -- Send a presence stanza 128 module:send(st.presence({ from = host, to = userjid })); 129 end 130 return true; 131end 132 133module:hook("message/bare", on_message); 134module:hook("presence/bare", on_presence); 135