mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-26 17:38:45 +01:00
Convert to exmpp.
SVN Revision: 1513
This commit is contained in:
parent
70956ece12
commit
d9a493561b
@ -1,3 +1,9 @@
|
||||
2008-08-06 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
||||
|
||||
* src/mod_offline.erl, src/mod_offline_odbc.erl, src/mod_echo.erl,
|
||||
src/mod_last.erl, src/mod_configure2.erl, src/mod_last_odbc.erl,
|
||||
src/gen_iq_handler.erl: Convert to exmpp.
|
||||
|
||||
2008-07-25 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
|
||||
|
||||
* src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl,
|
||||
|
@ -63,7 +63,11 @@
|
||||
mod_annouce,
|
||||
mod_caps,
|
||||
mod_configure,
|
||||
mod_configure2,
|
||||
mod_disco,
|
||||
mod_echo,
|
||||
mod_offline,
|
||||
mod_offline_odbc,
|
||||
mod_roster,
|
||||
mod_vcard
|
||||
]).
|
||||
|
@ -33,30 +33,36 @@
|
||||
stop/1,
|
||||
process_local_iq/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
-define(NS_ECONFIGURE, "http://ejabberd.jabberstudio.org/protocol/configure").
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
% XXX The namespace used in this module isn't known by Exmpp: if the
|
||||
% known list isn't updated by Ejabberd, some element names will be
|
||||
% represented with strings.
|
||||
% XXX This module currently supposed that they'll be atoms.
|
||||
|
||||
-define(NS_ECONFIGURE, 'http://ejabberd.jabberstudio.org/protocol/configure').
|
||||
-define(NS_ECONFIGURE_s, "http://ejabberd.jabberstudio.org/protocol/configure").
|
||||
|
||||
start(Host, Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE_s,
|
||||
?MODULE, process_local_iq, IQDisc),
|
||||
ok.
|
||||
|
||||
stop(Host) ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE).
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ECONFIGURE_s).
|
||||
|
||||
|
||||
process_local_iq(From, To, #iq{type = Type, lang = _Lang, sub_el = SubEl} = IQ) ->
|
||||
case acl:match_rule(To#jid.lserver, configure, From) of
|
||||
process_local_iq(From, To, IQ) ->
|
||||
case acl:match_rule(To#jid.ldomain, configure, From) of
|
||||
deny ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
exmpp_iq:error(IQ, 'not-allowed');
|
||||
allow ->
|
||||
case Type of
|
||||
case exmpp_iq:get_type(IQ) of
|
||||
set ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_FEATURE_NOT_IMPLEMENTED]};
|
||||
exmpp_iq:error(IQ, 'feature-not-implemented');
|
||||
%%case xml:get_tag_attr_s("type", SubEl) of
|
||||
%% "cancel" ->
|
||||
%% IQ#iq{type = result,
|
||||
@ -90,56 +96,57 @@ process_local_iq(From, To, #iq{type = Type, lang = _Lang, sub_el = SubEl} = IQ)
|
||||
%% sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
%%end;
|
||||
get ->
|
||||
case process_get(SubEl) of
|
||||
case process_get(IQ#xmlel.children) of
|
||||
{result, Res} ->
|
||||
IQ#iq{type = result, sub_el = [Res]};
|
||||
exmpp_iq:result(IQ, Res);
|
||||
{error, Error} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, Error]}
|
||||
exmpp_iq:error(IQ, Error)
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
process_get({xmlelement, "info", _Attrs, _SubEls}) ->
|
||||
process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'info'}) ->
|
||||
S2SConns = ejabberd_s2s:dirty_get_connections(),
|
||||
TConns = lists:usort([element(2, C) || C <- S2SConns]),
|
||||
Attrs = [{"registered-users",
|
||||
Attrs = [#xmlattr{name = 'registered-users', value =
|
||||
integer_to_list(mnesia:table_info(passwd, size))},
|
||||
{"online-users",
|
||||
#xmlattr{name = 'online-users', value =
|
||||
integer_to_list(mnesia:table_info(presence, size))},
|
||||
{"running-nodes",
|
||||
#xmlattr{name = 'running-nodes', value =
|
||||
integer_to_list(length(mnesia:system_info(running_db_nodes)))},
|
||||
{"stopped-nodes",
|
||||
#xmlattr{name = 'stopped-nodes', value =
|
||||
integer_to_list(
|
||||
length(lists:usort(mnesia:system_info(db_nodes) ++
|
||||
mnesia:system_info(extra_db_nodes)) --
|
||||
mnesia:system_info(running_db_nodes)))},
|
||||
{"outgoing-s2s-servers", integer_to_list(length(TConns))}],
|
||||
{result, {xmlelement, "info",
|
||||
[{"xmlns", ?NS_ECONFIGURE} | Attrs], []}};
|
||||
process_get({xmlelement, "welcome-message", Attrs, _SubEls}) ->
|
||||
#xmlattr{name = 'outgoing-s2s-servers', value =
|
||||
integer_to_list(length(TConns))}],
|
||||
{result, #xmlel{ns = ?NS_ECONFIGURE, name = 'info', attrs = Attrs}};
|
||||
process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'welcome-message', attrs = Attrs}) ->
|
||||
{Subj, Body} = case ejabberd_config:get_local_option(welcome_message) of
|
||||
{_Subj, _Body} = SB -> SB;
|
||||
_ -> {"", ""}
|
||||
end,
|
||||
{result, {xmlelement, "welcome-message", Attrs,
|
||||
[{xmlelement, "subject", [], [{xmlcdata, Subj}]},
|
||||
{xmlelement, "body", [], [{xmlcdata, Body}]}]}};
|
||||
process_get({xmlelement, "registration-watchers", Attrs, _SubEls}) ->
|
||||
{result, #xmlel{ns = ?NS_ECONFIGURE, name = 'welcome-message',
|
||||
attrs = Attrs, children =
|
||||
[#xmlel{ns = ?NS_ECONFIGURE, name = 'subject', children = [#xmlcdata{cdata = list_to_binary(Subj)}]},
|
||||
#xmlel{ns = ?NS_ECONFIGURE, name = 'body', children = [#xmlcdata{cdata = list_to_binary(Body)}]}]}};
|
||||
process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'registration-watchers', attrs = Attrs}) ->
|
||||
SubEls =
|
||||
case ejabberd_config:get_local_option(registration_watchers) of
|
||||
JIDs when is_list(JIDs) ->
|
||||
lists:map(fun(JID) ->
|
||||
{xmlelement, "jid", [], [{xmlcdata, JID}]}
|
||||
#xmlel{ns = ?NS_ECONFIGURE, name = 'jid', children = [#xmlcdata{cdata = list_to_binary(JID)}]}
|
||||
end, JIDs);
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
{result, {xmlelement, "registration_watchers", Attrs, SubEls}};
|
||||
process_get({xmlelement, "acls", Attrs, _SubEls}) ->
|
||||
{result, #xmlel{ns = ?NS_ECONFIGURE, name = 'registration_watchers', attrs = Attrs, children = SubEls}};
|
||||
process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'acls', attrs = Attrs}) ->
|
||||
Str = lists:flatten(io_lib:format("~p.", [ets:tab2list(acl)])),
|
||||
{result, {xmlelement, "acls", Attrs, [{xmlcdata, Str}]}};
|
||||
process_get({xmlelement, "access", Attrs, _SubEls}) ->
|
||||
{result, #xmlel{ns = ?NS_ECONFIGURE, name = 'acls', attrs = Attrs, children = [#xmlcdata{cdata = list_to_binary(Str)}]}};
|
||||
process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'access', attrs = Attrs}) ->
|
||||
Str =
|
||||
lists:flatten(
|
||||
io_lib:format(
|
||||
@ -149,22 +156,22 @@ process_get({xmlelement, "access", Attrs, _SubEls}) ->
|
||||
[],
|
||||
[{{access, '$1', '$2'}}]}])
|
||||
])),
|
||||
{result, {xmlelement, "access", Attrs, [{xmlcdata, Str}]}};
|
||||
process_get({xmlelement, "last", Attrs, _SubEls}) ->
|
||||
{result, #xmlel{ns = ?NS_ECONFIGURE, name = 'access', attrs = Attrs, children = [#xmlcdata{cdata = list_to_binary(Str)}]}};
|
||||
process_get(#xmlel{ns = ?NS_ECONFIGURE, name = 'last', attrs = Attrs}) ->
|
||||
case catch mnesia:dirty_select(
|
||||
last_activity, [{{last_activity, '_', '$1', '_'}, [], ['$1']}]) of
|
||||
{'EXIT', _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
{error, 'internal-server-error'};
|
||||
Vals ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
TimeStamp = MegaSecs * 1000000 + Secs,
|
||||
Str = lists:flatten(
|
||||
lists:append(
|
||||
[[integer_to_list(TimeStamp - V), " "] || V <- Vals])),
|
||||
{result, {xmlelement, "last", Attrs, [{xmlcdata, Str}]}}
|
||||
{result, #xmlel{ns = ?NS_ECONFIGURE, name = 'last', attrs = Attrs, children = [#xmlcdata{cdata = list_to_binary(Str)}]}}
|
||||
end;
|
||||
%%process_get({xmlelement, Name, Attrs, SubEls}) ->
|
||||
%% {result, };
|
||||
process_get(_) ->
|
||||
{error, ?ERR_BAD_REQUEST}.
|
||||
{error, 'bad-request'}.
|
||||
|
||||
|
@ -37,8 +37,9 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-record(state, {host}).
|
||||
|
||||
@ -117,8 +118,8 @@ handle_cast(_Msg, State) ->
|
||||
%% Description: Handling all non call/cast messages
|
||||
%%--------------------------------------------------------------------
|
||||
handle_info({route, From, To, Packet}, State) ->
|
||||
Packet2 = case From#jid.user of
|
||||
"" -> jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST);
|
||||
Packet2 = case From#jid.node of
|
||||
<<>> -> exmpp_stanza:reply_with_error(Packet, 'bad-request');
|
||||
_ -> Packet
|
||||
end,
|
||||
do_client_version(disabled, To, From), % Put 'enabled' to enable it
|
||||
@ -171,16 +172,16 @@ code_change(_OldVsn, State, _Extra) ->
|
||||
do_client_version(disabled, _From, _To) ->
|
||||
ok;
|
||||
do_client_version(enabled, From, To) ->
|
||||
ToS = jlib:jid_to_string(To),
|
||||
%% It is important to identify this process and packet
|
||||
Random_resource = integer_to_list(random:uniform(100000)),
|
||||
From2 = From#jid{resource = Random_resource,
|
||||
lresource = Random_resource},
|
||||
|
||||
%% Build an iq:query request
|
||||
Packet = {xmlelement, "iq",
|
||||
[{"to", ToS}, {"type", "get"}],
|
||||
[{xmlelement, "query", [{"xmlns", ?NS_VERSION}], []}]},
|
||||
Request = #xmlel{ns = ?NS_SOFT_VERSION, name = 'query'},
|
||||
Packet = exmpp_stanza:set_recipient(
|
||||
exmpp_iq:get(?NS_JABBER_CLIENT, Request),
|
||||
To),
|
||||
|
||||
%% Send the request
|
||||
ejabberd_router:route(From2, To, Packet),
|
||||
@ -189,15 +190,15 @@ do_client_version(enabled, From, To) ->
|
||||
%% It is very important to only accept a packet which is the
|
||||
%% response to the request that he sent
|
||||
Els = receive {route, To, From2, IQ} ->
|
||||
{xmlelement, "query", _, List} = xml:get_subtag(IQ, "query"),
|
||||
#xmlel{ns = ?NS_SOFT_VERSION, name = 'query', children = List} = exmpp_iq:get_payload(IQ),
|
||||
List
|
||||
after 5000 -> % Timeout in miliseconds: 5 seconds
|
||||
[]
|
||||
end,
|
||||
Values = [{Name, Value} || {xmlelement,Name,[],[{xmlcdata,Value}]} <- Els],
|
||||
Values = [{Name, binary_to_list(Value)} || #xmlel{name = Name, children = [#xmlcdata{cdata = Value}]} <- Els],
|
||||
|
||||
%% Print in log
|
||||
Values_string1 = [io_lib:format("~n~s: ~p", [N, V]) || {N, V} <- Values],
|
||||
Values_string2 = lists:concat(Values_string1),
|
||||
?INFO_MSG("Information of the client: ~s~s", [ToS, Values_string2]).
|
||||
?INFO_MSG("Information of the client: ~s~s", [exmpp_jid:jid_to_string(To), Values_string2]).
|
||||
|
||||
|
@ -38,8 +38,9 @@
|
||||
get_last_info/2,
|
||||
remove_user/2]).
|
||||
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("mod_privacy.hrl").
|
||||
|
||||
-record(last_activity, {us, timestamp, status}).
|
||||
@ -51,9 +52,9 @@ start(Host, Opts) ->
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, last_activity)}]),
|
||||
update_table(),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s,
|
||||
?MODULE, process_local_iq, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s,
|
||||
?MODULE, process_sm_iq, IQDisc),
|
||||
ejabberd_hooks:add(remove_user, Host,
|
||||
?MODULE, remove_user, 50),
|
||||
@ -65,30 +66,28 @@ stop(Host) ->
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:delete(unset_presence_hook, Host,
|
||||
?MODULE, on_presence_update, 50),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST).
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s).
|
||||
|
||||
process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
case Type of
|
||||
process_local_iq(_From, _To, IQ) ->
|
||||
case exmpp_iq:get_type(IQ) of
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
exmpp_iq:error(IQ, 'not-allowed');
|
||||
get ->
|
||||
Sec = trunc(element(1, erlang:statistics(wall_clock))/1000),
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_LAST},
|
||||
{"seconds", integer_to_list(Sec)}],
|
||||
[]}]}
|
||||
Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs =
|
||||
[#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]},
|
||||
exmpp_iq:result(IQ, Response)
|
||||
end.
|
||||
|
||||
|
||||
process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
case Type of
|
||||
process_sm_iq(From, To, IQ) ->
|
||||
case exmpp_iq:get_type(IQ) of
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
exmpp_iq:error(IQ, 'not-allowed');
|
||||
get ->
|
||||
User = To#jid.luser,
|
||||
Server = To#jid.lserver,
|
||||
User = To#jid.lnode,
|
||||
Server = To#jid.ldomain,
|
||||
{Subscription, _Groups} =
|
||||
ejabberd_hooks:run_fold(
|
||||
roster_get_jid_info, Server,
|
||||
@ -104,36 +103,33 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
allow,
|
||||
[User, Server, UserListRecord,
|
||||
{From, To,
|
||||
{xmlelement, "presence", [], []}},
|
||||
exmpp_presence:available()},
|
||||
out]) of
|
||||
allow ->
|
||||
get_last(IQ, SubEl, User, Server);
|
||||
get_last(IQ, User, Server);
|
||||
deny ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
exmpp_iq:error(IQ, 'not-allowed')
|
||||
end;
|
||||
true ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
exmpp_iq:error(IQ, 'not-allowed')
|
||||
end
|
||||
end.
|
||||
|
||||
%% TODO: This function could use get_last_info/2
|
||||
get_last(IQ, SubEl, LUser, LServer) ->
|
||||
get_last(IQ, LUser, LServer) ->
|
||||
case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of
|
||||
{'EXIT', _Reason} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
|
||||
exmpp_iq:error(IQ, 'internal-server-error');
|
||||
[] ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
|
||||
exmpp_iq:error(IQ, 'service-unavailable');
|
||||
[#last_activity{timestamp = TimeStamp, status = Status}] ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
TimeStamp2 = MegaSecs * 1000000 + Secs,
|
||||
Sec = TimeStamp2 - TimeStamp,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_LAST},
|
||||
{"seconds", integer_to_list(Sec)}],
|
||||
[{xmlcdata, Status}]}]}
|
||||
Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query',
|
||||
attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}],
|
||||
children = [#xmlcdata{cdata = list_to_binary(Status)}]},
|
||||
exmpp_iq:result(IQ, Response)
|
||||
end.
|
||||
|
||||
|
||||
@ -144,8 +140,8 @@ on_presence_update(User, Server, _Resource, Status) ->
|
||||
store_last_info(User, Server, TimeStamp, Status).
|
||||
|
||||
store_last_info(User, Server, TimeStamp, Status) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
US = {LUser, LServer},
|
||||
F = fun() ->
|
||||
mnesia:write(#last_activity{us = US,
|
||||
@ -166,8 +162,8 @@ get_last_info(LUser, LServer) ->
|
||||
end.
|
||||
|
||||
remove_user(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
US = {LUser, LServer},
|
||||
F = fun() ->
|
||||
mnesia:delete({last_activity, US})
|
||||
|
@ -38,15 +38,16 @@
|
||||
get_last_info/2,
|
||||
remove_user/2]).
|
||||
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("mod_privacy.hrl").
|
||||
|
||||
start(Host, Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s,
|
||||
?MODULE, process_local_iq, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s,
|
||||
?MODULE, process_sm_iq, IQDisc),
|
||||
ejabberd_hooks:add(remove_user, Host,
|
||||
?MODULE, remove_user, 50),
|
||||
@ -58,29 +59,27 @@ stop(Host) ->
|
||||
?MODULE, remove_user, 50),
|
||||
ejabberd_hooks:delete(unset_presence_hook, Host,
|
||||
?MODULE, on_presence_update, 50),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST).
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_LAST_ACTIVITY_s),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_LAST_ACTIVITY_s).
|
||||
|
||||
process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
case Type of
|
||||
process_local_iq(_From, _To, IQ) ->
|
||||
case exmpp_iq:get_type(IQ) of
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
exmpp_iq:error(IQ, 'not-allowed');
|
||||
get ->
|
||||
Sec = trunc(element(1, erlang:statistics(wall_clock))/1000),
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_LAST},
|
||||
{"seconds", integer_to_list(Sec)}],
|
||||
[]}]}
|
||||
Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query', attrs =
|
||||
[#xmlattr{name = 'seconds', value = integer_to_list(Sec)}]},
|
||||
exmpp_iq:result(IQ, Response)
|
||||
end.
|
||||
|
||||
process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
case Type of
|
||||
process_sm_iq(From, To, IQ) ->
|
||||
case exmpp_iq:get_type(IQ) of
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
exmpp_iq:error(IQ, 'not-allowed');
|
||||
get ->
|
||||
User = To#jid.luser,
|
||||
Server = To#jid.lserver,
|
||||
User = To#jid.lnode,
|
||||
Server = To#jid.ldomain,
|
||||
{Subscription, _Groups} =
|
||||
ejabberd_hooks:run_fold(
|
||||
roster_get_jid_info, Server,
|
||||
@ -96,42 +95,38 @@ process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
allow,
|
||||
[User, Server, UserListRecord,
|
||||
{From, To,
|
||||
{xmlelement, "presence", [], []}},
|
||||
exmpp_presence:available()},
|
||||
out]) of
|
||||
allow ->
|
||||
get_last(IQ, SubEl, User, Server);
|
||||
get_last(IQ, User, Server);
|
||||
deny ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
exmpp_iq:error(IQ, 'not-allowed')
|
||||
end;
|
||||
true ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
exmpp_iq:error(IQ, 'not-allowed')
|
||||
end
|
||||
end.
|
||||
|
||||
%% TODO: This function could use get_last_info/2
|
||||
get_last(IQ, SubEl, LUser, LServer) ->
|
||||
get_last(IQ, LUser, LServer) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch odbc_queries:get_last(LServer, Username) of
|
||||
{'EXIT', _Reason} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
|
||||
exmpp_iq:error(IQ, 'internal-server-error');
|
||||
{selected, ["seconds","state"], []} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
|
||||
exmpp_iq:error(IQ, 'service-unavailable');
|
||||
{selected, ["seconds","state"], [{STimeStamp, Status}]} ->
|
||||
case catch list_to_integer(STimeStamp) of
|
||||
TimeStamp when is_integer(TimeStamp) ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
TimeStamp2 = MegaSecs * 1000000 + Secs,
|
||||
Sec = TimeStamp2 - TimeStamp,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_LAST},
|
||||
{"seconds", integer_to_list(Sec)}],
|
||||
[{xmlcdata, Status}]}]};
|
||||
Response = #xmlel{ns = ?NS_LAST_ACTIVITY, name = 'query',
|
||||
attrs = [#xmlattr{name = 'seconds', value = integer_to_list(Sec)}],
|
||||
children = [#xmlcdata{cdata = list_to_binary(Status)}]},
|
||||
exmpp_iq:result(IQ, Response);
|
||||
_ ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
|
||||
exmpp_iq:error(IQ, 'internal-server-error')
|
||||
end
|
||||
end.
|
||||
|
||||
@ -141,8 +136,8 @@ on_presence_update(User, Server, _Resource, Status) ->
|
||||
store_last_info(User, Server, TimeStamp, Status).
|
||||
|
||||
store_last_info(User, Server, TimeStamp, Status) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)),
|
||||
State = ejabberd_odbc:escape(Status),
|
||||
@ -166,7 +161,7 @@ get_last_info(LUser, LServer) ->
|
||||
end.
|
||||
|
||||
remove_user(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
odbc_queries:del_last(LServer, Username).
|
||||
|
@ -41,8 +41,9 @@
|
||||
webadmin_page/3,
|
||||
webadmin_user/4]).
|
||||
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("web/ejabberd_http.hrl").
|
||||
-include("web/ejabberd_web_admin.hrl").
|
||||
|
||||
@ -51,6 +52,11 @@
|
||||
-define(PROCNAME, ejabberd_offline).
|
||||
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
|
||||
|
||||
% These are the namespace already declared by the stream opening. This is
|
||||
% used at serialization time.
|
||||
-define(DEFAULT_NS, ?NS_JABBER_CLIENT).
|
||||
-define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]).
|
||||
|
||||
start(Host, Opts) ->
|
||||
mnesia:create_table(offline_msg,
|
||||
[{disc_only_copies, [node()]},
|
||||
@ -142,23 +148,25 @@ stop(Host) ->
|
||||
{wait, Proc}.
|
||||
|
||||
store_packet(From, To, Packet) ->
|
||||
Type = xml:get_tag_attr_s("type", Packet),
|
||||
Type = exmpp_stanza:get_type(Packet),
|
||||
if
|
||||
(Type /= "error") and (Type /= "groupchat") and
|
||||
(Type /= "headline") ->
|
||||
case check_event(From, To, Packet) of
|
||||
true ->
|
||||
#jid{luser = LUser, lserver = LServer} = To,
|
||||
#jid{lnode = LUser, ldomain = LServer} = To,
|
||||
TimeStamp = now(),
|
||||
{xmlelement, _Name, _Attrs, Els} = Packet,
|
||||
Expire = find_x_expire(TimeStamp, Els),
|
||||
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
|
||||
Expire = find_x_expire(TimeStamp, Packet#xmlel.children),
|
||||
% XXX OLD FORMAT: Packet is stored in the old format.
|
||||
PacketOld = exmpp_xml:xmlel_to_xmlelement(Packet,
|
||||
[?DEFAULT_NS], ?PREFIXED_NS),
|
||||
gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) !
|
||||
#offline_msg{us = {LUser, LServer},
|
||||
timestamp = TimeStamp,
|
||||
expire = Expire,
|
||||
from = From,
|
||||
to = To,
|
||||
packet = Packet},
|
||||
packet = PacketOld},
|
||||
stop;
|
||||
_ ->
|
||||
ok
|
||||
@ -168,31 +176,28 @@ store_packet(From, To, Packet) ->
|
||||
end.
|
||||
|
||||
check_event(From, To, Packet) ->
|
||||
{xmlelement, Name, Attrs, Els} = Packet,
|
||||
case find_x_event(Els) of
|
||||
case find_x_event(Packet#xmlel.children) of
|
||||
false ->
|
||||
true;
|
||||
El ->
|
||||
case xml:get_subtag(El, "id") of
|
||||
false ->
|
||||
case xml:get_subtag(El, "offline") of
|
||||
false ->
|
||||
case exmpp_xml:get_element(El, 'id') of
|
||||
undefined ->
|
||||
case exmpp_xml:get_element(El, 'offline') of
|
||||
undefined ->
|
||||
true;
|
||||
_ ->
|
||||
ID = case xml:get_tag_attr_s("id", Packet) of
|
||||
"" ->
|
||||
{xmlelement, "id", [], []};
|
||||
ID = case exmpp_stanza:get_id(Packet) of
|
||||
undefined ->
|
||||
#xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id'};
|
||||
S ->
|
||||
{xmlelement, "id", [],
|
||||
[{xmlcdata, S}]}
|
||||
#xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id',
|
||||
children = [#xmlcdata{cdata =
|
||||
list_to_binary(S)}]}
|
||||
end,
|
||||
X = #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'x', children =
|
||||
[ID, #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'offline'}]},
|
||||
ejabberd_router:route(
|
||||
To, From, {xmlelement, Name, Attrs,
|
||||
[{xmlelement, "x",
|
||||
[{"xmlns", ?NS_EVENT}],
|
||||
[ID,
|
||||
{xmlelement, "offline", [], []}]}]
|
||||
}),
|
||||
To, From, exmpp_xml:set_children(Packet, [X])),
|
||||
true
|
||||
end;
|
||||
_ ->
|
||||
@ -202,44 +207,34 @@ check_event(From, To, Packet) ->
|
||||
|
||||
find_x_event([]) ->
|
||||
false;
|
||||
find_x_event([{xmlcdata, _} | Els]) ->
|
||||
find_x_event(Els);
|
||||
find_x_event([El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EVENT ->
|
||||
El;
|
||||
_ ->
|
||||
find_x_event(Els)
|
||||
end.
|
||||
find_x_event([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | _Els]) ->
|
||||
El;
|
||||
find_x_event([_ | Els]) ->
|
||||
find_x_event(Els).
|
||||
|
||||
find_x_expire(_, []) ->
|
||||
never;
|
||||
find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) ->
|
||||
find_x_expire(TimeStamp, Els);
|
||||
find_x_expire(TimeStamp, [El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EXPIRE ->
|
||||
Val = xml:get_tag_attr_s("seconds", El),
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
never
|
||||
end;
|
||||
find_x_expire(TimeStamp, [#xmlel{ns = ?NS_MESSAGE_EXPIRE} = El | _Els]) ->
|
||||
Val = exmpp_xml:get_attribute(El, 'seconds', ""),
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
find_x_expire(TimeStamp, Els)
|
||||
end.
|
||||
never
|
||||
end;
|
||||
find_x_expire(TimeStamp, [_ | Els]) ->
|
||||
find_x_expire(TimeStamp, Els).
|
||||
|
||||
|
||||
resend_offline_messages(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
US = {LUser, LServer},
|
||||
F = fun() ->
|
||||
Rs = mnesia:wread({offline_msg, US}),
|
||||
@ -250,16 +245,22 @@ resend_offline_messages(User, Server) ->
|
||||
{atomic, Rs} ->
|
||||
lists:foreach(
|
||||
fun(R) ->
|
||||
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
|
||||
Packet = case R#offline_msg.packet of
|
||||
#xmlelement{} = P ->
|
||||
exmpp_xml:xmlelement_to_xmlel(P,
|
||||
[?DEFAULT_NS], ?PREFIXED_NS);
|
||||
#xmlel{} = P ->
|
||||
P
|
||||
end,
|
||||
% XXX OLD FORMAT: Convert From & To.
|
||||
ejabberd_sm !
|
||||
{route,
|
||||
R#offline_msg.from,
|
||||
R#offline_msg.to,
|
||||
{xmlelement, Name, Attrs,
|
||||
Els ++
|
||||
[jlib:timestamp_to_xml(
|
||||
jlib:from_old_jid(R#offline_msg.from),
|
||||
jlib:from_old_jid(R#offline_msg.to),
|
||||
exmpp_xml:append_child(Packet,
|
||||
jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
R#offline_msg.timestamp))]}}
|
||||
R#offline_msg.timestamp)))}
|
||||
end,
|
||||
lists:keysort(#offline_msg.timestamp, Rs));
|
||||
_ ->
|
||||
@ -267,8 +268,8 @@ resend_offline_messages(User, Server) ->
|
||||
end.
|
||||
|
||||
pop_offline_messages(Ls, User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
US = {LUser, LServer},
|
||||
F = fun() ->
|
||||
Rs = mnesia:wread({offline_msg, US}),
|
||||
@ -280,15 +281,21 @@ pop_offline_messages(Ls, User, Server) ->
|
||||
TS = now(),
|
||||
Ls ++ lists:map(
|
||||
fun(R) ->
|
||||
{xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
|
||||
Packet = case R#offline_msg.packet of
|
||||
#xmlelement{} = P ->
|
||||
exmpp_xml:xmlelement_to_xmlel(P,
|
||||
[?DEFAULT_NS], ?PREFIXED_NS);
|
||||
#xmlel{} = P ->
|
||||
P
|
||||
end,
|
||||
% XXX OLD FORMAT: Convert From & To.
|
||||
{route,
|
||||
R#offline_msg.from,
|
||||
R#offline_msg.to,
|
||||
{xmlelement, Name, Attrs,
|
||||
Els ++
|
||||
[jlib:timestamp_to_xml(
|
||||
jlib:from_old_jid(R#offline_msg.from),
|
||||
jlib:from_old_jid(R#offline_msg.to),
|
||||
exmpp_xml:append_child(Packet,
|
||||
jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
R#offline_msg.timestamp))]}}
|
||||
R#offline_msg.timestamp)))}
|
||||
end,
|
||||
lists:filter(
|
||||
fun(R) ->
|
||||
@ -343,8 +350,8 @@ remove_old_messages(Days) ->
|
||||
mnesia:transaction(F).
|
||||
|
||||
remove_user(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
US = {LUser, LServer},
|
||||
F = fun() ->
|
||||
mnesia:delete({offline_msg, US})
|
||||
@ -371,10 +378,15 @@ update_table() ->
|
||||
F1 = fun() ->
|
||||
mnesia:write_lock_table(mod_offline_tmp_table),
|
||||
mnesia:foldl(
|
||||
fun(#offline_msg{us = U} = R, _) ->
|
||||
fun(#offline_msg{us = U, packet = P} = R, _) ->
|
||||
New_R = R#offline_msg{
|
||||
us = {U, Host},
|
||||
packet = exmpp_xml:xmlelement_to_xmlel(P,
|
||||
[?DEFAULT_NS], ?PREFIXED_NS)
|
||||
},
|
||||
mnesia:dirty_write(
|
||||
mod_offline_tmp_table,
|
||||
R#offline_msg{us = {U, Host}})
|
||||
New_R)
|
||||
end, ok, offline_msg)
|
||||
end,
|
||||
mnesia:transaction(F1),
|
||||
@ -402,8 +414,7 @@ update_table() ->
|
||||
mnesia:transform_table(
|
||||
offline_msg,
|
||||
fun({_, U, TS, F, T, P}) ->
|
||||
{xmlelement, _Name, _Attrs, Els} = P,
|
||||
Expire = find_x_expire(TS, Els),
|
||||
Expire = find_x_expire(TS, P#xmlelement.children),
|
||||
#offline_msg{us = U,
|
||||
timestamp = TS,
|
||||
expire = Expire,
|
||||
@ -442,14 +453,21 @@ update_table() ->
|
||||
%% Warn senders that their messages have been discarded:
|
||||
discard_warn_sender(Msgs) ->
|
||||
lists:foreach(
|
||||
fun(#offline_msg{from=From, to=To, packet=Packet}) ->
|
||||
fun(#offline_msg{from=From, to=To, packet=Packet0}) ->
|
||||
Packet = case Packet0 of
|
||||
#xmlelement{} = P ->
|
||||
exmpp_xml:xmlelement_to_xmlel(P,
|
||||
[?DEFAULT_NS], ?PREFIXED_NS);
|
||||
#xmlel{} = P ->
|
||||
P
|
||||
end,
|
||||
ErrText = "Your contact offline message queue is full. The message has been discarded.",
|
||||
Lang = xml:get_tag_attr_s("xml:lang", Packet),
|
||||
Err = jlib:make_error_reply(
|
||||
Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)),
|
||||
Error = exmpp_stanza:error('resource-constraint',
|
||||
{"en", ErrText}),
|
||||
Err = exmpp_stanza:reply_with_error(Packet, Error),
|
||||
ejabberd_router:route(
|
||||
To,
|
||||
From, Err)
|
||||
jlib:from_old_jid(To),
|
||||
jlib:from_old_jid(From), Err)
|
||||
end, Msgs).
|
||||
|
||||
|
||||
@ -464,14 +482,14 @@ webadmin_page(_, Host,
|
||||
webadmin_page(Acc, _, _) -> Acc.
|
||||
|
||||
user_queue(User, Server, Query, Lang) ->
|
||||
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||
US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)},
|
||||
Res = user_queue_parse_query(US, Query),
|
||||
Msgs = lists:keysort(#offline_msg.timestamp,
|
||||
mnesia:dirty_read({offline_msg, US})),
|
||||
FMsgs =
|
||||
lists:map(
|
||||
fun(#offline_msg{timestamp = TimeStamp, from = From, to = To,
|
||||
packet = {xmlelement, Name, Attrs, Els}} = Msg) ->
|
||||
packet = Packet} = Msg) ->
|
||||
ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))),
|
||||
{{Year, Month, Day}, {Hour, Minute, Second}} =
|
||||
calendar:now_to_local_time(TimeStamp),
|
||||
@ -479,11 +497,14 @@ user_queue(User, Server, Query, Lang) ->
|
||||
io_lib:format(
|
||||
"~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
|
||||
[Year, Month, Day, Hour, Minute, Second])),
|
||||
SFrom = jlib:jid_to_string(From),
|
||||
STo = jlib:jid_to_string(To),
|
||||
Attrs2 = jlib:replace_from_to_attrs(SFrom, STo, Attrs),
|
||||
Packet = {xmlelement, Name, Attrs2, Els},
|
||||
FPacket = ejabberd_web_admin:pretty_print_xml(Packet),
|
||||
SFrom = exmpp_jid:jid_to_string(jlib:from_old_jid(From)),
|
||||
STo = exmpp_jid:jid_to_string(jlib:from_old_jid(To)),
|
||||
Packet0 = exmpp_xml:xmlelement_to_xmlel(Packet,
|
||||
[?DEFAULT_NS], ?PREFIXED_NS),
|
||||
Packet1 = exmpp_stanza:set_jids(Packet0, SFrom, STo),
|
||||
FPacket = exmpp_xml:node_to_list(
|
||||
exmpp_xml:indent_document(Packet1, <<" ">>),
|
||||
[?DEFAULT_NS], ?PREFIXED_NS),
|
||||
?XE("tr",
|
||||
[?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]),
|
||||
?XAC("td", [{"class", "valign"}], Time),
|
||||
@ -547,10 +568,10 @@ user_queue_parse_query(US, Query) ->
|
||||
end.
|
||||
|
||||
us_to_list({User, Server}) ->
|
||||
jlib:jid_to_string({User, Server, ""}).
|
||||
exmpp_jid:jid_to_string(User, Server).
|
||||
|
||||
webadmin_user(Acc, User, Server, Lang) ->
|
||||
US = {jlib:nodeprep(User), jlib:nameprep(Server)},
|
||||
US = {exmpp_stringprep:nodeprep(User), exmpp_stringprep:nameprep(Server)},
|
||||
QueueLen = length(mnesia:dirty_read({offline_msg, US})),
|
||||
FQueueLen = [?AC("queue/",
|
||||
integer_to_list(QueueLen))],
|
||||
|
@ -40,8 +40,9 @@
|
||||
webadmin_page/3,
|
||||
webadmin_user/4]).
|
||||
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("web/ejabberd_http.hrl").
|
||||
-include("web/ejabberd_web_admin.hrl").
|
||||
|
||||
@ -50,6 +51,11 @@
|
||||
-define(PROCNAME, ejabberd_offline).
|
||||
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
|
||||
|
||||
% These are the namespace already declared by the stream opening. This is
|
||||
% used at serialization time.
|
||||
-define(DEFAULT_NS, ?NS_JABBER_CLIENT).
|
||||
-define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]).
|
||||
|
||||
start(Host, Opts) ->
|
||||
ejabberd_hooks:add(offline_message_hook, Host,
|
||||
?MODULE, store_packet, 50),
|
||||
@ -93,24 +99,20 @@ loop(Host, MaxOfflineMsgs) ->
|
||||
fun(M) ->
|
||||
Username =
|
||||
ejabberd_odbc:escape(
|
||||
(M#offline_msg.to)#jid.luser),
|
||||
(M#offline_msg.to)#jid.lnode),
|
||||
From = M#offline_msg.from,
|
||||
To = M#offline_msg.to,
|
||||
{xmlelement, Name, Attrs, Els} =
|
||||
M#offline_msg.packet,
|
||||
Attrs2 = jlib:replace_from_to_attrs(
|
||||
jlib:jid_to_string(From),
|
||||
jlib:jid_to_string(To),
|
||||
Attrs),
|
||||
Packet = {xmlelement, Name, Attrs2,
|
||||
Els ++
|
||||
[jlib:timestamp_to_xml(
|
||||
Packet0 = exmpp_stanza:set_jids(
|
||||
From,
|
||||
To,
|
||||
M#offline_msg.packet),
|
||||
Packet1 = exmpp_xml:append_child(Packet0,
|
||||
jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
M#offline_msg.timestamp))]},
|
||||
M#offline_msg.timestamp))),
|
||||
XML =
|
||||
ejabberd_odbc:escape(
|
||||
lists:flatten(
|
||||
xml:element_to_string(Packet))),
|
||||
exmpp_xml:document_to_string(Packet1)),
|
||||
odbc_queries:add_spool_sql(Username, XML)
|
||||
end, Msgs),
|
||||
case catch odbc_queries:add_spool(Host, Query) of
|
||||
@ -152,17 +154,16 @@ stop(Host) ->
|
||||
ok.
|
||||
|
||||
store_packet(From, To, Packet) ->
|
||||
Type = xml:get_tag_attr_s("type", Packet),
|
||||
Type = exmpp_stanza_:get_type(Packet, 'type'),
|
||||
if
|
||||
(Type /= "error") and (Type /= "groupchat") and
|
||||
(Type /= "headline") ->
|
||||
case check_event(From, To, Packet) of
|
||||
true ->
|
||||
#jid{luser = LUser} = To,
|
||||
#jid{lnode = LUser} = To,
|
||||
TimeStamp = now(),
|
||||
{xmlelement, _Name, _Attrs, Els} = Packet,
|
||||
Expire = find_x_expire(TimeStamp, Els),
|
||||
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
|
||||
Expire = find_x_expire(TimeStamp, Packet#xmlel.children),
|
||||
gen_mod:get_module_proc(To#jid.ldomain, ?PROCNAME) !
|
||||
#offline_msg{user = LUser,
|
||||
timestamp = TimeStamp,
|
||||
expire = Expire,
|
||||
@ -178,31 +179,27 @@ store_packet(From, To, Packet) ->
|
||||
end.
|
||||
|
||||
check_event(From, To, Packet) ->
|
||||
{xmlelement, Name, Attrs, Els} = Packet,
|
||||
case find_x_event(Els) of
|
||||
case find_x_event(Packet#xmlel.children) of
|
||||
false ->
|
||||
true;
|
||||
El ->
|
||||
case xml:get_subtag(El, "id") of
|
||||
false ->
|
||||
case xml:get_subtag(El, "offline") of
|
||||
false ->
|
||||
case exmpp_xml:get_element(El, 'id') of
|
||||
undefined ->
|
||||
case exmpp_xml:get_element(El, 'offline') of
|
||||
undefined ->
|
||||
true;
|
||||
_ ->
|
||||
ID = case xml:get_tag_attr_s("id", Packet) of
|
||||
ID = case exmpp_xml:get_attribute(Packet, 'id', "") of
|
||||
"" ->
|
||||
{xmlelement, "id", [], []};
|
||||
#xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id'};
|
||||
S ->
|
||||
{xmlelement, "id", [],
|
||||
[{xmlcdata, S}]}
|
||||
#xmlel{ns = ?NS_MESSAGE_EVENT, name = 'id',
|
||||
children = [#xmlcdata{cdata = list_to_binary(S)}]}
|
||||
end,
|
||||
X = #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'x', children =
|
||||
[ID, #xmlel{ns = ?NS_MESSAGE_EVENT, name = 'offline'}]},
|
||||
ejabberd_router:route(
|
||||
To, From, {xmlelement, Name, Attrs,
|
||||
[{xmlelement, "x",
|
||||
[{"xmlns", ?NS_EVENT}],
|
||||
[ID,
|
||||
{xmlelement, "offline", [], []}]}]
|
||||
}),
|
||||
To, From, exmpp_xml:set_children(Packet, [X])),
|
||||
true
|
||||
end;
|
||||
_ ->
|
||||
@ -212,64 +209,49 @@ check_event(From, To, Packet) ->
|
||||
|
||||
find_x_event([]) ->
|
||||
false;
|
||||
find_x_event([{xmlcdata, _} | Els]) ->
|
||||
find_x_event(Els);
|
||||
find_x_event([El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EVENT ->
|
||||
El;
|
||||
_ ->
|
||||
find_x_event(Els)
|
||||
end.
|
||||
find_x_event([#xmlel{ns = ?NS_MESSAGE_EVENT} = El | _Els]) ->
|
||||
El;
|
||||
find_x_event([_ | Els]) ->
|
||||
find_x_event(Els).
|
||||
|
||||
find_x_expire(_, []) ->
|
||||
never;
|
||||
find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) ->
|
||||
find_x_expire(TimeStamp, Els);
|
||||
find_x_expire(TimeStamp, [El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EXPIRE ->
|
||||
Val = xml:get_tag_attr_s("seconds", El),
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
never
|
||||
end;
|
||||
find_x_expire(TimeStamp, [#xmlel{ns = ?NS_MESSAGE_EXPIRE} = El | _Els]) ->
|
||||
Val = exmpp_xml:get_attribute(El, 'seconds', ""),
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
find_x_expire(TimeStamp, Els)
|
||||
end.
|
||||
never
|
||||
end;
|
||||
find_x_expire(TimeStamp, [_ | Els]) ->
|
||||
find_x_expire(TimeStamp, Els).
|
||||
|
||||
|
||||
pop_offline_messages(Ls, User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
EUser = ejabberd_odbc:escape(LUser),
|
||||
case odbc_queries:get_and_del_spool_msg_t(LServer, EUser) of
|
||||
{atomic, {selected, ["username","xml"], Rs}} ->
|
||||
Ls ++ lists:flatmap(
|
||||
fun({_, XML}) ->
|
||||
case xml_stream:parse_element(XML) of
|
||||
{error, _Reason} ->
|
||||
[];
|
||||
El ->
|
||||
To = jlib:string_to_jid(
|
||||
xml:get_tag_attr_s("to", El)),
|
||||
From = jlib:string_to_jid(
|
||||
xml:get_tag_attr_s("from", El)),
|
||||
if
|
||||
(To /= error) and
|
||||
(From /= error) ->
|
||||
[{route, From, To, El}];
|
||||
true ->
|
||||
[]
|
||||
end
|
||||
try
|
||||
[El] = exmpp_xml:parse_document(XML, [namespace, name_as_atom]),
|
||||
To = exmpp_jid:list_to_jid(
|
||||
exmpp_stanza:get_recipient(El)),
|
||||
From = exmpp_jid:list_to_jid(
|
||||
exmpp_stanza:get_sender(El)),
|
||||
[{route, From, To, El}]
|
||||
catch
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
end, Rs);
|
||||
_ ->
|
||||
@ -278,8 +260,8 @@ pop_offline_messages(Ls, User, Server) ->
|
||||
|
||||
|
||||
remove_user(User, Server) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
odbc_queries:del_spool_msg(LServer, Username).
|
||||
|
||||
@ -294,9 +276,9 @@ discard_warn_sender(Msgs) ->
|
||||
lists:foreach(
|
||||
fun(#offline_msg{from=From, to=To, packet=Packet}) ->
|
||||
ErrText = "Your contact offline message queue is full. The message has been discarded.",
|
||||
Lang = xml:get_tag_attr_s("xml:lang", Packet),
|
||||
Err = jlib:make_error_reply(
|
||||
Packet, ?ERRT_RESOURCE_CONSTRAINT(Lang, ErrText)),
|
||||
Error = exmpp_stanza:error('resource-constraint',
|
||||
{"en", ErrText}),
|
||||
Err = exmpp_stanza:reply_with_error(Packet, Error),
|
||||
ejabberd_router:route(
|
||||
To,
|
||||
From, Err)
|
||||
@ -314,8 +296,8 @@ webadmin_page(_, Host,
|
||||
webadmin_page(Acc, _, _) -> Acc.
|
||||
|
||||
user_queue(User, Server, Query, Lang) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
US = {LUser, LServer},
|
||||
Res = user_queue_parse_query(Username, LServer, Query),
|
||||
@ -327,11 +309,12 @@ user_queue(User, Server, Query, Lang) ->
|
||||
{selected, ["username", "xml"], Rs} ->
|
||||
lists:flatmap(
|
||||
fun({_, XML}) ->
|
||||
case xml_stream:parse_element(XML) of
|
||||
{error, _Reason} ->
|
||||
[];
|
||||
El ->
|
||||
try exmpp_xml:parse_document(XML, [namespace, name_as_atom]) of
|
||||
[El] ->
|
||||
[El]
|
||||
catch
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
end, Rs);
|
||||
_ ->
|
||||
@ -339,10 +322,12 @@ user_queue(User, Server, Query, Lang) ->
|
||||
end,
|
||||
FMsgs =
|
||||
lists:map(
|
||||
fun({xmlelement, _Name, _Attrs, _Els} = Msg) ->
|
||||
fun(#xmlel{} = Msg) ->
|
||||
ID = jlib:encode_base64(binary_to_list(term_to_binary(Msg))),
|
||||
Packet = Msg,
|
||||
FPacket = ejabberd_web_admin:pretty_print_xml(Packet),
|
||||
FPacket = exmpp_xml:node_to_list(
|
||||
exmpp_xml:indent_document(Packet, <<" ">>),
|
||||
[?DEFAULT_NS], ?PREFIXED_NS),
|
||||
?XE("tr",
|
||||
[?XAE("td", [{"class", "valign"}], [?INPUT("checkbox", "selected", ID)]),
|
||||
?XAE("td", [{"class", "valign"}], [?XC("pre", FPacket)])]
|
||||
@ -386,11 +371,12 @@ user_queue_parse_query(Username, LServer, Query) ->
|
||||
{selected, ["xml", "seq"], Rs} ->
|
||||
lists:flatmap(
|
||||
fun({XML, Seq}) ->
|
||||
case xml_stream:parse_element(XML) of
|
||||
{error, _Reason} ->
|
||||
[];
|
||||
El ->
|
||||
try exmpp_xml:parse_document(XML, [namespace, name_as_atom]) of
|
||||
[El] ->
|
||||
[{El, Seq}]
|
||||
catch
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
end, Rs);
|
||||
_ ->
|
||||
@ -421,11 +407,11 @@ user_queue_parse_query(Username, LServer, Query) ->
|
||||
end.
|
||||
|
||||
us_to_list({User, Server}) ->
|
||||
jlib:jid_to_string({User, Server, ""}).
|
||||
exmpp_jid:jid_to_list(User, Server).
|
||||
|
||||
webadmin_user(Acc, User, Server, Lang) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
LServer = jlib:nameprep(Server),
|
||||
LUser = exmpp_stringprep:nodeprep(User),
|
||||
LServer = exmpp_stringprep:nameprep(Server),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
QueueLen = case catch ejabberd_odbc:sql_query(
|
||||
LServer,
|
||||
|
Loading…
Reference in New Issue
Block a user