diff --git a/ChangeLog b/ChangeLog index 56668a0b9..2f72cee34 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2003-10-24 Alexey Shchepin + + * src/mod_offline.erl: Added function remove_old_messages/1 + + * src/mod_last.erl: jabber:iq:last support (JEP-0012) + * src/ejabberd_sm.erl: Likewise + + * src/jlib.hrl: Added NS_LAST macros + 2003-10-23 Alexey Shchepin * src/ejabberd_logger_h.erl: New error_logger handler diff --git a/src/ejabberd.app b/src/ejabberd.app index 02b111181..df772dbab 100644 --- a/src/ejabberd.app +++ b/src/ejabberd.app @@ -14,6 +14,7 @@ ejabberd_c2s, ejabberd_config, ejabberd_listener, + ejabberd_logger_h, ejabberd_local, ejabberd_router, ejabberd_s2s, @@ -30,6 +31,7 @@ mod_configure, mod_disco, mod_echo, + mod_last, mod_offline, mod_private, mod_register, diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index f1d915c4e..0626cfce4 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -90,7 +90,8 @@ {mod_irc, []}, {mod_muc, []}, {mod_pubsub, []}, - {mod_time, [{iqdisc, no_queue}]}, + {mod_time, []}, + {mod_last, []}, {mod_version, []} ]}. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 1e2bc204c..32c333b9e 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -177,9 +177,9 @@ clean_table_from_bad_node(Node) -> do_route(From, To, Packet) -> ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", [From, To, Packet, 8]), - #jid{user = User, server = Server, resource = Resource, + #jid{user = User, resource = Resource, luser = LUser, lserver = LServer, lresource = LResource} = To, - {xmlelement, Name, Attrs, Els} = Packet, + {xmlelement, Name, Attrs, _Els} = Packet, case Resource of "" -> case Name of @@ -316,7 +316,7 @@ route_message(From, To, Packet) -> get_user_resources(User) -> LUser = jlib:nodeprep(User), case catch mnesia:dirty_index_read(session, LUser, #session.user) of - {'EXIT', Reason} -> + {'EXIT', _Reason} -> []; Rs -> lists:map(fun(R) -> @@ -342,11 +342,12 @@ unset_presence(User, Resource) -> UR = {User, Resource}, mnesia:delete({presence, UR}) end, - mnesia:transaction(F). + mnesia:transaction(F), + catch mod_last:on_presence_update(LUser). get_user_present_resources(LUser) -> case catch mnesia:dirty_index_read(presence, LUser, #presence.user) of - {'EXIT', Reason} -> + {'EXIT', _Reason} -> []; Rs -> lists:map(fun(R) -> @@ -366,7 +367,7 @@ dirty_get_my_sessions_list() -> process_iq(From, To, Packet) -> IQ = jlib:iq_query_info(Packet), case IQ of - {iq, ID, Type, XMLNS, SubEl} -> + {iq, _ID, _Type, XMLNS, _SubEl} -> case ets:lookup(sm_iqtable, XMLNS) of [{_, Module, Function}] -> ResIQ = Module:Function(From, To, IQ), diff --git a/src/jlib.hrl b/src/jlib.hrl index 4ca09fc34..fdbf35dae 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -17,6 +17,7 @@ -define(NS_PRIVATE, "jabber:iq:private"). -define(NS_VERSION, "jabber:iq:version"). -define(NS_TIME, "jabber:iq:time"). +-define(NS_LAST, "jabber:iq:last"). -define(NS_XDATA, "jabber:x:data"). -define(NS_IQDATA, "jabber:iq:data"). -define(NS_DELAY, "jabber:x:delay"). diff --git a/src/mod_last.erl b/src/mod_last.erl new file mode 100644 index 000000000..50f16fd24 --- /dev/null +++ b/src/mod_last.erl @@ -0,0 +1,114 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_last.erl +%%% Author : Alexey Shchepin +%%% Purpose : jabber:iq:last support (JEP-0012) +%%% Created : 24 Oct 2003 by Alexey Shchepin +%%% 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, + on_presence_update/1]). + +-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). + +process_local_iq(_From, _To, {iq, ID, Type, XMLNS, SubEl}) -> + case Type of + set -> + {iq, ID, error, XMLNS, + [SubEl, ?ERR_NOT_ALLOWED]}; + get -> + Sec = trunc(element(1, erlang:statistics(wall_clock))/1000), + {iq, ID, result, XMLNS, + [{xmlelement, "query", + [{"xmlns", ?NS_LAST}, + {"seconds", integer_to_list(Sec)}], + []}]} + end. + + +process_sm_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) -> + case Type of + set -> + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]}; + 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} -> + get_last(ID, XMLNS, SubEl, User); + List -> + case mod_privacy:check_packet( + User, List, + {From, To, + {xmlelement, "presence", [], []}}, + out) of + allow -> + get_last(ID, XMLNS, SubEl, User); + deny -> + {iq, ID, error, XMLNS, + [SubEl, ?ERR_NOT_ALLOWED]} + end + end; + true -> + {iq, ID, error, XMLNS, [SubEl, ?ERR_NOT_ALLOWED]} + end + end. + +get_last(ID, XMLNS, SubEl, LUser) -> + case catch mnesia:dirty_read(last_activity, LUser) of + {'EXIT', _Reason} -> + {iq, ID, error, XMLNS, [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; + [] -> + {iq, ID, error, XMLNS, [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; + [#last_activity{timestamp = TimeStamp}] -> + {MegaSecs, Secs, _MicroSecs} = now(), + TimeStamp2 = MegaSecs * 1000000 + Secs, + Sec = TimeStamp2 - TimeStamp, + {iq, ID, result, XMLNS, + [{xmlelement, "query", + [{"xmlns", ?NS_LAST}, + {"seconds", integer_to_list(Sec)}], + []}]} + 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). + + diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 9462d77f0..63537600e 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -16,6 +16,7 @@ stop/0, store_packet/3, resend_offline_messages/1, + remove_old_messages/1, remove_user/1]). -include("jlib.hrl"). @@ -150,6 +151,22 @@ resend_offline_messages(User) -> ok end. +remove_old_messages(Days) -> + {MegaSecs, Secs, _MicroSecs} = now(), + S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days, + MegaSecs1 = S div 1000000, + Secs1 = S rem 1000000, + TimeStamp = {MegaSecs1, Secs1, 0}, + F = fun() -> + mnesia:foldl( + fun(#offline_msg{timestamp = TS} = Rec, _Acc) + when TS < TimeStamp -> + mnesia:delete_object(Rec); + (_Rec, _Acc) -> ok + end, ok, offline_msg) + end, + mnesia:transaction(F). + remove_user(User) -> LUser = jlib:nodeprep(User), F = fun() ->