is_user_exists/2,
remove_user/2,
remove_user/3,
- plain_password_required/1
+ plain_password_required/1,
+ ctl_process_get_registered/3
]).
-include("ejabberd.hrl").
+-include("ejabberd_ctl.hrl").
%%%----------------------------------------------------------------------
%%% API
remove_user(User, Server, Password) ->
(auth_module(Server)):remove_user(User, Server, Password).
+
+ctl_process_get_registered(_Val, Host, ["registered-users"]) ->
+ Users = ejabberd_auth:get_vh_registered_users(Host),
+ NewLine = io_lib:format("~n", []),
+ SUsers = lists:sort(Users),
+ FUsers = lists:map(fun({U, _S}) -> [U, NewLine] end, SUsers),
+ io:format("~s", [FUsers]),
+ {stop, ?STATUS_SUCCESS};
+ctl_process_get_registered(Val, _Host, _Args) ->
+ Val.
+
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
-author('alexey@sevcom.net').
-export([start/0,
+ init/0,
process/1,
register_commands/3,
- unregister_commands/3]).
+ register_commands/4,
+ unregister_commands/3,
+ unregister_commands/4]).
-include("ejabberd_ctl.hrl").
halt(?STATUS_USAGE)
end.
+init() ->
+ ets:new(ejabberd_ctl_cmds, [named_table, set, public]),
+ ets:new(ejabberd_ctl_host_cmds, [named_table, set, public]).
+
process(["status"]) ->
{InternalStatus, ProvidedStatus} = init:get_status(),
?STATUS_ERROR
end;
-process(["registered-users"]) ->
- case ejabberd_auth:dirty_get_registered_users() of
- Users when is_list(Users) ->
- NewLine = io_lib:format("~n", []),
- SUsers = lists:sort(Users),
- FUsers = lists:map(fun({U, S}) -> [U, $@, S, NewLine] end, SUsers),
- io:format("~s", [FUsers]),
- ?STATUS_SUCCESS;
- {error, Reason} ->
- io:format("Can't get list of registered users at node ~p: ~p~n",
- [node(), Reason]),
- ?STATUS_ERROR
- end;
-
process(["delete-expired-messages"]) ->
mod_offline:remove_expired_messages(),
?STATUS_SUCCESS;
+process(["vhost", H | Args]) ->
+ case jlib:nameprep(H) of
+ false ->
+ io:format("Bad hostname: ~p~n", [H]),
+ ?STATUS_ERROR;
+ Host ->
+ case ejabberd_hooks:run_fold(
+ ejabberd_ctl_process, Host, false, [Host, Args]) of
+ false ->
+ print_vhost_usage(Host),
+ ?STATUS_USAGE;
+ Status ->
+ Status
+ end
+ end;
+
process(Args) ->
- case ejabberd_hooks:run_fold(
- ejabberd_ctl_process,
- false,
- [Args]) of
+ case ejabberd_hooks:run_fold(ejabberd_ctl_process, false, [Args]) of
false ->
print_usage(),
?STATUS_USAGE;
print_usage() ->
- catch ets:new(ejabberd_ctl_cmds, [named_table, ordered_set, public]),
CmdDescs =
[{"status", "get ejabberd status"},
{"stop", "stop ejabberd"},
{"load file", "restore a database from a text file"},
{"import-file file", "import user data from jabberd 1.4 spool file"},
{"import-dir dir", "import user data from jabberd 1.4 spool directory"},
- {"registered-users", "list all registered users"},
- {"delete-expired-messages", "delete expired offline messages from database"}] ++
+ {"delete-expired-messages", "delete expired offline messages from database"},
+ {"vhost host ...", "execute host-specific commands"}] ++
ets:tab2list(ejabberd_ctl_cmds),
MaxCmdLen =
lists:max(lists:map(
FmtCmdDescs =
lists:map(
fun({Cmd, Desc}) ->
- [" ", Cmd, string:chars($\s, MaxCmdLen - length(Cmd) + 1),
+ [" ", Cmd, string:chars($\s, MaxCmdLen - length(Cmd) + 2),
Desc, NewLine]
end, CmdDescs),
io:format(
" ejabberdctl ejabberd@host restart~n"
).
+print_vhost_usage(Host) ->
+ CmdDescs =
+ ets:select(ejabberd_ctl_host_cmds,
+ [{{Host, '$1', '$2'}, [], [{{'$1', '$2'}}]}]),
+ MaxCmdLen =
+ if
+ CmdDescs == [] ->
+ 0;
+ true ->
+ lists:max(lists:map(
+ fun({Cmd, _Desc}) ->
+ length(Cmd)
+ end, CmdDescs))
+ end,
+ NewLine = io_lib:format("~n", []),
+ FmtCmdDescs =
+ lists:map(
+ fun({Cmd, Desc}) ->
+ [" ", Cmd, string:chars($\s, MaxCmdLen - length(Cmd) + 2),
+ Desc, NewLine]
+ end, CmdDescs),
+ io:format(
+ "Usage: ejabberdctl node vhost host command~n"
+ "~n"
+ "Available commands:~n"
+ ++ FmtCmdDescs ++
+ "~n"
+ ).
+
register_commands(CmdDescs, Module, Function) ->
- catch ets:new(ejabberd_ctl_cmds, [named_table, ordered_set, public]),
ets:insert(ejabberd_ctl_cmds, CmdDescs),
ejabberd_hooks:add(ejabberd_ctl_process,
Module, Function, 50),
ok.
+register_commands(Host, CmdDescs, Module, Function) ->
+ ets:insert(ejabberd_ctl_host_cmds,
+ [{Host, Cmd, Desc} || {Cmd, Desc} <- CmdDescs]),
+ ejabberd_hooks:add(ejabberd_ctl_process, Host,
+ Module, Function, 50),
+ ok.
+
unregister_commands(CmdDescs, Module, Function) ->
- catch ets:new(ejabberd_ctl_cmds, [named_table, ordered_set, public]),
lists:foreach(fun(CmdDesc) ->
ets:delete_object(ejabberd_ctl_cmds, CmdDesc)
end, CmdDescs),
Module, Function, 50),
ok.
+unregister_commands(Host, CmdDescs, Module, Function) ->
+ lists:foreach(fun({Cmd, Desc}) ->
+ ets:delete_object(ejabberd_ctl_host_cmds,
+ {Host, Cmd, Desc})
+ end, CmdDescs),
+ ejabberd_hooks:delete(ejabberd_ctl_process,
+ Module, Function, 50),
+ ok.
+
dump_to_textfile(File) ->
dump_to_textfile(mnesia:system_info(is_running), file:open(File, write)).
dump_to_textfile(yes, {ok, F}) ->
SUSRs = lists:sort(USRs),
FUSRs = lists:map(fun({U, S, R}) -> [U, $@, S, $/, R, NewLine] end, SUSRs),
io:format("~s", [FUSRs]),
- ?STATUS_SUCCESS;
+ {stop, ?STATUS_SUCCESS};
ctl_process(_Val, ["connected-users-number"]) ->
N = length(dirty_get_sessions_list()),
io:format("~p~n", [N]),
- ?STATUS_SUCCESS;
+ {stop, ?STATUS_SUCCESS};
ctl_process(_Val, ["user-resources", User, Server]) ->
Resources = get_user_resources(User, Server),
NewLine = io_lib:format("~n", []),
SResources = lists:sort(Resources),
FResources = lists:map(fun(R) -> [R, NewLine] end, SResources),
io:format("~s", [FResources]),
- ?STATUS_SUCCESS;
+ {stop, ?STATUS_SUCCESS};
ctl_process(Val, _Args) ->
Val.