diff --git a/src/mod_announce.erl b/src/mod_announce.erl index d30cf57f2..0cf8c5349 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -211,15 +211,15 @@ disco_identity(Acc, _From, _To, Node, Lang) -> %%------------------------------------------------------------------------- --define(INFO_RESULT(Allow, Feats), +-define(INFO_RESULT(Allow, Feats, Lang), case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; allow -> {result, Feats} end). -disco_features(Acc, From, #jid{lserver = LServer} = _To, <<"announce">>, _Lang) -> +disco_features(Acc, From, #jid{lserver = LServer} = _To, <<"announce">>, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -229,13 +229,14 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, <<"announce">>, _Lang) case {acl:match_rule(LServer, Access1, From), acl:match_rule(global, Access2, From)} of {deny, deny} -> - {error, ?ERR_FORBIDDEN}; + Txt = <<"Denied by ACL">>, + {error, ?ERRT_FORBIDDEN(Lang, Txt)}; _ -> {result, []} end end; -disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> +disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -246,25 +247,25 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> AllowGlobal = acl:match_rule(global, AccessGlobal, From), case Node of ?NS_ADMIN_ANNOUNCE -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMIN_ANNOUNCE_ALL -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMIN_SET_MOTD -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMIN_EDIT_MOTD -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMIN_DELETE_MOTD -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMIN_ANNOUNCE_ALLHOSTS -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); + ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS], Lang); ?NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); + ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS], Lang); ?NS_ADMIN_SET_MOTD_ALLHOSTS -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); + ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS], Lang); ?NS_ADMIN_EDIT_MOTD_ALLHOSTS -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); + ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS], Lang); ?NS_ADMIN_DELETE_MOTD_ALLHOSTS -> - ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS]); + ?INFO_RESULT(AllowGlobal, [?NS_COMMANDS], Lang); _ -> Acc end @@ -283,10 +284,10 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> } )). --define(ITEMS_RESULT(Allow, Items), +-define(ITEMS_RESULT(Allow, Items, Lang), case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; allow -> {result, Items} end). @@ -320,7 +321,7 @@ disco_items(Acc, From, #jid{lserver = LServer} = To, <<"announce">>, Lang) -> announce_items(Acc, From, To, Lang) end; -disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> +disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -331,25 +332,25 @@ disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) -> AllowGlobal = acl:match_rule(global, AccessGlobal, From), case Node of ?NS_ADMIN_ANNOUNCE -> - ?ITEMS_RESULT(Allow, []); + ?ITEMS_RESULT(Allow, [], Lang); ?NS_ADMIN_ANNOUNCE_ALL -> - ?ITEMS_RESULT(Allow, []); + ?ITEMS_RESULT(Allow, [], Lang); ?NS_ADMIN_SET_MOTD -> - ?ITEMS_RESULT(Allow, []); + ?ITEMS_RESULT(Allow, [], Lang); ?NS_ADMIN_EDIT_MOTD -> - ?ITEMS_RESULT(Allow, []); + ?ITEMS_RESULT(Allow, [], Lang); ?NS_ADMIN_DELETE_MOTD -> - ?ITEMS_RESULT(Allow, []); + ?ITEMS_RESULT(Allow, [], Lang); ?NS_ADMIN_ANNOUNCE_ALLHOSTS -> - ?ITEMS_RESULT(AllowGlobal, []); + ?ITEMS_RESULT(AllowGlobal, [], Lang); ?NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS -> - ?ITEMS_RESULT(AllowGlobal, []); + ?ITEMS_RESULT(AllowGlobal, [], Lang); ?NS_ADMIN_SET_MOTD_ALLHOSTS -> - ?ITEMS_RESULT(AllowGlobal, []); + ?ITEMS_RESULT(AllowGlobal, [], Lang); ?NS_ADMIN_EDIT_MOTD_ALLHOSTS -> - ?ITEMS_RESULT(AllowGlobal, []); + ?ITEMS_RESULT(AllowGlobal, [], Lang); ?NS_ADMIN_DELETE_MOTD_ALLHOSTS -> - ?ITEMS_RESULT(AllowGlobal, []); + ?ITEMS_RESULT(AllowGlobal, [], Lang); _ -> Acc end @@ -396,7 +397,8 @@ announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) commands_result(Allow, From, To, Request) -> case Allow of deny -> - {error, ?ERR_FORBIDDEN}; + Lang = Request#adhoc_request.lang, + {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; allow -> announce_commands(From, To, Request) end. @@ -463,12 +465,13 @@ announce_commands(From, To, %% User returns form. case jlib:parse_xdata_submit(XData) of invalid -> - {error, ?ERR_BAD_REQUEST}; + {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)}; Fields -> handle_adhoc_form(From, To, Request, Fields) end; true -> - {error, ?ERR_BAD_REQUEST} + Txt = <<"Incorrect action or data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end. -define(VVALUE(Val), @@ -688,7 +691,9 @@ announce_all(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> Local = jid:make(<<>>, To#jid.server, <<>>), @@ -703,7 +708,9 @@ announce_all_hosts_all(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> Local = jid:make(<<>>, To#jid.server, <<>>), @@ -719,7 +726,9 @@ announce_online(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:get_vh_session_list(Host), @@ -731,7 +740,9 @@ announce_all_hosts_online(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> announce_online1(ejabberd_sm:dirty_get_sessions_list(), @@ -752,7 +763,9 @@ announce_motd(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> announce_motd(Host, Packet) @@ -762,7 +775,9 @@ announce_all_hosts_motd(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -815,7 +830,9 @@ announce_motd_update(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> announce_motd_update(Host, Packet) @@ -825,7 +842,9 @@ announce_all_hosts_motd_update(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, @@ -861,7 +880,9 @@ announce_motd_delete(From, To, Packet) -> Access = get_access(Host), case acl:match_rule(Host, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> announce_motd_delete(Host) @@ -871,7 +892,9 @@ announce_all_hosts_motd_delete(From, To, Packet) -> Access = get_access(global), case acl:match_rule(global, Access, From) of deny -> - Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), + Txt = <<"Denied by ACL">>, + Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)), ejabberd_router:route(To, From, Err); allow -> Hosts = ?MYHOSTS, diff --git a/src/mod_configure.erl b/src/mod_configure.erl index 5e0117047..a836c33bd 100644 --- a/src/mod_configure.erl +++ b/src/mod_configure.erl @@ -198,81 +198,81 @@ get_local_identity(Acc, _From, _To, Node, Lang) -> %%%----------------------------------------------------------------------- --define(INFO_RESULT(Allow, Feats), +-define(INFO_RESULT(Allow, Feats, Lang), case Allow of - deny -> {error, ?ERR_FORBIDDEN}; + deny -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; allow -> {result, Feats} end). get_sm_features(Acc, From, - #jid{lserver = LServer} = _To, Node, _Lang) -> + #jid{lserver = LServer} = _To, Node, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; _ -> Allow = acl:match_rule(LServer, configure, From), case Node of - <<"config">> -> ?INFO_RESULT(Allow, [?NS_COMMANDS]); + <<"config">> -> ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); _ -> Acc end end. get_local_features(Acc, From, - #jid{lserver = LServer} = _To, Node, _Lang) -> + #jid{lserver = LServer} = _To, Node, Lang) -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; _ -> LNode = tokenize(Node), Allow = acl:match_rule(LServer, configure, From), case LNode of - [<<"config">>] -> ?INFO_RESULT(Allow, []); - [<<"user">>] -> ?INFO_RESULT(Allow, []); - [<<"online users">>] -> ?INFO_RESULT(Allow, []); - [<<"all users">>] -> ?INFO_RESULT(Allow, []); + [<<"config">>] -> ?INFO_RESULT(Allow, [], Lang); + [<<"user">>] -> ?INFO_RESULT(Allow, [], Lang); + [<<"online users">>] -> ?INFO_RESULT(Allow, [], Lang); + [<<"all users">>] -> ?INFO_RESULT(Allow, [], Lang); [<<"all users">>, <<$@, _/binary>>] -> - ?INFO_RESULT(Allow, []); - [<<"outgoing s2s">> | _] -> ?INFO_RESULT(Allow, []); - [<<"running nodes">>] -> ?INFO_RESULT(Allow, []); - [<<"stopped nodes">>] -> ?INFO_RESULT(Allow, []); + ?INFO_RESULT(Allow, [], Lang); + [<<"outgoing s2s">> | _] -> ?INFO_RESULT(Allow, [], Lang); + [<<"running nodes">>] -> ?INFO_RESULT(Allow, [], Lang); + [<<"stopped nodes">>] -> ?INFO_RESULT(Allow, [], Lang); [<<"running nodes">>, _ENode] -> - ?INFO_RESULT(Allow, [?NS_STATS]); + ?INFO_RESULT(Allow, [?NS_STATS], Lang); [<<"running nodes">>, _ENode, <<"DB">>] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); [<<"running nodes">>, _ENode, <<"modules">>] -> - ?INFO_RESULT(Allow, []); + ?INFO_RESULT(Allow, [], Lang); [<<"running nodes">>, _ENode, <<"modules">>, _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); [<<"running nodes">>, _ENode, <<"backup">>] -> - ?INFO_RESULT(Allow, []); + ?INFO_RESULT(Allow, [], Lang); [<<"running nodes">>, _ENode, <<"backup">>, _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); [<<"running nodes">>, _ENode, <<"import">>] -> - ?INFO_RESULT(Allow, []); + ?INFO_RESULT(Allow, [], Lang); [<<"running nodes">>, _ENode, <<"import">>, _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); [<<"running nodes">>, _ENode, <<"restart">>] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); [<<"running nodes">>, _ENode, <<"shutdown">>] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); [<<"config">>, _] -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"add-user">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"delete-user">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"end-user-session">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"get-user-password">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"change-user-password">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"get-user-lastlogin">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"user-stats">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"get-registered-users-num">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); ?NS_ADMINL(<<"get-online-users-num">>) -> - ?INFO_RESULT(Allow, [?NS_COMMANDS]); + ?INFO_RESULT(Allow, [?NS_COMMANDS], Lang); _ -> Acc end end. @@ -318,7 +318,8 @@ get_sm_items(Acc, From, {result, Items ++ Nodes ++ get_user_resources(User, Server)}; {allow, <<"config">>} -> {result, []}; - {_, <<"config">>} -> {error, ?ERR_FORBIDDEN}; + {_, <<"config">>} -> + {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; _ -> Acc end end. @@ -448,63 +449,64 @@ get_local_items(Acc, From, #jid{lserver = LServer} = To, _ -> LNode = tokenize(Node), Allow = acl:match_rule(LServer, configure, From), + Err = ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>), case LNode of [<<"config">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"user">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"online users">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"all users">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"all users">>, <<$@, _/binary>>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"outgoing s2s">> | _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"stopped nodes">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"DB">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"modules">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"modules">>, _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"backup">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"backup">>, _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"import">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"import">>, _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"restart">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"running nodes">>, _ENode, <<"shutdown">>] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); [<<"config">>, _] -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"add-user">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"delete-user">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"end-user-session">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"get-user-password">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"change-user-password">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"get-user-lastlogin">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"user-stats">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"get-registered-users-num">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); ?NS_ADMINL(<<"get-online-users-num">>) -> - ?ITEMS_RESULT(Allow, LNode, {error, ?ERR_FORBIDDEN}); + ?ITEMS_RESULT(Allow, LNode, {error, Err}); _ -> Acc end end. @@ -562,33 +564,29 @@ get_local_items({_, Host}, [<<"all users">>], _Server, get_local_items({_, Host}, [<<"all users">>, <<$@, Diap/binary>>], _Server, _Lang) -> - case catch ejabberd_auth:get_vh_registered_users(Host) - of - {'EXIT', _Reason} -> ?ERR_INTERNAL_SERVER_ERROR; - Users -> - SUsers = lists:sort([{S, U} || {U, S} <- Users]), - case catch begin - [S1, S2] = ejabberd_regexp:split(Diap, <<"-">>), - N1 = jlib:binary_to_integer(S1), - N2 = jlib:binary_to_integer(S2), - Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), - lists:map(fun ({S, U}) -> - #xmlel{name = <<"item">>, - attrs = - [{<<"jid">>, - <>}, - {<<"name">>, - <>}], - children = []} - end, - Sub) - end - of - {'EXIT', _Reason} -> ?ERR_NOT_ACCEPTABLE; - Res -> {result, Res} - end + Users = ejabberd_auth:get_vh_registered_users(Host), + SUsers = lists:sort([{S, U} || {U, S} <- Users]), + case catch begin + [S1, S2] = ejabberd_regexp:split(Diap, <<"-">>), + N1 = jlib:binary_to_integer(S1), + N2 = jlib:binary_to_integer(S2), + Sub = lists:sublist(SUsers, N1, N2 - N1 + 1), + lists:map(fun ({S, U}) -> + #xmlel{name = <<"item">>, + attrs = + [{<<"jid">>, + <>}, + {<<"name">>, + <>}], + children = []} + end, + Sub) + end + of + {'EXIT', _Reason} -> ?ERR_NOT_ACCEPTABLE; + Res -> {result, Res} end; get_local_items({_, Host}, [<<"outgoing s2s">>], _Server, Lang) -> @@ -826,33 +824,33 @@ get_stopped_nodes(_Lang) -> %%------------------------------------------------------------------------- -define(COMMANDS_RESULT(LServerOrGlobal, From, To, - Request), + Request, Lang), case acl:match_rule(LServerOrGlobal, configure, From) of - deny -> {error, ?ERR_FORBIDDEN}; + deny -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; allow -> adhoc_local_commands(From, To, Request) end). adhoc_local_commands(Acc, From, #jid{lserver = LServer} = To, - #adhoc_request{node = Node} = Request) -> + #adhoc_request{node = Node, lang = Lang} = Request) -> LNode = tokenize(Node), case LNode of [<<"running nodes">>, _ENode, <<"DB">>] -> - ?COMMANDS_RESULT(global, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request, Lang); [<<"running nodes">>, _ENode, <<"modules">>, _] -> - ?COMMANDS_RESULT(LServer, From, To, Request); + ?COMMANDS_RESULT(LServer, From, To, Request, Lang); [<<"running nodes">>, _ENode, <<"backup">>, _] -> - ?COMMANDS_RESULT(global, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request, Lang); [<<"running nodes">>, _ENode, <<"import">>, _] -> - ?COMMANDS_RESULT(global, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request, Lang); [<<"running nodes">>, _ENode, <<"restart">>] -> - ?COMMANDS_RESULT(global, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request, Lang); [<<"running nodes">>, _ENode, <<"shutdown">>] -> - ?COMMANDS_RESULT(global, From, To, Request); + ?COMMANDS_RESULT(global, From, To, Request, Lang); [<<"config">>, _] -> - ?COMMANDS_RESULT(LServer, From, To, Request); + ?COMMANDS_RESULT(LServer, From, To, Request, Lang); ?NS_ADMINL(_) -> - ?COMMANDS_RESULT(LServer, From, To, Request); + ?COMMANDS_RESULT(LServer, From, To, Request, Lang); _ -> Acc end. @@ -882,7 +880,8 @@ adhoc_local_commands(From, end; XData /= false, ActionIsExecute -> case jlib:parse_xdata_submit(XData) of - invalid -> {error, ?ERR_BAD_REQUEST}; + invalid -> + {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)}; Fields -> case catch set_form(From, LServer, LNode, Lang, Fields) of @@ -898,7 +897,8 @@ adhoc_local_commands(From, {error, Error} -> {error, Error} end end; - true -> {error, ?ERR_BAD_REQUEST} + true -> + {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect action or data form">>)} end. -define(TVFIELD(Type, Var, Val), @@ -980,10 +980,14 @@ adhoc_local_commands(From, get_form(_Host, [<<"running nodes">>, ENode, <<"DB">>], Lang) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case ejabberd_cluster:call(Node, mnesia, system_info, [tables]) of - {badrpc, _Reason} -> + {badrpc, Reason} -> + ?ERROR_MSG("RPC call mnesia:system_info(tables) on node " + "~s failed: ~p", [Node, Reason]), {error, ?ERR_INTERNAL_SERVER_ERROR}; Tables -> STables = lists:sort(Tables), @@ -1023,10 +1027,14 @@ get_form(Host, [<<"running nodes">>, ENode, <<"modules">>, <<"stop">>], Lang) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case ejabberd_cluster:call(Node, gen_mod, loaded_modules, [Host]) of - {badrpc, _Reason} -> + {badrpc, Reason} -> + ?ERROR_MSG("RPC call gen_mod:loaded_modules(~s) on node " + "~s failed: ~p", [Host, Node, Reason]), {error, ?ERR_INTERNAL_SERVER_ERROR}; Modules -> SModules = lists:sort(Modules), @@ -1562,9 +1570,11 @@ get_form(_Host, _, _Lang) -> {error, ?ERR_SERVICE_UNAVAILABLE}. set_form(_From, _Host, - [<<"running nodes">>, ENode, <<"DB">>], _Lang, XData) -> + [<<"running nodes">>, ENode, <<"DB">>], Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> lists:foreach(fun ({SVar, SVals}) -> Table = jlib:binary_to_atom(SVar), @@ -1596,9 +1606,11 @@ set_form(_From, _Host, end; set_form(_From, Host, [<<"running nodes">>, ENode, <<"modules">>, <<"stop">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> lists:foreach(fun ({Var, Vals}) -> case Vals of @@ -1615,12 +1627,16 @@ set_form(_From, Host, set_form(_From, Host, [<<"running nodes">>, ENode, <<"modules">>, <<"start">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case lists:keysearch(<<"modules">>, 1, XData) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'modules' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, {_, Strings}} -> String = lists:foldl(fun (S, Res) -> <> @@ -1637,98 +1653,143 @@ set_form(_From, Host, end, Modules), {result, []}; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Parse failed">>)} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Scan failed">>)} end end end; set_form(_From, _Host, [<<"running nodes">>, ENode, <<"backup">>, <<"backup">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case lists:keysearch(<<"path">>, 1, XData) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'path' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, {_, [String]}} -> case ejabberd_cluster:call(Node, mnesia, backup, [String]) of - {badrpc, _Reason} -> + {badrpc, Reason} -> + ?ERROR_MSG("RPC call mnesia:backup(~s) to node ~s " + "failed: ~p", [String, Node, Reason]), + {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, Reason} -> + ?ERROR_MSG("RPC call mnesia:backup(~s) to node ~s " + "failed: ~p", [String, Node, Reason]), {error, ?ERR_INTERNAL_SERVER_ERROR}; - {error, _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Incorrect value of 'path' in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end end; set_form(_From, _Host, [<<"running nodes">>, ENode, <<"backup">>, <<"restore">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case lists:keysearch(<<"path">>, 1, XData) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'path' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, {_, [String]}} -> case ejabberd_cluster:call(Node, ejabberd_admin, restore, [String]) of - {badrpc, _Reason} -> + {badrpc, Reason} -> + ?ERROR_MSG("RPC call ejabberd_admin:restore(~s) to node " + "~s failed: ~p", [String, Node, Reason]), + {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, Reason} -> + ?ERROR_MSG("RPC call ejabberd_admin:restore(~s) to node " + "~s failed: ~p", [String, Node, Reason]), {error, ?ERR_INTERNAL_SERVER_ERROR}; - {error, _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Incorrect value of 'path' in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end end; set_form(_From, _Host, [<<"running nodes">>, ENode, <<"backup">>, <<"textfile">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case lists:keysearch(<<"path">>, 1, XData) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'path' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, {_, [String]}} -> case ejabberd_cluster:call(Node, ejabberd_admin, dump_to_textfile, [String]) of - {badrpc, _Reason} -> + {badrpc, Reason} -> + ?ERROR_MSG("RPC call ejabberd_admin:dump_to_textfile(~s) " + "to node ~s failed: ~p", [String, Node, Reason]), + {error, ?ERR_INTERNAL_SERVER_ERROR}; + {error, Reason} -> + ?ERROR_MSG("RPC call ejabberd_admin:dump_to_textfile(~s) " + "to node ~s failed: ~p", [String, Node, Reason]), {error, ?ERR_INTERNAL_SERVER_ERROR}; - {error, _Reason} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; _ -> {result, []} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Incorrect value of 'path' in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end end; set_form(_From, _Host, [<<"running nodes">>, ENode, <<"import">>, <<"file">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case lists:keysearch(<<"path">>, 1, XData) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'path' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, {_, [String]}} -> ejabberd_cluster:call(Node, jd2ejd, import_file, [String]), {result, []}; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Incorrect value of 'path' in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end end; set_form(_From, _Host, [<<"running nodes">>, ENode, <<"import">>, <<"dir">>], - _Lang, XData) -> + Lang, XData) -> case search_running_node(ENode) of - false -> {error, ?ERR_ITEM_NOT_FOUND}; + false -> + Txt = <<"No running node found">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)}; Node -> case lists:keysearch(<<"path">>, 1, XData) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'path' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, {_, [String]}} -> ejabberd_cluster:call(Node, jd2ejd, import_dir, [String]), {result, []}; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Incorrect value of 'path' in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end end; set_form(From, Host, @@ -1739,7 +1800,7 @@ set_form(From, Host, [<<"running nodes">>, ENode, <<"shutdown">>], _Lang, XData) -> stop_node(From, Host, ENode, stop, XData); -set_form(_From, Host, [<<"config">>, <<"acls">>], _Lang, +set_form(_From, Host, [<<"config">>, <<"acls">>], Lang, XData) -> case lists:keysearch(<<"acls">>, 1, XData) of {value, {_, Strings}} -> @@ -1753,14 +1814,16 @@ set_form(_From, Host, [<<"config">>, <<"acls">>], _Lang, {ok, ACLs} -> acl:add_list(Host, ACLs, true), {result, []}; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Parse failed">>)} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Scan failed">>)} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"No 'acls' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end; set_form(_From, Host, [<<"config">>, <<"access">>], - _Lang, XData) -> + Lang, XData) -> SetAccess = fun (Rs) -> mnesia:transaction(fun () -> Os = mnesia:select(local_config, @@ -1803,11 +1866,13 @@ set_form(_From, Host, [<<"config">>, <<"access">>], {atomic, _} -> {result, []}; _ -> {error, ?ERR_BAD_REQUEST} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Parse failed">>)} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Scan failed">>)} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"No 'access' found in data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end; set_form(From, Host, ?NS_ADMINL(<<"add-user">>), _Lang, XData) -> @@ -2052,7 +2117,7 @@ adhoc_sm_commands(_Acc, From, action = Action, xdata = XData} = Request) -> case acl:match_rule(LServer, configure, From) of - deny -> {error, ?ERR_FORBIDDEN}; + deny -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; allow -> ActionIsExecute = lists:member(Action, [<<"">>, <<"execute">>, @@ -2071,11 +2136,15 @@ adhoc_sm_commands(_Acc, From, end; XData /= false, ActionIsExecute -> case jlib:parse_xdata_submit(XData) of - invalid -> {error, ?ERR_BAD_REQUEST}; + invalid -> + Txt = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; Fields -> set_sm_form(User, Server, <<"config">>, Request, Fields) end; - true -> {error, ?ERR_BAD_REQUEST} + true -> + Txt = <<"Incorrect action or data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end end; adhoc_sm_commands(Acc, _From, _To, _Request) -> Acc. @@ -2135,12 +2204,16 @@ set_sm_form(User, Server, <<"config">>, {value, {_, [Password]}} -> ejabberd_auth:set_password(User, Server, Password), adhoc:produce_response(Response); - _ -> {error, ?ERR_NOT_ACCEPTABLE} + _ -> + Txt = <<"No 'password' found in data form">>, + {error, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)} end; {value, {_, [<<"remove">>]}} -> catch ejabberd_auth:remove_user(User, Server), adhoc:produce_response(Response); - _ -> {error, ?ERR_NOT_ACCEPTABLE} + _ -> + Txt = <<"Incorrect value of 'action' in data form">>, + {error, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)} end; set_sm_form(_User, _Server, _Node, _Request, _Fields) -> {error, ?ERR_SERVICE_UNAVAILABLE}. diff --git a/src/mod_disco.erl b/src/mod_disco.erl index 734e90d36..0d5abcb4b 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -150,7 +150,8 @@ process_local_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; get -> Node = fxml:get_tag_attr_s(<<"node">>, SubEl), Host = To#jid.lserver, @@ -177,7 +178,8 @@ process_local_iq_info(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; get -> Host = To#jid.lserver, Node = fxml:get_tag_attr_s(<<"node">>, SubEl), @@ -229,10 +231,12 @@ get_local_features(Acc, _From, To, <<>>, _Lang) -> ets:select(disco_features, [{{{'_', Host}}, [], ['$_']}]) ++ Feats}; -get_local_features(Acc, _From, _To, _Node, _Lang) -> +get_local_features(Acc, _From, _To, _Node, Lang) -> case Acc of {result, _Features} -> Acc; - empty -> {error, ?ERR_ITEM_NOT_FOUND} + empty -> + Txt = <<"No features available">>, + {error, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)} end. features_to_xml(FeatureList) -> @@ -271,8 +275,8 @@ get_local_services(Acc, _From, To, <<>>, _Lang) -> get_local_services({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_local_services(empty, _From, _To, _Node, _Lang) -> - {error, ?ERR_ITEM_NOT_FOUND}. +get_local_services(empty, _From, _To, _Node, Lang) -> + {error, ?ERRT_ITEM_NOT_FOUND(Lang, <<"No services available">>)}. get_vh_services(Host) -> Hosts = lists:sort(fun (H1, H2) -> @@ -300,7 +304,8 @@ process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; get -> case is_presence_subscribed(From, To) of true -> @@ -325,8 +330,9 @@ process_sm_iq_items(From, To, IQ#iq{type = error, sub_el = [SubEl, Error]} end; false -> + Txt = <<"Not subscribed">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]} + sub_el = [SubEl, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)]} end end. @@ -347,12 +353,14 @@ get_sm_items(Acc, From, get_sm_items({result, _} = Acc, _From, _To, _Node, _Lang) -> Acc; -get_sm_items(empty, From, To, _Node, _Lang) -> +get_sm_items(empty, From, To, _Node, Lang) -> #jid{luser = LFrom, lserver = LSFrom} = From, #jid{luser = LTo, lserver = LSTo} = To, case {LFrom, LSFrom} of {LTo, LSTo} -> {error, ?ERR_ITEM_NOT_FOUND}; - _ -> {error, ?ERR_NOT_ALLOWED} + _ -> + Txt = <<"Query to another users is forbidden">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} end. is_presence_subscribed(#jid{luser = User, lserver = Server}, @@ -373,7 +381,8 @@ process_sm_iq_info(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> case Type of set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; get -> case is_presence_subscribed(From, To) of true -> @@ -405,8 +414,9 @@ process_sm_iq_info(From, To, IQ#iq{type = error, sub_el = [SubEl, Error]} end; false -> + Txt = <<"Not subscribed">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]} + sub_el = [SubEl, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)]} end end. @@ -423,12 +433,14 @@ get_sm_identity(Acc, _From, _ -> [] end. -get_sm_features(empty, From, To, _Node, _Lang) -> +get_sm_features(empty, From, To, _Node, Lang) -> #jid{luser = LFrom, lserver = LSFrom} = From, #jid{luser = LTo, lserver = LSTo} = To, case {LFrom, LSFrom} of {LTo, LSTo} -> {error, ?ERR_ITEM_NOT_FOUND}; - _ -> {error, ?ERR_NOT_ALLOWED} + _ -> + Txt = <<"Query to another users is forbidden">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} end; get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. diff --git a/src/mod_irc.erl b/src/mod_irc.erl index d5cd01353..f6e452d82 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -304,8 +304,9 @@ do_route1(Host, ServerHost, From, To, Packet) -> Lang)}]}, Res = jlib:iq_to_xml(ResIQ); _ -> - Res = jlib:make_error_reply(Packet, - ?ERR_ITEM_NOT_FOUND) + Txt = <<"Node not found">>, + Res = jlib:make_error_reply( + Packet, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)) end, ejabberd_router:route(To, From, Res); #iq{xmlns = ?NS_REGISTER} = IQ -> @@ -319,7 +320,7 @@ do_route1(Host, ServerHost, From, To, Packet) -> attrs = [{<<"xmlns">>, XMLNS}], children = iq_get_vcard(Lang)}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); - #iq{type = set, xmlns = ?NS_COMMANDS, lang = _Lang, + #iq{type = set, xmlns = ?NS_COMMANDS, lang = Lang, sub_el = SubEl} = IQ -> Request = adhoc:parse_request(IQ), @@ -348,8 +349,9 @@ do_route1(Host, ServerHost, From, To, Packet) -> true -> ok end; _ -> - Err = jlib:make_error_reply(Packet, - ?ERR_ITEM_NOT_FOUND), + Txt = <<"Node not found">>, + Err = jlib:make_error_reply( + Packet, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)), ejabberd_router:route(To, From, Err) end; #iq{} = _IQ -> @@ -407,12 +409,14 @@ do_route1(Host, ServerHost, From, To, Packet) -> ok end; _ -> + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), case str:tokens(ChanServ, <<"!">>) of [<<_, _/binary>> = Nick, <<_, _/binary>> = Server] -> case ets:lookup(irc_connection, {From, Server, Host}) of [] -> - Err = jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), + Txt = <<"IRC connection not found">>, + Err = jlib:make_error_reply( + Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)), ejabberd_router:route(To, From, Err); [R] -> Pid = R#irc_connection.pid, @@ -421,7 +425,9 @@ do_route1(Host, ServerHost, From, To, Packet) -> ok end; _ -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), + Txt = <<"Failed to parse chanserv">>, + Err = jlib:make_error_reply( + Packet, ?ERRT_BAD_REQUEST(Lang, Txt)), ejabberd_router:route(To, From, Err) end end @@ -532,8 +538,9 @@ process_irc_register(ServerHost, Host, From, _To, XDataEl = find_xdata_el(SubEl), case XDataEl of false -> + Txt1 = <<"No data form found">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]}; + sub_el = [SubEl, ?ERRT_NOT_ACCEPTABLE(Lang, Txt1)]}; #xmlel{attrs = Attrs} -> case fxml:get_attr_s(<<"type">>, Attrs) of <<"cancel">> -> @@ -546,8 +553,9 @@ process_irc_register(ServerHost, Host, From, _To, XData = jlib:parse_xdata_submit(XDataEl), case XData of invalid -> + Txt2 = <<"Incorrect data form">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]}; + sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt2)]}; _ -> Node = str:tokens(fxml:get_tag_attr_s(<<"node">>, SubEl), @@ -567,7 +575,9 @@ process_irc_register(ServerHost, Host, From, _To, end end; _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]} + Txt3 = <<"Incorrect value of 'type' attribute">>, + IQ#iq{type = error, + sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt3)]} end end; get -> @@ -629,7 +639,9 @@ get_form(ServerHost, Host, From, [], Lang) -> #jid{user = User, server = Server} = From, DefaultEncoding = get_default_encoding(Host), Customs = case get_data(ServerHost, Host, From) of - error -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + error -> + Txt1 = <<"Database failure">>, + {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt1)}; empty -> {User, []}; Data -> get_username_and_connection_params(Data) end, @@ -763,7 +775,7 @@ set_data(LServer, Host, From, Data, odbc) -> end, ejabberd_odbc:sql_transaction(LServer, F). -set_form(ServerHost, Host, From, [], _Lang, XData) -> +set_form(ServerHost, Host, From, [], Lang, XData) -> case {lists:keysearch(<<"username">>, 1, XData), lists:keysearch(<<"connections_params">>, 1, XData)} of @@ -781,11 +793,11 @@ set_form(ServerHost, Host, From, [], _Lang, XData) -> {connections_params, ConnectionsParams}]) of {atomic, _} -> {result, []}; - _ -> {error, ?ERR_NOT_ACCEPTABLE} + _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Database failure">>)} end; - _ -> {error, ?ERR_NOT_ACCEPTABLE} + _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Parse error">>)} end; - _ -> {error, ?ERR_NOT_ACCEPTABLE} + _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Scan error">>)} end; _ -> {error, ?ERR_NOT_ACCEPTABLE} end; @@ -909,7 +921,9 @@ adhoc_join(From, To, elements = [Form]}); true -> case jlib:parse_xdata_submit(XData) of - invalid -> {error, ?ERR_BAD_REQUEST}; + invalid -> + Txt1 = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt1)}; Fields -> Channel = case lists:keysearch(<<"channel">>, 1, Fields) of @@ -998,7 +1012,8 @@ adhoc_register(ServerHost, From, To, true -> case jlib:parse_xdata_submit(XData) of invalid -> - Error = {error, ?ERR_BAD_REQUEST}, + Txt1 = <<"Incorrect data form">>, + Error = {error, ?ERRT_BAD_REQUEST(Lang, Txt1)}, Username = false, ConnectionsParams = false; Fields -> @@ -1021,7 +1036,9 @@ adhoc_register(ServerHost, From, To, {atomic, _} -> adhoc:produce_response(Request, #adhoc_response{status = completed}); - _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} + _ -> + Txt2 = <<"Database failure">>, + {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt2)} end; true -> Form = generate_adhoc_register_form(Lang, Username, diff --git a/src/mod_last.erl b/src/mod_last.erl index e67a02cc2..009a1cb06 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -152,8 +152,7 @@ process_sm_iq(From, To, of allow -> get_last_iq(IQ, SubEl, User, Server); deny -> - Txt = <<"Denied by privacy lists">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} + IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} end; true -> Txt = <<"Not subscribed">>, diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 06fdf325f..c9c785757 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -252,7 +252,7 @@ normal_state({route, From, <<"">>, IsVoiceApprovement = is_voice_approvement(Els) and not is_visitor(From, StateData), if IsInvitation -> - case catch check_invitation(From, Els, Lang, StateData) + case catch check_invitation(From, Packet, Lang, StateData) of {error, Error} -> Err = jlib:make_error_reply(Packet, Error), @@ -433,9 +433,11 @@ normal_state({route, From, <<"">>, process_iq_owner(From, Type, Lang, SubEl, StateData); ?NS_DISCO_INFO -> case fxml:get_attr(<<"node">>, Attrs) of - false -> process_iq_disco_info(From, Type, Lang, StateData); - {value, _} -> {error, ?ERR_SERVICE_UNAVAILABLE} - end; + false -> process_iq_disco_info(From, Type, Lang, StateData); + {value, _} -> + Txt = <<"Disco info is not available for this node">>, + {error, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)} + end; ?NS_DISCO_ITEMS -> process_iq_disco_items(From, Type, Lang, StateData); ?NS_VCARD -> @@ -817,8 +819,9 @@ handle_info({captcha_failed, From}, normal_state, of {ok, {Nick, Packet}} -> Robots = (?DICT):erase(From, StateData#state.robots), - Err = jlib:make_error_reply(Packet, - ?ERR_NOT_AUTHORIZED), + Txt = <<"The CAPTCHA verification has failed">>, + Err = jlib:make_error_reply( + Packet, ?ERRT_NOT_AUTHORIZED(?MYLANG, Txt)), ejabberd_router:route % TODO: s/Nick/""/ (jid:replace_resource(StateData#state.jid, Nick), @@ -1807,6 +1810,22 @@ add_new_user(From, Nick, StateData#state.host, From, Nick), get_default_role(Affiliation, StateData)} of + {false, _, _, _} when NUsers >= MaxUsers orelse NUsers >= MaxAdminUsers -> + Txt = <<"Too many users in this conference">>, + Err = jlib:make_error_reply(Packet, + ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt)), + ejabberd_router:route % TODO: s/Nick/""/ + (jid:replace_resource(StateData#state.jid, Nick), + From, Err), + StateData; + {false, _, _, _} when NConferences >= MaxConferences -> + Txt = <<"You have joined too many conferences">>, + Err = jlib:make_error_reply(Packet, + ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt)), + ejabberd_router:route % TODO: s/Nick/""/ + (jid:replace_resource(StateData#state.jid, Nick), + From, Err), + StateData; {false, _, _, _} -> Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE), @@ -2555,14 +2574,18 @@ process_iq_admin(From, set, Lang, SubEl, StateData) -> process_admin_items_set(From, Items, Lang, StateData); process_iq_admin(From, get, Lang, SubEl, StateData) -> case fxml:get_subtag(SubEl, <<"item">>) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'item' element found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; Item -> FAffiliation = get_affiliation(From, StateData), FRole = get_role(From, StateData), case fxml:get_tag_attr(<<"role">>, Item) of false -> case fxml:get_tag_attr(<<"affiliation">>, Item) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'affiliation' attribute found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, StrAffiliation} -> case catch list_to_affiliation(StrAffiliation) of {'EXIT', _} -> {error, ?ERR_BAD_REQUEST}; @@ -2583,7 +2606,9 @@ process_iq_admin(From, get, Lang, SubEl, StateData) -> end; {value, StrRole} -> case catch list_to_role(StrRole) of - {'EXIT', _} -> {error, ?ERR_BAD_REQUEST}; + {'EXIT', _} -> + Txt = <<"Incorrect value of 'role' attribute">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; SRole -> if FRole == moderator -> Items = items_with_role(SRole, StateData), @@ -2780,7 +2805,9 @@ find_changed_items(UJID, UAffiliation, URole, {error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}; J -> {value, J} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt1 = <<"No 'nick' attribute found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt1)} end end, case TJID of @@ -2790,7 +2817,9 @@ find_changed_items(UJID, UAffiliation, URole, case fxml:get_attr(<<"role">>, Attrs) of false -> case fxml:get_attr(<<"affiliation">>, Attrs) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt2 = <<"No 'affiliation' attribute found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt2)}; {value, StrAffiliation} -> case catch list_to_affiliation(StrAffiliation) of {'EXIT', _} -> @@ -2839,7 +2868,9 @@ find_changed_items(UJID, UAffiliation, URole, find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, [MoreRes | Res]); - false -> {error, ?ERR_NOT_ALLOWED} + false -> + Txt3 = <<"Changing role/affiliation is not allowed">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt3)} end end end; @@ -2885,7 +2916,9 @@ find_changed_items(UJID, UAffiliation, URole, find_changed_items(UJID, UAffiliation, URole, Items, Lang, StateData, [MoreRes | Res]); - _ -> {error, ?ERR_NOT_ALLOWED} + _ -> + Txt4 = <<"Changing role/affiliation is not allowed">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt4)} end end end; @@ -3143,10 +3176,12 @@ process_iq_owner(From, set, Lang, SubEl, StateData) -> andalso is_password_settings_correct(XEl, StateData) of - true -> set_config(XEl, StateData); + true -> set_config(XEl, StateData, Lang); false -> {error, ?ERR_NOT_ACCEPTABLE} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end; [#xmlel{name = <<"destroy">>} = SubEl1] -> ?INFO_MSG("Destroyed MUC room ~s by the owner ~s", @@ -3170,7 +3205,9 @@ process_iq_owner(From, get, Lang, SubEl, StateData) -> [] -> get_config(Lang, StateData, From); [Item] -> case fxml:get_tag_attr(<<"affiliation">>, Item) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> + Txt = <<"No 'affiliation' attribute found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; {value, StrAffiliation} -> case catch list_to_affiliation(StrAffiliation) of {'EXIT', _} -> @@ -3642,10 +3679,10 @@ get_config(Lang, StateData, From) -> children = Res}], StateData}. -set_config(XEl, StateData) -> +set_config(XEl, StateData, Lang) -> XData = jlib:parse_xdata_submit(XEl), case XData of - invalid -> {error, ?ERR_BAD_REQUEST}; + invalid -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)}; _ -> case set_xoption(XData, StateData#state.config) of #config{} = Config -> @@ -3675,14 +3712,20 @@ set_config(XEl, StateData) -> <<"1">> -> set_xoption(Opts, Config#config{Opt = true}); <<"true">> -> set_xoption(Opts, Config#config{Opt = true}); - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Value of '~s' should be boolean">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_BAD_REQUEST(?MYLANG, ErrTxt)} end). -define(SET_NAT_XOPT(Opt, Val), case catch jlib:binary_to_integer(Val) of I when is_integer(I), I > 0 -> set_xoption(Opts, Config#config{Opt = I}); - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Value of '~s' should be integer">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_BAD_REQUEST(?MYLANG, ErrTxt)} end). -define(SET_STRING_XOPT(Opt, Val), @@ -3735,7 +3778,10 @@ set_xoption([{<<"allow_private_messages_from_visitors">>, <<"nobody">> -> ?SET_STRING_XOPT(allow_private_messages_from_visitors, nobody); - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Value of 'allow_private_messages_from_visitors' " + "should be anyone|moderators|nobody">>, + {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)} end; set_xoption([{<<"muc#roomconfig_allowvisitorstatus">>, [Val]} @@ -3803,7 +3849,10 @@ set_xoption([{<<"muc#roomconfig_presencebroadcast">>, Vals} | Opts], end end, {false, false, false}, Vals), case Roles of - error -> {error, ?ERR_BAD_REQUEST}; + error -> + Txt = <<"Value of 'muc#roomconfig_presencebroadcast' should " + "be moderator|participant|visitor">>, + {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)}; {M, P, V} -> Res = if M -> [moderator]; true -> [] end ++ @@ -3831,7 +3880,10 @@ set_xoption([{<<"muc#roomconfig_whois">>, [Val]} <<"anyone">> -> ?SET_BOOL_XOPT(anonymous, (iolist_to_binary(integer_to_list(0)))); - _ -> {error, ?ERR_BAD_REQUEST} + _ -> + Txt = <<"Value of 'muc#roomconfig_whois' should be " + "moderators|anyone">>, + {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)} end; set_xoption([{<<"muc#roomconfig_maxusers">>, [Val]} | Opts], @@ -3854,8 +3906,10 @@ set_xoption([{<<"muc#roomconfig_captcha_whitelist">>, ?SET_JIDMULTI_XOPT(captcha_whitelist, JIDs); set_xoption([{<<"FORM_TYPE">>, _} | Opts], Config) -> set_xoption(Opts, Config); -set_xoption([_ | _Opts], _Config) -> - {error, ?ERR_BAD_REQUEST}. +set_xoption([{Opt, _Vals} | _Opts], _Config) -> + Txt = <<"Unknown option '~s'">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_BAD_REQUEST(?MYLANG, ErrTxt)}. change_config(Config, StateData) -> send_config_change_info(Config, StateData), @@ -4128,8 +4182,9 @@ destroy_room(DEl, StateData) -> false -> ?FEATURE(Fiffalse) end). -process_iq_disco_info(_From, set, _Lang, _StateData) -> - {error, ?ERR_NOT_ALLOWED}; +process_iq_disco_info(_From, set, Lang, _StateData) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt)}; process_iq_disco_info(_From, get, Lang, StateData) -> Config = StateData#state.config, {result, @@ -4199,9 +4254,10 @@ iq_disco_info_extras(Lang, StateData) -> <<"muc#roominfo_occupants">>, (iolist_to_binary(integer_to_list(Len))))]}]. -process_iq_disco_items(_From, set, _Lang, _StateData) -> - {error, ?ERR_NOT_ALLOWED}; -process_iq_disco_items(From, get, _Lang, StateData) -> +process_iq_disco_items(_From, set, Lang, _StateData) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt)}; +process_iq_disco_items(From, get, Lang, StateData) -> case (StateData#state.config)#config.public_list of true -> {result, get_mucroom_disco_items(StateData), StateData}; @@ -4209,18 +4265,26 @@ process_iq_disco_items(From, get, _Lang, StateData) -> case is_occupant_or_admin(From, StateData) of true -> {result, get_mucroom_disco_items(StateData), StateData}; - _ -> {error, ?ERR_FORBIDDEN} + _ -> + Txt = <<"Only occupants or administrators can perform this query">>, + {error, ?ERRT_FORBIDDEN(Lang, Txt)} end end. -process_iq_captcha(_From, get, _Lang, _SubEl, +process_iq_captcha(_From, get, Lang, _SubEl, _StateData) -> - {error, ?ERR_NOT_ALLOWED}; -process_iq_captcha(_From, set, _Lang, SubEl, + Txt = <<"Value 'get' of 'type' attribute is not allowed">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt)}; +process_iq_captcha(_From, set, Lang, SubEl, StateData) -> case ejabberd_captcha:process_reply(SubEl) of ok -> {result, [], StateData}; - _ -> {error, ?ERR_NOT_ACCEPTABLE} + {error, malformed} -> + Txt = <<"Incorrect CAPTCHA submit">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; + _ -> + Txt = <<"The CAPTCHA verification has failed">>, + {error, ?ERRT_NOT_ALLOWED(Lang, Txt)} end. process_iq_vcard(_From, get, _Lang, _SubEl, StateData) -> @@ -4442,33 +4506,38 @@ is_invitation(Els) -> end, false, Els). -check_invitation(From, Els, Lang, StateData) -> +check_invitation(From, Packet, Lang, StateData) -> FAffiliation = get_affiliation(From, StateData), CanInvite = (StateData#state.config)#config.allow_user_invites orelse FAffiliation == admin orelse FAffiliation == owner, - InviteEl = case fxml:remove_cdata(Els) of - [#xmlel{name = <<"x">>, children = Els1} = XEl] -> - case fxml:get_tag_attr_s(<<"xmlns">>, XEl) of - ?NS_MUC_USER -> ok; - _ -> throw({error, ?ERR_BAD_REQUEST}) - end, - case fxml:remove_cdata(Els1) of - [#xmlel{name = <<"invite">>} = InviteEl1] -> InviteEl1; - _ -> throw({error, ?ERR_BAD_REQUEST}) - end; - _ -> throw({error, ?ERR_BAD_REQUEST}) + InviteEl = case fxml:get_subtag_with_xmlns(Packet, <<"x">>, ?NS_MUC_USER) of + false -> + Txt1 = <<"No 'x' element found">>, + throw({error, ?ERRT_BAD_REQUEST(Lang, Txt1)}); + XEl -> + case fxml:get_subtag(XEl, <<"invite">>) of + false -> + Txt2 = <<"No 'invite' element found">>, + throw({error, ?ERRT_BAD_REQUEST(Lang, Txt2)}); + InviteEl1 -> + InviteEl1 + end end, JID = case jid:from_string(fxml:get_tag_attr_s(<<"to">>, InviteEl)) of - error -> throw({error, ?ERR_JID_MALFORMED}); + error -> + Txt = <<"Incorrect value of 'to' attribute">>, + throw({error, ?ERRT_JID_MALFORMED(Lang, Txt)}); JID1 -> JID1 end, case CanInvite of - false -> throw({error, ?ERR_NOT_ALLOWED}); + false -> + Txt3 = <<"Invitations are not allowed in this conference">>, + throw({error, ?ERRT_NOT_ALLOWED(Lang, Txt3)}); true -> Reason = fxml:get_path_s(InviteEl, [{elem, <<"reason">>}, cdata]), diff --git a/src/mod_privacy.erl b/src/mod_privacy.erl index 193befe82..ea36fed25 100644 --- a/src/mod_privacy.erl +++ b/src/mod_privacy.erl @@ -105,27 +105,29 @@ process_iq(_From, _To, IQ) -> SubEl = IQ#iq.sub_el, IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}. -process_iq_get(_, From, _To, #iq{sub_el = SubEl}, +process_iq_get(_, From, _To, #iq{lang = Lang, sub_el = SubEl}, #userlist{name = Active}) -> #jid{luser = LUser, lserver = LServer} = From, #xmlel{children = Els} = SubEl, case fxml:remove_cdata(Els) of - [] -> process_lists_get(LUser, LServer, Active); + [] -> process_lists_get(LUser, LServer, Active, Lang); [#xmlel{name = Name, attrs = Attrs}] -> case Name of <<"list">> -> ListName = fxml:get_attr(<<"name">>, Attrs), - process_list_get(LUser, LServer, ListName); - _ -> {error, ?ERR_BAD_REQUEST} + process_list_get(LUser, LServer, ListName, Lang); + _ -> + Txt = <<"Unsupported tag name">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end; - _ -> {error, ?ERR_BAD_REQUEST} + _ -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Too many elements">>)} end. -process_lists_get(LUser, LServer, Active) -> - case process_lists_get(LUser, LServer, Active, +process_lists_get(LUser, LServer, Active, Lang) -> + case process_lists_get_db(LUser, LServer, Active, gen_mod:db_type(LServer, ?MODULE)) of - error -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + error -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; {_Default, []} -> {result, [#xmlel{name = <<"query">>, @@ -151,7 +153,7 @@ process_lists_get(LUser, LServer, Active) -> children = ADItems}]} end. -process_lists_get(LUser, LServer, _Active, mnesia) -> +process_lists_get_db(LUser, LServer, _Active, mnesia) -> case catch mnesia:dirty_read(privacy, {LUser, LServer}) of {'EXIT', _Reason} -> error; @@ -165,7 +167,7 @@ process_lists_get(LUser, LServer, _Active, mnesia) -> Lists), {Default, LItems} end; -process_lists_get(LUser, LServer, _Active, riak) -> +process_lists_get_db(LUser, LServer, _Active, riak) -> case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of {ok, #privacy{default = Default, lists = Lists}} -> LItems = lists:map(fun ({N, _}) -> @@ -180,7 +182,7 @@ process_lists_get(LUser, LServer, _Active, riak) -> {error, _} -> error end; -process_lists_get(LUser, LServer, _Active, odbc) -> +process_lists_get_db(LUser, LServer, _Active, odbc) -> Default = case catch sql_get_default_privacy_list(LUser, LServer) of {selected, []} -> none; {selected, [{DefName}]} -> DefName; @@ -198,11 +200,11 @@ process_lists_get(LUser, LServer, _Active, odbc) -> _ -> error end. -process_list_get(LUser, LServer, {value, Name}) -> - case process_list_get(LUser, LServer, Name, +process_list_get(LUser, LServer, {value, Name}, Lang) -> + case process_list_get_db(LUser, LServer, Name, gen_mod:db_type(LServer, ?MODULE)) of - error -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + error -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; not_found -> {error, ?ERR_ITEM_NOT_FOUND}; Items -> LItems = lists:map(fun item_to_xml/1, Items), @@ -213,10 +215,10 @@ process_list_get(LUser, LServer, {value, Name}) -> [#xmlel{name = <<"list">>, attrs = [{<<"name">>, Name}], children = LItems}]}]} end; -process_list_get(_LUser, _LServer, false) -> +process_list_get(_LUser, _LServer, false, _Lang) -> {error, ?ERR_BAD_REQUEST}. -process_list_get(LUser, LServer, Name, mnesia) -> +process_list_get_db(LUser, LServer, Name, mnesia) -> case catch mnesia:dirty_read(privacy, {LUser, LServer}) of {'EXIT', _Reason} -> error; @@ -227,7 +229,7 @@ process_list_get(LUser, LServer, Name, mnesia) -> _ -> not_found end end; -process_list_get(LUser, LServer, Name, riak) -> +process_list_get_db(LUser, LServer, Name, riak) -> case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of {ok, #privacy{lists = Lists}} -> case lists:keysearch(Name, 1, Lists) of @@ -239,7 +241,7 @@ process_list_get(LUser, LServer, Name, riak) -> {error, _} -> error end; -process_list_get(LUser, LServer, Name, odbc) -> +process_list_get_db(LUser, LServer, Name, odbc) -> case catch sql_get_privacy_list_id(LUser, LServer, Name) of {selected, []} -> not_found; {selected, [{ID}]} -> @@ -332,7 +334,7 @@ list_to_action(S) -> <<"deny">> -> deny end. -process_iq_set(_, From, _To, #iq{sub_el = SubEl}) -> +process_iq_set(_, From, _To, #iq{lang = Lang, sub_el = SubEl}) -> #jid{luser = LUser, lserver = LServer} = From, #xmlel{children = Els} = SubEl, case fxml:remove_cdata(Els) of @@ -342,27 +344,30 @@ process_iq_set(_, From, _To, #iq{sub_el = SubEl}) -> case Name of <<"list">> -> process_list_set(LUser, LServer, ListName, - fxml:remove_cdata(SubEls)); + fxml:remove_cdata(SubEls), Lang); <<"active">> -> process_active_set(LUser, LServer, ListName); <<"default">> -> - process_default_set(LUser, LServer, ListName); - _ -> {error, ?ERR_BAD_REQUEST} + process_default_set(LUser, LServer, ListName, Lang); + _ -> + Txt = <<"Unsupported tag name">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end; _ -> {error, ?ERR_BAD_REQUEST} end. -process_default_set(LUser, LServer, Value) -> - case process_default_set(LUser, LServer, Value, +process_default_set(LUser, LServer, Value, Lang) -> + case process_default_set_db(LUser, LServer, Value, gen_mod:db_type(LServer, ?MODULE)) of - {atomic, error} -> {error, ?ERR_INTERNAL_SERVER_ERROR}; + {atomic, error} -> + {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)}; {atomic, not_found} -> {error, ?ERR_ITEM_NOT_FOUND}; {atomic, ok} -> {result, []}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} end. -process_default_set(LUser, LServer, {value, Name}, +process_default_set_db(LUser, LServer, {value, Name}, mnesia) -> F = fun () -> case mnesia:read({privacy, {LUser, LServer}}) of @@ -378,7 +383,7 @@ process_default_set(LUser, LServer, {value, Name}, end end, mnesia:transaction(F); -process_default_set(LUser, LServer, {value, Name}, riak) -> +process_default_set_db(LUser, LServer, {value, Name}, riak) -> {atomic, case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of {ok, #privacy{lists = Lists} = P} -> @@ -393,7 +398,7 @@ process_default_set(LUser, LServer, {value, Name}, riak) -> {error, _} -> not_found end}; -process_default_set(LUser, LServer, {value, Name}, +process_default_set_db(LUser, LServer, {value, Name}, odbc) -> F = fun () -> case sql_get_privacy_list_names_t(LUser) of @@ -406,7 +411,7 @@ process_default_set(LUser, LServer, {value, Name}, end end, odbc_queries:sql_transaction(LServer, F); -process_default_set(LUser, LServer, false, mnesia) -> +process_default_set_db(LUser, LServer, false, mnesia) -> F = fun () -> case mnesia:read({privacy, {LUser, LServer}}) of [] -> ok; @@ -414,7 +419,7 @@ process_default_set(LUser, LServer, false, mnesia) -> end end, mnesia:transaction(F); -process_default_set(LUser, LServer, false, riak) -> +process_default_set_db(LUser, LServer, false, riak) -> {atomic, case ejabberd_riak:get(privacy, privacy_schema(), {LUser, LServer}) of {ok, R} -> @@ -422,7 +427,7 @@ process_default_set(LUser, LServer, false, riak) -> {error, _} -> ok end}; -process_default_set(LUser, LServer, false, odbc) -> +process_default_set_db(LUser, LServer, false, odbc) -> case catch sql_unset_default_privacy_list(LUser, LServer) of @@ -588,14 +593,16 @@ set_privacy_list(LUser, LServer, Name, List, odbc) -> end, odbc_queries:sql_transaction(LServer, F). -process_list_set(LUser, LServer, {value, Name}, Els) -> +process_list_set(LUser, LServer, {value, Name}, Els, Lang) -> case parse_items(Els) of false -> {error, ?ERR_BAD_REQUEST}; remove -> case remove_privacy_list(LUser, LServer, Name, gen_mod:db_type(LServer, ?MODULE)) of - {atomic, conflict} -> {error, ?ERR_CONFLICT}; + {atomic, conflict} -> + Txt = <<"Cannot remove default list">>, + {error, ?ERRT_CONFLICT(Lang, Txt)}; {atomic, ok} -> ejabberd_sm:route(jid:make(LUser, LServer, <<"">>), @@ -605,7 +612,7 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> list = []}, Name}}), {result, []}; - _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} + _ -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} end; List -> case set_privacy_list(LUser, LServer, Name, List, @@ -622,10 +629,10 @@ process_list_set(LUser, LServer, {value, Name}, Els) -> needdb = NeedDb}, Name}}), {result, []}; - _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} + _ -> {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, <<"Database failure">>)} end end; -process_list_set(_LUser, _LServer, false, _Els) -> +process_list_set(_LUser, _LServer, false, _Els, _Lang) -> {error, ?ERR_BAD_REQUEST}. parse_items([]) -> remove; diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index 6531ed876..247b9f8c4 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -1034,7 +1034,10 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> none -> ok; invalid -> - Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST), + Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), + Txt = <<"Incorrect authorization response">>, + Err = jlib:make_error_reply( + Packet, ?ERRT_BAD_REQUEST(Lang, Txt)), ejabberd_router:route(To, From, Err); XFields -> handle_authorization_response(Host, From, To, Packet, XFields) @@ -1418,13 +1421,14 @@ adhoc_request(Host, _ServerHost, Owner, send_pending_node_form(Host, Owner, Lang, Plugins); adhoc_request(Host, _ServerHost, Owner, #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, - action = <<"execute">>, xdata = XData}, + action = <<"execute">>, xdata = XData, lang = Lang}, _Access, _Plugins) -> ParseOptions = case XData of #xmlel{name = <<"x">>} = XEl -> case jlib:parse_xdata_submit(XEl) of invalid -> - {error, ?ERR_BAD_REQUEST}; + Txt = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; XData2 -> case set_xoption(Host, XData2, []) of NewOpts when is_list(NewOpts) -> {result, NewOpts}; @@ -1432,8 +1436,8 @@ adhoc_request(Host, _ServerHost, Owner, end end; _ -> - ?INFO_MSG("Bad XForm: ~p", [XData]), - {error, ?ERR_BAD_REQUEST} + Txt = <<"No data form found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end, case ParseOptions of {result, XForm} -> @@ -1463,7 +1467,9 @@ send_pending_node_form(Host, Owner, _Lang, Plugins) -> end, case lists:filter(Filter, Plugins) of [] -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}; + Err = extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, + unsupported, <<"get-pending">>), + {error, Err}; Ps -> XOpts = [#xmlel{name = <<"option">>, attrs = [], children = [#xmlel{name = <<"value">>, @@ -1504,10 +1510,11 @@ send_pending_auth_events(Host, Node, Owner) -> true -> case node_call(Host, Type, get_affiliation, [Nidx, Owner]) of {result, owner} -> node_call(Host, Type, get_node_subscriptions, [Nidx]); - _ -> {error, ?ERR_FORBIDDEN} + _ -> {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} end; false -> - {error, ?ERR_FEATURE_NOT_IMPLEMENTED} + {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, + unsupported, <<"get-pending">>)} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -1644,6 +1651,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> ejabberd_router:route(service_jid(Host), JID, Stanza). handle_authorization_response(Host, From, To, Packet, XFields) -> + Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet), case {lists:keysearch(<<"pubsub#node">>, 1, XFields), lists:keysearch(<<"pubsub#subscriber_jid">>, 1, XFields), lists:keysearch(<<"pubsub#allow">>, 1, XFields)} @@ -1665,7 +1673,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> {result, Subs} = node_call(Host, Type, get_subscriptions, [Nidx, Subscriber]), update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs); false -> - {error, ?ERR_FORBIDDEN} + {error, ?ERRT_FORBIDDEN(Lang, <<"You're not an owner">>)} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -1680,7 +1688,8 @@ handle_authorization_response(Host, From, To, Packet, XFields) -> ejabberd_router:route(To, From, Err) end; _ -> - Err = jlib:make_error_reply(Packet, ?ERR_NOT_ACCEPTABLE), + Txt = <<"Incorrect data form">>, + Err = jlib:make_error_reply(Packet, ?ERRT_NOT_ACCEPTABLE(Lang, Txt)), ejabberd_router:route(To, From, Err) end. @@ -1691,7 +1700,7 @@ update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> end, Subs), case Sub of - [{pending, SubId}] -> + [{pending, SubId}|_] -> NewSub = case Allow of true -> subscribed; false -> none @@ -1700,7 +1709,8 @@ update_auth(Host, Node, Type, Nidx, Subscriber, Allow, Subs) -> send_authorization_approval(Host, Subscriber, Node, NewSub), {result, ok}; _ -> - {error, ?ERR_UNEXPECTED_REQUEST} + Txt = <<"No pending subscriptions found">>, + {error, ?ERRT_UNEXPECTED_REQUEST(?MYLANG, Txt)} end. -define(XFIELD(Type, Label, Var, Val), @@ -1830,7 +1840,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> [#xmlel{name = <<"x">>} = XEl] -> case jlib:parse_xdata_submit(XEl) of invalid -> - {error, ?ERR_BAD_REQUEST}; + Txt = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)}; XData -> case set_xoption(Host, XData, node_options(Host, Type)) of NewOpts when is_list(NewOpts) -> {result, NewOpts}; @@ -1839,7 +1850,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> end; _ -> ?INFO_MSG("Node ~p; bad configuration: ~p", [Node, Configuration]), - {error, ?ERR_BAD_REQUEST} + Txt = <<"No data form found">>, + {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)} end, case ParseOptions of {result, NodeOptions} -> @@ -1876,7 +1888,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> Error end; _ -> - {error, ?ERR_FORBIDDEN} + Txt1 = <<"You're not allowed to create nodes">>, + {error, ?ERRT_FORBIDDEN(?MYLANG, Txt1)} end end, Reply = [#xmlel{name = <<"pubsub">>, @@ -1926,7 +1939,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) -> | {error, xmlel()} ). delete_node(_Host, <<>>, _Owner) -> - {error, ?ERR_NOT_ALLOWED}; + {error, ?ERRT_NOT_ALLOWED(?MYLANG, <<"No node specified">>)}; delete_node(Host, Node, Owner) -> Action = fun (#pubsub_node{type = Type, id = Nidx}) -> case node_call(Host, Type, get_affiliation, [Nidx, Owner]) of @@ -1938,7 +1951,7 @@ delete_node(Host, Node, Owner) -> Error -> Error end; _ -> - {error, ?ERR_FORBIDDEN} + {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} end end, Reply = [], @@ -2247,22 +2260,28 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, Access) -> {result, Reply}; {result, {_, Result}} -> {result, Result}; - {error, ?ERR_ITEM_NOT_FOUND} -> - Type = select_type(ServerHost, Host, Node), - case lists:member(<<"auto-create">>, plugin_features(Host, Type)) of + {error, _} = Error -> + case is_item_not_found(Error) of true -> - case create_node(Host, ServerHost, Node, Publisher, Type, Access, []) of - {result, - [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"create">>, - attrs = [{<<"node">>, NewNode}]}]}]} -> - publish_item(Host, ServerHost, NewNode, Publisher, ItemId, Payload); - _ -> - {error, ?ERR_ITEM_NOT_FOUND} + Type = select_type(ServerHost, Host, Node), + case lists:member(<<"auto-create">>, plugin_features(Host, Type)) of + true -> + case create_node(Host, ServerHost, Node, Publisher, Type, Access, []) of + {result, + [#xmlel{name = <<"pubsub">>, + attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + children = [#xmlel{name = <<"create">>, + attrs = [{<<"node">>, NewNode}]}]}]} -> + publish_item(Host, ServerHost, NewNode, Publisher, ItemId, Payload); + _ -> + {error, ?ERR_ITEM_NOT_FOUND} + end; + false -> + Txt = <<"Automatic node creation is not enabled">>, + {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, Txt)} end; false -> - {error, ?ERR_ITEM_NOT_FOUND} + Error end; Error -> Error @@ -2416,7 +2435,9 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIds, RSM) -> end; true -> case catch jlib:binary_to_integer(SMaxItems) of - {'EXIT', _} -> {error, ?ERR_BAD_REQUEST}; + {'EXIT', _} -> + Txt = <<"Value of 'max_items' should be integer">>, + {error, ?ERRT_BAD_REQUEST(?MYLANG, Txt)}; Val -> Val end end, @@ -2639,7 +2660,7 @@ get_affiliations(Host, Node, JID) -> {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"modify-affiliations">>)}; Affiliation /= owner -> - {error, ?ERR_FORBIDDEN}; + {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)}; true -> node_call(Host, Type, get_node_affiliations, [Nidx]) end @@ -2732,7 +2753,7 @@ set_affiliations(Host, Node, From, EntitiesEls) -> FilteredEntities), {result, []}; _ -> - {error, ?ERR_FORBIDDEN} + {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -2948,7 +2969,7 @@ get_subscriptions(Host, Node, JID) -> {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, <<"manage-subscriptions">>)}; Affiliation /= owner -> - {error, ?ERR_FORBIDDEN}; + {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)}; true -> node_call(Host, Type, get_node_subscriptions, [Nidx]) end @@ -3059,10 +3080,10 @@ set_subscriptions(Host, Node, From, EntitiesEls) -> [], Entities), case Result of [] -> {result, []}; - _ -> {error, ?ERR_NOT_ACCEPTABLE} + [{error, E}|_] -> {error, E} end; _ -> - {error, ?ERR_FORBIDDEN} + {error, ?ERRT_FORBIDDEN(?MYLANG, <<"You're not an owner">>)} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -3606,7 +3627,7 @@ get_configure(Host, ServerHost, Node, From, Lang) -> children = get_configure_xfields(Type, Options, Lang, Groups)}]}]}]}; _ -> - {error, ?ERR_FORBIDDEN} + {error, ?ERRT_FORBIDDEN(Lang, <<"You're not an owner">>)} end end, case transaction(Host, Node, Action, sync_dirty) of @@ -3820,7 +3841,8 @@ set_configure(Host, Node, From, Els, Lang) -> {result, owner} -> case jlib:parse_xdata_submit(XEl) of invalid -> - {error, ?ERR_BAD_REQUEST}; + Txt = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)}; XData -> OldOpts = case Options of [] -> node_options(Host, Type); @@ -3840,7 +3862,8 @@ set_configure(Host, Node, From, Els, Lang) -> end end; _ -> - {error, ?ERR_FORBIDDEN} + Txt = <<"You're not an owner">>, + {error, ?ERRT_FORBIDDEN(Lang, Txt)} end end, case transaction(Host, Node, Action, transaction) of @@ -3854,10 +3877,12 @@ set_configure(Host, Node, From, Els, Lang) -> Other end; _ -> - {error, ?ERR_BAD_REQUEST} + Txt = <<"Incorrect data form">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end; _ -> - {error, ?ERR_BAD_REQUEST} + Txt = <<"No data form found">>, + {error, ?ERRT_BAD_REQUEST(Lang, Txt)} end. add_opt(Key, Value, Opts) -> @@ -3872,7 +3897,10 @@ add_opt(Key, Value, Opts) -> _ -> error end, case BoolVal of - error -> {error, ?ERR_NOT_ACCEPTABLE}; + error -> + Txt = <<"Value of '~s' should be boolean">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}; _ -> set_xoption(Host, Opts, add_opt(Opt, BoolVal, NewOpts)) end). @@ -3885,10 +3913,14 @@ add_opt(Key, Value, Opts) -> if (Max =:= undefined) orelse (IVal =< Max) -> set_xoption(Host, Opts, add_opt(Opt, IVal, NewOpts)); true -> - {error, ?ERR_NOT_ACCEPTABLE} + Txt = <<"Incorrect value of '~s'">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} end; _ -> - {error, ?ERR_NOT_ACCEPTABLE} + Txt = <<"Value of '~s' should be integer">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} end). -define(SET_ALIST_XOPT(Opt, Val, Vals), @@ -3896,7 +3928,9 @@ add_opt(Key, Value, Opts) -> true -> set_xoption(Host, Opts, add_opt(Opt, jlib:binary_to_atom(Val), NewOpts)); false -> - {error, ?ERR_NOT_ACCEPTABLE} + Txt = <<"Incorrect value of '~s'">>, + ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])), + {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)} end). -define(SET_LIST_XOPT(Opt, Val), @@ -4139,8 +4173,9 @@ features(Host, Node) when is_binary(Node) -> tree_call({_User, Server, _Resource}, Function, Args) -> tree_call(Server, Function, Args); tree_call(Host, Function, Args) -> - ?DEBUG("tree_call ~p ~p ~p", [Host, Function, Args]), - catch apply(tree(Host), Function, Args). + Tree = tree(Host), + ?DEBUG("tree_call apply(~s, ~s, ~p) @ ~s", [Tree, Function, Args, Host]), + catch apply(Tree, Function, Args). tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p", [Host, Function, Args]), @@ -4267,6 +4302,13 @@ extended_error(#xmlel{name = Error, attrs = Attrs, children = SubEls}, Ext, ExtA #xmlel{name = Error, attrs = Attrs, children = lists:reverse([#xmlel{name = Ext, attrs = ExtAttrs} | SubEls])}. +is_item_not_found({error, ErrEl}) -> + case fxml:get_subtag_with_xmlns( + ErrEl, <<"item-not-found">>, ?NS_STANZAS) of + #xmlel{} -> true; + _ -> false + end. + string_to_ljid(JID) -> case jid:from_string(JID) of error -> diff --git a/src/mod_register.erl b/src/mod_register.erl index 56c5f7205..fee2a2284 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -151,21 +151,28 @@ process_iq(From, To, %% modules. lists:foreach can %% only return ok: not_allowed -> + Txt = <<"Removal is not allowed">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + sub_el = [SubEl, + ?ERRT_NOT_ALLOWED(Lang, Txt)]}; not_exists -> + Txt = <<"No such user">>, IQ#iq{type = error, sub_el = - [SubEl, ?ERR_ITEM_NOT_FOUND]}; - _ -> + [SubEl, + ?ERRT_ITEM_NOT_FOUND(Lang, Txt)]}; + Err -> + ?ERROR_MSG("failed to remove user ~s@~s: ~p", + [User, Server, Err]), IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} end; true -> + Txt = <<"No password in this query">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]} + sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} end end; (UTag == false) and (RTag /= false) and AllowRemove -> @@ -182,7 +189,9 @@ process_iq(From, To, ejabberd_auth:remove_user(User, Server), ignore; _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + Txt = <<"The query is only allowed from local users">>, + IQ#iq{type = error, + sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]} end; (UTag /= false) and (PTag /= false) -> User = fxml:get_tag_cdata(UTag), @@ -200,11 +209,14 @@ process_iq(From, To, SubEl, Source, Lang, true); _ -> + Txt = <<"Incorrect data form">>, IQ#iq{type = error, - sub_el = [SubEl, ?ERR_BAD_REQUEST]} + sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} end; {error, malformed} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}; + Txt = <<"Incorrect CAPTCHA submit">>, + IQ#iq{type = error, + sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]}; _ -> ErrText = <<"The CAPTCHA verification has failed">>, IQ#iq{type = error, @@ -344,7 +356,8 @@ try_register_or_set_password(User, Server, Password, IQ#iq{type = error, sub_el = [SubEl, Error]} end; deny -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} + Txt = <<"Denied by ACL">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} end; _ -> IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} @@ -359,13 +372,17 @@ try_set_password(User, Server, Password, IQ, SubEl, of ok -> IQ#iq{type = result, sub_el = []}; {error, empty_password} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}; + Txt = <<"Empty password">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]}; {error, not_allowed} -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; + Txt = <<"Chaning password is not allowed">>, + IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}; {error, invalid_jid} -> IQ#iq{type = error, - sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}; - _ -> + sub_el = [SubEl, ?ERR_JID_MALFORMED]}; + Err -> + ?ERROR_MSG("failed to register user ~s@~s: ~p", + [User, Server, Err]), IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} end; @@ -377,7 +394,7 @@ try_set_password(User, Server, Password, IQ, SubEl, try_register(User, Server, Password, SourceRaw, Lang) -> case jid:is_nodename(User) of - false -> {error, ?ERR_BAD_REQUEST}; + false -> {error, ?ERRT_BAD_REQUEST(Lang, <<"Malformed username">>)}; _ -> JID = jid:make(User, Server, <<"">>), Access = gen_mod:get_module_opt(Server, ?MODULE, access, @@ -387,8 +404,8 @@ try_register(User, Server, Password, SourceRaw, Lang) -> case {acl:match_rule(Server, Access, JID), check_ip_access(SourceRaw, IPAccess)} of - {deny, _} -> {error, ?ERR_FORBIDDEN}; - {_, deny} -> {error, ?ERR_FORBIDDEN}; + {deny, _} -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; + {_, deny} -> {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)}; {allow, allow} -> Source = may_remove_resource(SourceRaw), case check_timeout(Source) of @@ -406,14 +423,20 @@ try_register(User, Server, Password, SourceRaw, Lang) -> Error -> remove_timeout(Source), case Error of - {atomic, exists} -> {error, ?ERR_CONFLICT}; + {atomic, exists} -> + Txt = <<"User already exists">>, + {error, ?ERRT_CONFLICT(Lang, Txt)}; {error, invalid_jid} -> {error, ?ERR_JID_MALFORMED}; {error, not_allowed} -> {error, ?ERR_NOT_ALLOWED}; {error, too_many_users} -> - {error, ?ERR_NOT_ALLOWED}; - {error, _Reason} -> + Txt = <<"Too many users registered">>, + {error, ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt)}; + {error, _} -> + ?ERROR_MSG("failed to register user " + "~s@~s: ~p", + [User, Server, Error]), {error, ?ERR_INTERNAL_SERVER_ERROR} end end; diff --git a/src/node_flat_odbc.erl b/src/node_flat_odbc.erl index 5aeb973d1..5dd520668 100644 --- a/src/node_flat_odbc.erl +++ b/src/node_flat_odbc.erl @@ -800,8 +800,10 @@ get_item(Nidx, ItemId) -> {selected, [<<"itemid">>, <<"publisher">>, <<"creation">>, <<"modification">>, <<"payload">>], [RItem]} -> {result, raw_to_item(Nidx, RItem)}; - _ -> - {error, ?ERR_ITEM_NOT_FOUND} + {selected, _, []} -> + {error, ?ERR_ITEM_NOT_FOUND}; + {'EXIT', _} -> + {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)} end. get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->