Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2013-08-12 16:25:05 +0400
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2013-08-21 16:17:59 +0400
commit91a74e3e27cf2c2f6b25888c3cc276d0ddbf5c69 (patch)
treea3838e249275ca587018d865fade3f3c41e9eddb /src
parentf68dfacbbf3b7489571de61f61818576fb836a63 (diff)
Change configuration file format to YAML
Diffstat (limited to 'src')
-rw-r--r--src/acl.erl469
-rw-r--r--src/cyrsasl_digest.erl4
-rw-r--r--src/ejabberd_admin.erl6
-rw-r--r--src/ejabberd_app.erl18
-rw-r--r--src/ejabberd_auth.erl2
-rw-r--r--src/ejabberd_auth_anonymous.erl4
-rw-r--r--src/ejabberd_auth_external.erl4
-rw-r--r--src/ejabberd_auth_internal.erl2
-rw-r--r--src/ejabberd_auth_ldap.erl4
-rw-r--r--src/ejabberd_auth_pam.erl4
-rw-r--r--src/ejabberd_c2s.erl21
-rw-r--r--src/ejabberd_c2s_config.erl2
-rw-r--r--src/ejabberd_captcha.erl8
-rw-r--r--src/ejabberd_config.erl499
-rw-r--r--src/ejabberd_ctl.erl2
-rw-r--r--src/ejabberd_frontend_socket.erl3
-rw-r--r--src/ejabberd_http.erl42
-rw-r--r--src/ejabberd_http_poll.erl2
-rw-r--r--src/ejabberd_listener.erl99
-rw-r--r--src/ejabberd_node_groups.erl7
-rw-r--r--src/ejabberd_odbc.erl68
-rw-r--r--src/ejabberd_odbc_sup.erl27
-rw-r--r--src/ejabberd_rdbms.erl22
-rw-r--r--src/ejabberd_router.erl12
-rw-r--r--src/ejabberd_s2s.erl68
-rw-r--r--src/ejabberd_s2s_in.erl10
-rw-r--r--src/ejabberd_s2s_out.erl79
-rw-r--r--src/ejabberd_service.erl57
-rw-r--r--src/ejabberd_system_monitor.erl4
-rw-r--r--src/ejabberd_web_admin.erl6
-rw-r--r--src/eldap_utils.erl2
-rw-r--r--src/extauth.erl2
-rw-r--r--src/gen_iq_handler.erl18
-rw-r--r--src/gen_mod.erl23
-rw-r--r--src/mod_carboncopy.erl2
-rw-r--r--src/mod_configure2.erl4
-rw-r--r--src/mod_disco.erl33
-rw-r--r--src/mod_last.erl26
-rw-r--r--src/mod_muc_log.erl14
-rw-r--r--src/mod_proxy65.erl5
-rw-r--r--src/mod_proxy65_service.erl25
-rw-r--r--src/mod_proxy65_stream.erl12
-rw-r--r--src/mod_register.erl137
-rw-r--r--src/mod_vcard_ldap.erl18
-rw-r--r--src/node_pep.erl8
-rw-r--r--src/node_pep_odbc.erl2
-rw-r--r--src/odbc_queries.erl12
-rw-r--r--src/shaper.erl75
48 files changed, 1299 insertions, 674 deletions
diff --git a/src/acl.erl b/src/acl.erl
index 1338e55b6..4c4523617 100644
--- a/src/acl.erl
+++ b/src/acl.erl
@@ -29,35 +29,38 @@
-author('alexey@process-one.net').
-export([start/0, to_record/3, add/3, add_list/3,
- add_local/3, add_list_local/3,
- match_rule/3, match_acl/3]).
+ add_local/3, add_list_local/3, load_from_config/0,
+ match_rule/3, match_acl/3, transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jlib.hrl").
-record(acl, {aclname, aclspec}).
+-record(access, {name :: access_name(),
+ rules = [] :: [access_rule()]}).
-type regexp() :: binary().
-type glob() :: binary().
+-type access_name() :: atom().
+-type access_rule() :: {atom(), any()}.
+-type host() :: binary().
-type aclname() :: {atom(), binary() | global}.
-type aclspec() :: all | none |
- {user, binary()} |
- {user, binary(), binary()} |
+ {user, {binary(), host()} | binary()} |
{server, binary()} |
{resource, binary()} |
- {user_regexp, regexp()} |
- {shared_group, binary()} |
- {shared_group, binary(), binary()} |
- {user_regexp, regexp(), binary()} |
+ {user_regexp, {regexp(), host()} | regexp()} |
+ {shared_group, {binary(), host()} | binary()} |
+ {user_regexp, {regexp(), host()} | regexp()} |
{server_regexp, regexp()} |
{resource_regexp, regexp()} |
- {node_regexp, regexp(), regexp()} |
- {user_glob, glob()} |
- {user_glob, glob(), binary()} |
+ {node_regexp, {regexp(), regexp()}} |
+ {user_glob, {glob(), host()} | glob()} |
{server_glob, glob()} |
{resource_glob, glob()} |
- {node_glob, glob(), glob()}.
+ {ip, {inet:ip_address(), integer()}} |
+ {node_glob, {glob(), glob()}}.
-type acl() :: #acl{aclname :: aclname(),
aclspec :: aclspec()}.
@@ -65,12 +68,23 @@
-export_type([acl/0]).
start() ->
+ case catch mnesia:table_info(acl, storage_type) of
+ disc_copies ->
+ mnesia:delete_table(acl);
+ _ ->
+ ok
+ end,
mnesia:create_table(acl,
- [{disc_copies, [node()]}, {type, bag},
+ [{ram_copies, [node()]}, {type, bag},
{local_content, true},
{attributes, record_info(fields, acl)}]),
+ mnesia:create_table(access,
+ [{ram_copies, [node()]},
+ {local_content, true},
+ {attributes, record_info(fields, access)}]),
mnesia:add_table_copy(acl, node(), ram_copies),
- update_table(),
+ mnesia:add_table_copy(access, node(), ram_copies),
+ load_from_config(),
ok.
-spec to_record(binary(), atom(), aclspec()) -> acl().
@@ -82,7 +96,7 @@ to_record(Host, ACLName, ACLSpec) ->
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
add(Host, ACLName, ACLSpec) ->
- {ResL, BadNodes} = rpc:multicall(ejabberd_cluster:get_nodes(),
+ {ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
?MODULE, add_local,
[Host, ACLName, ACLSpec]),
case lists:keyfind(aborted, 1, ResL) of
@@ -109,7 +123,7 @@ add_local(Host, ACLName, ACLSpec) ->
-spec add_list(binary(), [acl()], boolean()) -> ok | {error, any()}.
add_list(Host, ACLs, Clear) ->
- {ResL, BadNodes} = rpc:multicall(ejabberd_cluster:get_nodes(),
+ {ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
?MODULE, add_list_local,
[Host, ACLs, Clear]),
case lists:keyfind(aborted, 1, ResL) of
@@ -147,130 +161,196 @@ add_list_local(Host, ACLs, Clear) ->
end,
mnesia:transaction(F).
-normalize(A) -> jlib:nodeprep(iolist_to_binary(A)).
-
-normalize_spec({A, B}) -> {A, normalize(B)};
-normalize_spec({A, B, C}) ->
- {A, normalize(B), normalize(C)};
-normalize_spec(all) -> all;
-normalize_spec(none) -> none.
-
--spec match_rule(global | binary(), atom(), jid() | ljid()) -> any().
-
-match_rule(global, Rule, JID) ->
- case Rule of
- all -> allow;
- none -> deny;
- _ ->
- case ejabberd_config:get_global_option(
- {access, Rule, global}, fun(V) -> V end)
- of
- undefined -> deny;
- GACLs -> match_acls(GACLs, JID, global)
- end
- end;
-match_rule(Host, Rule, JID) ->
- case Rule of
- all -> allow;
- none -> deny;
- _ ->
- case ejabberd_config:get_global_option(
- {access, Rule, global}, fun(V) -> V end)
- of
- undefined ->
- case ejabberd_config:get_global_option(
- {access, Rule, Host}, fun(V) -> V end)
- of
- undefined -> deny;
- ACLs -> match_acls(ACLs, JID, Host)
- end;
- GACLs ->
- case ejabberd_config:get_global_option(
- {access, Rule, Host}, fun(V) -> V end)
- of
- undefined -> match_acls(GACLs, JID, Host);
- ACLs ->
- case lists:reverse(GACLs) of
- [{allow, all} | Rest] ->
- match_acls(lists:reverse(Rest) ++
- ACLs ++ [{allow, all}],
- JID, Host);
- _ -> match_acls(GACLs ++ ACLs, JID, Host)
- end
- end
- end
+-spec add_access(binary() | global,
+ access_name(), [access_rule()]) -> ok | {error, any()}.
+
+add_access(Host, Access, Rules) ->
+ case mnesia:transaction(
+ fun() ->
+ mnesia:write(
+ #access{name = {Access, Host},
+ rules = Rules})
+ end) of
+ {atomic, ok} ->
+ ok;
+ Err ->
+ {error, Err}
+ end.
+
+-spec load_from_config() -> ok.
+
+load_from_config() ->
+ Hosts = [global|?MYHOSTS],
+ lists:foreach(
+ fun(Host) ->
+ ACLs = ejabberd_config:get_option(
+ {acl, Host}, fun(V) -> V end, []),
+ AccessRules = ejabberd_config:get_option(
+ {access, Host}, fun(V) -> V end, []),
+ lists:foreach(
+ fun({ACLName, SpecList}) ->
+ lists:foreach(
+ fun({ACLType, ACLSpecs}) when is_list(ACLSpecs) ->
+ lists:foreach(
+ fun(ACLSpec) ->
+ add(Host, ACLName,
+ {ACLType, ACLSpec})
+ end, lists:flatten(ACLSpecs));
+ ({ACLType, ACLSpecs}) ->
+ add(Host, ACLName, {ACLType, ACLSpecs})
+ end, lists:flatten(SpecList))
+ end, ACLs),
+ lists:foreach(
+ fun({Access, Rules}) ->
+ add_access(Host, Access, Rules)
+ end, AccessRules)
+ end, Hosts).
+
+b(S) ->
+ iolist_to_binary(S).
+
+nodeprep(S) ->
+ jlib:nodeprep(b(S)).
+
+nameprep(S) ->
+ jlib:nameprep(b(S)).
+
+resourceprep(S) ->
+ jlib:resourceprep(b(S)).
+
+normalize_spec(Spec) ->
+ case Spec of
+ all -> all;
+ none -> none;
+ {user, {U, S}} -> {user, {nodeprep(U), nameprep(S)}};
+ {user, U} -> {user, nodeprep(U)};
+ {shared_group, {G, H}} -> {shared_group, {b(G), nameprep(H)}};
+ {shared_group, G} -> {shared_group, b(G)};
+ {user_regexp, {UR, S}} -> {user_regexp, {b(UR), nameprep(S)}};
+ {user_regexp, UR} -> {user_regexp, b(UR)};
+ {node_regexp, {UR, SR}} -> {node_regexp, {b(UR), b(SR)}};
+ {user_glob, {UR, S}} -> {user_glob, {b(UR), nameprep(S)}};
+ {user_glob, UR} -> {user_glob, b(UR)};
+ {node_glob, {UR, SR}} -> {node_glob, {b(UR), b(SR)}};
+ {server, S} -> {server, nameprep(S)};
+ {resource, R} -> {resource, resourceprep(R)};
+ {server_regexp, SR} -> {server_regexp, b(SR)};
+ {server_glob, S} -> {server_glob, b(S)};
+ {resource_glob, R} -> {resource_glob, b(R)};
+ {ip, S} ->
+ case parse_ip_netmask(b(S)) of
+ {ok, Net, Mask} ->
+ {ip, {Net, Mask}};
+ error ->
+ ?INFO_MSG("Invalid network address: ~p", [S]),
+ none
+ end
+ end.
+
+-spec match_rule(global | binary(), access_name(),
+ jid() | ljid() | inet:ip_address()) -> any().
+
+match_rule(_Host, all, _JID) ->
+ allow;
+match_rule(_Host, none, _JID) ->
+ deny;
+match_rule(Host, Access, JID) ->
+ GAccess = ets:lookup(access, {Access, global}),
+ LAccess = if Host /= global ->
+ ets:lookup(access, {Access, Host});
+ true ->
+ []
+ end,
+ case GAccess ++ LAccess of
+ [] ->
+ ?WARNING_MSG("Attempt to match against unspecified "
+ "access rule '~s' (scope: ~s)",
+ [Access, Host]),
+ deny;
+ AccessList ->
+ Rules = lists:flatmap(
+ fun(#access{rules = Rs}) ->
+ Rs
+ end, AccessList),
+ match_acls(Rules, JID, Host)
end.
match_acls([], _, _Host) -> deny;
-match_acls([{Access, ACL} | ACLs], JID, Host) ->
+match_acls([{ACL, Access} | ACLs], JID, Host) ->
case match_acl(ACL, JID, Host) of
true -> Access;
_ -> match_acls(ACLs, JID, Host)
end.
--spec match_acl(atom(), jid() | ljid(), binary()) -> boolean().
+-spec match_acl(atom(),
+ jid() | ljid() | inet:ip_address(),
+ binary()) -> boolean().
+match_acl(all, _JID, _Host) ->
+ true;
+match_acl(none, _JID, _Host) ->
+ false;
+match_acl(ACL, IP, Host) when tuple_size(IP) == 4;
+ tuple_size(IP) == 8 ->
+ lists:any(
+ fun(#acl{aclspec = {ip, {Net, Mask}}}) ->
+ is_ip_match(IP, Net, Mask);
+ (_) ->
+ false
+ end,
+ ets:lookup(acl, {ACL, Host}) ++
+ ets:lookup(acl, {ACL, global}));
match_acl(ACL, JID, Host) ->
- case ACL of
- all -> true;
- none -> false;
- _ ->
- {User, Server, Resource} = jlib:jid_tolower(JID),
- lists:any(fun (#acl{aclspec = Spec}) ->
- case Spec of
- all -> true;
- {user, U} ->
- U == User andalso
- (Host == Server orelse
- Host == global andalso
- lists:member(Server, ?MYHOSTS));
- {user, U, S} -> U == User andalso S == Server;
- {server, S} -> S == Server;
- {resource, R} -> R == Resource;
- {user_regexp, UR} ->
- (Host == Server orelse
- Host == global andalso
- lists:member(Server, ?MYHOSTS))
- andalso is_regexp_match(User, UR);
- {shared_group, G} ->
- Mod = loaded_shared_roster_module(Host),
- Mod:is_user_in_group({User, Server}, G, Host);
- {shared_group, G, H} ->
- Mod = loaded_shared_roster_module(H),
- Mod:is_user_in_group({User, Server}, G, H);
- {user_regexp, UR, S} ->
- S == Server andalso is_regexp_match(User, UR);
- {server_regexp, SR} ->
- is_regexp_match(Server, SR);
- {resource_regexp, RR} ->
- is_regexp_match(Resource, RR);
- {node_regexp, UR, SR} ->
- is_regexp_match(Server, SR) andalso
- is_regexp_match(User, UR);
- {user_glob, UR} ->
- (Host == Server orelse
- Host == global andalso
- lists:member(Server, ?MYHOSTS))
- andalso is_glob_match(User, UR);
- {user_glob, UR, S} ->
- S == Server andalso is_glob_match(User, UR);
- {server_glob, SR} -> is_glob_match(Server, SR);
- {resource_glob, RR} ->
- is_glob_match(Resource, RR);
- {node_glob, UR, SR} ->
- is_glob_match(Server, SR) andalso
- is_glob_match(User, UR);
- WrongSpec ->
- ?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
- "config file and reload it with the override_a"
- "cls option enabled",
- [WrongSpec]),
- false
- end
- end,
- ets:lookup(acl, {ACL, global}) ++
- ets:lookup(acl, {ACL, Host}))
- end.
+ {User, Server, Resource} = jlib:jid_tolower(JID),
+ lists:any(
+ fun(#acl{aclspec = Spec}) ->
+ case Spec of
+ all -> true;
+ {user, {U, S}} -> U == User andalso S == Server;
+ {user, U} ->
+ U == User andalso
+ lists:member(Server, ?MYHOSTS);
+ {server, S} -> S == Server;
+ {resource, R} -> R == Resource;
+ {shared_group, {G, H}} ->
+ Mod = loaded_shared_roster_module(H),
+ Mod:is_user_in_group({User, Server}, G, H);
+ {shared_group, G} ->
+ Mod = loaded_shared_roster_module(Host),
+ Mod:is_user_in_group({User, Server}, G, Host);
+ {user_regexp, {UR, S}} ->
+ S == Server andalso is_regexp_match(User, UR);
+ {user_regexp, UR} ->
+ lists:member(Server, ?MYHOSTS)
+ andalso is_regexp_match(User, UR);
+ {server_regexp, SR} ->
+ is_regexp_match(Server, SR);
+ {resource_regexp, RR} ->
+ is_regexp_match(Resource, RR);
+ {node_regexp, {UR, SR}} ->
+ is_regexp_match(Server, SR) andalso
+ is_regexp_match(User, UR);
+ {user_glob, {UR, S}} ->
+ S == Server andalso is_glob_match(User, UR);
+ {user_glob, UR} ->
+ lists:member(Server, ?MYHOSTS)
+ andalso is_glob_match(User, UR);
+ {server_glob, SR} -> is_glob_match(Server, SR);
+ {resource_glob, RR} ->
+ is_glob_match(Resource, RR);
+ {node_glob, {UR, SR}} ->
+ is_glob_match(Server, SR) andalso
+ is_glob_match(User, UR);
+ WrongSpec ->
+ ?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
+ "config file and reload it with the override_a"
+ "cls option enabled",
+ [WrongSpec]),
+ false
+ end
+ end,
+ ets:lookup(acl, {ACL, Host}) ++
+ ets:lookup(acl, {ACL, global})).
is_regexp_match(String, RegExp) ->
case ejabberd_regexp:run(String, RegExp) of
@@ -286,34 +366,115 @@ is_glob_match(String, Glob) ->
is_regexp_match(String,
ejabberd_regexp:sh_to_awk(Glob)).
+is_ip_match({_, _, _, _} = IP, {_, _, _, _} = Net, Mask) ->
+ IPInt = ip_to_integer(IP),
+ NetInt = ip_to_integer(Net),
+ M = bnot (1 bsl (32 - Mask) - 1),
+ IPInt band M =:= NetInt band M;
+is_ip_match({_, _, _, _, _, _, _, _} = IP,
+ {_, _, _, _, _, _, _, _} = Net, Mask) ->
+ IPInt = ip_to_integer(IP),
+ NetInt = ip_to_integer(Net),
+ M = bnot (1 bsl (128 - Mask) - 1),
+ IPInt band M =:= NetInt band M;
+is_ip_match(_, _, _) ->
+ false.
+
+ip_to_integer({IP1, IP2, IP3, IP4}) ->
+ IP1 bsl 8 bor IP2 bsl 8 bor IP3 bsl 8 bor IP4;
+ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7,
+ IP8}) ->
+ IP1 bsl 16 bor IP2 bsl 16 bor IP3 bsl 16 bor IP4 bsl 16
+ bor IP5
+ bsl 16
+ bor IP6
+ bsl 16
+ bor IP7
+ bsl 16
+ bor IP8.
+
loaded_shared_roster_module(Host) ->
case gen_mod:is_loaded(Host, mod_shared_roster_ldap) of
true -> mod_shared_roster_ldap;
false -> mod_shared_roster
end.
-update_table() ->
- Fields = record_info(fields, acl),
- case mnesia:table_info(acl, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- acl, Fields, bag,
- fun(#acl{aclspec = Spec}) when is_tuple(Spec) ->
- element(2, Spec);
- (_) ->
- '$next'
- end,
- fun(#acl{aclname = {ACLName, Host},
- aclspec = Spec} = R) ->
- NewHost = if Host == global ->
- Host;
- true ->
- iolist_to_binary(Host)
- end,
- R#acl{aclname = {ACLName, NewHost},
- aclspec = normalize_spec(Spec)}
- end);
- _ ->
- ?INFO_MSG("Recreating acl table", []),
- mnesia:transform_table(acl, ignore, Fields)
+parse_ip_netmask(S) ->
+ case str:tokens(S, <<"/">>) of
+ [IPStr] ->
+ case inet_parse:address(binary_to_list(IPStr)) of
+ {ok, {_, _, _, _} = IP} -> {ok, IP, 32};
+ {ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
+ _ -> error
+ end;
+ [IPStr, MaskStr] ->
+ case catch jlib:binary_to_integer(MaskStr) of
+ Mask when is_integer(Mask), Mask >= 0 ->
+ case inet_parse:address(binary_to_list(IPStr)) of
+ {ok, {_, _, _, _} = IP} when Mask =< 32 ->
+ {ok, IP, Mask};
+ {ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
+ {ok, IP, Mask};
+ _ -> error
+ end;
+ _ -> error
+ end;
+ _ -> error
end.
+
+transform_options(Opts) ->
+ Opts1 = lists:foldl(fun transform_options/2, [], Opts),
+ {ACLOpts, Opts2} = lists:mapfoldl(
+ fun({acl, Os}, Acc) ->
+ {Os, Acc};
+ (O, Acc) ->
+ {[], [O|Acc]}
+ end, [], Opts1),
+ {AccessOpts, Opts3} = lists:mapfoldl(
+ fun({access, Os}, Acc) ->
+ {Os, Acc};
+ (O, Acc) ->
+ {[], [O|Acc]}
+ end, [], Opts2),
+ ACLOpts1 = ejabberd_config:collect_options(lists:flatten(ACLOpts)),
+ AccessOpts1 = case ejabberd_config:collect_options(
+ lists:flatten(AccessOpts)) of
+ [] -> [];
+ L1 -> [{access, L1}]
+ end,
+ ACLOpts2 = case lists:map(
+ fun({ACLName, Os}) ->
+ {ACLName, ejabberd_config:collect_options(Os)}
+ end, ACLOpts1) of
+ [] -> [];
+ L2 -> [{acl, L2}]
+ end,
+ ACLOpts2 ++ AccessOpts1 ++ Opts3.
+
+transform_options({acl, Name, Type}, Opts) ->
+ T = case Type of
+ all -> all;
+ none -> none;
+ {user, U} -> {user, [U]};
+ {user, U, S} -> {user, [[{U, S}]]};
+ {shared_group, G} -> {shared_group, [G]};
+ {shared_group, G, H} -> {shared_group, [[{G, H}]]};
+ {user_regexp, UR} -> {user_regexp, [UR]};
+ {user_regexp, UR, S} -> {user_regexp, [[{UR, S}]]};
+ {node_regexp, UR, SR} -> {node_regexp, [[{UR, SR}]]};
+ {user_glob, UR} -> {user_glob, [UR]};
+ {user_glob, UR, S} -> {user_glob, [[{UR, S}]]};
+ {node_glob, UR, SR} -> {node_glob, [[{UR, SR}]]};
+ {server, S} -> {server, [S]};
+ {resource, R} -> {resource, [R]};
+ {server_regexp, SR} -> {server_regexp, [SR]};
+ {server_glob, S} -> {server_glob, [S]};
+ {ip, S} -> {ip, [S]};
+ {resource_glob, R} -> {resource_glob, [R]}
+ end,
+ [{acl, [{Name, [T]}]}|Opts];
+transform_options({access, Name, Rules}, Opts) ->
+ NewRules = [{ACL, Action} || {Action, ACL} <- Rules],
+ [{access, [{Name, NewRules}]}|Opts];
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
index ecb50c159..3f7133943 100644
--- a/src/cyrsasl_digest.erl
+++ b/src/cyrsasl_digest.erl
@@ -204,11 +204,11 @@ get_local_fqdn() ->
Str when is_binary(Str) -> Str;
_ ->
<<"unknown-fqdn, please configure fqdn "
- "option in ejabberd.cfg!">>
+ "option in ejabberd.yml!">>
end.
get_local_fqdn2() ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
fqdn, fun iolist_to_binary/1) of
ConfiguredFqdn when is_binary(ConfiguredFqdn) ->
ConfiguredFqdn;
diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl
index 5218d588a..a21331536 100644
--- a/src/ejabberd_admin.erl
+++ b/src/ejabberd_admin.erl
@@ -164,6 +164,12 @@ commands() ->
module = ejd2odbc, function = export,
args = [{host, string}, {file, string}], result = {res, rescode}},
+ #ejabberd_commands{name = convert_to_yaml, tags = [config],
+ desc = "Convert the input file from Erlang to YAML format",
+ module = ejabberd_config, function = convert_to_yaml,
+ args = [{in, string}, {out, string}],
+ result = {res, rescode}},
+
#ejabberd_commands{name = delete_expired_messages, tags = [purge],
desc = "Delete expired offline messages from database",
module = ?MODULE, function = delete_expired_messages,
diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
index ed67f0335..dba61b7d9 100644
--- a/src/ejabberd_app.erl
+++ b/src/ejabberd_app.erl
@@ -47,12 +47,14 @@ start(normal, _Args) ->
db_init(),
start(),
translate:start(),
- acl:start(),
ejabberd_ctl:init(),
ejabberd_commands:init(),
ejabberd_admin:start(),
gen_mod:start(),
ejabberd_config:start(),
+ set_loglevel_from_config(),
+ acl:start(),
+ shaper:start(),
connect_nodes(),
Sup = ejabberd_sup:start_link(),
ejabberd_rdbms:start(),
@@ -119,7 +121,7 @@ db_init() ->
start_modules() ->
lists:foreach(
fun(Host) ->
- Modules = ejabberd_config:get_local_option(
+ Modules = ejabberd_config:get_option(
{modules, Host},
fun(Mods) ->
lists:map(
@@ -137,7 +139,7 @@ start_modules() ->
stop_modules() ->
lists:foreach(
fun(Host) ->
- Modules = ejabberd_config:get_local_option(
+ Modules = ejabberd_config:get_option(
{modules, Host},
fun(Mods) ->
lists:map(
@@ -152,7 +154,7 @@ stop_modules() ->
end, ?MYHOSTS).
connect_nodes() ->
- Nodes = ejabberd_config:get_local_option(
+ Nodes = ejabberd_config:get_option(
cluster_nodes,
fun(Ns) ->
true = lists:all(fun is_atom/1, Ns),
@@ -212,9 +214,17 @@ delete_pid_file() ->
file:delete(PidFilename)
end.
+set_loglevel_from_config() ->
+ Level = ejabberd_config:get_option(
+ loglevel,
+ fun(P) when P>=0, P=<5 -> P end,
+ 4),
+ ejabberd_logger:set(Level).
+
start_apps() ->
ejabberd:start_app(sasl),
ejabberd:start_app(ssl),
+ ejabberd:start_app(p1_yaml),
ejabberd:start_app(p1_tls),
ejabberd:start_app(p1_xml),
ejabberd:start_app(p1_stringprep),
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index 7cc40ae1e..704c82cd4 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -423,7 +423,7 @@ auth_modules() ->
%% Return the list of authenticated modules for a given host
auth_modules(Server) ->
LServer = jlib:nameprep(Server),
- Methods = ejabberd_config:get_local_option(
+ Methods = ejabberd_config:get_option(
{auth_method, LServer},
fun(V) when is_list(V) ->
true = lists:all(fun is_atom/1, V),
diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl
index d8101efc4..180e9d0df 100644
--- a/src/ejabberd_auth_anonymous.erl
+++ b/src/ejabberd_auth_anonymous.erl
@@ -104,7 +104,7 @@ is_login_anonymous_enabled(Host) ->
%% Return the anonymous protocol to use: sasl_anon|login_anon|both
%% defaults to login_anon
anonymous_protocol(Host) ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{anonymous_protocol, Host},
fun(sasl_anon) -> sasl_anon;
(login_anon) -> login_anon;
@@ -115,7 +115,7 @@ anonymous_protocol(Host) ->
%% Return true if multiple connections have been allowed in the config file
%% defaults to false
allow_multiple_connections(Host) ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{allow_multiple_connections, Host},
fun(V) when is_boolean(V) -> V end,
false).
diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl
index 2d1bb7cb9..514b551d7 100644
--- a/src/ejabberd_auth_external.erl
+++ b/src/ejabberd_auth_external.erl
@@ -48,7 +48,7 @@
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
- Cmd = ejabberd_config:get_local_option(
+ Cmd = ejabberd_config:get_option(
{extauth_program, Host},
fun(V) ->
binary_to_list(iolist_to_binary(V))
@@ -171,7 +171,7 @@ remove_user(User, Server, Password) ->
%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
get_cache_option(Host) ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
{extauth_cache, Host},
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> false;
diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl
index 5a6c1b10a..8d7d0a0dd 100644
--- a/src/ejabberd_auth_internal.erl
+++ b/src/ejabberd_auth_internal.erl
@@ -406,7 +406,7 @@ is_scrammed() ->
is_option_scram() ->
scram ==
- ejabberd_config:get_local_option({auth_password_format, ?MYNAME},
+ ejabberd_config:get_option({auth_password_format, ?MYNAME},
fun(V) -> V end).
maybe_alert_password_scrammed_without_option() ->
diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl
index 1baf43887..1c1a4f313 100644
--- a/src/ejabberd_auth_ldap.erl
+++ b/src/ejabberd_auth_ldap.erl
@@ -369,8 +369,10 @@ parse_options(Host) ->
{iolist_to_binary(U),
iolist_to_binary(P)};
({U}) ->
+ {iolist_to_binary(U)};
+ (U) ->
{iolist_to_binary(U)}
- end, Us)
+ end, lists:flatten(Us))
end, [{<<"uid">>, <<"%u">>}]),
UIDs = eldap_utils:uids_domain_subst(Host, UIDsTemp),
SubFilter = eldap_utils:generate_subfilter(UIDs),
diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl
index c81208494..8e744e2c4 100644
--- a/src/ejabberd_auth_pam.erl
+++ b/src/ejabberd_auth_pam.erl
@@ -107,13 +107,13 @@ store_type() -> external.
%% Internal functions
%%====================================================================
get_pam_service(Host) ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{pam_service, Host},
fun iolist_to_binary/1,
<<"ejabberd">>).
get_pam_userinfotype(Host) ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{pam_userinfotype, Host},
fun(username) -> username;
(jid) -> jid
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index 5e50d9bf9..610f22c24 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -47,7 +47,8 @@
del_aux_field/2,
get_subscription/2,
broadcast/4,
- get_subscribed/1]).
+ get_subscribed/1,
+ transform_listen_option/2]).
%% gen_fsm callbacks
-export([init/1,
@@ -233,11 +234,10 @@ init([{SockMod, Socket}, Opts]) ->
{value, {_, XS}} -> XS;
_ -> false
end,
- Zlib = lists:member(zlib, Opts),
- StartTLS = lists:member(starttls, Opts),
- StartTLSRequired = lists:member(starttls_required,
- Opts),
- TLSEnabled = lists:member(tls, Opts),
+ Zlib = proplists:get_bool(zlib, Opts),
+ StartTLS = proplists:get_bool(starttls, Opts),
+ StartTLSRequired = proplists:get_bool(starttls_required, Opts),
+ TLSEnabled = proplists:get_bool(tls, Opts),
TLS = StartTLS orelse
StartTLSRequired orelse TLSEnabled,
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
@@ -682,7 +682,7 @@ wait_for_feature_request({xmlstreamelement, El},
when TLS == true, TLSEnabled == false,
SockMod == gen_tcp ->
TLSOpts = case
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{domain_certfile, StateData#state.server},
fun iolist_to_binary/1)
of
@@ -876,7 +876,7 @@ resource_conflict_action(U, S, R) ->
R)
of
true ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{resource_conflict, S},
fun(setresource) -> setresource;
(closeold) -> closeold;
@@ -2279,7 +2279,7 @@ fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) -> [{max_queue, N}];
_ ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];
@@ -2377,3 +2377,6 @@ pack_string(String, Pack) ->
{value, PackedString} -> {PackedString, Pack};
none -> {String, gb_trees:insert(String, String, Pack)}
end.
+
+transform_listen_option(Opt, Opts) ->
+ [Opt|Opts].
diff --git a/src/ejabberd_c2s_config.erl b/src/ejabberd_c2s_config.erl
index 4dbc48f38..2229e5ef1 100644
--- a/src/ejabberd_c2s_config.erl
+++ b/src/ejabberd_c2s_config.erl
@@ -34,7 +34,7 @@
%% Get first c2s configuration limitations to apply it to other c2s
%% connectors.
get_c2s_limits() ->
- case ejabberd_config:get_local_option(listen, fun(V) -> V end) of
+ case ejabberd_config:get_option(listen, fun(V) -> V end) of
undefined -> [];
C2SFirstListen ->
case lists:keysearch(ejabberd_c2s, 2, C2SFirstListen) of
diff --git a/src/ejabberd_captcha.erl b/src/ejabberd_captcha.erl
index 7442cf73c..e9a3ea3a9 100644
--- a/src/ejabberd_captcha.erl
+++ b/src/ejabberd_captcha.erl
@@ -504,7 +504,7 @@ do_create_image(Key) ->
end.
get_prog_name() ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
captcha_cmd,
fun(FileName) ->
F = iolist_to_binary(FileName),
@@ -521,7 +521,7 @@ get_prog_name() ->
end.
get_url(Str) ->
- CaptchaHost = ejabberd_config:get_local_option(
+ CaptchaHost = ejabberd_config:get_option(
captcha_host,
fun iolist_to_binary/1,
<<"">>),
@@ -549,7 +549,7 @@ get_transfer_protocol(PortString) ->
get_captcha_transfer_protocol(PortListeners).
get_port_listeners(PortNumber) ->
- AllListeners = ejabberd_config:get_local_option(listen, fun(V) -> V end),
+ AllListeners = ejabberd_config:get_option(listen, fun(V) -> V end),
lists:filter(fun ({{Port, _Ip, _Netp}, _Module1,
_Opts1})
when Port == PortNumber ->
@@ -579,7 +579,7 @@ get_captcha_transfer_protocol([_ | Listeners]) ->
is_limited(undefined) -> false;
is_limited(Limiter) ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
captcha_limit,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> false;
diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl
index b46603270..0551b49a5 100644
--- a/src/ejabberd_config.erl
+++ b/src/ejabberd_config.erl
@@ -27,16 +27,16 @@
-module(ejabberd_config).
-author('alexey@process-one.net').
--export([start/0, load_file/1,
+-export([start/0, load_file/1, read_file/1,
add_global_option/2, add_local_option/2,
get_global_option/2, get_local_option/2,
get_global_option/3, get_local_option/3,
- get_option/2, get_option/3, add_option/2]).
--export([get_vh_by_auth_method/1]).
--export([is_file_readable/1]).
--export([get_version/0, get_myhosts/0, get_mylang/0]).
--export([prepare_opt_val/4]).
--export([convert_table_to_binary/5]).
+ get_option/2, get_option/3, add_option/2,
+ 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]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -53,21 +53,29 @@
start() ->
+ case catch mnesia:table_info(local_config, storage_type) of
+ disc_copies ->
+ mnesia:delete_table(local_config);
+ _ ->
+ ok
+ end,
mnesia:create_table(local_config,
- [{disc_copies, [node()]},
+ [{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, local_config)}]),
mnesia:add_table_copy(local_config, node(), ram_copies),
Config = get_ejabberd_config_path(),
- load_file(Config),
+ State = read_file(Config),
%% This start time is used by mod_last:
- add_option(node_start, now()),
- ok.
+ {MegaSecs, Secs, _} = now(),
+ UnixTime = MegaSecs*1000000 + Secs,
+ State1 = set_option({node_start, global}, UnixTime, State),
+ set_opts(State1).
%% @doc Get the filename of the ejabberd configuration file.
-%% The filename can be specified with: erl -config "/path/to/ejabberd.cfg".
+%% The filename can be specified with: erl -config "/path/to/ejabberd.yml".
%% It can also be specified with the environtment variable EJABBERD_CONFIG_PATH.
-%% If not specified, the default value 'ejabberd.cfg' is assumed.
+%% If not specified, the default value 'ejabberd.yml' is assumed.
%% @spec () -> string()
get_ejabberd_config_path() ->
case application:get_env(config) of
@@ -81,16 +89,59 @@ get_ejabberd_config_path() ->
end
end.
-%% @doc Load the ejabberd configuration file.
+%% @doc Read the ejabberd configuration file.
%% It also includes additional configuration files and replaces macros.
%% This function will crash if finds some error in the configuration file.
-%% @spec (File::string()) -> ok
-load_file(File) ->
- Terms = get_plain_terms_file(File),
+%% @spec (File::string()) -> #state{}.
+read_file(File) ->
+ read_file(File, [{replace_macros, true},
+ {include_files, true}]).
+
+read_file(File, Opts) ->
+ Terms1 = get_plain_terms_file(File, Opts),
+ Terms_macros = case proplists:get_bool(replace_macros, Opts) of
+ true -> replace_macros(Terms1);
+ false -> Terms1
+ end,
+ Terms = transform_terms(Terms_macros),
State = lists:foldl(fun search_hosts/2, #state{}, Terms),
- Terms_macros = replace_macros(Terms),
- Res = lists:foldl(fun process_term/2, State, Terms_macros),
- set_opts(Res).
+ {Head, Tail} = lists:partition(
+ fun({host_config, _}) -> false;
+ ({append_host_config, _}) -> false;
+ (_) -> true
+ end, Terms),
+ State1 = lists:foldl(fun process_term/2, State, Head ++ Tail),
+ State1#state{opts = compact(State1#state.opts)}.
+
+-spec load_file(string()) -> ok.
+
+load_file(File) ->
+ State = read_file(File),
+ set_opts(State).
+
+-spec convert_to_yaml(file:filename()) -> ok | {error, any()}.
+
+convert_to_yaml(File) ->
+ convert_to_yaml(File, stdout).
+
+-spec convert_to_yaml(file:filename(),
+ stdout | file:filename()) -> ok | {error, any()}.
+
+convert_to_yaml(File, Output) ->
+ State = read_file(File, [{include_files, false}]),
+ Opts = [{K, V} || #local_config{key = K, value = V} <- State#state.opts],
+ {GOpts, HOpts} = split_by_hosts(Opts),
+ NewOpts = GOpts ++ lists:map(
+ fun({Host, Opts1}) ->
+ {host_config, [{Host, Opts1}]}
+ end, HOpts),
+ Data = p1_yaml:encode(lists:reverse(NewOpts)),
+ case Output of
+ stdout ->
+ io:format("~s~n", [Data]);
+ FileName ->
+ file:write_file(FileName, Data)
+ end.
%% @doc Read an ejabberd configuration file and return the terms.
%% Input is an absolute or relative path to an ejabberd config file.
@@ -99,22 +150,47 @@ load_file(File) ->
%% and the terms in those files were included.
%% @spec(string()) -> [term()]
%% @spec(iolist()) -> [term()]
-get_plain_terms_file(File) when is_binary(File) ->
- get_plain_terms_file(binary_to_list(File));
-get_plain_terms_file(File1) ->
+get_plain_terms_file(File) ->
+ get_plain_terms_file(File, [{include_files, true}]).
+
+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),
- case file:consult(File) of
+ case consult(File) of
{ok, Terms} ->
BinTerms = strings_to_binary(Terms),
- include_config_files(BinTerms);
- {error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
- ExitText = describe_config_problem(File, Reason, LineNumber),
- ?ERROR_MSG(ExitText, []),
- exit_or_halt(ExitText);
+ case proplists:get_bool(include_files, Opts) of
+ true ->
+ include_config_files(BinTerms);
+ false ->
+ BinTerms
+ end;
{error, Reason} ->
- ExitText = describe_config_problem(File, Reason),
- ?ERROR_MSG(ExitText, []),
- exit_or_halt(ExitText)
+ ?ERROR_MSG(Reason, []),
+ exit_or_halt(Reason)
+ end.
+
+consult(File) ->
+ case filename:extension(File) of
+ ".yml" ->
+ case p1_yaml:decode_from_file(File, [plain_as_atom]) of
+ {ok, []} ->
+ {ok, []};
+ {ok, [Document|_]} ->
+ {ok, Document};
+ {error, Err} ->
+ {error, p1_yaml:format_error(Err)}
+ end;
+ _ ->
+ case file:consult(File) of
+ {ok, Terms} ->
+ {ok, Terms};
+ {error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
+ {error, describe_config_problem(File, Reason, LineNumber)};
+ {error, Reason} ->
+ {error, describe_config_problem(File, Reason)}
+ end
end.
%% @doc Convert configuration filename to absolute path.
@@ -158,7 +234,7 @@ search_hosts(Term, State) ->
add_hosts_to_option(Hosts, State) ->
PrepHosts = normalize_hosts(Hosts),
- add_option(hosts, PrepHosts, State#state{hosts = PrepHosts}).
+ set_option({hosts, global}, PrepHosts, State#state{hosts = PrepHosts}).
normalize_hosts(Hosts) ->
normalize_hosts(Hosts,[]).
@@ -232,21 +308,37 @@ exit_or_halt(ExitText) ->
%% @doc Include additional configuration files in the list of terms.
%% @spec ([term()]) -> [term()]
include_config_files(Terms) ->
- include_config_files(Terms, []).
+ {FileOpts, Terms1} =
+ lists:mapfoldl(
+ fun({include_config_file, _} = T, Ts) ->
+ {[transform_include_option(T)], Ts};
+ ({include_config_file, _, _} = T, Ts) ->
+ {[transform_include_option(T)], Ts};
+ (T, Ts) ->
+ {[], [T|Ts]}
+ end, [], Terms),
+ Terms2 = lists:flatmap(
+ fun({File, Opts}) ->
+ include_config_file(File, Opts)
+ end, lists:flatten(FileOpts)),
+ Terms1 ++ Terms2.
+
+transform_include_option({include_config_file, File}) when is_list(File) ->
+ case is_string(File) of
+ true -> {File, []};
+ false -> File
+ end;
+transform_include_option({include_config_file, Filename}) ->
+ {Filename, []};
+transform_include_option({include_config_file, Filename, Options}) ->
+ {Filename, Options}.
-include_config_files([], Res) ->
- Res;
-include_config_files([{include_config_file, Filename} | Terms], Res) ->
- include_config_files([{include_config_file, Filename, []} | Terms], Res);
-include_config_files([{include_config_file, Filename, Options} | Terms], Res) ->
+include_config_file(Filename, Options) ->
Included_terms = get_plain_terms_file(Filename),
Disallow = proplists:get_value(disallow, Options, []),
Included_terms2 = delete_disallowed(Disallow, Included_terms),
Allow_only = proplists:get_value(allow_only, Options, all),
- Included_terms3 = keep_only_allowed(Allow_only, Included_terms2),
- include_config_files(Terms, Res ++ Included_terms3);
-include_config_files([Term | Terms], Res) ->
- include_config_files(Terms, Res ++ [Term]).
+ keep_only_allowed(Allow_only, Included_terms2).
%% @doc Filter from the list of terms the disallowed.
%% Returns a sublist of Terms without the ones which first element is
@@ -308,12 +400,19 @@ split_terms_macros(Terms) ->
fun(Term, {TOs, Ms}) ->
case Term of
{define_macro, Key, Value} ->
- case is_atom(Key) and is_all_uppercase(Key) of
+ case is_correct_macro({Key, Value}) of
true ->
{TOs, Ms++[{Key, Value}]};
false ->
exit({macro_not_properly_defined, Term})
end;
+ {define_macro, KeyVals} ->
+ case lists:all(fun is_correct_macro/1, KeyVals) of
+ true ->
+ {TOs, Ms ++ KeyVals};
+ false ->
+ exit({macros_not_properly_defined, Term})
+ end;
Term ->
{TOs ++ [Term], Ms}
end
@@ -321,6 +420,11 @@ split_terms_macros(Terms) ->
{[], []},
Terms).
+is_correct_macro({Key, _Val}) ->
+ is_atom(Key) and is_all_uppercase(Key);
+is_correct_macro(_) ->
+ false.
+
%% @doc Recursively replace in Terms macro usages with the defined value.
%% @spec (Terms, Macros) -> Terms
%% Terms = [term()]
@@ -328,7 +432,9 @@ split_terms_macros(Terms) ->
replace([], _) ->
[];
replace([Term|Terms], Macros) ->
- [replace_term(Term, Macros) | replace(Terms, Macros)].
+ [replace_term(Term, Macros) | replace(Terms, Macros)];
+replace(Term, Macros) ->
+ replace_term(Term, Macros).
replace_term(Key, Macros) when is_atom(Key) ->
case is_all_uppercase(Key) of
@@ -362,121 +468,65 @@ is_all_uppercase(Atom) ->
process_term(Term, State) ->
case Term of
- override_global ->
- State#state{override_global = true};
- override_local ->
- State#state{override_local = true};
- override_acls ->
- State#state{override_acls = true};
- {host_config, Host, Terms} ->
- lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
- State, Terms);
- {listen, Listeners} ->
- Listeners2 =
- lists:map(
- fun({PortIP, Module, Opts}) ->
- {Port, IPT, _, _, Proto, OptsClean} =
- ejabberd_listener:parse_listener_portip(PortIP, Opts),
- {{Port, IPT, Proto}, Module, OptsClean}
- end,
- Listeners),
- add_option(listen, Listeners2, State);
- {s2s_certfile, CertFile} ->
- CertFileS = binary_to_list(CertFile),
- case ejabberd_config:is_file_readable(CertFileS) of
- true -> add_option(s2s_certfile, CertFile, State);
- false ->
- ErrorText = "There is a problem in the configuration: "
- "the specified file is not readable: ",
- throw({error, ErrorText ++ CertFileS})
- end;
- {domain_certfile, Domain, CertFile} ->
- CertFileS = binary_to_list(CertFile),
- case ejabberd_config:is_file_readable(CertFileS) of
- true -> add_option({domain_certfile, Domain}, CertFile, State);
- false ->
- ErrorText = "There is a problem in the configuration: "
- "the specified file is not readable: ",
- throw({error, ErrorText ++ CertFileS})
- end;
- {loglevel, Loglevel} ->
- ejabberd_logger:set(Loglevel),
- State;
+ {host_config, HostTerms} ->
+ lists:foldl(
+ fun({Host, Terms}, AccState) ->
+ lists:foldl(fun(T, S) ->
+ process_host_term(T, Host, S, set)
+ end, AccState, Terms)
+ end, State, HostTerms);
+ {append_host_config, HostTerms} ->
+ lists:foldl(
+ fun({Host, Terms}, AccState) ->
+ lists:foldl(fun(T, S) ->
+ process_host_term(T, Host, S, append)
+ end, AccState, Terms)
+ end, State, HostTerms);
_ ->
- lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
- State, [global|State#state.hosts])
+ process_host_term(Term, global, State, set)
end.
-process_host_term(Term, Host, State) ->
+process_host_term(Term, Host, State, Action) ->
case Term of
- {acl, ACLName, ACLData} ->
- State#state{opts =
- [acl:to_record(Host, ACLName, ACLData) | State#state.opts]};
- {access, RuleName, Rules} ->
- add_option({access, RuleName, Host}, Rules, State);
- {shaper, Name, Data} ->
- add_option({shaper, Name, Host}, Data, State);
- {modules, Modules} ->
- add_option({modules, Host}, replace_modules(Modules), State);
+ {modules, Modules} when Action == set ->
+ set_option({modules, Host}, replace_modules(Modules), State);
+ {modules, Modules} when Action == append ->
+ append_option({modules, Host}, replace_modules(Modules), State);
{host, _} ->
State;
{hosts, _} ->
State;
- {Opt, Val} ->
- add_option({Opt, Host}, Val, State)
- end.
-
-add_option(Opt, Val, State) when is_atom(Opt) ->
- add_option({Opt, global}, Val, State);
-add_option(Opt, Val, State) ->
- case Opt of
- {{add, OptName}, Host} ->
- State#state{opts = compact({OptName, Host}, Val,
- State#state.opts, [])};
- _ ->
- State#state{opts = [#local_config{key = Opt, value = Val} |
- State#state.opts]}
- end.
-
-compact({OptName, Host} = Opt, Val, [], Os) ->
- ?WARNING_MSG("The option '~p' is defined for the host ~p using host_config "
- "before the global '~p' option. This host_config option may get overwritten.", [OptName, Host, OptName]),
- [#local_config{key = Opt, value = Val}] ++ Os;
-%% Traverse the list of the options already parsed
-compact(Opt, Val, [O | Os1], Os2) ->
- case catch O#local_config.key of
- %% If the key of a local_config matches the Opt that wants to be added
- Opt ->
- %% Then prepend the new value to the list of old values
- Os2 ++ [#local_config{key = Opt,
- value = Val++O#local_config.value}
- ] ++ Os1;
- _ ->
- compact(Opt, Val, Os1, Os2++[O])
+ {Opt, Val} when Action == set ->
+ set_option({Opt, Host}, Val, State);
+ {Opt, Val} when Action == append ->
+ append_option({Opt, Host}, Val, State);
+ Opt ->
+ ?WARNING_MSG("Ignore invalid (outdated?) option ~p", [Opt]),
+ State
end.
+set_option(Opt, Val, State) ->
+ State#state{opts = [#local_config{key = Opt, value = Val} |
+ State#state.opts]}.
+
+append_option({Opt, Host}, Val, State) ->
+ GlobalVals = lists:flatmap(
+ fun(#local_config{key = {O, global}, value = V})
+ when O == Opt ->
+ if is_list(V) -> V;
+ true -> [V]
+ end;
+ (_) ->
+ []
+ end, State#state.opts),
+ NewVal = if is_list(Val) -> Val ++ GlobalVals;
+ true -> [Val|GlobalVals]
+ end,
+ set_option({Opt, Host}, NewVal, State).
set_opts(State) ->
- Opts = lists:reverse(State#state.opts),
+ Opts = State#state.opts,
F = fun() ->
- if
- State#state.override_local ->
- Ksl = mnesia:all_keys(local_config),
- lists:foreach(fun(K) ->
- mnesia:delete({local_config, K})
- end, Ksl);
- true ->
- ok
- end,
- if
- State#state.override_acls ->
- Ksa = mnesia:all_keys(acl),
- lists:foreach(fun(K) ->
- mnesia:delete({acl, K})
- end, Ksa);
- true ->
- ok
- end,
lists:foreach(fun(R) ->
mnesia:write(R)
end, Opts)
@@ -565,11 +615,22 @@ get_option(Opt, F) ->
get_option(Opt, F, Default) when is_atom(Opt) ->
get_option({Opt, global}, F, Default);
get_option(Opt, F, Default) ->
+ case Opt of
+ {O, global} when is_atom(O) -> ok;
+ {O, H} when is_atom(O), is_binary(H) -> ok;
+ _ -> ?WARNING_MSG("Option ~p has invalid (outdated?) format. "
+ "This is likely a bug", [Opt])
+ end,
case ets:lookup(local_config, Opt) of
[#local_config{value = Val}] ->
prepare_opt_val(Opt, Val, F, Default);
- _ ->
- Default
+ _ ->
+ case Opt of
+ {Key, Host} when Host /= global ->
+ get_option({Key, global}, F, Default);
+ _ ->
+ Default
+ end
end.
-spec get_vh_by_auth_method(atom()) -> [binary()].
@@ -632,14 +693,14 @@ replace_modules(Modules) ->
emit_deprecation_warning(Module, NewModule, DBType),
NewOpts = [{db_type, DBType} |
lists:keydelete(db_type, 1, Opts)],
- {NewModule, NewOpts};
+ {NewModule, transform_module_options(Module, NewOpts)};
NewModule ->
if Module /= NewModule ->
emit_deprecation_warning(Module, NewModule);
true ->
ok
end,
- {NewModule, Opts}
+ {NewModule, transform_module_options(Module, Opts)}
end
end, Modules).
@@ -695,6 +756,142 @@ format_term(S) when is_list(S), S /= [] ->
format_term(T) ->
io_lib:format("~p", [binary_to_strings(T)]).
+transform_terms(Terms) ->
+ %% We could check all ejabberd beams, but this
+ %% slows down start-up procedure :(
+ Mods = [mod_register,
+ mod_last,
+ ejabberd_s2s,
+ ejabberd_listener,
+ ejabberd_odbc_sup,
+ shaper,
+ ejabberd_s2s_out,
+ acl,
+ ejabberd_config],
+ collect_options(transform_terms(Mods, Terms)).
+
+transform_terms([Mod|Mods], Terms) ->
+ case catch Mod:transform_options(Terms) of
+ {'EXIT', _} = Err ->
+ ?ERROR_MSG("Failed to transform terms by ~p: ~p", [Mod, Err]),
+ transform_terms(Mods, Terms);
+ NewTerms ->
+ transform_terms(Mods, NewTerms)
+ end;
+transform_terms([], NewTerms) ->
+ NewTerms.
+
+transform_module_options(Module, Opts) ->
+ Opts1 = gen_iq_handler:transform_module_options(Opts),
+ try
+ Module:transform_module_options(Opts1)
+ catch error:undef ->
+ Opts1
+ end.
+
+compact(Cfg) ->
+ Opts = [{K, V} || #local_config{key = K, value = V} <- Cfg],
+ {GOpts, HOpts} = split_by_hosts(Opts),
+ [#local_config{key = {O, global}, value = V} || {O, V} <- GOpts] ++
+ lists:flatmap(
+ fun({Host, OptVal}) ->
+ case lists:member(OptVal, GOpts) of
+ true ->
+ [];
+ false ->
+ [#local_config{key = {Opt, Host}, value = Val}
+ || {Opt, Val} <- OptVal]
+ end
+ end, lists:flatten(HOpts)).
+
+split_by_hosts(Opts) ->
+ Opts1 = orddict:to_list(
+ lists:foldl(
+ fun({{Opt, Host}, Val}, D) ->
+ orddict:append(Host, {Opt, Val}, D)
+ end, orddict:new(), Opts)),
+ case lists:keytake(global, 1, Opts1) of
+ {value, {global, GlobalOpts}, HostOpts} ->
+ {GlobalOpts, HostOpts};
+ _ ->
+ {[], Opts1}
+ end.
+
+collect_options(Opts) ->
+ {D, InvalidOpts} =
+ lists:foldl(
+ fun({K, V}, {D, Os}) when is_list(V) ->
+ {orddict:append_list(K, V, D), Os};
+ ({K, V}, {D, Os}) ->
+ {orddict:store(K, V, D), Os};
+ (Opt, {D, Os}) ->
+ {D, [Opt|Os]}
+ end, {orddict:new(), []}, Opts),
+ InvalidOpts ++ orddict:to_list(D).
+
+transform_options(Opts) ->
+ Opts1 = lists:foldl(fun transform_options/2, [], Opts),
+ {HOpts, Opts2} = lists:mapfoldl(
+ fun({host_config, O}, Os) ->
+ {[O], Os};
+ (O, Os) ->
+ {[], [O|Os]}
+ end, [], Opts1),
+ {AHOpts, Opts3} = lists:mapfoldl(
+ fun({append_host_config, O}, Os) ->
+ {[O], Os};
+ (O, Os) ->
+ {[], [O|Os]}
+ end, [], Opts2),
+ HOpts1 = case collect_options(lists:flatten(HOpts)) of
+ [] ->
+ [];
+ HOs ->
+ [{host_config,
+ [{H, transform_terms(O)} || {H, O} <- HOs]}]
+ end,
+ AHOpts1 = case collect_options(lists:flatten(AHOpts)) of
+ [] ->
+ [];
+ AHOs ->
+ [{append_host_config,
+ [{H, transform_terms(O)} || {H, O} <- AHOs]}]
+ end,
+ HOpts1 ++ AHOpts1 ++ Opts3.
+
+transform_options({domain_certfile, Domain, CertFile}, Opts) ->
+ ?WARNING_MSG("Option 'domain_certfile' now should be defined "
+ "per virtual host or globally. The old format is "
+ "still supported but it is better to fix your config", []),
+ [{host_config, [{Domain, [{domain_certfile, CertFile}]}]}|Opts];
+transform_options(Opt, Opts) when Opt == override_global;
+ Opt == override_local;
+ Opt == override_acls ->
+ ?WARNING_MSG("Ignoring '~s' option which has no effect anymore", [Opt]),
+ Opts;
+transform_options({host_config, Host, HOpts}, Opts) ->
+ {AddOpts, HOpts1} =
+ lists:mapfoldl(
+ fun({{add, Opt}, Val}, Os) ->
+ ?WARNING_MSG("Option 'add' is deprecated. "
+ "The option is still supported "
+ "but it is better to fix your config: "
+ "use 'append_host_config' instead.", []),
+ {[{Opt, Val}], Os};
+ (O, Os) ->
+ {[], [O|Os]}
+ end, [], HOpts),
+ [{append_host_config, [{Host, lists:flatten(AddOpts)}]},
+ {host_config, [{Host, HOpts1}]}|Opts];
+transform_options({define_macro, Macro, Val}, Opts) ->
+ [{define_macro, [{Macro, Val}]}|Opts];
+transform_options({include_config_file, _} = Opt, Opts) ->
+ [{include_config_file, [transform_include_option(Opt)]} | Opts];
+transform_options({include_config_file, _, _} = Opt, Opts) ->
+ [{include_config_file, [transform_include_option(Opt)]} | Opts];
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
+
-spec convert_table_to_binary(atom(), [atom()], atom(),
fun(), fun()) -> ok.
diff --git a/src/ejabberd_ctl.erl b/src/ejabberd_ctl.erl
index 38b94ef4d..d3944e266 100644
--- a/src/ejabberd_ctl.erl
+++ b/src/ejabberd_ctl.erl
@@ -237,7 +237,7 @@ process2(Args, Auth, AccessCommands) ->
end.
get_accesscommands() ->
- ejabberd_config:get_local_option(ejabberdctl_access_commands,
+ ejabberd_config:get_option(ejabberdctl_access_commands,
fun(V) when is_list(V) -> V end, []).
%%-----------------------------
diff --git a/src/ejabberd_frontend_socket.erl b/src/ejabberd_frontend_socket.erl
index adc7c2579..583396ec9 100644
--- a/src/ejabberd_frontend_socket.erl
+++ b/src/ejabberd_frontend_socket.erl
@@ -280,7 +280,7 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
%%% Internal functions
%%--------------------------------------------------------------------
check_starttls(SockMod, Socket, Receiver, Opts) ->
- TLSEnabled = lists:member(tls, Opts),
+ TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts = lists:filter(fun({certfile, _}) -> true;
(_) -> false
end, Opts),
@@ -292,4 +292,3 @@ check_starttls(SockMod, Socket, Receiver, Opts) ->
true ->
{SockMod, Socket}
end.
-
diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl
index 899d50eb3..151a34ef4 100644
--- a/src/ejabberd_http.erl
+++ b/src/ejabberd_http.erl
@@ -30,7 +30,8 @@
%% External exports
-export([start/2, start_link/2, become_controller/1,
- socket_type/0, receive_headers/1, url_encode/1]).
+ socket_type/0, receive_headers/1, url_encode/1,
+ transform_listen_option/2]).
%% Callbacks
-export([init/2]).
@@ -91,7 +92,7 @@ start_link(SockData, Opts) ->
[SockData, Opts])}.
init({SockMod, Socket}, Opts) ->
- TLSEnabled = lists:member(tls, Opts),
+ TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
(_) -> false
end,
@@ -133,12 +134,13 @@ init({SockMod, Socket}, Opts) ->
true -> [{[<<"http-poll">>], ejabberd_http_poll}];
false -> []
end,
- DefinedHandlers = case lists:keysearch(request_handlers,
- 1, Opts)
- of
- {value, {request_handlers, H}} -> H;
- false -> []
- end,
+ DefinedHandlers = gen_mod:get_opt(
+ request_handlers, Opts,
+ fun(Hs) ->
+ [{str:tokens(
+ iolist_to_binary(Path), <<"/">>),
+ Mod} || {Path, Mod} <- Hs]
+ end, []),
RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
Admin ++ Bind ++ Poll,
?DEBUG("S: ~p~n", [RequestHandlers]),
@@ -484,7 +486,7 @@ analyze_ip_xff(IP, [], _Host) -> IP;
analyze_ip_xff({IPLast, Port}, XFF, Host) ->
[ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++
[jlib:ip_to_list(IPLast)],
- TrustedProxies = ejabberd_config:get_local_option(
+ TrustedProxies = ejabberd_config:get_option(
{trusted_proxies, Host},
fun(TPs) ->
[iolist_to_binary(TP) || TP <- TPs]
@@ -834,3 +836,25 @@ normalize_path([_Parent, <<"..">>|Path], Norm) ->
normalize_path(Path, Norm);
normalize_path([Part | Path], Norm) ->
normalize_path(Path, [Part|Norm]).
+
+transform_listen_option(captcha, Opts) ->
+ [{captcha, true}|Opts];
+transform_listen_option(register, Opts) ->
+ [{register, true}|Opts];
+transform_listen_option(web_admin, Opts) ->
+ [{web_admin, true}|Opts];
+transform_listen_option(http_bind, Opts) ->
+ [{http_bind, true}|Opts];
+transform_listen_option(http_poll, Opts) ->
+ [{http_poll, true}|Opts];
+transform_listen_option({request_handlers, Hs}, Opts) ->
+ Hs1 = lists:map(
+ fun({PList, Mod}) when is_list(PList) ->
+ Path = iolist_to_binary([[$/, P] || P <- PList]),
+ {Path, Mod};
+ (Opt) ->
+ Opt
+ end, Hs),
+ [{request_handlers, Hs1} | Opts];
+transform_listen_option(Opt, Opts) ->
+ [Opt|Opts].
diff --git a/src/ejabberd_http_poll.erl b/src/ejabberd_http_poll.erl
index f144aeb59..89933a595 100644
--- a/src/ejabberd_http_poll.erl
+++ b/src/ejabberd_http_poll.erl
@@ -205,7 +205,7 @@ get_human_html_xmlel() ->
init([ID, Key, IP]) ->
?INFO_MSG("started: ~p", [{ID, Key, IP}]),
Opts = ejabberd_c2s_config:get_c2s_limits(),
- HTTPPollTimeout = ejabberd_config:get_local_option(
+ HTTPPollTimeout = ejabberd_config:get_option(
{http_poll_timeout, ?MYNAME},
fun(I) when is_integer(I), I>0 -> I end,
?HTTP_POLL_TIMEOUT) * 1000,
diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
index be90cf92f..033eb0e0f 100644
--- a/src/ejabberd_listener.erl
+++ b/src/ejabberd_listener.erl
@@ -36,7 +36,8 @@
parse_listener_portip/2,
add_listener/3,
delete_listener/2,
- validate_cfg/1
+ transform_options/1,
+ validate_cfg/1
]).
-include("ejabberd.hrl").
@@ -55,7 +56,7 @@ init(_) ->
{ok, {{one_for_one, 10, 1}, []}}.
bind_tcp_ports() ->
- case ejabberd_config:get_local_option(listen, fun validate_cfg/1) of
+ case ejabberd_config:get_option(listen, fun validate_cfg/1) of
undefined ->
ignore;
Ls ->
@@ -88,7 +89,7 @@ bind_tcp_port(PortIP, Module, RawOpts) ->
end.
start_listeners() ->
- case ejabberd_config:get_local_option(listen, fun validate_cfg/1) of
+ case ejabberd_config:get_option(listen, fun validate_cfg/1) of
undefined ->
ignore;
Ls ->
@@ -267,7 +268,7 @@ strip_ip_option(Opts) ->
Opts),
case IPL of
%% Only the first ip option is considered
- [{ip, T1} | _] when is_tuple(T1) ->
+ [{ip, T1} | _] ->
{T1, OptsNoIP};
[] ->
{no_ip_option, OptsNoIP}
@@ -364,7 +365,7 @@ start_listener_sup(Port, Module, Opts) ->
supervisor:start_child(ejabberd_listeners, ChildSpec).
stop_listeners() ->
- Ports = ejabberd_config:get_local_option(listen, fun validate_cfg/1),
+ Ports = ejabberd_config:get_option(listen, fun validate_cfg/1),
lists:foreach(
fun({PortIpNetp, Module, _Opts}) ->
delete_listener(PortIpNetp, Module)
@@ -397,7 +398,7 @@ add_listener(PortIP, Module, Opts) ->
PortIP1 = {Port, IPT, Proto},
case start_listener(PortIP1, Module, Opts) of
{ok, _Pid} ->
- Ports = case ejabberd_config:get_local_option(
+ Ports = case ejabberd_config:get_option(
listen, fun validate_cfg/1) of
undefined ->
[];
@@ -406,7 +407,8 @@ add_listener(PortIP, Module, Opts) ->
end,
Ports1 = lists:keydelete(PortIP1, 1, Ports),
Ports2 = [{PortIP1, Module, Opts} | Ports1],
- ejabberd_config:add_local_option(listen, Ports2),
+ Ports3 = lists:map(fun transform_option/1, Ports2),
+ ejabberd_config:add_option(listen, Ports3),
ok;
{error, {already_started, _Pid}} ->
{error, {already_started, PortIP}};
@@ -428,7 +430,7 @@ delete_listener(PortIP, Module) ->
delete_listener(PortIP, Module, Opts) ->
{Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts),
PortIP1 = {Port, IPT, Proto},
- Ports = case ejabberd_config:get_local_option(
+ Ports = case ejabberd_config:get_option(
listen, fun validate_cfg/1) of
undefined ->
[];
@@ -436,7 +438,8 @@ delete_listener(PortIP, Module, Opts) ->
Ls
end,
Ports1 = lists:keydelete(PortIP1, 1, Ports),
- ejabberd_config:add_local_option(listen, Ports1),
+ Ports2 = lists:map(fun transform_option/1, Ports1),
+ ejabberd_config:add_option(listen, Ports2),
stop_listener(PortIP1, Module).
@@ -541,6 +544,55 @@ format_error(Reason) ->
-define(IS_PORT(P), (is_integer(P) and (P > 0) and (P =< 65535))).
-define(IS_TRANSPORT(T), ((T == tcp) or (T == udp))).
+transform_option({{Port, IP, Transport}, Mod, Opts}) ->
+ IPStr = if is_tuple(IP) ->
+ list_to_binary(inet_parse:ntoa(IP));
+ true ->
+ IP
+ end,
+ Opts1 = lists:map(
+ fun({ip, IPT}) when is_tuple(IPT) ->
+ {ip, list_to_binary(inet_parse:ntoa(IP))};
+ (tls) -> {tls, true};
+ (ssl) -> {tls, true};
+ (zlib) -> {zlib, true};
+ (starttls) -> {starttls, true};
+ (starttls_required) -> {starttls_required, true};
+ (Opt) -> Opt
+ end, Opts),
+ Opts2 = lists:foldl(
+ fun(Opt, Acc) ->
+ try
+ Mod:transform_listen_option(Opt, Acc)
+ catch error:undef ->
+ Acc
+ end
+ end, [], Opts1),
+ TransportOpt = if Transport == tcp -> [];
+ true -> [{transport, Transport}]
+ end,
+ IPOpt = if IPStr == <<"0.0.0.0">> -> [];
+ true -> [{ip, IPStr}]
+ end,
+ IPOpt ++ TransportOpt ++ [{port, Port}, {module, Mod} | Opts2];
+transform_option({{Port, Transport}, Mod, Opts})
+ when ?IS_TRANSPORT(Transport) ->
+ transform_option({{Port, {0,0,0,0}, Transport}, Mod, Opts});
+transform_option({{Port, IP}, Mod, Opts}) ->
+ transform_option({{Port, IP, tcp}, Mod, Opts});
+transform_option({Port, Mod, Opts}) ->
+ transform_option({{Port, {0,0,0,0}, tcp}, Mod, Opts});
+transform_option(Opt) ->
+ Opt.
+
+transform_options(Opts) ->
+ lists:foldl(fun transform_options/2, [], Opts).
+
+transform_options({listen, LOpts}, Opts) ->
+ [{listen, lists:map(fun transform_option/1, LOpts)} | Opts];
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
+
-type transport() :: udp | tcp.
-type port_ip_transport() :: inet:port_number() |
{inet:port_number(), transport()} |
@@ -551,18 +603,21 @@ format_error(Reason) ->
validate_cfg(L) ->
lists:map(
- fun({PortIPTransport, Mod1, Opts}) when is_atom(Mod1), is_list(Opts) ->
- Mod = prepare_mod(Mod1),
- case PortIPTransport of
- Port when ?IS_PORT(Port) ->
- {Port, Mod, Opts};
- {Port, Trans} when ?IS_PORT(Port) and ?IS_TRANSPORT(Trans) ->
- {{Port, Trans}, Mod, Opts};
- {Port, IP} when ?IS_PORT(Port) ->
- {{Port, prepare_ip(IP)}, Mod, Opts};
- {Port, IP, Trans} when ?IS_PORT(Port) and ?IS_TRANSPORT(Trans) ->
- {{Port, prepare_ip(IP), Trans}, Mod, Opts}
- end
+ fun(LOpts) ->
+ lists:foldl(
+ fun({port, Port}, {{_, IP, T}, Mod, Opts}) ->
+ true = ?IS_PORT(Port),
+ {{Port, IP, T}, Mod, Opts};
+ ({ip, IP}, {{Port, _, T}, Mod, Opts}) ->
+ {{Port, prepare_ip(IP), T}, Mod, Opts};
+ ({transport, T}, {{Port, IP, _}, Mod, Opts}) ->
+ true = ?IS_TRANSPORT(T),
+ {{Port, IP, T}, Mod, Opts};
+ ({module, Mod}, {Port, _, Opts}) ->
+ {Port, prepare_mod(Mod), Opts};
+ (Opt, {Port, Mod, Opts}) ->
+ {Port, Mod, [Opt|Opts]}
+ end, {{5222, {0,0,0,0}, tcp}, ejabberd_c2s, []}, LOpts)
end, L).
prepare_ip({A, B, C, D} = IP)
@@ -583,5 +638,5 @@ prepare_mod(ejabberd_stun) ->
prepare_mod(stun) ->
ejabberd:start_app(p1_stun),
stun;
-prepare_mod(Mod) ->
+prepare_mod(Mod) when is_atom(Mod) ->
Mod.
diff --git a/src/ejabberd_node_groups.erl b/src/ejabberd_node_groups.erl
index 4e0335b97..eb39b7265 100644
--- a/src/ejabberd_node_groups.erl
+++ b/src/ejabberd_node_groups.erl
@@ -84,7 +84,12 @@ get_closest_node(Name) ->
%%--------------------------------------------------------------------
init([]) ->
{FE, BE} =
- case ejabberd_config:get_local_option(node_type, fun(N) -> N end) of
+ case ejabberd_config:get_option(
+ node_type,
+ fun(frontend) -> frontend;
+ (backend) -> backend;
+ (generic) -> generic
+ end, generic) of
frontend ->
{true, false};
backend ->
diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl
index 937805579..40a15a5ce 100644
--- a/src/ejabberd_odbc.erl
+++ b/src/ejabberd_odbc.erl
@@ -71,12 +71,12 @@
-define(TOP_LEVEL_TXN, 0).
--define(MAX_TRANSACTION_RESTARTS, 10).
-
-define(PGSQL_PORT, 5432).
-define(MYSQL_PORT, 3306).
+-define(MAX_TRANSACTION_RESTARTS, 10).
+
-define(TRANSACTION_TIMEOUT, 60000).
-define(KEEPALIVE_TIMEOUT, 60000).
@@ -201,8 +201,8 @@ decode_term(Bin) ->
%%% Callback functions from gen_fsm
%%%----------------------------------------------------------------------
init([Host, StartInterval]) ->
- case ejabberd_config:get_local_option(
- {odbc_keepalive_interval, Host},
+ case ejabberd_config:get_option(
+ {keepalive_interval, Host},
fun(I) when is_integer(I), I>0 -> I end) of
undefined ->
ok;
@@ -573,39 +573,39 @@ log(Level, Format, Args) ->
end.
db_opts(Host) ->
- case ejabberd_config:get_local_option(
- {odbc_server, Host},
- fun({Type, Server, DB, User, Pass}) ->
- {Type,
- iolist_to_binary(Server),
- case Type of
- mysql -> ?MYSQL_PORT;
- pgsql -> ?PGSQL_PORT
- end,
- iolist_to_binary(DB),
- iolist_to_binary(User),
- iolist_to_binary(Pass)};
- ({Type, Server, Port, DB, User, Pass})
- when ((Type == mysql) or (Type == pgsql))
- and (is_integer(Port) and ((Port > 0)
- and (Port < 65536))) ->
- {Type,
- iolist_to_binary(Server),
- Port,
- iolist_to_binary(DB),
- iolist_to_binary(User),
- iolist_to_binary(Pass)};
- (S) ->
- iolist_to_binary(S)
- end, <<"localhost">>) of
- {Type, Server, Port, DB, User, Pass} ->
- [Type, Server, Port, DB, User, Pass];
- SQLServer ->
- [odbc, SQLServer]
+ Type = ejabberd_config:get_option({odbc_type, Host},
+ fun(mysql) -> mysql;
+ (pgsql) -> pgsql;
+ (odbc) -> odbc
+ end, odbc),
+ Server = ejabberd_config:get_option({odbc_server, Host},
+ fun iolist_to_binary/1,
+ <<"localhost">>),
+ case Type of
+ odbc ->
+ [odbc, Server];
+ _ ->
+ Port = ejabberd_config:get_option(
+ {port, Host},
+ fun(P) when is_integer(P), P > 0, P < 65536 -> P end,
+ case Type of
+ mysql -> ?MYSQL_PORT;
+ pgsql -> ?PGSQL_PORT
+ end),
+ DB = ejabberd_config:get_option({odbc_database, Host},
+ fun iolist_to_binary/1,
+ <<"ejabberd">>),
+ User = ejabberd_config:get_option({odbc_username, Host},
+ fun iolist_to_binary/1,
+ <<"ejabberd">>),
+ Pass = ejabberd_config:get_option({odbc_password, Host},
+ fun iolist_to_binary/1,
+ <<"">>),
+ [Type, Server, Port, DB, User, Pass]
end.
max_fsm_queue() ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
max_fsm_queue,
fun(N) when is_integer(N), N > 0 -> N end).
diff --git a/src/ejabberd_odbc_sup.erl b/src/ejabberd_odbc_sup.erl
index 2ddc751f8..86b737948 100644
--- a/src/ejabberd_odbc_sup.erl
+++ b/src/ejabberd_odbc_sup.erl
@@ -30,11 +30,15 @@
%% API
-export([start_link/1, init/1, add_pid/2, remove_pid/2,
- get_pids/1, get_random_pid/1]).
+ get_pids/1, get_random_pid/1, transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
+-define(PGSQL_PORT, 5432).
+
+-define(MYSQL_PORT, 3306).
+
-define(DEFAULT_POOL_SIZE, 10).
-define(DEFAULT_ODBC_START_INTERVAL, 30).
@@ -56,11 +60,11 @@ start_link(Host) ->
?MODULE, [Host]).
init([Host]) ->
- PoolSize = ejabberd_config:get_local_option(
+ PoolSize = ejabberd_config:get_option(
{odbc_pool_size, Host},
fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_POOL_SIZE),
- StartInterval = ejabberd_config:get_local_option(
+ StartInterval = ejabberd_config:get_option(
{odbc_start_interval, Host},
fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_ODBC_START_INTERVAL),
@@ -93,3 +97,20 @@ remove_pid(Host, Pid) ->
mnesia:delete_object(#sql_pool{host = Host, pid = Pid})
end,
mnesia:ets(F).
+
+transform_options(Opts) ->
+ lists:foldl(fun transform_options/2, [], Opts).
+
+transform_options({odbc_server, {Type, Server, Port, DB, User, Pass}}, Opts) ->
+ [{odbc_type, Type},
+ {odbc_server, Server},
+ {odbc_port, Port},
+ {odbc_database, DB},
+ {odbc_username, User},
+ {odbc_password, Pass}|Opts];
+transform_options({odbc_server, {mysql, Server, DB, User, Pass}}, Opts) ->
+ transform_options({odbc_server, {mysql, Server, ?MYSQL_PORT, DB, User, Pass}}, Opts);
+transform_options({odbc_server, {pgsql, Server, DB, User, Pass}}, Opts) ->
+ transform_options({odbc_server, {pgsql, Server, ?PGSQL_PORT, DB, User, Pass}}, Opts);
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
diff --git a/src/ejabberd_rdbms.erl b/src/ejabberd_rdbms.erl
index a7324e4ca..b5525de10 100644
--- a/src/ejabberd_rdbms.erl
+++ b/src/ejabberd_rdbms.erl
@@ -69,18 +69,16 @@ start_odbc(Host, App) ->
start_odbc(Host, App)
end.
-%% Returns {true, App} if we have configured odbc_server for the given host
+%% Returns {true, App} if we have configured odbc for the given host
needs_odbc(Host) ->
LHost = jlib:nameprep(Host),
- case ejabberd_config:get_local_option(
- {odbc_server, LHost}, fun(Res) -> Res end) of
- {mysql, _, _, _, _} -> {true, p1_mysql};
- {pgsql, _, _, _, _} -> {true, p1_pgsql};
- {mysql, _, _, _, _, _} -> {true, p1_mysql};
- {pgsql, _, _, _, _, _} -> {true, p1_pgsql};
- S ->
- case catch iolist_to_binary(S) of
- {'EXIT', _} -> false;
- _ -> true
- end
+ case ejabberd_config:get_option({odbc_type, LHost},
+ fun(mysql) -> mysql;
+ (pgsql) -> pgsql;
+ (odbc) -> odbc
+ end, undefined) of
+ mysql -> {true, p1_mysql};
+ pgsql -> {true, p1_pgsql};
+ odbc -> {true, odbc};
+ undefined -> false
end.
diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl
index ea020a186..24f52d329 100644
--- a/src/ejabberd_router.erl
+++ b/src/ejabberd_router.erl
@@ -387,14 +387,10 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
end.
get_component_number(LDomain) ->
- case
- ejabberd_config:get_local_option({domain_balancing_component_number,
- LDomain}, fun(D) -> D end)
- of
- N when is_integer(N), N > 1 -> N;
- _ -> undefined
- end.
-
+ ejabberd_config:get_option(
+ {domain_balancing_component_number, LDomain},
+ fun(N) when is_integer(N), N > 1 -> N end,
+ undefined).
update_tables() ->
case catch mnesia:table_info(route, attributes) of
diff --git a/src/ejabberd_s2s.erl b/src/ejabberd_s2s.erl
index 591d31da2..b13fdd58e 100644
--- a/src/ejabberd_s2s.erl
+++ b/src/ejabberd_s2s.erl
@@ -45,7 +45,7 @@
handle_info/2, terminate/2, code_change/3]).
%% ejabberd API
--export([get_info_s2s_connections/1]).
+-export([get_info_s2s_connections/1, transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -461,12 +461,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber,
%% --------------------------------------------------------------------
is_service(From, To) ->
LFromDomain = From#jid.lserver,
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
{route_subdomains, LFromDomain},
- fun(s2s) -> s2s end) of
+ fun(s2s) -> s2s; (local) -> local end, local) of
s2s -> % bypass RFC 3920 10.3
false;
- undefined ->
+ local ->
Hosts = (?MYHOSTS),
P = fun (ParentDomain) ->
lists:member(ParentDomain, Hosts)
@@ -548,34 +548,50 @@ allow_host2(MyServer, S2SHost) ->
end.
allow_host1(MyHost, S2SHost) ->
- case ejabberd_config:get_local_option(
- {{s2s_host, S2SHost}, MyHost},
- fun(deny) -> deny; (allow) -> allow end)
- of
- deny -> false;
- allow -> true;
- undefined ->
- case ejabberd_config:get_local_option(
- {s2s_default_policy, MyHost},
- fun(deny) -> deny; (allow) -> allow end)
- of
- deny -> false;
- _ ->
- case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
- allow, [MyHost, S2SHost])
- of
- deny -> false;
- allow -> true;
- _ -> true
- end
- end
+ Rule = ejabberd_config:get_option(
+ s2s_access,
+ fun(A) when is_atom(A) -> A end,
+ all),
+ JID = jlib:make_jid(<<"">>, S2SHost, <<"">>),
+ case acl:match_rule(MyHost, Rule, JID) of
+ deny -> false;
+ allow ->
+ case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
+ allow, [MyHost, S2SHost]) of
+ deny -> false;
+ allow -> true;
+ _ -> true
+ end
end.
+transform_options(Opts) ->
+ lists:foldl(fun transform_options/2, [], Opts).
+
+transform_options({{s2s_host, Host}, Action}, Opts) ->
+ ?WARNING_MSG("Option 's2s_host' is deprecated. "
+ "The option is still supported but it is better to "
+ "fix your config: use access rules instead.", []),
+ ACLName = jlib:binary_to_atom(
+ iolist_to_binary(["s2s_access_", Host])),
+ [{acl, ACLName, {server, Host}},
+ {access, s2s, [{Action, ACLName}]},
+ {s2s_access, s2s} |
+ Opts];
+transform_options({s2s_default_policy, Action}, Opts) ->
+ ?WARNING_MSG("Option 's2s_default_policy' is deprecated. "
+ "The option is still supported but it is better to "
+ "fix your config: "
+ "use 's2s_access' with an access rule.", []),
+ [{access, s2s, [{Action, all}]},
+ {s2s_access, s2s} |
+ Opts];
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
+
%% Get information about S2S connections of the specified type.
%% @spec (Type) -> [Info]
%% where Type = in | out
%% Info = [{InfoName::atom(), InfoValue::any()}]
-
get_info_s2s_connections(Type) ->
ChildType = case Type of
in -> ejabberd_s2s_in_sup;
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
index 7692614ea..2ad335657 100644
--- a/src/ejabberd_s2s_in.erl
+++ b/src/ejabberd_s2s_in.erl
@@ -149,7 +149,7 @@ init([{SockMod, Socket}, Opts]) ->
_ -> none
end,
{StartTLS, TLSRequired, TLSCertverify} =
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
s2s_use_starttls,
fun(false) -> false;
(true) -> true;
@@ -171,7 +171,7 @@ init([{SockMod, Socket}, Opts]) ->
required_trusted ->
{true, true, true}
end,
- TLSOpts1 = case ejabberd_config:get_local_option(
+ TLSOpts1 = case ejabberd_config:get_option(
s2s_certfile,
fun iolist_to_binary/1) of
undefined -> [];
@@ -324,7 +324,7 @@ wait_for_feature_request({xmlstreamelement, El},
?DEBUG("starttls", []),
Socket = StateData#state.socket,
TLSOpts1 = case
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{domain_certfile, StateData#state.server},
fun iolist_to_binary/1) of
undefined -> StateData#state.tls_options;
@@ -332,7 +332,7 @@ wait_for_feature_request({xmlstreamelement, El},
[{certfile, CertFile} | lists:keydelete(certfile, 1,
StateData#state.tls_options)]
end,
- TLSOpts = case ejabberd_config:get_local_option(
+ TLSOpts = case ejabberd_config:get_option(
{s2s_tls_compression, StateData#state.server},
fun(true) -> true;
(false) -> false
@@ -843,7 +843,7 @@ fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) -> [{max_queue, N}];
_ ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];
diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
index 1aaaa9998..f52a673e4 100644
--- a/src/ejabberd_s2s_out.erl
+++ b/src/ejabberd_s2s_out.erl
@@ -35,7 +35,8 @@
start_link/3,
start_connection/1,
terminate_if_waiting_delay/2,
- stop_connection/1]).
+ stop_connection/1,
+ transform_options/1]).
%% p1_fsm callbacks (same as gen_fsm)
-export([init/1,
@@ -161,7 +162,7 @@ init([From, Server, Type]) ->
process_flag(trap_exit, true),
?DEBUG("started: ~p", [{From, Server, Type}]),
{TLS, TLSRequired} = case
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
s2s_use_starttls,
fun(true) -> true;
(false) -> false;
@@ -184,13 +185,13 @@ init([From, Server, Type]) ->
end,
UseV10 = TLS,
TLSOpts1 = case
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
s2s_certfile, fun iolist_to_binary/1)
of
undefined -> [connect];
CertFile -> [{certfile, CertFile}, connect]
end,
- TLSOpts = case ejabberd_config:get_local_option(
+ TLSOpts = case ejabberd_config:get_option(
{s2s_tls_compression, From},
fun(true) -> true;
(false) -> false
@@ -702,7 +703,7 @@ wait_for_starttls_proceed({xmlstreamelement, El},
[{StateData#state.myname, StateData#state.server}]),
Socket = StateData#state.socket,
TLSOpts = case
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{domain_certfile, StateData#state.myname},
fun iolist_to_binary/1)
of
@@ -1142,16 +1143,15 @@ get_addr_port(Server) ->
end.
srv_lookup(Server) ->
- Options = case
- ejabberd_config:get_local_option(
- s2s_dns_options, fun(L) when is_list(L) -> L end)
- of
- undefined -> [];
- L -> L
- end,
- TimeoutMs = timer:seconds(proplists:get_value(timeout,
- Options, 10)),
- Retries = proplists:get_value(retries, Options, 2),
+ TimeoutMs = timer:seconds(
+ ejabberd_config:get_option(
+ s2s_dns_timeout,
+ fun(I) when is_integer(I), I>=0 -> I end,
+ 10)),
+ Retries = ejabberd_config:get_option(
+ s2s_dns_retries,
+ fun(I) when is_integer(I), I>=0 -> I end,
+ 2),
srv_lookup(binary_to_list(Server), TimeoutMs, Retries).
%% XXX - this behaviour is suboptimal in the case that the domain
@@ -1211,15 +1211,15 @@ get_addrs(Host, Family) ->
end.
outgoing_s2s_port() ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
outgoing_s2s_port,
fun(I) when is_integer(I), I > 0, I =< 65536 -> I end,
5269).
outgoing_s2s_families() ->
- ejabberd_config:get_local_option(
- outgoing_s2s_options,
- fun({Families, _}) ->
+ ejabberd_config:get_option(
+ outgoing_s2s_families,
+ fun(Families) ->
true = lists:all(
fun(ipv4) -> true;
(ipv6) -> true
@@ -1228,14 +1228,43 @@ outgoing_s2s_families() ->
end, [ipv4, ipv6]).
outgoing_s2s_timeout() ->
- ejabberd_config:get_local_option(
- outgoing_s2s_options,
- fun({_, TimeOut}) when is_integer(TimeOut), TimeOut > 0 ->
+ ejabberd_config:get_option(
+ outgoing_s2s_timeout,
+ fun(TimeOut) when is_integer(TimeOut), TimeOut > 0 ->
TimeOut;
- ({_, infinity}) ->
+ (infinity) ->
infinity
end, 10000).
+transform_options(Opts) ->
+ lists:foldl(fun transform_options/2, [], Opts).
+
+transform_options({outgoing_s2s_options, Families, Timeout}, Opts) ->
+ ?WARNING_MSG("Option 'outgoing_s2s_options' is deprecated. "
+ "The option is still supported "
+ "but it is better to fix your config: "
+ "use 'outgoing_s2s_timeout' and "
+ "'outgoing_s2s_families' instead.", []),
+ [{outgoing_s2s_families, Families},
+ {outgoing_s2s_timeout, Timeout}
+ | Opts];
+transform_options({s2s_dns_options, S2SDNSOpts}, AllOpts) ->
+ ?WARNING_MSG("Option 's2s_dns_options' is deprecated. "
+ "The option is still supported "
+ "but it is better to fix your config: "
+ "use 's2s_dns_timeout' and "
+ "'s2s_dns_retries' instead", []),
+ lists:foldr(
+ fun({timeout, T}, AccOpts) ->
+ [{s2s_dns_timeout, T}|AccOpts];
+ ({retries, R}, AccOpts) ->
+ [{s2s_dns_retries, R}|AccOpts];
+ (_, AccOpts) ->
+ AccOpts
+ end, AllOpts, S2SDNSOpts);
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
+
%% Human readable S2S logging: Log only new outgoing connections as INFO
%% Do not log dialback
log_s2s_out(false, _, _, _) -> ok;
@@ -1278,7 +1307,7 @@ wait_before_reconnect(StateData) ->
queue = queue:new()}}.
get_max_retry_delay() ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
s2s_max_retry_delay,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> ?MAX_RETRY_DELAY;
@@ -1295,7 +1324,7 @@ terminate_if_waiting_delay(From, To) ->
Pids).
fsm_limit_opts() ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];
diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl
index 49bea8950..35f7c187a 100644
--- a/src/ejabberd_service.erl
+++ b/src/ejabberd_service.erl
@@ -34,7 +34,7 @@
%% External exports
-export([start/2, start_link/2, send_text/2,
- send_element/2, socket_type/0]).
+ send_element/2, socket_type/0, transform_listen_option/2]).
%% gen_fsm callbacks
-export([init/1, wait_for_stream/2,
@@ -124,29 +124,18 @@ init([{SockMod, Socket}, Opts]) ->
{value, {_, A}} -> A;
_ -> all
end,
- {Hosts, Password} = case lists:keysearch(hosts, 1, Opts)
- of
- {value, {_, Hs, HOpts}} ->
- case lists:keysearch(password, 1, HOpts) of
- {value, {_, P}} -> {Hs, P};
- _ ->
- % TODO: generate error
- false
- end;
- _ ->
- case lists:keysearch(host, 1, Opts) of
- {value, {_, H, HOpts}} ->
- case lists:keysearch(password, 1, HOpts) of
- {value, {_, P}} -> {[H], P};
- _ ->
- % TODO: generate error
- false
- end;
- _ ->
- % TODO: generate error
- false
- end
- end,
+ %% This should be improved probably
+ {Hosts, HostOpts} = case lists:keyfind(hosts, 1, Opts) of
+ {_, HOpts} ->
+ {[H || {H, _} <- HOpts],
+ lists:flatten(
+ [O || {_, O} <- HOpts])};
+ _ ->
+ {[], []}
+ end,
+ Password = gen_mod:get_opt(password, HostOpts,
+ fun iolist_to_binary/1,
+ p1_sha:sha(crypto:rand_bytes(20))),
Shaper = case lists:keysearch(shaper_rule, 1, Opts) of
{value, {_, S}} -> S;
_ -> none
@@ -384,12 +373,30 @@ send_element(StateData, El) ->
new_id() -> randoms:get_string().
+transform_listen_option({hosts, Hosts, O}, Opts) ->
+ case lists:keyfind(hosts, 1, Opts) of
+ {_, PrevHostOpts} ->
+ NewHostOpts =
+ lists:foldl(
+ fun(H, Acc) ->
+ dict:append_list(H, O, Acc)
+ end, dict:from_list(PrevHostOpts), Hosts),
+ [{hosts, dict:to_list(NewHostOpts)}|
+ lists:keydelete(hosts, 1, Opts)];
+ _ ->
+ [{hosts, [{H, O} || H <- Hosts]}|Opts]
+ end;
+transform_listen_option({host, Host, Os}, Opts) ->
+ transform_listen_option({hosts, [Host], Os}, Opts);
+transform_listen_option(Opt, Opts) ->
+ [Opt|Opts].
+
fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) ->
[{max_queue, N}];
_ ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];
diff --git a/src/ejabberd_system_monitor.erl b/src/ejabberd_system_monitor.erl
index 2f5d1c330..92a41b9d8 100644
--- a/src/ejabberd_system_monitor.erl
+++ b/src/ejabberd_system_monitor.erl
@@ -53,7 +53,7 @@
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
- LH = ejabberd_config:get_local_option(
+ LH = ejabberd_config:get_option(
watchdog_large_heap,
fun(I) when is_integer(I), I > 0 -> I end,
1000000),
@@ -200,7 +200,7 @@ send_message(From, To, Body) ->
[{xmlcdata, Body}]}]}).
get_admin_jids() ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
watchdog_admins,
fun(JIDs) ->
[jlib:jid_tolower(
diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl
index 8a2bacf15..4506455bd 100644
--- a/src/ejabberd_web_admin.erl
+++ b/src/ejabberd_web_admin.erl
@@ -827,14 +827,14 @@ process_admin(Host,
{value, {_, String}} ->
case parse_access_rule(String) of
{ok, Rs} ->
- ejabberd_config:add_global_option({access, Name, Host},
+ ejabberd_config:add_option({access, Name, Host},
Rs),
ok;
_ -> error
end;
_ -> nothing
end,
- Rules = case ejabberd_config:get_global_option(
+ Rules = case ejabberd_config:get_option(
{access, Name, Host}, fun(V) -> V end)
of
undefined -> [];
@@ -1198,7 +1198,7 @@ access_parse_addnew(_AccessRules, Host, Query) ->
case lists:keysearch(<<"namenew">>, 1, Query) of
{value, {_, String}} when String /= <<"">> ->
Name = jlib:binary_to_atom(String),
- ejabberd_config:add_global_option({access, Name, Host},
+ ejabberd_config:add_option({access, Name, Host},
[]),
ok
end.
diff --git a/src/eldap_utils.erl b/src/eldap_utils.erl
index 6209802a8..a18a04ed6 100644
--- a/src/eldap_utils.erl
+++ b/src/eldap_utils.erl
@@ -182,7 +182,7 @@ get_opt({Key, Host}, Opts, F) ->
get_opt({Key, Host}, Opts, F, Default) ->
case gen_mod:get_opt(Key, Opts, F, undefined) of
undefined ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{Key, Host}, F, Default);
Val ->
Val
diff --git a/src/extauth.erl b/src/extauth.erl
index 23a409ce5..e57ac0b8d 100644
--- a/src/extauth.erl
+++ b/src/extauth.erl
@@ -106,7 +106,7 @@ random_instance(MaxNum) ->
random:uniform(MaxNum) - 1.
get_instances(Server) ->
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{extauth_instances, Server},
fun(V) when is_integer(V), V > 0 ->
V
diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl
index d53971fe4..628c1c90c 100644
--- a/src/gen_iq_handler.erl
+++ b/src/gen_iq_handler.erl
@@ -33,7 +33,7 @@
%% API
-export([start_link/3, add_iq_handler/6,
remove_iq_handler/3, stop_iq_handler/3, handle/7,
- process_iq/6, check_type/1]).
+ process_iq/6, check_type/1, transform_module_options/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
@@ -46,7 +46,7 @@
-record(state, {host, module, function}).
-type component() :: ejabberd_sm | ejabberd_local.
--type type() :: no_queue | one_queue | {queues, pos_integer()} | parallel.
+-type type() :: no_queue | one_queue | pos_integer() | parallel.
-type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
%%====================================================================
@@ -71,7 +71,7 @@ add_iq_handler(Component, Host, NS, Module, Function,
[Host, Module, Function]),
Component:register_iq_handler(Host, NS, Module,
Function, {one_queue, Pid});
- {queues, N} ->
+ N when is_integer(N) ->
Pids = lists:map(fun (_) ->
{ok, Pid} =
supervisor:start_child(ejabberd_iq_sup,
@@ -130,9 +130,19 @@ process_iq(_Host, Module, Function, From, To, IQ) ->
check_type(no_queue) -> no_queue;
check_type(one_queue) -> one_queue;
-check_type({queues, N}) when is_integer(N), N>0 -> {queues, N};
+check_type(N) when is_integer(N), N>0 -> N;
check_type(parallel) -> parallel.
+-spec transform_module_options([{atom(), any()}]) -> [{atom(), any()}].
+
+transform_module_options(Opts) ->
+ lists:map(
+ fun({iqdisc, {queues, N}}) ->
+ {iqdisc, N};
+ (Opt) ->
+ Opt
+ end, Opts).
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index 5245dc65c..0b06529b5 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -64,13 +64,11 @@ start() ->
-spec start_module(binary(), atom(), opts()) -> any().
start_module(Host, Module, Opts) ->
- set_module_opts_mnesia(Host, Module, Opts),
ets:insert(ejabberd_modules,
#ejabberd_module{module_host = {Module, Host},
opts = Opts}),
try Module:start(Host, Opts) catch
Class:Reason ->
- del_module_mnesia(Host, Module),
ets:delete(ejabberd_modules, {Module, Host}),
ErrorText =
io_lib:format("Problem starting the module ~p for host "
@@ -101,7 +99,7 @@ is_app_running(AppName) ->
stop_module(Host, Module) ->
case stop_module_keep_config(Host, Module) of
error -> error;
- ok -> del_module_mnesia(Host, Module)
+ ok -> ok
end.
%% @doc Stop the module in a host, but keep its configuration.
@@ -232,25 +230,6 @@ loaded_modules_with_opts(Host) ->
opts = '$2'},
[], [{{'$1', '$2'}}]}]).
-set_module_opts_mnesia(Host, Module, Opts) ->
- Modules = ejabberd_config:get_local_option(
- {modules, Host},
- fun(Ls) when is_list(Ls) -> Ls end,
- []),
- Modules1 = lists:keydelete(Module, 1, Modules),
- Modules2 = [{Module, Opts} | Modules1],
- ejabberd_config:add_local_option({modules, Host},
- Modules2).
-
-del_module_mnesia(Host, Module) ->
- Modules = ejabberd_config:get_local_option(
- {modules, Host},
- fun(Ls) when is_list(Ls) -> Ls end,
- []),
- Modules1 = lists:keydelete(Module, 1, Modules),
- ejabberd_config:add_local_option({modules, Host},
- Modules1).
-
-spec get_hosts(opts(), binary()) -> [binary()].
get_hosts(Opts, Prefix) ->
diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl
index 9c2ab319b..087d090c8 100644
--- a/src/mod_carboncopy.erl
+++ b/src/mod_carboncopy.erl
@@ -3,7 +3,7 @@
%%% Author : Eric Cestari <ecestari@process-one.net>
%%% Purpose : Message Carbons XEP-0280 0.8
%%% Created : 5 May 2008 by Mickael Remond <mremond@process-one.net>
-%%% Usage : Add the following line in modules section of ejabberd.cfg:
+%%% Usage : Add the following line in modules section of ejabberd.yml:
%%% {mod_carboncopy, []}
%%%
%%%
diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl
index e3fbe82dc..375621441 100644
--- a/src/mod_configure2.erl
+++ b/src/mod_configure2.erl
@@ -129,7 +129,7 @@ process_get(#xmlel{name = <<"info">>}) ->
children = []}};
process_get(#xmlel{name = <<"welcome-message">>,
attrs = Attrs}) ->
- {Subj, Body} = ejabberd_config:get_local_option(
+ {Subj, Body} = ejabberd_config:get_option(
welcome_message,
fun({Subj, Body}) ->
{iolist_to_binary(Subj),
@@ -145,7 +145,7 @@ process_get(#xmlel{name = <<"welcome-message">>,
children = [{xmlcdata, Body}]}]}};
process_get(#xmlel{name = <<"registration-watchers">>,
attrs = Attrs}) ->
- SubEls = ejabberd_config:get_local_option(
+ SubEls = ejabberd_config:get_option(
registration_watchers,
fun(JIDs) when is_list(JIDs) ->
lists:map(
diff --git a/src/mod_disco.erl b/src/mod_disco.erl
index d62251686..df3f320c7 100644
--- a/src/mod_disco.erl
+++ b/src/mod_disco.erl
@@ -36,7 +36,8 @@
process_sm_iq_items/3, process_sm_iq_info/3,
get_sm_identity/5, get_sm_features/5, get_sm_items/5,
get_info/5, register_feature/2, unregister_feature/2,
- register_extra_domain/2, unregister_extra_domain/2]).
+ register_extra_domain/2, unregister_extra_domain/2,
+ transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -440,6 +441,22 @@ get_user_resources(User, Server) ->
end,
lists:sort(Rs)).
+transform_module_options(Opts) ->
+ lists:map(
+ fun({server_info, Infos}) ->
+ NewInfos = lists:map(
+ fun({Modules, Name, URLs}) ->
+ [[{modules, Modules},
+ {name, Name},
+ {urls, URLs}]];
+ (Opt) ->
+ Opt
+ end, Infos),
+ {server_info, NewInfos};
+ (Opt) ->
+ Opt
+ end, Opts).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Support for: XEP-0157 Contact Addresses for XMPP Services
@@ -465,9 +482,17 @@ get_info(_A, Host, Mod, Node, _Lang) when Node == <<>> ->
get_info(Acc, _, _, _Node, _) -> Acc.
get_fields_xml(Host, Module) ->
- Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info,
- fun(L) when is_list(L) -> L end,
- []),
+ Fields = gen_mod:get_module_opt(
+ Host, ?MODULE, server_info,
+ fun(L) ->
+ lists:map(
+ fun(Opts) ->
+ Mods = proplists:get_value(modules, Opts, all),
+ Name = proplists:get_value(names, Opts, <<>>),
+ URLs = proplists:get_value(urls, Opts, []),
+ {Mods, Name, URLs}
+ end, lists:flatmap(L))
+ end, []),
Fields_good = lists:filter(fun ({Modules, _, _}) ->
case Modules of
all -> true;
diff --git a/src/mod_last.erl b/src/mod_last.erl
index 3ea86b350..6e35938d2 100644
--- a/src/mod_last.erl
+++ b/src/mod_last.erl
@@ -32,7 +32,8 @@
-export([start/2, stop/1, process_local_iq/3, export/1,
process_sm_iq/3, on_presence_update/4, import/1, import/3,
- store_last_info/4, get_last_info/2, remove_user/2]).
+ store_last_info/4, get_last_info/2, remove_user/2,
+ transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -101,18 +102,13 @@ process_local_iq(_From, _To,
%% @doc Get the uptime of the ejabberd node, expressed in seconds.
%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime.
get_node_uptime() ->
- case ejabberd_config:get_local_option(
+ case ejabberd_config:get_option(
node_start,
- fun({MegaSecs, Secs, MicroSecs} = Now)
- when is_integer(MegaSecs), MegaSecs >= 0,
- is_integer(Secs), Secs >= 0,
- is_integer(MicroSecs), MicroSecs >= 0 ->
- Now
- end) of
+ fun(S) when is_integer(S), S >= 0 -> S end) of
undefined ->
trunc(element(1, erlang:statistics(wall_clock)) / 1000);
- StartNow ->
- now_to_seconds(now()) - now_to_seconds(StartNow)
+ Now ->
+ now_to_seconds(now()) - Now
end.
now_to_seconds({MegaSecs, Secs, _MicroSecs}) ->
@@ -319,3 +315,13 @@ import(_LServer, mnesia, #last_activity{} = LA) ->
mnesia:dirty_write(LA);
import(_, _, _) ->
pass.
+
+transform_options(Opts) ->
+ lists:foldl(fun transform_options/2, [], Opts).
+
+transform_options({node_start, {_, _, _} = Now}, Opts) ->
+ ?WARNING_MSG("Old 'node_start' format detected. This is still supported "
+ "but it is better to fix your config.", []),
+ [{node_start, now_to_seconds(Now)}|Opts];
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl
index 97d992145..357d19216 100644
--- a/src/mod_muc_log.erl
+++ b/src/mod_muc_log.erl
@@ -33,7 +33,7 @@
-behaviour(gen_mod).
%% API
--export([start_link/2, start/2, stop/1,
+-export([start_link/2, start/2, stop/1, transform_module_options/1,
check_access_log/2, add_to_log/5]).
%% gen_server callbacks
@@ -111,6 +111,14 @@ check_access_log(Host, From) ->
Res -> Res
end.
+transform_module_options(Opts) ->
+ lists:map(
+ fun({top_link, {S1, S2}}) ->
+ {top_link, [{S1, S2}]};
+ (Opt) ->
+ Opt
+ end, Opts).
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
@@ -152,14 +160,14 @@ init([Host, Opts]) ->
(universal) -> universal
end, local),
Top_link = gen_mod:get_opt(top_link, Opts,
- fun({S1, S2}) ->
+ fun([{S1, S2}]) ->
{iolist_to_binary(S1),
iolist_to_binary(S2)}
end, {<<"/">>, <<"Home">>}),
NoFollow = gen_mod:get_opt(spam_prevention, Opts,
fun(B) when is_boolean(B) -> B end,
true),
- Lang = ejabberd_config:get_local_option(
+ Lang = ejabberd_config:get_option(
{language, Host},
fun iolist_to_binary/1,
?MYLANG),
diff --git a/src/mod_proxy65.erl b/src/mod_proxy65.erl
index 3e8354caf..85bec283b 100644
--- a/src/mod_proxy65.erl
+++ b/src/mod_proxy65.erl
@@ -33,7 +33,7 @@
-behaviour(supervisor).
%% gen_mod callbacks.
--export([start/2, stop/1]).
+-export([start/2, stop/1, transform_module_options/1]).
%% supervisor callbacks.
-export([init/1]).
@@ -64,6 +64,9 @@ start_link(Host, Opts) ->
supervisor:start_link({local, Proc}, ?MODULE,
[Host, Opts]).
+transform_module_options(Opts) ->
+ mod_proxy65_service:transform_module_options(Opts).
+
init([Host, Opts]) ->
Service = {mod_proxy65_service,
{mod_proxy65_service, start_link, [Host, Opts]},
diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl
index 7d16e0f17..33d40b1cc 100644
--- a/src/mod_proxy65_service.erl
+++ b/src/mod_proxy65_service.erl
@@ -35,7 +35,7 @@
handle_cast/2, terminate/2, code_change/3]).
%% API.
--export([start_link/2, add_listener/2,
+-export([start_link/2, add_listener/2, transform_module_options/1,
delete_listener/1]).
-include("ejabberd.hrl").
@@ -261,16 +261,15 @@ parse_options(ServerHost, Opts) ->
Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1,
<<"SOCKS5 Bytestreams">>),
IP = gen_mod:get_opt(ip, Opts,
- fun(Addr) ->
- jlib:ip_to_list(Addr),
+ fun(S) ->
+ {ok, Addr} = inet_parse:address(
+ binary_to_list(
+ iolist_to_binary(S))),
Addr
end, get_my_ip()),
HostName = gen_mod:get_opt(hostname, Opts,
- fun(Addr) when is_tuple(Addr) ->
- jlib:ip_to_list(Addr);
- (S) ->
- iolist_to_binary(S)
- end, jlib:ip_to_list(IP)),
+ fun iolist_to_binary/1,
+ jlib:ip_to_list(IP)),
StreamAddr = [{<<"jid">>, MyHost},
{<<"host">>, HostName},
{<<"port">>, jlib:integer_to_binary(Port)}],
@@ -278,6 +277,16 @@ parse_options(ServerHost, Opts) ->
name = Name, port = Port, ip = IP,
stream_addr = StreamAddr, acl = ACL}.
+transform_module_options(Opts) ->
+ lists:map(
+ fun({ip, IP}) when is_tuple(IP) ->
+ {ip, jlib:ip_to_list(IP)};
+ ({hostname, IP}) when is_tuple(IP) ->
+ {hostname, jlib:ip_to_list(IP)};
+ (Opt) ->
+ Opt
+ end, Opts).
+
get_my_ip() ->
{ok, MyHostName} = inet:gethostname(),
case inet:getaddr(MyHostName, inet) of
diff --git a/src/mod_proxy65_stream.erl b/src/mod_proxy65_stream.erl
index 9b861f4db..b37dcc13a 100644
--- a/src/mod_proxy65_stream.erl
+++ b/src/mod_proxy65_stream.erl
@@ -279,10 +279,14 @@ select_auth_method(anonymous, AuthMethods) ->
%% Obviously, we must use shaper with maximum rate.
find_maxrate(Shaper, JID1, JID2, Host) ->
- MaxRate1 = shaper:new(acl:match_rule(Host, Shaper,
- JID1)),
- MaxRate2 = shaper:new(acl:match_rule(Host, Shaper,
- JID2)),
+ MaxRate1 = case acl:match_rule(Host, Shaper, JID1) of
+ deny -> none;
+ R1 -> shaper:new(R1)
+ end,
+ MaxRate2 = case acl:match_rule(Host, Shaper, JID2) of
+ deny -> none;
+ R2 -> shaper:new(R2)
+ end,
if MaxRate1 == none; MaxRate2 == none -> none;
true -> lists:max([MaxRate1, MaxRate2])
end.
diff --git a/src/mod_register.erl b/src/mod_register.erl
index 2b4e53de6..197927df0 100644
--- a/src/mod_register.erl
+++ b/src/mod_register.erl
@@ -32,7 +32,8 @@
-export([start/2, stop/1, stream_feature_register/2,
unauthenticated_iq_register/4, try_register/5,
- process_iq/3, send_registration_notifications/3]).
+ process_iq/3, send_registration_notifications/3,
+ transform_options/1, transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -418,7 +419,11 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
send_welcome_message(JID) ->
Host = JID#jid.lserver,
case gen_mod:get_module_opt(Host, ?MODULE, welcome_message,
- fun({S, B}) ->
+ fun(Opts) ->
+ S = proplists:get_value(
+ subject, Opts, <<>>),
+ B = proplists:get_value(
+ body, Opts, <<>>),
{iolist_to_binary(S),
iolist_to_binary(B)}
end, {<<"">>, <<"">>})
@@ -483,7 +488,7 @@ check_from(JID, Server) ->
check_timeout(undefined) -> true;
check_timeout(Source) ->
- Timeout = ejabberd_config:get_local_option(
+ Timeout = ejabberd_config:get_option(
registration_timeout,
fun(TO) when is_integer(TO), TO > 0 ->
TO;
@@ -537,7 +542,7 @@ clean_treap(Treap, CleanPriority) ->
remove_timeout(undefined) -> true;
remove_timeout(Source) ->
- Timeout = ejabberd_config:get_local_option(
+ Timeout = ejabberd_config:get_option(
registration_timeout,
fun(TO) when is_integer(TO), TO > 0 ->
TO;
@@ -604,6 +609,54 @@ is_strong_password(Server, Password) ->
ejabberd_auth:entropy(Password) >= Entropy
end.
+transform_options(Opts) ->
+ Opts1 = transform_ip_access(Opts),
+ transform_module_options(Opts1).
+
+transform_ip_access(Opts) ->
+ try
+ {value, {modules, ModOpts}, Opts1} = lists:keytake(modules, 1, Opts),
+ {value, {?MODULE, RegOpts}, ModOpts1} = lists:keytake(?MODULE, 1, ModOpts),
+ {value, {ip_access, L}, RegOpts1} = lists:keytake(ip_access, 1, RegOpts),
+ true = is_list(L),
+ ?WARNING_MSG("Old 'ip_access' format detected. "
+ "The old format is still supported "
+ "but it is better to fix your config: "
+ "use access rules instead.", []),
+ ACLs = lists:flatmap(
+ fun({Action, S}) ->
+ ACLName = jlib:binary_to_atom(
+ iolist_to_binary(
+ ["ip_", S])),
+ [{Action, ACLName},
+ {acl, ACLName, {ip, S}}]
+ end, L),
+ Access = {access, mod_register_networks,
+ [{Action, ACLName} || {Action, ACLName} <- ACLs]},
+ [ACL || {acl, _, _} = ACL <- ACLs] ++
+ [Access,
+ {modules,
+ [{mod_register,
+ [{ip_access, mod_register_networks}|RegOpts1]}
+ | ModOpts1]}|Opts1]
+ catch error:{badmatch, false} ->
+ Opts
+ end.
+
+transform_module_options(Opts) ->
+ lists:flatmap(
+ fun({welcome_message, {Subj, Body}}) ->
+ ?WARNING_MSG("Old 'welcome_message' format detected. "
+ "The old format is still supported "
+ "but it is better to fix your config: "
+ "change it to {welcome_message, "
+ "[{subject, Subject}, {body, Body}]}",
+ []),
+ [{welcome_message, [{subject, Subj}, {body, Body}]}];
+ (Opt) ->
+ [Opt]
+ end, Opts).
+
%%%
%%% ip_access management
%%%
@@ -614,75 +667,15 @@ may_remove_resource(From) -> From.
get_ip_access(Host) ->
gen_mod:get_module_opt(Host, ?MODULE, ip_access,
- fun(IPAccess) ->
- lists:flatmap(
- fun({Access, S}) ->
- {ok, IP, Mask} =
- parse_ip_netmask(
- iolist_to_binary(S)),
- [{Access, IP, Mask}]
- end, IPAccess)
- end, []).
-
-parse_ip_netmask(S) ->
- case str:tokens(S, <<"/">>) of
- [IPStr] ->
- case inet_parse:address(binary_to_list(IPStr)) of
- {ok, {_, _, _, _} = IP} -> {ok, IP, 32};
- {ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
- _ -> error
- end;
- [IPStr, MaskStr] ->
- case catch jlib:binary_to_integer(MaskStr) of
- Mask when is_integer(Mask), Mask >= 0 ->
- case inet_parse:address(binary_to_list(IPStr)) of
- {ok, {_, _, _, _} = IP} when Mask =< 32 ->
- {ok, IP, Mask};
- {ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
- {ok, IP, Mask};
- _ -> error
- end;
- _ -> error
- end;
- _ -> error
- end.
+ fun(A) when is_atom(A) -> A end,
+ all).
-check_ip_access(_Source, []) -> allow;
check_ip_access({User, Server, Resource}, IPAccess) ->
case ejabberd_sm:get_user_ip(User, Server, Resource) of
- {IPAddress, _PortNumber} ->
- check_ip_access(IPAddress, IPAccess);
- _ -> true
- end;
-check_ip_access({_, _, _, _} = IP,
- [{Access, {_, _, _, _} = Net, Mask} | IPAccess]) ->
- IPInt = ip_to_integer(IP),
- NetInt = ip_to_integer(Net),
- M = bnot (1 bsl (32 - Mask) - 1),
- if IPInt band M =:= NetInt band M -> Access;
- true -> check_ip_access(IP, IPAccess)
- end;
-check_ip_access({_, _, _, _, _, _, _, _} = IP,
- [{Access, {_, _, _, _, _, _, _, _} = Net, Mask}
- | IPAccess]) ->
- IPInt = ip_to_integer(IP),
- NetInt = ip_to_integer(Net),
- M = bnot (1 bsl (128 - Mask) - 1),
- if IPInt band M =:= NetInt band M -> Access;
- true -> check_ip_access(IP, IPAccess)
+ {IPAddress, _PortNumber} ->
+ check_ip_access(IPAddress, IPAccess);
+ _ ->
+ deny
end;
-check_ip_access(IP, [_ | IPAccess]) ->
- check_ip_access(IP, IPAccess).
-
-ip_to_integer({IP1, IP2, IP3, IP4}) ->
- IP1 bsl 8 bor IP2 bsl 8 bor IP3 bsl 8 bor IP4;
-ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7,
- IP8}) ->
- IP1 bsl 16 bor IP2 bsl 16 bor IP3 bsl 16 bor IP4 bsl 16
- bor IP5
- bsl 16
- bor IP6
- bsl 16
- bor IP7
- bsl 16
- bor IP8.
+check_ip_access(IPAddress, IPAccess) ->
+ acl:match_rule(global, IPAccess, IPAddress).
diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl
index 7711353d2..1c96dd4a1 100644
--- a/src/mod_vcard_ldap.erl
+++ b/src/mod_vcard_ldap.erl
@@ -38,7 +38,7 @@
-export([start/2, start_link/2, stop/1,
get_sm_features/5, process_local_iq/3, process_sm_iq/3,
- remove_user/1, route/4]).
+ remove_user/1, route/4, transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -767,7 +767,7 @@ parse_options(Host, Opts) ->
VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts,
fun(Ls) ->
lists:map(
- fun({S, P, L}) ->
+ fun({S, [{P, L}]}) ->
{iolist_to_binary(S),
iolist_to_binary(P),
[iolist_to_binary(E)
@@ -823,6 +823,20 @@ parse_options(Host, Opts) ->
search_reported_attrs = SearchReportedAttrs,
matches = Matches}.
+transform_module_options(Opts) ->
+ lists:map(
+ fun({ldap_vcard_map, Map}) ->
+ NewMap = lists:map(
+ fun({Field, Pattern, Attrs}) ->
+ {Field, [{Pattern, Attrs}]};
+ (Opt) ->
+ Opt
+ end, Map),
+ {ldap_vcard_map, NewMap};
+ (Opt) ->
+ Opt
+ end, Opts).
+
check_filter(F) ->
NewF = iolist_to_binary(F),
{ok, _} = eldap_filter:parse(NewF),
diff --git a/src/node_pep.erl b/src/node_pep.erl
index f4b0bb38c..5635dee94 100644
--- a/src/node_pep.erl
+++ b/src/node_pep.erl
@@ -490,13 +490,11 @@ path_to_node(Path) -> node_flat:path_to_node(Path).
%% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) ->
- Modules = ejabberd_config:get_local_option({modules, ServerHost}, fun(Ms) when is_list(Ms) -> Ms end),
- ModCaps = [mod_caps_enabled || {mod_caps, _Opts} <- Modules],
- case ModCaps of
- [] ->
+ case gen_mod:is_loaded(ServerHost, mod_caps) of
+ false ->
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
"of host ~p. This plugin requires mod_caps "
"to be enabled, but it isn't.",
[ServerHost]);
- _ -> ok
+ true -> ok
end.
diff --git a/src/node_pep_odbc.erl b/src/node_pep_odbc.erl
index 81cb7bc53..e4e1fafa9 100644
--- a/src/node_pep_odbc.erl
+++ b/src/node_pep_odbc.erl
@@ -433,7 +433,7 @@ path_to_node(Path) -> node_flat_odbc:path_to_node(Path).
%% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) ->
- Modules = ejabberd_config:get_local_option({modules,
+ Modules = ejabberd_config:get_option({modules,
ServerHost},
fun(Ms) when is_list(Ms) -> Ms end),
ModCaps = [mod_caps_enabled
diff --git a/src/odbc_queries.erl b/src/odbc_queries.erl
index 23b8e8da6..314b7cc13 100644
--- a/src/odbc_queries.erl
+++ b/src/odbc_queries.erl
@@ -219,13 +219,15 @@ list_users(LServer,
[Prefix, Limit, Offset]))]).
users_number(LServer) ->
- case element(1,
- ejabberd_config:get_local_option(
- {odbc_server, LServer}, fun(V) -> V end))
- of
+ Type = ejabberd_config:get_option({odbc_type, LServer},
+ fun(pgsql) -> pgsql;
+ (mysql) -> mysql;
+ (odbc) -> odbc
+ end, odbc),
+ case Type of
pgsql ->
case
- ejabberd_config:get_local_option(
+ ejabberd_config:get_option(
{pgsql_users_number_estimate, LServer},
fun(V) when is_boolean(V) -> V end,
false)
diff --git a/src/shaper.erl b/src/shaper.erl
index 37c1a30c9..41e5f0626 100644
--- a/src/shaper.erl
+++ b/src/shaper.erl
@@ -28,7 +28,8 @@
-author('alexey@process-one.net').
--export([new/1, new1/1, update/2]).
+-export([start/0, new/1, new1/1, update/2,
+ transform_options/1, load_from_config/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -37,32 +38,66 @@
lastrate = 0.0 :: float(),
lasttime = 0 :: integer()}).
--type maxrate() :: none | #maxrate{}.
+-record(shaper, {name :: {atom(), global},
+ maxrate :: integer()}).
--type shaper() :: maxrate() | {maxrate(), integer()}.
+-type shaper() :: none | #maxrate{}.
-export_type([shaper/0]).
--spec new(atom()) -> maxrate().
+-spec start() -> ok.
+start() ->
+ mnesia:create_table(shaper,
+ [{ram_copies, [node()]},
+ {local_content, true},
+ {attributes, record_info(fields, shaper)}]),
+ mnesia:add_table_copy(shaper, node(), ram_copies),
+ load_from_config(),
+ ok.
+
+-spec load_from_config() -> ok | {error, any()}.
+
+load_from_config() ->
+ Shapers = ejabberd_config:get_option(
+ shaper, fun(V) -> V end, []),
+ case mnesia:transaction(
+ fun() ->
+ lists:foreach(
+ fun({Name, MaxRate}) ->
+ mnesia:write(#shaper{name = {Name, global},
+ maxrate = MaxRate})
+ end, Shapers)
+ end) of
+ {atomic, ok} ->
+ ok;
+ Err ->
+ {error, Err}
+ end.
+
+-spec new(atom()) -> shaper().
+
+new(none) ->
+ none;
new(Name) ->
- Data = ejabberd_config:get_global_option(
- {shaper, Name, global},
- fun({maxrate, R}) when is_integer(R), R>0 ->
- {maxrate, R};
- (none) ->
- none
- end, none),
- new1(Data).
+ MaxRate = case ets:lookup(shaper, {Name, global}) of
+ [#shaper{maxrate = R}] ->
+ R;
+ [] ->
+ ?WARNING_MSG("Attempt to initialize an "
+ "unspecified shaper '~s'", [Name]),
+ none
+ end,
+ new1(MaxRate).
--spec new1(none | {maxrate, integer()}) -> maxrate().
+-spec new1(none | integer()) -> shaper().
new1(none) -> none;
-new1({maxrate, MaxRate}) ->
+new1(MaxRate) ->
#maxrate{maxrate = MaxRate, lastrate = 0.0,
lasttime = now_to_usec(now())}.
--spec update(maxrate(), integer()) -> {maxrate(), integer()}.
+-spec update(shaper(), integer()) -> {shaper(), integer()}.
update(none, _Size) -> {none, 0};
update(#maxrate{} = State, Size) ->
@@ -84,5 +119,15 @@ update(#maxrate{} = State, Size) ->
lasttime = NextNow},
Pause}.
+transform_options(Opts) ->
+ lists:foldl(fun transform_options/2, [], Opts).
+
+transform_options({shaper, Name, {maxrate, N}}, Opts) ->
+ [{shaper, [{Name, N}]}|Opts];
+transform_options({shaper, Name, none}, Opts) ->
+ [{shaper, [{Name, none}]}|Opts];
+transform_options(Opt, Opts) ->
+ [Opt|Opts].
+
now_to_usec({MSec, Sec, USec}) ->
(MSec * 1000000 + Sec) * 1000000 + USec.