|
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)) })); |