From 79a804ac3b6df6bc82162a8889dee27096751ee4 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 4 Apr 2018 01:34:53 +0200 Subject: [PATCH] Update mod_message_log to work with ejabberd 18.x --- mod_message_log/src/mod_message_log.erl | 196 ++++++++++-------------- 1 file changed, 82 insertions(+), 114 deletions(-) diff --git a/mod_message_log/src/mod_message_log.erl b/mod_message_log/src/mod_message_log.erl index 9245202..f6c4621 100644 --- a/mod_message_log/src/mod_message_log.erl +++ b/mod_message_log/src/mod_message_log.erl @@ -11,11 +11,12 @@ -behaviour(gen_mod). -behaviour(gen_server). -%% gen_mod/supervisor callbacks. --export([start_link/1, - start/2, +%% gen_mod callbacks. +-export([start/2, stop/1, - mod_opt_type/1]). + mod_opt_type/1, + mod_options/1, + depends/2]). %% gen_server callbacks. -export([init/1, @@ -26,13 +27,12 @@ code_change/3]). %% ejabberd_hooks callbacks. --export([log_packet_send/4, - log_packet_receive/5, - log_packet_offline/3, +-export([log_packet_send/1, + log_packet_receive/1, + log_packet_offline/1, reopen_log/0]). --include("ejabberd.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PROCNAME, ?MODULE). -define(DEFAULT_FILENAME, <<"message.log">>). @@ -43,18 +43,13 @@ -type direction() :: incoming | outgoing | offline. -type state() :: #state{}. +-type c2s_state() :: ejabberd_c2s:state(). +-type c2s_hook_acc() :: {stanza() | drop, c2s_state()}. %% ------------------------------------------------------------------- -%% gen_mod/supervisor callbacks. +%% gen_mod callbacks. %% ------------------------------------------------------------------- - --spec start_link(gen_mod:opts()) -> {ok, pid()} | ignore | {error, _}. - -start_link(Opts) -> - gen_server:start_link({local, ?PROCNAME}, ?MODULE, Opts, []). - -spec start(binary(), gen_mod:opts()) -> {ok, _} | {ok, _, _} | {error, _}. - start(Host, Opts) -> ejabberd_hooks:add(user_send_packet, Host, ?MODULE, log_packet_send, 42), @@ -62,18 +57,16 @@ start(Host, Opts) -> log_packet_receive, 42), ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, log_packet_offline, 42), - Spec = { - ?PROCNAME, - {?MODULE, start_link, [Opts]}, - permanent, - 3000, - worker, - [?MODULE] - }, - supervisor:start_child(ejabberd_sup, Spec). + case gen_mod:start_child(?MODULE, Host, Opts) of + {ok, Ref} -> + {ok, Ref}; + {error, {already_started, Ref}} -> + {ok, Ref}; + {error, Reason} -> + {error, Reason} + end. -spec stop(binary()) -> ok. - stop(Host) -> ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, log_packet_send, 42), @@ -81,26 +74,25 @@ stop(Host) -> log_packet_receive, 42), ejabberd_hooks:delete(offline_message_hook, Host, ?MODULE, log_packet_offline, 42), - case supervisor:terminate_child(ejabberd_sup, ?PROCNAME) of - ok -> - ok = supervisor:delete_child(ejabberd_sup, ?PROCNAME); - {error, not_found} -> - ok % We just run one process per node. - end. - --spec mod_opt_type(atom()) -> fun((term()) -> term()) | [atom()]. + gen_mod:stop_child(?MODULE, Host), + ok. +-spec mod_opt_type(atom()) -> fun((term()) -> term()). mod_opt_type(filename) -> - fun iolist_to_binary/1; -mod_opt_type(_) -> - [filename]. + fun iolist_to_binary/1. + +-spec mod_options(binary()) -> [{atom(), any()}]. +mod_options(_Host) -> + [{filename, ?DEFAULT_FILENAME}]. + +-spec depends(binary(), gen_mod:opts()) -> [{module(), hard | soft}]. +depends(_Host, _Opts) -> + []. %% ------------------------------------------------------------------- %% gen_server callbacks. %% ------------------------------------------------------------------- - -spec init(gen_mod:opts()) -> {ok, state()}. - init(Opts) -> process_flag(trap_exit, true), ejabberd_hooks:add(reopen_log_hook, ?MODULE, reopen_log, 42), @@ -110,12 +102,10 @@ init(Opts) -> {ok, #state{filename = Filename, iodevice = IoDevice}}. -spec handle_call(_, {pid(), _}, state()) -> {noreply, state()}. - handle_call(_Request, _From, State) -> {noreply, State}. -spec handle_cast(_, state()) -> {noreply, state()}. - handle_cast({message, Direction, From, To, Type}, #state{iodevice = IoDevice} = State) -> write_log(IoDevice, Direction, From, To, Type), @@ -129,106 +119,85 @@ handle_cast(_Request, State) -> {noreply, State}. -spec handle_info(timeout | _, state()) -> {noreply, state()}. - handle_info(_Info, State) -> {noreply, State}. -spec terminate(normal | shutdown | {shutdown, _} | _, _) -> any(). - terminate(_Reason, State) -> ejabberd_hooks:delete(reopen_log_hook, ?MODULE, reopen_log, 42), ok = file:close(State#state.iodevice). -spec code_change({down, _} | _, state(), _) -> {ok, state()}. - code_change(_OldVsn, State, _Extra) -> {ok, State}. %% ------------------------------------------------------------------- %% ejabberd_hooks callbacks. %% ------------------------------------------------------------------- +-spec log_packet_send(c2s_hook_acc()) -> c2s_hook_acc(). +log_packet_send({#message{} = Msg, _C2SState} = Acc) -> + log_packet(outgoing, Msg), + Acc; +log_packet_send({_Stanza, _C2SState} = Acc) -> + Acc. --spec log_packet_send(xmlel(), term(), jid(), jid()) -> xmlel(). +-spec log_packet_receive(c2s_hook_acc()) -> c2s_hook_acc(). +log_packet_receive({#message{} = Msg, _C2SState} = Acc) -> + log_packet(incoming, Msg), + Acc; +log_packet_receive({_Stanza, _C2SState} = Acc) -> + Acc. -log_packet_send(Packet, _C2SState, From, To) -> - log_packet(outgoing, From, To, Packet), - Packet. - --spec log_packet_receive(xmlel(), term(), jid(), jid(), jid()) -> xmlel(). - -log_packet_receive(Packet, _C2SState, JID, From, _To) -> - log_packet(incoming, From, JID, Packet), - Packet. - --spec log_packet_offline(jid(), jid(), xmlel()) -> any(). - -log_packet_offline(From, To, Packet) -> - log_packet(offline, From, To, Packet). +-spec log_packet_offline(message()) -> any(). +log_packet_offline(Msg) -> + log_packet(offline, Msg). -spec reopen_log() -> any(). - reopen_log() -> gen_server:cast(?PROCNAME, reopen_log). %% ------------------------------------------------------------------- %% Internal functions. %% ------------------------------------------------------------------- +-spec log_packet(direction(), message()) -> any(). +log_packet(Direction, #message{from = From, to = To, type = Type} = Msg) -> + case should_log(Msg) of + true -> + {Type1, Direction1} = case is_carbon(Msg) of + {true, Direction0} -> + {carbon, Direction0}; + false -> + {Type, Direction} + end, + gen_server:cast(?PROCNAME, {message, Direction1, From, To, Type1}); + false -> + ok + end. --spec log_packet(direction(), jid(), jid(), xmlel()) -> any(). - -log_packet(Direction, From, To, #xmlel{name = <<"message">>} = Packet) -> - case fxml:get_subtag(Packet, <<"body">>) of - #xmlel{children = Body} when length(Body) > 0 -> - Type = get_message_type(Packet), - gen_server:cast(?PROCNAME, {message, Direction, From, To, Type}); - _ -> - case is_carbon(Packet) of - {true, OrigDirection} -> - gen_server:cast(?PROCNAME, {message, OrigDirection, From, To, - carbon}); - false -> - ok - end +-spec is_carbon(message()) -> {true, direction()} | false. +is_carbon(#message{meta = #{carbon_copy := true}} = Msg) -> + case xmpp:has_subtag(Msg, #carbons_sent{}) of + true -> + {true, outgoing}; + false -> + {true, incoming} end; -log_packet(_Direction, _From, _To, _Packet) -> - ok. +is_carbon(_Msg) -> + false. --spec get_message_type(xmlel()) -> binary(). - -get_message_type(#xmlel{attrs = Attrs}) -> - case fxml:get_attr_s(<<"type">>, Attrs) of - <<"">> -> - <<"normal">>; - Type -> - Type - end. - --spec is_carbon(xmlel()) -> {true, direction()} | false. - -is_carbon(Packet) -> - {Direction, SubTag} = case {fxml:get_subtag(Packet, <<"sent">>), - fxml:get_subtag(Packet, <<"received">>)} of - {false, false} -> - {false, false}; - {false, Tag} -> - {incoming, Tag}; - {Tag, _} -> - {outgoing, Tag} - end, - F = fun(_, false) -> - false; - (Name, Tag) -> - fxml:get_subtag(Tag, Name) - end, - case lists:foldl(F, SubTag, [<<"forwarded">>, <<"message">>, <<"body">>]) of - #xmlel{children = Body} when length(Body) > 0 -> - {true, Direction}; - _ -> - false - end. - --spec write_log(io:device(), direction(), jid(), jid(), binary()) -> ok. +-spec should_log(message()) -> boolean(). +should_log(#message{meta = #{carbon_copy := true}} = Msg) -> + should_log(xmpp_util:unwrap_carbon(Msg)); +should_log(#message{type = error}) -> + false; +should_log(#message{body = Body, sub_els = SubEls}) -> + xmpp:get_text(Body) /= <<>> + orelse lists:any(fun(#xmlel{name = <<"encrypted">>}) -> true; + (_) -> false + end, SubEls). +-spec write_log(io:device(), direction(), jid(), jid(), + message_type() | offline | carbon) -> ok. write_log(IoDevice, Direction, From, To, Type) -> Date = format_date(calendar:local_time()), Record = io_lib:format("~s [~s, ~s] ~s -> ~s~n", @@ -238,7 +207,6 @@ write_log(IoDevice, Direction, From, To, Type) -> ok = file:write(IoDevice, [Record]). -spec format_date(calendar:datetime()) -> io_lib:chars(). - format_date({{Year, Month, Day}, {Hour, Minute, Second}}) -> Format = "~B-~2..0B-~2..0B ~2..0B:~2..0B:~2..0B", io_lib:format(Format, [Year, Month, Day, Hour, Minute, Second]).