Merge 0.10->trunk
authorKim Alvefur <zash@zash.se>
Tue, 19 May 2015 16:33:47 +0200
changeset 6724 3807af36d773
parent 6708 c269ab6ab98a (current diff)
parent 6723 936cf2f7531f (diff)
child 6726 fb25dce69d41
Merge 0.10->trunk
core/hostmanager.lua
--- a/core/configmanager.lua	Fri May 15 15:33:31 2015 +0200
+++ b/core/configmanager.lua	Tue May 19 16:33:47 2015 +0200
@@ -28,7 +28,7 @@
 
 local parsers = {};
 
-local config_mt = { __index = function (t, k) return rawget(t, "*"); end};
+local config_mt = { __index = function (t, _) return rawget(t, "*"); end};
 local config = setmetatable({ ["*"] = { } }, config_mt);
 
 -- When host not found, use global
@@ -54,11 +54,11 @@
 	end
 end
 
-local function set(config, host, key, value)
+local function set(config_table, host, key, value)
 	if host and key then
-		local hostconfig = rawget(config, host);
+		local hostconfig = rawget(config_table, host);
 		if not hostconfig then
-			hostconfig = rawset(config, host, setmetatable({}, host_mt))[host];
+			hostconfig = rawset(config_table, host, setmetatable({}, host_mt))[host];
 		end
 		hostconfig[key] = value;
 		return true;
@@ -73,20 +73,20 @@
 	return set(config, host, key, value);
 end
 
-function load(filename, format)
-	format = format or filename:match("%w+$");
+function load(filename, config_format)
+	config_format = config_format or filename:match("%w+$");
 
-	if parsers[format] and parsers[format].load then
+	if parsers[config_format] and parsers[config_format].load then
 		local f, err = io.open(filename);
 		if f then
 			local new_config = setmetatable({ ["*"] = { } }, config_mt);
-			local ok, err = parsers[format].load(f:read("*a"), filename, new_config);
+			local ok, err = parsers[config_format].load(f:read("*a"), filename, new_config);
 			f:close();
 			if ok then
 				config = new_config;
 				fire_event("config-reloaded", {
 					filename = filename,
-					format = format,
+					format = config_format,
 					config = config
 				});
 			end
@@ -95,65 +95,61 @@
 		return f, "file", err;
 	end
 
-	if not format then
+	if not config_format then
 		return nil, "file", "no parser specified";
 	else
-		return nil, "file", "no parser for "..(format);
+		return nil, "file", "no parser for "..(config_format);
 	end
 end
 
-function save(filename, format)
-end
-
-function addparser(format, parser)
-	if format and parser then
-		parsers[format] = parser;
+function addparser(config_format, parser)
+	if config_format and parser then
+		parsers[config_format] = parser;
 	end
 end
 
 -- _M needed to avoid name clash with local 'parsers'
 function _M.parsers()
 	local p = {};
-	for format in pairs(parsers) do
-		table.insert(p, format);
+	for config_format in pairs(parsers) do
+		table.insert(p, config_format);
 	end
 	return p;
 end
 
 -- Built-in Lua parser
 do
-	local pcall, setmetatable = _G.pcall, _G.setmetatable;
-	local rawget = _G.rawget;
+	local pcall = _G.pcall;
 	parsers.lua = {};
-	function parsers.lua.load(data, config_file, config)
+	function parsers.lua.load(data, config_file, config_table)
 		local env;
 		-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
 		env = setmetatable({
 			Host = true, host = true, VirtualHost = true,
 			Component = true, component = true,
 			Include = true, include = true, RunScript = true }, {
-				__index = function (t, k)
+				__index = function (_, k)
 					return rawget(_G, k);
 				end,
-				__newindex = function (t, k, v)
-					set(config, env.__currenthost or "*", k, v);
+				__newindex = function (_, k, v)
+					set(config_table, env.__currenthost or "*", k, v);
 				end
 		});
 
 		rawset(env, "__currenthost", "*") -- Default is global
 		function env.VirtualHost(name)
 			name = nameprep(name);
-			if rawget(config, name) and rawget(config[name], "component_module") then
+			if rawget(config_table, name) and rawget(config_table[name], "component_module") then
 				error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s",
-					name, config[name].component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
+					name, config_table[name].component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
 			end
 			rawset(env, "__currenthost", name);
 			-- Needs at least one setting to logically exist :)
-			set(config, name or "*", "defined", true);
+			set(config_table, name or "*", "defined", true);
 			return function (config_options)
 				rawset(env, "__currenthost", "*"); -- Return to global scope
 				for option_name, option_value in pairs(config_options) do
-					set(config, name or "*", option_name, option_value);
+					set(config_table, name or "*", option_name, option_value);
 				end
 			end;
 		end
@@ -161,24 +157,24 @@
 
 		function env.Component(name)
 			name = nameprep(name);
-			if rawget(config, name) and rawget(config[name], "defined") and not rawget(config[name], "component_module") then
+			if rawget(config_table, name) and rawget(config_table[name], "defined") and not rawget(config_table[name], "component_module") then
 				error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s",
 					name, name, name), 0);
 			end
-			set(config, name, "component_module", "component");
+			set(config_table, name, "component_module", "component");
 			-- Don't load the global modules by default
-			set(config, name, "load_global_modules", false);
+			set(config_table, name, "load_global_modules", false);
 			rawset(env, "__currenthost", name);
 			local function handle_config_options(config_options)
 				rawset(env, "__currenthost", "*"); -- Return to global scope
 				for option_name, option_value in pairs(config_options) do
-					set(config, name or "*", option_name, option_value);
+					set(config_table, name or "*", option_name, option_value);
 				end
 			end
 
 			return function (module)
 					if type(module) == "string" then
-						set(config, name, "component_module", module);
+						set(config_table, name, "component_module", module);
 						return handle_config_options;
 					end
 					return handle_config_options(module);
@@ -187,6 +183,7 @@
 		env.component = env.Component;
 
 		function env.Include(file)
+			-- Check whether this is a wildcard Include
 			if file:match("[*?]") then
 				local lfs = deps.softreq "lfs";
 				if not lfs then
@@ -206,16 +203,17 @@
 						env.Include(path..path_sep..f);
 					end
 				end
-			else
-				local file = resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file);
-				local f, err = io.open(file);
-				if f then
-					local ret, err = parsers.lua.load(f:read("*a"), file, config);
-					if not ret then error(err:gsub("%[string.-%]", file), 0); end
-				end
-				if not f then error("Error loading included "..file..": "..err, 0); end
-				return f, err;
+				return;
 			end
+			-- Not a wildcard, so resolve (potentially) relative path and run through config parser
+			file = resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file);
+			local f, err = io.open(file);
+			if f then
+				local ret, err = parsers.lua.load(f:read("*a"), file, config_table);
+				if not ret then error(err:gsub("%[string.-%]", file), 0); end
+			end
+			if not f then error("Error loading included "..file..": "..err, 0); end
+			return f, err;
 		end
 		env.include = env.Include;
 
--- a/core/hostmanager.lua	Fri May 15 15:33:31 2015 +0200
+++ b/core/hostmanager.lua	Tue May 19 16:33:47 2015 +0200
@@ -26,9 +26,23 @@
 
 local pairs, select, rawget = pairs, select, rawget;
 local tostring, type = tostring, type;
+local setmetatable = setmetatable;
 
 module "hostmanager"
 
+local host_mt = { }
+function host_mt:__tostring()
+	if self.type == "component" then
+		local typ = configmanager.get(self.host, "component_module");
+		if typ == "component" then
+			return ("Component %q"):format(self.host);
+		end
+		return ("Component %q %q"):format(self.host, typ);
+	elseif self.type == "local" then
+		return ("VirtualHost %q"):format(self.host);
+	end
+end
+
 local hosts_loaded_once;
 
 local function load_enabled_hosts(config)
@@ -69,6 +83,7 @@
 		send = host_send;
 		modules = {};
 	};
+	setmetatable(host_session, host_mt);
 	if not host_config.component_module then -- host
 		host_session.type = "local";
 		host_session.sessions = {};
--- a/core/loggingmanager.lua	Fri May 15 15:33:31 2015 +0200
+++ b/core/loggingmanager.lua	Tue May 19 16:33:47 2015 +0200
@@ -177,8 +177,8 @@
 -- Column width for "source" (used by stdout and console)
 local sourcewidth = 20;
 
-function log_sink_types.stdout(config)
-	local timestamps = config.timestamps;
+function log_sink_types.stdout(sink_config)
+	local timestamps = sink_config.timestamps;
 
 	if timestamps == true then
 		timestamps = default_timestamp; -- Default format
@@ -207,13 +207,13 @@
 		logstyles["warn"] = getstyle("bold", "yellow");
 		logstyles["error"] = getstyle("bold", "red");
 	end
-	function log_sink_types.console(config)
+	function log_sink_types.console(sink_config)
 		-- Really if we don't want pretty colours then just use plain stdout
 		if not do_pretty_printing then
-			return log_sink_types.stdout(config);
+			return log_sink_types.stdout(sink_config);
 		end
 
-		local timestamps = config.timestamps;
+		local timestamps = sink_config.timestamps;
 
 		if timestamps == true then
 			timestamps = default_timestamp; -- Default format
@@ -240,15 +240,15 @@
 end
 
 local empty_function = function () end;
-function log_sink_types.file(config)
-	local log = config.filename;
+function log_sink_types.file(sink_config)
+	local log = sink_config.filename;
 	local logfile = io_open(log, "a+");
 	if not logfile then
 		return empty_function;
 	end
 	local write, flush = logfile.write, logfile.flush;
 
-	local timestamps = config.timestamps;
+	local timestamps = sink_config.timestamps;
 
 	if timestamps == nil or timestamps == true then
 		timestamps = default_timestamp; -- Default format
--- a/plugins/mod_auth_internal_hashed.lua	Fri May 15 15:33:31 2015 +0200
+++ b/plugins/mod_auth_internal_hashed.lua	Tue May 19 16:33:47 2015 +0200
@@ -13,31 +13,14 @@
 local usermanager = require "core.usermanager";
 local generate_uuid = require "util.uuid".generate;
 local new_sasl = require "util.sasl".new;
+local hex = require"util.hex";
+local to_hex, from_hex = hex.to, hex.from;
 
 local log = module._log;
 local host = module.host;
 
 local accounts = module:open_store("accounts");
 
-local to_hex;
-do
-	local function replace_byte_with_hex(byte)
-		return ("%02x"):format(byte:byte());
-	end
-	function to_hex(binary_string)
-		return binary_string:gsub(".", replace_byte_with_hex);
-	end
-end
-
-local from_hex;
-do
-	local function replace_hex_with_byte(hex)
-		return string.char(tonumber(hex, 16));
-	end
-	function from_hex(hex_string)
-		return hex_string:gsub("..", replace_hex_with_byte);
-	end
-end
 
 
 -- Default; can be set per-user
--- a/plugins/mod_tls.lua	Fri May 15 15:33:31 2015 +0200
+++ b/plugins/mod_tls.lua	Tue May 19 16:33:47 2015 +0200
@@ -21,6 +21,7 @@
 
 local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
 local starttls_attr = { xmlns = xmlns_starttls };
+local starttls_initiate= st.stanza("starttls", starttls_attr);
 local starttls_proceed = st.stanza("proceed", starttls_attr);
 local starttls_failure = st.stanza("failure", starttls_attr);
 local c2s_feature = st.stanza("starttls", starttls_attr);
@@ -60,7 +61,7 @@
 end
 
 local function can_do_tls(session)
-	if not session.conn.starttls then
+	if session.ssl_ctx == false or not session.conn.starttls then
 		return false;
 	elseif session.ssl_ctx then
 		return true;
@@ -116,7 +117,7 @@
 	module:log("debug", "Received features element");
 	if can_do_tls(session) and stanza:get_child("starttls", xmlns_starttls) then
 		module:log("debug", "%s is offering TLS, taking up the offer...", session.to_host);
-		session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>");
+		session.sends2s(starttls_initiate);
 		return true;
 	end
 end, 500);
--- a/prosodyctl	Fri May 15 15:33:31 2015 +0200
+++ b/prosodyctl	Tue May 19 16:33:47 2015 +0200
@@ -578,6 +578,8 @@
 	print("");
 	print("# Lua module versions");
 	local module_versions, longest_name = {}, 8;
+	local luaevent =dependencies.softreq"luaevent";
+	local ssl = dependencies.softreq"ssl";
 	for name, module in pairs(package.loaded) do
 		if type(module) == "table" and rawget(module, "_VERSION")
 		and name ~= "_G" and not name:match("%.") then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/interpolation.lua	Tue May 19 16:33:47 2015 +0200
@@ -0,0 +1,77 @@
+-- Simple template language
+--
+-- The new() function takes a pattern and an escape function and returns 
+-- a render() function.  Both are required.
+--
+-- The function render() takes a string template and a table of values.
+-- Sequences like {name} in the template string are substituted
+-- with values from the table, optionally depending on a modifier
+-- symbol.
+--
+-- Variants are:
+-- {name} is substituted for values["name"] and is escaped using the 
+-- second argument to new_render().  To disable the escaping, use {name!}.
+-- {name.item} can be used to access table items.
+-- To renter lists of items: {name# item number {idx} is {item} }
+-- Or key-value pairs: {name% t[ {idx} ] = {item} }
+-- To show a defaults for missing values {name? sub-template } can be used, 
+-- which renders a sub-template if values["name"] is false-ish.
+-- {name& sub-template } does the opposite, the sub-template is rendered 
+-- if the selected value is anything but false or nil.
+
+local type, tostring = type, tostring;
+local pairs, ipairs = pairs, ipairs;
+local s_sub, s_gsub, s_match = string.sub, string.gsub, string.match;
+local t_concat = table.concat;
+
+local function new_render(pat, escape)
+	-- assert(type(pat) == "string", "bad argument #1 to 'new_render' (string expected)");
+	-- assert(type(escape) == "function", "bad argument #2 to 'new_render' (function expected)");
+	local function render(template, values)
+		-- assert(type(template) == "string", "bad argument #1 to 'render' (string expected)");
+		-- assert(type(values) == "table", "bad argument #2 to 'render' (table expected)");
+		return (s_gsub(template, pat, function (block)
+			block = s_sub(block, 2, -2);
+			local name, opt, e = s_match(block, "^([%a_][%w_.]*)(%p?)()");
+			if not name then return end
+			local value = values[name];
+			if not value and name:find(".", 2, true) then
+				value = values;
+				for word in name:gmatch"[^.]+" do
+					value = value[word];
+					if not value then break; end
+				end
+			end
+			if opt == '#' or opt == '%' then
+				if type(value) ~= "table" then return ""; end
+				local iter = opt == '#' and ipairs or pairs;
+				local out, i, subtpl = {}, 1, s_sub(block, e);
+				local subvalues = setmetatable({}, { __index = values });
+				for idx, item in iter(value) do
+					subvalues.idx = idx;
+					subvalues.item = item;
+					out[i], i = render(subtpl, subvalues), i+1;
+				end
+				return t_concat(out);
+			elseif opt == '&' then
+				if not value then return ""; end
+				return render(s_sub(block, e), values);
+			elseif opt == '?' and not value then
+				return render(s_sub(block, e), values);
+			elseif value ~= nil then
+				if type(value) ~= "string" then
+					value = tostring(value);
+				end
+				if opt ~= '!' then
+					return escape(value);
+				end
+				return value;
+			end
+		end));
+	end
+	return render;
+end
+
+return {
+	new = new_render;
+};
--- a/util/x509.lua	Fri May 15 15:33:31 2015 +0200
+++ b/util/x509.lua	Tue May 19 16:33:47 2015 +0200
@@ -148,6 +148,9 @@
 end
 
 function verify_identity(host, service, cert)
+	if cert.setencode then
+		cert:setencode("utf8");
+	end
 	local ext = cert:extensions()
 	if ext[oid_subjectaltname] then
 		local sans = ext[oid_subjectaltname];