Diff

plugins/mod_admin_telnet.lua @ 6054:7a5ddbaf758d

Merge 0.9->0.10
author Matthew Wild <mwild1@gmail.com>
date Wed, 02 Apr 2014 17:41:38 +0100
parent 6017:ac0879a8190a
child 6067:dab7ad6fa23c
line wrap: on
line diff
--- a/plugins/mod_admin_telnet.lua	Wed Apr 02 14:31:19 2014 +0100
+++ b/plugins/mod_admin_telnet.lua	Wed Apr 02 17:41:38 2014 +0100
@@ -1,7 +1,7 @@
 -- Prosody IM
 -- Copyright (C) 2008-2010 Matthew Wild
 -- Copyright (C) 2008-2010 Waqas Hussain
--- 
+--
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
 --
@@ -17,7 +17,6 @@
 
 local prosody = _G.prosody;
 local hosts = prosody.hosts;
-local incoming_s2s = prosody.incoming_s2s;
 
 local console_listener = { default_port = 5582; default_mode = "*a"; interface = "127.0.0.1" };
 
@@ -60,20 +59,20 @@
 			disconnect = function () conn:close(); end;
 			};
 	session.env = setmetatable({}, default_env_mt);
-	
+
 	-- Load up environment with helper objects
 	for name, t in pairs(def_env) do
 		if type(t) == "table" then
 			session.env[name] = setmetatable({ session = session }, { __index = t });
 		end
 	end
-	
+
 	return session;
 end
 
 function console:process_line(session, line)
 	local useglobalenv;
-	
+
 	if line:match("^>") then
 		line = line:gsub("^>", "");
 		useglobalenv = true;
@@ -87,9 +86,9 @@
 			return;
 		end
 	end
-	
+
 	session.env._ = line;
-	
+
 	local chunkname = "=console";
 	local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil
 	local chunk, err = envload("return "..line, chunkname, env);
@@ -103,20 +102,20 @@
 			return;
 		end
 	end
-	
+
 	local ranok, taskok, message = pcall(chunk);
-	
+
 	if not (ranok or message or useglobalenv) and commands[line:lower()] then
 		commands[line:lower()](session, line);
 		return;
 	end
-	
+
 	if not ranok then
 		session.print("Fatal error while running command, it did not complete");
 		session.print("Error: "..taskok);
 		return;
 	end
-	
+
 	if not message then
 		session.print("Result: "..tostring(taskok));
 		return;
@@ -125,7 +124,7 @@
 		session.print("Message: "..tostring(message));
 		return;
 	end
-	
+
 	session.print("OK: "..tostring(message));
 end
 
@@ -344,9 +343,9 @@
 
 function def_env.module:load(name, hosts, config)
 	local mm = require "modulemanager";
-	
+
 	hosts = get_hosts_set(hosts);
-	
+
 	-- Load the module for each host
 	local ok, err, count, mod = true, nil, 0, nil;
 	for host in hosts do
@@ -367,15 +366,15 @@
 			end
 		end
 	end
-	
-	return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err));	
+
+	return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err));
 end
 
 function def_env.module:unload(name, hosts)
 	local mm = require "modulemanager";
 
 	hosts = get_hosts_set(hosts, name);
-	
+
 	-- Unload the module for each host
 	local ok, err, count = true, nil, 0;
 	for host in hosts do
@@ -433,7 +432,7 @@
 	if type(hosts) ~= "table" then
 		return false, "Please supply a host or a list of hosts you would like to see";
 	end
-	
+
 	local print = self.session.print;
 	for _, host in ipairs(hosts) do
 		print((host == "*" and "Global" or host)..":");
@@ -483,6 +482,25 @@
 function def_env.hosts:add(name)
 end
 
+local function session_flags(session, line)
+	line = line or {};
+	if session.cert_identity_status == "valid" then
+		line[#line+1] = "(secure)";
+	elseif session.secure then
+		line[#line+1] = "(encrypted)";
+	end
+	if session.compressed then
+		line[#line+1] = "(compressed)";
+	end
+	if session.smacks then
+		line[#line+1] = "(sm)";
+	end
+	if session.ip and session.ip:match(":") then
+		line[#line+1] = "(IPv6)";
+	end
+	return table.concat(line, " ");
+end
+
 def_env.c2s = {};
 
 local function show_c2s(callback)
@@ -501,7 +519,7 @@
 	show_c2s(function (jid, session)
 		if (not match_jid) or jid:match(match_jid) then
 			count = count + 1;
-		end		
+		end
 	end);
 	return true, "Total: "..count.." clients";
 end
@@ -518,15 +536,10 @@
 			count = count + 1;
 			local status, priority = "unavailable", tostring(session.priority or "-");
 			if session.presence then
-				status = session.presence:child_with_name("show");
-				if status then
-					status = status:get_text() or "[invalid!]";
-				else
-					status = "available";
-				end
+				status = session.presence:get_child_text("show") or "available";
 			end
-			print("   "..jid.." - "..status.."("..priority..")");
-		end		
+			print(session_flags(session, { "   "..jid.." - "..status.."("..priority..")" }));
+		end
 	end);
 	return true, "Total: "..count.." clients";
 end
@@ -537,7 +550,7 @@
 		if ((not match_jid) or jid:match(match_jid)) and not session.secure then
 			count = count + 1;
 			print(jid);
-		end		
+		end
 	end);
 	return true, "Total: "..count.." insecure client connections";
 end
@@ -548,7 +561,7 @@
 		if ((not match_jid) or jid:match(match_jid)) and session.secure then
 			count = count + 1;
 			print(jid);
-		end		
+		end
 	end);
 	return true, "Total: "..count.." secure client connections";
 end
@@ -564,96 +577,80 @@
 	return true, "Total: "..count.." sessions closed";
 end
 
-local function session_flags(session, line)
-	if session.cert_identity_status == "valid" then
-		line[#line+1] = "(secure)";
-	elseif session.secure then
-		line[#line+1] = "(encrypted)";
-	end
-	if session.compressed then
-		line[#line+1] = "(compressed)";
-	end
-	if session.smacks then
-		line[#line+1] = "(sm)";
-	end
-	if session.conn and session.conn:ip():match(":") then
-		line[#line+1] = "(IPv6)";
-	end
-	return table.concat(line, " ");
-end
 
 def_env.s2s = {};
 function def_env.s2s:show(match_jid)
-	local _print = self.session.print;
 	local print = self.session.print;
-	
+
 	local count_in, count_out = 0,0;
-	
-	for host, host_session in pairs(hosts) do
-		print = function (...) _print(host); _print(...); print = _print; end
-		for remotehost, session in pairs(host_session.s2sout) do
-			if (not match_jid) or remotehost:match(match_jid) or host:match(match_jid) then
-				count_out = count_out + 1;
-				print(session_flags(session, {"   ", host, "->", remotehost}));
-				if session.sendq then
-					print("        There are "..#session.sendq.." queued outgoing stanzas for this connection");
-				end
-				if session.type == "s2sout_unauthed" then
-					if session.connecting then
-						print("        Connection not yet established");
-						if not session.srv_hosts then
-							if not session.conn then
-								print("        We do not yet have a DNS answer for this host's SRV records");
-							else
-								print("        This host has no SRV records, using A record instead");
-							end
-						elseif session.srv_choice then
-							print("        We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts);
-							local srv_choice = session.srv_hosts[session.srv_choice];
-							print("        Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269));
+	local s2s_list = { };
+
+	local s2s_sessions = module:shared"/*/s2s/sessions";
+	for _, session in pairs(s2s_sessions) do
+		local remotehost, localhost, direction;
+		if session.direction == "outgoing" then
+			direction = "->";
+			count_out = count_out + 1;
+			remotehost, localhost = session.to_host or "?", session.from_host or "?";
+		else
+			direction = "<-";
+			count_in = count_in + 1;
+			remotehost, localhost = session.from_host or "?", session.to_host or "?";
+		end
+		local sess_lines = { l = localhost, r = remotehost,
+			session_flags(session, { "", direction, remotehost or "?",
+				"["..session.type..tostring(session):match("[a-f0-9]*$").."]" })};
+
+		if (not match_jid) or remotehost:match(match_jid) or localhost:match(match_jid) then
+			table.insert(s2s_list, sess_lines);
+			local print = function (s) table.insert(sess_lines, "        "..s); end
+			if session.sendq then
+				print("There are "..#session.sendq.." queued outgoing stanzas for this connection");
+			end
+			if session.type == "s2sout_unauthed" then
+				if session.connecting then
+					print("Connection not yet established");
+					if not session.srv_hosts then
+						if not session.conn then
+							print("We do not yet have a DNS answer for this host's SRV records");
+						else
+							print("This host has no SRV records, using A record instead");
 						end
-					elseif session.notopen then
-						print("        The <stream> has not yet been opened");
-					elseif not session.dialback_key then
-						print("        Dialback has not been initiated yet");
-					elseif session.dialback_key then
-						print("        Dialback has been requested, but no result received");
+					elseif session.srv_choice then
+						print("We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts);
+						local srv_choice = session.srv_hosts[session.srv_choice];
+						print("Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269));
 					end
+				elseif session.notopen then
+					print("The <stream> has not yet been opened");
+				elseif not session.dialback_key then
+					print("Dialback has not been initiated yet");
+				elseif session.dialback_key then
+					print("Dialback has been requested, but no result received");
 				end
 			end
-		end	
-		local subhost_filter = function (h)
-				return (match_jid and h:match(match_jid));
-			end
-		for session in pairs(incoming_s2s) do
-			if session.to_host == host and ((not match_jid) or host:match(match_jid)
-				or (session.from_host and session.from_host:match(match_jid))
-				-- Pft! is what I say to list comprehensions
-				or (session.hosts and #array.collect(keys(session.hosts)):filter(subhost_filter)>0)) then
-				count_in = count_in + 1;
-				print(session_flags(session, {"   ", host, "<-", session.from_host or "(unknown)"}));
-				if session.type == "s2sin_unauthed" then
-						print("        Connection not yet authenticated");
-				end
+			if session.type == "s2sin_unauthed" then
+				print("Connection not yet authenticated");
+			elseif session.type == "s2sin" then
 				for name in pairs(session.hosts) do
 					if name ~= session.from_host then
-						print("        also hosts "..tostring(name));
+						print("also hosts "..tostring(name));
 					end
 				end
 			end
 		end
-		
-		print = _print;
 	end
-	
-	for session in pairs(incoming_s2s) do
-		if not session.to_host and ((not match_jid) or session.from_host and session.from_host:match(match_jid)) then
-			count_in = count_in + 1;
-			print("Other incoming s2s connections");
-			print("    (unknown) <- "..(session.from_host or "(unknown)"));			
-		end
+
+	-- Sort by local host, then remote host
+	table.sort(s2s_list, function(a,b)
+		if a.l == b.l then return a.r < b.r; end
+		return a.l < b.l;
+	end);
+	local lasthost;
+	for _, sess_lines in ipairs(s2s_list) do
+		if sess_lines.l ~= lasthost then print(sess_lines.l); lasthost=sess_lines.l end
+		for _, line in ipairs(sess_lines) do print(line); end
 	end
-	
 	return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections";
 end
 
@@ -685,14 +682,9 @@
 function def_env.s2s:showcert(domain)
 	local ser = require "util.serialization".serialize;
 	local print = self.session.print;
-	local domain_sessions = set.new(array.collect(keys(incoming_s2s)))
-		/function(session) return session.from_host == domain and session or nil; end;
-	for local_host in values(prosody.hosts) do
-		local s2sout = local_host.s2sout;
-		if s2sout and s2sout[domain] then
-			domain_sessions:add(s2sout[domain]);
-		end
-	end
+	local s2s_sessions = module:shared"/*/s2s/sessions";
+	local domain_sessions = set.new(array.collect(values(s2s_sessions)))
+		/function(session) return (session.to_host == domain or session.from_host == domain) and session or nil; end;
 	local cert_set = {};
 	for session in domain_sessions do
 		local conn = session.conn;
@@ -731,18 +723,18 @@
 	local domain_certs = array.collect(values(cert_set));
 	-- Phew. We now have a array of unique certificates presented by domain.
 	local n_certs = #domain_certs;
-	
+
 	if n_certs == 0 then
 		return "No certificates found for "..domain;
 	end
-	
+
 	local function _capitalize_and_colon(byte)
 		return string.upper(byte)..":";
 	end
 	local function pretty_fingerprint(hash)
 		return hash:gsub("..", _capitalize_and_colon):sub(1, -2);
 	end
-	
+
 	for cert_info in values(domain_certs) do
 		local certs = cert_info.certs;
 		local cert = certs[1];
@@ -783,76 +775,38 @@
 
 function def_env.s2s:close(from, to)
 	local print, count = self.session.print, 0;
-	
-	if not (from and to) then
+	local s2s_sessions = module:shared"/*/s2s/sessions";
+
+	local match_id;
+	if from and not to then
+		match_id, from = from;
+	elseif not to then
 		return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'";
 	elseif from == to then
 		return false, "Both from and to are the same... you can't do that :)";
 	end
-	
-	if hosts[from] and not hosts[to] then
-		-- Is an outgoing connection
-		local session = hosts[from].s2sout[to];
-		if not session then
-			print("No outgoing connection from "..from.." to "..to)
-		else
+
+	for _, session in pairs(s2s_sessions) do
+		local id = session.type..tostring(session):match("[a-f0-9]+$");
+		if (match_id and match_id == id)
+		or (session.from_host == from and session.to_host == to) then
+			print(("Closing connection from %s to %s [%s]"):format(session.from_host, session.to_host, id));
 			(session.close or s2smanager.destroy_session)(session);
-			count = count + 1;
-			print("Closed outgoing session from "..from.." to "..to);
+			count = count + 1 ;
 		end
-	elseif hosts[to] and not hosts[from] then
-		-- Is an incoming connection
-		for session in pairs(incoming_s2s) do
-			if session.to_host == to and session.from_host == from then
-				(session.close or s2smanager.destroy_session)(session);
-				count = count + 1;
 			end
-		end
-		
-		if count == 0 then
-			print("No incoming connections from "..from.." to "..to);
-		else
-			print("Closed "..count.." incoming session"..((count == 1 and "") or "s").." from "..from.." to "..to);
-		end
-	elseif hosts[to] and hosts[from] then
-		return false, "Both of the hostnames you specified are local, there are no s2s sessions to close";
-	else
-		return false, "Neither of the hostnames you specified are being used on this server";
-	end
-	
 	return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s");
 end
 
 function def_env.s2s:closeall(host)
         local count = 0;
-
-        if not host or type(host) ~= "string" then return false, "wrong syntax: please use s2s:closeall('hostname.tld')"; end
-        if hosts[host] then
-                for session in pairs(incoming_s2s) do
-                        if session.to_host == host then
-                                (session.close or s2smanager.destroy_session)(session);
+	local s2s_sessions = module:shared"/*/s2s/sessions";
+	for _,session in pairs(s2s_sessions) do
+		if not host or session.from_host == host or session.to_host == host then
+			session:close();
                                 count = count + 1;
                         end
                 end
-                for _, session in pairs(hosts[host].s2sout) do
-                        (session.close or s2smanager.destroy_session)(session);
-                        count = count + 1;
-                end
-        else
-                for session in pairs(incoming_s2s) do
-			if session.from_host == host then
-				(session.close or s2smanager.destroy_session)(session);
-				count = count + 1;
-			end
-		end
-		for _, h in pairs(hosts) do
-			if h.s2sout[host] then
-				(h.s2sout[host].close or s2smanager.destroy_session)(h.s2sout[host]);
-				count = count + 1;
-			end
-		end
-        end
-
 	if count == 0 then return false, "No sessions to close.";
 	else return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end
 end
@@ -1076,12 +1030,12 @@
 	local option = module:get_option("console_banner");
 	if option == nil or option == "full" or option == "graphic" then
 		session.print [[
-                   ____                \   /     _       
-                    |  _ \ _ __ ___  ___  _-_   __| |_   _ 
+                   ____                \   /     _
+                    |  _ \ _ __ ___  ___  _-_   __| |_   _
                     | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
                     |  __/| | | (_) \__ \ |_| | (_| | |_| |
                     |_|   |_|  \___/|___/\___/ \__,_|\__, |
-                    A study in simplicity            |___/ 
+                    A study in simplicity            |___/
 
 ]]
 	end