aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvgeny Khramtsov <xramtsov@gmail.com>2016-11-24 15:43:38 +0400
committerGitHub <noreply@github.com>2016-11-24 15:43:38 +0400
commit8f692f51d82e440a59649b6edc8ab202b6b3079f (patch)
tree0d7161b67db427cad7c28eb1afb79720833465a5 /src
parentUse new versions of fast_xml and xmpp (diff)
parentUse 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.erl44
-rw-r--r--src/ejabberd_sm.erl22
-rw-r--r--src/mod_carboncopy.erl30
-rw-r--r--src/mod_mam.erl39
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,