-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2011 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License
-%%% along with this program; if not, write to the Free Software
-%%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-%%%
-%%%----------------------------------------------------------------------
-
-%%% @headerfile "ejabberd_commands.hrl"
-
-%%% @doc Management of ejabberd commands.
-%%%
-%%% An ejabberd command is an abstract function identified by a name,
-%%% with a defined number and type of calling arguments and type of
-%%% result, that can be defined in any Erlang module and executed
-%%% using any valid frontend.
-%%%
-%%%
-%%% == Define a new ejabberd command ==
-%%%
-%%% ejabberd commands can be defined and registered in
-%%% any Erlang module.
-%%%
-%%% Some commands are procedures; and their purpose is to perform an
-%%% action in the server, so the command result is only some result
-%%% code or result tuple. Other commands are inspectors, and their
-%%% purpose is to gather some information about the server and return
-%%% a detailed response: it can be integer, string, atom, tuple, list
-%%% or a mix of those ones.
-%%%
-%%% The arguments and result of an ejabberd command are strictly
-%%% defined. The number and format of the arguments provided when
-%%% calling an ejabberd command must match the definition of that
-%%% command. The format of the result provided by an ejabberd command
-%%% must be exactly its definition. For example, if a command is said
-%%% to return an integer, it must always return an integer (except in
-%%% case of a crash).
-%%%
-%%% If you are developing an Erlang module that will run inside
-%%% ejabberd and you want to provide a new ejabberd command to
-%%% administer some task related to your module, you only need to:
-%%% implement a function, define the command, and register it.
-%%%
-%%%
-%%% === Define a new ejabberd command ===
-%%%
-%%% An ejabberd command is defined using the Erlang record
-%%% 'ejabberd_commands'. This record has several elements that you
-%%% must define. Note that 'tags', 'desc' and 'longdesc' are optional.
-%%%
-%%% For example let's define an ejabberd command 'pow' that gets the
-%%% integers 'base' and 'exponent'. Its result will be an integer
-%%% 'power':
-%%%
-%%% #ejabberd_commands{name = pow, tags = [test],
-%%% desc = "Return the power of base for exponent",
-%%% longdesc = "This is an example command. The formula is:\n"
-%%% " power = base ^ exponent",
-%%% module = ?MODULE, function = pow,
-%%% args = [{base, integer}, {exponent, integer}],
-%%% result = {power, integer}}
-%%%
-%%%
-%%% === Implement the function associated to the command ===
-%%%
-%%% Now implement a function in your module that matches the arguments
-%%% and result of the ejabberd command.
-%%%
-%%% For example the function calc_power gets two integers Base and
-%%% Exponent. It calculates the power and rounds to an integer:
-%%%
-%%% calc_power(Base, Exponent) ->
-%%% PowFloat = math:pow(Base, Exponent),
-%%% round(PowFloat).
-%%%
-%%% Since this function will be called by ejabberd_commands, it must be exported.
-%%% Add to your module:
-%%% -export([calc_power/2]).
-%%%
-%%% Only some types of result formats are allowed.
-%%% If the format is defined as 'rescode', then your function must return:
-%%% ok | true | atom()
-%%% where the atoms ok and true as considered positive answers,
-%%% and any other response atom is considered negative.
-%%%
-%%% If the format is defined as 'restuple', then the command must return:
-%%% {rescode(), string()}
-%%%
-%%% If the format is defined as '{list, something()}', then the command
-%%% must return a list of something().
-%%%
-%%%
-%%% === Register the command ===
-%%%
-%%% Define this function and put inside the #ejabberd_command you
-%%% defined in the beginning:
-%%%
-%%% commands() ->
-%%% [
-%%%
-%%% ].
-%%%
-%%% You need to include this header file in order to use the record:
-%%%
-%%% -include("ejabberd_commands.hrl").
-%%%
-%%% When your module is initialized or started, register your commands:
-%%%
-%%% ejabberd_commands:register_commands(commands()),
-%%%
-%%% And when your module is stopped, unregister your commands:
-%%%
-%%% ejabberd_commands:unregister_commands(commands()),
-%%%
-%%% That's all! Now when your module is started, the command will be
-%%% registered and any frontend can access it. For example:
-%%%
-%%% $ mongooseimctl help pow
-%%%
-%%% Command Name: pow
-%%%
-%%% Arguments: base::integer
-%%% exponent::integer
-%%%
-%%% Returns: power::integer
-%%%
-%%% Tags: test
-%%%
-%%% Description: Return the power of base for exponent
-%%%
-%%% This is an example command. The formula is:
-%%% power = base ^ exponent
-%%%
-%%% $ mongooseimctl pow 3 4
-%%% 81
-%%%
-%%%
-%%%
-%%% == Execute an ejabberd command ==
-%%%
-%%% ejabberd commands are mean to be executed using any valid
-%%% frontend. An ejabberd commands is implemented in a regular Erlang
-%%% function, so it is also possible to execute this function in any
-%%% Erlang module, without dealing with the associated ejabberd
-%%% commands.
-%%%
-%%%
-%%% == Frontend to ejabberd commands ==
-%%%
-%%% Currently there is one frontend to ejabberd commands: the shell
-%%% script - mongooseimctl
-%%%
-%%% === mongooseimctl as a frontend to ejabberd commands ===
-%%%
-%%% It is possible to use mongooseimctl to get documentation of any
-%%% command. But mongooseimctl does not support all the argument types
-%%% allowed in ejabberd commands, so there are some ejabberd commands
-%%% that cannot be executed using mongooseimctl.
-%%%
-%%% Also note that the mongooseimctl shell administration script also
-%%% manages mongooseimctl commands, which are unrelated to ejabberd
-%%% commands and can only be executed using mongooseimctl.
-%%%
-%%% TODO: consider this feature:
-%%% All commands are catched. If an error happens, return the restuple:
-%%% {error, flattened error string}
-%%% This means that ecomm call APIs ejabberd_ctl need to allows this.
-
-
--module(ejabberd_commands).
--author('badlop@process-one.net').
-
--export([init/0,
- list_commands/0,
- get_command_format/1,
- get_command_definition/1,
- get_tags_commands/0,
- register_commands/1,
- unregister_commands/1,
- execute_command/2,
- execute_command/4
- ]).
-
--ignore_xref([execute_command/2]).
-
--include("ejabberd_commands.hrl").
--include("mongoose.hrl").
-
-%% Allowed types for arguments are integer, string, tuple and list.
--type atype() :: integer | string | atom | binary | {tuple, [aterm()]} | {list, aterm()}.
-
-%% A rtype is either an atom or a tuple with two elements.
--type rtype() :: integer | string | atom | binary | {tuple, [rterm()]}
- | {list, rterm()} | rescode | restuple.
-
-%% An argument term is a tuple with the term name and the term type.
--type aterm() :: {Name::atom(), Type::atype()}.
-
-%% A result term is a tuple with the term name and the term type.
--type rterm() :: {Name::atom(), Type::rtype()}.
-
--type cmd() :: #ejabberd_commands{
- name :: atom(),
- tags :: [atom()],
- desc :: string(),
- longdesc :: string(),
- module :: module(),
- function :: atom(),
- args :: [ejabberd_commands:aterm()],
- result :: ejabberd_commands:rterm()
- }.
-
--type auth() :: {User :: binary(), Server :: binary(), Password :: binary()} | noauth.
-
--type cmd_error() :: command_unknown | account_unprivileged
- | invalid_account_data | no_auth_provided.
--type access_commands() :: #{acl:rule_name() => command_rules()}.
--type command_rules() :: #{commands := all | [atom()],
- argument_restrictions := argument_restrictions()}.
-
-%% Currently only string arguments can have restrictions
--type argument_restrictions() :: #{ArgName :: atom() => Value :: string()}.
-
--type list_cmd() :: {Name::atom(), Args::[aterm()], Desc::string()}.
-
--export_type([rterm/0,
- aterm/0,
- cmd/0,
- auth/0,
- access_commands/0,
- list_cmd/0]).
-
-init() ->
- case ets:info(ejabberd_commands) of
- undefined ->
- ets:new(ejabberd_commands, [named_table, set, public,
- {keypos, #ejabberd_commands.name}]);
- _ ->
- ok
- end.
-
-%% @doc Register ejabberd commands. If a command is already registered, a
-%% warning is printed and the old command is preserved.
--spec register_commands([cmd()]) -> ok.
-register_commands(Commands) ->
- lists:foreach(
- fun(Command) ->
- Inserted = ets:insert_new(ejabberd_commands, Command),
- ?LOG_IF(warning, not Inserted,
- #{what => register_command_duplicate,
- text => <<"This command is already defined">>,
- command => Command})
- end,
- Commands).
-
-%% @doc Unregister ejabberd commands.
--spec unregister_commands([cmd()]) -> ok.
-unregister_commands(Commands) ->
- lists:foreach(
- fun(Command) ->
- ets:delete_object(ejabberd_commands, Command)
- end,
- Commands).
-
-%% @doc Get a list of all the available commands, arguments and description.
--spec list_commands() -> [list_cmd()].
-list_commands() ->
- Commands = ets:match(ejabberd_commands,
- #ejabberd_commands{name = '$1',
- args = '$2',
- desc = '$3',
- _ = '_'}),
- [{A, B, C} || [A, B, C] <- Commands].
-
-%% @doc Get the format of arguments and result of a command.
--spec get_command_format(Name::atom()) -> {Args::[aterm()], Result::rterm()}
- | {error, command_unknown}.
-get_command_format(Name) ->
- Matched = ets:match(ejabberd_commands,
- #ejabberd_commands{name = Name,
- args = '$1',
- result = '$2',
- _ = '_'}),
- case Matched of
- [] ->
- {error, command_unknown};
- [[Args, Result]] ->
- {Args, Result}
- end.
-
-%% @doc Get the definition record of a command.
--spec get_command_definition(Name::atom()) -> cmd() | 'command_not_found'.
-get_command_definition(Name) ->
- case ets:lookup(ejabberd_commands, Name) of
- [E] -> E;
- [] -> command_not_found
- end.
-
-%% @doc Execute a command.
--spec execute_command(Name :: atom(),
- Arguments :: list()
- ) -> Result :: term() | {error, command_unknown}.
-execute_command(Name, Arguments) ->
- execute_command(#{}, noauth, Name, Arguments).
-
--spec execute_command(AccessCommands :: access_commands(),
- Auth :: auth(),
- Name :: atom(),
- Arguments :: [term()]
- ) -> Result :: term() | {error, cmd_error()}.
-execute_command(AccessCommands, Auth, Name, Arguments) ->
- case ets:lookup(ejabberd_commands, Name) of
- [Command] ->
- try check_access_commands(AccessCommands, Auth, Name, Command, Arguments) of
- ok -> execute_command2(Command, Arguments)
- catch
- {error, Error} -> {error, Error}
- end;
- [] -> {error, command_unknown}
- end.
-
-%% @private
-execute_command2(Command, Arguments) ->
- Module = Command#ejabberd_commands.module,
- Function = Command#ejabberd_commands.function,
- ?LOG_DEBUG(#{what => execute_command,
- command_module => Module,
- command_function => Function,
- command_args => Arguments}),
- apply(Module, Function, Arguments).
-
-%% @doc Get all the tags and associated commands.
--spec get_tags_commands() -> [{Tag::string(), [CommandName::string()]}].
-get_tags_commands() ->
- CommandTags = ets:match(ejabberd_commands,
- #ejabberd_commands{
- name = '$1',
- tags = '$2',
- _ = '_'}),
- Dict = lists:foldl(
- fun([CommandNameAtom, CTags], D) ->
- CommandName = atom_to_list(CommandNameAtom),
- case CTags of
- [] ->
- orddict:append("untagged", CommandName, D);
- _ ->
- lists:foldl(
- fun(TagAtom, DD) ->
- Tag = atom_to_list(TagAtom),
- orddict:append(Tag, CommandName, DD)
- end,
- D,
- CTags)
- end
- end,
- orddict:new(),
- CommandTags),
- orddict:to_list(Dict).
-
-%% -----------------------------
-%% Access verification
-%% -----------------------------
-
-%% @doc Check access is allowed to that command.
-%% At least one AccessCommand must be satisfied.
-%% May throw {error, account_unprivileged | invalid_account_data}
--spec check_access_commands(AccessCommands :: access_commands(),
- Auth :: auth(),
- Method :: atom(),
- Command :: tuple(),
- Arguments :: [any()]
- ) -> ok | none().
-check_access_commands(AccessCommands, _Auth, _Method, _Command, _Arguments)
- when AccessCommands =:= #{} -> ok;
-check_access_commands(AccessCommands, Auth, Method, Command, Arguments) ->
- AccessCommandsAllowed =
- maps:filter(
- fun(Access, CommandSpec) ->
- case check_access(Access, Auth) of
- true ->
- check_access_command(Command, CommandSpec, Method, Arguments);
- false ->
- false
- end
- end,
- AccessCommands),
- case AccessCommandsAllowed =:= #{} of
- true -> throw({error, account_unprivileged});
- false -> ok
- end.
-
-%% @private
-%% May throw {error, invalid_account_data}
--spec check_auth(auth()) -> {ok, jid:jid()} | no_return().
-check_auth({User, Server, Password}) ->
- %% Check the account exists and password is valid
- JID = jid:make_bare(User, Server),
- AccountPass = ejabberd_auth:get_password_s(JID),
- AccountPassMD5 = get_md5(AccountPass),
- case Password of
- AccountPass -> {ok, JID};
- AccountPassMD5 -> {ok, JID};
- _ -> throw({error, invalid_account_data})
- end.
-
--spec get_md5(iodata()) -> string().
-get_md5(AccountPass) ->
- lists:flatten([io_lib:format("~.16B", [X])
- || X <- binary_to_list(crypto:hash(md5, AccountPass))]).
-
--spec check_access(Access :: acl:rule_name(), Auth :: auth()) -> boolean().
-check_access(all, _) ->
- true;
-check_access(_, noauth) ->
- false;
-check_access(Access, Auth) ->
- {ok, JID} = check_auth(Auth),
- %% Check this user has access permission
- {_, LServer} = jid:to_lus(JID),
- {ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer),
- case acl:match_rule(HostType, LServer, Access, JID) of
- allow -> true;
- deny -> false
- end.
-
--spec check_access_command(cmd(), command_rules(), atom(), [any()]) -> boolean().
-check_access_command(Command, CommandRules, Method, Arguments) ->
- #{commands := Commands, argument_restrictions := ArgumentRestrictions} = CommandRules,
- case Commands == all orelse lists:member(Method, Commands) of
- true -> check_access_arguments(Command, ArgumentRestrictions, Arguments);
- false -> false
- end.
-
--spec check_access_arguments(Command :: cmd(),
- Restrictions :: [any()],
- Args :: [any()]) -> boolean().
-check_access_arguments(Command, ArgumentRestrictions, Arguments) ->
- ArgumentsTagged = tag_arguments(Command#ejabberd_commands.args, Arguments),
- lists:all(
- fun({ArgName, ArgValue}) ->
- case ArgumentRestrictions of
- %% If there is a restriction, check the value is acceptable
- #{ArgName := ArgAllowedValue} -> ArgValue =:= ArgAllowedValue;
- #{} -> true
- end
- end, ArgumentsTagged).
-
--spec tag_arguments(ArgsDefs :: [{atom(), integer() | string() | {_, _}}],
- Args :: [any()] ) -> [{_, _}].
-tag_arguments(ArgsDefs, Args) ->
- lists:zipwith(
- fun({ArgName, _ArgType}, ArgValue) ->
- {ArgName, ArgValue}
- end,
- ArgsDefs,
- Args).
diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl
index 4df6e3571b7..80ebf418f39 100644
--- a/src/ejabberd_ctl.erl
+++ b/src/ejabberd_ctl.erl
@@ -35,29 +35,19 @@
%%% Note: strings cannot have blankspaces
%%%
%%% Does not support commands that have arguments with ctypes: list, tuple
-%%%
-%%% TODO: Update the guide
-%%% TODO: Mention this in the release notes
-%%% Note: the commands with several words use now the underline: _
-%%% It is still possible to call the commands with dash: -
-%%% but this is deprecated, and may be removed in a future version.
-module(ejabberd_ctl).
-author('alexey@process-one.net').
-export([start/0,
- process/1,
- process2/2]).
+ process/1]).
--ignore_xref([process/1, process2/2, start/0]).
+-ignore_xref([process/1, start/0]).
-include("ejabberd_ctl.hrl").
--include("ejabberd_commands.hrl").
-include("mongoose_logger.hrl").
--type format() :: integer | string | atom | binary | {list, format()}.
--type format_type() :: binary() | string() | char() | node().
-type cmd() :: {CallString :: string(), Args :: [string()], Desc :: string()}.
-define(ASCII_SPACE_CHARACTER, $\s).
@@ -130,12 +120,16 @@ process(["stop"]) ->
process(["restart"]) ->
init:restart(),
?STATUS_SUCCESS;
-process(["mnesia"]) ->
- ?PRINT("~p~n", [mnesia:system_info(all)]),
- ?STATUS_SUCCESS;
-process(["mnesia", "info"]) ->
- mnesia:info(),
- ?STATUS_SUCCESS;
+process(["join_cluster", Arg]) when is_list(Arg) ->
+ join_cluster(Arg);
+process(["join_cluster" | _]) ->
+ cluster_command_usage();
+process(["leave_cluster"]) ->
+ leave_cluster();
+process(["remove_from_cluster", Arg]) when is_list(Arg) ->
+ remove_from_cluster(Arg);
+process(["remove_from_cluster" | _]) ->
+ cluster_command_usage();
process(["graphql", Arg]) when is_list(Arg) ->
Doc = list_to_binary(Arg),
Ep = mongoose_graphql:get_endpoint(admin),
@@ -144,42 +138,13 @@ process(["graphql", Arg]) when is_list(Arg) ->
process(["graphql" | _]) ->
?PRINT("This command requires one string type argument!\n", []),
?STATUS_ERROR;
-
-%% @doc The arguments --long and --dual are not documented because they are
-%% automatically selected depending in the number of columns of the shell
-process(["help" | Mode]) ->
- {MaxC, ShCode} = get_shell_info(),
- case Mode of
- [] ->
- print_usage_old(dual, MaxC, ShCode),
- ?STATUS_USAGE;
- ["--dual"] ->
- print_usage_old(dual, MaxC, ShCode),
- ?STATUS_USAGE;
- ["--long"] ->
- print_usage_old(long, MaxC, ShCode),
- ?STATUS_USAGE;
- ["--tags"] ->
- print_usage_tags(MaxC, ShCode),
- ?STATUS_SUCCESS;
- ["--tags", Tag] ->
- print_usage_tags(Tag, MaxC, ShCode),
- ?STATUS_SUCCESS;
- ["help"] ->
- print_usage_help(MaxC, ShCode),
- ?STATUS_SUCCESS;
- [CmdString | _] ->
- CmdStringU = re:replace(CmdString, "-", "_", [global, {return, list}]),
- print_usage_commands(CmdStringU, MaxC, ShCode),
- ?STATUS_SUCCESS
- end;
process(Args) ->
case mongoose_graphql_commands:process(Args) of
#{status := executed, result := Result} ->
handle_graphql_result(Result);
- #{status := error, reason := Reason} when Reason =:= no_args;
- Reason =:= unknown_category ->
- run_command(Args); % Fallback to the old commands
+ #{status := error, reason := no_args} = Ctx ->
+ print_usage(Ctx),
+ ?STATUS_USAGE;
#{status := error} = Ctx ->
?PRINT(error_message(Ctx) ++ "\n\n", []),
print_usage(Ctx),
@@ -194,6 +159,8 @@ error_message(#{reason := unknown_command, command := Command}) ->
io_lib:format("Unknown command '~s'", [Command]);
error_message(#{reason := invalid_args}) ->
"Could not parse the command arguments";
+error_message(#{reason := unknown_category}) ->
+ "Unknown category";
error_message(#{reason := {unknown_arg, ArgName}, command := Command}) ->
io_lib:format("Unknown argument '~s' for command '~s'", [ArgName, Command]);
error_message(#{reason := {invalid_arg_value, ArgName, ArgValue}, command := Command}) ->
@@ -207,7 +174,10 @@ error_message(#{reason := {missing_args, MissingArgs}, command := Command}) ->
print_usage(#{category := Category, command := Command, args_spec := ArgsSpec}) ->
print_usage_command(Category, Command, ArgsSpec);
print_usage(#{category := Category, commands := Commands}) ->
- print_usage_category(Category, Commands).
+ print_usage_category(Category, Commands);
+print_usage(_) ->
+ {MaxC, ShCode} = get_shell_info(),
+ print_usage(MaxC, ShCode).
handle_graphql_result({ok, Result}) ->
JSONResult = mongoose_graphql_response:term_to_pretty_json(Result),
@@ -222,227 +192,9 @@ handle_graphql_result({error, Reason}) ->
?PRINT("~s\n", [JSONResult]),
?STATUS_ERROR.
-run_command(Args) ->
- AccessCommands = get_accesscommands(),
- {String, Code} = process2(Args, AccessCommands),
- case String of
- [] -> ok;
- _ ->
- io:format("~s~n", [String])
- end,
- Code.
-
--spec process2(Args :: [string()], AccessCommands :: ejabberd_commands:access_commands()) ->
- {String::string(), Code::integer()}.
-process2(["--auth", User, Server, Pass | Args], AccessCommands) ->
- process2(Args, {list_to_binary(User), list_to_binary(Server), list_to_binary(Pass)},
- AccessCommands);
-process2(Args, AccessCommands) ->
- process2(Args, noauth, AccessCommands).
-
-
-%% @private
-process2(Args, Auth, AccessCommands) ->
- case try_call_command(Args, Auth, AccessCommands) of
- {String, wrong_command_arguments} when is_list(String) ->
- io:format(lists:flatten(["\n" | String]++["\n"])),
- [CommandString | _] = Args,
- process(["help" | [CommandString]]),
- {lists:flatten(String), ?STATUS_ERROR};
- {String, Code} when is_list(String) and is_integer(Code) ->
- {lists:flatten(String), Code};
- String when is_list(String) ->
- {lists:flatten(String), ?STATUS_SUCCESS};
- Other ->
- {"Erroneous result: " ++ io_lib:format("~p", [Other]), ?STATUS_ERROR}
- end.
-
-
--spec get_accesscommands() -> ejabberd_commands:access_commands().
-get_accesscommands() ->
- mongoose_config:get_opt(mongooseimctl_access_commands).
-
-
-%%-----------------------------
-%% Command calling
-%%-----------------------------
--spec try_call_command(Args :: [string()],
- Auth :: ejabberd_commands:auth(),
- AccessCommands :: ejabberd_commands:access_commands()
- ) -> string() | integer() | {string(), integer()} | {string(), wrong_command_arguments}.
-try_call_command([], _, _) ->
- print_usage(),
- {"", ?STATUS_USAGE};
-try_call_command(Args, Auth, AccessCommands) ->
- try call_command(Args, Auth, AccessCommands) of
- {error, command_unknown} ->
- {io_lib:format("Error: command ~p not known.", [hd(Args)]), ?STATUS_ERROR};
- Res ->
- Res
- catch
- A:Why:Stack ->
- {io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR}
- end.
-
-
--spec call_command(Args :: [string()],
- Auth :: ejabberd_commands:auth(),
- AccessCommands :: ejabberd_commands:access_commands()
- ) -> string() | integer() | {string(), integer()}
- | {string(), wrong_command_arguments} | {error, command_unknown}.
-call_command([CmdString | Args], Auth, AccessCommands) ->
- CmdStringU = re:replace(CmdString, "-", "_", [global, {return, list}]),
- Command = list_to_atom(CmdStringU),
- case ejabberd_commands:get_command_format(Command) of
- {error, command_unknown} ->
- {error, command_unknown};
- {ArgsFormat, ResultFormat} ->
- case (catch format_args(Args, ArgsFormat)) of
- ArgsFormatted when is_list(ArgsFormatted) ->
- Result = ejabberd_commands:execute_command(AccessCommands, Auth, Command,
- ArgsFormatted),
- format_result(Result, ResultFormat);
- {'EXIT', {function_clause, [{lists, zip, [A1, A2], _FileInfo} | _]}} ->
- {NumCompa, TextCompa} =
- case {length(A1), length(A2)} of
- {L1, L2} when L1 < L2 -> {L2-L1, "less argument"};
- {L1, L2} when L1 > L2 -> {L1-L2, "more argument"}
- end,
- {io_lib:format("Error: the command ~p requires ~p ~s.",
- [CmdString, NumCompa, TextCompa]),
- wrong_command_arguments}
- end
- end.
-
-
%%-----------------------------
%% Format arguments
%%-----------------------------
-
-%% @private
--spec format_args(Args :: [any()],
- ArgsFormat :: [format()]) -> [any()].
-format_args(Args, ArgsFormat) ->
- lists:foldl(
- fun({{_ArgName, ArgFormat}, Arg}, Res) ->
- Formatted = format_arg(Arg, ArgFormat),
- Res ++ [Formatted]
- end,
- [],
- lists:zip(ArgsFormat, Args)).
-
-
-%% @private
--spec format_arg(string(), format()) -> format_type().
-format_arg(Arg, integer) ->
- format_arg2(Arg, "~d");
-format_arg("", string) ->
- "";
-format_arg(Arg, string) ->
- NumChars = integer_to_list(string:len(Arg)),
- Parse = "~" ++ NumChars ++ "c",
- format_arg2(Arg, Parse);
-format_arg(Arg, binary) ->
- list_to_binary(format_arg(Arg, string));
-format_arg(Arg, {list, Type}) ->
- [format_arg(Token, Type) || Token <- string:tokens(Arg, ";")];
-format_arg("self", atom) ->
- node();
-format_arg(Arg, atom) ->
- list_to_atom(Arg).
-
-%% @private
--spec format_arg2(Arg :: string(),
- Parse :: nonempty_string()
- ) -> [[any()] | char()] | char().
-format_arg2(Arg, Parse)->
- {ok, [Arg2], _RemainingArguments} = io_lib:fread(Parse, Arg),
- Arg2.
-
-%%-----------------------------
-%% Format result
-%%-----------------------------
-
-format_error(Error) ->
- try
- io_lib:format("\"~ts\"", [Error])
- catch _ ->
- io_lib:format("~p", [Error])
- end.
-
--spec format_result(In :: tuple() | atom() | integer() | string() | binary(),
- {_, 'atom'|'integer'|'string'|'binary'}
- ) -> string() | {string(), _}.
-format_result({Atom, Error}, _) when is_atom(Atom), Atom =/= ok ->
- {io_lib:format("Error: ~ts", [format_error(Error)]), make_status(error)};
-format_result(Atom, {_Name, atom}) ->
- io_lib:format("~p", [Atom]);
-format_result(Int, {_Name, integer}) ->
- io_lib:format("~p", [Int]);
-format_result(String, {_Name, string}) ->
- io_lib:format("~s", [String]);
-format_result(Binary, {_Name, binary}) ->
- io_lib:format("~s", [Binary]);
-format_result(Code, {_Name, rescode}) ->
- {"", make_status(Code)};
-format_result({Code, Text}, {_Name, restuple}) ->
- {io_lib:format("~s", [Text]), make_status(Code)};
-%% The result is a list of something: [something()]
-format_result([], {_Name, {list, _ElementsDef}}) ->
- "";
-format_result([FirstElement | Elements], {_Name, {list, ElementsDef}}) ->
- %% Start formatting the first element
- [format_result(FirstElement, ElementsDef) |
- %% If there are more elements, put always first a newline character
- lists:map(
- fun(Element) ->
- ["\n" | format_result(Element, ElementsDef)]
- end,
- Elements)];
-%% The result is a tuple with several elements: {something1(), something2(), ...}
-%% NOTE: the elements in the tuple are separated with tabular characters,
-%% if a string is empty, it will be difficult to notice in the shell,
-%% maybe a different separation character should be used, like ;;?
-format_result(ElementsTuple, {_Name, {tuple, ElementsDef}}) ->
- ElementsList = tuple_to_list(ElementsTuple),
- [{FirstE, FirstD} | ElementsAndDef] = lists:zip(ElementsList, ElementsDef),
- [format_result(FirstE, FirstD) |
- lists:map(
- fun({Element, ElementDef}) ->
- ["\t" | format_result(Element, ElementDef)]
- end,
- ElementsAndDef)];
-format_result({ok, List}, ListDef) ->
- format_result(List, ListDef).
-
--spec make_status(ok | true | _) -> 0 | 1.
-make_status(ok) -> ?STATUS_SUCCESS;
-make_status(true) -> ?STATUS_SUCCESS;
-make_status(_Error) -> ?STATUS_ERROR.
-
-
--spec get_list_commands()
- -> [{Call :: string(), Args :: [string()], Desc :: string()}].
-get_list_commands() ->
- try ejabberd_commands:list_commands() of
- Commands ->
- [tuple_command_help(Command)
- || {N, _, _}=Command <- Commands,
- %% Don't show again those commands, because they are already
- %% announced by ejabberd_ctl itself
- N /= status, N /= stop, N /= restart]
- catch
- exit:_ ->
- []
- end.
-
-
--spec tuple_command_help(ejabberd_commands:list_cmd()) -> cmd().
-tuple_command_help({Name, Args, Desc}) ->
- Arguments = [atom_to_list(ArgN) || {ArgN, _ArgF} <- Args],
- CallString = atom_to_list(Name),
- {CallString, Arguments, Desc}.
-
format_status([{node, Node}, {internal_status, IS}, {provided_status, PS},
{mongoose_status, MS}, {os_pid, OSPid}, {uptime, UptimeHMS},
{dist_proto, DistProto}, {logs, LogFiles}]) ->
@@ -476,54 +228,33 @@ format_status([{node, Node}, {internal_status, IS}, {provided_status, PS},
print_usage() ->
{MaxC, ShCode} = get_shell_info(),
- print_usage(dual, MaxC, ShCode).
+ print_usage(MaxC, ShCode).
--spec print_usage(dual | long, MaxC :: integer(), ShCode :: boolean()) -> ok.
-print_usage(HelpMode, MaxC, ShCode) ->
+-spec print_usage(MaxC :: integer(), ShCode :: boolean()) -> ok.
+print_usage(MaxC, ShCode) ->
?PRINT(["Usage: ", ?B("mongooseimctl"), " [", ?U("category"), "] ", ?U("command"),
" [", ?U("arguments"), "]\n\n"
"Most MongooseIM commands are grouped into the following categories:\n"], []),
- print_categories(HelpMode, MaxC, ShCode),
+ print_categories(MaxC, ShCode),
?PRINT(["\nTo list the commands in a particular category:\n mongooseimctl ", ?U("category"),
"\n"], []),
?PRINT(["\nThe following basic system management commands do not have a category:\n"], []),
- print_usage_commands(HelpMode, MaxC, ShCode, basic_commands()).
-
--spec print_usage_old(dual | long, MaxC :: integer(), ShCode :: boolean()) -> ok.
-print_usage_old(HelpMode, MaxC, ShCode) ->
- ?PRINT(["The following commands are deprecated and ", ?B("will be removed"), " soon.\n"
- "To learn about the new commands, run 'mongooseimctl' without any arguments.\n\n"], []),
- AllCommands = basic_commands() ++ get_list_commands(),
- ?PRINT(
- ["Usage: ", ?B("mongooseimctl"), " [--node ", ?U("nodename"), "] [--auth ",
- ?U("user"), " ", ?U("host"), " ", ?U("password"), "] ",
- ?U("command"), " [", ?U("options"), "]\n"
- "\n"
- "Available commands in this MongooseIM node:\n"], []),
- print_usage_commands(HelpMode, MaxC, ShCode, AllCommands),
- ?PRINT(
- ["\n"
- "Examples:\n"
- " mongooseimctl restart\n"
- " mongooseimctl --node mongooseim@host restart\n"],
- []).
+ print_usage_commands(MaxC, ShCode, basic_commands()).
-spec basic_commands() -> [cmd()].
basic_commands() ->
[{"status", [], "Get MongooseIM status"},
{"stop", [], "Stop MongooseIM"},
{"restart", [], "Restart MongooseIM"},
- {"help", ["[--tags [tag] | com?*]"], "Show help for the deprecated commands"},
- {"mnesia", ["[info]"], "Show information about Mnesia database management system"},
{"graphql", ["query"], "Execute GraphQL query or mutation"}].
--spec print_categories(dual | long, MaxC :: integer(), ShCode :: boolean()) -> ok.
-print_categories(HelpMode, MaxC, ShCode) ->
+-spec print_categories(MaxC :: integer(), ShCode :: boolean()) -> ok.
+print_categories(MaxC, ShCode) ->
SortedSpecs = lists:sort(maps:to_list(mongoose_graphql_commands:get_specs())),
Categories = [{binary_to_list(Category), [], binary_to_list(Desc)}
|| {Category, #{desc := Desc}} <- SortedSpecs],
- print_usage_commands(HelpMode, MaxC, ShCode, Categories).
+ print_usage_commands(MaxC, ShCode, Categories).
-spec print_usage_category(mongoose_graphql_commands:category(),
mongoose_graphql_commands:command_map()) -> ok.
@@ -534,7 +265,7 @@ print_usage_category(Category, Commands) ->
"The following commands are available in the category '", Category, "':\n"], []),
CmdSpec = [{binary_to_list(Command), [], binary_to_list(Desc)}
|| {Command, #{desc := Desc}} <- maps:to_list(Commands)],
- print_usage_commands(dual, MaxC, ShCode, CmdSpec),
+ print_usage_commands(MaxC, ShCode, CmdSpec),
?PRINT(["\nTo list the arguments for a particular command:\n"
" mongooseimctl ", Category, " ", ?U("command"), " --help", "\n"], []).
@@ -551,16 +282,15 @@ print_usage_command(Category, Command, ArgsSpec) ->
%% This will be replaced with new logic when old commands are dropped
Args = [{binary_to_list(Name), [], mongoose_graphql_commands:wrap_type(Wrap, Type)}
|| #{name := Name, type := Type, wrap := Wrap} <- ArgsSpec],
- print_usage_commands(dual, MaxC, ShCode, Args),
+ print_usage_commands(MaxC, ShCode, Args),
?PRINT(["\nScalar values do not need quoting unless they contain special characters or spaces.\n"
"Complex input types are passed as JSON maps or lists, depending on the type.\n"
"When a type is followed by '!', the corresponding argument is required.\n"], []).
--spec print_usage_commands(HelpMode :: 'dual' | 'long',
- MaxC :: integer(),
+-spec print_usage_commands(MaxC :: integer(),
ShCode :: boolean(),
Commands :: [cmd(), ...]) -> 'ok'.
-print_usage_commands(HelpMode, MaxC, ShCode, Commands) ->
+print_usage_commands(MaxC, ShCode, Commands) ->
CmdDescsSorted = lists:keysort(1, Commands),
%% What is the length of the largest command?
@@ -585,7 +315,7 @@ print_usage_commands(HelpMode, MaxC, ShCode, Commands) ->
%% For each command in the list of commands
%% Convert its definition to a line
- FmtCmdDescs = format_command_lines(CmdArgsLenDescsSorted, MaxCmdLen, MaxC, ShCode, HelpMode),
+ FmtCmdDescs = format_command_lines(CmdArgsLenDescsSorted, MaxCmdLen, MaxC, ShCode),
?PRINT([FmtCmdDescs], []).
%% @doc Get some info about the shell: how many columns of width and guess if
@@ -658,228 +388,30 @@ join(L, [Word | Words], LenLastSeg, LastSeg, ResSeg) ->
-spec format_command_lines(CALD :: [{[any()], [any()], number(), _}, ...],
MaxCmdLen :: integer(),
MaxC :: integer(),
- ShCode :: boolean(),
- 'dual' | 'long') -> [[any(), ...], ...].
-format_command_lines(CALD, MaxCmdLen, MaxC, ShCode, dual)
- when MaxC - MaxCmdLen < 40 ->
- %% If the space available for descriptions is too narrow, enforce long help mode
- format_command_lines(CALD, MaxCmdLen, MaxC, ShCode, long);
-format_command_lines(CALD, MaxCmdLen, MaxC, ShCode, dual) ->
+ ShCode :: boolean()) -> [[any(), ...], ...].
+format_command_lines(CALD, MaxCmdLen, MaxC, ShCode) when MaxC - MaxCmdLen < 40 ->
+ % Long mode
lists:map(
- fun({Cmd, Args, CmdArgsL, Desc}) ->
- DescFmt = prepare_description(MaxCmdLen+4, MaxC, Desc),
- [" ", ?B(Cmd), " ", [[?U(Arg), " "] || Arg <- Args], string:chars(?ASCII_SPACE_CHARACTER, MaxCmdLen - CmdArgsL + 1),
- DescFmt, "\n"]
- end, CALD);
-format_command_lines(CALD, _MaxCmdLen, MaxC, ShCode, long) ->
+ fun({Cmd, Args, _CmdArgsL, Desc}) ->
+ DescFmt = prepare_description(8, MaxC, Desc),
+ ["\n ", ?B(Cmd), " ", [[?U(Arg), " "] || Arg <- Args], "\n", " ",
+ DescFmt, "\n"]
+ end, CALD);
+
+format_command_lines(CALD, MaxCmdLen, MaxC, ShCode) ->
+ % Dual mode
lists:map(
- fun({Cmd, Args, _CmdArgsL, Desc}) ->
- DescFmt = prepare_description(8, MaxC, Desc),
- ["\n ", ?B(Cmd), " ", [[?U(Arg), " "] || Arg <- Args], "\n", " ",
- DescFmt, "\n"]
- end, CALD).
-
-%%-----------------------------
-%% Print Tags
-%%-----------------------------
-
-print_usage_tags(MaxC, ShCode) ->
- ?PRINT("Available tags and commands:", []),
- TagsCommands = ejabberd_commands:get_tags_commands(),
- lists:foreach(
- fun({Tag, Commands} = _TagCommands) ->
- ?PRINT(["\n\n ", ?B(Tag), "\n "], []),
- Words = lists:sort(Commands),
- Desc = prepare_long_line(5, MaxC, Words),
- ?PRINT(Desc, [])
- end,
- TagsCommands),
- ?PRINT("\n\n", []).
-
-
-print_usage_tags(Tag, MaxC, ShCode) ->
- ?PRINT(["Available commands with tag ", ?B(Tag), ":", "\n"], []),
- HelpMode = long,
- TagsCommands = ejabberd_commands:get_tags_commands(),
- CommandsNames = case lists:keysearch(Tag, 1, TagsCommands) of
- {value, {Tag, CNs}} -> CNs;
- false -> []
- end,
- CommandsList = lists:map(
- fun(NameString) ->
- C = ejabberd_commands:get_command_definition(list_to_atom(NameString)),
- #ejabberd_commands{name = Name,
- args = Args,
- desc = Desc} = C,
- tuple_command_help({Name, Args, Desc})
- end,
- CommandsNames),
- print_usage_commands(HelpMode, MaxC, ShCode, CommandsList),
- ?PRINT("\n", []).
-
-
-%%-----------------------------
-%% Print usage of 'help' command
-%%-----------------------------
-
-print_usage_help(MaxC, ShCode) ->
- LongDesc =
- ["The special 'help' mongooseimctl command provides help of MongooseIM commands.\n\n"
- "The format is:\n ", ?B("mongooseimctl"), " ", ?B("help"), " [", ?B("--tags"), " ", ?U("[tag]"), " | ", ?U("com?*"), "]\n\n"
- "The optional arguments:\n"
- " ", ?B("--tags"), " Show all tags and the names of commands in each tag\n"
- " ", ?B("--tags"), " ", ?U("tag"), " Show description of commands in this tag\n"
- " ", ?U("command"), " Show detailed description of the command\n"
- " ", ?U("com?*"), " Show detailed description of commands that match this glob.\n"
- " You can use ? to match a simple character, \n"
- " and * to match several characters.\n"
- "\n",
- "Some example usages:\n",
- " mongooseimctl help\n",
- " mongooseimctl help --tags\n",
- " mongooseimctl help --tags accounts\n",
- " mongooseimctl help register\n",
- " mongooseimctl help regist*\n",
- "\n",
- "Please note that 'mongooseimctl help' shows all MongooseIM commands, \n",
- "even those that cannot be used in the shell with mongooseimctl.\n",
- "Those commands can be identified because the description starts with: *"],
- ArgsDef = [],
- C = #ejabberd_commands{
- name = help,
- desc = "Show help of MongooseIM commands",
- longdesc = lists:flatten(LongDesc),
- args = ArgsDef,
- module = none,
- function = none,
- result = {help, string}},
- print_usage_command("help", C, MaxC, ShCode).
-
+ fun({Cmd, Args, CmdArgsL, Desc}) ->
+ DescFmt = prepare_description(MaxCmdLen+4, MaxC, Desc),
+ [" ", ?B(Cmd), " ", [[?U(Arg), " "] || Arg <- Args],
+ string:chars(?ASCII_SPACE_CHARACTER, MaxCmdLen - CmdArgsL + 1),
+ DescFmt, "\n"]
+ end, CALD).
%%-----------------------------
%% Print usage command
%%-----------------------------
--spec print_usage_commands(CmdSubString :: string(), MaxC :: integer(), ShCode :: boolean()) -> ok.
-print_usage_commands(CmdSubString, MaxC, ShCode) ->
- %% Get which command names match this substring
- AllCommandsNames = [atom_to_list(Name) || {Name, _, _} <- ejabberd_commands:list_commands()],
- Cmds = filter_commands(AllCommandsNames, CmdSubString),
- case Cmds of
- [] -> io:format("Error: no command found that match: ~p~n", [CmdSubString]);
- _ -> print_usage_commands2(lists:sort(Cmds), MaxC, ShCode)
- end.
-
-
-print_usage_commands2(Cmds, MaxC, ShCode) ->
- %% Then for each one print it
- lists:mapfoldl(
- fun(Cmd, Remaining) ->
- print_usage_command_old(Cmd, MaxC, ShCode),
- case Remaining > 1 of
- true -> ?PRINT([" ", lists:duplicate(MaxC, 126), " \n"], []);
- false -> ok
- end,
- {ok, Remaining-1}
- end,
- length(Cmds),
- Cmds).
-
-
-filter_commands(All, SubString) ->
- case lists:member(SubString, All) of
- true -> [SubString];
- false -> filter_commands_regexp(All, SubString)
- end.
-
-
-filter_commands_regexp(All, Glob) ->
- RegExp = xmerl_regexp:sh_to_awk(Glob),
- lists:filter(
- fun(Command) ->
- case re:run(Command, RegExp, [{capture, none}]) of
- match ->
- true;
- nomatch ->
- false
- end
- end,
- All).
-
-
--spec print_usage_command_old(Cmd :: string(), MaxC :: integer(), ShCode :: boolean()) -> ok.
-print_usage_command_old(Cmd, MaxC, ShCode) ->
- Name = list_to_atom(Cmd),
- case ejabberd_commands:get_command_definition(Name) of
- command_not_found ->
- io:format("Error: command ~p not known.~n", [Cmd]);
- C ->
- print_usage_command(Cmd, C, MaxC, ShCode)
- end.
-
-
-print_usage_command(Cmd, C, MaxC, ShCode) ->
- #ejabberd_commands{
- tags = TagsAtoms,
- desc = Desc,
- longdesc = LongDesc,
- args = ArgsDef,
- result = ResultDef} = C,
-
- NameFmt = [" ", ?B("Command Name"), ": ", Cmd, "\n"],
-
- %% Initial indentation of result is 13 = length(" Arguments: ")
- Args = [format_usage_ctype(ArgDef, 13) || ArgDef <- ArgsDef],
- ArgsMargin = lists:duplicate(13, ?ASCII_SPACE_CHARACTER),
- ArgsListFmt = case Args of
- [] -> "\n";
- _ -> [ [Arg, "\n", ArgsMargin] || Arg <- Args]
- end,
- ArgsFmt = [" ", ?B("Arguments"), ": ", ArgsListFmt],
-
- %% Initial indentation of result is 11 = length(" Returns: ")
- ResultFmt = format_usage_ctype(ResultDef, 11),
- ReturnsFmt = [" ", ?B("Returns"), ": ", ResultFmt],
-
- TagsFmt = [" ", ?B("Tags"), ": ", prepare_long_line(8, MaxC, [atom_to_list(TagA) || TagA <- TagsAtoms])],
-
- DescFmt = [" ", ?B("Description"), ": ", prepare_description(15, MaxC, Desc)],
-
- LongDescFmt = case LongDesc of
- "" -> "";
- _ -> ["", prepare_description(0, MaxC, LongDesc), "\n\n"]
- end,
-
- ?PRINT(["\n", NameFmt, "\n", ArgsFmt, "\n", ReturnsFmt, "\n\n", TagsFmt, "\n\n", DescFmt, "\n\n", LongDescFmt], []).
-
-
-format_usage_ctype(Type, _Indentation)
- when (Type==atom) or (Type==integer) or (Type==string) or (Type==rescode) or (Type==restuple) or (Type==binary)->
- io_lib:format("~p", [Type]);
-format_usage_ctype({Name, Type}, _Indentation)
- when (Type==atom) or (Type==integer) or (Type==string) or (Type==rescode) or (Type==restuple) or (Type==binary)->
- io_lib:format("~p::~p", [Name, Type]);
-format_usage_ctype({Name, {list, ElementDef}}, Indentation) ->
- NameFmt = atom_to_list(Name),
- Indentation2 = Indentation + length(NameFmt) + 4,
- ElementFmt = format_usage_ctype(ElementDef, Indentation2),
- [NameFmt, "::[ ", ElementFmt, " ]"];
-format_usage_ctype({Name, {tuple, ElementsDef}}, Indentation) ->
- NameFmt = atom_to_list(Name),
- Indentation2 = Indentation + length(NameFmt) + 4,
- ElementsFmt = format_usage_tuple(ElementsDef, Indentation2),
- [NameFmt, "::{ " | ElementsFmt].
-
-
-format_usage_tuple([], _Indentation) ->
- [];
-format_usage_tuple([ElementDef], Indentation) ->
- [format_usage_ctype(ElementDef, Indentation), " }"];
-format_usage_tuple([ElementDef | ElementsDef], Indentation) ->
- ElementFmt = format_usage_ctype(ElementDef, Indentation),
- MarginString = lists:duplicate(Indentation, ?ASCII_SPACE_CHARACTER), % Put spaces
- [ElementFmt, ", \n", MarginString, format_usage_tuple(ElementsDef, Indentation)].
-
get_mongoose_status() ->
case lists:keyfind(mongooseim, 1, application:which_applications()) of
false ->
@@ -899,3 +431,30 @@ get_dist_proto() ->
{ok, [Proto]} -> Proto;
_ -> "inet_tcp"
end.
+
+%%-----------------------------
+%% Cluster management commands
+%%-----------------------------
+
+join_cluster(NodeString) ->
+ handle_cluster_operation(join_cluster, [NodeString]).
+
+leave_cluster() ->
+ handle_cluster_operation(leave_cluster, []).
+
+remove_from_cluster(NodeString) ->
+ handle_cluster_operation(remove_from_cluster, [NodeString]).
+
+handle_cluster_operation(Operation, Args) ->
+ case apply(mongoose_server_api, Operation, Args) of
+ {ok, Result} ->
+ ?PRINT("~s\n", [Result]),
+ ?STATUS_SUCCESS;
+ {_, Result} ->
+ ?PRINT("Error: \"~s\"\n", [Result]),
+ ?STATUS_ERROR
+ end.
+
+cluster_command_usage() ->
+ ?PRINT("This command requires one argument: other node's name\n", []),
+ ?STATUS_ERROR.
diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl
index 1bc0c324676..9c80372b42a 100644
--- a/src/ejabberd_s2s.erl
+++ b/src/ejabberd_s2s.erl
@@ -115,7 +115,6 @@ node_cleanup(Acc, #{node := Node}, _) ->
init([]) ->
internal_database_init(),
set_shared_secret(),
- ejabberd_commands:register_commands(mongoose_s2s_lib:commands()),
gen_hook:add_handlers(hooks()),
{ok, #state{}}.
@@ -133,7 +132,6 @@ handle_info(Msg, State) ->
terminate(_Reason, _State) ->
gen_hook:delete_handlers(hooks()),
- ejabberd_commands:unregister_commands(mongoose_s2s_lib:commands()),
ok.
code_change(_OldVsn, State, _Extra) ->
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index 181c3f3479f..00446b0a88f 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -88,7 +88,6 @@
-include("mongoose.hrl").
-include("jlib.hrl").
--include("ejabberd_commands.hrl").
-include("session.hrl").
-record(state, {}).
@@ -441,7 +440,6 @@ init([]) ->
gen_hook:add_handler(node_cleanup, global, fun ?MODULE:node_cleanup/3, #{}, 50),
lists:foreach(fun(HostType) -> gen_hook:add_handlers(hooks(HostType)) end,
?ALL_HOST_TYPES),
- ejabberd_commands:register_commands(commands()),
%% Create metrics after backend has started, otherwise probe could have null value
create_metrics(),
{ok, #state{}}.
@@ -532,13 +530,6 @@ handle_info(_Info, State) ->
%%--------------------------------------------------------------------
-spec terminate(_, state()) -> 'ok'.
terminate(_Reason, _State) ->
- try
- ejabberd_commands:unregister_commands(commands())
- catch Class:Reason:Stacktrace ->
- ?LOG_ERROR(#{what => sm_terminate_failed,
- text => <<"Caught error while terminating SM">>,
- class => Class, reason => Reason, stacktrace => Stacktrace})
- end,
ok.
%%--------------------------------------------------------------------
@@ -927,34 +918,6 @@ process_iq(_, From, To, Acc, Packet) ->
{Acc1, Err} = jlib:make_error_reply(Acc, Packet, mongoose_xmpp_errors:bad_request()),
ejabberd_router:route(To, From, Acc1, Err).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% ejabberd commands
-
--spec commands() -> [ejabberd_commands:cmd(), ...].
-commands() ->
- [
- %% TODO: Implement following API functions with pluggable backends architcture
- %% #ejabberd_commands{name = connected_users,
- %% tags = [session],
- %% desc = "List all established sessions",
- %% module = ?MODULE, function = connected_users,
- %% args = [],
- %% result = {connected_users, {list, {sessions, string}}}},
- %% #ejabberd_commands{name = connected_users_number,
- %% tags = [session, stats],
- %% desc = "Get the number of established sessions",
- %% module = ?MODULE, function = connected_users_number,
- %% args = [],
- %% result = {num_sessions, integer}},
- #ejabberd_commands{name = user_resources,
- tags = [session],
- desc = "List user's connected resources",
- module = ?MODULE, function = user_resources,
- args = [{user, string}, {host, string}],
- result = {resources, {list, {resource, binary}}}}
- ].
-
-
-spec user_resources(UserStr :: string(), ServerStr :: string()) -> [binary()].
user_resources(UserStr, ServerStr) ->
JID = jid:make_bare(list_to_binary(UserStr), list_to_binary(ServerStr)),
diff --git a/src/http_upload/mod_http_upload_api.erl b/src/http_upload/mod_http_upload_api.erl
index 88940c39ab3..618ec2727d1 100644
--- a/src/http_upload/mod_http_upload_api.erl
+++ b/src/http_upload/mod_http_upload_api.erl
@@ -1,23 +1,6 @@
-module(mod_http_upload_api).
--export([get_urls/5, get_urls_mongooseimctl/5]).
-
--ignore_xref([get_urls_mongooseimctl/5]).
-
--spec get_urls_mongooseimctl(Domain :: jid:lserver(), Filename :: binary(), Size :: pos_integer(),
- ContentType :: binary() | undefined, Timeout :: pos_integer()) ->
- {ok | error, string()}.
-get_urls_mongooseimctl(_Domain, _Filename, Size, _ContentType, _Timeout) when Size =< 0 ->
- {error, "size must be positive integer"};
-get_urls_mongooseimctl(_Domain, _Filename, _Size, _ContentType, Timeout) when Timeout =< 0 ->
- {error, "timeout must be positive integer"};
-get_urls_mongooseimctl(Domain, Filename, Size, ContentType, Timeout) ->
- case get_urls(Domain, Filename, Size, ContentType, Timeout) of
- {ok, #{<<"putUrl">> := PutURL, <<"getUrl">> := GetURL, <<"headers">> := Headers}} ->
- {ok, generate_output_message(PutURL, GetURL, Headers)};
- {_, Message} ->
- {error, Message}
- end.
+-export([get_urls/5]).
-spec get_urls(Domain :: jid:lserver(), Filename :: nonempty_binary(), Size :: pos_integer(),
ContentType :: binary() | null | undefined, Timeout :: pos_integer()) ->
@@ -53,19 +36,3 @@ check_module_and_get_urls(HostType, Filename, Size, ContentType, Timeout) ->
false ->
{module_not_loaded_error, "mod_http_upload is not loaded for this host"}
end.
-
--spec generate_output_message(PutURL :: binary(),
- GetURL :: binary(),
- Headers :: [{ok, map()}]) -> string().
-generate_output_message(PutURL, GetURL, Headers) ->
- PutURLOutput = url_output("PutURL:", PutURL),
- GetURLOutput = url_output("GetURL:", GetURL),
- HeadersOutput = headers_output(Headers),
- lists:flatten([PutURLOutput, GetURLOutput, HeadersOutput]).
-
-url_output(Name, Url) ->
- io_lib:format("~s ~s~n", [Name, Url]).
-
-headers_output(Headers) ->
- List = [{Name, Value} || {ok, #{<<"name">> := Name, <<"value">> := Value}} <- Headers],
- io_lib:format("Header: ~p~n", [List]).
diff --git a/src/mod_auth_token.erl b/src/mod_auth_token.erl
index ada75cbc0f9..edf9280c9a1 100644
--- a/src/mod_auth_token.erl
+++ b/src/mod_auth_token.erl
@@ -4,7 +4,6 @@
-behaviour(mongoose_module_metrics).
-include("mongoose.hrl").
--include("ejabberd_commands.hrl").
-include("jlib.hrl").
-include("mod_auth_token.hrl").
-include("mongoose_config_spec.hrl").
@@ -32,9 +31,6 @@
-export([deserialize/1,
serialize/1]).
-%% Command-line interface
--export([revoke_token_command/1]).
-
%% Test only!
-export([datetime_to_seconds/1,
seconds_to_datetime/1]).
@@ -52,7 +48,7 @@
-ignore_xref([
behaviour_info/1, datetime_to_seconds/1, deserialize/1,
expiry_datetime/3, get_key_for_host_type/2, process_iq/5,
- revoke/2, revoke_token_command/1, seconds_to_datetime/1,
+ revoke/2, seconds_to_datetime/1,
serialize/1, token/3, token_with_mac/2
]).
@@ -82,7 +78,6 @@ start(HostType, #{iqdisc := IQDisc} = Opts) ->
gen_iq_handler:add_iq_handler_for_domain(
HostType, ?NS_ESL_TOKEN_AUTH, ejabberd_sm,
fun ?MODULE:process_iq/5, #{}, IQDisc),
- ejabberd_commands:register_commands(commands()),
ok.
-spec stop(mongooseim:host_type()) -> ok.
@@ -128,13 +123,6 @@ validity_period_spec() ->
required = all
}.
--spec commands() -> [ejabberd_commands:cmd()].
-commands() ->
- [#ejabberd_commands{ name = revoke_token, tags = [tokens],
- desc = "Revoke REFRESH token",
- module = ?MODULE, function = revoke_token_command,
- args = [{owner, binary}], result = {res, restuple} }].
-
%%
%% Other stuff
%%
@@ -414,17 +402,6 @@ key_name(access) -> token_secret;
key_name(refresh) -> token_secret;
key_name(provision) -> provision_pre_shared.
--spec revoke_token_command(Owner) -> ResTuple when
- Owner :: binary(),
- ResCode :: ok | not_found | error,
- ResTuple :: {ResCode, string()}.
-revoke_token_command(Owner) ->
- JID = jid:from_binary(Owner),
- case mod_auth_token_api:revoke_token_command(JID) of
- {ok, _} = Result -> Result;
- Error -> Error
- end.
-
-spec clean_tokens(Acc, Params, Extra) -> {ok, Acc} when
Acc :: mongoose_acc:t(),
Params :: #{jid := jid:jid()},
diff --git a/src/mod_private_api.erl b/src/mod_private_api.erl
index d78676455ba..a260966eeaf 100644
--- a/src/mod_private_api.erl
+++ b/src/mod_private_api.erl
@@ -2,7 +2,6 @@
-module(mod_private_api).
-include("mongoose.hrl").
--include("ejabberd_commands.hrl").
-include("jlib.hrl").
-include_lib("exml/include/exml.hrl").
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index 8fb34453013..965bf19cae9 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -48,11 +48,9 @@
process_iq/5,
get_roster_entry/4,
item_to_map/1,
- set_items/3,
set_roster_entry/5,
remove_from_roster/3,
- item_to_xml/1,
- broadcast_item/3
+ item_to_xml/1
]).
% Hook handlers
@@ -68,7 +66,8 @@
get_personal_data/3
]).
--export([transaction/2,
+-export([set_items/3,
+ transaction/2,
process_subscription_t/6,
get_user_rosters_length/2]). % for testing
@@ -77,7 +76,9 @@
-ignore_xref([get_user_rosters_length/2,
item_to_xml/1,
process_subscription_t/6,
- transaction/2]).
+ set_items/3,
+ transaction/2
+ ]).
-include("mongoose.hrl").
-include("jlib.hrl").
diff --git a/src/mongoose_account_api.erl b/src/mongoose_account_api.erl
index ec36e2df17f..2af5ac49b57 100644
--- a/src/mongoose_account_api.erl
+++ b/src/mongoose_account_api.erl
@@ -8,15 +8,11 @@
unregister_user/1,
unregister_user/2,
ban_account/2,
- ban_account/3,
change_password/2,
change_password/3,
check_account/1,
- check_account/2,
check_password/2,
- check_password/3,
check_password_hash/3,
- check_password_hash/4,
import_users/1]).
-type register_result() :: {ok | exists | invalid_jid | cannot_register |
@@ -126,11 +122,6 @@ change_password(JID, Password) ->
Result = ejabberd_auth:set_password(JID, Password),
format_change_password(Result).
--spec check_account(jid:user(), jid:server()) -> check_account_result().
-check_account(User, Host) ->
- JID = jid:make_bare(User, Host),
- check_account(JID).
-
-spec check_account(jid:jid()) -> check_account_result().
check_account(JID) ->
case ejabberd_auth:does_user_exist(JID) of
@@ -140,11 +131,6 @@ check_account(JID) ->
{user_does_not_exist, io_lib:format("User ~s does not exist", [jid:to_binary(JID)])}
end.
--spec check_password(jid:user(), jid:server(), binary()) -> check_password_result().
-check_password(User, Host, Password) ->
- JID = jid:make_bare(User, Host),
- check_password(JID, Password).
-
-spec check_password(jid:jid(), binary()) -> check_password_result().
check_password(JID, Password) ->
case ejabberd_auth:does_user_exist(JID) of
@@ -163,12 +149,6 @@ check_password(JID, Password) ->
" exist", [Password, jid:to_binary(JID)])}
end.
--spec check_password_hash(jid:user(), jid:server(), string(), string()) ->
- check_password_hash_result().
-check_password_hash(User, Host, PasswordHash, HashMethod) ->
- JID = jid:make_bare(User, Host),
- check_password_hash(JID, PasswordHash, HashMethod).
-
-spec check_password_hash(jid:jid(), string(), string()) -> check_password_hash_result().
check_password_hash(JID, PasswordHash, HashMethod) ->
AccountPass = ejabberd_auth:get_password_s(JID),
@@ -214,11 +194,6 @@ from_reason(invalid_jid) -> <<"invalidJID">>;
from_reason(null_password) -> <<"emptyPassword">>;
from_reason(bad_csv) -> <<"invalidRecord">>.
--spec ban_account(jid:user(), jid:server(), binary()) -> change_password_result().
-ban_account(User, Host, ReasonText) ->
- JID = jid:make_bare(User, Host),
- ban_account(JID, ReasonText).
-
-spec ban_account(jid:jid(), binary()) -> change_password_result().
ban_account(JID, Reason) ->
case ejabberd_auth:does_user_exist(JID) of
diff --git a/src/mongoose_bin.erl b/src/mongoose_bin.erl
index db832e55659..984d1f0713b 100644
--- a/src/mongoose_bin.erl
+++ b/src/mongoose_bin.erl
@@ -12,8 +12,7 @@
join/2,
encode_crypto/1,
gen_from_crypto/0,
- gen_from_timestamp/0,
- string_to_binary/1]).
+ gen_from_timestamp/0]).
%% ---------------------------------------------------
%% API
@@ -47,20 +46,6 @@ gen_from_timestamp() ->
-spec encode_crypto(iodata()) -> binary().
encode_crypto(Text) -> base16:encode(crypto:hash(sha, Text)).
--spec string_to_binary(binary() | list()) -> binary().
-string_to_binary(S) when is_list(S) ->
- % If list is in Erlang representation of Unicode, we must use `unicode` module
- % If it's not or is already converted, we must use list_to_binary
- % since input can be from `file:consult/1` and prior to 17.0
- % this function returned bytes in a list instead of proper unicode string
- % so it is already like after a call to `unicode`.
- case lists:any(fun(C) -> C > 255 end, S) of
- true -> unicode:characters_to_binary(S);
- false -> list_to_binary(S)
- end;
-string_to_binary(B) when is_binary(B) ->
- B.
-
%% ---------------------------------------------------
%% Internal functions
%% ---------------------------------------------------
diff --git a/src/mongoose_cluster.erl b/src/mongoose_cluster.erl
index 79e31d343e0..ead93c4b6c2 100644
--- a/src/mongoose_cluster.erl
+++ b/src/mongoose_cluster.erl
@@ -2,8 +2,6 @@
%% This is a library module for cluster management: joining / leaving a cluster.
-%% TODO: it might make sense to expose this stuff as service_admin_extra_cluster
-
-export([join/1, leave/0, remove_from_cluster/1, is_node_alive/1]).
-export([all_cluster_nodes/0, other_cluster_nodes/0]).
diff --git a/src/mongoose_server_api.erl b/src/mongoose_server_api.erl
index 1d9e1e79183..390ccac5b81 100644
--- a/src/mongoose_server_api.erl
+++ b/src/mongoose_server_api.erl
@@ -1,20 +1,9 @@
-module(mongoose_server_api).
--export([get_loglevel_mongooseimctl/0]).
-
-export([status/0, get_cookie/0, join_cluster/1, leave_cluster/0,
remove_from_cluster/1, stop/0, restart/0, remove_node/1, set_loglevel/1,
get_loglevel/0]).
--ignore_xref([get_loglevel_mongooseimctl/0]).
-
--spec get_loglevel_mongooseimctl() -> {ok, iolist()}.
-get_loglevel_mongooseimctl() ->
- Level = mongoose_logs:get_global_loglevel(),
- Number = mongoose_logs:loglevel_keyword_to_number(Level),
- String = io_lib:format("global loglevel is ~p, which means '~p'", [Number, Level]),
- {ok, String}.
-
-spec get_loglevel() -> {ok, mongoose_logs:atom_log_level()}.
get_loglevel() ->
{ok, mongoose_logs:get_global_loglevel()}.
diff --git a/src/s2s/mongoose_s2s_lib.erl b/src/s2s/mongoose_s2s_lib.erl
index e1df46831e9..74f5a4f5c34 100644
--- a/src/s2s/mongoose_s2s_lib.erl
+++ b/src/s2s/mongoose_s2s_lib.erl
@@ -13,12 +13,10 @@
choose_pid/2,
need_more_connections/2,
needed_extra_connections_number_if_allowed/2,
- allow_host/1,
- commands/0]).
+ allow_host/1]).
-include("mongoose.hrl").
-include("jlib.hrl").
--include("ejabberd_commands.hrl").
-type fromto() :: ejabberd_s2s:fromto().
-type s2s_pids() :: ejabberd_s2s:s2s_pids().
@@ -198,20 +196,3 @@ parent_domains(<<$., Rest/binary>>, Acc) ->
parent_domains(Rest, [Rest | Acc]);
parent_domains(<<_, Rest/binary>>, Acc) ->
parent_domains(Rest, Acc).
-
--spec commands() -> [ejabberd_commands:cmd()].
-commands() ->
- [
- #ejabberd_commands{name = incoming_s2s_number,
- tags = [stats, s2s],
- desc = "Number of incoming s2s connections on the node",
- module = stats_api, function = incoming_s2s_number,
- args = [],
- result = {s2s_incoming, integer}},
- #ejabberd_commands{name = outgoing_s2s_number,
- tags = [stats, s2s],
- desc = "Number of outgoing s2s connections on the node",
- module = stats_api, function = outgoing_s2s_number,
- args = [],
- result = {s2s_outgoing, integer}}
- ].
diff --git a/src/stats_api.erl b/src/stats_api.erl
index 9881e2ecc12..495a85796ab 100644
--- a/src/stats_api.erl
+++ b/src/stats_api.erl
@@ -1,9 +1,6 @@
-module(stats_api).
-export([incoming_s2s_number/0, outgoing_s2s_number/0, stats/1, stats/2]).
--export([stats_mongooseimctl/1, stats_mongooseimctl/2]).
-
--ignore_xref([stats_mongooseimctl/1, stats_mongooseimctl/2]).
-include("mongoose.hrl").
@@ -36,17 +33,3 @@ stats(<<"onlineusers">>, Host) ->
{ok, ejabberd_sm:get_vh_session_number(Host)};
stats(_Name, _Host) ->
{not_found, "Stats not found"}.
-
--spec stats_mongooseimctl(binary()) -> {ok | not_found, string()}.
-stats_mongooseimctl(Name) ->
- case stats(Name) of
- {ok, Stat} -> {ok, integer_to_list(Stat)};
- Error -> Error
- end.
-
--spec stats_mongooseimctl(binary(), binary()) -> {ok | not_found, string()}.
-stats_mongooseimctl(Name, Host) ->
- case stats(Name, Host) of
- {ok, Stat} -> {ok, integer_to_list(Stat)};
- Error -> Error
- end.
diff --git a/test/acc_SUITE.erl b/test/acc_SUITE.erl
index 7449cdc933f..255e5721bfa 100644
--- a/test/acc_SUITE.erl
+++ b/test/acc_SUITE.erl
@@ -4,7 +4,6 @@
-include_lib("exml/include/exml.hrl").
-include_lib("eunit/include/eunit.hrl").
--include("ejabberd_commands.hrl").
-include("jlib.hrl").
-include("mongoose.hrl").
diff --git a/test/auth_tokens_SUITE.erl b/test/auth_tokens_SUITE.erl
index 15c0d03af61..98ba07a62aa 100644
--- a/test/auth_tokens_SUITE.erl
+++ b/test/auth_tokens_SUITE.erl
@@ -65,7 +65,6 @@ init_per_testcase(validity_period_test, Config) ->
mock_rdbms_backend(),
mock_mongoose_metrics(),
mock_gen_iq_handler(),
- mock_ejabberd_commands(),
async_helper:start(Config, [{mongooseim_helper, start_link_loaded_hooks, []}]);
init_per_testcase(revoked_token_is_not_valid, Config) ->
@@ -91,7 +90,6 @@ end_per_testcase(validity_period_test, C) ->
meck:unload(mod_auth_token_backend),
meck:unload(mongoose_metrics),
meck:unload(gen_iq_handler),
- meck:unload(ejabberd_commands),
async_helper:stop_all(C),
C;
@@ -254,10 +252,6 @@ mock_tested_backend() ->
receive {valid_seq_no, SeqNo} -> SeqNo end
end).
-mock_ejabberd_commands() ->
- meck:new(ejabberd_commands, []),
- meck:expect(ejabberd_commands, register_commands, fun (_) -> ok end).
-
provision_token_example() ->
{token,provision,
{{2055,10,27},{10,54,22}},
diff --git a/test/common/config_parser_helper.erl b/test/common/config_parser_helper.erl
index bf4a2eacd75..5311da27d49 100644
--- a/test/common/config_parser_helper.erl
+++ b/test/common/config_parser_helper.erl
@@ -18,7 +18,6 @@ options("host_types") ->
{language, <<"en">>},
{listen, []},
{loglevel, warning},
- {mongooseimctl_access_commands, #{}},
{outgoing_pools, []},
{rdbms_server_type, generic},
{registration_timeout, 600},
@@ -80,9 +79,6 @@ options("miscellaneous") ->
transport => #{num_acceptors => 10, max_connections => 1024}
})]},
{loglevel, warning},
- {mongooseimctl_access_commands,
- #{local => #{commands => [join_cluster],
- argument_restrictions => #{node => "mongooseim@prime"}}}},
{outgoing_pools, []},
{rdbms_server_type, mssql},
{registration_timeout, 600},
@@ -119,7 +115,6 @@ options("modules") ->
{language, <<"en">>},
{listen, []},
{loglevel, warning},
- {mongooseimctl_access_commands, #{}},
{outgoing_pools, []},
{rdbms_server_type, generic},
{registration_timeout, 600},
@@ -240,7 +235,6 @@ options("mongooseim-pgsql") ->
]},
{loglevel, warning},
{max_fsm_queue, 1000},
- {mongooseimctl_access_commands, #{}},
{outgoing_pools,
lists:map(
fun pool_config/1,
@@ -260,10 +254,7 @@ options("mongooseim-pgsql") ->
{registration_timeout, infinity},
{routing_modules, mongoose_router:default_routing_modules()},
{services,
- #{service_admin_extra =>
- #{submods => [node, accounts, sessions, vcard, gdpr, upload,
- roster, last, private, stanza, stats]},
- service_mongoose_system_metrics =>
+ #{service_mongoose_system_metrics =>
#{initial_report => 300000,
periodic_report => 10800000}}},
{sm_backend, mnesia},
@@ -322,7 +313,6 @@ options("outgoing_pools") ->
{language, <<"en">>},
{listen, []},
{loglevel, warning},
- {mongooseimctl_access_commands, #{}},
{outgoing_pools,
lists:map(
fun pool_config/1,
@@ -386,7 +376,6 @@ options("s2s_only") ->
{language, <<"en">>},
{listen, []},
{loglevel, warning},
- {mongooseimctl_access_commands, #{}},
{outgoing_pools, []},
{rdbms_server_type, generic},
{registration_timeout, 600},
@@ -1071,8 +1060,6 @@ extra_service_listener_config() ->
conflict_behaviour => disconnect,
connection_type => component}.
-default_config([general, mongooseimctl_access_commands, _Key]) ->
- #{commands => all, argument_restrictions => #{}};
default_config([listen, http]) ->
(common_listener_config())#{module => ejabberd_cowboy,
transport => default_config([listen, http, transport]),
@@ -1258,9 +1245,6 @@ default_config([outgoing_pools, _Type, _Tag, conn_opts, tls] = P) ->
server_name_indication => default_config(P ++ [server_name_indication])};
default_config([outgoing_pools, _Type, _Tag, conn_opts, tls, server_name_indication]) ->
#{enabled => true, protocol => default};
-default_config([services, service_admin_extra]) ->
- #{submods => [node, accounts, sessions, vcard, roster, last,
- private, stanza, stats, gdpr, upload, domain]};
default_config([services, service_domain_db]) ->
#{event_cleaning_interval => 1800,
event_max_age => 7200,
diff --git a/test/config_parser_SUITE.erl b/test/config_parser_SUITE.erl
index 9b6935c543f..74240f8a5cd 100644
--- a/test/config_parser_SUITE.erl
+++ b/test/config_parser_SUITE.erl
@@ -81,7 +81,6 @@ groups() ->
http_server_name,
rdbms_server_type,
route_subdomains,
- mongooseimctl_access_commands,
routing_modules,
replaced_wait_timeout,
hide_service_name,
@@ -230,8 +229,7 @@ groups() ->
mod_version,
modules_without_config,
incorrect_module]},
- {services, [parallel], [service_admin_extra,
- service_domain_db,
+ {services, [parallel], [service_domain_db,
service_mongoose_system_metrics]}
].
@@ -417,19 +415,6 @@ route_subdomains(_Config) ->
?cfgh(route_subdomains, s2s, #{<<"general">> => #{<<"route_subdomains">> => <<"s2s">>}}),
?errh(#{<<"general">> => #{<<"route_subdomains">> => <<"c2s">>}}).
-mongooseimctl_access_commands(_Config) ->
- ?cfg(mongooseimctl_access_commands, #{}, #{}), % default
- P = [mongooseimctl_access_commands, local],
- T = fun(Opts) ->
- #{<<"general">> => #{<<"mongooseimctl_access_commands">> => #{<<"local">> => Opts}}}
- end,
- ?cfg(P, default_config([general, mongooseimctl_access_commands, local]), T(#{})),
- ?cfg(P ++ [commands], [join_cluster], T(#{<<"commands">> => [<<"join_cluster">>]})),
- ?cfg(P ++ [argument_restrictions], #{node => "mim1@host1"},
- T(#{<<"argument_restrictions">> => #{<<"node">> => <<"mim1@host1">>}})),
- ?err(T(#{<<"commands">> => [<<>>]})),
- ?err(T(#{<<"argument_restrictions">> => #{<<"node">> => 1}})).
-
routing_modules(_Config) ->
?cfg(routing_modules, mongoose_router:default_routing_modules(), #{}), % default
?cfg(routing_modules,
@@ -2857,15 +2842,6 @@ incorrect_module(_Config) ->
%% Services
-service_admin_extra(_Config) ->
- P = [services, service_admin_extra],
- T = fun(Opts) -> #{<<"services">> => #{<<"service_admin_extra">> => Opts}} end,
- ?cfg(P, default_config(P), T(#{})),
- ?cfg(P ++ [submods], [node], T(#{<<"submods">> => [<<"node">>]})),
- ?err(T(#{<<"submods">> => 1})),
- ?err(T(#{<<"submods">> => [1]})),
- ?err(T(#{<<"submods">> => [<<"nodejshaha">>]})).
-
service_domain_db(_Config) ->
P = [services, service_domain_db],
T = fun(Opts) -> #{<<"services">> => #{<<"service_domain_db">> => Opts}} end,
diff --git a/test/config_parser_SUITE_data/miscellaneous.toml b/test/config_parser_SUITE_data/miscellaneous.toml
index e423e6b2d27..6ff3da56a3b 100644
--- a/test/config_parser_SUITE_data/miscellaneous.toml
+++ b/test/config_parser_SUITE_data/miscellaneous.toml
@@ -14,10 +14,6 @@
replaced_wait_timeout = 2000
hide_service_name = true
- [general.mongooseimctl_access_commands.local]
- commands = ["join_cluster"]
- argument_restrictions.node = "mongooseim@prime"
-
[[general.domain_certfile]]
domain = "example.com"
certfile = "priv/cert.pem"
diff --git a/test/config_parser_SUITE_data/mongooseim-pgsql.toml b/test/config_parser_SUITE_data/mongooseim-pgsql.toml
index 78b5f2e0ed1..b6bc8c6c9d1 100644
--- a/test/config_parser_SUITE_data/mongooseim-pgsql.toml
+++ b/test/config_parser_SUITE_data/mongooseim-pgsql.toml
@@ -148,10 +148,6 @@
tls.cacertfile = "priv/ca.pem"
tls.server_name_indication.enabled = false
-[services.service_admin_extra]
- submods = ["node", "accounts", "sessions", "vcard", "gdpr", "upload",
- "roster", "last", "private", "stanza", "stats"]
-
[services.service_mongoose_system_metrics]
initial_report = 300_000
periodic_report = 10_800_000
diff --git a/test/ejabberd_sm_SUITE.erl b/test/ejabberd_sm_SUITE.erl
index 38d4a72caf4..f8f38866074 100644
--- a/test/ejabberd_sm_SUITE.erl
+++ b/test/ejabberd_sm_SUITE.erl
@@ -400,7 +400,6 @@ unique_count_while_removing_entries(C) ->
unload_meck() ->
meck:unload(acl),
meck:unload(gen_hook),
- meck:unload(ejabberd_commands),
meck:unload(mongoose_domain_api),
catch ets:delete(test_c2s_info),
catch meck:unload(mongoose_c2s).
@@ -647,7 +646,4 @@ sm_backend(ejabberd_sm_cets) -> cets.
set_meck() ->
meck:expect(gen_hook, add_handler, fun(_, _, _, _, _) -> ok end),
meck:expect(gen_hook, add_handlers, fun(_) -> ok end),
- meck:new(ejabberd_commands, []),
- meck:expect(ejabberd_commands, register_commands, fun(_) -> ok end),
- meck:expect(ejabberd_commands, unregister_commands, fun(_) -> ok end),
ok.
diff --git a/test/mongoose_cleanup_SUITE.erl b/test/mongoose_cleanup_SUITE.erl
index f41a3e83548..72822d01a1f 100644
--- a/test/mongoose_cleanup_SUITE.erl
+++ b/test/mongoose_cleanup_SUITE.erl
@@ -125,7 +125,7 @@ opts() ->
{modules, ?HOST} => #{}}.
meck_mods(bosh) -> [exometer, mod_bosh_socket];
-meck_mods(s2s) -> [exometer, ejabberd_commands, mongoose_bin];
+meck_mods(s2s) -> [exometer, mongoose_bin];
meck_mods(component) -> [exometer];
meck_mods(_) -> [exometer, ejabberd_sm, ejabberd_local].
@@ -298,10 +298,6 @@ setup_meck([ejabberd_local | R]) ->
meck:expect(ejabberd_local, register_iq_handler,
fun(_A1, _A2, _A3) -> ok end),
setup_meck(R);
-setup_meck([ejabberd_commands | R]) ->
- meck:new(ejabberd_commands),
- meck:expect(ejabberd_commands, register_commands, fun(_) -> ok end),
- setup_meck(R);
setup_meck([mongoose_bin | R]) ->
meck:new(mongoose_bin, [passthrough]),
meck:expect(mongoose_bin, gen_from_crypto, fun() -> <<"123456">> end),
diff --git a/test/mongoose_config_SUITE.erl b/test/mongoose_config_SUITE.erl
index 50ebd37e482..c2783954df7 100644
--- a/test/mongoose_config_SUITE.erl
+++ b/test/mongoose_config_SUITE.erl
@@ -175,7 +175,6 @@ minimal_config_opts() ->
language => <<"en">>,
listen => [],
loglevel => warning,
- mongooseimctl_access_commands => #{},
outgoing_pools => [],
rdbms_server_type => generic,
registration_timeout => 600,
diff --git a/tools/pkg/scripts/smoke_test.sh b/tools/pkg/scripts/smoke_test.sh
index d073dc5354c..fba996dc022 100755
--- a/tools/pkg/scripts/smoke_test.sh
+++ b/tools/pkg/scripts/smoke_test.sh
@@ -67,14 +67,15 @@ echo "Checking status via 'mongooseimctl status'"
mongooseimctl status
echo "Trying to register a user with 'mongooseimctl register localhost a_password'"
-mongooseimctl register localhost a_password
+mongooseimctl account registerUser --domain localhost --password a_password
echo "Trying to register a user with 'mongooseimctl register_identified user localhost a_password_2'"
-mongooseimctl register_identified user localhost a_password_2
+mongooseimctl account registerUser --username user --domain localhost --password a_password_2
echo "Checking if 2 users are registered on host 'localhost'"
expected=2
-registered=$(mongooseimctl registered_users localhost | wc -l)
+registered=$(_build/mim1/rel/mongooseim/bin/mongooseimctl account countUsers \
+ --domain localhost | grep -o '"countUsers" : [0-9]*' | awk '{print $3}')
if [ ${registered} -ne ${expected} ]; then
echo "registered value is ${registered} but expected ${expected}"
exit 1