2003-10-24 21:21:07 +02:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% File : mod_last.erl
|
|
|
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
|
|
|
%%% Purpose : jabber:iq:last support (JEP-0012)
|
|
|
|
%%% Created : 24 Oct 2003 by Alexey Shchepin <alexey@sevcom.net>
|
|
|
|
%%% Id : $Id$
|
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
|
|
|
|
-module(mod_last).
|
|
|
|
-author('alexey@sevcom.net').
|
|
|
|
-vsn('$Revision$ ').
|
|
|
|
|
|
|
|
-behaviour(gen_mod).
|
|
|
|
|
|
|
|
-export([start/1,
|
|
|
|
stop/0,
|
|
|
|
process_local_iq/3,
|
|
|
|
process_sm_iq/3,
|
2003-11-01 22:06:50 +01:00
|
|
|
on_presence_update/1,
|
|
|
|
remove_user/1]).
|
2003-10-24 21:21:07 +02:00
|
|
|
|
|
|
|
-include("ejabberd.hrl").
|
|
|
|
-include("jlib.hrl").
|
|
|
|
|
|
|
|
-record(last_activity, {user, timestamp}).
|
|
|
|
|
|
|
|
|
|
|
|
start(Opts) ->
|
|
|
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
|
|
|
mnesia:create_table(last_activity,
|
|
|
|
[{disc_copies, [node()]},
|
|
|
|
{attributes, record_info(fields, last_activity)}]),
|
|
|
|
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_LAST,
|
|
|
|
?MODULE, process_local_iq, IQDisc),
|
|
|
|
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST,
|
|
|
|
?MODULE, process_sm_iq, IQDisc).
|
|
|
|
|
|
|
|
stop() ->
|
|
|
|
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST).
|
|
|
|
|
2003-12-17 21:13:21 +01:00
|
|
|
process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
2003-10-24 21:21:07 +02:00
|
|
|
case Type of
|
|
|
|
set ->
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
2003-10-24 21:21:07 +02:00
|
|
|
get ->
|
|
|
|
Sec = trunc(element(1, erlang:statistics(wall_clock))/1000),
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = result,
|
|
|
|
sub_el = [{xmlelement, "query",
|
|
|
|
[{"xmlns", ?NS_LAST},
|
|
|
|
{"seconds", integer_to_list(Sec)}],
|
|
|
|
[]}]}
|
2003-10-24 21:21:07 +02:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
2003-12-17 21:13:21 +01:00
|
|
|
process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
2003-10-24 21:21:07 +02:00
|
|
|
case Type of
|
|
|
|
set ->
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
2003-10-24 21:21:07 +02:00
|
|
|
get ->
|
|
|
|
User = To#jid.luser,
|
|
|
|
{Subscription, _Groups} =
|
|
|
|
mod_roster:get_jid_info(User, From),
|
|
|
|
if
|
|
|
|
(Subscription == both) or (Subscription == from) ->
|
|
|
|
case catch mod_privacy:get_user_list(User) of
|
|
|
|
{'EXIT', _Reason} ->
|
2003-12-17 21:13:21 +01:00
|
|
|
get_last(IQ, SubEl, User);
|
2003-10-24 21:21:07 +02:00
|
|
|
List ->
|
|
|
|
case mod_privacy:check_packet(
|
|
|
|
User, List,
|
|
|
|
{From, To,
|
|
|
|
{xmlelement, "presence", [], []}},
|
|
|
|
out) of
|
|
|
|
allow ->
|
2003-12-17 21:13:21 +01:00
|
|
|
get_last(IQ, SubEl, User);
|
2003-10-24 21:21:07 +02:00
|
|
|
deny ->
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = error,
|
|
|
|
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
2003-10-24 21:21:07 +02:00
|
|
|
end
|
|
|
|
end;
|
|
|
|
true ->
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = error,
|
|
|
|
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
2003-10-24 21:21:07 +02:00
|
|
|
end
|
|
|
|
end.
|
|
|
|
|
2003-12-17 21:13:21 +01:00
|
|
|
get_last(IQ, SubEl, LUser) ->
|
2003-10-24 21:21:07 +02:00
|
|
|
case catch mnesia:dirty_read(last_activity, LUser) of
|
|
|
|
{'EXIT', _Reason} ->
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
|
2003-10-24 21:21:07 +02:00
|
|
|
[] ->
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
|
2003-10-24 21:21:07 +02:00
|
|
|
[#last_activity{timestamp = TimeStamp}] ->
|
|
|
|
{MegaSecs, Secs, _MicroSecs} = now(),
|
|
|
|
TimeStamp2 = MegaSecs * 1000000 + Secs,
|
|
|
|
Sec = TimeStamp2 - TimeStamp,
|
2003-12-17 21:13:21 +01:00
|
|
|
IQ#iq{type = result,
|
|
|
|
sub_el = [{xmlelement, "query",
|
|
|
|
[{"xmlns", ?NS_LAST},
|
|
|
|
{"seconds", integer_to_list(Sec)}],
|
|
|
|
[]}]}
|
2003-10-24 21:21:07 +02:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
on_presence_update(LUser) ->
|
|
|
|
{MegaSecs, Secs, _MicroSecs} = now(),
|
|
|
|
TimeStamp = MegaSecs * 1000000 + Secs,
|
|
|
|
F = fun() ->
|
|
|
|
mnesia:write(#last_activity{user = LUser,
|
|
|
|
timestamp = TimeStamp})
|
|
|
|
end,
|
|
|
|
mnesia:transaction(F).
|
|
|
|
|
|
|
|
|
2003-11-01 22:06:50 +01:00
|
|
|
remove_user(User) ->
|
|
|
|
LUser = jlib:nodeprep(User),
|
|
|
|
F = fun() ->
|
|
|
|
mnesia:delete({last_activity, LUser})
|
|
|
|
end,
|
|
|
|
mnesia:transaction(F).
|