24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-06-02 21:17:12 +02:00

Apply patch from Evgeniy Khramtsov

This commit is contained in:
Maxim Ignatenko 2011-09-26 09:55:07 +03:00
parent 499b884c67
commit ff57c8a58c

View File

@ -256,109 +256,140 @@ normal_state({route, From, "",
From, Err), From, Err),
{next_state, normal_state, StateData}; {next_state, normal_state, StateData};
Type when (Type == "") or (Type == "normal") -> Type when (Type == "") or (Type == "normal") ->
IsInvitation = is_invitation(Els), IsInvitation = is_invitation(Els),
IsVoiceRequest = is_voice_request(Els) and is_visitor(From, StateData), IsVoiceRequest = is_voice_request(Els)
IsVoiceApprovement = is_voice_approvement(Els) and not is_visitor(From, StateData), and is_visitor(From, StateData),
if IsVoiceApprovement = is_voice_approvement(Els)
IsInvitation -> and not is_visitor(From, StateData),
case catch check_invitation(From, Els, Lang, StateData) of if IsInvitation ->
case catch check_invitation(From, Els, Lang, StateData) of
{error, Error} -> {error, Error} ->
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, Error), Packet, Error),
ejabberd_router:route( ejabberd_router:route(
StateData#state.jid, StateData#state.jid,
From, Err), From, Err),
{next_state, normal_state, StateData}; {next_state, normal_state, StateData};
IJID -> IJID ->
Config = StateData#state.config, Config = StateData#state.config,
case Config#config.members_only of case Config#config.members_only of
true -> true ->
case get_affiliation(IJID, StateData) of case get_affiliation(IJID, StateData) of
none -> none ->
NSD = set_affiliation( NSD = set_affiliation(
IJID, IJID,
member, member,
StateData), StateData),
case (NSD#state.config)#config.persistent of case (NSD#state.config)#config.persistent of
true -> true ->
mod_muc:store_room( mod_muc:store_room(
NSD#state.host, NSD#state.host,
NSD#state.room, NSD#state.room,
make_opts(NSD)); make_opts(NSD));
_ -> _ ->
ok ok
end, end,
{next_state, normal_state, NSD}; {next_state, normal_state, NSD};
_ -> _ ->
{next_state, normal_state, {next_state, normal_state,
StateData} StateData}
end; end;
false -> false ->
{next_state, normal_state, StateData} {next_state, normal_state, StateData}
end end
end; end;
IsVoiceRequest -> IsVoiceRequest ->
NewStateData = case (StateData#state.config)#config.allow_voice_requests of NewStateData =
true -> case (StateData#state.config)#config.allow_voice_requests of
MinInterval = (StateData#state.config)#config.voice_request_min_interval, true ->
BareFrom = jlib:jid_remove_resource(jlib:jid_tolower(From)), MinInterval = (StateData#state.config)
LastTime = last_voice_request_time(BareFrom, StateData), #config.voice_request_min_interval,
TimeFromLastRequest = timer:now_diff(erlang:now(), LastTime), BareFrom = jlib:jid_remove_resource(
if jlib:jid_tolower(From)),
TimeFromLastRequest > MinInterval*1000000 -> LastTime = last_voice_request_time(
send_voice_request(From, StateData), BareFrom, StateData),
update_voice_request_time(BareFrom, StateData); TimeFromLastRequest =
true -> timer:now_diff(
ErrText = "Please, wait for a while before sending new voice request", now(), LastTime) div 1000000,
Err = jlib:make_error_reply( if TimeFromLastRequest > MinInterval ->
Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), send_voice_request(
From, StateData),
update_voice_request_time(
BareFrom, StateData);
true ->
ErrText = "Please, wait for "
"a while before sending "
"new voice request",
Err = jlib:make_error_reply(
Packet,
?ERRT_NOT_ACCEPTABLE(
Lang, ErrText)),
ejabberd_router:route( ejabberd_router:route(
StateData#state.jid, From, Err), StateData#state.jid,
From, Err),
StateData StateData
end; end;
false -> false ->
ErrText = "Voice requests are disabled in this room", ErrText = "Voice requests are "
"disabled in this room",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), Packet,
?ERRT_FORBIDDEN(
Lang, ErrText)),
ejabberd_router:route( ejabberd_router:route(
StateData#state.jid, From, Err), StateData#state.jid, From, Err),
StateData StateData
end, end,
{next_state, normal_state, NewStateData}; {next_state, normal_state, NewStateData};
IsVoiceApprovement -> IsVoiceApprovement ->
NewStateData = case is_moderator(From, StateData) of NewStateData =
true -> case is_moderator(From, StateData) of
true ->
case extract_jid_from_voice_approvement(Els) of case extract_jid_from_voice_approvement(Els) of
{error, _} -> error ->
ErrText = "Failed to extract JID from your voice request approvement", ErrText = "Failed to extract "
"JID from your voice "
"request approvement",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_BAD_REQUEST(Lang, ErrText)), Packet,
?ERRT_BAD_REQUEST(
Lang, ErrText)),
ejabberd_router:route( ejabberd_router:route(
StateData#state.jid, From, Err), StateData#state.jid,
From, Err),
StateData; StateData;
TargetJid -> {ok, TargetJid} ->
case is_visitor(TargetJid, StateData) of case is_visitor(
true -> TargetJid, StateData) of
true ->
Reason = [], Reason = [],
NSD = set_role(TargetJid, participant, StateData), NSD = set_role(
catch send_new_presence(TargetJid, Reason, NSD), TargetJid,
participant,
StateData),
catch send_new_presence(
TargetJid,
Reason, NSD),
NSD; NSD;
_ -> _ ->
StateData StateData
end end
end; end;
_ -> _ ->
ErrText = "Only moderators can approve voice requests", ErrText = "Only moderators can "
"approve voice requests",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
Packet, ?ERRT_NOT_ALLOWED(Lang, ErrText)), Packet,
?ERRT_NOT_ALLOWED(
Lang, ErrText)),
ejabberd_router:route( ejabberd_router:route(
StateData#state.jid, From, Err), StateData#state.jid, From, Err),
StateData StateData
end, end,
{next_state, normal_state, NewStateData}; {next_state, normal_state, NewStateData};
true -> true ->
{next_state, normal_state, StateData} {next_state, normal_state, StateData}
end; end;
_ -> _ ->
ErrText = "Improper message type", ErrText = "Improper message type",
Err = jlib:make_error_reply( Err = jlib:make_error_reply(
@ -3713,153 +3744,121 @@ get_mucroom_disco_items(StateData) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Voice request support % Voice request support
is_voice_request({xmlelement, "x", _, _} = Elem) ->
case xml:get_tag_attr_s("xmlns", Elem) of
?NS_XDATA ->
Fields = jlib:parse_xdata_submit(Elem),
lists:foldl(
fun(X,Y) ->
check_voice_request_fields(X,Y)
end,
true, Fields);
_ ->
false
end;
is_voice_request(Els) -> is_voice_request(Els) ->
lists:foldl( lists:foldl(
fun(_, true) -> fun({xmlelement, "x", Attrs, _} = El, false) ->
true; case xml:get_attr_s("xmlns", Attrs) of
({xmlelement, "x", _, _} = X, false) -> ?NS_XDATA ->
is_voice_request(X); case jlib:parse_xdata_submit(El) of
(_, _) -> [_|_] = Fields ->
false case {lists:keysearch("FORM_TYPE", 1, Fields),
end, false, Els). lists:keysearch("muc#role", 1, Fields)} of
{["http://jabber.org/protocol/muc#request"],
check_voice_request_fields(_, false) -> ["participant"]} ->
false; true;
check_voice_request_fields({"FORM_TYPE", ["http://jabber.org/protocol/muc#request"]}, true) -> _ ->
true; false
check_voice_request_fields({"FORM_TYPE", _}, _) -> end;
false; _ ->
check_voice_request_fields({"muc#role", ["participant"]}, true) -> false
true; end;
check_voice_request_fields({"muc#role", _}, _) -> _ ->
false; false
check_voice_request_fields(_, true) -> end;
true. % silently ignore any extra fields (_, Acc) ->
Acc
end, false, Els).
prepare_request_form(Requester, Nick, Lang) -> prepare_request_form(Requester, Nick, Lang) ->
{xmlelement, "message", [{"type", "normal"}], [ {xmlelement, "message", [{"type", "normal"}],
{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
[ [{xmlelement, "title", [],
{xmlelement, "title", [], [{xmlcdata, translate:translate(Lang, "Voice request")}]},
[{xmlcdata, translate:translate(Lang, "Voice request")}]}, {xmlelement, "instructions", [],
{xmlelement, "instructions", [], [{xmlcdata,
[{xmlcdata, translate:translate(Lang, "To approve this request for voice, select the \"Grant voice to this person?\" checkbox and click OK. To skip this request, click the cancel button.")}]}, translate:translate(
{xmlelement, "field", [{"var", "FORM_TYPE"}, {"type", "hidden"}], Lang, "To approve this request for voice, select the "
[{xmlelement, "value", [], "\"Grant voice to this person?\" checkbox and click OK. "
[{xmlcdata, "http://jabber.org/protocol/muc#request"}]}]}, "To skip this request, click the cancel button.")}]},
?STRINGXFIELD("Requested role", "muc#role", "participant"), {xmlelement, "field", [{"var", "FORM_TYPE"}, {"type", "hidden"}],
?STRINGXFIELD("User JID", "muc#jid", jlib:jid_to_string(Requester)), [{xmlelement, "value", [],
?STRINGXFIELD("Nickname", "muc#roomnick", Nick), [{xmlcdata, "http://jabber.org/protocol/muc#request"}]}]},
?BOOLXFIELD("Grant voice to this person?", "muc#request_allow", false) ?STRINGXFIELD("Requested role", "muc#role", "participant"),
] ?STRINGXFIELD("User JID", "muc#jid", jlib:jid_to_string(Requester)),
}]}. ?STRINGXFIELD("Nickname", "muc#roomnick", Nick),
?BOOLXFIELD("Grant voice to this person?", "muc#request_allow", false)
]}]}.
send_voice_request(From, StateData) -> send_voice_request(From, StateData) ->
Moderators = search_role(moderator, StateData), Moderators = search_role(moderator, StateData),
FromNick = find_nick_by_jid(From, StateData), FromNick = find_nick_by_jid(From, StateData),
lists:foreach( lists:foreach(
fun({_, User}) -> fun({_, User}) ->
ejabberd_router:route( ejabberd_router:route(
StateData#state.jid, StateData#state.jid,
User#user.jid, User#user.jid,
prepare_request_form(From, FromNick, "")) prepare_request_form(From, FromNick, ""))
end, Moderators). end, Moderators).
is_voice_approvement({xmlelement, "x", _, _} = Elem) ->
case xml:get_tag_attr_s("xmlns", Elem) of
?NS_XDATA ->
Fields = jlib:parse_xdata_submit(Elem),
lists:foldl(
fun(X,Y) ->
check_voice_approvement_fields(X,Y)
end,
true, Fields);
_ ->
false
end;
is_voice_approvement(Els) -> is_voice_approvement(Els) ->
lists:foldl( lists:foldl(
fun(_, true) -> fun({xmlelement, "x", Attrs, _} = El, false) ->
true; case xml:get_attr_s("xmlns", Attrs) of
({xmlelement, "x", _, _} = X, false) -> ?NS_XDATA ->
is_voice_approvement(X); case jlib:parse_xdata_submit(El) of
(_, _) -> [_|_] = Fs ->
false case {lists:keysearch("FORM_TYPE", 1, Fs),
end, false, Els). lists:keysearch("muc#role", 1, Fs),
lists:keysearch("muc#request_allow", 1, Fs)} of
check_voice_approvement_fields(_, false) -> {["http://jabber.org/protocol/muc#request"],
false; ["participant"], [Flag]}
check_voice_approvement_fields({"FORM_TYPE", ["http://jabber.org/protocol/muc#request"]}, true) -> when Flag == "true"; Flag == "1" ->
true; true;
check_voice_approvement_fields({"FORM_TYPE", _}, _) -> _ ->
false; false
check_voice_approvement_fields({"muc#role", ["participant"]}, true) -> end;
true; _ ->
check_voice_approvement_fields({"muc#role", _}, _) -> false
false; end;
check_voice_approvement_fields({"muc#request_allow", ["true"]}, true) -> _ ->
true; false
check_voice_approvement_fields({"muc#request_allow", ["1"]}, true) -> end;
true; (_, Acc) ->
check_voice_approvement_fields({"muc#request_allow", _}, _) -> Acc
false; end, false, Els).
check_voice_approvement_fields(_, true) ->
true. % do not check any other fields
extract_jid_from_voice_approvement(Els) -> extract_jid_from_voice_approvement(Els) ->
lists:foldl( lists:foldl(
fun(X, Acc) -> fun({xmlelement, "x", _, _} = El, error) ->
case Acc of Fields = case jlib:parse_xdata_submit(El) of
{error, _} -> invalid -> [];
case X of Res -> Res
{xmlelement, "x", _, _} -> end,
Fields = jlib:parse_xdata_submit(X), lists:foldl(
Jid = lists:foldl( fun({"muc#jid", [JIDStr]}, error) ->
fun(T, Acc2) -> case jlib:string_to_jid(JIDStr) of
case Acc2 of error -> error;
{error, _} -> J -> {ok, J}
case T of end;
{"muc#jid", [Jid]} -> (_, Acc) ->
Jid; Acc
_ -> end, error, Fields);
Acc2 (_, Acc) ->
end; Acc
_ -> end, error, Els).
Acc2
end
end, {error, jid_not_found}, Fields),
jlib:string_to_jid(Jid);
_ ->
Acc
end;
_ ->
Acc
end
end, {error, jid_not_found}, Els).
last_voice_request_time(BareJID, StateData) -> last_voice_request_time(BareJID, StateData) ->
case treap:lookup(BareJID, StateData#state.last_voice_request_time) of case treap:lookup(BareJID, StateData#state.last_voice_request_time) of
{ok, _, Value} -> {ok, _, Value} ->
Value; Value;
error -> error ->
{0, 0, 0} {0, 0, 0}
end. end.
update_voice_request_time(BareJID, StateData) -> update_voice_request_time(BareJID, StateData) ->
NewDict = treap:insert(BareJID, {0, 0}, erlang:now(), StateData#state.last_voice_request_time), NewDict = treap:insert(BareJID, {0, 0}, erlang:now(),
StateData#state{last_voice_request_time = NewDict}. StateData#state.last_voice_request_time),
StateData#state{last_voice_request_time = NewDict}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Invitation support % Invitation support