diff options
Diffstat (limited to 'src/mod_carboncopy.erl')
-rw-r--r-- | src/mod_carboncopy.erl | 104 |
1 files changed, 54 insertions, 50 deletions
diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index 24c09bffd..81cf78a9d 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -7,7 +7,7 @@ %%% {mod_carboncopy, []} %%% %%% -%%% ejabberd, Copyright (C) 2002-2015 ProcessOne +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -25,7 +25,9 @@ %%% %%%---------------------------------------------------------------------- -module (mod_carboncopy). + -author ('ecestari@process-one.net'). +-protocol({xep, 280, '0.8'}). -behavior(gen_mod). @@ -33,13 +35,9 @@ -export([start/2, stop/1]). -%% Hooks: --export([user_send_packet/3, - user_receive_packet/4, - iq_handler2/3, - iq_handler1/3, - remove_connection/4, - is_carbon_copy/1]). +-export([user_send_packet/4, user_receive_packet/5, + iq_handler2/3, iq_handler1/3, remove_connection/4, + is_carbon_copy/1, mod_opt_type/1]). -include("ejabberd.hrl"). -include("logger.hrl"). @@ -57,9 +55,9 @@ is_carbon_copy(Packet) -> is_carbon_copy(Packet, <<"received">>). is_carbon_copy(Packet, Direction) -> - case xml:get_subtag(Packet, Direction) of + case fxml:get_subtag(Packet, Direction) of #xmlel{name = Direction, attrs = Attrs} -> - case xml:get_attr_s(<<"xmlns">>, Attrs) of + case fxml:get_attr_s(<<"xmlns">>, Attrs) of ?NS_CARBONS_2 -> true; ?NS_CARBONS_1 -> true; _ -> false @@ -106,7 +104,7 @@ iq_handler1(From, To, IQ) -> iq_handler(From, _To, #iq{type=set, sub_el = #xmlel{name = Operation, children = []}} = IQ, CC)-> ?DEBUG("carbons IQ received: ~p", [IQ]), - {U, S, R} = jlib:jid_tolower(From), + {U, S, R} = jid:tolower(From), Result = case Operation of <<"enable">>-> ?INFO_MSG("carbons enabled for user ~s@~s/~s", [U,S,R]), @@ -115,7 +113,7 @@ iq_handler(From, _To, #iq{type=set, sub_el = #xmlel{name = Operation, children ?INFO_MSG("carbons disabled for user ~s@~s/~s", [U,S,R]), disable(S, U, R) end, - case Result of + case Result of ok -> ?DEBUG("carbons IQ result: ok", []), IQ#iq{type=result, sub_el=[]}; @@ -127,43 +125,43 @@ 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) -> +user_send_packet(Packet, _C2SState, From, To) -> check_and_forward(From, To, Packet, sent). -user_receive_packet(JID, _From, To, Packet) -> +user_receive_packet(Packet, _C2SState, JID, _From, To) -> check_and_forward(JID, To, Packet, received). - -% verifier si le trafic est local -% Modified from original version: + +% 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, To, Packet, Direction)-> - case is_chat_or_normal_message(Packet) andalso - xml:get_subtag(Packet, <<"private">>) == false andalso - xml:get_subtag(Packet, <<"no-copy">>) == false of + case is_chat_message(Packet) andalso + fxml:get_subtag(Packet, <<"private">>) == false andalso + fxml:get_subtag(Packet, <<"no-copy">>) == false of true -> case is_carbon_copy(Packet) of false -> - send_copies(JID, To, Packet, Direction); + send_copies(JID, To, Packet, Direction), + Packet; true -> - %% stop the hook chain, we don't want mod_logdb to register - %% this message (duplicate) - stop + %% stop the hook chain, we don't want logging modules to duplicates + %% this message + {stop, Packet} end; _ -> - ok + Packet end. remove_connection(User, Server, Resource, _Status)-> disable(Server, User, Resource), ok. - + %%% Internal %% Direction = received | sent <received xmlns='urn:xmpp:carbons:1'/> send_copies(JID, To, Packet, Direction)-> - {U, S, R} = jlib:jid_tolower(JID), + {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 @@ -182,7 +180,7 @@ send_copies(JID, To, Packet, Direction)-> TargetJIDs = case {IsBareTo, R} of {true, MaxRes} -> OrigTo = fun(Res) -> lists:member({MaxPrio, Res}, PrioRes) end, - [ {jlib:make_jid({U, S, CCRes}), CC_Version} + [ {jid:make({U, S, CCRes}), CC_Version} || {CCRes, CC_Version} <- list(U, S), lists:member(CCRes, AvailRs), not OrigTo(CCRes) ]; {true, _} -> @@ -193,16 +191,16 @@ send_copies(JID, To, Packet, Direction)-> %% MaxRes) in order to avoid duplicates. []; {false, _} -> - [ {jlib:make_jid({U, S, CCRes}), CC_Version} + [ {jid:make({U, S, CCRes}), CC_Version} || {CCRes, CC_Version} <- list(U, S), lists:member(CCRes, AvailRs), CCRes /= R ] - %TargetJIDs = lists:delete(JID, [ jlib:make_jid({U, S, CCRes}) || CCRes <- list(U, S) ]), + %TargetJIDs = lists:delete(JID, [ jid:make({U, S, CCRes}) || CCRes <- list(U, S) ]), end, lists:map(fun({Dest,Version}) -> - {_, _, Resource} = jlib:jid_tolower(Dest), + {_, _, Resource} = jid:tolower(Dest), ?DEBUG("Sending: ~p =/= ~p", [R, Resource]), - Sender = jlib:make_jid({U, S, <<>>}), + Sender = jid:make({U, S, <<>>}), %{xmlelement, N, A, C} = Packet, New = build_forward_packet(JID, Packet, Sender, Dest, Direction, Version), ejabberd_router:route(Sender, Dest, New) @@ -210,31 +208,31 @@ send_copies(JID, To, Packet, Direction)-> ok. build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_2) -> - #xmlel{name = <<"message">>, + #xmlel{name = <<"message">>, attrs = [{<<"xmlns">>, <<"jabber:client">>}, {<<"type">>, message_type(Packet)}, - {<<"from">>, jlib:jid_to_string(Sender)}, - {<<"to">>, jlib:jid_to_string(Dest)}], - children = [ - #xmlel{name = list_to_binary(atom_to_list(Direction)), + {<<"from">>, jid:to_string(Sender)}, + {<<"to">>, jid:to_string(Dest)}], + children = [ + #xmlel{name = list_to_binary(atom_to_list(Direction)), attrs = [{<<"xmlns">>, ?NS_CARBONS_2}], children = [ - #xmlel{name = <<"forwarded">>, + #xmlel{name = <<"forwarded">>, attrs = [{<<"xmlns">>, ?NS_FORWARD}], children = [ complete_packet(JID, Packet, Direction)]} ]} ]}; build_forward_packet(JID, Packet, Sender, Dest, Direction, ?NS_CARBONS_1) -> - #xmlel{name = <<"message">>, + #xmlel{name = <<"message">>, attrs = [{<<"xmlns">>, <<"jabber:client">>}, {<<"type">>, message_type(Packet)}, - {<<"from">>, jlib:jid_to_string(Sender)}, - {<<"to">>, jlib:jid_to_string(Dest)}], - children = [ - #xmlel{name = list_to_binary(atom_to_list(Direction)), + {<<"from">>, jid:to_string(Sender)}, + {<<"to">>, jid:to_string(Dest)}], + children = [ + #xmlel{name = list_to_binary(atom_to_list(Direction)), attrs = [{<<"xmlns">>, ?NS_CARBONS_1}]}, - #xmlel{name = <<"forwarded">>, + #xmlel{name = <<"forwarded">>, attrs = [{<<"xmlns">>, ?NS_FORWARD}], children = [complete_packet(JID, Packet, Direction)]} ]}. @@ -261,7 +259,7 @@ complete_packet(From, #xmlel{name = <<"message">>, attrs = OrigAttrs} = Packet, Attrs = lists:keystore(<<"xmlns">>, 1, OrigAttrs, {<<"xmlns">>, <<"jabber:client">>}), case proplists:get_value(<<"from">>, Attrs) of undefined -> - Packet#xmlel{attrs = [{<<"from">>, jlib:jid_to_string(From)}|Attrs]}; + Packet#xmlel{attrs = [{<<"from">>, jid:to_string(From)}|Attrs]}; _ -> Packet#xmlel{attrs = Attrs} end; @@ -270,20 +268,26 @@ complete_packet(_From, #xmlel{name = <<"message">>, attrs=OrigAttrs} = Packet, r Packet#xmlel{attrs = Attrs}. message_type(#xmlel{attrs = Attrs}) -> - case xml:get_attr(<<"type">>, Attrs) of + case fxml:get_attr(<<"type">>, Attrs) of {value, Type} -> Type; false -> <<"normal">> end. -is_chat_or_normal_message(#xmlel{name = <<"message">>} = Packet) -> +is_chat_message(#xmlel{name = <<"message">>} = Packet) -> case message_type(Packet) of <<"chat">> -> true; - <<"normal">> -> true; + <<"normal">> -> has_non_empty_body(Packet); _ -> false end; -is_chat_or_normal_message(_Packet) -> false. +is_chat_message(_Packet) -> false. + +has_non_empty_body(Packet) -> + fxml:get_subtag_cdata(Packet, <<"body">>) =/= <<"">>. %% list {resource, cc_version} with carbons enabled for given user and host -list(User, Server)-> +list(User, Server) -> mnesia:dirty_select(?TABLE, [{#carboncopy{us = {User, Server}, resource = '$2', version = '$3'}, [], [{{'$2','$3'}}]}]). + +mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1; +mod_opt_type(_) -> [iqdisc]. |