mirror of
https://github.com/processone/ejabberd
synced 2025-10-03 09:49:18 +02:00
mod_pubsub_serverinfo: initial import as found on ejabberd-contrib
This commit is contained in:
parent
6b47d3eb0d
commit
740b0c7dd7
5 changed files with 1127 additions and 0 deletions
17
include/pubsub_serverinfo_codec.hrl
Normal file
17
include/pubsub_serverinfo_codec.hrl
Normal file
|
@ -0,0 +1,17 @@
|
|||
%% Created automatically by XML generator (fxml_gen.erl)
|
||||
%% Source: pubsub_serverinfo_codec.spec
|
||||
|
||||
-record(pubsub_serverinfo_remote_domain, {name = <<>> :: binary(),
|
||||
type = [] :: ['bidi' | 'incoming' | 'outgoing']}).
|
||||
-type pubsub_serverinfo_remote_domain() :: #pubsub_serverinfo_remote_domain{}.
|
||||
|
||||
-record(pubsub_serverinfo_domain, {name = <<>> :: binary(),
|
||||
remote_domain :: 'undefined' | [#pubsub_serverinfo_remote_domain{}]}).
|
||||
-type pubsub_serverinfo_domain() :: #pubsub_serverinfo_domain{}.
|
||||
|
||||
-record(pubsub_serverinfo, {domain = [] :: [#pubsub_serverinfo_domain{}]}).
|
||||
-type pubsub_serverinfo() :: #pubsub_serverinfo{}.
|
||||
|
||||
-type pubsub_serverinfo_codec() :: pubsub_serverinfo() |
|
||||
pubsub_serverinfo_domain() |
|
||||
pubsub_serverinfo_remote_domain().
|
52
specs/pubsub_serverinfo_codec.spec
Normal file
52
specs/pubsub_serverinfo_codec.spec
Normal file
|
@ -0,0 +1,52 @@
|
|||
-xml(pubsub_serverinfo,
|
||||
#elem{name = <<"serverinfo">>,
|
||||
xmlns = <<"urn:xmpp:serverinfo:0">>,
|
||||
module = pubsub_serverinfo_codec,
|
||||
result = {pubsub_serverinfo, '$domain'},
|
||||
refs = [#ref{name = pubsub_serverinfo_domain,
|
||||
label = '$domain',
|
||||
min = 0}]}).
|
||||
|
||||
-xml(pubsub_serverinfo_domain,
|
||||
#elem{name = <<"domain">>,
|
||||
xmlns = <<"urn:xmpp:serverinfo:0">>,
|
||||
module = pubsub_serverinfo_codec,
|
||||
result = {pubsub_serverinfo_domain, '$name', '$remote_domain'},
|
||||
attrs = [#attr{name = <<"name">>,
|
||||
label = '$name',
|
||||
required = true}],
|
||||
refs = [#ref{name = pubsub_serverinfo_federation,
|
||||
label = '$remote_domain',
|
||||
min = 0, max = 1}]}).
|
||||
|
||||
-xml(pubsub_serverinfo_federation,
|
||||
#elem{name = <<"federation">>,
|
||||
xmlns = <<"urn:xmpp:serverinfo:0">>,
|
||||
module = pubsub_serverinfo_codec,
|
||||
result = '$remote_domain',
|
||||
refs = [#ref{name = pubsub_serverinfo_remote_domain,
|
||||
label = '$remote_domain',
|
||||
min = 0}]}).
|
||||
|
||||
-xml(pubsub_serverinfo_remote_domain,
|
||||
#elem{name = <<"remote-domain">>,
|
||||
xmlns = <<"urn:xmpp:serverinfo:0">>,
|
||||
module = pubsub_serverinfo_codec,
|
||||
result = {pubsub_serverinfo_remote_domain, '$name', '$type'},
|
||||
attrs = [#attr{name = <<"name">>,
|
||||
label = '$name',
|
||||
required = true}],
|
||||
refs = [#ref{name = pubsub_serverinfo_connection,
|
||||
label = '$type',
|
||||
min = 0}]}).
|
||||
|
||||
-xml(pubsub_serverinfo_connection,
|
||||
#elem{name = <<"connection">>,
|
||||
xmlns = <<"urn:xmpp:serverinfo:0">>,
|
||||
module = pubsub_serverinfo_codec,
|
||||
result = '$type',
|
||||
attrs = [#attr{name = <<"type">>,
|
||||
label = '$type',
|
||||
required = true,
|
||||
enc = {enc_enum, []},
|
||||
dec = {dec_enum, [[incoming, outgoing, bidi]]}}]}).
|
312
src/mod_pubsub_serverinfo.erl
Normal file
312
src/mod_pubsub_serverinfo.erl
Normal file
|
@ -0,0 +1,312 @@
|
|||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_pubsub_serverinfo.erl
|
||||
%%% Author : Stefan Strigler <stefan@strigler.de>
|
||||
%%% Purpose : Exposes server information over Pub/Sub
|
||||
%%% Created : 26 Dec 2023 by Guus der Kinderen <guus.der.kinderen@gmail.com>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2023 - 2025 ProcessOne
|
||||
%%%
|
||||
%%% This program is free software; you can redistribute it and/or
|
||||
%%% modify it under the terms of the GNU General Public License as
|
||||
%%% published by the Free Software Foundation; either version 2 of the
|
||||
%%% License, or (at your option) any later version.
|
||||
%%%
|
||||
%%% This program is distributed in the hope that it will be useful,
|
||||
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
%%% General Public License for more details.
|
||||
%%%
|
||||
%%% You should have received a copy of the GNU General Public License along
|
||||
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(mod_pubsub_serverinfo).
|
||||
-author('stefan@strigler.de').
|
||||
-behaviour(gen_mod).
|
||||
-behaviour(gen_server).
|
||||
|
||||
-include("pubsub_serverinfo_codec.hrl").
|
||||
-include("logger.hrl").
|
||||
-include_lib("xmpp/include/xmpp.hrl").
|
||||
|
||||
%% gen_mod callbacks.
|
||||
-export([start/2, stop/1, depends/2, mod_options/1, mod_opt_type/1, get_local_features/5, mod_doc/0]).
|
||||
-export([init/1, handle_cast/2, handle_call/3, handle_info/2, terminate/2]).
|
||||
-export([in_auth_result/3, out_auth_result/2, get_info/5]).
|
||||
|
||||
-define(NS_URN_SERVERINFO, <<"urn:xmpp:serverinfo:0">>).
|
||||
-define(PUBLIC_HOSTS_URL, <<"https://data.xmpp.net/providers/v2/providers-Ds.json">>).
|
||||
|
||||
-record(state, {host, pubsub_host, node, monitors = #{}, timer = undefined, public_hosts = []}).
|
||||
|
||||
start(Host, Opts) ->
|
||||
case pubsub_host(Host, Opts) of
|
||||
{error, _Reason} = Error ->
|
||||
Error;
|
||||
PubsubHost ->
|
||||
xmpp:register_codec(pubsub_serverinfo_codec),
|
||||
ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 50),
|
||||
ejabberd_hooks:add(disco_info, Host, ?MODULE, get_info, 50),
|
||||
ejabberd_hooks:add(s2s_out_auth_result, Host, ?MODULE, out_auth_result, 50),
|
||||
ejabberd_hooks:add(s2s_in_auth_result, Host, ?MODULE, in_auth_result, 50),
|
||||
gen_mod:start_child(?MODULE, Host, PubsubHost)
|
||||
end.
|
||||
|
||||
stop(Host) ->
|
||||
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 50),
|
||||
ejabberd_hooks:delete(disco_info, Host, ?MODULE, get_info, 50),
|
||||
ejabberd_hooks:delete(s2s_out_auth_result, Host, ?MODULE, out_auth_result, 50),
|
||||
ejabberd_hooks:delete(s2s_in_auth_result, Host, ?MODULE, in_auth_result, 50),
|
||||
gen_mod:stop_child(?MODULE, Host).
|
||||
|
||||
init([Host, PubsubHost]) ->
|
||||
TRef = timer:send_interval(timer:minutes(5), self(), update_pubsub),
|
||||
Monitors = init_monitors(Host),
|
||||
PublicHosts = fetch_public_hosts(),
|
||||
State = #state{host = Host,
|
||||
pubsub_host = PubsubHost,
|
||||
node = <<"serverinfo">>,
|
||||
timer = TRef,
|
||||
monitors = Monitors,
|
||||
public_hosts = PublicHosts},
|
||||
self() ! update_pubsub,
|
||||
{ok, State}.
|
||||
|
||||
-spec init_monitors(binary()) -> map().
|
||||
init_monitors(Host) ->
|
||||
lists:foldl(
|
||||
fun(Domain, Monitors) ->
|
||||
RefIn = make_ref(), % just dummies
|
||||
RefOut = make_ref(),
|
||||
maps:merge(#{RefIn => {incoming, {Host, Domain, true}},
|
||||
RefOut => {outgoing, {Host, Domain, true}}},
|
||||
Monitors)
|
||||
end,
|
||||
#{},
|
||||
ejabberd_option:hosts() -- [Host]).
|
||||
|
||||
-spec fetch_public_hosts() -> list().
|
||||
fetch_public_hosts() ->
|
||||
try
|
||||
{ok, {{_, 200, _}, _Headers, Body}} = httpc:request(get, {?PUBLIC_HOSTS_URL, []}, [{timeout, 1000}], [{body_format, binary}]),
|
||||
case misc:json_decode(Body) of
|
||||
PublicHosts when is_list(PublicHosts) -> PublicHosts;
|
||||
Other ->
|
||||
?WARNING_MSG("Parsed JSON for public hosts was not a list: ~p", [Other]),
|
||||
[]
|
||||
end
|
||||
catch E:R ->
|
||||
?WARNING_MSG("Failed fetching public hosts (~p): ~p", [E, R]),
|
||||
[]
|
||||
end.
|
||||
|
||||
handle_cast({Event, Domain, Pid}, #state{host = Host, monitors = Mons} = State)
|
||||
when Event == register_in; Event == register_out ->
|
||||
Ref = monitor(process, Pid),
|
||||
IsPublic = check_if_public(Domain, State),
|
||||
NewMons = maps:put(Ref, {event_to_dir(Event), {Host, Domain, IsPublic}}, Mons),
|
||||
{noreply, State#state{monitors = NewMons}};
|
||||
handle_cast(_, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
event_to_dir(register_in) -> incoming;
|
||||
event_to_dir(register_out) -> outgoing.
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({iq_reply, IQReply, {LServer, RServer}},
|
||||
#state{monitors = Mons} = State) ->
|
||||
case IQReply of
|
||||
#iq{type = result, sub_els = [El]} ->
|
||||
case xmpp:decode(El) of
|
||||
#disco_info{features = Features} ->
|
||||
case lists:member(?NS_URN_SERVERINFO, Features) of
|
||||
true ->
|
||||
NewMons = maps:fold(fun(Ref, {Dir, {LServer0, RServer0, _}}, Acc)
|
||||
when LServer == LServer0, RServer == RServer0 ->
|
||||
maps:put(Ref, {Dir, {LServer, RServer, true}}, Acc);
|
||||
(Ref, Other, Acc) ->
|
||||
maps:put(Ref, Other, Acc)
|
||||
end,
|
||||
#{},
|
||||
Mons),
|
||||
{noreply, State#state{monitors = NewMons}};
|
||||
_ ->
|
||||
{noreply, State}
|
||||
end;
|
||||
_ ->
|
||||
{noreply, State}
|
||||
end;
|
||||
_ ->
|
||||
{noreply, State}
|
||||
end;
|
||||
handle_info(update_pubsub, State) ->
|
||||
update_pubsub(State),
|
||||
{noreply, State};
|
||||
handle_info({'DOWN', Mon, process, _Pid, _Info}, #state{monitors = Mons} = State) ->
|
||||
{noreply, State#state{monitors = maps:remove(Mon, Mons)}};
|
||||
handle_info(_Request, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, #state{monitors = Mons, timer = Timer}) ->
|
||||
case is_reference(Timer) of
|
||||
true ->
|
||||
case erlang:cancel_timer(Timer) of
|
||||
false ->
|
||||
receive {timeout, Timer, _} -> ok
|
||||
after 0 -> ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
maps:fold(
|
||||
fun(Mon, _, _) ->
|
||||
demonitor(Mon)
|
||||
end, ok, Mons).
|
||||
|
||||
depends(_Host, _Opts) ->
|
||||
[{mod_pubsub, hard}].
|
||||
|
||||
mod_options(_Host) ->
|
||||
[{pubsub_host, undefined}].
|
||||
|
||||
mod_opt_type(pubsub_host) ->
|
||||
econf:either(undefined, econf:host()).
|
||||
|
||||
mod_doc() -> #{}.
|
||||
|
||||
in_auth_result(#{server_host := Host, remote_server := RServer} = State, true, _Server) ->
|
||||
gen_server:cast(gen_mod:get_module_proc(Host, ?MODULE), {register_in, RServer, self()}),
|
||||
State;
|
||||
in_auth_result(State, _, _) ->
|
||||
State.
|
||||
|
||||
out_auth_result(#{server_host := Host, remote_server := RServer} = State, true) ->
|
||||
gen_server:cast(gen_mod:get_module_proc(Host, ?MODULE), {register_out, RServer, self()}),
|
||||
State;
|
||||
out_auth_result(State, _) ->
|
||||
State.
|
||||
|
||||
check_if_public(Domain, State) ->
|
||||
maybe_send_disco_info(is_public(Domain, State) orelse is_monitored(Domain, State), Domain, State).
|
||||
|
||||
is_public(Domain, #state{public_hosts = PublicHosts}) ->
|
||||
lists:member(Domain, PublicHosts).
|
||||
|
||||
is_monitored(Domain, #state{host = Host, monitors = Mons}) ->
|
||||
maps:size(
|
||||
maps:filter(
|
||||
fun(_Ref, {_Dir, {LServer, RServer, IsPublic}})
|
||||
when LServer == Host, RServer == Domain -> IsPublic;
|
||||
(_Ref, _Other) -> false
|
||||
end,
|
||||
Mons)) =/= 0.
|
||||
|
||||
maybe_send_disco_info(true, _Domain, _State) -> true;
|
||||
maybe_send_disco_info(false, Domain, #state{host = Host}) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?MODULE),
|
||||
IQ = #iq{type = get, from = jid:make(Host),
|
||||
to = jid:make(Domain), sub_els = [#disco_info{}]},
|
||||
ejabberd_router:route_iq(IQ, {Host, Domain}, Proc),
|
||||
false.
|
||||
|
||||
update_pubsub(#state{host = Host, pubsub_host = PubsubHost, node = Node, monitors = Mons}) ->
|
||||
Map = maps:fold(
|
||||
fun(_, {Dir, {MyDomain, Target, IsPublic}}, Acc) ->
|
||||
maps:update_with(MyDomain,
|
||||
fun(Acc2) ->
|
||||
maps:update_with(Target,
|
||||
fun({Types, _}) -> {Types#{Dir => true}, IsPublic} end,
|
||||
{#{Dir => true}, IsPublic}, Acc2)
|
||||
end, #{Target => {#{Dir => true}, IsPublic}}, Acc)
|
||||
end, #{}, Mons),
|
||||
Domains = maps:fold(
|
||||
fun(MyDomain, Targets, Acc) ->
|
||||
Remote = maps:fold(
|
||||
fun(Remote, {Types, true}, Acc2) ->
|
||||
[#pubsub_serverinfo_remote_domain{name = Remote, type = maps:keys(Types)} | Acc2];
|
||||
(_HiddenRemote, {Types, false}, Acc2) ->
|
||||
[#pubsub_serverinfo_remote_domain{type = maps:keys(Types)} | Acc2]
|
||||
end, [], Targets),
|
||||
[#pubsub_serverinfo_domain{name = MyDomain, remote_domain = Remote} | Acc]
|
||||
end, [], Map),
|
||||
|
||||
PubOpts = [{persist_items, true}, {max_items, 1}, {access_model, open}],
|
||||
?DEBUG("Publishing serverinfo pubsub item on ~s: ~p", [PubsubHost, Domains]),
|
||||
mod_pubsub:publish_item(
|
||||
PubsubHost, Host, Node, jid:make(Host),
|
||||
<<"current">>, [xmpp:encode(#pubsub_serverinfo{domain = Domains})], PubOpts, all).
|
||||
|
||||
get_local_features({error, _} = Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc;
|
||||
get_local_features(Acc, _From, _To, Node, _Lang) when Node == <<>> ->
|
||||
case Acc of
|
||||
{result, Features} ->
|
||||
{result, [?NS_URN_SERVERINFO | Features]};
|
||||
empty -> {result, [?NS_URN_SERVERINFO]}
|
||||
end;
|
||||
get_local_features(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
get_info(Acc, Host, Mod, Node, Lang) when (Mod == undefined orelse Mod == mod_disco), Node == <<"">> ->
|
||||
case mod_disco:get_info(Acc, Host, Mod, Node, Lang) of
|
||||
[#xdata{fields = Fields} = XD | Rest] ->
|
||||
PubsubHost = pubsub_host(Host),
|
||||
NodeField = #xdata_field{var = <<"serverinfo-pubsub-node">>,
|
||||
values = [<<"xmpp:", PubsubHost/binary, "?;node=serverinfo">>]},
|
||||
{stop, [XD#xdata{fields = Fields ++ [NodeField]} | Rest]};
|
||||
_ ->
|
||||
Acc
|
||||
end;
|
||||
get_info(Acc, Host, Mod, Node, _Lang) when Node == <<"">>, is_atom(Mod) ->
|
||||
PubsubHost = pubsub_host(Host),
|
||||
[#xdata{type = result,
|
||||
fields = [
|
||||
#xdata_field{type = hidden,
|
||||
var = <<"FORM_TYPE">>,
|
||||
values = [?NS_SERVERINFO]},
|
||||
#xdata_field{var = <<"serverinfo-pubsub-node">>,
|
||||
values = [<<"xmpp:", PubsubHost/binary, "?;node=serverinfo">>]}]} | Acc];
|
||||
get_info(Acc, _Host, _Mod, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
pubsub_host(Host) ->
|
||||
case pubsub_host(Host, gen_mod:get_module_opts(Host, ?MODULE)) of
|
||||
{error, _Reason} = Error ->
|
||||
throw(Error);
|
||||
PubsubHost ->
|
||||
PubsubHost
|
||||
end.
|
||||
|
||||
pubsub_host(Host, Opts) ->
|
||||
case gen_mod:get_opt(pubsub_host, Opts) of
|
||||
undefined ->
|
||||
PubsubHost = hd(get_mod_pubsub_hosts(Host)),
|
||||
?INFO_MSG("No pubsub_host in configuration for ~p, choosing ~s", [?MODULE, PubsubHost]),
|
||||
PubsubHost;
|
||||
PubsubHost ->
|
||||
case check_pubsub_host_exists(Host, PubsubHost) of
|
||||
true ->
|
||||
PubsubHost;
|
||||
false ->
|
||||
{error, {pubsub_host_does_not_exist, PubsubHost}}
|
||||
end
|
||||
end.
|
||||
|
||||
check_pubsub_host_exists(Host, PubsubHost) ->
|
||||
lists:member(PubsubHost, get_mod_pubsub_hosts(Host)).
|
||||
|
||||
get_mod_pubsub_hosts(Host) ->
|
||||
case gen_mod:get_module_opt(Host, mod_pubsub, hosts) of
|
||||
[] ->
|
||||
[gen_mod:get_module_opt(Host, mod_pubsub, host)];
|
||||
PubsubHosts ->
|
||||
PubsubHosts
|
||||
end.
|
734
src/pubsub_serverinfo_codec.erl
Normal file
734
src/pubsub_serverinfo_codec.erl
Normal file
|
@ -0,0 +1,734 @@
|
|||
%% Created automatically by XML generator (fxml_gen.erl)
|
||||
%% Source: pubsub_serverinfo_codec.spec
|
||||
|
||||
-module(pubsub_serverinfo_codec).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
decode(El) -> decode(El, <<>>, []).
|
||||
|
||||
decode(El, Opts) -> decode(El, <<>>, Opts).
|
||||
|
||||
decode({xmlel, Name, Attrs, _} = El, TopXMLNS, Opts) ->
|
||||
XMLNS = get_attr(<<"xmlns">>, Attrs, TopXMLNS),
|
||||
case get_mod(Name, XMLNS) of
|
||||
undefined when XMLNS == <<>> ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{missing_tag_xmlns, Name}});
|
||||
undefined ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{unknown_tag, Name, XMLNS}});
|
||||
Mod -> Mod:do_decode(Name, XMLNS, El, Opts)
|
||||
end.
|
||||
|
||||
encode(El) -> encode(El, <<>>).
|
||||
|
||||
encode({xmlel, _, _, _} = El, _) -> El;
|
||||
encode({xmlcdata, _} = CData, _) -> CData;
|
||||
encode(El, TopXMLNS) ->
|
||||
Mod = get_mod(El),
|
||||
Mod:do_encode(El, TopXMLNS).
|
||||
|
||||
|
||||
get_name(El) ->
|
||||
Mod = get_mod(El),
|
||||
Mod:do_get_name(El).
|
||||
|
||||
get_ns(El) ->
|
||||
Mod = get_mod(El),
|
||||
Mod:do_get_ns(El).
|
||||
|
||||
is_known_tag({xmlel, Name, Attrs, _}, TopXMLNS) ->
|
||||
XMLNS = get_attr(<<"xmlns">>, Attrs, TopXMLNS),
|
||||
get_mod(Name, XMLNS) /= undefined.
|
||||
|
||||
get_els(Term) ->
|
||||
Mod = get_mod(Term),
|
||||
Mod:get_els(Term).
|
||||
|
||||
set_els(Term, Els) ->
|
||||
Mod = get_mod(Term),
|
||||
Mod:set_els(Term, Els).
|
||||
|
||||
do_decode(<<"connection">>, <<"urn:xmpp:serverinfo:0">>,
|
||||
El, Opts) ->
|
||||
decode_pubsub_serverinfo_connection(<<"urn:xmpp:serverinfo:0">>,
|
||||
Opts,
|
||||
El);
|
||||
do_decode(<<"remote-domain">>,
|
||||
<<"urn:xmpp:serverinfo:0">>, El, Opts) ->
|
||||
decode_pubsub_serverinfo_remote_domain(<<"urn:xmpp:serverinfo:0">>,
|
||||
Opts,
|
||||
El);
|
||||
do_decode(<<"federation">>, <<"urn:xmpp:serverinfo:0">>,
|
||||
El, Opts) ->
|
||||
decode_pubsub_serverinfo_federation(<<"urn:xmpp:serverinfo:0">>,
|
||||
Opts,
|
||||
El);
|
||||
do_decode(<<"domain">>, <<"urn:xmpp:serverinfo:0">>, El,
|
||||
Opts) ->
|
||||
decode_pubsub_serverinfo_domain(<<"urn:xmpp:serverinfo:0">>,
|
||||
Opts,
|
||||
El);
|
||||
do_decode(<<"serverinfo">>, <<"urn:xmpp:serverinfo:0">>,
|
||||
El, Opts) ->
|
||||
decode_pubsub_serverinfo(<<"urn:xmpp:serverinfo:0">>,
|
||||
Opts,
|
||||
El);
|
||||
do_decode(Name, <<>>, _, _) ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{missing_tag_xmlns, Name}});
|
||||
do_decode(Name, XMLNS, _, _) ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{unknown_tag, Name, XMLNS}}).
|
||||
|
||||
tags() ->
|
||||
[{<<"connection">>, <<"urn:xmpp:serverinfo:0">>},
|
||||
{<<"remote-domain">>, <<"urn:xmpp:serverinfo:0">>},
|
||||
{<<"federation">>, <<"urn:xmpp:serverinfo:0">>},
|
||||
{<<"domain">>, <<"urn:xmpp:serverinfo:0">>},
|
||||
{<<"serverinfo">>, <<"urn:xmpp:serverinfo:0">>}].
|
||||
|
||||
do_encode({pubsub_serverinfo, _} = Serverinfo,
|
||||
TopXMLNS) ->
|
||||
encode_pubsub_serverinfo(Serverinfo, TopXMLNS);
|
||||
do_encode({pubsub_serverinfo_domain, _, _} = Domain,
|
||||
TopXMLNS) ->
|
||||
encode_pubsub_serverinfo_domain(Domain, TopXMLNS);
|
||||
do_encode({pubsub_serverinfo_remote_domain, _, _} =
|
||||
Remote_domain,
|
||||
TopXMLNS) ->
|
||||
encode_pubsub_serverinfo_remote_domain(Remote_domain,
|
||||
TopXMLNS).
|
||||
|
||||
do_get_name({pubsub_serverinfo, _}) -> <<"serverinfo">>;
|
||||
do_get_name({pubsub_serverinfo_domain, _, _}) ->
|
||||
<<"domain">>;
|
||||
do_get_name({pubsub_serverinfo_remote_domain, _, _}) ->
|
||||
<<"remote-domain">>.
|
||||
|
||||
do_get_ns({pubsub_serverinfo, _}) ->
|
||||
<<"urn:xmpp:serverinfo:0">>;
|
||||
do_get_ns({pubsub_serverinfo_domain, _, _}) ->
|
||||
<<"urn:xmpp:serverinfo:0">>;
|
||||
do_get_ns({pubsub_serverinfo_remote_domain, _, _}) ->
|
||||
<<"urn:xmpp:serverinfo:0">>.
|
||||
|
||||
register_module(Mod) ->
|
||||
register_module(Mod, pubsub_serverinfo_codec_external).
|
||||
|
||||
unregister_module(Mod) ->
|
||||
unregister_module(Mod,
|
||||
pubsub_serverinfo_codec_external).
|
||||
|
||||
format_error({bad_attr_value, Attr, Tag, XMLNS}) ->
|
||||
<<"Bad value of attribute '", Attr/binary, "' in tag <",
|
||||
Tag/binary, "/> qualified by namespace '", XMLNS/binary,
|
||||
"'">>;
|
||||
format_error({bad_cdata_value, <<>>, Tag, XMLNS}) ->
|
||||
<<"Bad value of cdata in tag <", Tag/binary,
|
||||
"/> qualified by namespace '", XMLNS/binary, "'">>;
|
||||
format_error({missing_tag, Tag, XMLNS}) ->
|
||||
<<"Missing tag <", Tag/binary,
|
||||
"/> qualified by namespace '", XMLNS/binary, "'">>;
|
||||
format_error({missing_attr, Attr, Tag, XMLNS}) ->
|
||||
<<"Missing attribute '", Attr/binary, "' in tag <",
|
||||
Tag/binary, "/> qualified by namespace '", XMLNS/binary,
|
||||
"'">>;
|
||||
format_error({missing_cdata, <<>>, Tag, XMLNS}) ->
|
||||
<<"Missing cdata in tag <", Tag/binary,
|
||||
"/> qualified by namespace '", XMLNS/binary, "'">>;
|
||||
format_error({unknown_tag, Tag, XMLNS}) ->
|
||||
<<"Unknown tag <", Tag/binary,
|
||||
"/> qualified by namespace '", XMLNS/binary, "'">>;
|
||||
format_error({missing_tag_xmlns, Tag}) ->
|
||||
<<"Missing namespace for tag <", Tag/binary, "/>">>.
|
||||
|
||||
io_format_error({bad_attr_value, Attr, Tag, XMLNS}) ->
|
||||
{<<"Bad value of attribute '~s' in tag <~s/> "
|
||||
"qualified by namespace '~s'">>,
|
||||
[Attr, Tag, XMLNS]};
|
||||
io_format_error({bad_cdata_value, <<>>, Tag, XMLNS}) ->
|
||||
{<<"Bad value of cdata in tag <~s/> qualified "
|
||||
"by namespace '~s'">>,
|
||||
[Tag, XMLNS]};
|
||||
io_format_error({missing_tag, Tag, XMLNS}) ->
|
||||
{<<"Missing tag <~s/> qualified by namespace "
|
||||
"'~s'">>,
|
||||
[Tag, XMLNS]};
|
||||
io_format_error({missing_attr, Attr, Tag, XMLNS}) ->
|
||||
{<<"Missing attribute '~s' in tag <~s/> "
|
||||
"qualified by namespace '~s'">>,
|
||||
[Attr, Tag, XMLNS]};
|
||||
io_format_error({missing_cdata, <<>>, Tag, XMLNS}) ->
|
||||
{<<"Missing cdata in tag <~s/> qualified "
|
||||
"by namespace '~s'">>,
|
||||
[Tag, XMLNS]};
|
||||
io_format_error({unknown_tag, Tag, XMLNS}) ->
|
||||
{<<"Unknown tag <~s/> qualified by namespace "
|
||||
"'~s'">>,
|
||||
[Tag, XMLNS]};
|
||||
io_format_error({missing_tag_xmlns, Tag}) ->
|
||||
{<<"Missing namespace for tag <~s/>">>, [Tag]}.
|
||||
|
||||
get_attr(Attr, Attrs, Default) ->
|
||||
case lists:keyfind(Attr, 1, Attrs) of
|
||||
{_, Val} -> Val;
|
||||
false -> Default
|
||||
end.
|
||||
|
||||
enc_xmlns_attrs(XMLNS, XMLNS) -> [];
|
||||
enc_xmlns_attrs(XMLNS, _) -> [{<<"xmlns">>, XMLNS}].
|
||||
|
||||
choose_top_xmlns(<<>>, NSList, TopXMLNS) ->
|
||||
case lists:member(TopXMLNS, NSList) of
|
||||
true -> TopXMLNS;
|
||||
false -> hd(NSList)
|
||||
end;
|
||||
choose_top_xmlns(XMLNS, _, _) -> XMLNS.
|
||||
|
||||
register_module(Mod, ResolverMod) ->
|
||||
MD5Sum = try Mod:module_info(md5) of
|
||||
Val -> Val
|
||||
catch
|
||||
error:badarg ->
|
||||
{ok, {Mod, Val}} = beam_lib:md5(code:which(Mod)),
|
||||
Val
|
||||
end,
|
||||
case orddict:find(Mod, ResolverMod:modules()) of
|
||||
{ok, MD5Sum} -> ok;
|
||||
_ ->
|
||||
Mods = orddict:store(Mod,
|
||||
MD5Sum,
|
||||
ResolverMod:modules()),
|
||||
recompile_resolver(Mods, ResolverMod)
|
||||
end.
|
||||
|
||||
unregister_module(Mod, ResolverMod) ->
|
||||
case orddict:find(Mod, ResolverMod:modules()) of
|
||||
{ok, _} ->
|
||||
Mods = orddict:erase(Mod, ResolverMod:modules()),
|
||||
recompile_resolver(Mods, ResolverMod);
|
||||
error -> ok
|
||||
end.
|
||||
|
||||
recompile_resolver(Mods, ResolverMod) ->
|
||||
Tags = lists:flatmap(fun (M) ->
|
||||
[{Name, XMLNS, M} || {Name, XMLNS} <- M:tags()]
|
||||
end,
|
||||
orddict:fetch_keys(Mods)),
|
||||
Records = lists:flatmap(fun (M) ->
|
||||
[{RecName, RecSize, M}
|
||||
|| {RecName, RecSize} <- M:records()]
|
||||
end,
|
||||
orddict:fetch_keys(Mods)),
|
||||
Lookup1 = string:join(lists:map(fun ({RecName,
|
||||
RecSize,
|
||||
M}) ->
|
||||
io_lib:format("lookup({~s}) -> '~s'",
|
||||
[string:join([io_lib:format("'~s'",
|
||||
[RecName])
|
||||
| ["_"
|
||||
|| _
|
||||
<- lists:seq(1,
|
||||
RecSize)]],
|
||||
","),
|
||||
M])
|
||||
end,
|
||||
Records)
|
||||
++
|
||||
["lookup(Term) -> erlang:error(badarg, "
|
||||
"[Term])."],
|
||||
";" ++ io_lib:nl()),
|
||||
Lookup2 = string:join(lists:map(fun ({Name,
|
||||
XMLNS,
|
||||
M}) ->
|
||||
io_lib:format("lookup(~w, ~w) -> '~s'",
|
||||
[Name, XMLNS, M])
|
||||
end,
|
||||
Tags)
|
||||
++ ["lookup(_, _) -> undefined."],
|
||||
";" ++ io_lib:nl()),
|
||||
Modules = io_lib:format("modules() -> [~s].",
|
||||
[string:join([io_lib:format("{'~s', ~w}", [M, S])
|
||||
|| {M, S} <- Mods],
|
||||
",")]),
|
||||
Module = io_lib:format("-module(~s).", [ResolverMod]),
|
||||
Compile = "-compile(export_all).",
|
||||
Forms = lists:map(fun (Expr) ->
|
||||
{ok, Tokens, _} =
|
||||
erl_scan:string(lists:flatten(Expr)),
|
||||
{ok, Form} = erl_parse:parse_form(Tokens),
|
||||
Form
|
||||
end,
|
||||
[Module, Compile, Modules, Lookup1, Lookup2]),
|
||||
{ok, Code} = case compile:forms(Forms, []) of
|
||||
{ok, ResolverMod, Bin} -> {ok, Bin};
|
||||
{ok, ResolverMod, Bin, _Warnings} -> {ok, Bin};
|
||||
Error -> Error
|
||||
end,
|
||||
{module, ResolverMod} = code:load_binary(ResolverMod,
|
||||
"nofile",
|
||||
Code),
|
||||
ok.
|
||||
|
||||
dec_enum(Val, Enums) ->
|
||||
AtomVal = erlang:binary_to_existing_atom(Val, utf8),
|
||||
case lists:member(AtomVal, Enums) of
|
||||
true -> AtomVal
|
||||
end.
|
||||
|
||||
enc_enum(Atom) -> erlang:atom_to_binary(Atom, utf8).
|
||||
|
||||
pp(pubsub_serverinfo, 1) -> [domain];
|
||||
pp(pubsub_serverinfo_domain, 2) ->
|
||||
[name, remote_domain];
|
||||
pp(pubsub_serverinfo_remote_domain, 2) -> [name, type];
|
||||
pp(xmlel, 3) -> [name, attrs, children];
|
||||
pp(Name, Arity) ->
|
||||
try get_mod(erlang:make_tuple(Arity + 1,
|
||||
undefined,
|
||||
[{1, Name}]))
|
||||
of
|
||||
Mod -> Mod:pp(Name, Arity)
|
||||
catch
|
||||
error:badarg -> no
|
||||
end.
|
||||
|
||||
records() ->
|
||||
[{pubsub_serverinfo, 1},
|
||||
{pubsub_serverinfo_domain, 2},
|
||||
{pubsub_serverinfo_remote_domain, 2}].
|
||||
|
||||
get_mod(<<"serverinfo">>,
|
||||
<<"urn:xmpp:serverinfo:0">>) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod(<<"remote-domain">>,
|
||||
<<"urn:xmpp:serverinfo:0">>) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod(<<"federation">>,
|
||||
<<"urn:xmpp:serverinfo:0">>) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod(<<"domain">>, <<"urn:xmpp:serverinfo:0">>) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod(<<"connection">>,
|
||||
<<"urn:xmpp:serverinfo:0">>) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod(Name, XMLNS) ->
|
||||
pubsub_serverinfo_codec_external:lookup(Name, XMLNS).
|
||||
|
||||
get_mod({pubsub_serverinfo, _}) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod({pubsub_serverinfo_domain, _, _}) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod({pubsub_serverinfo_remote_domain, _, _}) ->
|
||||
pubsub_serverinfo_codec;
|
||||
get_mod(Record) ->
|
||||
pubsub_serverinfo_codec_external:lookup(Record).
|
||||
|
||||
decode_pubsub_serverinfo_connection(__TopXMLNS, __Opts,
|
||||
{xmlel, <<"connection">>, _attrs, _els}) ->
|
||||
Type =
|
||||
decode_pubsub_serverinfo_connection_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
undefined),
|
||||
Type.
|
||||
|
||||
decode_pubsub_serverinfo_connection_attrs(__TopXMLNS,
|
||||
[{<<"type">>, _val} | _attrs],
|
||||
_Type) ->
|
||||
decode_pubsub_serverinfo_connection_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
_val);
|
||||
decode_pubsub_serverinfo_connection_attrs(__TopXMLNS,
|
||||
[_ | _attrs], Type) ->
|
||||
decode_pubsub_serverinfo_connection_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
Type);
|
||||
decode_pubsub_serverinfo_connection_attrs(__TopXMLNS,
|
||||
[], Type) ->
|
||||
decode_pubsub_serverinfo_connection_attr_type(__TopXMLNS,
|
||||
Type).
|
||||
|
||||
encode_pubsub_serverinfo_connection(Type, __TopXMLNS) ->
|
||||
__NewTopXMLNS =
|
||||
pubsub_serverinfo_codec:choose_top_xmlns(<<"urn:xmpp:serverinfo:0">>,
|
||||
[],
|
||||
__TopXMLNS),
|
||||
_els = [],
|
||||
_attrs =
|
||||
encode_pubsub_serverinfo_connection_attr_type(Type,
|
||||
pubsub_serverinfo_codec:enc_xmlns_attrs(__NewTopXMLNS,
|
||||
__TopXMLNS)),
|
||||
{xmlel, <<"connection">>, _attrs, _els}.
|
||||
|
||||
decode_pubsub_serverinfo_connection_attr_type(__TopXMLNS,
|
||||
undefined) ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{missing_attr,
|
||||
<<"type">>,
|
||||
<<"connection">>,
|
||||
__TopXMLNS}});
|
||||
decode_pubsub_serverinfo_connection_attr_type(__TopXMLNS,
|
||||
_val) ->
|
||||
case catch dec_enum(_val, [incoming, outgoing, bidi]) of
|
||||
{'EXIT', _} ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{bad_attr_value,
|
||||
<<"type">>,
|
||||
<<"connection">>,
|
||||
__TopXMLNS}});
|
||||
_res -> _res
|
||||
end.
|
||||
|
||||
encode_pubsub_serverinfo_connection_attr_type(_val,
|
||||
_acc) ->
|
||||
[{<<"type">>, enc_enum(_val)} | _acc].
|
||||
|
||||
decode_pubsub_serverinfo_remote_domain(__TopXMLNS,
|
||||
__Opts,
|
||||
{xmlel,
|
||||
<<"remote-domain">>,
|
||||
_attrs,
|
||||
_els}) ->
|
||||
Type =
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
[]),
|
||||
Name =
|
||||
decode_pubsub_serverinfo_remote_domain_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
undefined),
|
||||
{pubsub_serverinfo_remote_domain, Name, Type}.
|
||||
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts, [], Type) ->
|
||||
lists:reverse(Type);
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
[{xmlel,
|
||||
<<"connection">>,
|
||||
_attrs,
|
||||
_} =
|
||||
_el
|
||||
| _els],
|
||||
Type) ->
|
||||
case pubsub_serverinfo_codec:get_attr(<<"xmlns">>,
|
||||
_attrs,
|
||||
__TopXMLNS)
|
||||
of
|
||||
<<"urn:xmpp:serverinfo:0">> ->
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
[decode_pubsub_serverinfo_connection(<<"urn:xmpp:serverinfo:0">>,
|
||||
__Opts,
|
||||
_el)
|
||||
| Type]);
|
||||
_ ->
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Type)
|
||||
end;
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts, [_ | _els], Type) ->
|
||||
decode_pubsub_serverinfo_remote_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Type).
|
||||
|
||||
decode_pubsub_serverinfo_remote_domain_attrs(__TopXMLNS,
|
||||
[{<<"name">>, _val} | _attrs],
|
||||
_Name) ->
|
||||
decode_pubsub_serverinfo_remote_domain_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
_val);
|
||||
decode_pubsub_serverinfo_remote_domain_attrs(__TopXMLNS,
|
||||
[_ | _attrs], Name) ->
|
||||
decode_pubsub_serverinfo_remote_domain_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
Name);
|
||||
decode_pubsub_serverinfo_remote_domain_attrs(__TopXMLNS,
|
||||
[], Name) ->
|
||||
decode_pubsub_serverinfo_remote_domain_attr_name(__TopXMLNS,
|
||||
Name).
|
||||
|
||||
encode_pubsub_serverinfo_remote_domain({pubsub_serverinfo_remote_domain,
|
||||
Name,
|
||||
Type},
|
||||
__TopXMLNS) ->
|
||||
__NewTopXMLNS =
|
||||
pubsub_serverinfo_codec:choose_top_xmlns(<<"urn:xmpp:serverinfo:0">>,
|
||||
[],
|
||||
__TopXMLNS),
|
||||
_els =
|
||||
lists:reverse('encode_pubsub_serverinfo_remote_domain_$type'(Type,
|
||||
__NewTopXMLNS,
|
||||
[])),
|
||||
_attrs =
|
||||
encode_pubsub_serverinfo_remote_domain_attr_name(Name,
|
||||
pubsub_serverinfo_codec:enc_xmlns_attrs(__NewTopXMLNS,
|
||||
__TopXMLNS)),
|
||||
{xmlel, <<"remote-domain">>, _attrs, _els}.
|
||||
|
||||
'encode_pubsub_serverinfo_remote_domain_$type'([],
|
||||
__TopXMLNS, _acc) ->
|
||||
_acc;
|
||||
'encode_pubsub_serverinfo_remote_domain_$type'([Type
|
||||
| _els],
|
||||
__TopXMLNS, _acc) ->
|
||||
'encode_pubsub_serverinfo_remote_domain_$type'(_els,
|
||||
__TopXMLNS,
|
||||
[encode_pubsub_serverinfo_connection(Type,
|
||||
__TopXMLNS)
|
||||
| _acc]).
|
||||
|
||||
decode_pubsub_serverinfo_remote_domain_attr_name(__TopXMLNS,
|
||||
undefined) ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{missing_attr,
|
||||
<<"name">>,
|
||||
<<"remote-domain">>,
|
||||
__TopXMLNS}});
|
||||
decode_pubsub_serverinfo_remote_domain_attr_name(__TopXMLNS,
|
||||
_val) ->
|
||||
_val.
|
||||
|
||||
encode_pubsub_serverinfo_remote_domain_attr_name(_val,
|
||||
_acc) ->
|
||||
[{<<"name">>, _val} | _acc].
|
||||
|
||||
decode_pubsub_serverinfo_federation(__TopXMLNS, __Opts,
|
||||
{xmlel, <<"federation">>, _attrs, _els}) ->
|
||||
Remote_domain =
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
[]),
|
||||
Remote_domain.
|
||||
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts, [], Remote_domain) ->
|
||||
lists:reverse(Remote_domain);
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts,
|
||||
[{xmlel,
|
||||
<<"remote-domain">>,
|
||||
_attrs,
|
||||
_} =
|
||||
_el
|
||||
| _els],
|
||||
Remote_domain) ->
|
||||
case pubsub_serverinfo_codec:get_attr(<<"xmlns">>,
|
||||
_attrs,
|
||||
__TopXMLNS)
|
||||
of
|
||||
<<"urn:xmpp:serverinfo:0">> ->
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
[decode_pubsub_serverinfo_remote_domain(<<"urn:xmpp:serverinfo:0">>,
|
||||
__Opts,
|
||||
_el)
|
||||
| Remote_domain]);
|
||||
_ ->
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Remote_domain)
|
||||
end;
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts, [_ | _els], Remote_domain) ->
|
||||
decode_pubsub_serverinfo_federation_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Remote_domain).
|
||||
|
||||
encode_pubsub_serverinfo_federation(Remote_domain,
|
||||
__TopXMLNS) ->
|
||||
__NewTopXMLNS =
|
||||
pubsub_serverinfo_codec:choose_top_xmlns(<<"urn:xmpp:serverinfo:0">>,
|
||||
[],
|
||||
__TopXMLNS),
|
||||
_els =
|
||||
lists:reverse('encode_pubsub_serverinfo_federation_$remote_domain'(Remote_domain,
|
||||
__NewTopXMLNS,
|
||||
[])),
|
||||
_attrs =
|
||||
pubsub_serverinfo_codec:enc_xmlns_attrs(__NewTopXMLNS,
|
||||
__TopXMLNS),
|
||||
{xmlel, <<"federation">>, _attrs, _els}.
|
||||
|
||||
'encode_pubsub_serverinfo_federation_$remote_domain'([],
|
||||
__TopXMLNS, _acc) ->
|
||||
_acc;
|
||||
'encode_pubsub_serverinfo_federation_$remote_domain'([Remote_domain
|
||||
| _els],
|
||||
__TopXMLNS, _acc) ->
|
||||
'encode_pubsub_serverinfo_federation_$remote_domain'(_els,
|
||||
__TopXMLNS,
|
||||
[encode_pubsub_serverinfo_remote_domain(Remote_domain,
|
||||
__TopXMLNS)
|
||||
| _acc]).
|
||||
|
||||
decode_pubsub_serverinfo_domain(__TopXMLNS, __Opts,
|
||||
{xmlel, <<"domain">>, _attrs, _els}) ->
|
||||
Remote_domain =
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
undefined),
|
||||
Name = decode_pubsub_serverinfo_domain_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
undefined),
|
||||
{pubsub_serverinfo_domain, Name, Remote_domain}.
|
||||
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS, __Opts,
|
||||
[], Remote_domain) ->
|
||||
Remote_domain;
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS, __Opts,
|
||||
[{xmlel, <<"federation">>, _attrs, _} = _el
|
||||
| _els],
|
||||
Remote_domain) ->
|
||||
case pubsub_serverinfo_codec:get_attr(<<"xmlns">>,
|
||||
_attrs,
|
||||
__TopXMLNS)
|
||||
of
|
||||
<<"urn:xmpp:serverinfo:0">> ->
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
decode_pubsub_serverinfo_federation(<<"urn:xmpp:serverinfo:0">>,
|
||||
__Opts,
|
||||
_el));
|
||||
_ ->
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Remote_domain)
|
||||
end;
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS, __Opts,
|
||||
[_ | _els], Remote_domain) ->
|
||||
decode_pubsub_serverinfo_domain_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Remote_domain).
|
||||
|
||||
decode_pubsub_serverinfo_domain_attrs(__TopXMLNS,
|
||||
[{<<"name">>, _val} | _attrs], _Name) ->
|
||||
decode_pubsub_serverinfo_domain_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
_val);
|
||||
decode_pubsub_serverinfo_domain_attrs(__TopXMLNS,
|
||||
[_ | _attrs], Name) ->
|
||||
decode_pubsub_serverinfo_domain_attrs(__TopXMLNS,
|
||||
_attrs,
|
||||
Name);
|
||||
decode_pubsub_serverinfo_domain_attrs(__TopXMLNS, [],
|
||||
Name) ->
|
||||
decode_pubsub_serverinfo_domain_attr_name(__TopXMLNS,
|
||||
Name).
|
||||
|
||||
encode_pubsub_serverinfo_domain({pubsub_serverinfo_domain,
|
||||
Name,
|
||||
Remote_domain},
|
||||
__TopXMLNS) ->
|
||||
__NewTopXMLNS =
|
||||
pubsub_serverinfo_codec:choose_top_xmlns(<<"urn:xmpp:serverinfo:0">>,
|
||||
[],
|
||||
__TopXMLNS),
|
||||
_els =
|
||||
lists:reverse('encode_pubsub_serverinfo_domain_$remote_domain'(Remote_domain,
|
||||
__NewTopXMLNS,
|
||||
[])),
|
||||
_attrs = encode_pubsub_serverinfo_domain_attr_name(Name,
|
||||
pubsub_serverinfo_codec:enc_xmlns_attrs(__NewTopXMLNS,
|
||||
__TopXMLNS)),
|
||||
{xmlel, <<"domain">>, _attrs, _els}.
|
||||
|
||||
'encode_pubsub_serverinfo_domain_$remote_domain'(undefined,
|
||||
__TopXMLNS, _acc) ->
|
||||
_acc;
|
||||
'encode_pubsub_serverinfo_domain_$remote_domain'(Remote_domain,
|
||||
__TopXMLNS, _acc) ->
|
||||
[encode_pubsub_serverinfo_federation(Remote_domain,
|
||||
__TopXMLNS)
|
||||
| _acc].
|
||||
|
||||
decode_pubsub_serverinfo_domain_attr_name(__TopXMLNS,
|
||||
undefined) ->
|
||||
erlang:error({pubsub_serverinfo_codec,
|
||||
{missing_attr, <<"name">>, <<"domain">>, __TopXMLNS}});
|
||||
decode_pubsub_serverinfo_domain_attr_name(__TopXMLNS,
|
||||
_val) ->
|
||||
_val.
|
||||
|
||||
encode_pubsub_serverinfo_domain_attr_name(_val, _acc) ->
|
||||
[{<<"name">>, _val} | _acc].
|
||||
|
||||
decode_pubsub_serverinfo(__TopXMLNS, __Opts,
|
||||
{xmlel, <<"serverinfo">>, _attrs, _els}) ->
|
||||
Domain = decode_pubsub_serverinfo_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
[]),
|
||||
{pubsub_serverinfo, Domain}.
|
||||
|
||||
decode_pubsub_serverinfo_els(__TopXMLNS, __Opts, [],
|
||||
Domain) ->
|
||||
lists:reverse(Domain);
|
||||
decode_pubsub_serverinfo_els(__TopXMLNS, __Opts,
|
||||
[{xmlel, <<"domain">>, _attrs, _} = _el | _els],
|
||||
Domain) ->
|
||||
case pubsub_serverinfo_codec:get_attr(<<"xmlns">>,
|
||||
_attrs,
|
||||
__TopXMLNS)
|
||||
of
|
||||
<<"urn:xmpp:serverinfo:0">> ->
|
||||
decode_pubsub_serverinfo_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
[decode_pubsub_serverinfo_domain(<<"urn:xmpp:serverinfo:0">>,
|
||||
__Opts,
|
||||
_el)
|
||||
| Domain]);
|
||||
_ ->
|
||||
decode_pubsub_serverinfo_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Domain)
|
||||
end;
|
||||
decode_pubsub_serverinfo_els(__TopXMLNS, __Opts,
|
||||
[_ | _els], Domain) ->
|
||||
decode_pubsub_serverinfo_els(__TopXMLNS,
|
||||
__Opts,
|
||||
_els,
|
||||
Domain).
|
||||
|
||||
encode_pubsub_serverinfo({pubsub_serverinfo, Domain},
|
||||
__TopXMLNS) ->
|
||||
__NewTopXMLNS =
|
||||
pubsub_serverinfo_codec:choose_top_xmlns(<<"urn:xmpp:serverinfo:0">>,
|
||||
[],
|
||||
__TopXMLNS),
|
||||
_els =
|
||||
lists:reverse('encode_pubsub_serverinfo_$domain'(Domain,
|
||||
__NewTopXMLNS,
|
||||
[])),
|
||||
_attrs =
|
||||
pubsub_serverinfo_codec:enc_xmlns_attrs(__NewTopXMLNS,
|
||||
__TopXMLNS),
|
||||
{xmlel, <<"serverinfo">>, _attrs, _els}.
|
||||
|
||||
'encode_pubsub_serverinfo_$domain'([], __TopXMLNS,
|
||||
_acc) ->
|
||||
_acc;
|
||||
'encode_pubsub_serverinfo_$domain'([Domain | _els],
|
||||
__TopXMLNS, _acc) ->
|
||||
'encode_pubsub_serverinfo_$domain'(_els,
|
||||
__TopXMLNS,
|
||||
[encode_pubsub_serverinfo_domain(Domain,
|
||||
__TopXMLNS)
|
||||
| _acc]).
|
12
src/pubsub_serverinfo_codec_external.erl
Normal file
12
src/pubsub_serverinfo_codec_external.erl
Normal file
|
@ -0,0 +1,12 @@
|
|||
%% Created automatically by XML generator (fxml_gen.erl)
|
||||
%% Source: pubsub_serverinfo_codec.spec
|
||||
|
||||
-module(pubsub_serverinfo_codec_external).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
modules() -> [].
|
||||
|
||||
lookup(_, _) -> undefined.
|
||||
|
||||
lookup(Term) -> erlang:error(badarg, [Term]).
|
Loading…
Add table
Add a link
Reference in a new issue