aboutsummaryrefslogtreecommitdiff
path: root/src/mod_roster.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_roster.erl')
-rw-r--r--src/mod_roster.erl308
1 files changed, 163 insertions, 145 deletions
diff --git a/src/mod_roster.erl b/src/mod_roster.erl
index d313c2415..426589319 100644
--- a/src/mod_roster.erl
+++ b/src/mod_roster.erl
@@ -48,7 +48,7 @@
out_subscription/1, set_items/3, remove_user/2,
get_jid_info/4, encode_item/1, webadmin_page/3,
webadmin_user/4, get_versioning_feature/2,
- roster_versioning_enabled/1, roster_version/2,
+ roster_version/2,
mod_opt_type/1, mod_options/1, set_roster/1, del_roster/3,
process_rosteritems/5,
depends/2, set_item_and_notify_clients/3]).
@@ -59,11 +59,13 @@
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-include("ejabberd_stacktrace.hrl").
+-include("translate.hrl").
-define(ROSTER_CACHE, roster_cache).
-define(ROSTER_ITEM_CACHE, roster_item_cache).
-define(ROSTER_VERSION_CACHE, roster_version_cache).
+-type c2s_state() :: ejabberd_c2s:state().
-export_type([subscription/0]).
-callback init(binary(), gen_mod:opts()) -> any().
@@ -75,7 +77,7 @@
-callback read_subscription_and_groups(binary(), binary(), ljid())
-> {ok, {subscription(), ask(), [binary()]}} | error.
-callback roster_subscribe(binary(), binary(), ljid(), #roster{}) -> any().
--callback transaction(binary(), function()) -> {atomic, any()} | {aborted, any()}.
+-callback transaction(binary(), fun(() -> T)) -> {atomic, T} | {aborted, any()}.
-callback remove_user(binary(), binary()) -> any().
-callback update_roster(binary(), binary(), ljid(), #roster{}) -> any().
-callback del_roster(binary(), binary(), ljid()) -> any().
@@ -85,7 +87,7 @@
-optional_callbacks([use_cache/2, cache_nodes/1]).
start(Host, Opts) ->
- Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
+ Mod = gen_mod:db_mod(Opts, ?MODULE),
Mod:init(Host, Opts),
init_cache(Mod, Host, Opts),
ejabberd_hooks:add(roster_get, Host, ?MODULE,
@@ -132,8 +134,8 @@ stop(Host) ->
?NS_ROSTER).
reload(Host, NewOpts, OldOpts) ->
- NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE),
- OldMod = gen_mod:db_mod(Host, OldOpts, ?MODULE),
+ NewMod = gen_mod:db_mod(NewOpts, ?MODULE),
+ OldMod = gen_mod:db_mod(OldOpts, ?MODULE),
if NewMod /= OldMod ->
NewMod:init(Host, NewOpts);
true ->
@@ -144,6 +146,7 @@ reload(Host, NewOpts, OldOpts) ->
depends(_Host, _Opts) ->
[].
+-spec process_iq(iq()) -> iq().
process_iq(#iq{from = #jid{luser = U, lserver = S},
to = #jid{luser = U, lserver = S}} = IQ) ->
process_local_iq(IQ);
@@ -151,31 +154,32 @@ process_iq(#iq{lang = Lang, to = To} = IQ) ->
case ejabberd_hooks:run_fold(roster_remote_access,
To#jid.lserver, false, [IQ]) of
false ->
- Txt = <<"Query to another users is forbidden">>,
+ Txt = ?T("Query to another users is forbidden"),
xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang));
true ->
process_local_iq(IQ)
end.
+-spec process_local_iq(iq()) -> iq().
process_local_iq(#iq{type = set,lang = Lang,
sub_els = [#roster_query{
items = [#roster_item{ask = Ask}]}]} = IQ)
when Ask /= undefined ->
- Txt = <<"Possessing 'ask' attribute is not allowed by RFC6121">>,
+ Txt = ?T("Possessing 'ask' attribute is not allowed by RFC6121"),
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
process_local_iq(#iq{type = set, from = From, lang = Lang,
sub_els = [#roster_query{
items = [#roster_item{} = Item]}]} = IQ) ->
case has_duplicated_groups(Item#roster_item.groups) of
true ->
- Txt = <<"Duplicated groups are not allowed by RFC6121">>,
+ Txt = ?T("Duplicated groups are not allowed by RFC6121"),
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
false ->
#jid{lserver = LServer} = From,
- Access = gen_mod:get_module_opt(LServer, ?MODULE, access),
+ Access = mod_roster_opt:access(LServer),
case acl:match_rule(LServer, Access, From) of
deny ->
- Txt = <<"Access denied by service policy">>,
+ Txt = ?T("Access denied by service policy"),
xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
allow ->
process_iq_set(IQ)
@@ -183,7 +187,7 @@ process_local_iq(#iq{type = set, from = From, lang = Lang,
end;
process_local_iq(#iq{type = set, lang = Lang,
sub_els = [#roster_query{items = [_|_]}]} = IQ) ->
- Txt = <<"Multiple <item/> elements are not allowed by RFC6121">>,
+ Txt = ?T("Multiple <item/> elements are not allowed by RFC6121"),
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
process_local_iq(#iq{type = get, lang = Lang,
sub_els = [#roster_query{items = Items}]} = IQ) ->
@@ -191,31 +195,26 @@ process_local_iq(#iq{type = get, lang = Lang,
[] ->
process_iq_get(IQ);
[_|_] ->
- Txt = <<"The query must not contain <item/> elements">>,
+ Txt = ?T("The query must not contain <item/> elements"),
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang))
end;
process_local_iq(#iq{lang = Lang} = IQ) ->
- Txt = <<"No module is handling this query">>,
+ Txt = ?T("No module is handling this query"),
xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)).
+-spec roster_hash([#roster{}]) -> binary().
roster_hash(Items) ->
str:sha(term_to_binary(lists:sort([R#roster{groups =
lists:sort(Grs)}
|| R = #roster{groups = Grs}
<- Items]))).
-roster_versioning_enabled(Host) ->
- gen_mod:get_module_opt(Host, ?MODULE, versioning).
-
-roster_version_on_db(Host) ->
- gen_mod:get_module_opt(Host, ?MODULE, store_current_id).
-
%% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled.
-spec get_versioning_feature([xmpp_element()], binary()) -> [xmpp_element()].
get_versioning_feature(Acc, Host) ->
case gen_mod:is_loaded(Host, ?MODULE) of
true ->
- case roster_versioning_enabled(Host) of
+ case mod_roster_opt:versioning(Host) of
true ->
[#rosterver_feature{}|Acc];
false ->
@@ -225,9 +224,10 @@ get_versioning_feature(Acc, Host) ->
Acc
end.
+-spec roster_version(binary(), binary()) -> undefined | binary().
roster_version(LServer, LUser) ->
US = {LUser, LServer},
- case roster_version_on_db(LServer) of
+ case mod_roster_opt:store_current_id(LServer) of
true ->
case read_roster_version(LUser, LServer) of
error -> undefined;
@@ -238,6 +238,7 @@ roster_version(LServer, LUser) ->
[], [US]))
end.
+-spec read_roster_version(binary(), binary()) -> {ok, binary()} | error.
read_roster_version(LUser, LServer) ->
ets_cache:lookup(
?ROSTER_VERSION_CACHE, {LUser, LServer},
@@ -246,12 +247,15 @@ read_roster_version(LUser, LServer) ->
Mod:read_roster_version(LUser, LServer)
end).
+-spec write_roster_version(binary(), binary()) -> binary().
write_roster_version(LUser, LServer) ->
write_roster_version(LUser, LServer, false).
+-spec write_roster_version_t(binary(), binary()) -> binary().
write_roster_version_t(LUser, LServer) ->
write_roster_version(LUser, LServer, true).
+-spec write_roster_version(binary(), binary(), boolean()) -> binary().
write_roster_version(LUser, LServer, InTransaction) ->
Ver = str:sha(term_to_binary(erlang:unique_integer())),
Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -269,62 +273,57 @@ write_roster_version(LUser, LServer, InTransaction) ->
%% - roster versioning is not used by the client OR
%% - roster versioning is used by server and client, BUT the server isn't storing versions on db OR
%% - the roster version from client don't match current version.
-process_iq_get(#iq{to = To, lang = Lang,
+-spec process_iq_get(iq()) -> iq().
+process_iq_get(#iq{to = To,
sub_els = [#roster_query{ver = RequestedVersion}]} = IQ) ->
LUser = To#jid.luser,
LServer = To#jid.lserver,
US = {LUser, LServer},
- try {ItemsToSend, VersionToSend} =
- case {roster_versioning_enabled(LServer),
- roster_version_on_db(LServer)} of
- {true, true} when RequestedVersion /= undefined ->
- case read_roster_version(LUser, LServer) of
- error ->
- RosterVersion = write_roster_version(LUser, LServer),
- {lists:map(fun encode_item/1,
- ejabberd_hooks:run_fold(
- roster_get, To#jid.lserver, [], [US])),
- RosterVersion};
- {ok, RequestedVersion} ->
- {false, false};
- {ok, NewVersion} ->
- {lists:map(fun encode_item/1,
- ejabberd_hooks:run_fold(
- roster_get, To#jid.lserver, [], [US])),
- NewVersion}
- end;
- {true, false} when RequestedVersion /= undefined ->
- RosterItems = ejabberd_hooks:run_fold(
- roster_get, To#jid.lserver, [], [US]),
- case roster_hash(RosterItems) of
- RequestedVersion ->
- {false, false};
- New ->
- {lists:map(fun encode_item/1, RosterItems), New}
- end;
- _ ->
- {lists:map(fun encode_item/1,
- ejabberd_hooks:run_fold(
- roster_get, To#jid.lserver, [], [US])),
- false}
- end,
- xmpp:make_iq_result(
- IQ,
- case {ItemsToSend, VersionToSend} of
- {false, false} ->
- undefined;
- {Items, false} ->
- #roster_query{items = Items};
- {Items, Version} ->
- #roster_query{items = Items,
- ver = Version}
- end)
- catch ?EX_RULE(E, R, St) ->
- ?ERROR_MSG("failed to process roster get for ~s: ~p",
- [jid:encode(To), {E, {R, ?EX_STACK(St)}}]),
- Txt = <<"Roster module has failed">>,
- xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang))
- end.
+ {ItemsToSend, VersionToSend} =
+ case {mod_roster_opt:versioning(LServer),
+ mod_roster_opt:store_current_id(LServer)} of
+ {true, true} when RequestedVersion /= undefined ->
+ case read_roster_version(LUser, LServer) of
+ error ->
+ RosterVersion = write_roster_version(LUser, LServer),
+ {lists:map(fun encode_item/1,
+ ejabberd_hooks:run_fold(
+ roster_get, To#jid.lserver, [], [US])),
+ RosterVersion};
+ {ok, RequestedVersion} ->
+ {false, false};
+ {ok, NewVersion} ->
+ {lists:map(fun encode_item/1,
+ ejabberd_hooks:run_fold(
+ roster_get, To#jid.lserver, [], [US])),
+ NewVersion}
+ end;
+ {true, false} when RequestedVersion /= undefined ->
+ RosterItems = ejabberd_hooks:run_fold(
+ roster_get, To#jid.lserver, [], [US]),
+ case roster_hash(RosterItems) of
+ RequestedVersion ->
+ {false, false};
+ New ->
+ {lists:map(fun encode_item/1, RosterItems), New}
+ end;
+ _ ->
+ {lists:map(fun encode_item/1,
+ ejabberd_hooks:run_fold(
+ roster_get, To#jid.lserver, [], [US])),
+ false}
+ end,
+ xmpp:make_iq_result(
+ IQ,
+ case {ItemsToSend, VersionToSend} of
+ {false, false} ->
+ undefined;
+ {Items, false} ->
+ #roster_query{items = Items};
+ {Items, Version} ->
+ #roster_query{items = Items,
+ ver = Version}
+ end).
-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}].
get_user_roster(Acc, {LUser, LServer}) ->
@@ -337,6 +336,7 @@ get_user_roster(Acc, {LUser, LServer}) ->
Items)
++ Acc.
+-spec get_roster(binary(), binary()) -> [#roster{}].
get_roster(LUser, LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
R = case use_cache(Mod, LServer, roster) of
@@ -352,6 +352,7 @@ get_roster(LUser, LServer) ->
error -> []
end.
+-spec get_roster_item(binary(), binary(), ljid()) -> #roster{}.
get_roster_item(LUser, LServer, LJID) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
case Mod:get_roster_item(LUser, LServer, LJID) of
@@ -363,6 +364,8 @@ get_roster_item(LUser, LServer, LJID) ->
us = {LUser, LServer}, jid = LBJID}
end.
+-spec get_subscription_and_groups(binary(), binary(), ljid()) ->
+ {subscription(), ask(), [binary()]}.
get_subscription_and_groups(LUser, LServer, LJID) ->
LBJID = jid:remove_resource(LJID),
Mod = gen_mod:db_mod(LServer, ?MODULE),
@@ -397,6 +400,7 @@ get_subscription_and_groups(LUser, LServer, LJID) ->
{none, none, []}
end.
+-spec set_roster(#roster{}) -> {atomic | aborted, any()}.
set_roster(#roster{us = {LUser, LServer}, jid = LJID} = Item) ->
transaction(
LUser, LServer, [LJID],
@@ -404,6 +408,7 @@ set_roster(#roster{us = {LUser, LServer}, jid = LJID} = Item) ->
update_roster_t(LUser, LServer, LJID, Item)
end).
+-spec del_roster(binary(), binary(), ljid()) -> {atomic | aborted, any()}.
del_roster(LUser, LServer, LJID) ->
transaction(
LUser, LServer, [LJID],
@@ -411,6 +416,7 @@ del_roster(LUser, LServer, LJID) ->
del_roster_t(LUser, LServer, LJID)
end).
+-spec encode_item(#roster{}) -> roster_item().
encode_item(Item) ->
#roster_item{jid = jid:make(Item#roster.jid),
name = Item#roster.name,
@@ -422,6 +428,7 @@ encode_item(Item) ->
end,
groups = Item#roster.groups}.
+-spec decode_item(roster_item(), #roster{}, boolean()) -> #roster{}.
decode_item(#roster_item{subscription = remove} = Item, R, _) ->
R#roster{jid = jid:tolower(Item#roster_item.jid),
name = <<"">>,
@@ -439,58 +446,58 @@ decode_item(Item, R, Managed) ->
end,
groups = Item#roster_item.groups}.
-process_iq_set(#iq{from = _From, to = To,
+-spec process_iq_set(iq()) -> iq().
+process_iq_set(#iq{from = _From, to = To, lang = Lang,
sub_els = [#roster_query{items = [QueryItem]}]} = IQ) ->
case set_item_and_notify_clients(To, QueryItem, false) of
ok ->
xmpp:make_iq_result(IQ);
- E ->
- ?ERROR_MSG("roster set failed:~nIQ = ~s~nError = ~p",
- [xmpp:pp(IQ), E]),
- xmpp:make_error(IQ, xmpp:err_internal_server_error())
+ {error, _} ->
+ Txt = ?T("Database failure"),
+ Err = xmpp:err_internal_server_error(Txt, Lang),
+ xmpp:make_error(IQ, Err)
end.
--spec set_item_and_notify_clients(jid(), #roster_item{}, boolean()) -> ok | error.
+-spec set_item_and_notify_clients(jid(), #roster_item{}, boolean()) -> ok | {error, any()}.
set_item_and_notify_clients(To, #roster_item{jid = PeerJID} = RosterItem,
OverrideSubscription) ->
#jid{luser = LUser, lserver = LServer} = To,
PeerLJID = jid:tolower(PeerJID),
F = fun () ->
- Item = get_roster_item(LUser, LServer, PeerLJID),
- Item2 = decode_item(RosterItem, Item, OverrideSubscription),
- Item3 = ejabberd_hooks:run_fold(roster_process_item,
- LServer, Item2,
- [LServer]),
- case Item3#roster.subscription of
- remove -> del_roster_t(LUser, LServer, PeerLJID);
- _ -> update_roster_t(LUser, LServer, PeerLJID, Item3)
- end,
- case roster_version_on_db(LServer) of
- true -> write_roster_version_t(LUser, LServer);
- false -> ok
- end,
- {Item, Item3}
+ Item1 = get_roster_item(LUser, LServer, PeerLJID),
+ Item2 = decode_item(RosterItem, Item1, OverrideSubscription),
+ Item3 = ejabberd_hooks:run_fold(roster_process_item,
+ LServer, Item2,
+ [LServer]),
+ case Item3#roster.subscription of
+ remove -> del_roster_t(LUser, LServer, PeerLJID);
+ _ -> update_roster_t(LUser, LServer, PeerLJID, Item3)
+ end,
+ case mod_roster_opt:store_current_id(LServer) of
+ true -> write_roster_version_t(LUser, LServer);
+ false -> ok
+ end,
+ {Item1, Item3}
end,
case transaction(LUser, LServer, [PeerLJID], F) of
- {atomic, {OldItem, Item}} ->
- push_item(To, OldItem, Item),
- case Item#roster.subscription of
+ {atomic, {OldItem, NewItem}} ->
+ push_item(To, OldItem, NewItem),
+ case NewItem#roster.subscription of
remove ->
send_unsubscribing_presence(To, OldItem);
_ ->
ok
- end,
- ok;
- E ->
- E
+ end;
+ {aborted, Reason} ->
+ {error, Reason}
end.
+-spec push_item(jid(), #roster{}, #roster{}) -> ok.
push_item(To, OldItem, NewItem) ->
#jid{luser = LUser, lserver = LServer} = To,
- Ver = case roster_versioning_enabled(LServer) of
+ Ver = case mod_roster_opt:versioning(LServer) of
true -> roster_version(LServer, LUser);
- false -> undefined;
- undefined -> undefined
+ false -> undefined
end,
lists:foreach(
fun(Resource) ->
@@ -498,6 +505,7 @@ push_item(To, OldItem, NewItem) ->
push_item(To1, OldItem, NewItem, Ver)
end, ejabberd_sm:get_user_resources(LUser, LServer)).
+-spec push_item(jid(), #roster{}, #roster{}, undefined | binary()) -> ok.
push_item(To, OldItem, NewItem, Ver) ->
route_presence_change(To, OldItem, NewItem),
IQ = #iq{type = set, to = To,
@@ -536,14 +544,17 @@ route_presence_change(From, OldItem, NewItem) ->
ok
end.
+-spec ask_to_pending(ask()) -> none | in | out | both.
ask_to_pending(subscribe) -> out;
ask_to_pending(unsubscribe) -> none;
ask_to_pending(Ask) -> Ask.
+-spec roster_subscribe_t(binary(), binary(), ljid(), #roster{}) -> any().
roster_subscribe_t(LUser, LServer, LJID, Item) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:roster_subscribe(LUser, LServer, LJID, Item).
+-spec transaction(binary(), binary(), [ljid()], fun(() -> T)) -> {atomic, T} | {aborted, any()}.
transaction(LUser, LServer, LJIDs, F) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
case Mod:transaction(LServer, F) of
@@ -569,6 +580,9 @@ out_subscription(#presence{from = From, to = JID, type = Type}) ->
#jid{user = User, server = Server} = From,
process_subscription(out, User, Server, JID, Type, <<"">>).
+-spec process_subscription(in | out, binary(), binary(), jid(),
+ subscribe | subscribed | unsubscribe | unsubscribed,
+ binary()) -> boolean().
process_subscription(Direction, User, Server, JID1,
Type, Reason) ->
LUser = jid:nodeprep(User),
@@ -606,7 +620,7 @@ process_subscription(Direction, User, Server, JID1,
ask = Pending,
askmessage = AskMessage},
roster_subscribe_t(LUser, LServer, LJID, NewItem),
- case roster_version_on_db(LServer) of
+ case mod_roster_opt:store_current_id(LServer) of
true -> write_roster_version_t(LUser, LServer);
false -> ok
end,
@@ -767,6 +781,7 @@ remove_user(User, Server) ->
%% For each contact with Subscription:
%% Both or From, send a "unsubscribed" presence stanza;
%% Both or To, send a "unsubscribe" presence stanza.
+-spec send_unsubscription_to_rosteritems(binary(), binary(), [#roster{}]) -> ok.
send_unsubscription_to_rosteritems(LUser, LServer, RosterItems) ->
From = jid:make({LUser, LServer, <<"">>}),
lists:foreach(fun (RosterItem) ->
@@ -774,6 +789,7 @@ send_unsubscription_to_rosteritems(LUser, LServer, RosterItems) ->
end,
RosterItems).
+-spec send_unsubscribing_presence(jid(), #roster{}) -> ok.
send_unsubscribing_presence(From, Item) ->
IsTo = case Item#roster.subscription of
both -> true;
@@ -798,12 +814,11 @@ send_unsubscribing_presence(From, Item) ->
from = jid:remove_resource(From),
to = jid:make(Item#roster.jid)});
true -> ok
- end,
- ok.
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec set_items(binary(), binary(), roster_query()) -> any().
+-spec set_items(binary(), binary(), roster_query()) -> {atomic, ok} | {aborted, any()}.
set_items(User, Server, #roster_query{items = Items}) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
@@ -816,14 +831,17 @@ set_items(User, Server, #roster_query{items = Items}) ->
end,
transaction(LUser, LServer, LJIDs, F).
+-spec update_roster_t(binary(), binary(), ljid(), #roster{}) -> any().
update_roster_t(LUser, LServer, LJID, Item) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:update_roster(LUser, LServer, LJID, Item).
+-spec del_roster_t(binary(), binary(), ljid()) -> any().
del_roster_t(LUser, LServer, LJID) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:del_roster(LUser, LServer, LJID).
+-spec process_item_set_t(binary(), binary(), roster_item()) -> any().
process_item_set_t(LUser, LServer, #roster_item{jid = JID1} = QueryItem) ->
JID = {JID1#jid.user, JID1#jid.server, <<>>},
LJID = {JID1#jid.luser, JID1#jid.lserver, <<>>},
@@ -836,8 +854,7 @@ process_item_set_t(LUser, LServer, #roster_item{jid = JID1} = QueryItem) ->
end;
process_item_set_t(_LUser, _LServer, _) -> ok.
--spec c2s_self_presence({presence(), ejabberd_c2s:state()})
- -> {presence(), ejabberd_c2s:state()}.
+-spec c2s_self_presence({presence(), c2s_state()}) -> {presence(), c2s_state()}.
c2s_self_presence({_, #{pres_last := _}} = Acc) ->
Acc;
c2s_self_presence({#presence{type = available} = Pkt, State}) ->
@@ -851,7 +868,7 @@ c2s_self_presence({#presence{type = available} = Pkt, State}) ->
c2s_self_presence(Acc) ->
Acc.
--spec resend_pending_subscriptions(ejabberd_c2s:state()) -> ejabberd_c2s:state().
+-spec resend_pending_subscriptions(c2s_state()) -> c2s_state().
resend_pending_subscriptions(#{jid := JID} = State) ->
BareJID = jid:remove_resource(JID),
Result = get_roster(JID#jid.luser, JID#jid.lserver),
@@ -927,16 +944,16 @@ user_roster(User, Server, Query, Lang) ->
Items = get_roster(LUser, LServer),
SItems = lists:sort(Items),
FItems = case SItems of
- [] -> [?CT(<<"None">>)];
+ [] -> [?CT(?T("None"))];
_ ->
[?XE(<<"table">>,
[?XE(<<"thead">>,
[?XE(<<"tr">>,
- [?XCT(<<"td">>, <<"Jabber ID">>),
- ?XCT(<<"td">>, <<"Nickname">>),
- ?XCT(<<"td">>, <<"Subscription">>),
- ?XCT(<<"td">>, <<"Pending">>),
- ?XCT(<<"td">>, <<"Groups">>)])]),
+ [?XCT(<<"td">>, ?T("Jabber ID")),
+ ?XCT(<<"td">>, ?T("Nickname")),
+ ?XCT(<<"td">>, ?T("Subscription")),
+ ?XCT(<<"td">>, ?T("Pending")),
+ ?XCT(<<"td">>, ?T("Groups"))])]),
?XE(<<"tbody">>,
(lists:map(fun (R) ->
Groups = lists:flatmap(fun
@@ -974,7 +991,7 @@ user_roster(User, Server, Query, Lang) ->
[?INPUTT(<<"submit">>,
<<"validate",
(ejabberd_web_admin:term_to_id(R#roster.jid))/binary>>,
- <<"Validate">>)]);
+ ?T("Validate"))]);
true -> ?X(<<"td">>)
end,
?XAE(<<"td">>,
@@ -983,16 +1000,16 @@ user_roster(User, Server, Query, Lang) ->
[?INPUTT(<<"submit">>,
<<"remove",
(ejabberd_web_admin:term_to_id(R#roster.jid))/binary>>,
- <<"Remove">>)])])
+ ?T("Remove"))])])
end,
SItems)))])]
end,
[?XC(<<"h1">>,
- (<<(?T(<<"Roster of ">>))/binary, (us_to_list(US))/binary>>))]
+ (<<(translate:translate(Lang, ?T("Roster of ")))/binary, (us_to_list(US))/binary>>))]
++
case Res of
- ok -> [?XREST(<<"Submitted">>)];
- error -> [?XREST(<<"Bad format">>)];
+ ok -> [?XREST(?T("Submitted"))];
+ error -> [?XREST(?T("Bad format"))];
nothing -> []
end
++
@@ -1002,7 +1019,7 @@ user_roster(User, Server, Query, Lang) ->
[?P, ?INPUT(<<"text">>, <<"newjid">>, <<"">>),
?C(<<" ">>),
?INPUTT(<<"submit">>, <<"addjid">>,
- <<"Add Jabber ID">>)]))].
+ ?T("Add Jabber ID"))]))].
build_contact_jid_td(RosterJID) ->
ContactJID = jid:make(RosterJID),
@@ -1011,7 +1028,7 @@ build_contact_jid_td(RosterJID) ->
of
{<<"">>, _} -> <<"">>;
{CUser, CServer} ->
- case lists:member(CServer, ejabberd_config:get_myhosts()) of
+ case lists:member(CServer, ejabberd_option:hosts()) of
false -> <<"">>;
true ->
<<"/admin/server/", CServer/binary, "/user/",
@@ -1102,9 +1119,10 @@ us_to_list({User, Server}) ->
webadmin_user(Acc, _User, _Server, Lang) ->
Acc ++
- [?XE(<<"h3">>, [?ACT(<<"roster/">>, <<"Roster">>)])].
+ [?XE(<<"h3">>, [?ACT(<<"roster/">>, ?T("Roster"))])].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec has_duplicated_groups([binary()]) -> boolean().
has_duplicated_groups(Groups) ->
GroupsPrep = lists:usort([jid:resourceprep(G) || G <- Groups]),
not (length(GroupsPrep) == length(Groups)).
@@ -1129,19 +1147,16 @@ init_cache(Mod, Host, Opts) ->
-spec cache_opts(gen_mod:opts()) -> [proplists:property()].
cache_opts(Opts) ->
- MaxSize = gen_mod:get_opt(cache_size, Opts),
- CacheMissed = gen_mod:get_opt(cache_missed, Opts),
- LifeTime = case gen_mod:get_opt(cache_life_time, Opts) of
- infinity -> infinity;
- I -> timer:seconds(I)
- end,
+ MaxSize = mod_roster_opt:cache_size(Opts),
+ CacheMissed = mod_roster_opt:cache_missed(Opts),
+ LifeTime = mod_roster_opt:cache_life_time(Opts),
[{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
-spec use_cache(module(), binary(), roster | roster_version) -> boolean().
use_cache(Mod, Host, Table) ->
case erlang:function_exported(Mod, use_cache, 2) of
true -> Mod:use_cache(Host, Table);
- false -> gen_mod:get_module_opt(Host, ?MODULE, use_cache)
+ false -> mod_roster_opt:use_cache(Host)
end.
-spec cache_nodes(module(), binary()) -> [node()].
@@ -1215,25 +1230,28 @@ import(LServer, {sql, _}, DBType, <<"roster_version">>, [LUser, Ver]) ->
Mod:import(LServer, <<"roster_version">>, [LUser, Ver]).
mod_opt_type(access) ->
- fun acl:access_rules_validator/1;
-mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
+ econf:acl();
mod_opt_type(store_current_id) ->
- fun (B) when is_boolean(B) -> B end;
+ econf:bool();
mod_opt_type(versioning) ->
- fun (B) when is_boolean(B) -> B end;
-mod_opt_type(O) when O == cache_life_time; O == cache_size ->
- fun (I) when is_integer(I), I > 0 -> I;
- (infinity) -> infinity
- end;
-mod_opt_type(O) when O == use_cache; O == cache_missed ->
- fun (B) when is_boolean(B) -> B end.
+ econf:bool();
+mod_opt_type(db_type) ->
+ econf:db_type(?MODULE);
+mod_opt_type(use_cache) ->
+ econf:bool();
+mod_opt_type(cache_size) ->
+ econf:pos_int(infinity);
+mod_opt_type(cache_missed) ->
+ econf:bool();
+mod_opt_type(cache_life_time) ->
+ econf:timeout(second, infinity).
mod_options(Host) ->
[{access, all},
{store_current_id, false},
{versioning, false},
{db_type, ejabberd_config:default_db(Host, ?MODULE)},
- {use_cache, ejabberd_config:use_cache(Host)},
- {cache_size, ejabberd_config:cache_size(Host)},
- {cache_missed, ejabberd_config:cache_missed(Host)},
- {cache_life_time, ejabberd_config:cache_life_time(Host)}].
+ {use_cache, ejabberd_option:use_cache(Host)},
+ {cache_size, ejabberd_option:cache_size(Host)},
+ {cache_missed, ejabberd_option:cache_missed(Host)},
+ {cache_life_time, ejabberd_option:cache_life_time(Host)}].