From b88fa6f6174a2472fb438a8717a69d8affb212b6 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 7 Jan 2015 13:11:53 +0100 Subject: [PATCH] Fix missing presences when adding shared groups (Github PR#99, thanks to Bokner) --- src/mod_shared_roster.erl | 108 ++++++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 33 deletions(-) diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 916285660..38c5327e6 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -835,12 +835,13 @@ add_user_to_group(Host, US, Group) -> (?MODULE):set_group_opts(Host, Group, GroupOpts ++ MoreGroupOpts); nomatch -> - push_user_to_displayed(LUser, LServer, Group, Host, - both), - push_displayed_to_user(LUser, LServer, Group, Host, - both), - add_user_to_group(Host, US, Group, - gen_mod:db_type(Host, ?MODULE)) + DisplayedToGroups = displayed_to_groups(Group, Host), + DisplayedGroups = get_displayed_groups(Group, LServer), + push_user_to_displayed(LUser, LServer, Group, Host, both, DisplayedToGroups), + push_displayed_to_user(LUser, LServer, Host, both, DisplayedGroups), + broadcast_user_to_displayed(LUser, LServer, Host, both, DisplayedToGroups), + broadcast_displayed_to_user(LUser, LServer, Host, both, DisplayedGroups), + add_user_to_group(Host, US, Group, gen_mod:db_type(Host, ?MODULE)) end. add_user_to_group(Host, US, Group, mnesia) -> @@ -865,12 +866,17 @@ add_user_to_group(Host, US, Group, odbc) -> end, ejabberd_odbc:sql_transaction(Host, F). -push_displayed_to_user(LUser, LServer, Group, Host, - Subscription) -> +get_displayed_groups(Group, LServer) -> GroupsOpts = groups_with_opts(LServer), GroupOpts = proplists:get_value(Group, GroupsOpts, []), - DisplayedGroups = proplists:get_value(displayed_groups, - GroupOpts, []), + proplists:get_value(displayed_groups, GroupOpts, []). + +broadcast_displayed_to_user(LUser, LServer, Host, Subscription, DisplayedGroups) -> + [broadcast_members_to_user(LUser, LServer, DGroup, Host, + Subscription) + || DGroup <- DisplayedGroups]. + +push_displayed_to_user(LUser, LServer, Host, Subscription, DisplayedGroups) -> [push_members_to_user(LUser, LServer, DGroup, Host, Subscription) || DGroup <- DisplayedGroups]. @@ -894,10 +900,10 @@ remove_user_from_group(Host, US, Group) -> nomatch -> Result = remove_user_from_group(Host, US, Group, gen_mod:db_type(Host, ?MODULE)), - push_user_to_displayed(LUser, LServer, Group, Host, - remove), - push_displayed_to_user(LUser, LServer, Group, Host, - remove), + DisplayedToGroups = displayed_to_groups(Group, Host), + DisplayedGroups = get_displayed_groups(Group, LServer), + push_user_to_displayed(LUser, LServer, Group, Host, remove, DisplayedToGroups), + push_displayed_to_user(LUser, LServer, Host, remove, DisplayedGroups), Result end. @@ -930,10 +936,17 @@ push_members_to_user(LUser, LServer, Group, Host, end, Members). +broadcast_members_to_user(LUser, LServer, Group, Host, Subscription) -> + Members = get_group_users(Host, Group), + lists:foreach( + fun({U, S}) -> + broadcast_subscription(U, S, {LUser, LServer, <<"">>}, Subscription) + end, Members). + register_user(User, Server) -> Groups = get_user_groups({User, Server}), [push_user_to_displayed(User, Server, Group, Server, - both) + both, displayed_to_groups(Group, Server)) || Group <- Groups]. remove_user(User, Server) -> @@ -965,17 +978,18 @@ push_user_to_members(User, Server, Subscription) -> end, lists:usort(SpecialGroups ++ UserGroups)). -push_user_to_displayed(LUser, LServer, Group, Host, - Subscription) -> +push_user_to_displayed(LUser, LServer, Group, Host, Subscription, DisplayedToGroupsOpts) -> GroupsOpts = groups_with_opts(Host), GroupOpts = proplists:get_value(Group, GroupsOpts, []), GroupName = proplists:get_value(name, GroupOpts, Group), - DisplayedToGroupsOpts = displayed_to_groups(Group, - Host), [push_user_to_group(LUser, LServer, GroupD, Host, GroupName, Subscription) || {GroupD, _Opts} <- DisplayedToGroupsOpts]. +broadcast_user_to_displayed(LUser, LServer, Host, Subscription, DisplayedToGroupsOpts) -> + [broadcast_user_to_group(LUser, LServer, GroupD, Host, Subscription) + || {GroupD, _Opts} <- DisplayedToGroupsOpts]. + push_user_to_group(LUser, LServer, Group, Host, GroupName, Subscription) -> lists:foreach(fun ({U, S}) @@ -987,6 +1001,13 @@ push_user_to_group(LUser, LServer, Group, Host, end, get_group_users(Host, Group)). +broadcast_user_to_group(LUser, LServer, Group, Host, Subscription) -> + lists:foreach( + fun({U, S}) when (U == LUser) and (S == LServer) -> ok; + ({U, S}) -> + broadcast_subscription(LUser, LServer, {U, S, <<"">>}, Subscription) + end, get_group_users(Host, Group)). + %% Get list of groups to which this group is displayed displayed_to_groups(GroupName, LServer) -> GroupsOpts = groups_with_opts(LServer), @@ -997,11 +1018,7 @@ displayed_to_groups(GroupName, LServer) -> end, GroupsOpts). -push_item(User, Server, From, Item) -> - ejabberd_sm:route(From, - jlib:make_jid(User, Server, <<"">>), - {broadcast, {item, Item#roster.jid, - Item#roster.subscription}}), +push_item(User, Server, Item) -> Stanza = jlib:iq_to_xml(#iq{type = set, xmlns = ?NS_ROSTER, id = <<"push", (randoms:get_string())/binary>>, @@ -1022,8 +1039,7 @@ push_roster_item(User, Server, ContactU, ContactS, us = {User, Server}, jid = {ContactU, ContactS, <<"">>}, name = <<"">>, subscription = Subscription, ask = none, groups = [GroupName]}, - push_item(User, Server, - jlib:make_jid(<<"">>, Server, <<"">>), Item). + push_item(User, Server, Item). item_to_xml(Item) -> Attrs1 = [{<<"jid">>, @@ -1067,14 +1083,16 @@ user_available(New) -> case length(Resources) of %% first session for this user 1 -> - OnlineGroups = get_special_users_groups_online(LServer), + UserGroups = get_user_groups({LUser, LServer}), lists:foreach(fun (OG) -> ?DEBUG("user_available: pushing ~p @ ~p grp ~p", [LUser, LServer, OG]), - push_user_to_displayed(LUser, LServer, OG, - LServer, both) + DisplayedToGroups = displayed_to_groups(OG, LServer), + DisplayedGroups = get_displayed_groups(OG, LServer), + broadcast_displayed_to_user(LUser, LServer, LServer, both, DisplayedGroups), + broadcast_user_to_displayed(LUser, LServer, LServer, both, DisplayedToGroups) end, - OnlineGroups); + UserGroups); _ -> ok end. @@ -1089,9 +1107,9 @@ unset_presence(LUser, LServer, Resource, Status) -> OnlineGroups = get_special_users_groups_online(LServer), lists:foreach(fun (OG) -> push_user_to_displayed(LUser, LServer, OG, - LServer, remove), - push_displayed_to_user(LUser, LServer, OG, - LServer, remove) + LServer, remove, displayed_to_groups(OG, LServer)), + push_displayed_to_user(LUser, LServer, + LServer, remove, displayed_to_groups(OG, LServer)) end, OnlineGroups); _ -> ok @@ -1306,6 +1324,11 @@ shared_roster_group_parse_query(Host, Group, Query) -> true -> [{online_users, true}]; false -> [] end, + CurrentDisplayedGroups = get_displayed_groups(Group, Host), + AddedDisplayedGroups = DispGroups -- CurrentDisplayedGroups, + RemovedDisplayedGroups = CurrentDisplayedGroups -- DispGroups, + displayed_groups_update(OldMembers, RemovedDisplayedGroups, remove), + displayed_groups_update(OldMembers, AddedDisplayedGroups, both), (?MODULE):set_group_opts(Host, Group, NameOpt ++ DispGroupsOpt ++ @@ -1346,6 +1369,25 @@ split_grouphost(Host, Group) -> [_] -> {Host, Group} end. +broadcast_subscription(User, Server, ContactJid, Subscription) -> + ejabberd_sm:route( + jlib:make_jid(<<"">>, Server, <<"">>), + jlib:make_jid(User, Server, <<"">>), + {broadcast, {item, ContactJid, + Subscription}}). + +displayed_groups_update(Members, DisplayedGroups, Subscription) -> + lists:foreach(fun({U, S}) -> + push_displayed_to_user(U, S, S, Subscription, DisplayedGroups), + case Subscription of + both -> + broadcast_displayed_to_user(U, S, S, to, DisplayedGroups), + broadcast_displayed_to_user(U, S, S, from, DisplayedGroups); + Subscr -> + broadcast_displayed_to_user(U, S, S, Subscr, DisplayedGroups) + end + end, Members). + make_jid_s(U, S) -> ejabberd_odbc:escape(jlib:jid_to_string(jlib:jid_tolower(jlib:make_jid(U, S,