prosodyctl
changeset 1087 5e9475bec571
child 1089 a817cbaa0f46
equal deleted inserted replaced
1086:0b895e1ac713 1087:5e9475bec571
       
     1 #!/usr/bin/env lua
       
     2 -- Prosody IM v0.4
       
     3 -- Copyright (C) 2008-2009 Matthew Wild
       
     4 -- Copyright (C) 2008-2009 Waqas Hussain
       
     5 -- 
       
     6 -- This project is MIT/X11 licensed. Please see the
       
     7 -- COPYING file in the source package for more information.
       
     8 --
       
     9 
       
    10 -- prosodyctl - command-line controller for Prosody XMPP server
       
    11 
       
    12 -- Will be modified by configure script if run --
       
    13 
       
    14 CFG_SOURCEDIR=nil;
       
    15 CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR");
       
    16 CFG_PLUGINDIR=nil;
       
    17 CFG_DATADIR=os.getenv("PROSODY_DATADIR");
       
    18 
       
    19 -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- --
       
    20 
       
    21 if CFG_SOURCEDIR then
       
    22 	package.path = CFG_SOURCEDIR.."/?.lua;"..package.path
       
    23 	package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath
       
    24 end
       
    25 
       
    26 if CFG_DATADIR then
       
    27 	if os.getenv("HOME") then
       
    28 		CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME"));
       
    29 	end
       
    30 end
       
    31 
       
    32 -- Required to be able to find packages installed with luarocks
       
    33 pcall(require, "luarocks.require")
       
    34 
       
    35 
       
    36 config = require "core.configmanager"
       
    37 
       
    38 do
       
    39 	-- TODO: Check for other formats when we add support for them
       
    40 	-- Use lfs? Make a new conf/ dir?
       
    41 	local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
       
    42 	if not ok then
       
    43 		print("\n");
       
    44 		print("**************************");
       
    45 		if level == "parser" then
       
    46 			print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
       
    47 			local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)");
       
    48 			print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err)));
       
    49 			print("");
       
    50 		elseif level == "file" then
       
    51 			print("Prosody was unable to find the configuration file.");
       
    52 			print("We looked for: "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
       
    53 			print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist");
       
    54 			print("Copy or rename it to prosody.cfg.lua and edit as necessary.");
       
    55 		end
       
    56 		print("More help on configuring Prosody can be found at http://prosody.im/doc/configure");
       
    57 		print("Good luck!");
       
    58 		print("**************************");
       
    59 		print("");
       
    60 		os.exit(1);
       
    61 	end
       
    62 end
       
    63 
       
    64 local error_messages = setmetatable({ 
       
    65 		["invalid-username"] = "The given username is invalid in a Jabber ID";
       
    66 		["invalid-hostname"] = "The given hostname is invalid";
       
    67 		["no-password"] = "No password was supplied";
       
    68 		["no-such-user"] = "The given user does not exist on the server";
       
    69 		}, { __index = function (t,k) return "Error: "..(tostring(k):gsub("%-", " "):gsub("^.", string.upper)); end });
       
    70 
       
    71 hosts = {};
       
    72 
       
    73 require "core.hostmanager"
       
    74 require "core.eventmanager".fire_event("server-starting");
       
    75 
       
    76 require "util.prosodyctl"
       
    77 -----------------------
       
    78 
       
    79 function show_message(msg, ...)
       
    80 	print(msg:format(...));
       
    81 end
       
    82 
       
    83 function show_warning(msg, ...)
       
    84 	print(msg:format(...));
       
    85 end
       
    86 
       
    87 function show_usage(usage, desc)
       
    88 	print("Usage: "..arg[0].." "..usage);
       
    89 	if desc then
       
    90 		print(" "..desc);
       
    91 	end
       
    92 end
       
    93 
       
    94 local function getchar(n)
       
    95 	os.execute("stty raw -echo");
       
    96 	local char = io.read(n or 1);
       
    97 	os.execute("stty sane");
       
    98 	return char;
       
    99 end
       
   100 	
       
   101 local function getpass()
       
   102 	os.execute("stty -echo");
       
   103 	local pass = io.read("*l");
       
   104 	os.execute("stty sane");
       
   105 	io.write("\n");
       
   106 	return pass;
       
   107 end
       
   108 
       
   109 function show_yesno(prompt)
       
   110 	io.write(prompt, " ");
       
   111 	local choice = getchar():lower();
       
   112 	io.write("\n");
       
   113 	if not choice:match("%a") then
       
   114 		choice = prompt:match("%[.-(%U).-%]$");
       
   115 		if not choice then return nil; end
       
   116 	end
       
   117 	return (choice == "y");
       
   118 end
       
   119 
       
   120 local function read_password()
       
   121 	local password;
       
   122 	while true do
       
   123 		io.write("Enter new password: ");
       
   124 		password = getpass();
       
   125 		io.write("Retype new password: ");
       
   126 		if getpass() ~= password then
       
   127 			if not show_yesno [=[Passwords did not match, try again? [Y/n]]=] then
       
   128 				return;
       
   129 			end
       
   130 		else
       
   131 			break;
       
   132 		end
       
   133 	end
       
   134 	return password;
       
   135 end
       
   136 -----------------------
       
   137 local commands = {};
       
   138 local command = arg[1];
       
   139 
       
   140 function commands.adduser(arg)
       
   141 	if not arg[1] or arg[1] == "--help" then
       
   142 		show_usage([[adduser JID]], [[Create the specified user account in Prosody]]);
       
   143 		return 1;
       
   144 	end
       
   145 	local user, host = arg[1]:match("([^@]+)@(.+)");
       
   146 	if not user and host then
       
   147 		show_message [[Failed to understand JID, please supply the JID you want to create]]
       
   148 		show_usage [[adduser user@host]]
       
   149 		return 1;
       
   150 	end
       
   151 	
       
   152 	if not host then
       
   153 		show_message [[Please specify a JID, including a host. e.g. alice@example.com]];
       
   154 		return 1;
       
   155 	end
       
   156 	
       
   157 	if prosodyctl.user_exists{ user = user, host = host } then
       
   158 		show_message [[That user already exists]];
       
   159 		return 1;
       
   160 	end
       
   161 	
       
   162 	if not hosts[host] then
       
   163 		show_warning("The host '%s' is not listed in the configuration file (or is not enabled).", host)
       
   164 		show_warning("The user will not be able to log in until this is changed.");
       
   165 	end
       
   166 	
       
   167 	local password = read_password();
       
   168 	if not password then return 1; end
       
   169 	
       
   170 	local ok, msg = prosodyctl.adduser { user = user, host = host, password = password };
       
   171 	
       
   172 	if ok then return 0; end
       
   173 	
       
   174 	show_message(error_messages[msg])
       
   175 	return 1;
       
   176 end
       
   177 
       
   178 function commands.passwd(arg)
       
   179 	if not arg[1] or arg[1] == "--help" then
       
   180 		show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]);
       
   181 		return 1;
       
   182 	end
       
   183 	local user, host = arg[1]:match("([^@]+)@(.+)");
       
   184 	if not user and host then
       
   185 		show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
       
   186 		show_usage [[passwd user@host]]
       
   187 		return 1;
       
   188 	end
       
   189 	
       
   190 	if not host then
       
   191 		show_message [[Please specify a JID, including a host. e.g. alice@example.com]];
       
   192 		return 1;
       
   193 	end
       
   194 	
       
   195 	if not prosodyctl.user_exists { user = user, host = host } then
       
   196 		show_message [[That user does not exist, use prosodyctl adduser to create a new user]]
       
   197 		return 1;
       
   198 	end
       
   199 	
       
   200 	local password = read_password();
       
   201 	if not password then return 1; end
       
   202 	
       
   203 	local ok, msg = prosodyctl.passwd { user = user, host = host, password = password };
       
   204 	
       
   205 	if ok then return 0; end
       
   206 	
       
   207 	show_message(error_messages[msg])
       
   208 	return 1;
       
   209 end
       
   210 
       
   211 function commands.deluser(arg)
       
   212 	if not arg[1] or arg[1] == "--help" then
       
   213 		show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]);
       
   214 		return 1;
       
   215 	end
       
   216 	local user, host = arg[1]:match("([^@]+)@(.+)");
       
   217 	if not user and host then
       
   218 		show_message [[Failed to understand JID, please supply the JID you want to set the password for]]
       
   219 		show_usage [[passwd user@host]]
       
   220 		return 1;
       
   221 	end
       
   222 	
       
   223 	if not host then
       
   224 		show_message [[Please specify a JID, including a host. e.g. alice@example.com]];
       
   225 		return 1;
       
   226 	end
       
   227 	
       
   228 	if not prosodyctl.user_exists { user = user, host = host } then
       
   229 		show_message [[That user does not exist on this server]]
       
   230 		return 1;
       
   231 	end
       
   232 	
       
   233 	local ok, msg = prosodyctl.passwd { user = user, host = host };
       
   234 	
       
   235 	if ok then return 0; end
       
   236 	
       
   237 	show_message(error_messages[msg])
       
   238 	return 1;
       
   239 end
       
   240 
       
   241 function commands.start()
       
   242 	local ok, ret = prosodyctl.isrunning();
       
   243 	if not ok then
       
   244 		show_message(error_messages[ret]);
       
   245 		return 1;
       
   246 	end
       
   247 	
       
   248 	if ret then
       
   249 		local ok, ret = prosodyctl.getpid();
       
   250 		if not ok then
       
   251 			show_message("Couldn't get running Prosody's PID");
       
   252 			show_message(error_messages[ret]);
       
   253 			return 1;
       
   254 		end
       
   255 		show_message("Prosody is already running with PID %s", ret or "(unknown)");
       
   256 		return 1;
       
   257 	end
       
   258 	
       
   259 	local ok, ret = prosodyctl.start();
       
   260 	if ok then return 0; end
       
   261 
       
   262 	show_message("Failed to start Prosody");
       
   263 	show_message(error_messages[ret])	
       
   264 	return 1;	
       
   265 end
       
   266 
       
   267 function commands.status()
       
   268 	local ok, ret = prosodyctl.isrunning();
       
   269 	if not ok then
       
   270 		show_message(error_messages[ret]);
       
   271 		return 1;
       
   272 	end
       
   273 	
       
   274 	if ret then
       
   275 		local ok, ret = prosodyctl.getpid();
       
   276 		if not ok then
       
   277 			show_message("Couldn't get running Prosody's PID");
       
   278 			show_message(error_messages[ret]);
       
   279 			return 1;
       
   280 		end
       
   281 		show_message("Prosody is running with PID %s", ret or "(unknown)");
       
   282 		return 0;
       
   283 	end
       
   284 	return 1;
       
   285 end
       
   286 
       
   287 function commands.stop()
       
   288 	if not prosodyctl.isrunning() then
       
   289 		show_message("Prosody is not running");
       
   290 		return 1;
       
   291 	end
       
   292 	
       
   293 	local ok, ret = prosodyctl.stop();
       
   294 	if ok then return 0; end
       
   295 
       
   296 	show_message(error_messages[ret])	
       
   297 	return 1;
       
   298 end
       
   299 
       
   300 -- ejabberdctl compatibility
       
   301 
       
   302 function commands.register(arg)
       
   303 	local user, host, password = unpack(arg);
       
   304 	if (not (user and host)) or arg[1] == "--help" then
       
   305 		if not user and user ~= "--help" then
       
   306 			show_message [[No username specified]]
       
   307 		elseif not host then
       
   308 			show_message [[Please specify which host you want to register the user on]];
       
   309 		end
       
   310 		show_usage("register USER HOST [PASSWORD]", "Register a user on the server, with the given password");
       
   311 		return 1;
       
   312 	end
       
   313 	if not password then
       
   314 		password = read_password();
       
   315 		if not password then
       
   316 			show_message [[Unable to register user with no password]];
       
   317 			return 1;
       
   318 		end
       
   319 	end
       
   320 	
       
   321 	local ok, msg = prosodyctl.adduser { user = user, host = host, password = password };
       
   322 	
       
   323 	if ok then return 0; end
       
   324 	
       
   325 	show_message(error_messages[msg])
       
   326 	return 1;
       
   327 end
       
   328 
       
   329 function commands.unregister(arg)
       
   330 	local user, host = unpack(arg);
       
   331 	if (not (user and host)) or arg[1] == "--help" then
       
   332 		if not user then
       
   333 			show_message [[No username specified]]
       
   334 		elseif not host then
       
   335 			show_message [[Please specify which host you want to unregister the user from]];
       
   336 		end
       
   337 		show_usage("register USER HOST [PASSWORD]", "Permanently remove a user account from the server");
       
   338 		return 1;
       
   339 	end
       
   340 
       
   341 	local ok, msg = prosodyctl.deluser { user = user, host = host };
       
   342 	
       
   343 	if ok then return 0; end
       
   344 	
       
   345 	show_message(error_messages[msg])
       
   346 	return 1;
       
   347 end
       
   348 
       
   349 
       
   350 ---------------------
       
   351 
       
   352 if not commands[command] then -- Show help for all commands
       
   353 	function show_usage(usage, desc)
       
   354 		print(" "..usage);
       
   355 		print("    "..desc);
       
   356 	end
       
   357 
       
   358 	print("prosodyctl - Manage a Prosody server");
       
   359 	print("");
       
   360 	print("Usage: "..arg[0].." COMMAND [OPTIONS]");
       
   361 	print("");
       
   362 	print("Where COMMAND may be one of:\n");
       
   363 
       
   364 	local commands_order = { "adduser", "passwd", "deluser" };
       
   365 
       
   366 	local done = {};
       
   367 
       
   368 	for _, command_name in ipairs(commands_order) do
       
   369 		local command = commands[command_name];
       
   370 		if command then
       
   371 			command{ "--help" };
       
   372 			print""
       
   373 			done[command_name] = true;
       
   374 		end
       
   375 	end
       
   376 
       
   377 	for command_name, command in pairs(commands) do
       
   378 		if not done[command_name] then
       
   379 			command{ "--help" };
       
   380 			print""
       
   381 			done[command_name] = true;
       
   382 		end
       
   383 	end
       
   384 	
       
   385 	
       
   386 	os.exit(0);
       
   387 end
       
   388 
       
   389 os.exit(commands[command]({ select(2, unpack(arg)) }));