diff --git a/ChangeLog b/ChangeLog index 8e9dce87a..0ef9fe049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-08-06 Jean-Sébastien Pédron + + * 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 * src/adhoc.erl, src/mod_configure.erl, src/mod_announce.erl, diff --git a/src/gen_iq_handler.erl b/src/gen_iq_handler.erl index 33d445942..97a24efbb 100644 --- a/src/gen_iq_handler.erl +++ b/src/gen_iq_handler.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 ]). diff --git a/src/mod_configure2.erl b/src/mod_configure2.erl index db84c43b7..2b6874112 100644 --- a/src/mod_configure2.erl +++ b/src/mod_configure2.erl @@ -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'}. diff --git a/src/mod_echo.erl b/src/mod_echo.erl index 22875adcd..f2540081c 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -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]). diff --git a/src/mod_last.erl b/src/mod_last.erl index 3ed5964c7..dee915f86 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -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}) diff --git a/src/mod_last_odbc.erl b/src/mod_last_odbc.erl index 053876766..76489b4c0 100644 --- a/src/mod_last_odbc.erl +++ b/src/mod_last_odbc.erl @@ -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). diff --git a/src/mod_offline.erl b/src/mod_offline.erl index 3a751c328..283d68607 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -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))], diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index c3d0513d0..a8831aa0d 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -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,