mod_presence: Re-probe for contacts presence after outgoing 'subscribed' (fixes ...
[prosody.git] / prosodyctl
index caa5d0cf4a24678caab1b5b449f969732fc538b3..4c3ae981521e6ee2b109589fc729ba09af18cf45 100755 (executable)
@@ -51,6 +51,7 @@ local prosody = {
        lock_globals = function () end;
        unlock_globals = function () end;
        installed = CFG_SOURCEDIR ~= nil;
+       core_post_stanza = function () end; -- TODO: mod_router!
 };
 _G.prosody = prosody;
 
@@ -61,16 +62,17 @@ end
 
 config = require "core.configmanager"
 
+local ENV_CONFIG;
 do
        local filenames = {};
        
        local filename;
        if arg[1] == "--config" and arg[2] then
                table.insert(filenames, arg[2]);
-               table.remove(arg, 1); table.remove(arg, 1);
                if CFG_CONFIGDIR then
                        table.insert(filenames, CFG_CONFIGDIR.."/"..arg[2]);
                end
+               table.remove(arg, 1); table.remove(arg, 1);
        else
                for _, format in ipairs(config.parsers()) do
                        table.insert(filenames, (CFG_CONFIGDIR or ".").."/prosody.cfg."..format);
@@ -81,6 +83,7 @@ do
                local file = io.open(filename);
                if file then
                        file:close();
+                       ENV_CONFIG = filename;
                        CFG_CONFIGDIR = filename:match("^(.*)[\\/][^\\/]*$");
                        break;
                end
@@ -107,11 +110,11 @@ do
                os.exit(1);
        end
 end
-local original_logging_config = config.get("*", "core", "log");
-config.set("*", "core", "log", { { levels = { min="info" }, to = "console" } });
+local original_logging_config = config.get("*", "log");
+config.set("*", "log", { { levels = { min="info" }, to = "console" } });
 
-local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
-local custom_plugin_paths = config.get("*", "core", "plugin_paths");
+local data_path = config.get("*", "data_path") or CFG_DATADIR or "data";
+local custom_plugin_paths = config.get("*", "plugin_paths");
 if custom_plugin_paths then
        local path_sep = package.config:sub(3,3);
        -- path1;path2;path3;defaultpath...
@@ -132,7 +135,7 @@ dependencies.log_warnings();
 -- Switch away from root and into the prosody user --
 local switched_user, current_uid;
 
-local want_pposix_version = "0.3.5";
+local want_pposix_version = "0.3.6";
 local ok, pposix = pcall(require, "util.pposix");
 
 if ok and pposix then
@@ -140,8 +143,8 @@ if ok and pposix then
        current_uid = pposix.getuid();
        if current_uid == 0 then
                -- We haz root!
-               local desired_user = config.get("*", "core", "prosody_user") or "prosody";
-               local desired_group = config.get("*", "core", "prosody_group") or desired_user;
+               local desired_user = config.get("*", "prosody_user") or "prosody";
+               local desired_group = config.get("*", "prosody_group") or desired_user;
                local ok, err = pposix.setgid(desired_group);
                if ok then
                        ok, err = pposix.initgroups(desired_user);
@@ -160,11 +163,14 @@ if ok and pposix then
        end
        
        -- Set our umask to protect data files
-       pposix.umask(config.get("*", "core", "umask") or "027");
+       pposix.umask(config.get("*", "umask") or "027");
+       pposix.setenv("HOME", data_path);
+       pposix.setenv("PROSODY_CONFIG", ENV_CONFIG);
 else
        print("Error: Unable to load pposix module. Check that Prosody is installed correctly.")
        print("For more help send the below error to us through http://prosody.im/discuss");
        print(tostring(pposix))
+       os.exit(1);
 end
 
 local function test_writeable(filename)
@@ -214,6 +220,7 @@ local error_messages = setmetatable({
                ["no-such-host"] = "The given hostname does not exist in the config";
                ["unable-to-save-data"] = "Unable to store, perhaps you don't have permission?";
                ["no-pidfile"] = "There is no 'pidfile' option in the configuration file, see http://prosody.im/doc/prosodyctl#pidfile for help";
+               ["invalid-pidfile"] = "The 'pidfile' option in the configuration file is not a string, see http://prosody.im/doc/prosodyctl#pidfile for help";
                ["no-posix"] = "The mod_posix module is not enabled in the Prosody config file, see http://prosody.im/doc/prosodyctl for more info";
                ["no-such-method"] = "This module has no commands";
                ["not-running"] = "Prosody is not running";
@@ -262,7 +269,9 @@ local show_yesno = prosodyctl.show_yesno;
 local show_prompt = prosodyctl.show_prompt;
 local read_password = prosodyctl.read_password;
 
-local prosodyctl_timeout = (config.get("*", "core", "prosodyctl_timeout") or 5) * 2;
+local jid_split = require "util.jid".prepped_split;
+
+local prosodyctl_timeout = (config.get("*", "prosodyctl_timeout") or 5) * 2;
 -----------------------
 local commands = {};
 local command = arg[1];
@@ -272,7 +281,7 @@ function commands.adduser(arg)
                show_usage([[adduser JID]], [[Create the specified user account in Prosody]]);
                return 1;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to create]]
                show_usage [[adduser user@host]]
@@ -311,7 +320,7 @@ function commands.passwd(arg)
                show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]);
                return 1;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1])
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
                show_usage [[passwd user@host]]
@@ -350,7 +359,7 @@ function commands.deluser(arg)
                show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]);
                return 1;
        end
-       local user, host = arg[1]:match("([^@]+)@(.+)");
+       local user, host = jid_split(arg[1]);
        if not user and host then
                show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
                show_usage [[passwd user@host]]
@@ -364,7 +373,6 @@ function commands.deluser(arg)
        
        if not hosts[host] then
                show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host)
-               show_warning("The user will not be able to log in until this is changed.");
                hosts[host] = make_host(host);
        end
 
@@ -405,7 +413,7 @@ function commands.start(arg)
        
        local ok, ret = prosodyctl.start();
        if ok then
-               if config.get("*", "core", "daemonize") ~= false then
+               if config.get("*", "daemonize") ~= false then
                        local i=1;
                        while true do
                                local ok, running = prosodyctl.isrunning();
@@ -540,7 +548,7 @@ function commands.about(arg)
                print("  "..path);
        end
        print("");
-       local luarocks_status = (pcall(require, "luarocks.loader") and "Installed ("..(luarocks.cfg.program_version or "2.x+")..")")
+       local luarocks_status = (pcall(require, "luarocks.loader") and "Installed ("..(package.loaded["luarocks.cfg"].program_version or "2.x+")..")")
                or (pcall(require, "luarocks.require") and "Installed (1.x)")
                or "Not installed";
        print("LuaRocks:        ", luarocks_status);
@@ -637,8 +645,8 @@ function commands.unregister(arg)
        return 1;
 end
 
-local openssl = require "util.openssl";
-local lfs = require "lfs";
+local openssl;
+local lfs;
 
 local cert_commands = {};
 
@@ -648,27 +656,42 @@ end
 
 function cert_commands.config(arg)
        if #arg >= 1 and arg[1] ~= "--help" then
-               local conf_filename = (CFG_DATADIR or ".") .. "/" .. arg[1] .. ".cnf";
+               local conf_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".cnf";
                if ask_overwrite(conf_filename) then
                        return nil, conf_filename;
                end
                local conf = openssl.config.new();
                conf:from_prosody(hosts, config, arg);
-               for k, v in pairs(conf.distinguished_name) do
-                       local nv;
-                       if k == "commonName" then 
-                               v = arg[1]
-                       elseif k == "emailAddress" then
-                               v = "xmpp@" .. arg[1];
-                       end
-                       nv = show_prompt(("%s (%s):"):format(k, nv or v));
-                       nv = (not nv or nv == "") and v or nv;
-                       if nv:find"[\192-\252][\128-\191]+" then
-                               conf.req.string_mask = "utf8only"
+               show_message("Please provide details to include in the certificate config file.");
+               show_message("Leave the field empty to use the default value or '.' to exclude the field.")
+               for i, k in ipairs(openssl._DN_order) do
+                       local v = conf.distinguished_name[k];
+                       if v then
+                               local nv;
+                               if k == "commonName" then
+                                       v = arg[1]
+                               elseif k == "emailAddress" then
+                                       v = "xmpp@" .. arg[1];
+                               elseif k == "countryName" then
+                                       local tld = arg[1]:match"%.([a-z]+)$";
+                                       if tld and #tld == 2 and tld ~= "uk" then
+                                               v = tld:upper();
+                                       end
+                               end
+                               nv = show_prompt(("%s (%s):"):format(k, nv or v));
+                               nv = (not nv or nv == "") and v or nv;
+                               if nv:find"[\192-\252][\128-\191]+" then
+                                       conf.req.string_mask = "utf8only"
+                               end
+                               conf.distinguished_name[k] = nv ~= "." and nv or nil;
                        end
-                       conf.distinguished_name[k] = nv ~= "." and nv or nil;
                end
-               local conf_file = io.open(conf_filename, "w");
+               local conf_file, err = io.open(conf_filename, "w");
+               if not conf_file then
+                       show_warning("Could not open OpenSSL config file for writing");
+                       show_warning(err);
+                       os.exit(1);
+               end
                conf_file:write(conf:serialize());
                conf_file:close();
                print("");
@@ -681,15 +704,17 @@ end
 
 function cert_commands.key(arg)
        if #arg >= 1 and arg[1] ~= "--help" then
-               local key_filename = (CFG_DATADIR or ".") .. "/" .. arg[1] .. ".key";
+               local key_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".key";
                if ask_overwrite(key_filename) then
                        return nil, key_filename;
                end
-               os.remove(key_filename); -- We chmod this file to not have write permissions
+               os.remove(key_filename); -- This file, if it exists is unlikely to have write permissions
                local key_size = tonumber(arg[2] or show_prompt("Choose key size (2048):") or 2048);
+               local old_umask = pposix.umask("0377");
                if openssl.genrsa{out=key_filename, key_size} then
                        os.execute(("chmod 400 '%s'"):format(key_filename));
                        show_message("Key written to ".. key_filename);
+                       pposix.umask(old_umask);
                        return nil, key_filename;
                end
                show_message("There was a problem, see OpenSSL output");
@@ -701,7 +726,7 @@ end
 
 function cert_commands.request(arg)
        if #arg >= 1 and arg[1] ~= "--help" then
-               local req_filename = (CFG_DATADIR or ".") .. "/" .. arg[1] .. ".req";
+               local req_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".req";
                if ask_overwrite(req_filename) then
                        return nil, req_filename;
                end
@@ -719,9 +744,9 @@ end
 
 function cert_commands.generate(arg)
        if #arg >= 1 and arg[1] ~= "--help" then
-               local cert_filename = (CFG_DATADIR or ".") .. "/" .. arg[1] .. ".cert";
+               local cert_filename = (CFG_DATADIR or "./certs") .. "/" .. arg[1] .. ".crt";
                if ask_overwrite(cert_filename) then
-                       return nil, conf_filename;
+                       return nil, cert_filename;
                end
                local _, key_filename = cert_commands.key({arg[1]});
                local _, conf_filename = cert_commands.config(arg);
@@ -740,6 +765,8 @@ end
 
 function commands.cert(arg)
        if #arg >= 1 and arg[1] ~= "--help" then
+               openssl = require "util.openssl";
+               lfs = require "lfs";
                local subcmd = table.remove(arg, 1);
                if type(cert_commands[subcmd]) == "function" then
                        if not arg[1] then