summaryrefslogtreecommitdiff
path: root/src/ejabberd_config.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ejabberd_config.erl')
-rw-r--r--src/ejabberd_config.erl136
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) ->