Backport to Prosody 0.8 0.8
authorMikael Berthe <mikael@lilotux.net>
Tue, 31 Jul 2012 18:46:54 +0200
branch0.8
changeset 2 e193f80521cc
parent 1 7265595dbc3b
Backport to Prosody 0.8
mod_admin_messageconsole.lua
--- a/mod_admin_messageconsole.lua	Tue Jul 31 18:31:42 2012 +0200
+++ b/mod_admin_messageconsole.lua	Tue Jul 31 18:46:54 2012 +0200
@@ -1,6 +1,8 @@
 -- Prosody IM
 --
 -- This module depends on Prosody's admin_telnet module
+-- and some code (redirect_output() and onincoming() from console_listener)
+-- is duplicated here...
 --
 -- Copyright (C) 2008-2010 Matthew Wild
 -- Copyright (C) 2008-2010 Waqas Hussain
@@ -13,10 +15,9 @@
 local st = require "util.stanza";
 local um_is_admin = require "core.usermanager".is_admin;
 
-local admin_telnet = module:depends("admin_telnet");
-local telnet_def_env = module:shared("/*/admin_telnet/env");
-local telnet_commands = module:shared("/*/admin_telnet/commands");
-local default_env_mt = { __index = telnet_def_env };
+local telnet_def_env;
+local default_env_mt;
+local telnet_commands;
 
 local host = module.host;
 
@@ -29,6 +30,19 @@
 			disconnect  = function ()  end;
 			};
 
+	-- Initialization
+	-- Hack for 0.8 - Let's get dependencies now as we're almost
+	-- certain the admin_telnet module has been loaded by now.
+	if not telnet_def_env then
+		local prosody = _G.prosody;
+		local console = prosody.console;
+
+		telnet_def_env = console.env;
+		default_env_mt = { __index = telnet_def_env };
+
+		telnet_commands = console.commands;
+	end
+
 	session.print = function (...)
 		local t = {};
 		for i=1,select("#", ...) do
@@ -55,7 +69,94 @@
 	return session;
 end
 
-local function on_message(event)
+-- This function is 100% duplicated from mod_admin_telnet.
+function onincoming(session, data)
+
+	local commands = telnet_commands;
+	local partial = session.partial_data;
+	if partial then
+		data = partial..data;
+	end
+
+	local function redirect_output(_G, session)
+		local env = setmetatable({ print = session.print },
+			     { __index = function (t, k) return rawget(_G, k); end });
+		env.dofile = function(name)
+			local f, err = loadfile(name);
+			if not f then return f, err; end
+			return setfenv(f, env)();
+		end;
+		return env;
+	end
+
+	for line in data:gmatch("[^\n]*[\n\004]") do
+		-- Handle data (loop allows us to break to add \0 after response)
+		repeat
+			local useglobalenv;
+
+			if line:match("^>") then
+				line = line:gsub("^>", "");
+				useglobalenv = true;
+			elseif line == "\004" then
+				commands["bye"](session, line);
+				break;
+			else
+				local command = line:lower();
+				command = line:match("^%w+") or line:match("%p");
+				if commands[command] then
+					commands[command](session, line);
+					break;
+				end
+			end
+
+			session.env._ = line;
+
+			local chunkname = "=console";
+			local chunk, err = loadstring("return "..line, chunkname);
+			if not chunk then
+				chunk, err = loadstring(line, chunkname);
+				if not chunk then
+					err = err:gsub("^%[string .-%]:%d+: ", "");
+					err = err:gsub("^:%d+: ", "");
+					err = err:gsub("'<eof>'", "the end of the line");
+					session.print("Sorry, I couldn't understand that... "..err);
+					break;
+				end
+			end
+
+			setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil);
+
+			local ranok, taskok, message = pcall(chunk);
+
+			if not (ranok or message or useglobalenv) and commands[line:lower()] then
+				commands[line:lower()](session, line);
+				break;
+			end
+
+			if not ranok then
+				session.print("Fatal error while running command, it did not complete");
+				session.print("Error: "..taskok);
+				break;
+			end
+
+			if not message then
+				session.print("Result: "..tostring(taskok));
+				break;
+			elseif (not taskok) and message then
+				session.print("Command completed with a problem");
+				session.print("Message: "..tostring(message));
+				break;
+			end
+
+			session.print("OK: "..tostring(message));
+		until true
+
+		session.send(string.char(0));
+	end
+	session.partial_data = data:match("[^\n]+$");
+end
+
+function on_message(event)
 	-- Check the type of the incoming stanza to avoid loops:
 	if event.stanza.attr.type == "error" then
 		return; -- We do not want to reply to these, so leave.
@@ -80,7 +181,7 @@
 	local session = new_session();
 
 	-- Process the message using admin_telnet's onincoming function
-	admin_telnet.console_incoming_message(session, body.."\n");
+	onincoming(session, body.."\n");
 
 	-- Strip trailing blank line
 	session.fulltext = tostring(session.fulltext):gsub("\n\|%s*$", "")
@@ -89,7 +190,7 @@
 	local reply_stanza = st.message({ from = host, to = userjid,
 					type = "chat" });
 	reply_stanza = reply_stanza:body(session.fulltext);
-	module:send(reply_stanza);
+	core_post_stanza(hosts[module.host], reply_stanza);
 
 	return true;
 end
@@ -114,7 +215,7 @@
 		local presence_stanza = st.presence({ from = host,
 					to = userjid, type = "subscribed",
 					id = event.stanza.attr.id });
-		module:send(presence_stanza);
+		core_post_stanza(hosts[module.host], presence_stanza);
 	elseif (event.stanza.attr.type == "probe") then
 		send_presence = true;
 	elseif (event.stanza.attr.type == "unsubscribe") then
@@ -124,7 +225,9 @@
 
 	if (send_presence == true) then
 		-- Send a presence stanza
-		module:send(st.presence({ from = host, to = userjid }));
+		local presence_stanza = st.presence({ from = host,
+						      to = userjid });
+		core_post_stanza(hosts[module.host], presence_stanza);
 	end
 	return true;
 end