diff options
author | Evgeny Khramtsov <xramtsov@gmail.com> | 2016-11-24 15:43:38 +0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-24 15:43:38 +0400 |
commit | 8f692f51d82e440a59649b6edc8ab202b6b3079f (patch) | |
tree | 0d7161b67db427cad7c28eb1afb79720833465a5 /src | |
parent | Use new versions of fast_xml and xmpp (diff) | |
parent | Use xmpp:put_meta/3 to update metadata (diff) |
Merge pull request #1391 from weiss/mark-copies
Mark messages as copies by attaching metadata
Diffstat (limited to 'src')
-rw-r--r-- | src/ejabberd_c2s.erl | 44 | ||||
-rw-r--r-- | src/ejabberd_sm.erl | 22 | ||||
-rw-r--r-- | src/mod_carboncopy.erl | 30 | ||||
-rw-r--r-- | src/mod_mam.erl | 39 |
4 files changed, 53 insertions, 82 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7ef708d31..6d84d8d93 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -2645,44 +2645,30 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData) Txt = <<"User session terminated">>, ejabberd_router:route_error( To, From, El, xmpp:err_service_unavailable(Txt, Lang)); + (From, _To, #message{meta = #{carbon_copy := true}}, _Time) -> + %% XEP-0280 says: "When a receiving server attempts to deliver a + %% forked message, and that message bounces with an error for + %% any reason, the receiving server MUST NOT forward that error + %% back to the original sender." Resending such a stanza could + %% easily lead to unexpected results as well. + ?DEBUG("Dropping forwarded message stanza from ~s", + [jid:to_string(From)]); (From, To, El, Time) -> - %% We'll drop the stanza if it was <forwarded/> by some - %% encapsulating protocol as per XEP-0297. One such protocol is - %% XEP-0280, which says: "When a receiving server attempts to - %% deliver a forked message, and that message bounces with an - %% error for any reason, the receiving server MUST NOT forward - %% that error back to the original sender." Resending such a - %% stanza could easily lead to unexpected results as well. - case is_encapsulated_forward(El) of + case ejabberd_hooks:run_fold(message_is_archived, + StateData#state.server, false, + [StateData, From, + StateData#state.jid, El]) of true -> - ?DEBUG("Dropping forwarded message stanza from ~s", - [jid:to_string(From)]); + ?DEBUG("Dropping archived message stanza from ~p", + [jid:to_string(xmpp:get_from(El))]); false -> - case ejabberd_hooks:run_fold(message_is_archived, - StateData#state.server, - false, - [StateData, From, - StateData#state.jid, El]) of - true -> - ?DEBUG("Dropping archived message stanza from ~p", - [jid:to_string(xmpp:get_from(El))]); - false -> - ReRoute(From, To, El, Time) - end + ReRoute(From, To, El, Time) end end, handle_unacked_stanzas(StateData, F); handle_unacked_stanzas(_StateData) -> ok. --spec is_encapsulated_forward(stanza()) -> boolean(). -is_encapsulated_forward(#message{} = Msg) -> - xmpp:has_subtag(Msg, #forwarded{}) orelse - xmpp:has_subtag(Msg, #carbons_sent{}) orelse - xmpp:has_subtag(Msg, #carbons_received{}); -is_encapsulated_forward(_El) -> - false. - -spec inherit_session_state(state(), binary()) -> {ok, state()} | {error, binary()} | {error, binary(), non_neg_integer()}. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 18703dc9c..d40db28cc 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -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,15 @@ 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) -> + xmpp:put_meta(Packet, sm_copy, true); +maybe_mark_as_copy(Packet, _, _, _, _) -> + Packet. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec clean_session_list([#session{}]) -> [#session{}]. clean_session_list(Ss) -> diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 1c8ca1fdc..5839a65b2 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -52,9 +52,10 @@ -callback list(binary(), binary()) -> [{binary(), binary()}]. -spec is_carbon_copy(stanza()) -> boolean(). -is_carbon_copy(Packet) -> - xmpp:has_subtag(Packet, #carbons_sent{}) orelse - xmpp:has_subtag(Packet, #carbons_received{}). +is_carbon_copy(#message{meta = #{carbon_copy := true}}) -> + true; +is_carbon_copy(_) -> + false. start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts,fun gen_iq_handler:check_type/1, one_queue), @@ -153,7 +154,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 +167,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), @@ -203,7 +204,8 @@ build_forward_packet(JID, #message{type = T} = Msg, Sender, Dest, Direction) -> sent -> #carbons_sent{forwarded = Forwarded}; received -> #carbons_received{forwarded = Forwarded} end, - #message{from = Sender, to = Dest, type = T, sub_els = [Carbon]}. + #message{from = Sender, to = Dest, type = T, sub_els = [Carbon], + meta = #{carbon_copy => true}}. -spec enable(binary(), binary(), binary(), binary()) -> ok | {error, any()}. enable(Host, U, R, CC)-> diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 61754ae59..0433dee79 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -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, |