Update mod_message_log to work with ejabberd 18.x
This commit is contained in:
parent
7d2a7aa418
commit
79a804ac3b
|
@ -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]).
|
||||
|
|
Loading…
Reference in New Issue