]> granicus.if.org Git - ejabberd/commitdiff
Fix missing presences when adding shared groups (Github PR#99, thanks to Bokner)
authorBadlop <badlop@process-one.net>
Wed, 7 Jan 2015 12:11:53 +0000 (13:11 +0100)
committerBadlop <badlop@process-one.net>
Wed, 7 Jan 2015 12:11:53 +0000 (13:11 +0100)
src/mod_shared_roster.erl

index 91628566020abfc01a2f357f96e54d2b02dbfb75..38c5327e6aa2c8b1c1a8b9c9896a61ffb836aca4 100644 (file)
@@ -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,