]> granicus.if.org Git - ejabberd/commitdiff
Allow {mod_}opt_type to transform values passed to it, and for better error reporting
authorPaweł Chmielowski <pchmielowski@process-one.net>
Tue, 21 Jun 2016 10:25:29 +0000 (12:25 +0200)
committerPaweł Chmielowski <pchmielowski@process-one.net>
Tue, 21 Jun 2016 10:25:29 +0000 (12:25 +0200)
src/ejabberd_config.erl
src/gen_mod.erl

index 8c17e577f5b1ea69cf54600aa7626940ed4fc631..139047d9c8c055ef1ddfe707bb131d7713c5b2b3 100644 (file)
@@ -770,22 +770,32 @@ add_option(Opt, Val) ->
 -spec prepare_opt_val(any(), any(), check_fun(), any()) -> any().
 
 prepare_opt_val(Opt, Val, F, Default) ->
-    Res = case F of
-              {Mod, Fun} ->
-                  catch Mod:Fun(Val);
-              _ ->
-                  catch F(Val)
-          end,
-    case Res of
-        {'EXIT', _} ->
+    Call = case F of
+              {Mod, Fun} ->
+                  fun() -> Mod:Fun(Val) end;
+              _ ->
+                  fun() -> F(Val) end
+          end,
+    try Call() of
+       Res ->
+           Res
+    catch {replace_with, NewRes} ->
+           NewRes;
+         {invalid_syntax, Error} ->
+           ?WARNING_MSG("incorrect value '~s' of option '~s', "
+                        "using '~s' as fallback: ~s",
+                        [format_term(Val),
+                         format_term(Opt),
+                         format_term(Default),
+                         Error]),
+           Default;
+         _:_ ->
            ?WARNING_MSG("incorrect value '~s' of option '~s', "
                         "using '~s' as fallback",
                         [format_term(Val),
                          format_term(Opt),
                          format_term(Default)]),
-            Default;
-        _ ->
-            Res
+           Default
     end.
 
 -type check_fun() :: fun((any()) -> any()) | {module(), atom()}.
@@ -908,19 +918,26 @@ get_modules_with_options() ->
 
 validate_opts(#state{opts = Opts} = State) ->
     ModOpts = get_modules_with_options(),
-    NewOpts = lists:filter(
-               fun(#local_config{key = {Opt, _Host}, value = Val}) ->
+    NewOpts = lists:filtermap(
+               fun(#local_config{key = {Opt, _Host}, value = Val} = In) ->
                        case dict:find(Opt, ModOpts) of
                            {ok, [Mod|_]} ->
                                VFun = Mod:opt_type(Opt),
-                               case catch VFun(Val) of
-                                   {'EXIT', _} ->
+                               try VFun(Val) of
+                                   _ ->
+                                       true
+                               catch {replace_with, NewVal} ->
+                                       {true, In#local_config{value = NewVal}};
+                                     {invalid_syntax, Error} ->
+                                       ?ERROR_MSG("ignoring option '~s' with "
+                                                  "invalid value: ~p: ~s",
+                                                  [Opt, Val, Error]),
+                                       false;
+                                     _:_ ->
                                        ?ERROR_MSG("ignoring option '~s' with "
                                                   "invalid value: ~p",
                                                   [Opt, Val]),
-                                       false;
-                                   _ ->
-                                       true
+                                       false
                                end;
                            _ ->
                                ?ERROR_MSG("unknown option '~s' will be likely"
index f96397192eecd0830675bfe6adc3727ad8f63085..1cc65ac21a1074d192ce4f59e9acb07480336fea 100644 (file)
@@ -266,18 +266,25 @@ get_opt_host(Host, Opts, Default) ->
     ejabberd_regexp:greplace(Val, <<"@HOST@">>, Host).
 
 validate_opts(Module, Opts) ->
-    lists:filter(
+    lists:filtermap(
       fun({Opt, Val}) ->
              case catch Module:mod_opt_type(Opt) of
                  VFun when is_function(VFun) ->
-                     case catch VFun(Val) of
-                         {'EXIT', _} ->
+                     try VFun(Val) of
+                         _ ->
+                             true
+                     catch {replace_with, NewVal} ->
+                             {true, {Opt, NewVal}};
+                           {invalid_syntax, Error} ->
+                             ?ERROR_MSG("ignoring invalid value '~p' for "
+                                        "option '~s' of module '~s': ~s",
+                                        [Val, Opt, Module, Error]),
+                             false;
+                           _:_ ->
                              ?ERROR_MSG("ignoring invalid value '~p' for "
                                         "option '~s' of module '~s'",
                                         [Val, Opt, Module]),
-                             false;
-                         _ ->
-                             true
+                             false
                      end;
                  L when is_list(L) ->
                      SOpts = str:join([[$', atom_to_list(A), $'] || A <- L], <<", ">>),