diff options
42 files changed, 367 insertions, 178 deletions
diff --git a/Makefile.in b/Makefile.in index 0d913448..b08eb444 100644 --- a/Makefile.in +++ b/Makefile.in @@ -185,6 +185,7 @@ install: all copy-files -e "s*{{localstatedir}}*@localstatedir@*" \ -e "s*{{docdir}}*@docdir@*" \ -e "s*{{erl}}*@ERL@*" ejabberdctl.template \ + -e "s*{{epmd}}*@EPMD@*" ejabberdctl.template \ > ejabberdctl.example [ -f $(ETCDIR)/ejabberdctl.cfg ] \ && $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \ diff --git a/configure.ac b/configure.ac index e5d92c89..f3ff9ae5 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,7 @@ fi AC_PATH_TOOL(ERL, erl, , [${extra_erl_path}$PATH]) AC_PATH_TOOL(ERLC, erlc, , [${extra_erl_path}$PATH]) +AC_PATH_TOOL(EPMD, epmd, , [${extra_erl_path}$PATH]) AC_ERLANG_NEED_ERL AC_ERLANG_NEED_ERLC diff --git a/ejabberdctl.template b/ejabberdctl.template index 224650fe..7a3b589b 100755 --- a/ejabberdctl.template +++ b/ejabberdctl.template @@ -13,7 +13,7 @@ ERLANG_NODE=ejabberd@localhost SCRIPT_DIR=`cd ${0%/*} && pwd` ERL={{erl}} IEX={{bindir}}/iex -EPMD={{bindir}}/epmd +EPMD={{epmd}} INSTALLUSER={{installuser}} ERL_LIBS={{libdir}} @@ -83,18 +83,9 @@ if [ "$EJABBERD_DOC_PATH" = "" ] ; then fi if [ "$ERLANG_NODE_ARG" != "" ] ; then ERLANG_NODE=$ERLANG_NODE_ARG - NODE=${ERLANG_NODE%@*} fi -if [ "{{release}}" != "true" ] ; then - if [ "$EJABBERDDIR" = "" ] ; then - EJABBERDDIR={{libdir}}/ejabberd - fi - if [ "$EJABBERD_PRIV_PATH" = "" ] ; then - EJABBERD_PRIV_PATH=$EJABBERDDIR/priv - fi - if [ "$EJABBERD_BIN_PATH" = "" ] ; then - EJABBERD_BIN_PATH=$EJABBERD_PRIV_PATH/bin - fi +if [ "{{release}}" != "true" -a "$EJABBERD_BIN_PATH" = "" ] ; then + EJABBERD_BIN_PATH={{libdir}}/ejabberd/priv/bin fi EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log DATETIME=`date "+%Y%m%d-%H%M%S"` @@ -141,8 +132,8 @@ fi [ -z "$date" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_date '$date'" [ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd ${EJABBERD_OPTS}" -[ -d $SPOOL_DIR ] || $EXEC_CMD "mkdir -p $SPOOL_DIR" -cd $SPOOL_DIR +[ -d "$SPOOL_DIR" ] || $EXEC_CMD "mkdir -p $SPOOL_DIR" +cd "$SPOOL_DIR" # export global variables export EJABBERD_CONFIG_PATH @@ -221,7 +212,7 @@ iexdebug() --erl `shell_escape \"$ERLANG_OPTS\"` \ --erl `shell_escape \"${ARGS[@]}\"` \ --erl `shell_escape_str \"$@\"`" - $EXEC_CMD "$CMD" + $EXEC_CMD "ERL_PATH=$\"$ERL\" $CMD" } # start interactive server @@ -251,7 +242,7 @@ iexlive() --erl `shell_escape \"$ERLANG_OPTS\"` \ --erl `shell_escape \"${ARGS[@]}\"` \ --erl `shell_escape_str \"$@\"`" - $EXEC_CMD "$CMD" + $EXEC_CMD "ERL_PATH=\"$ERL\" $CMD" } # start server in the foreground @@ -396,13 +387,13 @@ uid() # stop epmd if there is no other running node stop_epmd() { - $EPMD -names 2>/dev/null | grep -q name || $EPMD -kill >/dev/null + "$EPMD" -names 2>/dev/null | grep -q name || "$EPMD" -kill >/dev/null } # make sure node not already running and node name unregistered check_start() { - $EPMD -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && { + "$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && { ps ux | grep -v grep | grep -q " $ERLANG_NODE " && { echo "ERROR: The ejabberd node '$ERLANG_NODE' is already running." exit 4 @@ -413,7 +404,7 @@ check_start() echo "Shutdown all other erlang nodes, and call 'epmd -kill'." exit 5 } || { - $EPMD -kill >/dev/null + "$EPMD" -kill >/dev/null } } } @@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do def project do [app: :ejabberd, - version: "16.03.0", + version: "16.04.0", description: description, elixir: "~> 1.2", elixirc_paths: ["lib"], @@ -3,10 +3,10 @@ "cf": {:hex, :cf, "0.2.1"}, "eredis": {:hex, :eredis, "1.0.8"}, "erlware_commons": {:hex, :erlware_commons, "0.19.0"}, - "esip": {:hex, :esip, "1.0.2"}, + "esip": {:hex, :esip, "1.0.4"}, "exrm": {:hex, :exrm, "1.0.3"}, "ezlib": {:hex, :ezlib, "1.0.1"}, - "fast_tls": {:hex, :fast_tls, "1.0.1"}, + "fast_tls": {:hex, :fast_tls, "1.0.3"}, "fast_xml": {:hex, :fast_xml, "1.1.11"}, "fast_yaml": {:hex, :fast_yaml, "1.0.3"}, "getopt": {:hex, :getopt, "0.8.2"}, @@ -20,7 +20,7 @@ "p1_utils": {:hex, :p1_utils, "1.0.3"}, "p1_xmlrpc": {:hex, :p1_xmlrpc, "1.15.1"}, "providers": {:hex, :providers, "1.6.0"}, - "relx": {:hex, :relx, "3.18.0"}, + "relx": {:hex, :relx, "3.19.0"}, "sqlite3": {:hex, :sqlite3, "1.1.5"}, "stringprep": {:hex, :stringprep, "1.0.3"}, - "stun": {:hex, :stun, "1.0.1"}} + "stun": {:hex, :stun, "1.0.3"}} diff --git a/rebar.config b/rebar.config index d006dc64..dfce7075 100644 --- a/rebar.config +++ b/rebar.config @@ -10,11 +10,11 @@ {deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.0.2"}}}, {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.4"}}}, {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.2"}}}, - {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.1"}}}, + {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.3"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.3"}}}, {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.3"}}}, - {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.1"}}}, - {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.2"}}}, + {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.3"}}}, + {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.4"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.3"}}}, {jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.7"}}}, {p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.1"}}}, diff --git a/sql/mysql.sql b/sql/mysql.sql index b7a86d0e..5150fc45 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -275,7 +275,7 @@ CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt(subid(3 CREATE TABLE muc_room ( name text NOT NULL, host text NOT NULL, - opts text NOT NULL, + opts mediumtext NOT NULL, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 0267a219..6b7f537c 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -136,7 +136,7 @@ check_password(User, AuthzId, Server, Password, Digest, %% {true, AuthModule} | false %% where %% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external -%% | ejabberd_auth_internal | ejabberd_auth_ldap +%% | ejabberd_auth_mnesia | ejabberd_auth_ldap %% | ejabberd_auth_sql | ejabberd_auth_pam | ejabberd_auth_riak -spec check_password_with_authmodule(binary(), binary(), binary(), binary()) -> false | {true, atom()}. @@ -428,30 +428,21 @@ auth_modules() -> %% Return the list of authenticated modules for a given host auth_modules(Server) -> LServer = jid:nameprep(Server), - Default = case gen_mod:default_db(LServer) of - mnesia -> internal; - DBType -> DBType - end, + Default = ejabberd_config:default_db(LServer, ?MODULE), Methods = ejabberd_config:get_option( - {auth_method, LServer}, - fun(V) when is_list(V) -> - true = lists:all(fun is_atom/1, V), - V; - (V) when is_atom(V) -> - [V] - end, [Default]), + {auth_method, LServer}, opt_type(auth_method), [Default]), [jlib:binary_to_atom(<<"ejabberd_auth_", (jlib:atom_to_binary(M))/binary>>) || M <- Methods]. export(Server) -> - ejabberd_auth_internal:export(Server). + ejabberd_auth_mnesia:export(Server). import(Server) -> - ejabberd_auth_internal:import(Server). + ejabberd_auth_mnesia:import(Server). import(Server, mnesia, Passwd) -> - ejabberd_auth_internal:import(Server, mnesia, Passwd); + ejabberd_auth_mnesia:import(Server, mnesia, Passwd); import(Server, riak, Passwd) -> ejabberd_auth_riak:import(Server, riak, Passwd); import(_, _, _) -> @@ -459,7 +450,7 @@ import(_, _, _) -> opt_type(auth_method) -> fun (V) when is_list(V) -> - true = lists:all(fun is_atom/1, V), V; - (V) when is_atom(V) -> [V] + lists:map(fun(M) -> ejabberd_config:v_db(?MODULE, M) end, V); + (V) -> [ejabberd_config:v_db(?MODULE, V)] end; opt_type(_) -> [auth_method]. diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl index 5897fba5..ef7c9755 100644 --- a/src/ejabberd_auth_external.erl +++ b/src/ejabberd_auth_external.erl @@ -56,7 +56,7 @@ start(Host) -> "extauth"), extauth:start(Host, Cmd), check_cache_last_options(Host), - ejabberd_auth_internal:start(Host). + ejabberd_auth_mnesia:start(Host). check_cache_last_options(Server) -> case get_cache_option(Server) of @@ -94,7 +94,7 @@ check_password(User, AuthzId, Server, Password, _Digest, set_password(User, Server, Password) -> case extauth:set_password(User, Server, Password) of true -> - set_password_internal(User, Server, Password), ok; + set_password_mnesia(User, Server, Password), ok; _ -> {error, unknown_problem} end. @@ -106,20 +106,20 @@ try_register(User, Server, Password) -> end. dirty_get_registered_users() -> - ejabberd_auth_internal:dirty_get_registered_users(). + ejabberd_auth_mnesia:dirty_get_registered_users(). get_vh_registered_users(Server) -> - ejabberd_auth_internal:get_vh_registered_users(Server). + ejabberd_auth_mnesia:get_vh_registered_users(Server). get_vh_registered_users(Server, Data) -> - ejabberd_auth_internal:get_vh_registered_users(Server, + ejabberd_auth_mnesia:get_vh_registered_users(Server, Data). get_vh_registered_users_number(Server) -> - ejabberd_auth_internal:get_vh_registered_users_number(Server). + ejabberd_auth_mnesia:get_vh_registered_users_number(Server). get_vh_registered_users_number(Server, Data) -> - ejabberd_auth_internal:get_vh_registered_users_number(Server, + ejabberd_auth_mnesia:get_vh_registered_users_number(Server, Data). %% The password can only be returned if cache is enabled, cached info exists and is fresh enough. @@ -151,7 +151,7 @@ remove_user(User, Server) -> case get_cache_option(Server) of false -> false; {true, _CacheTime} -> - ejabberd_auth_internal:remove_user(User, Server) + ejabberd_auth_mnesia:remove_user(User, Server) end end. @@ -162,7 +162,7 @@ remove_user(User, Server, Password) -> case get_cache_option(Server) of false -> false; {true, _CacheTime} -> - ejabberd_auth_internal:remove_user(User, Server, + ejabberd_auth_mnesia:remove_user(User, Server, Password) end end. @@ -197,7 +197,7 @@ check_password_cache(User, AuthzId, Server, Password, CacheTime) -> case get_last_access(User, Server) of online -> - check_password_internal(User, AuthzId, Server, Password); + check_password_mnesia(User, AuthzId, Server, Password); never -> check_password_external_cache(User, AuthzId, Server, Password); mod_last_required -> @@ -210,7 +210,7 @@ check_password_cache(User, AuthzId, Server, Password, case is_fresh_enough(TimeStamp, CacheTime) of %% If no need to refresh, check password against Mnesia true -> - case check_password_internal(User, AuthzId, Server, Password) of + case check_password_mnesia(User, AuthzId, Server, Password) of %% If password valid in Mnesia, accept it true -> true; %% Else (password nonvalid in Mnesia), check in extauth and cache result @@ -223,13 +223,13 @@ check_password_cache(User, AuthzId, Server, Password, end end. -get_password_internal(User, Server) -> - ejabberd_auth_internal:get_password(User, Server). +get_password_mnesia(User, Server) -> + ejabberd_auth_mnesia:get_password(User, Server). -spec get_password_cache(User::binary(), Server::binary(), CacheTime::integer()) -> Password::string() | false. get_password_cache(User, Server, CacheTime) -> case get_last_access(User, Server) of - online -> get_password_internal(User, Server); + online -> get_password_mnesia(User, Server); never -> false; mod_last_required -> ?ERROR_MSG("extauth is used, extauth_cache is enabled " @@ -239,7 +239,7 @@ get_password_cache(User, Server, CacheTime) -> false; TimeStamp -> case is_fresh_enough(TimeStamp, CacheTime) of - true -> get_password_internal(User, Server); + true -> get_password_mnesia(User, Server); false -> false end end. @@ -248,7 +248,7 @@ get_password_cache(User, Server, CacheTime) -> check_password_external_cache(User, AuthzId, Server, Password) -> case check_password_extauth(User, AuthzId, Server, Password) of true -> - set_password_internal(User, Server, Password), true; + set_password_mnesia(User, Server, Password), true; false -> false end. @@ -256,21 +256,21 @@ check_password_external_cache(User, AuthzId, Server, Password) -> try_register_external_cache(User, Server, Password) -> case try_register_extauth(User, Server, Password) of {atomic, ok} = R -> - set_password_internal(User, Server, Password), R; + set_password_mnesia(User, Server, Password), R; _ -> {error, not_allowed} end. %% @spec (User, AuthzId, Server, Password) -> true | false -check_password_internal(User, AuthzId, Server, Password) -> - ejabberd_auth_internal:check_password(User, AuthzId, Server, +check_password_mnesia(User, AuthzId, Server, Password) -> + ejabberd_auth_mnesia:check_password(User, AuthzId, Server, Password). %% @spec (User, Server, Password) -> ok | {error, invalid_jid} -set_password_internal(User, Server, Password) -> +set_password_mnesia(User, Server, Password) -> %% @spec (TimeLast, CacheTime) -> true | false %% TimeLast = online | never | integer() %% CacheTime = integer() | false - ejabberd_auth_internal:set_password(User, Server, + ejabberd_auth_mnesia:set_password(User, Server, Password). is_fresh_enough(TimeStampLast, CacheTime) -> diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_mnesia.erl index acbbfe50..9029404d 100644 --- a/src/ejabberd_auth_internal.erl +++ b/src/ejabberd_auth_mnesia.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------- -%%% File : ejabberd_auth_internal.erl +%%% File : ejabberd_auth_mnesia.erl %%% Author : Alexey Shchepin <alexey@process-one.net> %%% Purpose : Authentification via mnesia %%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net> @@ -23,7 +23,7 @@ %%% %%%---------------------------------------------------------------------- --module(ejabberd_auth_internal). +-module(ejabberd_auth_mnesia). -behaviour(ejabberd_config). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 948e2027..e75cb0ab 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1613,7 +1613,6 @@ handle_info({route, From, To, <<"error">> -> ok; <<"groupchat">> -> ok; <<"headline">> -> ok; - <<"result">> -> ok; _ -> Err = jlib:make_error_reply(Packet, diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index f73474fe..06de61b5 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -34,8 +34,8 @@ get_vh_by_auth_method/1, is_file_readable/1, get_version/0, get_myhosts/0, get_mylang/0, prepare_opt_val/4, convert_table_to_binary/5, - transform_options/1, collect_options/1, - convert_to_yaml/1, convert_to_yaml/2, + transform_options/1, collect_options/1, default_db/2, + convert_to_yaml/1, convert_to_yaml/2, v_db/2, env_binary_to_list/2, opt_type/1, may_hide_data/1]). -export([start/2]). @@ -227,6 +227,7 @@ get_plain_terms_file(File, Opts) when is_binary(File) -> get_plain_terms_file(binary_to_list(File), Opts); get_plain_terms_file(File1, Opts) -> File = get_absolute_path(File1), + DontStopOnError = lists:member(dont_halt_on_error, Opts), case consult(File) of {ok, Terms} -> BinTerms1 = strings_to_binary(Terms), @@ -246,9 +247,21 @@ get_plain_terms_file(File1, Opts) -> false -> BinTerms end; - {error, Reason} -> + {error, enoent, Reason} -> + case DontStopOnError of + true -> + ?WARNING_MSG(Reason, []), + []; + _ -> ?ERROR_MSG(Reason, []), exit_or_halt(Reason) + end; + {error, Reason} -> + ?ERROR_MSG(Reason, []), + case DontStopOnError of + true -> []; + _ -> exit_or_halt(Reason) + end end. consult(File) -> @@ -262,17 +275,29 @@ consult(File) -> {error, Err} -> Msg1 = "Cannot load " ++ File ++ ": ", Msg2 = fast_yaml:format_error(Err), + case Err of + enoent -> + {error, enoent, Msg1 ++ Msg2}; + _ -> {error, Msg1 ++ Msg2} + end end; _ -> case file:consult(File) of {ok, Terms} -> {ok, Terms}; + {error, enoent} -> + {error, enoent}; {error, {LineNumber, erl_parse, _ParseMessage} = Reason} -> {error, describe_config_problem(File, Reason, LineNumber)}; {error, Reason} -> + case Reason of + enoent -> + {error, enoent, describe_config_problem(File, Reason)}; + _ -> {error, describe_config_problem(File, Reason)} end + end end. parserl(<<"> ", Term/binary>>) -> @@ -488,7 +513,7 @@ transform_include_option({include_config_file, Filename, Options}) -> {Filename, Options}. include_config_file(Filename, Options) -> - Included_terms = get_plain_terms_file(Filename), + Included_terms = get_plain_terms_file(Filename, [{include_files, true}, dont_halt_on_error]), Disallow = proplists:get_value(disallow, Options, []), Included_terms2 = delete_disallowed(Disallow, Included_terms), Allow_only = proplists:get_value(allow_only, Options, all), @@ -651,9 +676,9 @@ process_host_term(Term, Host, State, Action) -> {hosts, _} -> State; {Opt, Val} when Action == set -> - set_option({rename_option(Opt), Host}, Val, State); + set_option({rename_option(Opt), Host}, change_val(Opt, Val), State); {Opt, Val} when Action == append -> - append_option({rename_option(Opt), Host}, Val, State); + append_option({rename_option(Opt), Host}, change_val(Opt, Val), State); Opt -> ?WARNING_MSG("Ignore invalid (outdated?) option ~p", [Opt]), State @@ -672,6 +697,21 @@ rename_option(Option) when is_atom(Option) -> rename_option(Option) -> Option. +change_val(auth_method, Val) -> + prepare_opt_val(auth_method, Val, + fun(V) -> + L = if is_list(V) -> V; + true -> [V] + end, + lists:map( + fun(odbc) -> sql; + (internal) -> mnesia; + (A) when is_atom(A) -> A + end, L) + end, [mnesia]); +change_val(_Opt, Val) -> + Val. + set_option(Opt, Val, State) -> State#state{opts = [#local_config{key = Opt, value = Val} | State#state.opts]}. @@ -738,13 +778,11 @@ prepare_opt_val(Opt, Val, F, Default) -> end, case Res of {'EXIT', _} -> - ?INFO_MSG("Configuration problem:~n" - "** Option: ~s~n" - "** Invalid value: ~s~n" - "** Using as fallback: ~s", - [format_term(Opt), - format_term(Val), - format_term(Default)]), + ?WARNING_MSG("incorrect value '~s' of option '~s', " + "using '~s' as fallback", + [format_term(Val), + format_term(Opt), + format_term(Default)]), Default; _ -> Res @@ -800,9 +838,57 @@ get_option(Opt, F, Default) -> end end. +init_module_db_table(Modules) -> + catch ets:new(module_db, [named_table, public, bag]), + %% Dirty hack for mod_pubsub + ets:insert(module_db, {mod_pubsub, mnesia}), + ets:insert(module_db, {mod_pubsub, sql}), + lists:foreach( + fun(M) -> + case re:split(atom_to_list(M), "_", [{return, list}]) of + [_] -> + ok; + Parts -> + [Suffix|T] = lists:reverse(Parts), + BareMod = string:join(lists:reverse(T), "_"), + ets:insert(module_db, {list_to_atom(BareMod), + list_to_atom(Suffix)}) + end + end, Modules). + +-spec v_db(module(), atom()) -> atom(). + +v_db(Mod, internal) -> v_db(Mod, mnesia); +v_db(Mod, odbc) -> v_db(Mod, sql); +v_db(Mod, Type) -> + case ets:match_object(module_db, {Mod, Type}) of + [_|_] -> Type; + [] -> erlang:error(badarg) + end. + +-spec default_db(binary(), module()) -> atom(). + +default_db(Host, Module) -> + case ejabberd_config:get_option( + {default_db, Host}, fun(T) when is_atom(T) -> T end) of + undefined -> + mnesia; + DBType -> + try + v_db(Module, DBType) + catch error:badarg -> + ?WARNING_MSG("Module '~s' doesn't support database '~s' " + "defined in option 'default_db', using " + "'mnesia' as fallback", [Module, DBType]), + mnesia + end + end. + get_modules_with_options() -> {ok, Mods} = application:get_key(ejabberd, modules), ExtMods = [Name || {Name, _Details} <- ext_mod:installed()], + AllMods = [?MODULE|ExtMods++Mods], + init_module_db_table(AllMods), lists:foldl( fun(Mod, D) -> case catch Mod:opt_type('') of @@ -814,7 +900,7 @@ get_modules_with_options() -> {'EXIT', {undef, _}} -> D end - end, dict:new(), [?MODULE|ExtMods++Mods]). + end, dict:new(), AllMods). validate_opts(#state{opts = Opts} = State) -> ModOpts = get_modules_with_options(), @@ -842,11 +928,25 @@ validate_opts(#state{opts = Opts} = State) -> -spec get_vh_by_auth_method(atom()) -> [binary()]. -%% Return the list of hosts handled by a given module +%% Return the list of hosts with a given auth method get_vh_by_auth_method(AuthMethod) -> - mnesia:dirty_select(local_config, - [{#local_config{key = {auth_method, '$1'}, - value=AuthMethod},[],['$1']}]). + Cfgs = mnesia:dirty_match_object(local_config, + #local_config{key = {auth_method, '_'}, + _ = '_'}), + lists:flatmap( + fun(#local_config{key = {auth_method, Host}, value = M}) -> + Methods = if not is_list(M) -> [M]; + true -> M + end, + case lists:member(AuthMethod, Methods) of + true when Host == global -> + get_myhosts(); + true -> + [Host]; + false -> + [] + end + end, Cfgs). %% @spec (Path::string()) -> true | false is_file_readable(Path) -> diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl index bb16e91e..d52d1c0a 100644 --- a/src/ejabberd_ctl.erl +++ b/src/ejabberd_ctl.erl @@ -239,7 +239,7 @@ process2(["--auth", User, Server, Pass | Args], AccessCommands, Version) -> process2(Args, AccessCommands, {list_to_binary(User), list_to_binary(Server), list_to_binary(Pass), true}, Version); process2(Args, AccessCommands, Version) -> - process2(Args, AccessCommands, admin, Version). + process2(Args, AccessCommands, noauth, Version). diff --git a/src/ejabberd_riak_sup.erl b/src/ejabberd_riak_sup.erl index af811441..ad65ecf8 100644 --- a/src/ejabberd_riak_sup.erl +++ b/src/ejabberd_riak_sup.erl @@ -70,8 +70,8 @@ is_riak_configured(Host) -> {modules, Host}, fun(L) when is_list(L) -> L end, []), ModuleWithRiakDBConfigured = lists:any( - fun({_Module, Opts}) -> - gen_mod:db_type(Host, Opts) == riak + fun({Module, Opts}) -> + gen_mod:db_type(Host, Opts, Module) == riak end, Modules), ServerConfigured or PortConfigured or AuthConfigured or ModuleWithRiakDBConfigured. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 219d46ad..25f6ea02 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -500,7 +500,7 @@ do_route(From, To, #xmlel{} = Packet) -> <<"headline">> -> route_message(From, To, Packet, headline); <<"error">> -> ok; <<"groupchat">> -> - ErrTxt = <<"Incorrect message type">>, + ErrTxt = <<"User session not found">>, Err = jlib:make_error_reply( Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)), ejabberd_router:route(To, From, Err); @@ -520,9 +520,10 @@ do_route(From, To, #xmlel{} = Packet) -> <<"chat">> -> route_message(From, To, Packet, chat); <<"normal">> -> route_message(From, To, Packet, normal); <<"">> -> route_message(From, To, Packet, normal); + <<"headline">> -> ok; <<"error">> -> ok; _ -> - ErrTxt = <<"Incorrect message type">>, + ErrTxt = <<"User session not found">>, Err = jlib:make_error_reply( Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, ErrTxt)), @@ -729,13 +730,10 @@ force_update_presence({LUser, LServer}) -> -spec get_sm_backend(binary()) -> module(). get_sm_backend(Host) -> - DBType = ejabberd_config:get_option({sm_db_type, Host}, - fun(mnesia) -> mnesia; - (internal) -> mnesia; - (odbc) -> sql; - (sql) -> sql; - (redis) -> redis - end, mnesia), + DBType = ejabberd_config:get_option( + {sm_db_type, Host}, + fun(T) -> ejabberd_config:v_db(?MODULE, T) end, + mnesia), list_to_atom("ejabberd_sm_" ++ atom_to_list(DBType)). -spec get_sm_backends() -> [module()]. @@ -808,11 +806,5 @@ kick_user(User, Server) -> make_sid() -> {p1_time_compat:unique_timestamp(), self()}. -opt_type(sm_db_type) -> - fun (mnesia) -> mnesia; - (internal) -> mnesia; - (sql) -> sql; - (odbc) -> sql; - (redis) -> redis - end; +opt_type(sm_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; opt_type(_) -> [sm_db_type]. diff --git a/src/ejd2sql.erl b/src/ejd2sql.erl index aa74286e..0457f6be 100644 --- a/src/ejd2sql.erl +++ b/src/ejd2sql.erl @@ -104,7 +104,7 @@ import_file(Server, FileName) -> LServer = jid:nameprep(Server), Mods = [{Mod, gen_mod:db_type(LServer, Mod)} || Mod <- modules(), gen_mod:is_loaded(LServer, Mod)], - AuthMods = case lists:member(ejabberd_auth_internal, + AuthMods = case lists:member(ejabberd_auth_mnesia, ejabberd_auth:auth_modules(LServer)) of true -> [{ejabberd_auth, mnesia}]; diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 26e662dc..f9639719 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -31,12 +31,12 @@ -export([start/0, start_module/2, start_module/3, stop_module/2, stop_module_keep_config/2, get_opt/3, - get_opt/4, get_opt_host/3, db_type/1, db_type/2, + get_opt/4, get_opt_host/3, db_type/2, db_type/3, get_module_opt/4, get_module_opt/5, get_module_opt_host/3, loaded_modules/1, loaded_modules_with_opts/1, get_hosts/2, get_module_proc/2, is_loaded/2, start_modules/0, start_modules/1, stop_modules/0, stop_modules/1, - default_db/1, v_db/1, opt_type/1, db_mod/2, db_mod/3]). + opt_type/1, db_mod/2, db_mod/3]). %%-export([behaviour_info/1]). @@ -52,6 +52,7 @@ -callback start(binary(), opts()) -> any(). -callback stop(binary()) -> any(). +-callback mod_opt_type(atom()) -> fun((term()) -> term()) | [atom()]. -export_type([opts/0]). -export_type([db_type/0]). @@ -295,44 +296,46 @@ validate_opts(Module, Opts) -> false end, Opts). --spec v_db(db_type() | internal) -> db_type(). - -v_db(odbc) -> sql; -v_db(sql) -> sql; -v_db(internal) -> mnesia; -v_db(mnesia) -> mnesia; -v_db(riak) -> riak. - --spec db_type(opts()) -> db_type(). - -db_type(Opts) -> - db_type(global, Opts). - --spec db_type(binary() | global, atom() | opts()) -> db_type(). +-spec db_type(binary() | global, module()) -> db_type(); + (opts(), module()) -> db_type(). +db_type(Opts, Module) when is_list(Opts) -> + db_type(global, Opts, Module); db_type(Host, Module) when is_atom(Module) -> - get_module_opt(Host, Module, db_type, fun v_db/1, default_db(Host)); -db_type(Host, Opts) when is_list(Opts) -> - get_opt(db_type, Opts, fun v_db/1, default_db(Host)). - --spec default_db(binary() | global) -> db_type(). + case catch Module:mod_opt_type(db_type) of + F when is_function(F) -> + case get_module_opt(Host, Module, db_type, F) of + undefined -> ejabberd_config:default_db(Host, Module); + Type -> Type + end; + _ -> + undefined + end. -default_db(Host) -> - ejabberd_config:get_option({default_db, Host}, fun v_db/1, mnesia). +-spec db_type(binary(), opts(), module()) -> db_type(). + +db_type(Host, Opts, Module) -> + case catch Module:mod_opt_type(db_type) of + F when is_function(F) -> + case get_opt(db_type, Opts, F) of + undefined -> ejabberd_config:default_db(Host, Module); + Type -> Type + end; + _ -> + undefined + end. -spec db_mod(binary() | global | db_type(), module()) -> module(). -db_mod(odbc, Module) -> list_to_atom(atom_to_list(Module) ++ "_sql"); -db_mod(sql, Module) -> list_to_atom(atom_to_list(Module) ++ "_sql"); -db_mod(mnesia, Module) -> list_to_atom(atom_to_list(Module) ++ "_mnesia"); -db_mod(riak, Module) -> list_to_atom(atom_to_list(Module) ++ "_riak"); +db_mod(Type, Module) when is_atom(Type) -> + list_to_atom(atom_to_list(Module) ++ "_" ++ atom_to_list(Type)); db_mod(Host, Module) when is_binary(Host) orelse Host == global -> db_mod(db_type(Host, Module), Module). -spec db_mod(binary() | global, opts(), module()) -> module(). db_mod(Host, Opts, Module) when is_list(Opts) -> - db_mod(db_type(Host, Opts), Module). + db_mod(db_type(Host, Opts, Module), Module). -spec loaded_modules(binary()) -> [atom()]. @@ -380,6 +383,6 @@ get_module_proc(Host, Base) -> is_loaded(Host, Module) -> ets:member(ejabberd_modules, {Module, Host}). -opt_type(default_db) -> fun v_db/1; +opt_type(default_db) -> fun(T) when is_atom(T) -> T end; opt_type(modules) -> fun (L) when is_list(L) -> L end; opt_type(_) -> [default_db, modules]. diff --git a/src/mod_announce.erl b/src/mod_announce.erl index d7251c50..9a9e665f 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -921,5 +921,5 @@ import(LServer, DBType, LA) -> mod_opt_type(access) -> fun (A) when is_atom(A) -> A end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [access, db_type]. diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 3d5c360a..966a9baa 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -651,6 +651,6 @@ mod_opt_type(cache_life_time) -> fun (I) when is_integer(I), I > 0 -> I end; mod_opt_type(cache_size) -> fun (I) when is_integer(I), I > 0 -> I end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [cache_life_time, cache_size, db_type]. diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index ebf1d0b0..bb20bd2f 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -279,8 +279,5 @@ list(User, Server) -> Mod:list(User, Server). mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; -mod_opt_type(db_type) -> - fun(internal) -> mnesia; - (mnesia) -> mnesia - end; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [db_type, iqdisc]. diff --git a/src/mod_irc.erl b/src/mod_irc.erl index e0c658de..f6487a1a 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -1253,7 +1253,7 @@ import(LServer, DBType, Data) -> mod_opt_type(access) -> fun (A) when is_atom(A) -> A end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(default_encoding) -> fun iolist_to_binary/1; mod_opt_type(host) -> fun iolist_to_binary/1; diff --git a/src/mod_last.erl b/src/mod_last.erl index 1af1847b..c39681f6 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -244,7 +244,7 @@ transform_options({node_start, {_, _, _} = Now}, Opts) -> transform_options(Opt, Opts) -> [Opt|Opts]. -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(_) -> [db_type, iqdisc]. diff --git a/src/mod_mam.erl b/src/mod_mam.erl index f84519a0..317fddfc 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -812,9 +812,9 @@ select(_LServer, JidRequestor, JidArchive, Start, End, _With, RSM, _ -> {Msgs, true, L} end; -select(LServer, From, From, Start, End, With, RSM, MsgType) -> +select(LServer, From, To, Start, End, With, RSM, MsgType) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:select(LServer, From, From, Start, End, With, RSM, MsgType). + Mod:select(LServer, From, To, Start, End, With, RSM, MsgType). msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer}, MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) -> @@ -1017,12 +1017,7 @@ mod_opt_type(cache_life_time) -> fun (I) when is_integer(I), I > 0 -> I end; mod_opt_type(cache_size) -> fun (I) when is_integer(I), I > 0 -> I end; -mod_opt_type(db_type) -> - fun(sql) -> sql; - (odbc) -> sql; - (internal) -> mnesia; - (mnesia) -> mnesia - end; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(default) -> fun (always) -> always; (never) -> never; diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl index c175fcb8..40484e48 100644 --- a/src/mod_metrics.erl +++ b/src/mod_metrics.erl @@ -39,7 +39,7 @@ s2s_send_packet, s2s_receive_packet, remove_user, register_user]). --export([start/2, stop/1, send_metrics/4, opt_type/1]). +-export([start/2, stop/1, send_metrics/4, opt_type/1, mod_opt_type/1]). -export([offline_message_hook/3, sm_register_connection_hook/3, sm_remove_connection_hook/3, @@ -126,3 +126,6 @@ send_metrics(Host, Probe, Peer, Port) -> opt_type(_) -> []. + +mod_opt_type(_) -> + []. diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 6aa18631..3d098e0d 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -932,7 +932,7 @@ mod_opt_type(access_create) -> fun (A) when is_atom(A) -> A end; mod_opt_type(access_persistent) -> fun (A) when is_atom(A) -> A end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(default_room_options) -> fun (L) when is_list(L) -> L end; mod_opt_type(history_size) -> diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 356d89a6..4d8aba76 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -867,7 +867,7 @@ import(LServer, DBType, Data) -> mod_opt_type(access_max_user_messages) -> fun (A) -> A end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(store_empty_body) -> fun (V) when is_boolean(V) -> V; (unless_chat_state) -> unless_chat_state diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 413dcb52..ad13c27c 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -593,6 +593,6 @@ import(LServer, DBType, Data) -> Mod = gen_mod:db_mod(DBType, ?MODULE), Mod:import(LServer, Data). -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(_) -> [db_type, iqdisc]. diff --git a/src/mod_private.erl b/src/mod_private.erl index 029789e6..38e42ca4 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -173,6 +173,6 @@ import(LServer, DBType, PD) -> Mod = gen_mod:db_mod(DBType, ?MODULE), Mod:import(LServer, PD). -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(_) -> [db_type, iqdisc]. diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index e42d5c05..35173a4f 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -254,10 +254,12 @@ init([ServerHost, Opts]) -> fun(A) when is_integer(A) andalso A >= 0 -> A end, ?MAXITEMS), MaxSubsNode = gen_mod:get_opt(max_subscriptions_node, Opts, fun(A) when is_integer(A) andalso A >= 0 -> A end, undefined), - DefaultNodeCfg = gen_mod:get_opt(default_node_config, Opts, - fun(A) when is_list(A) -> filter_node_options(A) end, []), pubsub_index:init(Host, ServerHost, Opts), {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts), + DefaultModule = plugin(Host, hd(Plugins)), + BaseOptions = DefaultModule:options(), + DefaultNodeCfg = gen_mod:get_opt(default_node_config, Opts, + fun(A) when is_list(A) -> filter_node_options(A, BaseOptions) end, []), mnesia:create_table(pubsub_last_item, [{ram_copies, [node()]}, {attributes, record_info(fields, pubsub_last_item)}]), @@ -2101,6 +2103,9 @@ subscribe_node(Host, Node, From, JID, Configuration) -> Type = TNode#pubsub_node.type, Options = TNode#pubsub_node.options, send_items(Host, Node, Nidx, Type, Options, Subscriber, last), + ServerHost = serverhost(Host), + ejabberd_hooks:run(pubsub_subscribe_node, ServerHost, + [ServerHost, Host, Node, Subscriber, SubId]), case Result of default -> {result, Reply({subscribed, SubId})}; _ -> {result, Result} @@ -2147,7 +2152,11 @@ unsubscribe_node(Host, Node, From, Subscriber, SubId) -> node_call(Host, Type, unsubscribe_node, [Nidx, From, Subscriber, SubId]) end, case transaction(Host, Node, Action, sync_dirty) of - {result, {_, default}} -> {result, []}; + {result, {_, default}} -> + ServerHost = serverhost(Host), + ejabberd_hooks:run(pubsub_unsubscribe_node, ServerHost, + [ServerHost, Host, Node, Subscriber, SubId]), + {result, []}; % {result, {_, Result}} -> {result, Result}; Error -> Error end. @@ -3163,11 +3172,9 @@ subscription_to_string(_) -> <<"none">>. Host :: mod_pubsub:host()) -> jid() ). -service_jid(Host) -> - case Host of - {U, S, _} -> {jid, U, S, <<>>, U, S, <<>>}; - _ -> {jid, <<>>, Host, <<>>, <<>>, Host, <<>>} - end. +service_jid(#jid{} = Jid) -> Jid; +service_jid({U, S, R}) -> jid:make(U, S, R); +service_jid(Host) -> jid:make(<<>>, Host, <<>>). %% @spec (LJID, NotifyType, Depth, NodeOptions, SubOptions) -> boolean() %% LJID = jid() @@ -3516,7 +3523,7 @@ broadcast_stanza(Host, _Node, _Nidx, _Type, NodeOptions, SubsByDepth, NotifyType end, SubIDsByJID). broadcast_stanza({LUser, LServer, LResource}, Publisher, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) -> - broadcast_stanza({LUser, LServer, LResource}, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM), + broadcast_stanza({LUser, LServer, <<>>}, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM), %% Handles implicit presence subscriptions SenderResource = user_resource(LUser, LServer, LResource), case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of @@ -3680,11 +3687,11 @@ node_plugin_options(Host, Type) -> Result -> Result end. -filter_node_options(Options) -> +filter_node_options(Options, BaseOptions) -> lists:foldl(fun({Key, Val}, Acc) -> DefaultValue = proplists:get_value(Key, Options, Val), [{Key, DefaultValue}|Acc] - end, [], node_flat:options()). + end, [], BaseOptions). node_owners_action(Host, Type, Nidx, []) -> case gen_mod:db_type(serverhost(Host), ?MODULE) of @@ -4468,7 +4475,7 @@ purge_offline(Host, LJID, Node) -> mod_opt_type(access_createnode) -> fun (A) when is_atom(A) -> A end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(host) -> fun iolist_to_binary/1; mod_opt_type(ignore_pep_from_offline) -> fun (A) when is_boolean(A) -> A end; diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 16354dd8..b3a627f7 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -1236,7 +1236,7 @@ import(LServer, DBType, R) -> mod_opt_type(access) -> fun (A) when is_atom(A) -> A end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(managers) -> fun (B) when is_list(B) -> B end; diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 6670cf77..76a619c9 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -1120,5 +1120,5 @@ import(LServer, DBType, Data) -> Mod = gen_mod:db_mod(DBType, ?MODULE), Mod:import(LServer, Data). -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [db_type]. diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index e5f5d9e3..5e042528 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -596,7 +596,7 @@ import(LServer, DBType, VCard) -> mod_opt_type(allow_return_all) -> fun (B) when is_boolean(B) -> B end; -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(host) -> fun iolist_to_binary/1; mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; mod_opt_type(matches) -> diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl index 198312c3..041b0b64 100644 --- a/src/mod_vcard_xupdate.erl +++ b/src/mod_vcard_xupdate.erl @@ -133,5 +133,5 @@ import(LServer, DBType, LA) -> Mod = gen_mod:db_mod(DBType, ?MODULE), Mod:import(LServer, LA). -mod_opt_type(db_type) -> fun gen_mod:v_db/1; +mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end; mod_opt_type(_) -> [db_type]. diff --git a/src/mod_vcard_xupdate_riak.erl b/src/mod_vcard_xupdate_riak.erl index 129a0c6a..242485bf 100644 --- a/src/mod_vcard_xupdate_riak.erl +++ b/src/mod_vcard_xupdate_riak.erl @@ -8,6 +8,8 @@ %%%------------------------------------------------------------------- -module(mod_vcard_xupdate_riak). +-behaviour(mod_vcard_xupdate). + %% API -export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2]). diff --git a/src/mod_vcard_xupdate_sql.erl b/src/mod_vcard_xupdate_sql.erl index 7f0079dd..00bb2950 100644 --- a/src/mod_vcard_xupdate_sql.erl +++ b/src/mod_vcard_xupdate_sql.erl @@ -8,6 +8,8 @@ %%%------------------------------------------------------------------- -module(mod_vcard_xupdate_sql). +-behaviour(mod_vcard_xupdate). + %% API -export([init/2, import/2, add_xupdate/3, get_xupdate/2, remove_xupdate/2, import/1, export/1]). diff --git a/src/shaper.erl b/src/shaper.erl index a136c213..eb82b8fa 100644 --- a/src/shaper.erl +++ b/src/shaper.erl @@ -124,9 +124,13 @@ update(#maxrate{} = State, Size) -> true -> 0 end, NextNow = p1_time_compat:system_time(micro_seconds) + Pause * 1000, + Div = case NextNow - State#maxrate.lasttime of + 0 -> 1; + V -> V + end, {State#maxrate{lastrate = (State#maxrate.lastrate + - 1000000 * Size / (NextNow - State#maxrate.lasttime)) + 1000000 * Size / Div) / 2, lasttime = NextNow}, Pause}. diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index e2f26807..3edbf587 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -303,6 +303,8 @@ db_tests(DB) when DB == mnesia; DB == redis -> [client_state_master, client_state_slave]}, {test_muc, [parallel], [muc_master, muc_slave]}, + {test_muc_mam, [parallel], + [muc_mam_master, muc_mam_slave]}, {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], @@ -343,6 +345,8 @@ db_tests(_) -> [mam_new_master, mam_new_slave]}, {test_muc, [parallel], [muc_master, muc_slave]}, + {test_muc_mam, [parallel], + [muc_mam_master, muc_mam_slave]}, {test_announce, [sequence], [announce_master, announce_slave]}, {test_vcard_xupdate, [parallel], @@ -1189,6 +1193,92 @@ proxy65_slave(Config) -> socks5_recv(Socks5, Data), disconnect(Config). +send_messages_to_room(Config, Range) -> + MyNick = ?config(master_nick, Config), + Room = muc_room_jid(Config), + MyNickJID = jid:replace_resource(Room, MyNick), + lists:foreach( + fun(N) -> + Text = #text{data = integer_to_binary(N)}, + I = send(Config, #message{to = Room, body = [Text], + type = groupchat}), + ?recv1(#message{from = MyNickJID, id = I, + type = groupchat, + body = [Text]}) + end, Range). + +retrieve_messages_from_room_via_mam(Config, Range) -> + MyNick = ?config(master_nick, Config), + Room = muc_room_jid(Config), + MyNickJID = jid:replace_resource(Room, MyNick), + QID = randoms:get_string(), + I = send(Config, #iq{type = set, to = Room, + sub_els = [#mam_query{xmlns = ?NS_MAM_1, id = QID}]}), + lists:foreach( + fun(N) -> + Text = #text{data = integer_to_binary(N)}, + ?recv1(#message{ + to = MyJID, from = Room, + sub_els = + [#mam_result{ + xmlns = ?NS_MAM_1, + queryid = QID, + sub_els = + [#forwarded{ + delay = #delay{}, + sub_els = [#message{ + from = MyNickJID, + type = groupchat, + body = [Text]}]}]}]}) + end, Range), + ?recv1(#iq{from = Room, id = I, type = result, sub_els = []}). + +muc_mam_master(Config) -> + MyJID = my_jid(Config), + MyNick = ?config(master_nick, Config), + Room = muc_room_jid(Config), + MyNickJID = jid:replace_resource(Room, MyNick), + %% Joining + send(Config, #presence{to = MyNickJID, sub_els = [#muc{}]}), + %% Receive self-presence + ?recv1(#presence{from = MyNickJID}), + %% MAM feature should not be advertised at this point, + %% because MAM is not enabled so far + false = is_feature_advertised(Config, ?NS_MAM_1, Room), + %% Fill in some history + send_messages_to_room(Config, lists:seq(1, 21)), + %% We now should be able to retrieve those via MAM, even though + %% MAM is disabled. However, only last 20 messages should be received. + retrieve_messages_from_room_via_mam(Config, lists:seq(2, 21)), + %% Now enable MAM for the conference + %% Retrieve config first + #iq{type = result, sub_els = [#muc_owner{config = #xdata{} = RoomCfg}]} = + send_recv(Config, #iq{type = get, sub_els = [#muc_owner{}], + to = Room}), + %% Find the MAM field in the config and enable it + NewFields = lists:flatmap( + fun(#xdata_field{var = <<"muc#roomconfig_mam">> = Var}) -> + [#xdata_field{var = Var, values = [<<"1">>]}]; + (_) -> + [] + end, RoomCfg#xdata.fields), + NewRoomCfg = #xdata{type = submit, fields = NewFields}, + I1 = send(Config, #iq{type = set, to = Room, + sub_els = [#muc_owner{config = NewRoomCfg}]}), + ?recv2(#iq{type = result, id = I1}, + #message{from = Room, type = groupchat, + sub_els = [#muc_user{status_codes = [104]}]}), + %% Check if MAM has been enabled + true = is_feature_advertised(Config, ?NS_MAM_1, Room), + %% We now sending some messages again + send_messages_to_room(Config, lists:seq(1, 5)), + %% And retrieve them via MAM again. + retrieve_messages_from_room_via_mam(Config, lists:seq(1, 5)), + disconnect(Config). + +muc_mam_slave(Config) -> + disconnect(Config). + muc_master(Config) -> MyJID = my_jid(Config), PeerJID = ?config(slave, Config), diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml index bd7f958d..869c24c7 100644 --- a/test/ejabberd_SUITE_data/ejabberd.yml +++ b/test/ejabberd_SUITE_data/ejabberd.yml @@ -424,7 +424,7 @@ listen: port: @@web_port@@ module: ejabberd_http captcha: true -loglevel: 4 +loglevel: @@loglevel@@ max_fsm_queue: 1000 modules: mod_adhoc: [] diff --git a/test/suite.erl b/test/suite.erl index 8000e1d2..f37b51ea 100644 --- a/test/suite.erl +++ b/test/suite.erl @@ -31,6 +31,7 @@ init_config(Config) -> {ok, CfgContentTpl} = file:read_file(ConfigPathTpl), CfgContent = process_config_tpl(CfgContentTpl, [ {c2s_port, 5222}, + {loglevel, 4}, {s2s_port, 5269}, {web_port, 5280}, {mysql_server, <<"localhost">>}, diff --git a/tools/xmpp_codec.erl b/tools/xmpp_codec.erl index 01e0676a..52950fea 100644 --- a/tools/xmpp_codec.erl +++ b/tools/xmpp_codec.erl @@ -103,6 +103,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> decode_mam_fin(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> decode_mam_prefs(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_prefs(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_prefs(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); @@ -116,6 +118,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> decode_mam_jid(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); {<<"result">>, <<"urn:xmpp:mam:0">>} -> decode_mam_result(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"result">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_result(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"result">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_result(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); @@ -124,6 +128,8 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) -> _el); {<<"query">>, <<"urn:xmpp:mam:0">>} -> decode_mam_query(<<"urn:xmpp:mam:0">>, IgnoreEls, _el); + {<<"query">>, <<"urn:xmpp:mam:1">>} -> + decode_mam_query(<<"urn:xmpp:mam:1">>, IgnoreEls, _el); {<<"query">>, <<"urn:xmpp:mam:tmp">>} -> decode_mam_query(<<"urn:xmpp:mam:tmp">>, IgnoreEls, _el); @@ -1141,14 +1147,17 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) -> {<<"forwarded">>, <<"urn:xmpp:forward:0">>} -> true; {<<"fin">>, <<"urn:xmpp:mam:0">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"prefs">>, <<"urn:xmpp:mam:1">>} -> true; {<<"prefs">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"always">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"never">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"jid">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"result">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"result">>, <<"urn:xmpp:mam:1">>} -> true; {<<"result">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"archived">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"query">>, <<"urn:xmpp:mam:0">>} -> true; + {<<"query">>, <<"urn:xmpp:mam:1">>} -> true; {<<"query">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"with">>, <<"urn:xmpp:mam:tmp">>} -> true; {<<"end">>, <<"urn:xmpp:mam:tmp">>} -> true; diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index e61b951c..536a11df 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -2145,7 +2145,7 @@ -xml(mam_query, #elem{name = <<"query">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:tmp">>], + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = {mam_query, '$xmlns', '$id', '$start', '$end', '$with', '$rsm', '$xdata'}, attrs = [#attr{name = <<"queryid">>, label = '$id'}, @@ -2168,7 +2168,7 @@ -xml(mam_result, #elem{name = <<"result">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:tmp">>], + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = {mam_result, '$xmlns', '$queryid', '$id', '$_els'}, attrs = [#attr{name = <<"queryid">>}, #attr{name = <<"xmlns">>}, @@ -2196,7 +2196,7 @@ -xml(mam_prefs, #elem{name = <<"prefs">>, - xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:tmp">>], + xmlns = [<<"urn:xmpp:mam:0">>, <<"urn:xmpp:mam:1">>, <<"urn:xmpp:mam:tmp">>], result = {mam_prefs, '$xmlns', '$default', '$always', '$never'}, attrs = [#attr{name = <<"default">>, dec = {dec_enum, [[always, never, roster]]}, diff --git a/vars.config.in b/vars.config.in index 44316f8a..57fade8d 100644 --- a/vars.config.in +++ b/vars.config.in @@ -40,6 +40,7 @@ {sysconfdir, "{{release_dir}}/etc"}. {installuser, "@INSTALLUSER@"}. {erl, "{{release_dir}}/{{erts_vsn}}/bin/erl"}. +{epmd, "{{release_dir}}/{{erts_vsn}}/bin/epmd"}. {localstatedir, "{{release_dir}}/var"}. {libdir, "{{release_dir}}/lib"}. {docdir, "{{release_dir}}/doc"}. |