aboutsummaryrefslogtreecommitdiff
path: root/src/mod_admin_extra.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_admin_extra.erl')
-rw-r--r--src/mod_admin_extra.erl402
1 files changed, 242 insertions, 160 deletions
diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl
index 48732ea35..4b117d50a 100644
--- a/src/mod_admin_extra.erl
+++ b/src/mod_admin_extra.erl
@@ -5,7 +5,7 @@
%%% Created : 10 Aug 2008 by Badlop <badlop@process-one.net>
%%%
%%%
-%%% ejabberd, Copyright (C) 2002-2008 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -30,31 +30,61 @@
-include("logger.hrl").
--export([start/2, stop/1, compile/1, get_cookie/0,
- remove_node/1, set_password/3, check_password/3,
- check_password_hash/4, delete_old_users/1,
- delete_old_users_vhost/2, ban_account/3,
+-export([start/2, stop/1, mod_opt_type/1,
+ get_commands_spec/0, depends/2]).
+
+% Commands API
+-export([
+ % Adminsys
+ compile/1, get_cookie/0, remove_node/1, export2sql/2,
+ restart_module/2,
+
+ % Sessions
num_active_users/2, num_resources/2, resource_num/3,
kick_session/4, status_num/2, status_num/1,
status_list/2, status_list/1, connected_users_info/0,
connected_users_vhost/1, set_presence/7,
- user_sessions_info/2, set_nickname/3, get_vcard/3,
+ get_presence/2, user_sessions_info/2, get_last/2,
+
+ % Accounts
+ set_password/3, check_password_hash/4, delete_old_users/1,
+ delete_old_users_vhost/2, ban_account/3, check_password/3,
+
+ % vCard
+ set_nickname/3, get_vcard/3,
get_vcard/4, get_vcard_multi/4, set_vcard/4,
- set_vcard/5, add_rosteritem/7, delete_rosteritem/4,
+ set_vcard/5,
+
+ % Roster
+ add_rosteritem/7, delete_rosteritem/4,
process_rosteritems/5, get_roster/2, push_roster/3,
- push_roster_all/1, push_alltoall/2, get_last/2,
- private_get/4, private_set/3, srg_create/5,
+ push_roster_all/1, push_alltoall/2,
+
+ % Private storage
+ private_get/4, private_set/3,
+
+ % Shared roster
+ srg_create/5,
srg_delete/2, srg_list/1, srg_get_info/2,
srg_get_members/2, srg_user_add/4, srg_user_del/4,
- send_message/5, send_stanza/3, send_stanza_c2s/4, privacy_set/3,
- stats/1, stats/2, mod_opt_type/1, get_commands_spec/0, depends/2]).
+
+ % Send message
+ send_message/5, send_stanza/3, send_stanza_c2s/4,
+
+ % Privacy list
+ privacy_set/3,
+
+ % Stats
+ stats/1, stats/2
+ ]).
-include("ejabberd.hrl").
-include("ejabberd_commands.hrl").
-include("mod_roster.hrl").
+-include("mod_privacy.hrl").
-include("ejabberd_sm.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
%%%
%%% gen_mod
@@ -124,9 +154,30 @@ get_commands_spec() ->
result = {res, rescode},
result_example = ok,
result_desc = "Status code: 0 on success, 1 otherwise"},
+ #ejabberd_commands{name = export2sql, tags = [mnesia],
+ desc = "Export Mnesia tables to files in directory",
+ module = ?MODULE, function = export2sql,
+ args = [{host, string}, {path, string}],
+ args_example = ["myserver.com","/tmp/export/sql"],
+ args_desc = ["Server name", "File to write sql export"],
+ result = {res, rescode},
+ result_example = ok,
+ result_desc = "Status code: 0 on success, 1 otherwise"},
+ #ejabberd_commands{name = restart_module, tags = [erlang],
+ desc = "Stop an ejabberd module, reload code and start",
+ module = ?MODULE, function = restart_module,
+ args = [{host, binary}, {module, binary}],
+ args_example = ["myserver.com","mod_admin_extra"],
+ args_desc = ["Server name", "Module to restart"],
+ result = {res, integer},
+ result_example = 0,
+ result_desc = "Returns integer code:\n"
+ " - 0: code reloaded, module restarted\n"
+ " - 1: error: module not loaded\n"
+ " - 2: code not reloaded, but module restarted"},
#ejabberd_commands{name = num_active_users, tags = [accounts, stats],
desc = "Get number of users active in the last days",
- policy = admin,
+ policy = admin,
module = ?MODULE, function = num_active_users,
args = [{host, binary}, {days, integer}],
args_example = [<<"myserver.com">>, 3],
@@ -175,8 +226,8 @@ get_commands_spec() ->
desc = "Check if the password hash is correct",
longdesc = "Allowed hash methods: md5, sha.",
module = ?MODULE, function = check_password_hash,
- args = [{user, binary}, {host, binary}, {passwordhash, string},
- {hashmethod, string}],
+ args = [{user, binary}, {host, binary}, {passwordhash, binary},
+ {hashmethod, binary}],
args_example = [<<"peter">>, <<"myserver.com">>,
<<"5ebe2294ecd0e0f08eab7690d2a6ee69">>, <<"md5">>],
args_desc = ["User name to check", "Server to check",
@@ -235,7 +286,7 @@ get_commands_spec() ->
result_desc = "Status code: 0 on success, 1 otherwise"},
#ejabberd_commands{name = status_num_host, tags = [session, stats],
desc = "Number of logged users with this status in host",
- policy = admin,
+ policy = admin,
module = ?MODULE, function = status_num,
args = [{host, binary}, {status, binary}],
args_example = [<<"myserver.com">>, <<"dnd">>],
@@ -245,7 +296,7 @@ get_commands_spec() ->
result_desc = "Number of connected sessions with given status type"},
#ejabberd_commands{name = status_num, tags = [session, stats],
desc = "Number of logged users with this status",
- policy = admin,
+ policy = admin,
module = ?MODULE, function = status_num,
args = [{status, binary}],
args_example = [<<"dnd">>],
@@ -297,11 +348,11 @@ get_commands_spec() ->
]}}
}}},
#ejabberd_commands{name = connected_users_vhost,
- tags = [session],
- desc = "Get the list of established sessions in a vhost",
- module = ?MODULE, function = connected_users_vhost,
- args = [{host, binary}],
- result = {connected_users_vhost, {list, {sessions, string}}}},
+ tags = [session],
+ desc = "Get the list of established sessions in a vhost",
+ module = ?MODULE, function = connected_users_vhost,
+ args = [{host, binary}],
+ result = {connected_users_vhost, {list, {sessions, string}}}},
#ejabberd_commands{name = user_sessions_info,
tags = [session],
desc = "Get information about all sessions of a user",
@@ -322,6 +373,28 @@ get_commands_spec() ->
]}}
}}},
+ #ejabberd_commands{name = get_presence, tags = [session],
+ desc =
+ "Retrieve the resource with highest priority, "
+ "and its presence (show and status message) "
+ "for a given user.",
+ longdesc =
+ "The 'jid' value contains the user jid "
+ "with resource.\nThe 'show' value contains "
+ "the user presence flag. It can take "
+ "limited values:\n - available\n - chat "
+ "(Free for chat)\n - away\n - dnd (Do "
+ "not disturb)\n - xa (Not available, "
+ "extended away)\n - unavailable (Not "
+ "connected)\n\n'status' is a free text "
+ "defined by the user client.",
+ module = ?MODULE, function = get_presence,
+ args = [{user, binary}, {server, binary}],
+ result =
+ {presence,
+ {tuple,
+ [{jid, string}, {show, string},
+ {status, string}]}}},
#ejabberd_commands{name = set_presence,
tags = [session],
desc = "Set presence of a session",
@@ -533,7 +606,7 @@ get_commands_spec() ->
#ejabberd_commands{name = get_offline_count,
tags = [offline],
desc = "Get the number of unread offline messages",
- policy = user,
+ policy = user,
module = mod_offline, function = count_offline_messages,
args = [],
result = {value, integer}},
@@ -561,13 +634,13 @@ get_commands_spec() ->
#ejabberd_commands{name = stats, tags = [stats],
desc = "Get statistical value: registeredusers onlineusers onlineusersnode uptimeseconds processes",
- policy = admin,
+ policy = admin,
module = ?MODULE, function = stats,
args = [{name, binary}],
result = {stat, integer}},
#ejabberd_commands{name = stats_host, tags = [stats],
desc = "Get statistical value for this host: registeredusers onlineusers",
- policy = admin,
+ policy = admin,
module = ?MODULE, function = stats,
args = [{name, binary}, {host, binary}],
result = {stat, integer}}
@@ -588,6 +661,48 @@ remove_node(Node) ->
mnesia:del_table_copy(schema, list_to_atom(Node)),
ok.
+restart_module(Host, Module) when is_binary(Module) ->
+ restart_module(Host, jlib:binary_to_atom(Module));
+restart_module(Host, Module) when is_atom(Module) ->
+ List = gen_mod:loaded_modules_with_opts(Host),
+ case proplists:get_value(Module, List) of
+ undefined ->
+ % not a running module, force code reload anyway
+ code:purge(Module),
+ code:delete(Module),
+ code:load_file(Module),
+ 1;
+ Opts ->
+ gen_mod:stop_module(Host, Module),
+ case code:soft_purge(Module) of
+ true ->
+ code:delete(Module),
+ code:load_file(Module),
+ gen_mod:start_module(Host, Module, Opts),
+ 0;
+ false ->
+ gen_mod:start_module(Host, Module, Opts),
+ 2
+ end
+ end.
+
+export2sql(Host, Directory) ->
+ Tables = [{export_last, last},
+ {export_offline, offline},
+ {export_passwd, passwd},
+ {export_private_storage, private_storage},
+ {export_roster, roster},
+ {export_vcard, vcard},
+ {export_vcard_search, vcard_search}],
+ Export = fun({TableFun, Table}) ->
+ Filename = filename:join([Directory, atom_to_list(Table)++".txt"]),
+ io:format("Trying to export Mnesia table '~p' on Host '~s' to file '~s'~n", [Table, Host, Filename]),
+ Res = (catch ejd2sql:TableFun(Host, Filename)),
+ io:format(" Result: ~p~n", [Res])
+ end,
+ lists:foreach(Export, Tables),
+ ok.
+
%%%
%%% Accounts
%%%
@@ -606,10 +721,10 @@ check_password_hash(User, Host, PasswordHash, HashMethod) ->
{A, _} when is_tuple(A) -> scrammed;
{_, <<"md5">>} -> get_md5(AccountPass);
{_, <<"sha">>} -> get_sha(AccountPass);
- {_, Method} ->
+ {_, Method} ->
?ERROR_MSG("check_password_hash called "
- "with hash method: ~p", [Method]),
- undefined
+ "with hash method: ~p", [Method]),
+ undefined
end,
case AccountPassHash of
scrammed ->
@@ -627,10 +742,11 @@ get_sha(AccountPass) ->
|| X <- binary_to_list(p1_sha:sha1(AccountPass))]).
num_active_users(Host, Days) ->
- list_last_activity(Host, true, Days).
+ DB_Type = gen_mod:db_type(Host, mod_last),
+ list_last_activity(Host, true, Days, DB_Type).
%% Code based on ejabberd/src/web/ejabberd_web_admin.erl
-list_last_activity(Host, Integral, Days) ->
+list_last_activity(Host, Integral, Days, mnesia) ->
TimeStamp = p1_time_compat:system_time(seconds),
TS = TimeStamp - Days * 86400,
case catch mnesia:dirty_select(
@@ -656,7 +772,11 @@ list_last_activity(Host, Integral, Days) ->
end,
lists:nth(Days, Hist ++ Tail)
end
- end.
+ end;
+list_last_activity(_Host, _Integral, _Days, DB_Type) ->
+ throw({error, iolist_to_binary(io_lib:format("Unsupported backend: ~p",
+ [DB_Type]))}).
+
histogram(Values, Integral) ->
histogram(lists:sort(Values), Integral, 0, 0, []).
histogram([H | T], Integral, Current, Count, Hist) when Current == H ->
@@ -760,7 +880,9 @@ set_random_password(User, Server, Reason) ->
set_password_auth(User, Server, NewPass).
build_random_password(Reason) ->
- Date = jlib:timestamp_to_legacy(calendar:universal_time()),
+ {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:universal_time(),
+ Date = str:format("~4..0B~2..0B~2..0BT~2..0B:~2..0B:~2..0B",
+ [Year, Month, Day, Hour, Minute, Second]),
RandomString = randoms:get_string(),
<<"BANNED_ACCOUNT--", Date/binary, "--", RandomString/binary, "--", Reason/binary>>.
@@ -865,9 +987,9 @@ connected_users_vhost(Host) ->
%% Code copied from ejabberd_sm.erl and customized
dirty_get_sessions_list2() ->
Ss = mnesia:dirty_select(
- session,
+ session,
[{#session{usr = '$1', sid = '$2', priority = '$3', info = '$4',
- _ = '_'},
+ _ = '_'},
[],
[['$1', '$2', '$3', '$4']]}]),
lists:filter(fun([_USR, _SID, _Priority, Info]) ->
@@ -879,24 +1001,40 @@ stringize(String) ->
%% Replace newline characters with other code
ejabberd_regexp:greplace(String, <<"\n">>, <<"\\n">>).
+get_presence(U, S) ->
+ Pids = [ejabberd_sm:get_session_pid(U, S, R)
+ || R <- ejabberd_sm:get_user_resources(U, S)],
+ OnlinePids = [Pid || Pid <- Pids, Pid=/=none],
+ case OnlinePids of
+ [] ->
+ {jid:to_string({U, S, <<>>}), <<"unavailable">>, <<"">>};
+ [SessionPid|_] ->
+ {_User, Resource, Show, Status} =
+ ejabberd_c2s:get_presence(SessionPid),
+ FullJID = jid:to_string({U, S, Resource}),
+ {FullJID, Show, Status}
+ end.
+
set_presence(User, Host, Resource, Type, Show, Status, Priority)
when is_integer(Priority) ->
BPriority = integer_to_binary(Priority),
set_presence(User, Host, Resource, Type, Show, Status, BPriority);
-set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
+set_presence(User, Host, Resource, Type, Show, Status, Priority0) ->
+ Priority = if is_integer(Priority0) -> Priority0;
+ true -> binary_to_integer(Priority0)
+ end,
case ejabberd_sm:get_session_pid(User, Host, Resource) of
none ->
error;
Pid ->
- USR = jid:to_string(jid:make(User, Host, Resource)),
- US = jid:to_string(jid:make(User, Host, <<>>)),
- Message = {route_xmlstreamelement,
- {xmlel, <<"presence">>,
- [{<<"from">>, USR}, {<<"to">>, US}, {<<"type">>, Type}],
- [{xmlel, <<"show">>, [], [{xmlcdata, Show}]},
- {xmlel, <<"status">>, [], [{xmlcdata, Status}]},
- {xmlel, <<"priority">>, [], [{xmlcdata, Priority}]}]}},
- Pid ! Message,
+ From = jid:make(User, Host, Resource),
+ To = jid:make(User, Host),
+ Presence = #presence{from = From, to = To,
+ type = jlib:binary_to_atom(Type),
+ show = jlib:binary_to_atom(Show),
+ status = xmpp:mk_text(Status),
+ priority = Priority},
+ Pid ! {route, From, To, Presence},
ok
end.
@@ -934,20 +1072,12 @@ user_sessions_info(User, Host) ->
%%%
set_nickname(User, Host, Nickname) ->
- R = mod_vcard:process_sm_iq(
- {jid, User, Host, <<>>, User, Host, <<>>},
- {jid, User, Host, <<>>, User, Host, <<>>},
- {iq, <<>>, set, <<>>, <<"en">>,
- {xmlel, <<"vCard">>, [
- {<<"xmlns">>, <<"vcard-temp">>}], [
- {xmlel, <<"NICKNAME">>, [], [{xmlcdata, Nickname}]}
- ]
- }}),
- case R of
- {iq, <<>>, result, <<>>, _L, []} ->
- ok;
- _ ->
- error
+ VCard = xmpp:encode(#vcard_temp{nickname = Nickname}),
+ case mod_vcard:set_vcard(User, jid:nameprep(Host), VCard) of
+ {error, badarg} ->
+ error;
+ ok ->
+ ok
end.
get_vcard(User, Host, Name) ->
@@ -971,26 +1101,17 @@ set_vcard(User, Host, Name, Subname, SomeContent) ->
%%
%% Internal vcard
-get_module_resource(Server) ->
- case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end, none) of
- none -> list_to_binary(atom_to_list(?MODULE));
- R when is_binary(R) -> R
- end.
-
get_vcard_content(User, Server, Data) ->
- [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
- JID = jid:make(User, Server, get_module_resource(Server)),
- IQ = #iq{type = get, xmlns = ?NS_VCARD},
- IQr = Module:Function(JID, JID, IQ),
- [A1] = IQr#iq.sub_el,
- case A1#xmlel.children of
- [_|_] ->
- case get_vcard(Data, A1) of
+ case mod_vcard:get_vcard(jid:nodeprep(User), jid:nameprep(Server)) of
+ [_|_] = Els ->
+ case get_vcard(Data, Els) of
[false] -> throw(error_no_value_found_in_vcard);
ElemList -> ?DEBUG("ELS ~p", [ElemList]), [fxml:get_tag_cdata(Elem) || Elem <- ElemList]
end;
[] ->
- throw(error_no_vcard_found)
+ throw(error_no_vcard_found);
+ error ->
+ throw(database_failure)
end.
get_vcard([<<"TEL">>, TelType], {_, _, _, OldEls}) ->
@@ -1015,25 +1136,19 @@ set_vcard_content(User, Server, Data, SomeContent) ->
[Bin | _] when is_binary(Bin) -> SomeContent;
Bin when is_binary(Bin) -> [SomeContent]
end,
- [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
- JID = jid:make(User, Server, get_module_resource(Server)),
- IQ = #iq{type = get, xmlns = ?NS_VCARD},
- IQr = Module:Function(JID, JID, IQ),
-
%% Get old vcard
- A4 = case IQr#iq.sub_el of
+ A4 = case mod_vcard:get_vcard(jid:nodeprep(User), jid:nameprep(Server)) of
[A1] ->
{_, _, _, A2} = A1,
update_vcard_els(Data, ContentList, A2);
[] ->
- update_vcard_els(Data, ContentList, [])
+ update_vcard_els(Data, ContentList, []);
+ error ->
+ throw(database_failure)
end,
-
%% Build new vcard
SubEl = {xmlel, <<"vCard">>, [{<<"xmlns">>,<<"vcard-temp">>}], A4},
- IQ2 = #iq{type=set, sub_el = SubEl},
-
- Module:Function(JID, JID, IQ2),
+ mod_vcard:set_vcard(User, jid:nameprep(Server), SubEl),
ok.
take_vcard_tel(TelType, [{xmlel, <<"TEL">>, _, SubEls}=OldEl | OldEls], NewEls, Taken) ->
@@ -1094,11 +1209,7 @@ add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) ->
subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) ->
ItemEl = build_roster_item(User, Server, {add, Nick, Subscription, Group}),
- mod_roster:set_items(
- LU, LS,
- {xmlel, <<"query">>,
- [{<<"xmlns">>, ?NS_ROSTER}],
- [ItemEl]}).
+ mod_roster:set_items(LU, LS, #roster_query{items = [ItemEl]}).
delete_rosteritem(LocalUser, LocalServer, User, Server) ->
case unsubscribe(LocalUser, LocalServer, User, Server) of
@@ -1111,11 +1222,7 @@ delete_rosteritem(LocalUser, LocalServer, User, Server) ->
unsubscribe(LU, LS, User, Server) ->
ItemEl = build_roster_item(User, Server, remove),
- mod_roster:set_items(
- LU, LS,
- {xmlel, <<"query">>,
- [{<<"xmlns">>, ?NS_ROSTER}],
- [ItemEl]}).
+ mod_roster:set_items(LU, LS, #roster_query{items = [ItemEl]}).
%% -----------------------------
%% Get Roster
@@ -1205,30 +1312,17 @@ push_roster_item(LU, LS, R, U, S, Action) ->
ejabberd_router:route(jid:remove_resource(LJID), LJID, ResIQ).
build_roster_item(U, S, {add, Nick, Subs, Group}) ->
- GNames = binary:split(Group,<<";">>, [global]),
- GroupEls = [{xmlel, <<"group">>, [], [{xmlcdata, GName}]} || GName <- GNames],
- {xmlel, <<"item">>,
- [{<<"jid">>, jid:to_string(jid:make(U, S, <<>>))},
- {<<"name">>, Nick},
- {<<"subscription">>, Subs}],
- GroupEls
- };
+ Groups = binary:split(Group,<<";">>, [global]),
+ #roster_item{jid = jid:make(U, S),
+ name = Nick,
+ subscription = jlib:binary_to_atom(Subs),
+ groups = Groups};
build_roster_item(U, S, remove) ->
- {xmlel, <<"item">>,
- [{<<"jid">>, jid:to_string(jid:make(U, S, <<>>))},
- {<<"subscription">>, <<"remove">>}],
- []
- }.
+ #roster_item{jid = jid:make(U, S), subscription = remove}.
build_iq_roster_push(Item) ->
- {xmlel, <<"iq">>,
- [{<<"type">>, <<"set">>}, {<<"id">>, <<"push">>}],
- [{xmlel, <<"query">>,
- [{<<"xmlns">>, ?NS_ROSTER}],
- [Item]
- }
- ]
- }.
+ #iq{type = set, id = <<"push">>,
+ sub_els = [#roster_query{items = [Item]}]}.
build_broadcast(U, S, {add, _Nick, Subs, _Group}) ->
build_broadcast(U, S, list_to_atom(binary_to_list(Subs)));
@@ -1274,17 +1368,9 @@ get_last(User, Server) ->
%% <aa xmlns='bb'>Cluth</aa>
private_get(Username, Host, Element, Ns) ->
- From = jid:make(Username, Host, <<>>),
- To = jid:make(Username, Host, <<>>),
- IQ = {iq, <<>>, get, ?NS_PRIVATE, <<>>,
- {xmlel, <<"query">>,
- [{<<"xmlns">>,?NS_PRIVATE}],
- [{xmlel, Element, [{<<"xmlns">>, Ns}], []}]}},
- ResIq = mod_private:process_sm_iq(From, To, IQ),
- [{xmlel, <<"query">>,
- [{<<"xmlns">>, ?NS_PRIVATE}],
- [SubEl]}] = ResIq#iq.sub_el,
- binary_to_list(fxml:element_to_binary(SubEl)).
+ Els = mod_private:get_data(jid:nodeprep(Username), jid:nameprep(Host),
+ [Ns, Element]),
+ binary_to_list(fxml:element_to_binary(xmpp:encode(#private{xml_els = Els}))).
private_set(Username, Host, ElementString) ->
case fxml_stream:parse_element(ElementString) of
@@ -1297,13 +1383,9 @@ private_set(Username, Host, ElementString) ->
end.
private_set2(Username, Host, Xml) ->
- From = jid:make(Username, Host, <<>>),
- To = jid:make(Username, Host, <<>>),
- IQ = {iq, <<>>, set, ?NS_PRIVATE, <<>>,
- {xmlel, <<"query">>,
- [{<<"xmlns">>, ?NS_PRIVATE}],
- [Xml]}},
- mod_private:process_sm_iq(From, To, IQ),
+ NS = fxml:get_tag_attr_s(<<"xmlns">>, Xml),
+ mod_private:set_data(jid:nodeprep(Username), jid:nameprep(Host),
+ [{NS, Xml}]),
ok.
%%%
@@ -1366,23 +1448,25 @@ send_message(Type, From, To, Subject, Body) ->
ejabberd_router:route(FromJID, ToJID, Packet).
build_packet(Type, Subject, Body) ->
- Tail = if Subject == <<"">>; Type == <<"chat">> -> [];
- true -> [{xmlel, <<"subject">>, [], [{xmlcdata, Subject}]}]
- end,
- {xmlel, <<"message">>,
- [{<<"type">>, Type}, {<<"id">>, randoms:get_string()}],
- [{xmlel, <<"body">>, [], [{xmlcdata, Body}]} | Tail]
- }.
+ #message{type = jlib:binary_to_atom(Type),
+ body = xmpp:mk_text(Body),
+ subject = xmpp:mk_text(Subject)}.
send_stanza(FromString, ToString, Stanza) ->
- case fxml_stream:parse_element(Stanza) of
- {error, Error} ->
- {error, Error};
- XmlEl ->
- #xmlel{attrs = Attrs} = XmlEl,
- From = jid:from_string(proplists:get_value(<<"from">>, Attrs, FromString)),
- To = jid:from_string(proplists:get_value(<<"to">>, Attrs, ToString)),
- ejabberd_router:route(From, To, XmlEl)
+ try
+ #xmlel{} = El = fxml_stream:parse_element(Stanza),
+ #jid{} = From = jid:from_string(FromString),
+ #jid{} = To = jid:to_string(ToString),
+ Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]),
+ ejabberd_router:route(From, To, Pkt)
+ catch _:{xmpp_codec, Why} ->
+ io:format("incorrect stanza: ~s~n", [xmpp:format_error(Why)]),
+ {error, Why};
+ _:{badmatch, {error, Why}} ->
+ io:format("invalid xml: ~p~n", [Why]),
+ {error, Why};
+ _:{badmatch, error} ->
+ {error, "JID malformed"}
end.
send_stanza_c2s(Username, Host, Resource, Stanza) ->
@@ -1398,17 +1482,16 @@ send_stanza_c2s(Username, Host, Resource, Stanza) ->
end.
privacy_set(Username, Host, QueryS) ->
- From = jid:make(Username, Host, <<"">>),
- To = jid:make(<<"">>, Host, <<"">>),
+ From = jid:make(Username, Host),
+ To = jid:make(Host),
QueryEl = fxml_stream:parse_element(QueryS),
- StanzaEl = {xmlel, <<"iq">>, [{<<"type">>, <<"set">>}], [QueryEl]},
- IQ = jlib:iq_query_info(StanzaEl),
- ejabberd_hooks:run_fold(
- privacy_iq_set,
- Host,
- {error, ?ERR_FEATURE_NOT_IMPLEMENTED},
- [From, To, IQ]
- ),
+ SubEl = xmpp:decode(QueryEl),
+ IQ = #iq{type = set, id = <<"push">>, sub_els = [SubEl],
+ from = From, to = To},
+ ejabberd_hooks:run_fold(privacy_iq_set,
+ Host,
+ {error, xmpp:err_feature_not_implemented()},
+ [IQ, #userlist{}]),
ok.
%%%
@@ -1589,5 +1672,4 @@ is_glob_match(String, <<"!", Glob/binary>>) ->
is_glob_match(String, Glob) ->
is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)).
-mod_opt_type(module_resource) -> fun (A) -> A end;
-mod_opt_type(_) -> [module_resource].
+mod_opt_type(_) -> [].