mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Merge pull request #1391 from weiss/mark-copies
Mark messages as copies by attaching metadata
This commit is contained in:
commit
8f692f51d8
@ -2645,44 +2645,30 @@ handle_unacked_stanzas(#state{mgmt_state = MgmtState} = StateData)
|
|||||||
Txt = <<"User session terminated">>,
|
Txt = <<"User session terminated">>,
|
||||||
ejabberd_router:route_error(
|
ejabberd_router:route_error(
|
||||||
To, From, El, xmpp:err_service_unavailable(Txt, Lang));
|
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) ->
|
(From, To, El, Time) ->
|
||||||
%% We'll drop the stanza if it was <forwarded/> by some
|
case ejabberd_hooks:run_fold(message_is_archived,
|
||||||
%% encapsulating protocol as per XEP-0297. One such protocol is
|
StateData#state.server, false,
|
||||||
%% XEP-0280, which says: "When a receiving server attempts to
|
[StateData, From,
|
||||||
%% deliver a forked message, and that message bounces with an
|
StateData#state.jid, El]) of
|
||||||
%% 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
|
|
||||||
true ->
|
true ->
|
||||||
?DEBUG("Dropping forwarded message stanza from ~s",
|
?DEBUG("Dropping archived message stanza from ~p",
|
||||||
[jid:to_string(From)]);
|
[jid:to_string(xmpp:get_from(El))]);
|
||||||
false ->
|
false ->
|
||||||
case ejabberd_hooks:run_fold(message_is_archived,
|
ReRoute(From, To, El, Time)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
handle_unacked_stanzas(StateData, F);
|
handle_unacked_stanzas(StateData, F);
|
||||||
handle_unacked_stanzas(_StateData) ->
|
handle_unacked_stanzas(_StateData) ->
|
||||||
ok.
|
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()} |
|
-spec inherit_session_state(state(), binary()) -> {ok, state()} |
|
||||||
{error, binary()} |
|
{error, binary()} |
|
||||||
{error, binary(), non_neg_integer()}.
|
{error, binary(), non_neg_integer()}.
|
||||||
|
@ -570,9 +570,9 @@ route_message(From, To, Packet, Type) ->
|
|||||||
LServer = To#jid.lserver,
|
LServer = To#jid.lserver,
|
||||||
PrioRes = get_user_present_resources(LUser, LServer),
|
PrioRes = get_user_present_resources(LUser, LServer),
|
||||||
case catch lists:max(PrioRes) of
|
case catch lists:max(PrioRes) of
|
||||||
{Priority, _R}
|
{MaxPrio, MaxRes}
|
||||||
when is_integer(Priority), Priority >= 0 ->
|
when is_integer(MaxPrio), MaxPrio >= 0 ->
|
||||||
lists:foreach(fun ({P, R}) when P == Priority;
|
lists:foreach(fun ({P, R}) when P == MaxPrio;
|
||||||
(P >= 0) and (Type == headline) ->
|
(P >= 0) and (Type == headline) ->
|
||||||
LResource = jid:resourceprep(R),
|
LResource = jid:resourceprep(R),
|
||||||
Mod = get_sm_backend(LServer),
|
Mod = get_sm_backend(LServer),
|
||||||
@ -584,7 +584,12 @@ route_message(From, To, Packet, Type) ->
|
|||||||
Session = lists:max(Ss),
|
Session = lists:max(Ss),
|
||||||
Pid = element(2, Session#session.sid),
|
Pid = element(2, Session#session.sid),
|
||||||
?DEBUG("sending to process ~p~n", [Pid]),
|
?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;
|
end;
|
||||||
%% Ignore other priority:
|
%% Ignore other priority:
|
||||||
({_Prio, _Res}) -> ok
|
({_Prio, _Res}) -> ok
|
||||||
@ -603,6 +608,15 @@ route_message(From, To, Packet, Type) ->
|
|||||||
end
|
end
|
||||||
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{}].
|
-spec clean_session_list([#session{}]) -> [#session{}].
|
||||||
clean_session_list(Ss) ->
|
clean_session_list(Ss) ->
|
||||||
|
@ -52,9 +52,10 @@
|
|||||||
-callback list(binary(), binary()) -> [{binary(), binary()}].
|
-callback list(binary(), binary()) -> [{binary(), binary()}].
|
||||||
|
|
||||||
-spec is_carbon_copy(stanza()) -> boolean().
|
-spec is_carbon_copy(stanza()) -> boolean().
|
||||||
is_carbon_copy(Packet) ->
|
is_carbon_copy(#message{meta = #{carbon_copy := true}}) ->
|
||||||
xmpp:has_subtag(Packet, #carbons_sent{}) orelse
|
true;
|
||||||
xmpp:has_subtag(Packet, #carbons_received{}).
|
is_carbon_copy(_) ->
|
||||||
|
false.
|
||||||
|
|
||||||
start(Host, Opts) ->
|
start(Host, Opts) ->
|
||||||
IQDisc = gen_mod:get_opt(iqdisc, Opts,fun gen_iq_handler:check_type/1, one_queue),
|
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),
|
{U, S, R} = jid:tolower(JID),
|
||||||
PrioRes = ejabberd_sm:get_user_present_resources(U, S),
|
PrioRes = ejabberd_sm:get_user_present_resources(U, S),
|
||||||
{_, AvailRs} = lists:unzip(PrioRes),
|
{_, AvailRs} = lists:unzip(PrioRes),
|
||||||
{MaxPrio, MaxRes} = case catch lists:max(PrioRes) of
|
{MaxPrio, _MaxRes} = case catch lists:max(PrioRes) of
|
||||||
{Prio, Res} -> {Prio, Res};
|
{Prio, Res} -> {Prio, Res};
|
||||||
_ -> {0, undefined}
|
_ -> {0, undefined}
|
||||||
end,
|
end,
|
||||||
@ -166,19 +167,19 @@ send_copies(JID, To, Packet, Direction)->
|
|||||||
end,
|
end,
|
||||||
%% list of JIDs that should receive a carbon copy of this message (excluding the
|
%% list of JIDs that should receive a carbon copy of this message (excluding the
|
||||||
%% receiver(s) of the original message
|
%% receiver(s) of the original message
|
||||||
TargetJIDs = case {IsBareTo, R} of
|
TargetJIDs = case {IsBareTo, Packet} of
|
||||||
{true, MaxRes} ->
|
{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 in order to avoid
|
||||||
|
%% duplicates.
|
||||||
|
[];
|
||||||
|
{true, _} ->
|
||||||
OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end,
|
OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end,
|
||||||
[ {jid:make({U, S, CCRes}), CC_Version}
|
[ {jid:make({U, S, CCRes}), CC_Version}
|
||||||
|| {CCRes, CC_Version} <- list(U, S),
|
|| {CCRes, CC_Version} <- list(U, S),
|
||||||
lists:member(CCRes, AvailRs), not OrigTo(CCRes) ];
|
lists:member(CCRes, AvailRs), not OrigTo(CCRes) ];
|
||||||
{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.
|
|
||||||
[];
|
|
||||||
{false, _} ->
|
{false, _} ->
|
||||||
[ {jid:make({U, S, CCRes}), CC_Version}
|
[ {jid:make({U, S, CCRes}), CC_Version}
|
||||||
|| {CCRes, CC_Version} <- list(U, S),
|
|| {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};
|
sent -> #carbons_sent{forwarded = Forwarded};
|
||||||
received -> #carbons_received{forwarded = Forwarded}
|
received -> #carbons_received{forwarded = Forwarded}
|
||||||
end,
|
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()}.
|
-spec enable(binary(), binary(), binary(), binary()) -> ok | {error, any()}.
|
||||||
enable(Host, U, R, CC)->
|
enable(Host, U, R, CC)->
|
||||||
|
@ -200,12 +200,11 @@ set_room_option(Acc, _Property, _Lang) ->
|
|||||||
Acc.
|
Acc.
|
||||||
|
|
||||||
-spec user_receive_packet(stanza(), ejabberd_c2s:state(), jid(), jid(), jid()) -> stanza().
|
-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,
|
LUser = JID#jid.luser,
|
||||||
LServer = JID#jid.lserver,
|
LServer = JID#jid.lserver,
|
||||||
IsBareCopy = is_bare_copy(JID, To),
|
|
||||||
case should_archive(Pkt, LServer) of
|
case should_archive(Pkt, LServer) of
|
||||||
true when not IsBareCopy ->
|
true ->
|
||||||
NewPkt = strip_my_archived_tag(Pkt, LServer),
|
NewPkt = strip_my_archived_tag(Pkt, LServer),
|
||||||
case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of
|
case store_msg(C2SState, NewPkt, LUser, LServer, Peer, recv) of
|
||||||
{ok, ID} ->
|
{ok, ID} ->
|
||||||
@ -454,6 +453,8 @@ process_iq(LServer, #iq{from = #jid{luser = LUser}, lang = Lang,
|
|||||||
|
|
||||||
should_archive(#message{type = error}, _LServer) ->
|
should_archive(#message{type = error}, _LServer) ->
|
||||||
false;
|
false;
|
||||||
|
should_archive(#message{meta = #{sm_copy := true}}, _LServer) ->
|
||||||
|
false;
|
||||||
should_archive(#message{body = Body, subject = Subject,
|
should_archive(#message{body = Body, subject = Subject,
|
||||||
type = Type} = Pkt, LServer) ->
|
type = Type} = Pkt, LServer) ->
|
||||||
case is_resent(Pkt, LServer) of
|
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) ->
|
maybe_update_from_to(Pkt, _JidRequestor, _JidArchive, _Peer, chat, _Nick) ->
|
||||||
Pkt.
|
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()}],
|
-spec send([{binary(), integer(), xmlel()}],
|
||||||
non_neg_integer(), boolean(), iq()) -> iq() | ignore.
|
non_neg_integer(), boolean(), iq()) -> iq() | ignore.
|
||||||
send(Msgs, Count, IsComplete,
|
send(Msgs, Count, IsComplete,
|
||||||
|
Loading…
Reference in New Issue
Block a user