25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-20 16:15:59 +01:00

mod_roster: Change hook type from #roster{} to #roster_item{}

The problem with #roster{} is that every new record entry is also stored
in the mnesia roster table.  Adding the mix_participant_id there makes
no sense because the normal roster items are no MIX channels.  Using
\#roster_item{} for the hook and #roster{} for storing the normal items
seems to be a better idea.
This commit is contained in:
Linus Jahn 2022-07-16 23:23:48 +02:00 committed by badlop
parent d450d40178
commit d6b72f1c5d
7 changed files with 79 additions and 103 deletions

View File

@ -28,8 +28,7 @@
ask = none :: ask() | '_', ask = none :: ask() | '_',
groups = [] :: [binary()] | '_', groups = [] :: [binary()] | '_',
askmessage = <<"">> :: binary() | '_', askmessage = <<"">> :: binary() | '_',
xs = [] :: [fxml:xmlel()] | '_', xs = [] :: [fxml:xmlel()] | '_'
mix_participant_id = <<>> :: binary() | '_'
}). }).
-record(roster_version, -record(roster_version,

View File

@ -777,9 +777,9 @@ broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres,
Roster = ejabberd_hooks:run_fold(roster_get, LServer, Roster = ejabberd_hooks:run_fold(roster_get, LServer,
[], [{LUser, LServer}]), [], [{LUser, LServer}]),
lists:foldl( lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, Acc) fun(#roster_item{jid = ItemJID, subscription = Sub}, Acc)
when Sub == both; Sub == from -> when Sub == both; Sub == from ->
maps:put(LJID, 1, Acc); maps:put(jid:tolower(ItemJID), 1, Acc);
(_, Acc) -> (_, Acc) ->
Acc Acc
end, #{BareJID => 1}, Roster); end, #{BareJID => 1}, Roster);
@ -813,8 +813,7 @@ broadcast_presence_available(#{jid := JID} = State,
[], [{LUser, LServer}]), [], [{LUser, LServer}]),
{FJIDs, TJIDs} = {FJIDs, TJIDs} =
lists:foldl( lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, {F, T}) -> fun(#roster_item{jid = To, subscription = Sub}, {F, T}) ->
To = jid:make(LJID),
F1 = if Sub == both orelse Sub == from -> F1 = if Sub == both orelse Sub == from ->
Pres1 = xmpp:set_to(Pres, To), Pres1 = xmpp:set_to(Pres, To),
case privacy_check_packet(State, Pres1, out) of case privacy_check_packet(State, Pres1, out) of
@ -843,10 +842,9 @@ broadcast_presence_available(#{jid := JID} = State,
Items = ejabberd_hooks:run_fold( Items = ejabberd_hooks:run_fold(
roster_get, LServer, [], [{LUser, LServer}]), roster_get, LServer, [], [{LUser, LServer}]),
JIDs = lists:foldl( JIDs = lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, Tos) fun(#roster_item{jid = To, subscription = Sub}, Tos)
when Sub == both orelse Sub == from -> when Sub == both orelse Sub == from ->
To = jid:make(LJID), P = xmpp:set_to(Pres, To),
P = xmpp:set_to(Pres, jid:make(LJID)),
case privacy_check_packet(State, P, out) of case privacy_check_packet(State, P, out) of
allow -> [To|Tos]; allow -> [To|Tos];
deny -> Tos deny -> Tos

View File

@ -1333,16 +1333,15 @@ get_roster(User, Server) ->
%% several times, each one in a different group. %% several times, each one in a different group.
make_roster_xmlrpc(Roster) -> make_roster_xmlrpc(Roster) ->
lists:foldl( lists:foldl(
fun(Item, Res) -> fun(#roster_item{jid = JID, name = Nick, subscription = Sub, ask = Ask} = Item, Res) ->
JIDS = jid:encode(Item#roster.jid), JIDS = jid:encode(JID),
Nick = Item#roster.name, Subs = atom_to_list(Sub),
Subs = atom_to_list(Item#roster.subscription), Asks = atom_to_list(Ask),
Ask = atom_to_list(Item#roster.ask), Groups = case Item#roster_item.groups of
Groups = case Item#roster.groups of
[] -> [<<>>]; [] -> [<<>>];
Gs -> Gs Gs -> Gs
end, end,
ItemsX = [{JIDS, Nick, Subs, Ask, Group} || Group <- Groups], ItemsX = [{JIDS, Nick, Subs, Asks, Group} || Group <- Groups],
ItemsX ++ Res ItemsX ++ Res
end, end,
[], [],

View File

@ -212,22 +212,20 @@ process_iq(#iq{type = set,
process_iq(IQ) -> process_iq(IQ) ->
xmpp:make_error(IQ, unsupported_query_error(IQ)). xmpp:make_error(IQ, unsupported_query_error(IQ)).
-spec get_mix_roster_items([#roster{}], {binary(), binary()}) -> [#roster{}]. -spec get_mix_roster_items([#roster_item{}], {binary(), binary()}) -> [#roster_item{}].
get_mix_roster_items(Acc, {LUser, LServer}) -> get_mix_roster_items(Acc, {LUser, LServer}) ->
JID = jid:make(LUser, LServer), JID = jid:make(LUser, LServer),
case get_channels(JID) of case get_channels(JID) of
{ok, Channels} -> {ok, Channels} ->
lists:map( lists:map(
fun({#jid{luser=Channel, lserver=Service}, Id}) -> fun({ItemJID, Id}) ->
#roster{ #roster_item{
jid = {Channel, Service, <<>>}, jid = ItemJID,
name = <<>>, name = <<>>,
subscription = both, subscription = both,
ask = none, ask = undefined,
groups = [<<"Channels">>], groups = [<<"Channels">>],
askmessage = <<>>, mix_channel = #mix_roster_channel{'participant-id' = Id}
xs = [],
mix_participant_id = Id
} }
end, Channels); end, Channels);
_ -> _ ->
@ -288,21 +286,19 @@ process_leave(#iq{from = From,
end. end.
-spec process_join_result(iq(), iq()) -> ok. -spec process_join_result(iq(), iq()) -> ok.
process_join_result(#iq{from = Channel, process_join_result(#iq{from = #jid{} = Channel,
type = result, sub_els = [#mix_join{id = ID} = Join]}, type = result, sub_els = [#mix_join{id = ID} = Join]},
#iq{to = To} = IQ) -> #iq{to = To} = IQ) ->
case add_channel(To, Channel, ID) of case add_channel(To, Channel, ID) of
ok -> ok ->
% Do roster push % Do roster push
#jid{luser = ChannelName, lserver = Service} = Channel, mod_roster:push_item(To, #roster_item{jid = #jid{}}, #roster_item{
mod_roster:push_item(To, #roster{}, #roster{ jid = Channel,
jid = {ChannelName, Service, <<>>},
name = <<>>, name = <<>>,
subscription = none, subscription = none,
ask = none, ask = undefined,
groups = [], groups = [],
askmessage = <<>>, mix_channel = #mix_roster_channel{'participant-id' = ID}
mix_participant_id = ID
}), }),
% send IQ result % send IQ result
ChanID = make_channel_id(Channel, ID), ChanID = make_channel_id(Channel, ID),
@ -319,11 +315,9 @@ process_join_result(Err, IQ) ->
process_leave_result(#iq{from = Channel, type = result, sub_els = [#mix_leave{} = Leave]}, process_leave_result(#iq{from = Channel, type = result, sub_els = [#mix_leave{} = Leave]},
#iq{to = User} = IQ) -> #iq{to = User} = IQ) ->
% Do roster push % Do roster push
#jid{luser = ChannelName, lserver = Service} = Channel,
mod_roster:push_item(User, mod_roster:push_item(User,
#roster{jid = {ChannelName, Service, <<>>}, subscription = none}, #roster_item{jid = Channel, subscription = none},
#roster{jid = {ChannelName, Service, <<>>}, #roster_item{jid = Channel, subscription = remove}),
subscription = remove}),
% send iq result % send iq result
ResIQ = xmpp:make_iq_result(IQ, #mix_client_leave{leave = Leave}), ResIQ = xmpp:make_iq_result(IQ, #mix_client_leave{leave = Leave}),
ejabberd_router:route(ResIQ); ejabberd_router:route(ResIQ);

View File

@ -41,7 +41,7 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/2, stop/1, reload/3, process_iq/1, export/1, -export([start/2, stop/1, reload/3, process_iq/1, export/1,
import_info/0, process_local_iq/1, get_user_roster/2, import_info/0, process_local_iq/1, get_user_roster_items/2,
import/5, get_roster/2, push_item/3, import/5, get_roster/2, push_item/3,
import_start/2, import_stop/2, is_subscribed/2, import_start/2, import_stop/2, is_subscribed/2,
c2s_self_presence/1, in_subscription/2, c2s_self_presence/1, in_subscription/2,
@ -92,7 +92,7 @@ start(Host, Opts) ->
Mod:init(Host, Opts), Mod:init(Host, Opts),
init_cache(Mod, Host, Opts), init_cache(Mod, Host, Opts),
ejabberd_hooks:add(roster_get, Host, ?MODULE, ejabberd_hooks:add(roster_get, Host, ?MODULE,
get_user_roster, 50), get_user_roster_items, 50),
ejabberd_hooks:add(roster_in_subscription, Host, ejabberd_hooks:add(roster_in_subscription, Host,
?MODULE, in_subscription, 50), ?MODULE, in_subscription, 50),
ejabberd_hooks:add(roster_out_subscription, Host, ejabberd_hooks:add(roster_out_subscription, Host,
@ -114,7 +114,7 @@ start(Host, Opts) ->
stop(Host) -> stop(Host) ->
ejabberd_hooks:delete(roster_get, Host, ?MODULE, ejabberd_hooks:delete(roster_get, Host, ?MODULE,
get_user_roster, 50), get_user_roster_items, 50),
ejabberd_hooks:delete(roster_in_subscription, Host, ejabberd_hooks:delete(roster_in_subscription, Host,
?MODULE, in_subscription, 50), ?MODULE, in_subscription, 50),
ejabberd_hooks:delete(roster_out_subscription, Host, ejabberd_hooks:delete(roster_out_subscription, Host,
@ -205,9 +205,8 @@ process_local_iq(#iq{lang = Lang} = IQ) ->
-spec roster_hash([#roster{}]) -> binary(). -spec roster_hash([#roster{}]) -> binary().
roster_hash(Items) -> roster_hash(Items) ->
str:sha(term_to_binary(lists:sort([R#roster{groups = str:sha(term_to_binary(lists:sort([R#roster_item{groups = lists:sort(Grs)}
lists:sort(Grs)} || R = #roster_item{groups = Grs}
|| R = #roster{groups = Grs}
<- Items]))). <- Items]))).
%% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled. %% Returns a list that may contain an xmlelement with the XEP-237 feature if it's enabled.
@ -227,7 +226,6 @@ get_versioning_feature(Acc, Host) ->
-spec roster_version(binary(), binary()) -> undefined | binary(). -spec roster_version(binary(), binary()) -> undefined | binary().
roster_version(LServer, LUser) -> roster_version(LServer, LUser) ->
US = {LUser, LServer},
case mod_roster_opt:store_current_id(LServer) of case mod_roster_opt:store_current_id(LServer) of
true -> true ->
case read_roster_version(LUser, LServer) of case read_roster_version(LUser, LServer) of
@ -235,8 +233,7 @@ roster_version(LServer, LUser) ->
{ok, V} -> V {ok, V} -> V
end; end;
false -> false ->
roster_hash(ejabberd_hooks:run_fold(roster_get, LServer, roster_hash(run_roster_get_hook(LUser, LServer))
[], [US]))
end. end.
-spec read_roster_version(binary(), binary()) -> {ok, binary()} | error. -spec read_roster_version(binary(), binary()) -> {ok, binary()} | error.
@ -279,7 +276,6 @@ process_iq_get(#iq{to = To, from = From,
sub_els = [#roster_query{ver = RequestedVersion, mix_annotate = MixAnnotate}]} = IQ) -> sub_els = [#roster_query{ver = RequestedVersion, mix_annotate = MixAnnotate}]} = IQ) ->
LUser = To#jid.luser, LUser = To#jid.luser,
LServer = To#jid.lserver, LServer = To#jid.lserver,
US = {LUser, LServer},
MixEnabled = MixAnnotate == #mix_roster_annotate{}, MixEnabled = MixAnnotate == #mix_roster_annotate{},
{ItemsToSend, VersionToSend} = {ItemsToSend, VersionToSend} =
case {mod_roster_opt:versioning(LServer), case {mod_roster_opt:versioning(LServer),
@ -288,32 +284,22 @@ process_iq_get(#iq{to = To, from = From,
case read_roster_version(LUser, LServer) of case read_roster_version(LUser, LServer) of
error -> error ->
RosterVersion = write_roster_version(LUser, LServer), RosterVersion = write_roster_version(LUser, LServer),
{lists:map(fun encode_item/1, {run_roster_get_hook(LUser, LServer), RosterVersion};
ejabberd_hooks:run_fold(
roster_get, To#jid.lserver, [], [US])),
RosterVersion};
{ok, RequestedVersion} -> {ok, RequestedVersion} ->
{false, false}; {false, false};
{ok, NewVersion} -> {ok, NewVersion} ->
{lists:map(fun encode_item/1, {run_roster_get_hook(LUser, LServer), NewVersion}
ejabberd_hooks:run_fold(
roster_get, To#jid.lserver, [], [US])),
NewVersion}
end; end;
{true, false} when RequestedVersion /= undefined -> {true, false} when RequestedVersion /= undefined ->
RosterItems = ejabberd_hooks:run_fold( RosterItems = run_roster_get_hook(LUser, LServer),
roster_get, To#jid.lserver, [], [US]),
case roster_hash(RosterItems) of case roster_hash(RosterItems) of
RequestedVersion -> RequestedVersion ->
{false, false}; {false, false};
New -> New ->
{lists:map(fun encode_item/1, RosterItems), New} {RosterItems, New}
end; end;
_ -> _ ->
{lists:map(fun encode_item/1, {run_roster_get_hook(LUser, LServer), false}
ejabberd_hooks:run_fold(
roster_get, To#jid.lserver, [], [US])),
false}
end, end,
% Store that MIX annotation is enabled (for roster pushes) % Store that MIX annotation is enabled (for roster pushes)
set_mix_annotation_enabled(From, MixEnabled), set_mix_annotation_enabled(From, MixEnabled),
@ -334,16 +320,21 @@ process_iq_get(#iq{to = To, from = From,
ver = Version} ver = Version}
end). end).
-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}]. -spec run_roster_get_hook(binary(), binary()) -> [#roster_item{}].
get_user_roster(Acc, {LUser, LServer}) -> run_roster_get_hook(LUser, LServer) ->
Items = get_roster(LUser, LServer), ejabberd_hooks:run_fold(roster_get, LServer, [], [{LUser, LServer}]).
lists:filter(fun (#roster{subscription = none,
ask = in}) -> -spec get_filtered_roster(binary(), binary()) -> [#roster{}].
false; get_filtered_roster(LUser, LServer) ->
(_) -> true lists:filter(
end, fun (#roster{subscription = none, ask = in}) -> false;
Items) (_) -> true
++ Acc. end,
get_roster(LUser, LServer)).
-spec get_user_roster_items([#roster_item{}], {binary(), binary()}) -> [#roster_item{}].
get_user_roster_items(Acc, {LUser, LServer}) ->
lists:map(fun encode_item/1, get_filtered_roster(LUser, LServer)) ++ Acc.
-spec get_roster(binary(), binary()) -> [#roster{}]. -spec get_roster(binary(), binary()) -> [#roster{}].
get_roster(LUser, LServer) -> get_roster(LUser, LServer) ->
@ -435,11 +426,7 @@ encode_item(Item) ->
both -> subscribe; both -> subscribe;
_ -> undefined _ -> undefined
end, end,
groups = Item#roster.groups, groups = Item#roster.groups}.
mix_channel = case Item#roster.mix_participant_id of
<<>> -> undefined;
_ -> #mix_roster_channel{'participant-id' = Item#roster.mix_participant_id}
end}.
-spec decode_item(roster_item(), #roster{}, boolean()) -> #roster{}. -spec decode_item(roster_item(), #roster{}, boolean()) -> #roster{}.
decode_item(#roster_item{subscription = remove} = Item, R, _) -> decode_item(#roster_item{subscription = remove} = Item, R, _) ->
@ -494,7 +481,7 @@ set_item_and_notify_clients(To, #roster_item{jid = PeerJID} = RosterItem,
end, end,
case transaction(LUser, LServer, [PeerLJID], F) of case transaction(LUser, LServer, [PeerLJID], F) of
{atomic, {OldItem, NewItem}} -> {atomic, {OldItem, NewItem}} ->
push_item(To, OldItem, NewItem), push_item(To, encode_item(OldItem), encode_item(NewItem)),
case NewItem#roster.subscription of case NewItem#roster.subscription of
remove -> remove ->
send_unsubscribing_presence(To, OldItem); send_unsubscribing_presence(To, OldItem);
@ -505,7 +492,7 @@ set_item_and_notify_clients(To, #roster_item{jid = PeerJID} = RosterItem,
{error, Reason} {error, Reason}
end. end.
-spec push_item(jid(), #roster{}, #roster{}) -> ok. -spec push_item(jid(), #roster_item{}, #roster_item{}) -> ok.
push_item(To, OldItem, NewItem) -> push_item(To, OldItem, NewItem) ->
#jid{luser = LUser, lserver = LServer} = To, #jid{luser = LUser, lserver = LServer} = To,
Ver = case mod_roster_opt:versioning(LServer) of Ver = case mod_roster_opt:versioning(LServer) of
@ -518,10 +505,10 @@ push_item(To, OldItem, NewItem) ->
push_item(To1, OldItem, NewItem, Ver) push_item(To1, OldItem, NewItem, Ver)
end, ejabberd_sm:get_user_resources(LUser, LServer)). end, ejabberd_sm:get_user_resources(LUser, LServer)).
-spec push_item(jid(), #roster{}, #roster{}, undefined | binary()) -> ok. -spec push_item(jid(), #roster_item{}, #roster_item{}, undefined | binary()) -> ok.
push_item(To, OldItem, NewItem, Ver) -> push_item(To, OldItem, NewItem, Ver) ->
route_presence_change(To, OldItem, NewItem), route_presence_change(To, OldItem, NewItem),
[Item] = process_items_mix([encode_item(NewItem)], To), [Item] = process_items_mix([NewItem], To),
IQ = #iq{type = set, to = To, IQ = #iq{type = set, to = To,
from = jid:remove_resource(To), from = jid:remove_resource(To),
id = <<"push", (p1_rand:get_string())/binary>>, id = <<"push", (p1_rand:get_string())/binary>>,
@ -529,11 +516,11 @@ push_item(To, OldItem, NewItem, Ver) ->
items = [Item]}]}, items = [Item]}]},
ejabberd_router:route(IQ). ejabberd_router:route(IQ).
-spec route_presence_change(jid(), #roster{}, #roster{}) -> ok. -spec route_presence_change(jid(), #roster_item{}, #roster_item{}) -> ok.
route_presence_change(From, OldItem, NewItem) -> route_presence_change(From, OldItem, NewItem) ->
OldSub = OldItem#roster.subscription, OldSub = OldItem#roster_item.subscription,
NewSub = NewItem#roster.subscription, NewSub = NewItem#roster_item.subscription,
To = jid:make(NewItem#roster.jid), To = NewItem#roster_item.jid,
NewIsFrom = NewSub == both orelse NewSub == from, NewIsFrom = NewSub == both orelse NewSub == from,
OldIsFrom = OldSub == both orelse OldSub == from, OldIsFrom = OldSub == both orelse OldSub == from,
if NewIsFrom andalso not OldIsFrom -> if NewIsFrom andalso not OldIsFrom ->
@ -657,7 +644,9 @@ process_subscription(Direction, User, Server, JID1,
NewItem#roster.ask == in -> NewItem#roster.ask == in ->
ok; ok;
true -> true ->
push_item(jid:make(User, Server), OldItem, NewItem) push_item(jid:make(User, Server),
encode_item(OldItem),
encode_item(NewItem))
end, end,
true; true;
none -> none ->
@ -835,7 +824,7 @@ in_auto_reply(_, _, _) -> none.
remove_user(User, Server) -> remove_user(User, Server) ->
LUser = jid:nodeprep(User), LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server), LServer = jid:nameprep(Server),
Items = get_user_roster([], {LUser, LServer}), Items = get_filtered_roster(LUser, LServer),
send_unsubscription_to_rosteritems(LUser, LServer, Items), send_unsubscription_to_rosteritems(LUser, LServer, Items),
Mod = gen_mod:db_mod(LServer, ?MODULE), Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:remove_user(LUser, LServer), Mod:remove_user(LUser, LServer),

View File

@ -185,8 +185,8 @@ cache_nodes(Mod, Host) ->
false -> ejabberd_cluster:get_nodes() false -> ejabberd_cluster:get_nodes()
end. end.
-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}]. -spec get_user_roster([#roster_item{}], {binary(), binary()}) -> [#roster_item{}].
get_user_roster(Items, {U, S} = US) -> get_user_roster(Items, {_, S} = US) ->
{DisplayedGroups, Cache} = get_user_displayed_groups(US), {DisplayedGroups, Cache} = get_user_displayed_groups(US),
SRUsers = lists:foldl( SRUsers = lists:foldl(
fun(Group, Acc1) -> fun(Group, Acc1) ->
@ -216,10 +216,10 @@ get_user_roster(Items, {U, S} = US) ->
end end
end, end,
SRUsers, Items), SRUsers, Items),
SRItems = [#roster{usj = {U, S, {U1, S1, <<"">>}}, SRItems = [#roster_item{jid = jid:make(U1, S1),
us = US, jid = {U1, S1, <<"">>}, name = get_rosteritem_name(U1, S1),
name = get_rosteritem_name(U1, S1), subscription = both, ask = undefined,
subscription = both, ask = none, groups = GroupLabels} groups = GroupLabels}
|| {{U1, S1}, GroupLabels} <- dict:to_list(SRUsersRest)], || {{U1, S1}, GroupLabels} <- dict:to_list(SRUsersRest)],
SRItems ++ NewItems1. SRItems ++ NewItems1.
@ -855,16 +855,14 @@ displayed_to_groups(GroupName, LServer) ->
push_item(User, Server, Item) -> push_item(User, Server, Item) ->
mod_roster:push_item(jid:make(User, Server), mod_roster:push_item(jid:make(User, Server),
Item#roster{subscription = none}, Item#roster_item{subscription = none},
Item). Item).
push_roster_item(User, Server, ContactU, ContactS, ContactN, push_roster_item(User, Server, ContactU, ContactS, ContactN,
GroupLabel, Subscription) -> GroupLabel, Subscription) ->
Item = #roster{usj = Item = #roster_item{jid = jid:make(ContactU, ContactS),
{User, Server, {ContactU, ContactS, <<"">>}}, name = ContactN, subscription = Subscription, ask = undefined,
us = {User, Server}, jid = {ContactU, ContactS, <<"">>}, groups = [GroupLabel]},
name = ContactN, subscription = Subscription, ask = none,
groups = [GroupLabel]},
push_item(User, Server, Item). push_item(User, Server, Item).
-spec c2s_self_presence({presence(), ejabberd_c2s:state()}) -spec c2s_self_presence({presence(), ejabberd_c2s:state()})

View File

@ -109,8 +109,8 @@ depends(_Host, _Opts) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Hooks %% Hooks
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec get_user_roster([#roster{}], {binary(), binary()}) -> [#roster{}]. -spec get_user_roster([#roster_item{}], {binary(), binary()}) -> [#roster_item{}].
get_user_roster(Items, {U, S} = US) -> get_user_roster(Items, US) ->
SRUsers = get_user_to_groups_map(US, true), SRUsers = get_user_to_groups_map(US, true),
{NewItems1, SRUsersRest} = lists:mapfoldl(fun (Item, {NewItems1, SRUsersRest} = lists:mapfoldl(fun (Item,
SRUsers1) -> SRUsers1) ->
@ -135,10 +135,9 @@ get_user_roster(Items, {U, S} = US) ->
end end
end, end,
SRUsers, Items), SRUsers, Items),
SRItems = [#roster{usj = {U, S, {U1, S1, <<"">>}}, SRItems = [#roster_item{jid = jid:make(U1, S1),
us = US, jid = {U1, S1, <<"">>}, name = get_user_name(U1, S1), subscription = both,
name = get_user_name(U1, S1), subscription = both, ask = undefined, groups = GroupNames}
ask = none, groups = GroupNames}
|| {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)], || {{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)],
SRItems ++ NewItems1. SRItems ++ NewItems1.