diff options
Diffstat (limited to 'src/ejabberd_config.erl')
-rw-r--r-- | src/ejabberd_config.erl | 136 |
1 files changed, 118 insertions, 18 deletions
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) -> |