Implement XEP-0410: MUC Self-Ping optimization

Fixes #2630
This commit is contained in:
Evgeny Khramtsov 2018-11-29 12:16:12 +03:00
parent 3f901b3793
commit 624485fe26
1 changed files with 40 additions and 26 deletions

View File

@ -51,9 +51,8 @@
code_change/4]).
-include("logger.hrl").
-include("xmpp.hrl").
-include("translate.hrl").
-include("mod_muc_room.hrl").
-define(MAX_USERS_DEFAULT_LIST,
@ -435,11 +434,10 @@ normal_state({route, ToNick,
{next_state, normal_state, StateData}
end;
normal_state({route, ToNick,
#iq{from = From, type = Type, lang = Lang} = Packet},
StateData) ->
case {(StateData#state.config)#config.allow_query_users,
maps:get(jid:tolower(From), StateData#state.users, error)} of
{true, #user{nick = FromNick}} ->
#iq{from = From, lang = Lang} = Packet},
#state{config = #config{allow_query_users = AllowQuery}} = StateData) ->
try maps:get(jid:tolower(From), StateData#state.users) of
#user{nick = FromNick} when AllowQuery orelse ToNick == FromNick ->
case find_jid_by_nick(ToNick, StateData) of
false ->
ErrText = <<"Recipient is not in the conference room">>,
@ -447,28 +445,33 @@ normal_state({route, ToNick,
ejabberd_router:route_error(Packet, Err);
To ->
FromJID = jid:replace_resource(StateData#state.jid, FromNick),
if Type == get; Type == set ->
ToJID = case is_vcard_request(Packet) of
true -> jid:remove_resource(To);
false -> To
end,
case direct_iq_type(Packet) of
vcard ->
ejabberd_router:route_iq(
xmpp:set_from_to(Packet, FromJID, ToJID), Packet, self());
true ->
ejabberd_router:route(
xmpp:set_from_to(Packet, FromJID, To))
xmpp:set_from_to(Packet, FromJID, jid:remove_resource(To)),
Packet, self());
ping when ToNick == FromNick ->
%% Self-ping optimization from XEP-0410
ejabberd_router:route(xmpp:make_iq_result(Packet));
response ->
ejabberd_router:route(xmpp:set_from_to(Packet, FromJID, To));
#stanza_error{} = Err ->
ejabberd_router:route_error(Packet, Err);
_OtherRequest ->
ejabberd_router:route_iq(
xmpp:set_from_to(Packet, FromJID, To), Packet, self())
end
end;
{true, error} ->
ErrText = <<"Only occupants are allowed to send queries "
"to the conference">>,
Err = xmpp:err_not_acceptable(ErrText, Lang),
ejabberd_router:route_error(Packet, Err);
_ ->
ErrText = <<"Queries to the conference members are "
"not allowed in this room">>,
Err = xmpp:err_not_allowed(ErrText, Lang),
ejabberd_router:route_error(Packet, Err)
catch _:{badkey, _} ->
ErrText = <<"Only occupants are allowed to send queries "
"to the conference">>,
Err = xmpp:err_not_acceptable(ErrText, Lang),
ejabberd_router:route_error(Packet, Err)
end,
{next_state, normal_state, StateData};
normal_state(_Event, StateData) ->
@ -951,11 +954,22 @@ process_voice_approval(From, Pkt, VoiceApproval, StateData) ->
StateData
end.
-spec is_vcard_request(iq()) -> boolean().
is_vcard_request(#iq{type = T, sub_els = [El]}) ->
(T == get orelse T == set) andalso xmpp:get_ns(El) == ?NS_VCARD;
is_vcard_request(_) ->
false.
-spec direct_iq_type(iq()) -> vcard | ping | request | response | stanza_error().
direct_iq_type(#iq{type = T, sub_els = SubEls, lang = Lang}) when T == get; T == set ->
case SubEls of
[El] ->
case xmpp:get_ns(El) of
?NS_VCARD when T == get -> vcard;
?NS_PING when T == get -> ping;
_ -> request
end;
[] ->
xmpp:err_bad_request(?T("No child elements found"), Lang);
[_|_] ->
xmpp:err_bad_request(?T("Too many child elements"), Lang)
end;
direct_iq_type(#iq{}) ->
response.
%% @doc Check if this non participant can send message to room.
%%