diff --git a/include/mod_roster.hrl b/include/mod_roster.hrl index a35666d6d9..a24c7dda16 100644 --- a/include/mod_roster.hrl +++ b/include/mod_roster.hrl @@ -18,12 +18,12 @@ %%% %%%---------------------------------------------------------------------- --record(roster, {usj, - us, - jid, - name = <<>>, +-record(roster, {usj :: {jid:luser(), jid:lserver(), jid:simple_jid()}, + us :: {jid:luser(), jid:lserver()}, + jid :: jid:simple_jid(), + name = <<>> :: binary(), subscription = none :: both | from | to | none | remove, - ask = none, + ask = none :: subscribe | unsubscribe | in | out | both | none, groups = [], askmessage = <<>>, xs = []}). diff --git a/src/admin_extra/service_admin_extra_roster.erl b/src/admin_extra/service_admin_extra_roster.erl index fb8ccb5a44..29aae1a86e 100644 --- a/src/admin_extra/service_admin_extra_roster.erl +++ b/src/admin_extra/service_admin_extra_roster.erl @@ -26,16 +26,15 @@ -module(service_admin_extra_roster). -author('badlop@process-one.net'). -export([ - commands/0, - - add_rosteritem/7, - delete_rosteritem/4, - process_rosteritems/5, - get_roster/2, - push_roster/3, - push_roster_all/1, - push_alltoall/2 - ]). + commands/0, + add_rosteritem/7, + delete_rosteritem/4, + process_rosteritems/5, + get_roster/2, + push_roster/3, + push_roster_all/1, + push_alltoall/2 + ]). -include("mongoose.hrl"). -include("ejabberd_commands.hrl"). @@ -164,12 +163,13 @@ commands() -> Subs :: subs()) -> {Res, string()} when Res :: user_doest_not_exist | error | bad_subs | ok. add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> - JID = jid:make(LocalUser, LocalServer, <<>>), - case ejabberd_auth:does_user_exist(JID) of + LocalJID = jid:make(LocalUser, LocalServer, <<>>), + case ejabberd_auth:does_user_exist(LocalJID) of true -> - case subscribe(LocalUser, LocalServer, User, Server, Nick, Group, Subs, []) of + RemoteJID = jid:make(User, Server, <<>>), + case subscribe(LocalJID, RemoteJID, Nick, Group, Subs, []) of {atomic, _} -> - do_add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs); + do_add_rosteritem(LocalJID, RemoteJID, Nick, Group, Subs); Other -> {error, io_lib:format("~p", [Other])} end; @@ -179,11 +179,11 @@ add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> [LocalUser, LocalServer])} end. -do_add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> +do_add_rosteritem(LocalJID, RemoteJID, Nick, Group, Subs) -> case lists:member(Subs, possible_subs_binary()) of true -> - push_roster_item(LocalUser, LocalServer, User, Server, {add, Nick, Subs, Group}), - {ok, io_lib:format("Added the item to the roster of ~s@~s", [LocalUser, LocalServer])}; + push_roster_item(LocalJID, RemoteJID, {add, Nick, Subs, Group}), + {ok, io_lib:format("Added the item to the roster of ~s", [jid:to_binary(LocalJID)])}; false -> {bad_subs, io_lib:format("Sub ~s is incorrect." " Choose one of the following:~nnone~nfrom~nto~nboth", @@ -192,20 +192,18 @@ do_add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> %% @doc returns result of mnesia or rdbms transaction --spec subscribe(LocalUser :: jid:user(), - LocalServer :: jid:server(), - User :: jid:user(), - Server :: jid:server(), +-spec subscribe(LocalJID :: jid:jid(), + RemoteJID :: jid:jid(), Nick :: binary(), Group :: binary() | string(), Subs :: subs(), _Xattrs :: [jlib:binary_pair()]) -> any(). -subscribe(LU, LS, User, Server, Nick, Group, SubscriptionS, _Xattrs) -> - ItemEl = build_roster_item(User, Server, {add, Nick, SubscriptionS, Group}), +subscribe(LocalJID, RemoteJID, Nick, Group, SubscriptionS, _Xattrs) -> + ItemEl = build_roster_item(RemoteJID, {add, Nick, SubscriptionS, Group}), QueryEl = #xmlel{ name = <<"query">>, attrs = [{<<"xmlns">>, <<"jabber:iq:roster">>}], children = [ItemEl]}, - mod_roster:set_items(LU, LS, QueryEl). + mod_roster:set_items(LocalJID, QueryEl). -spec delete_rosteritem(LocalUser :: jid:user(), @@ -214,14 +212,15 @@ subscribe(LU, LS, User, Server, Nick, Group, SubscriptionS, _Xattrs) -> Server :: jid:server()) -> {Res, string()} when Res :: ok | error | user_does_not_exist. delete_rosteritem(LocalUser, LocalServer, User, Server) -> - JID = jid:make(LocalUser, LocalServer, <<>>), - case ejabberd_auth:does_user_exist(JID) of + LocalJID = jid:make(LocalUser, LocalServer, <<>>), + case ejabberd_auth:does_user_exist(LocalJID) of true -> - case unsubscribe(LocalUser, LocalServer, User, Server) of + RemoteJID = jid:make(User, Server, <<>>), + case unsubscribe(LocalJID, RemoteJID) of {atomic, ok} -> - push_roster_item(LocalUser, LocalServer, User, Server, remove), - {ok, io_lib:format("The item removed from roster of ~s@~s", - [LocalUser, LocalServer])}; + push_roster_item(LocalJID, RemoteJID, remove), + {ok, io_lib:format("The item removed from roster of ~s", + [jid:to_binary(LocalJID)])}; Other -> {error, io_lib:format("~p", [Other])} end; @@ -233,16 +232,13 @@ delete_rosteritem(LocalUser, LocalServer, User, Server) -> %% @doc returns result of mnesia or rdbms transaction --spec unsubscribe(LocalUser :: jid:user(), - LocalServer :: jid:server(), - User :: jid:user(), - Server :: jid:server()) -> any(). -unsubscribe(LU, LS, User, Server) -> - ItemEl = build_roster_item(User, Server, remove), +-spec unsubscribe(LocalJID :: jid:jid(), RemoteJID :: jid:jid()) -> any(). +unsubscribe(LocalJID, RemoteJID) -> + ItemEl = build_roster_item(RemoteJID, remove), QueryEl = #xmlel{ name = <<"query">>, attrs = [{<<"xmlns">>, <<"jabber:iq:roster">>}], children = [ItemEl]}, - mod_roster:set_items(LU, LS, QueryEl). + mod_roster:set_items(LocalJID, QueryEl). %% ----------------------------- %% Get Roster @@ -325,7 +321,9 @@ subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) - subscribe_roster({Name, Server, Group, Nick}, Roster); %% Subscribe Name2 to Name1 subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} | Roster]) -> - subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, <<"both">>, []), + subscribe(jid:make(Name1, Server1, <<>>), + jid:make(Name2, Server2, <<>>), + Nick2, Group2, <<"both">>, []), subscribe_roster({Name1, Server1, Group1, Nick1}, Roster). @@ -346,42 +344,35 @@ build_list_users(Group, [{User, Server}|Users], Res) -> build_list_users(Group, Users, [{User, Server, Group, User}|Res]). -%% @spec(LU, LS, U, S, Action) -> ok +%% @spec(LocalJID, RemoteJID, Action) -> ok %% Action = {add, Nick, Subs, Group} | remove %% @doc Push to the roster of account LU@LS the contact U@S. %% The specific action to perform is defined in Action. --spec push_roster_item(jid:luser(), jid:lserver(), jid:user(), - jid:server(), Action :: push_action()) -> 'ok'. -push_roster_item(LU, LS, U, S, Action) -> - JID = jid:make(LU, LS, <<>>), +-spec push_roster_item(jid:jid(), jid:jid(), Action :: push_action()) -> 'ok'. +push_roster_item(JID, #jid{luser = U, lserver = S} = RemJID, Action) -> lists:foreach(fun(R) -> RJID = jid:replace_resource(JID, R), - push_roster_item(RJID, U, S, Action) + BroadcastEl = build_broadcast(U, S, Action), + ejabberd_sm:route(RJID, RJID, BroadcastEl), + Item = build_roster_item(RemJID, Action), + ResIQ = build_iq_roster_push(Item), + ejabberd_router:route(RJID, RJID, ResIQ) end, ejabberd_sm:get_user_resources(JID)). - --spec push_roster_item(jid:jid(), jid:user(), jid:server(), Action :: push_action()) -> - mongoose_acc:t(). -push_roster_item(JID, U, S, Action) -> - BroadcastEl = build_broadcast(U, S, Action), - ejabberd_sm:route(JID, JID, BroadcastEl), - Item = build_roster_item(U, S, Action), - ResIQ = build_iq_roster_push(Item), - ejabberd_router:route(JID, JID, ResIQ). - --spec build_roster_item(jid:user(), jid:server(), push_action() - ) -> exml:element(). -build_roster_item(U, S, {add, Nick, Subs, Group}) -> +-spec build_roster_item(jid:jid(), push_action()) -> exml:element(). +build_roster_item(#jid{resource = <<>>} = JID, {add, Nick, Subs, Group}) -> #xmlel{ name = <<"item">>, - attrs = [{<<"jid">>, jid:to_binary(jid:make(U, S, <<"">>))}, + attrs = [{<<"jid">>, jid:to_binary(JID)}, {<<"name">>, Nick}, {<<"subscription">>, Subs}], children = [#xmlel{name = <<"group">>, children = [#xmlcdata{content = Group}]}] }; -build_roster_item(U, S, remove) -> +build_roster_item(#jid{resource = <<>>} = JID, remove) -> #xmlel{ name = <<"item">>, - attrs = [{<<"jid">>, jid:to_binary(jid:make(U, S, <<"">>))}, - {<<"subscription">>, <<"remove">>}]}. + attrs = [{<<"jid">>, jid:to_binary(JID)}, + {<<"subscription">>, <<"remove">>}]}; +build_roster_item(#jid{} = JID, Action) -> + build_roster_item(jid:replace_resource(JID, <<>>), Action). -spec build_iq_roster_push(jlib:xmlcdata() | exml:element()) -> exml:element(). diff --git a/src/auth/ejabberd_auth.erl b/src/auth/ejabberd_auth.erl index 497bb8ba9b..4014482bf0 100644 --- a/src/auth/ejabberd_auth.erl +++ b/src/auth/ejabberd_auth.erl @@ -375,7 +375,6 @@ get_passterm_with_authmodule(#jid{luser = LUser, lserver = LServer}) -> %% @doc Returns true if the user exists in the DB or if an anonymous user is %% logged under the given name - -spec does_user_exist(JID :: jid:jid() | error) -> boolean(). does_user_exist(#jid{luser = LUser, lserver = LServer}) -> timed_call(LServer, does_user_exist, fun does_user_exist_timed/2, [LUser, LServer]); diff --git a/src/mod_commands.erl b/src/mod_commands.erl index f3f49b8193..1e07167d88 100644 --- a/src/mod_commands.erl +++ b/src/mod_commands.erl @@ -360,11 +360,8 @@ add_contact(Caller, JabberID, Name) -> add_contact(Caller, Other, Name, Groups) -> case parse_from_to(Caller, Other) of - {ok, CallerJid, _OtherJid} -> - case mod_roster:set_roster_entry(CallerJid, jid_to_binary(Other), Name, Groups) of - ok -> ok; - error -> {error, internal, "set roster entry failed"} - end; + {ok, CallerJid, OtherJid} -> + mod_roster:set_roster_entry(CallerJid, OtherJid, Name, Groups); E -> E end. @@ -383,17 +380,19 @@ maybe_delete_contacts(Caller, [H | T], NotDeleted) -> delete_contact(Caller, Other) -> case parse_from_to(Caller, Other) of - {ok, CallerJid, _OtherJid} -> - case jid_exists(CallerJid, jid_to_binary(Other)) of + {ok, CallerJid, OtherJid} -> + case jid_exists(CallerJid, OtherJid) of false -> error; true -> - mod_roster:remove_from_roster(CallerJid, jid_to_binary(Other)) - end + mod_roster:remove_from_roster(CallerJid, OtherJid) + end; + E -> + E end. --spec jid_exists(jid:jid(), binary()) -> boolean(). -jid_exists(UserJid, Contact) -> - Res = mod_roster:get_roster_entry(UserJid#jid.luser, UserJid#jid.lserver, Contact), +-spec jid_exists(jid:jid(), jid:jid()) -> boolean(). +jid_exists(CallerJid, OtherJid) -> + Res = mod_roster:get_roster_entry(CallerJid, OtherJid), Res =/= does_not_exist. registered_commands() -> @@ -553,8 +552,3 @@ parse_jid(Jid) when is_binary(Jid) -> error -> {error, io_lib:format("Invalid jid: ~p", [Jid])}; B -> B end. - -jid_to_binary(#jid{} = Jid) -> jid:to_binary(Jid); -jid_to_binary(B) when is_binary(B) -> B; -jid_to_binary(undefined) -> undefined. - diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 8bcb7fe949..ff8a9f9f91 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -46,15 +46,13 @@ process_local_iq/4, get_user_roster/2, get_subscription_lists/3, + get_roster_entry/2, get_roster_entry/3, - get_roster_entry/4, - get_roster_entry_t/3, - get_roster_entry_t/4, get_roster/2, item_to_map/1, in_subscription/6, out_subscription/5, - set_items/3, + set_items/2, set_roster_entry/4, remove_user/2, % for tests remove_user/3, @@ -62,13 +60,12 @@ get_jid_info/4, item_to_xml/1, get_versioning_feature/2, - roster_versioning_enabled/1, roster_version/2 - ]). + ]). -export([remove_test_user/2, transaction/2, - process_subscription_transaction/6, + process_subscription_transaction/5, get_user_rosters_length/2]). % for testing -export([get_personal_data/2]). @@ -226,18 +223,14 @@ hooks(Host) -> {roster_get_versioning_feature, Host, ?MODULE, get_versioning_feature, 50}, {get_personal_data, Host, ?MODULE, get_personal_data, 50}]. -get_roster_entry(LUser, LServer, Jid) -> - mod_roster_backend:get_roster_entry(jid:nameprep(LUser), LServer, jid_arg_to_lower(Jid)). +get_roster_entry(#jid{luser = LUser, lserver = LServer}, Jid) -> + mod_roster_backend:get_roster_entry(LUser, LServer, jid_arg_to_lower(Jid)). -get_roster_entry(LUser, LServer, Jid, full) -> - mod_roster_backend:get_roster_entry(jid:nameprep(LUser), LServer, jid_arg_to_lower(Jid), full). +get_roster_entry(#jid{luser = LUser, lserver = LServer}, Jid, full) -> + mod_roster_backend:get_roster_entry(LUser, LServer, jid_arg_to_lower(Jid), full). -get_roster_entry_t(LUser, LServer, Jid) -> - mod_roster_backend:get_roster_entry_t(jid:nameprep(LUser), LServer, jid_arg_to_lower(Jid)). - -get_roster_entry_t(LUser, LServer, Jid, full) -> - mod_roster_backend:get_roster_entry_t(jid:nameprep(LUser), LServer, - jid_arg_to_lower(Jid), full). +get_roster_entry_t(#jid{luser = LUser, lserver = LServer}, Jid, full) -> + mod_roster_backend:get_roster_entry_t(LUser, LServer, jid_arg_to_lower(Jid), full). -spec jid_arg_to_lower(JID :: jid:simple_jid() | jid:jid() | binary()) -> error | jid:simple_jid(). @@ -247,6 +240,8 @@ jid_arg_to_lower(Jid) when is_binary(Jid) -> jid_arg_to_lower(Jid) -> jid:to_lower(Jid). +-spec process_iq(jid:jid(), jid:jid(), mongoose_acc:t(), jlib:iq()) -> + {mongoose_acc:t(), jlib:iq()}. process_iq(From, To, Acc, IQ) -> #iq{sub_el = SubEl} = IQ, #jid{lserver = LServer} = From, @@ -257,6 +252,8 @@ process_iq(From, To, Acc, IQ) -> {Acc, IQ#iq{type = error, sub_el = [SubEl, mongoose_xmpp_errors:item_not_found()]}} end. +-spec process_local_iq(jid:jid(), jid:jid(), mongoose_acc:t(), jlib:iq()) -> + {mongoose_acc:t(), jlib:iq()}. process_local_iq(From, To, Acc, #iq{type = Type} = IQ) -> case Type of set -> @@ -270,9 +267,11 @@ roster_hash(Items) -> R = #roster{groups = Grs} <- Items], sha:sha1_hex(term_to_binary(lists:sort(L))). +-spec roster_versioning_enabled(jid:lserver()) -> boolean(). roster_versioning_enabled(Host) -> gen_mod:get_module_opt(Host, ?MODULE, versioning, false). +-spec roster_version_on_db(jid:lserver()) -> boolean(). roster_version_on_db(Host) -> gen_mod:get_module_opt(Host, ?MODULE, store_current_id, false). @@ -319,21 +318,19 @@ write_roster_version(LUser, LServer, InTransaction) -> %% - 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. +-spec process_iq_get(jid:jid(), jid:jid(), jlib:iq()) -> jlib:iq(). process_iq_get(From, To, IQ) -> mongoose_iq:try_to_handle_iq(From, To, IQ, fun do_process_iq_get/3). -do_process_iq_get(From, To, #iq{sub_el = SubEl} = IQ) -> - LServer = From#jid.lserver, +-spec do_process_iq_get(jid:jid(), jid:jid(), jlib:iq()) -> jlib:iq(). +do_process_iq_get(#jid{lserver = LServer} = From, To, #iq{sub_el = SubEl} = IQ) -> AttrVer = exml_query:attr(SubEl, <<"ver">>), %% type binary() | undefined VersioningRequested = is_binary(AttrVer), VersioningEnabled = roster_versioning_enabled(LServer), VersionOnDb = roster_version_on_db(LServer), - Strategy = choose_get_user_roster_strategy( - VersioningRequested, VersioningEnabled, VersionOnDb), - {ItemsToSend, VersionToSend} = - get_user_roster_based_on_version(Strategy, AttrVer, From, To), - IQ#iq{type = result, - sub_el = create_sub_el(ItemsToSend, VersionToSend)}. + Strategy = choose_get_user_roster_strategy(VersioningRequested, VersioningEnabled, VersionOnDb), + {ItemsToSend, VersionToSend} = get_user_roster_based_on_version(Strategy, AttrVer, From, To), + IQ#iq{type = result, sub_el = create_sub_el(ItemsToSend, VersionToSend)}. -spec choose_get_user_roster_strategy(VersioningRequested :: boolean(), VersioningEnabled :: boolean(), @@ -370,8 +367,7 @@ get_user_roster_db_versioning(RequestedVersion, From, To) get_user_roster_hash_versioning(RequestedVersion, From, To) when is_binary(RequestedVersion) -> - RosterItems = get_roster_old(To#jid.lserver, From#jid.luser, - From#jid.lserver), + RosterItems = get_roster_old(To#jid.lserver, From#jid.luser, From#jid.lserver), case roster_hash(RosterItems) of RequestedVersion -> {false, false}; @@ -397,9 +393,7 @@ create_sub_el(Items, Version) -> {<<"ver">>, Version}], children = Items}]. --spec get_user_roster(mongoose_acc:t(), - {jid:luser(), jid:lserver()}) -> - mongoose_acc:t(). +-spec get_user_roster(mongoose_acc:t(), {jid:luser(), jid:lserver()}) -> mongoose_acc:t(). get_user_roster(Acc, {LUser, LServer}) -> case mongoose_acc:get(roster, show_full_roster, false, Acc) of true -> @@ -445,41 +439,39 @@ item_to_xml(Item) -> #xmlel{name = <<"item">>, attrs = Attrs4, children = SubEls}. +-spec process_iq_set(jid:jid(), jid:jid(), jlib:iq()) -> jlib:iq(). process_iq_set(#jid{lserver = LServer} = From, To, #iq{sub_el = SubEl} = IQ) -> #xmlel{children = Els} = SubEl, mongoose_hooks:roster_set(LServer, ok, From, To, SubEl), lists:foreach(fun(El) -> process_item_set(From, To, El) end, Els), IQ#iq{type = result, sub_el = []}. +-spec process_item_set(jid:jid(), jid:jid(), exml:element()) -> ok. process_item_set(From, To, #xmlel{attrs = Attrs} = El) -> JID1 = jid:from_binary(xml:get_attr_s(<<"jid">>, Attrs)), do_process_item_set(JID1, From, To, El); process_item_set(_From, _To, _) -> ok. +-spec do_process_item_set(error | jid:jid(), jid:jid(), jid:jid(), exml:element()) -> ok. do_process_item_set(error, _, _, _) -> ok; -do_process_item_set(JID1, - #jid{user = User, luser = LUser, lserver = LServer} = From, - To, +do_process_item_set(#jid{} = JID1, #jid{} = From, #jid{} = To, #xmlel{attrs = Attrs, children = Els}) -> - LJID = jid:to_lower(JID1), MakeItem2 = fun(Item) -> Item1 = process_item_attrs(Item, Attrs), process_item_els(Item1, Els) end, - set_roster_item(User, LUser, LServer, LJID, From, To, MakeItem2). + set_roster_item(JID1, From, To, MakeItem2). %% @doc this is run when a roster item is to be added, updated or removed %% the interface of this func could probably be a bit simpler --spec set_roster_item(User :: binary(), - LUser :: binary(), - LServer :: binary(), - LJID :: jid:simple_jid() | error, - From ::jid:jid(), - To ::jid:jid(), +-spec set_roster_item(JID1 :: jid:jid(), + From :: jid:jid(), + To :: jid:jid(), MakeItem2 :: fun( (roster()) -> roster())) -> ok. -set_roster_item(User, LUser, LServer, LJID, From, To, MakeItem2) -> - F = fun () -> - Item = case get_roster_entry(LUser, LServer, LJID) of +set_roster_item(JID1, #jid{luser = LUser, lserver = LServer} = From, To, MakeItem2) -> + LJID = jid:to_lower(JID1), + F = fun() -> + Item = case get_roster_entry(From, LJID) of does_not_exist -> #roster{usj = {LUser, LServer, LJID}, us = {LUser, LServer}, @@ -501,7 +493,7 @@ set_roster_item(User, LUser, LServer, LJID, From, To, MakeItem2) -> end, case transaction(LServer, F) of {atomic, {OldItem, NewItem}} -> - push_item(User, LServer, To, NewItem), + push_item(From, To, NewItem), case NewItem#roster.subscription of remove -> send_unsubscribing_presence(From, OldItem), ok; @@ -516,7 +508,7 @@ process_item_attrs(Item, [{<<"jid">>, Val} | Attrs]) -> error -> process_item_attrs(Item, Attrs); JID1 -> - JID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}, + JID = jid:to_lower(JID1), process_item_attrs(Item#roster{jid = JID}, Attrs) end; process_item_attrs(Item, [{<<"name">>, Val} | Attrs]) -> @@ -549,26 +541,29 @@ process_item_els(Item, [{xmlcdata, _} | Els]) -> process_item_els(Item, Els); process_item_els(Item, []) -> Item. -push_item(User, Server, From, Item) -> - #jid{luser = LUser} = JID = jid:make(User, Server, <<"">>), - ejabberd_sm:route(jid:make(<<"">>, <<"">>, <<"">>), JID, +push_item(#jid{luser = LUser, lserver = LServer} = JID, From, Item) -> + ejabberd_sm:route(jid:make_noprep(<<>>, <<>>, <<>>), JID, {broadcast, {item, Item#roster.jid, Item#roster.subscription}}), - case roster_versioning_enabled(Server) of + case roster_versioning_enabled(LServer) of true -> - push_item_version(JID, Server, User, From, Item, - roster_version(Server, LUser)); + push_item_version(JID, From, Item, roster_version(LServer, LUser)); false -> - lists:foreach(fun (Resource) -> - push_item(User, Server, Resource, From, Item) + lists:foreach(fun(Resource) -> + push_item_without_version(JID, Resource, From, Item) end, ejabberd_sm:get_user_resources(JID)) end. -push_item(User, Server, Resource, From, Item) -> +push_item_without_version(#jid{lserver = Server} = JID, Resource, From, Item) -> mongoose_hooks:roster_push(Server, ok, From, Item), - push_item(User, Server, Resource, From, Item, not_found). + push_item_final(jid:replace_resource(JID, Resource), From, Item, not_found). + +push_item_version(JID, From, Item, RosterVersion) -> + lists:foreach(fun(Resource) -> + push_item_final(jid:replace_resource(JID, Resource), From, Item, RosterVersion) + end, ejabberd_sm:get_user_resources(JID)). -push_item(User, Server, Resource, From, Item, RosterVersion) -> +push_item_final(JID, From, Item, RosterVersion) -> ExtraAttrs = case RosterVersion of not_found -> []; _ -> [{<<"ver">>, RosterVersion}] @@ -581,26 +576,14 @@ push_item(User, Server, Resource, From, Item, RosterVersion) -> [#xmlel{name = <<"query">>, attrs = [{<<"xmlns">>, ?NS_ROSTER} | ExtraAttrs], children = [item_to_xml(Item)]}]}, - ejabberd_router:route(From, - jid:make(User, Server, Resource), - jlib:iq_to_xml(ResIQ)). - -push_item_version(JID, Server, User, From, Item, - RosterVersion) -> - lists:foreach(fun (Resource) -> - push_item(User, Server, Resource, From, Item, - RosterVersion) - end, - ejabberd_sm:get_user_resources(JID)). + ejabberd_router:route(From, JID, jlib:iq_to_xml(ResIQ)). -spec get_subscription_lists(Acc :: mongoose_acc:t(), User :: binary(), Server :: binary()) -> mongoose_acc:t(). get_subscription_lists(Acc, User, Server) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), + #jid{luser = LUser, lserver = LServer} = JID = jid:make(User, Server, <<>>), Items = mod_roster_backend:get_subscription_lists(Acc, LUser, LServer), - JID = jid:make(User, Server, <<>>), SubLists = fill_subscription_lists(JID, LServer, Items, [], [], []), mongoose_acc:set(roster, subscription_lists, SubLists, Acc). @@ -660,31 +643,32 @@ transaction(LServer, F) -> -spec in_subscription(Acc:: mongoose_acc:t(), User :: binary(), Server :: binary(), - JID ::jid:jid(), + JID :: jid:jid(), Type :: sub_presence(), Reason :: any()) -> mongoose_acc:t(). in_subscription(Acc, User, Server, JID, Type, Reason) -> - Res = process_subscription(in, User, Server, JID, Type, - Reason), + Res = process_subscription(in, User, Server, JID, Type, Reason), mongoose_acc:set(hook, result, Res, Acc). -spec out_subscription(Acc:: mongoose_acc:t(), User :: binary(), Server :: binary(), - JID ::jid:jid(), + JID :: jid:jid(), Type :: sub_presence()) -> mongoose_acc:t(). out_subscription(Acc, User, Server, JID, Type) -> - Res = process_subscription(out, User, Server, JID, Type, <<"">>), + Res = process_subscription(out, User, Server, JID, Type, <<>>), mongoose_acc:set(hook, result, Res, Acc). process_subscription(Direction, User, Server, JID1, Type, Reason) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), - LJID = jid:to_lower(JID1), - TransactionFun = fun() -> process_subscription_transaction(Direction, LUser, LServer, - LJID, Type, Reason) end, + JID = jid:make(User, Server, <<>>), + LServer = case JID of + #jid{lserver = LS} -> LS; + error -> error + end, + TransactionFun = + fun() -> process_subscription_transaction(Direction, JID, JID1, Type, Reason) end, case transaction(LServer, TransactionFun) of {atomic, {Push, AutoReply}} -> case AutoReply of @@ -693,13 +677,13 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> PresenceStanza = #xmlel{name = <<"presence">>, attrs = [{<<"type">>, autoreply_to_type(AutoReply)}], children = []}, - ejabberd_router:route(jid:make(User, Server, <<"">>), JID1, PresenceStanza) + ejabberd_router:route(JID, JID1, PresenceStanza) end, case Push of {push, #roster{ subscription = none, ask = in }} -> true; {push, Item} -> - push_item(User, Server, jid:make(User, Server, <<"">>), Item), + push_item(JID, JID, Item), true; none -> false end; @@ -709,11 +693,14 @@ process_subscription(Direction, User, Server, JID1, Type, Reason) -> autoreply_to_type(subscribed) -> <<"subscribed">>; autoreply_to_type(unsubscribed) -> <<"unsubscribed">>. -process_subscription_transaction(Direction, LUser, LServer, LJID, Type, Reason) -> - Item = case mod_roster_backend:get_roster_entry_t(LUser, LServer, LJID, full) of +process_subscription_transaction(Direction, JID, JID1, Type, Reason) -> + #jid{luser = LUser, lserver = LServer} = JID, + LJID = jid:to_lower(JID1), + Item = case get_roster_entry_t(JID, JID1, full) of does_not_exist -> #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; + us = {LUser, LServer}, + jid = LJID}; R -> R end, NewState = case Direction of @@ -864,21 +851,24 @@ get_user_rosters_length(User, Server) -> %% Used only by tests remove_user(User, Server) -> - Acc = mongoose_acc:new(#{ location => ?LOCATION, - lserver => <<_/binary>> = jid:nameprep(Server), - element => undefined }), + Acc = mongoose_acc:new(#{location => ?LOCATION, + lserver => <<_/binary>> = jid:nameprep(Server), + element => undefined}), remove_user(Acc, User, Server). remove_user(Acc, User, Server) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), - Acc1 = try_send_unsubscription_to_rosteritems(Acc, LUser, LServer), - mod_roster_backend:remove_user(LUser, LServer), - Acc1. + case jid:make(User, Server, <<>>) of + #jid{luser = LUser, lserver = LServer} = JID -> + Acc1 = try_send_unsubscription_to_rosteritems(Acc, JID), + mod_roster_backend:remove_user(LUser, LServer), + Acc1; + error -> + Acc + end. -try_send_unsubscription_to_rosteritems(Acc, LUser, LServer) -> +try_send_unsubscription_to_rosteritems(Acc, JID) -> try - send_unsubscription_to_rosteritems(Acc, LUser, LServer) + send_unsubscription_to_rosteritems(Acc, JID) catch E:R:S -> ?LOG_WARNING(#{what => roster_unsubcribe_failed, @@ -889,14 +879,13 @@ try_send_unsubscription_to_rosteritems(Acc, LUser, LServer) -> %% For each contact with Subscription: %% Both or From, send a "unsubscribed" presence stanza; %% Both or To, send a "unsubscribe" presence stanza. -send_unsubscription_to_rosteritems(Acc, LUser, LServer) -> +send_unsubscription_to_rosteritems(Acc, JID) -> + #jid{luser = LUser, lserver = LServer} = JID, Acc1 = get_user_roster(Acc, {LUser, LServer}), RosterItems = mongoose_acc:get(roster, items, [], Acc1), - From = jid:make({LUser, LServer, <<"">>}), - lists:foreach(fun (RosterItem) -> - send_unsubscribing_presence(From, RosterItem) - end, - RosterItems), + lists:foreach(fun(RosterItem) -> + send_unsubscribing_presence(JID, RosterItem) + end, RosterItems), Acc1. %% @spec (From::jid(), Item::roster()) -> any() @@ -921,49 +910,30 @@ send_presence_type(From, To, Type) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -set_items(User, Server, SubEl) -> +set_items(#jid{luser = LUser, lserver = LServer}, SubEl) -> #xmlel{children = Els} = SubEl, - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), F = fun () -> - lists:foreach(fun (El) -> + lists:foreach(fun(El) -> process_item_set_t(LUser, LServer, El) - end, - Els) + end, Els) end, transaction(LServer, F). %% @doc add a contact to roster, or update --spec set_roster_entry(jid:jid(), binary(), binary(), [binary()]) -> ok|error. -set_roster_entry(UserJid, ContactBin, Name, Groups) -> - set_roster_entry(UserJid, ContactBin, Name, Groups, unchanged). +-spec set_roster_entry(jid:jid(), jid:jid() | error, binary(), [binary()]) -> ok | error. +set_roster_entry(UserJid, ContactJid, Name, Groups) -> + set_roster_entry(UserJid, ContactJid, Name, Groups, unchanged). -spec set_roster_entry(UserJid ::jid:jid(), - ContactBin :: binary(), + ContactJid :: jid:jid(), Name :: binary() | unchanged, Groups :: [binary()] | unchanged, - NewSubscription :: remove | unchanged) -> ok|error. -set_roster_entry(UserJid, ContactBin, Name, Groups, NewSubscription) -> - LUser = UserJid#jid.luser, - LServer = UserJid#jid.lserver, - JID1 = jid:from_binary(ContactBin), - case JID1 of - error -> error; - _ -> - LJID = jid:to_lower(JID1), - MakeItem = fun(Item) -> - modify_roster_item(Item, Name, Groups, NewSubscription) - end, - set_roster_item( - LUser, % User - LUser, % LUser - LServer, % LServer - LJID, % LJID - UserJid, % From - UserJid, % To - MakeItem - ) - end. + NewSubscription :: remove | unchanged) -> ok | error. +set_roster_entry(UserJid, ContactJid, Name, Groups, NewSubscription) -> + MakeItem = fun(Item) -> + modify_roster_item(Item, Name, Groups, NewSubscription) + end, + set_roster_item(ContactJid, UserJid, UserJid, MakeItem). modify_roster_item(Item, Name, Groups, NewSubscription) -> Item1 = case Name of @@ -981,10 +951,9 @@ modify_roster_item(Item, Name, Groups, NewSubscription) -> %% @doc remove from roster - in practice it means changing %% subscription state to 'remove' --spec remove_from_roster(UserJid ::jid:jid(), - ContactBin :: binary()) -> ok|error. -remove_from_roster(UserJid, ContactBin) -> - set_roster_entry(UserJid, ContactBin, unchanged, unchanged, remove). +-spec remove_from_roster(UserJid ::jid:jid(), ContactJid :: jid:jid()) -> ok | error. +remove_from_roster(UserJid, ContactJid) -> + set_roster_entry(UserJid, ContactJid, unchanged, unchanged, remove). update_roster_t(LUser, LServer, LJID, Item) -> mod_roster_backend:update_roster_t(LUser, LServer, LJID, Item). @@ -1045,11 +1014,12 @@ process_item_attrs_ws(Item, []) -> Server :: jid:lserver(), JID ::jid:jid() | jid:ljid()) -> {subscription_state(), [binary()]}. get_jid_info(_, User, Server, JID) -> - case get_roster_entry(User, Server, JID, full) of + ToJID = jid:make(User, Server, <<>>), + case get_roster_entry(ToJID, JID, full) of error -> {none, []}; does_not_exist -> LRJID = jid:to_bare(jid:to_lower(JID)), - case get_roster_entry(User, Server, LRJID, full) of + case get_roster_entry(ToJID, LRJID, full) of error -> {none, []}; does_not_exist -> {none, []}; R -> {R#roster.subscription, R#roster.groups} diff --git a/src/mongoose_client_api/mongoose_client_api_contacts.erl b/src/mongoose_client_api/mongoose_client_api_contacts.erl index fc657b569e..81f899e33b 100644 --- a/src/mongoose_client_api/mongoose_client_api_contacts.erl +++ b/src/mongoose_client_api/mongoose_client_api_contacts.erl @@ -193,6 +193,6 @@ to_binary(S) -> -spec jid_exists(binary(), binary()) -> boolean(). jid_exists(CJid, Jid) -> - FJid = jid:from_binary(CJid), - Res = mod_roster:get_roster_entry(FJid#jid.luser, FJid#jid.lserver, Jid), + #jid{} = FJid = jid:from_binary(CJid), + Res = mod_roster:get_roster_entry(FJid, Jid), Res =/= does_not_exist. diff --git a/src/muc_light/mod_muc_light.erl b/src/muc_light/mod_muc_light.erl index 2ac9d752e0..59a9fdd23c 100644 --- a/src/muc_light/mod_muc_light.erl +++ b/src/muc_light/mod_muc_light.erl @@ -319,8 +319,11 @@ add_rooms_to_roster(Acc, UserUS) -> Info = get_rooms_info(lists:sort(RoomList)), NewItems = lists:foldl( fun({{RoomU, RoomS}, RoomName, RoomVersion}, Items0) -> + JID = jid:make_noprep(RoomU, RoomS, <<>>), Item = #roster{ - jid = jid:make_noprep(RoomU, RoomS, <<>>), + usj = {RoomU, RoomS, jid:to_lower(JID)}, + us = {RoomU, RoomS}, + jid = jid:to_lower(JID), name = RoomName, subscription = to, groups = [?NS_MUC_LIGHT], diff --git a/test/roster_SUITE.erl b/test/roster_SUITE.erl index 6fe3bb99e5..28e8e6b451 100644 --- a/test/roster_SUITE.erl +++ b/test/roster_SUITE.erl @@ -67,7 +67,7 @@ end_per_testcase(_TC, C) -> roster_old(_C) -> R1 = get_roster_old(), ?assertEqual(length(R1), 0), - mod_roster:set_items(a(), host(), addbob_stanza()), + mod_roster:set_items(alice_jid(), addbob_stanza()), assert_state_old(none, none), subscription(out, subscribe), assert_state_old(none, out), @@ -76,7 +76,7 @@ roster_old(_C) -> roster_old_with_filter(_C) -> R1 = get_roster_old(), ?assertEqual(0, length(R1)), - mod_roster:set_items(a(), host(), addbob_stanza()), + mod_roster:set_items(alice_jid(), addbob_stanza()), assert_state_old(none, none), subscription(in, subscribe), R2 = get_roster_old(), @@ -86,29 +86,29 @@ roster_old_with_filter(_C) -> ok. roster_new(_C) -> - R1 = mod_roster:get_roster_entry(a(), host(), bob()), + R1 = mod_roster:get_roster_entry(alice_jid(), bob()), ?assertEqual(does_not_exist, R1), - mod_roster:set_items(a(), host(), addbob_stanza()), + mod_roster:set_items(alice_jid(), addbob_stanza()), assert_state_old(none, none), ct:pal("get_roster_old(): ~p", [get_roster_old()]), - R2 = mod_roster:get_roster_entry(a(), host(), bob()), + R2 = mod_roster:get_roster_entry(alice_jid(), bob()), ?assertMatch(#roster{}, R2), % is not guaranteed to contain full info - R3 = mod_roster:get_roster_entry(a(), host(), bob(), full), + R3 = mod_roster:get_roster_entry(alice_jid(), bob(), full), assert_state(R3, none, none, [<<"friends">>]), subscription(out, subscribe), - R4 = mod_roster:get_roster_entry(a(), host(), bob(), full), + R4 = mod_roster:get_roster_entry(alice_jid(), bob(), full), assert_state(R4, none, out, [<<"friends">>]). roster_case_insensitive(_C) -> - mod_roster:set_items(a(), host(), addbob_stanza()), + mod_roster:set_items(alice_jid(), addbob_stanza()), R1 = get_roster_old(), ?assertEqual(1, length(R1)), R2 = get_roster_old(ae()), ?assertEqual(1, length(R2)), - R3 = mod_roster:get_roster_entry(a(), host(), bob(), full), + R3 = mod_roster:get_roster_entry(alice_jid(), bob(), full), assert_state(R3, none, none, [<<"friends">>]), - R3 = mod_roster:get_roster_entry(ae(), host(), bob(), full), + R3 = mod_roster:get_roster_entry(alicE_jid(), bob(), full), assert_state(R3, none, none, [<<"friends">>]), ok. @@ -123,11 +123,10 @@ assert_state(Rentry, Subscription, Ask, Groups) -> ?assertEqual(Groups, Rentry#roster.groups). subscription(Direction, Type) -> - LBob = jid:to_lower(jid:from_binary(bob())), + BobJID = jid:from_binary(bob()), TFun = fun() -> mod_roster:process_subscription_transaction(Direction, - a(), - host(), - LBob, + alice_jid(), + BobJID, Type, <<"">>) end, @@ -166,6 +165,12 @@ delete_ets() -> catch ets:delete(mongoose_services), ok. +alice_jid() -> + jid:make(a(), host(), <<>>). + +alicE_jid() -> + jid:make(ae(), host(), <<>>). + a() -> <<"alice">>. ae() -> <<"alicE">>.