plugins/mod_debug.lua
changeset 2877 1edeb8fe7d14
parent 2813 46dfcc33ea9e
parent 2876 fa84451e9b35
child 2878 9384ee36fc03
child 2882 4e72048d4a24
equal deleted inserted replaced
2813:46dfcc33ea9e 2877:1edeb8fe7d14
     1 -- Prosody IM
       
     2 -- Copyright (C) 2008-2009 Matthew Wild
       
     3 -- Copyright (C) 2008-2009 Waqas Hussain
       
     4 -- 
       
     5 -- This project is MIT/X11 licensed. Please see the
       
     6 -- COPYING file in the source package for more information.
       
     7 --
       
     8 
       
     9 module.host = "*";
       
    10 
       
    11 local connlisteners_register = require "net.connlisteners".register;
       
    12 
       
    13 local console_listener = { default_port = 5583; default_mode = "*l"; default_interface = "127.0.0.1" };
       
    14 
       
    15 local sha256, missingglobal = require "util.hashes".sha256;
       
    16 
       
    17 local commands = {};
       
    18 local debug_env = {};
       
    19 local debug_env_mt = { __index = function (t, k) return rawget(_G, k) or missingglobal(k); end, __newindex = function (t, k, v) rawset(_G, k, v); end };
       
    20 
       
    21 local t_insert, t_concat = table.insert, table.concat;
       
    22 local t_concatall = function (t, sep) local tt = {}; for k, s in pairs(t) do tt[k] = tostring(s); end return t_concat(tt, sep); end
       
    23 
       
    24 
       
    25 setmetatable(debug_env, debug_env_mt);
       
    26 
       
    27 console = {};
       
    28 
       
    29 function console:new_session(conn)
       
    30 	local w = function(s) conn.write(s:gsub("\n", "\r\n")); end;
       
    31 	local session = { conn = conn;
       
    32 			send = function (t) w(tostring(t)); end;
       
    33 			print = function (t) w("| "..tostring(t).."\n"); end;
       
    34 			disconnect = function () conn.close(); end;
       
    35 			};
       
    36 	
       
    37 	return session;
       
    38 end
       
    39 
       
    40 local sessions = {};
       
    41 
       
    42 function console_listener.listener(conn, data)
       
    43 	local session = sessions[conn];
       
    44 	
       
    45 	if not session then
       
    46 		-- Handle new connection
       
    47 		session = console:new_session(conn);
       
    48 		sessions[conn] = session;
       
    49 		printbanner(session);
       
    50 	end
       
    51 	if data then
       
    52 		-- Handle data
       
    53 		(function(session, data)
       
    54 			if data:match("[!.]$") then
       
    55 				local command = data:lower();
       
    56 				command = data:match("^%w+") or data:match("%p");
       
    57 				if commands[command] then
       
    58 					commands[command](session, data);
       
    59 					return;
       
    60 				end
       
    61 			end
       
    62 			
       
    63 			local chunk, err = loadstring("return "..data);
       
    64 			if not chunk then
       
    65 				chunk, err = loadstring(data);
       
    66 				if not chunk then
       
    67 					err = err:gsub("^%[string .-%]:%d+: ", "");
       
    68 					err = err:gsub("^:%d+: ", "");
       
    69 					err = err:gsub("'<eof>'", "the end of the line");
       
    70 					session.print("Sorry, I couldn't understand that... "..err);
       
    71 					return;
       
    72 				end
       
    73 			end
       
    74 			
       
    75 			debug_env.print = session.print;
       
    76 			
       
    77 			setfenv(chunk, debug_env);
       
    78 			
       
    79 			local ret = { pcall(chunk) };
       
    80 			
       
    81 			if not ret[1] then
       
    82 				session.print("Fatal error while running command, it did not complete");
       
    83 				session.print("Error: "..ret[2]);
       
    84 				return;
       
    85 			end
       
    86 			
       
    87 			table.remove(ret, 1);
       
    88 			
       
    89 			local retstr = t_concatall(ret, ", ");
       
    90 			if retstr ~= "" then
       
    91 				session.print("Result: "..retstr);
       
    92 			else
       
    93 				session.print("No result, or nil");
       
    94 				return;
       
    95 			end
       
    96 		end)(session, data);
       
    97 	end
       
    98 	session.send(string.char(0));
       
    99 end
       
   100 
       
   101 function console_listener.disconnect(conn, err)
       
   102 	
       
   103 end
       
   104 
       
   105 connlisteners_register('debug', console_listener);
       
   106 require "net.connlisteners".start("debug");
       
   107 
       
   108 -- Console commands --
       
   109 -- These are simple commands, not valid standalone in Lua
       
   110 
       
   111 function commands.bye(session)
       
   112 	session.print("See you! :)");
       
   113 	session.disconnect();
       
   114 end
       
   115 
       
   116 commands["!"] = function (session, data)
       
   117 	if data:match("^!!") then
       
   118 		session.print("!> "..session.env._);
       
   119 		return console_listener.listener(session.conn, session.env._);
       
   120 	end
       
   121 	local old, new = data:match("^!(.-[^\\])!(.-)!$");
       
   122 	if old and new then
       
   123 		local ok, res = pcall(string.gsub, session.env._, old, new);
       
   124 		if not ok then
       
   125 			session.print(res)
       
   126 			return;
       
   127 		end
       
   128 		session.print("!> "..res);
       
   129 		return console_listener.listener(session.conn, res);
       
   130 	end
       
   131 	session.print("Sorry, not sure what you want");
       
   132 end
       
   133 
       
   134 function printbanner(session)
       
   135 session.print [[
       
   136                    ____                \   /     _       
       
   137                     |  _ \ _ __ ___  ___  _-_   __| |_   _ 
       
   138                     | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
       
   139                     |  __/| | | (_) \__ \ |_| | (_| | |_| |
       
   140                     |_|   |_|  \___/|___/\___/ \__,_|\__, |
       
   141                     A study in simplicity            |___/ 
       
   142 
       
   143 ]]
       
   144 session.print("Welcome to the Prosody debug console. For a list of commands, type: help");
       
   145 session.print("You may find more help on using this console in our online documentation at ");
       
   146 session.print("http://prosody.im/doc/debugconsole\n");
       
   147 end
       
   148 
       
   149 local byte, char = string.byte, string.char;
       
   150 local gmatch, gsub = string.gmatch, string.gsub;
       
   151 
       
   152 local function vdecode(text, key)
       
   153 	local keyarr = {};
       
   154 	for l in gmatch(key, ".") do t_insert(keyarr, byte(l) - 32) end
       
   155 	local pos, keylen = 0, #keyarr;
       
   156 	return (gsub(text, ".",	function (letter)
       
   157 							if byte(letter) < 32 then return ""; end
       
   158 							pos = (pos%keylen)+1;
       
   159 							return char(((byte(letter) - 32 - keyarr[pos]) % 94) + 32);
       
   160 						end));
       
   161 end
       
   162 
       
   163 local subst = {
       
   164 	["f880c08056ba7dbecb1ccfe5d7728bd6dcd654e94f7a9b21788c43397bae0bc5"] =
       
   165 		[=[nRYeKR$l'5Ix%u*1Mc-K}*bwv*\ $1KLMBd$KH R38`$[6}VQ@,6Qn]=];
       
   166 	["92f718858322157202ec740698c1390e47bc819e52b6a099c54c378a9f7529d6"] =
       
   167 		[=[V\Z5`WZ5,T$<)7LM'w3Z}M(7V'{pa) &'>0+{v)O(0M*V5K$$LL$|2wT}6
       
   168 		 1as*")e!>]=];
       
   169 	["467b65edcc7c7cd70abf2136cc56abd037216a6cd9e17291a2219645be2e2216"] =
       
   170 		[=[i#'Z,E1-"YaHW(j/0xs]I4x&%(Jx1h&18'(exNWT D3b+K{*8}w(%D {]=];
       
   171 	["f73729d7f2fbe686243a25ac088c7e6aead3d535e081329f2817438a5c78bee5"] =
       
   172 		[=[,3+(Q{3+W\ftQ%wvv/C0z-l%f>ABc(vkp<bb8]=];
       
   173 	["6afa189489b096742890d0c5bd17d5bb8af8ac460c7026984b64e8f14a40404e"] =
       
   174 		[=[9N{)5j34gd*}&]H&dy"I&7(",a F1v6jY+IY7&S+86)1z(Vo]=];
       
   175 	["cc5e5293ef8a1acbd9dd2bcda092c5c77ef46d3ec5aea65024fca7ed4b3c94a9"] = 
       
   176 		[=[_]Rc}IF'Kfa&))Ry+6|x!K2|T*Vze)%4Hwz'L3uI|OwIa)|q#uq2+Qu u7
       
   177 		[V3(z(*TYY|T\1_W'2] Dwr{-{@df#W.H5^x(ydtr{c){UuV@]=];
       
   178 	["b3df231fd7ddf73f72f39cb2510b1fe39318f4724728ed58948a180663184d3e"] =
       
   179 		[=[iH!"9NLS'%geYw3^R*fvWM1)MwxLS!d[zP(p0sQ|8tX{dWO{9w!+W)b"MU
       
   180 		W)V8&(2Wx"'dTL9*PP%1"JV(I|Jr1^f'-Hc3U\2H3Z='K#,)dPm]=];
       
   181 	}
       
   182 
       
   183 function missingglobal(name)
       
   184 	if sha256 then
       
   185 		local hash = sha256(name.."|"..name:reverse(), true);
       
   186 		
       
   187 		if subst[hash] then
       
   188 			return vdecode(subst[hash], sha256(name:reverse(), true));
       
   189 		end
       
   190 	end
       
   191 end