]> granicus.if.org Git - ejabberd/commitdiff
Let ejabberd_sm mark copied messages
authorHolger Weiss <holger@zedat.fu-berlin.de>
Tue, 22 Nov 2016 18:25:20 +0000 (19:25 +0100)
committerHolger Weiss <holger@zedat.fu-berlin.de>
Tue, 22 Nov 2016 18:25:20 +0000 (19:25 +0100)
When multiple resources have the same (highest) priority, ejabberd_sm
dispatches messages addressed to the bare JID (or to an unavailable
resource) to each of these resources.  Such messages are now marked with
an 'sm_copy' flag for all but one of the resources.  This makes it
easier for other modules to identify those duplicates.

Resolves #1356.

src/ejabberd_sm.erl
src/mod_carboncopy.erl
src/mod_mam.erl

index 18703dc9c9cb5d9f0b8b68be386739aef653f9e1..b3953ec49abfb1c850bdea85cca10b3fb3673343 100644 (file)
@@ -570,9 +570,9 @@ route_message(From, To, Packet, Type) ->
     LServer = To#jid.lserver,
     PrioRes = get_user_present_resources(LUser, LServer),
     case catch lists:max(PrioRes) of
-      {Priority, _R}
-         when is_integer(Priority), Priority >= 0 ->
-         lists:foreach(fun ({P, R}) when P == Priority;
+      {MaxPrio, MaxRes}
+         when is_integer(MaxPrio), MaxPrio >= 0 ->
+         lists:foreach(fun ({P, R}) when P == MaxPrio;
                                          (P >= 0) and (Type == headline) ->
                                LResource = jid:resourceprep(R),
                                Mod = get_sm_backend(LServer),
@@ -584,7 +584,12 @@ route_message(From, To, Packet, Type) ->
                                      Session = lists:max(Ss),
                                      Pid = element(2, Session#session.sid),
                                      ?DEBUG("sending to process ~p~n", [Pid]),
-                                     Pid ! {route, From, To, Packet}
+                                     LMaxRes = jid:resourceprep(MaxRes),
+                                     Packet1 = maybe_mark_as_copy(Packet,
+                                                                  LResource,
+                                                                  LMaxRes,
+                                                                  P, MaxPrio),
+                                     Pid ! {route, From, To, Packet1}
                                end;
                            %% Ignore other priority:
                            ({_Prio, _Res}) -> ok
@@ -603,6 +608,16 @@ route_message(From, To, Packet, Type) ->
            end
     end.
 
+-spec maybe_mark_as_copy(message(), binary(), binary(), integer(), integer())
+      -> message().
+maybe_mark_as_copy(Packet, R, R, P, P) ->
+    Packet;
+maybe_mark_as_copy(Packet, _, _, P, P) ->
+    Meta = Packet#message.meta,
+    Packet#message{meta = Meta#{sm_copy => true}};
+maybe_mark_as_copy(Packet, _, _, _, _) ->
+    Packet.
+
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 -spec clean_session_list([#session{}]) -> [#session{}].
 clean_session_list(Ss) ->
index 1c8ca1fdcd40ef38cfee8137182c00026d996df9..f1eb3e7900a4e687f0c86eadc45c41bffa465190 100644 (file)
@@ -153,7 +153,7 @@ send_copies(JID, To, Packet, Direction)->
     {U, S, R} = jid:tolower(JID),
     PrioRes = ejabberd_sm:get_user_present_resources(U, S),
     {_, AvailRs} = lists:unzip(PrioRes),
-    {MaxPrio, MaxRes} = case catch lists:max(PrioRes) of
+    {MaxPrio, _MaxRes} = case catch lists:max(PrioRes) of
        {Prio, Res} -> {Prio, Res};
        _ -> {0, undefined}
     end,
@@ -166,19 +166,19 @@ send_copies(JID, To, Packet, Direction)->
     end,
     %% list of JIDs that should receive a carbon copy of this message (excluding the
     %% receiver(s) of the original message
-    TargetJIDs = case {IsBareTo, R} of
-       {true, MaxRes} ->
-           OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end,
-           [ {jid:make({U, S, CCRes}), CC_Version}
-            || {CCRes, CC_Version} <- list(U, S),
-               lists:member(CCRes, AvailRs), not OrigTo(CCRes) ];
-       {true, _} ->
+    TargetJIDs = case {IsBareTo, Packet} of
+       {true, #message{meta = #{sm_copy := true}}} ->
            %% The message was sent to our bare JID, and we currently have
            %% multiple resources with the same highest priority, so the session
            %% manager routes the message to each of them. We create carbon
-           %% copies only from one of those resources (the one where R equals
-           %% MaxRes) in order to avoid duplicates.
+           %% copies only from one of those resources in order to avoid
+           %% duplicates.
            [];
+       {true, _} ->
+           OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end,
+           [ {jid:make({U, S, CCRes}), CC_Version}
+            || {CCRes, CC_Version} <- list(U, S),
+               lists:member(CCRes, AvailRs), not OrigTo(CCRes) ];
        {false, _} ->
            [ {jid:make({U, S, CCRes}), CC_Version}
             || {CCRes, CC_Version} <- list(U, S),
index 61754ae592634b3bbe104f9534cf0d98af619bbe..0433dee790155c69aac0a71b7555548319c6b6ea 100644 (file)
@@ -200,12 +200,11 @@ set_room_option(Acc, _Property, _Lang) ->
     Acc.
 
 -spec user_receive_packet(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza().
-user_receive_packet(Pkt, C2SState, JID, Peer, To) ->
+user_receive_packet(Pkt, C2SState, JID, Peer, _To) ->
     LUser = JID#jid.luser,
     LServer = JID#jid.lserver,
-    IsBareCopy = is_bare_copy(JID, To),
     case should_archive(Pkt, LServer) of
-       true when not IsBareCopy ->
+       true ->
            NewPkt = strip_my_archived_tag(Pkt, LServer),
            case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of
                {ok, ID} ->
@@ -454,6 +453,8 @@ process_iq(LServer, #iq{from = #jid{luser = LUser}, lang = Lang,
 
 should_archive(#message{type = error}, _LServer) ->
     false;
+should_archive(#message{meta = #{sm_copy := true}}, _LServer) ->
+    false;
 should_archive(#message{body = Body, subject = Subject,
                        type = Type} = Pkt, LServer) ->
     case is_resent(Pkt, LServer) of
@@ -812,38 +813,6 @@ maybe_update_from_to(#message{sub_els = Els} = Pkt, JidRequestor, JidArchive,
 maybe_update_from_to(Pkt, _JidRequestor, _JidArchive, _Peer, chat, _Nick) ->
     Pkt.
 
-is_bare_copy(#jid{luser = U, lserver = S, lresource = R}, To) ->
-    PrioRes = ejabberd_sm:get_user_present_resources(U, S),
-    MaxRes = case catch lists:max(PrioRes) of
-                {_Prio, Res} when is_binary(Res) ->
-                    Res;
-                _ ->
-                    undefined
-            end,
-    IsBareTo = case To of
-                  #jid{lresource = <<"">>} ->
-                      true;
-                  #jid{lresource = LRes} ->
-                      %% Unavailable resources are handled like bare JIDs.
-                      lists:keyfind(LRes, 2, PrioRes) =:= false
-              end,
-    case {IsBareTo, R} of
-       {true, MaxRes} ->
-           ?DEBUG("Recipient of message to bare JID has top priority: ~s@~s/~s",
-                  [U, S, R]),
-           false;
-       {true, _R} ->
-           %% The message was sent to our bare JID, and we currently have
-           %% multiple resources with the same highest priority, so the session
-           %% manager routes the message to each of them. We store the message
-           %% only from the resource where R equals MaxRes.
-           ?DEBUG("Additional recipient of message to bare JID: ~s@~s/~s",
-                  [U, S, R]),
-           true;
-       {false, _R} ->
-           false
-    end.
-
 -spec send([{binary(), integer(), xmlel()}],
           non_neg_integer(), boolean(), iq()) -> iq() | ignore.
 send(Msgs, Count, IsComplete,