Rewrite mod_mix to use XML generator

This commit is contained in:
Evgeniy Khramtsov 2016-07-31 08:51:47 +03:00
parent eb1d385d4e
commit 0bcbd12776
6 changed files with 383 additions and 475 deletions

View File

@ -15,6 +15,14 @@
'no-permanent-store' | 'no-permanent-storage'}).
-type hint() :: #hint{}.
-record(iq, {id :: binary(),
type :: 'error' | 'get' | 'result' | 'set',
lang :: binary(),
from :: any(),
to :: any(),
sub_els = [] :: [any()]}).
-type iq() :: #iq{}.
-record(feature_register, {}).
-type feature_register() :: #feature_register{}.
@ -170,6 +178,14 @@
-record(private, {xml_els = [] :: [any()]}).
-type private() :: #private{}.
-record(db_verify, {from :: any(),
to :: any(),
id :: binary(),
type :: 'error' | 'invalid' | 'valid',
key = <<>> :: binary(),
sub_els = [] :: [any()]}).
-type db_verify() :: #db_verify{}.
-record(nick, {name :: binary()}).
-type nick() :: #nick{}.
@ -267,6 +283,17 @@
jid :: any()}).
-type pubsub_subscribe() :: #pubsub_subscribe{}.
-record(message, {id :: binary(),
type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
lang :: binary(),
from :: any(),
to :: any(),
subject = [] :: [#text{}],
body = [] :: [#text{}],
thread :: binary(),
sub_els = [] :: [any()]}).
-type message() :: #message{}.
-record(sasl_auth, {mechanism :: binary(),
text :: any()}).
-type sasl_auth() :: #sasl_auth{}.
@ -349,6 +376,17 @@
items = [] :: [#pubsub_item{}]}).
-type pubsub_items() :: #pubsub_items{}.
-record(presence, {id :: binary(),
type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
lang :: binary(),
from :: any(),
to :: any(),
show :: 'away' | 'chat' | 'dnd' | 'xa',
status = [] :: [#text{}],
priority :: integer(),
sub_els = [] :: [any()]}).
-type presence() :: #presence{}.
-record(sic, {ip :: any(),
port :: non_neg_integer(),
xmlns :: binary()}).
@ -385,6 +423,13 @@
userid :: binary()}).
-type vcard_email() :: #vcard_email{}.
-record(db_result, {from :: any(),
to :: any(),
type :: 'error' | 'invalid' | 'valid',
key = <<>> :: binary(),
sub_els = [] :: [any()]}).
-type db_result() :: #db_result{}.
-record(carbons_received, {forwarded :: #forwarded{}}).
-type carbons_received() :: #carbons_received{}.
@ -729,57 +774,10 @@
code :: non_neg_integer(),
by :: binary(),
reason :: atom() | #gone{} | #redirect{},
text :: #text{}}).
text :: #text{},
sub_els = [] :: [any()]}).
-type error() :: #error{}.
-record(db_verify, {from :: any(),
to :: any(),
id :: binary(),
type :: 'error' | 'invalid' | 'valid',
key = <<>> :: binary(),
error :: #error{}}).
-type db_verify() :: #db_verify{}.
-record(db_result, {from :: any(),
to :: any(),
type :: 'error' | 'invalid' | 'valid',
key = <<>> :: binary(),
error :: #error{}}).
-type db_result() :: #db_result{}.
-record(presence, {id :: binary(),
type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
lang :: binary(),
from :: any(),
to :: any(),
show :: 'away' | 'chat' | 'dnd' | 'xa',
status = [] :: [#text{}],
priority :: integer(),
error :: #error{},
sub_els = [] :: [any()]}).
-type presence() :: #presence{}.
-record(message, {id :: binary(),
type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
lang :: binary(),
from :: any(),
to :: any(),
subject = [] :: [#text{}],
body = [] :: [#text{}],
thread :: binary(),
error :: #error{},
sub_els = [] :: [any()]}).
-type message() :: #message{}.
-record(iq, {id :: binary(),
type :: 'error' | 'get' | 'result' | 'set',
lang :: binary(),
from :: any(),
to :: any(),
error :: #error{},
sub_els = [] :: [any()]}).
-type iq() :: #iq{}.
-record(mix_join, {jid :: any(),
subscribe = [] :: [binary()]}).
-type mix_join() :: #mix_join{}.
@ -861,6 +859,7 @@
mam_archived() |
p1_rebind() |
sasl_abort() |
db_result() |
carbons_received() |
pubsub_retract() |
upload_slot() |
@ -868,7 +867,6 @@
compressed() |
block_list() |
rsm_set() |
db_result() |
'see-other-host'() |
hint() |
stream_start() |
@ -939,8 +937,8 @@
mix_join() |
xmpp_session() |
xdata() |
xcaptcha() |
iq() |
xcaptcha() |
streamhost() |
bind() |
last() |
@ -971,9 +969,9 @@
muc_destroy() |
vcard_key() |
csi() |
db_verify() |
roster_query() |
mam_query() |
db_verify() |
bookmark_url() |
vcard_email() |
vcard_label() |
@ -992,8 +990,8 @@
muc_unique() |
sasl_response() |
pubsub_subscribe() |
presence() |
message() |
presence() |
gone() |
sm_resume() |
carbons_enable() |

View File

@ -12,7 +12,7 @@
-behaviour(gen_mod).
%% API
-export([start_link/2, start/2, stop/1, process_iq/3,
-export([start_link/2, start/2, stop/1, process_iq/1,
disco_items/5, disco_identity/5, disco_info/5,
disco_features/5, mod_opt_type/1, depends/2]).
@ -21,8 +21,7 @@
terminate/2, code_change/3]).
-include("logger.hrl").
-include("jlib.hrl").
-include("pubsub.hrl").
-include("xmpp.hrl").
-define(PROCNAME, ejabberd_mod_mix).
-define(NODES, [?NS_MIX_NODES_MESSAGES,
@ -57,84 +56,59 @@ disco_features(_Acc, _From, _To, _Node, _Lang) ->
{result, [?NS_MIX_0]}.
disco_items(_Acc, _From, To, _Node, _Lang) when To#jid.luser /= <<"">> ->
To_s = jid:to_string(jid:remove_resource(To)),
{result, [#xmlel{name = <<"item">>,
attrs = [{<<"jid">>, To_s},
{<<"node">>, Node}]} || Node <- ?NODES]};
BareTo = jid:remove_resource(To),
{result, [#disco_item{jid = BareTo, node = Node} || Node <- ?NODES]};
disco_items(_Acc, _From, _To, _Node, _Lang) ->
{result, []}.
disco_identity(Acc, _From, To, _Node, _Lang) when To#jid.luser == <<"">> ->
Acc ++ [#xmlel{name = <<"identity">>,
attrs =
[{<<"category">>, <<"conference">>},
{<<"name">>, <<"MIX service">>},
{<<"type">>, <<"text">>}]}];
Acc ++ [#identity{category = <<"conference">>,
name = <<"MIX service">>,
type = <<"text">>}];
disco_identity(Acc, _From, _To, _Node, _Lang) ->
Acc ++ [#xmlel{name = <<"identity">>,
attrs =
[{<<"category">>, <<"conference">>},
{<<"type">>, <<"mix">>}]}].
Acc ++ [#identity{category = <<"conference">>,
type = <<"mix">>}].
disco_info(_Acc, _From, To, _Node, _Lang) when is_atom(To) ->
[#xmlel{name = <<"x">>,
attrs = [{<<"xmlns">>, ?NS_XDATA},
{<<"type">>, <<"result">>}],
children = [#xmlel{name = <<"field">>,
attrs = [{<<"var">>, <<"FORM_TYPE">>},
{<<"type">>, <<"hidden">>}],
children = [#xmlel{name = <<"value">>,
children = [{xmlcdata,
?NS_MIX_SERVICEINFO_0}]}]}]}];
[#xdata{type = result,
fields = [#xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values = [?NS_MIX_SERVICEINFO_0]}]}];
disco_info(Acc, _From, _To, _Node, _Lang) ->
Acc.
process_iq(From, To,
#iq{type = set, sub_el = #xmlel{name = <<"join">>} = SubEl} = IQ) ->
Nodes = lists:flatmap(
fun(#xmlel{name = <<"subscribe">>, attrs = Attrs}) ->
Node = fxml:get_attr_s(<<"node">>, Attrs),
case lists:member(Node, ?NODES) of
true -> [Node];
false -> []
end;
(_) ->
[]
end, SubEl#xmlel.children),
process_iq(#iq{type = set, from = From, to = To,
sub_els = [#mix_join{subscribe = SubNodes}]} = IQ) ->
Nodes = [Node || Node <- SubNodes, lists:member(Node, ?NODES)],
case subscribe_nodes(From, To, Nodes) of
{result, _} ->
case publish_participant(From, To) of
{result, _} ->
LFrom_s = jid:to_string(jid:tolower(jid:remove_resource(From))),
Subscribe = [#xmlel{name = <<"subscribe">>,
attrs = [{<<"node">>, Node}]} || Node <- Nodes],
IQ#iq{type = result,
sub_el = [#xmlel{name = <<"join">>,
attrs = [{<<"jid">>, LFrom_s},
{<<"xmlns">>, ?NS_MIX_0}],
children = Subscribe}]};
BareFrom = jid:remove_resource(From),
xmpp:make_iq_result(
IQ, #mix_join{jid = BareFrom, subscribe = Nodes});
{error, Err} ->
IQ#iq{type = error, sub_el = [SubEl, Err]}
xmpp:make_error(IQ, Err)
end;
{error, Err} ->
IQ#iq{type = error, sub_el = [SubEl, Err]}
xmpp:make_error(IQ, Err)
end;
process_iq(From, To,
#iq{type = set, sub_el = #xmlel{name = <<"leave">>} = SubEl} = IQ) ->
process_iq(#iq{type = set, from = From, to = To,
sub_els = [#mix_leave{}]} = IQ) ->
case delete_participant(From, To) of
{result, _} ->
case unsubscribe_nodes(From, To, ?NODES) of
{result, _} ->
IQ#iq{type = result, sub_el = []};
xmpp:make_iq_result(IQ);
{error, Err} ->
IQ#iq{type = error, sub_el = [SubEl, Err]}
xmpp:make_error(IQ, Err)
end;
{error, Err} ->
IQ#iq{type = error, sub_el = [SubEl, Err]}
xmpp:make_error(IQ, Err)
end;
process_iq(_From, _To, #iq{sub_el = SubEl, lang = Lang} = IQ) ->
process_iq(#iq{lang = Lang} = IQ) ->
Txt = <<"Unsupported MIX query">>,
IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]}.
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)).
%%%===================================================================
%%% gen_server callbacks
@ -185,8 +159,8 @@ handle_info({route, From, To, Packet}, State) ->
try
?ERROR_MSG("failed to route packet ~p from '~s' to '~s': ~p",
[Packet, jid:to_string(From), jid:to_string(To), Err]),
ErrPkt = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR),
ejabberd_router:route_error(To, From, ErrPkt, Packet)
Error = xmpp:err_internal_server_error(),
ejabberd_router:route_error(To, From, Packet, Error)
catch _:_ ->
ok
end;
@ -220,20 +194,11 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
do_route(_State, From, To, #xmlel{name = <<"iq">>} = Packet) ->
if To#jid.luser == <<"">> ->
ejabberd_local:process_iq(From, To, Packet);
true ->
ejabberd_sm:process_iq(From, To, Packet)
end;
do_route(_State, From, To, #xmlel{name = <<"presence">>} = Packet)
do_route(_State, From, To, #iq{} = Packet) ->
ejabberd_router:process_iq(From, To, Packet);
do_route(_State, From, To, #presence{type = unavailable})
when To#jid.luser /= <<"">> ->
case fxml:get_tag_attr_s(<<"type">>, Packet) of
<<"unavailable">> ->
delete_presence(From, To);
_ ->
ok
end;
delete_presence(From, To);
do_route(_State, _From, _To, _Packet) ->
ok.
@ -284,15 +249,14 @@ unsubscribe_nodes(From, To, Nodes) ->
end, {result, []}, Nodes).
publish_participant(From, To) ->
LFrom = jid:tolower(jid:remove_resource(From)),
BareFrom = jid:remove_resource(From),
LFrom = jid:tolower(BareFrom),
LTo = jid:tolower(jid:remove_resource(To)),
Participant = #xmlel{name = <<"participant">>,
attrs = [{<<"xmlns">>, ?NS_MIX_0},
{<<"jid">>, jid:to_string(LFrom)}]},
Participant = #mix_participant{jid = BareFrom},
ItemID = p1_sha:sha(jid:to_string(LFrom)),
mod_pubsub:publish_item(
LTo, To#jid.lserver, ?NS_MIX_NODES_PARTICIPANTS,
From, ItemID, [Participant]).
From, ItemID, [xmpp:encode(Participant)]).
delete_presence(From, To) ->
LFrom = jid:tolower(From),
@ -300,8 +264,8 @@ delete_presence(From, To) ->
case mod_pubsub:get_items(LTo, ?NS_MIX_NODES_PRESENCE) of
Items when is_list(Items) ->
lists:foreach(
fun(#pubsub_item{modification = {_, LJID},
itemid = {ItemID, _}}) when LJID == LFrom ->
fun({pubsub_item, {ItemID, _}, _, {_, LJID}, _})
when LJID == LFrom ->
delete_item(From, To, ?NS_MIX_NODES_PRESENCE, ItemID);
(_) ->
ok

View File

@ -1110,8 +1110,9 @@ change_stanzaid(ToJID, #iq{id = PreviousId} = Packet) ->
-spec decide_fate_message(message(), jid(), state()) ->
continue_delivery | forget_message |
{expulse_sender, binary()}.
decide_fate_message(#message{type = error, error = Err},
decide_fate_message(#message{type = error} = Msg,
From, StateData) ->
Err = xmpp:get_error(Msg),
PD = case check_error_kick(Err) of
%% If this is an error stanza and its condition matches a criteria
true ->

View File

@ -88,10 +88,10 @@ make_iq_result(#iq{type = Type, from = From, to = To} = IQ, El)
end,
IQ#iq{type = result, to = From, from = To, sub_els = SubEls}.
-spec make_error(message(), error()) -> message();
(presence(), error()) -> presence();
(iq(), error()) -> iq();
(xmlel(), error()) -> xmlel().
-spec make_error(message(), error() | xmlel()) -> message();
(presence(), error() | xmlel()) -> presence();
(iq(), error() | xmlel()) -> iq();
(xmlel(), error() | xmlel()) -> xmlel().
make_error(#message{type = Type, from = From, to = To, sub_els = Els} = Msg,
Err) when Type /= error ->
Msg#message{type = error, from = To, to = From, sub_els = Els ++ [Err]};
@ -159,9 +159,11 @@ get_to(#message{to = J}) -> J;
get_to(#presence{to = J}) -> J.
-spec get_error(iq() | message() | presence()) -> undefined | error().
get_error(#iq{error = E}) -> E;
get_error(#message{error = E}) -> E;
get_error(#presence{error = E}) -> E.
get_error(Stanza) ->
case get_subtag(Stanza, #error{}) of
false -> undefined;
Error -> Error
end.
-spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()];
(xmlel()) -> [xmlel()].
@ -215,9 +217,7 @@ set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}.
-spec set_error(iq(), error()) -> iq();
(message(), error()) -> message();
(presence(), error()) -> presence().
set_error(#iq{} = IQ, E) -> IQ#iq{error = E};
set_error(#message{} = Msg, E) -> Msg#message{error = E};
set_error(#presence{} = Pres, E) -> Pres#presence{error = E}.
set_error(Stanza, E) -> set_subtag(Stanza, E).
-spec set_els(iq(), [xmpp_element() | xmlel()]) -> iq();
(message(), [xmpp_element() | xmlel()]) -> message();

File diff suppressed because it is too large Load Diff

View File

@ -316,8 +316,7 @@
-xml(iq,
#elem{name = <<"iq">>,
xmlns = <<"jabber:client">>,
result = {iq, '$id', '$type', '$lang', '$from', '$to',
'$error', '$_els'},
result = {iq, '$id', '$type', '$lang', '$from', '$to', '$_els'},
attrs = [#attr{name = <<"id">>,
required = true},
#attr{name = <<"type">>,
@ -331,8 +330,7 @@
dec = {dec_jid, []},
enc = {enc_jid, []}},
#attr{name = <<"xml:lang">>,
label = '$lang'}],
refs = [#ref{name = error, min = 0, max = 1, label = '$error'}]}).
label = '$lang'}]}).
-xml(message_subject,
#elem{name = <<"subject">>,
@ -357,7 +355,7 @@
#elem{name = <<"message">>,
xmlns = <<"jabber:client">>,
result = {message, '$id', '$type', '$lang', '$from', '$to',
'$subject', '$body', '$thread', '$error', '$_els'},
'$subject', '$body', '$thread', '$_els'},
attrs = [#attr{name = <<"id">>},
#attr{name = <<"type">>,
default = normal,
@ -372,8 +370,7 @@
enc = {enc_jid, []}},
#attr{name = <<"xml:lang">>,
label = '$lang'}],
refs = [#ref{name = error, min = 0, max = 1, label = '$error'},
#ref{name = message_subject, label = '$subject'},
refs = [#ref{name = message_subject, label = '$subject'},
#ref{name = message_thread, min = 0, max = 1, label = '$thread'},
#ref{name = message_body, label = '$body'}]}).
@ -403,7 +400,7 @@
#elem{name = <<"presence">>,
xmlns = <<"jabber:client">>,
result = {presence, '$id', '$type', '$lang', '$from', '$to',
'$show', '$status', '$priority', '$error', '$_els'},
'$show', '$status', '$priority', '$_els'},
attrs = [#attr{name = <<"id">>},
#attr{name = <<"type">>,
default = available,
@ -419,8 +416,7 @@
enc = {enc_jid, []}},
#attr{name = <<"xml:lang">>,
label = '$lang'}],
refs = [#ref{name = error, min = 0, max = 1, label = '$error'},
#ref{name = presence_show, min = 0, max = 1, label = '$show'},
refs = [#ref{name = presence_show, min = 0, max = 1, label = '$show'},
#ref{name = presence_status, label = '$status'},
#ref{name = presence_priority, min = 0, max = 1,
label = '$priority'}]}).
@ -531,7 +527,7 @@
-xml(error,
#elem{name = <<"error">>,
xmlns = <<"jabber:client">>,
result = {error, '$type', '$code', '$by', '$reason', '$text'},
result = {error, '$type', '$code', '$by', '$reason', '$text', '$_els'},
attrs = [#attr{name = <<"type">>,
label = '$type',
required = true,
@ -2880,8 +2876,7 @@
-xml(db_result,
#elem{name = <<"db:result">>,
xmlns = <<"jabber:client">>,
result = {db_result, '$from', '$to', '$type', '$key', '$error'},
refs = [#ref{name = error, min = 0, max = 1}],
result = {db_result, '$from', '$to', '$type', '$key', '$_els'},
cdata = #cdata{default = <<"">>, label = '$key'},
attrs = [#attr{name = <<"from">>, required = true,
dec = {dec_jid, []}, enc = {enc_jid, []}},
@ -2894,8 +2889,7 @@
-xml(db_verify,
#elem{name = <<"db:verify">>,
xmlns = <<"jabber:client">>,
result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$error'},
refs = [#ref{name = error, min = 0, max = 1}],
result = {db_verify, '$from', '$to', '$id', '$type', '$key', '$_els'},
cdata = #cdata{default = <<"">>, label = '$key'},
attrs = [#attr{name = <<"from">>, required = true,
dec = {dec_jid, []}, enc = {enc_jid, []}},