diff options
-rw-r--r-- | src/ejabberd_sm.erl | 29 | ||||
-rw-r--r-- | src/mod_carboncopy.erl | 52 |
2 files changed, 49 insertions, 32 deletions
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 1db93f6ca..b1673d4b9 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -37,6 +37,7 @@ bounce_offline_message/3, disconnect_removed_user/2, get_user_resources/2, + get_user_present_resources/2, set_presence/7, unset_presence/6, close_session_unset_presence/5, @@ -166,6 +167,20 @@ get_user_resources(User, Server) -> [element(3, S#session.usr) || S <- clean_session_list(Ss)] end. +-spec get_user_present_resources(binary(), binary()) -> [tuple()]. + +get_user_present_resources(LUser, LServer) -> + US = {LUser, LServer}, + case catch mnesia:dirty_index_read(session, US, + #session.us) + of + {'EXIT', _Reason} -> []; + Ss -> + [{S#session.priority, element(3, S#session.usr)} + || S <- clean_session_list(Ss), + is_integer(S#session.priority)] + end. + -spec get_user_ip(binary(), binary(), binary()) -> ip(). get_user_ip(User, Server, Resource) -> @@ -669,20 +684,6 @@ clean_session_list([S1, S2 | Rest], Res) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -get_user_present_resources(LUser, LServer) -> - US = {LUser, LServer}, - case catch mnesia:dirty_index_read(session, US, - #session.us) - of - {'EXIT', _Reason} -> []; - Ss -> - [{S#session.priority, element(3, S#session.usr)} - || S <- clean_session_list(Ss), - is_integer(S#session.priority)] - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - %% On new session, check if some existing connections need to be replace check_for_sessions_to_replace(User, Server, Resource) -> LUser = jlib:nodeprep(User), diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 69362bd77..16f0c06fc 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -127,23 +127,18 @@ iq_handler(From, _To, #iq{type=set, sub_el = #xmlel{name = Operation, children iq_handler(_From, _To, IQ, _CC)-> IQ#iq{type=error, sub_el = [?ERR_NOT_ALLOWED]}. -user_send_packet(From, _To, Packet) -> - check_and_forward(From, Packet, sent). +user_send_packet(From, To, Packet) -> + check_and_forward(From, To, Packet, sent). -%% Only make carbon copies if the original destination was not a bare jid. -%% If the original destination was a bare jid, the message is going to be delivered to all -%% connected resources anyway. Avoid duplicate delivery. "XEP-0280 : 3.5 Receiving Messages" -user_receive_packet(JID, _From, #jid{resource=Resource} = _To, Packet) when Resource /= <<>> -> - check_and_forward(JID, Packet, received); -user_receive_packet(_JID, _From, _To, _Packet) -> - ok. +user_receive_packet(JID, _From, To, Packet) -> + check_and_forward(JID, To, Packet, received). % verifier si le trafic est local % Modified from original version: % - registered to the user_send_packet hook, to be called only once even for multicast % - do not support "private" message mode, and do not modify the original packet in any way % - we also replicate "read" notifications -check_and_forward(JID, #xmlel{name = <<"message">>, attrs = Attrs} = Packet, Direction)-> +check_and_forward(JID, To, #xmlel{name = <<"message">>, attrs = Attrs} = Packet, Direction)-> case xml:get_attr_s(<<"type">>, Attrs) of <<"chat">> -> case xml:get_subtag(Packet, <<"private">>) of @@ -154,11 +149,11 @@ check_and_forward(JID, #xmlel{name = <<"message">>, attrs = Attrs} = Packet, Dir %% receiving message back to original sender. SubTag = xml:get_subtag(Packet,<<"sent">>), if SubTag == false -> - send_copies(JID, Packet, Direction); + send_copies(JID, To, Packet, Direction); true -> case xml:get_subtag(SubTag,<<"forwarded">>) of false-> - send_copies(JID, Packet, Direction); + send_copies(JID, To, Packet, Direction); _ -> stop end @@ -174,7 +169,7 @@ check_and_forward(JID, #xmlel{name = <<"message">>, attrs = Attrs} = Packet, Dir ok end; -check_and_forward(_JID, _Packet, _)-> ok. +check_and_forward(_JID, _To, _Packet, _)-> ok. remove_connection(User, Server, Resource, _Status)-> disable(Server, User, Resource), @@ -183,14 +178,35 @@ remove_connection(User, Server, Resource, _Status)-> %%% Internal %% Direction = received | sent <received xmlns='urn:xmpp:carbons:1'/> -send_copies(JID, Packet, Direction)-> +send_copies(JID, To, Packet, Direction)-> {U, S, R} = jlib:jid_tolower(JID), + PrioRes = ejabberd_sm:get_user_present_resources(U, S), + IsBareTo = case {Direction, To} of + {received, #jid{lresource = <<>>}} -> true; + {received, #jid{lresource = LRes}} -> + %% unavailable resources are handled like bare JIDs + case lists:keyfind(LRes, 2, PrioRes) of + false -> true; + _ -> false + end; + _ -> false + end, %% list of JIDs that should receive a carbon copy of this message (excluding the - %% receiver of the original message - TargetJIDs = [ {jlib:make_jid({U, S, CCRes}), CC_Version} || {CCRes, CC_Version} <- list(U, S), CCRes /= R ], - %TargetJIDs = lists:delete(JID, [ jlib:make_jid({U, S, CCRes}) || CCRes <- list(U, S) ]), - + %% receiver(s) of the original message + TargetJIDs = if IsBareTo -> + MaxPrio = case catch lists:max(PrioRes) of + {Prio, _Res} -> Prio; + _ -> 0 + end, + OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end, + [ {jlib:make_jid({U, S, CCRes}), CC_Version} + || {CCRes, CC_Version} <- list(U, S), not OrigTo(CCRes) ]; + true -> + [ {jlib:make_jid({U, S, CCRes}), CC_Version} + || {CCRes, CC_Version} <- list(U, S), CCRes /= R ] + %TargetJIDs = lists:delete(JID, [ jlib:make_jid({U, S, CCRes}) || CCRes <- list(U, S) ]), + end, lists:map(fun({Dest,Version}) -> {_, _, Resource} = jlib:jid_tolower(Dest), |