From 740b0c7dd7a50524a927e34bfc3cd4d877d08163 Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Sat, 5 Jul 2025 14:19:20 +0200 Subject: [PATCH 1/6] mod_pubsub_serverinfo: initial import as found on ejabberd-contrib --- include/pubsub_serverinfo_codec.hrl | 17 + specs/pubsub_serverinfo_codec.spec | 52 ++ src/mod_pubsub_serverinfo.erl | 312 ++++++++++ src/pubsub_serverinfo_codec.erl | 734 +++++++++++++++++++++++ src/pubsub_serverinfo_codec_external.erl | 12 + 5 files changed, 1127 insertions(+) create mode 100644 include/pubsub_serverinfo_codec.hrl create mode 100644 specs/pubsub_serverinfo_codec.spec create mode 100644 src/mod_pubsub_serverinfo.erl create mode 100644 src/pubsub_serverinfo_codec.erl create mode 100644 src/pubsub_serverinfo_codec_external.erl diff --git a/include/pubsub_serverinfo_codec.hrl b/include/pubsub_serverinfo_codec.hrl new file mode 100644 index 000000000..81b975798 --- /dev/null +++ b/include/pubsub_serverinfo_codec.hrl @@ -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(). diff --git a/specs/pubsub_serverinfo_codec.spec b/specs/pubsub_serverinfo_codec.spec new file mode 100644 index 000000000..44966e9f1 --- /dev/null +++ b/specs/pubsub_serverinfo_codec.spec @@ -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]]}}]}). diff --git a/src/mod_pubsub_serverinfo.erl b/src/mod_pubsub_serverinfo.erl new file mode 100644 index 000000000..4ebc93732 --- /dev/null +++ b/src/mod_pubsub_serverinfo.erl @@ -0,0 +1,312 @@ +%%%---------------------------------------------------------------------- +%%% File : mod_pubsub_serverinfo.erl +%%% Author : Stefan Strigler +%%% Purpose : Exposes server information over Pub/Sub +%%% Created : 26 Dec 2023 by Guus der Kinderen +%%% +%%% +%%% 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. diff --git a/src/pubsub_serverinfo_codec.erl b/src/pubsub_serverinfo_codec.erl new file mode 100644 index 000000000..9b16edeaf --- /dev/null +++ b/src/pubsub_serverinfo_codec.erl @@ -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]). diff --git a/src/pubsub_serverinfo_codec_external.erl b/src/pubsub_serverinfo_codec_external.erl new file mode 100644 index 000000000..2f2df47e3 --- /dev/null +++ b/src/pubsub_serverinfo_codec_external.erl @@ -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]). From bf54cc59e12ef4c678066d06d621f792a8b5e639 Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Sat, 5 Jul 2025 14:23:03 +0200 Subject: [PATCH 2/6] mod_pubsub_serverinfo: apply `make format` --- src/mod_pubsub_serverinfo.erl | 334 +++++++++++++++++++--------------- 1 file changed, 191 insertions(+), 143 deletions(-) diff --git a/src/mod_pubsub_serverinfo.erl b/src/mod_pubsub_serverinfo.erl index 4ebc93732..d8b47fa91 100644 --- a/src/mod_pubsub_serverinfo.erl +++ b/src/mod_pubsub_serverinfo.erl @@ -42,17 +42,19 @@ -record(state, {host, pubsub_host, node, monitors = #{}, timer = undefined, public_hosts = []}). +%% @format-begin + 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) + {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) -> @@ -63,48 +65,53 @@ stop(Host) -> gen_mod:stop_child(?MODULE, Host). init([Host, PubsubHost]) -> - TRef = timer:send_interval(timer:minutes(5), self(), update_pubsub), + 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}, + 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]). + 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}]), + {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; + PublicHosts when is_list(PublicHosts) -> + PublicHosts; Other -> ?WARNING_MSG("Parsed JSON for public hosts was not a list: ~p", [Other]), [] end - catch E:R -> + 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 -> + 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), @@ -112,37 +119,41 @@ handle_cast({Event, Domain, Pid}, #state{host = Host, monitors = Mons} = State) handle_cast(_, State) -> {noreply, State}. -event_to_dir(register_in) -> incoming; -event_to_dir(register_out) -> outgoing. +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) -> +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} + #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), @@ -154,22 +165,22 @@ handle_info(_Request, 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 + 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). + maps:fold(fun(Mon, _, _) -> demonitor(Mon) end, ok, Mons). depends(_Host, _Opts) -> [{mod_pubsub, hard}]. @@ -180,124 +191,161 @@ mod_options(_Host) -> mod_opt_type(pubsub_host) -> econf:either(undefined, econf:host()). -mod_doc() -> #{}. +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()}), + 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()}), + 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). + 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. + 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(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{}]}, + 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), +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). + 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]} + {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 == <<"">> -> +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 + [#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]; + 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 + {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 + 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) -> @@ -305,8 +353,8 @@ check_pubsub_host_exists(Host, PubsubHost) -> 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 + [] -> + [gen_mod:get_module_opt(Host, mod_pubsub, host)]; + PubsubHosts -> + PubsubHosts end. From a6823d157c95fba829017a9d249f779e58b6d163 Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Sat, 5 Jul 2025 14:38:55 +0200 Subject: [PATCH 3/6] mod_pubsub_serverinfo: add documentation --- src/mod_pubsub_serverinfo.erl | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/mod_pubsub_serverinfo.erl b/src/mod_pubsub_serverinfo.erl index d8b47fa91..f002808bc 100644 --- a/src/mod_pubsub_serverinfo.erl +++ b/src/mod_pubsub_serverinfo.erl @@ -30,6 +30,8 @@ -include("pubsub_serverinfo_codec.hrl"). -include("logger.hrl"). +-include("translate.hrl"). + -include_lib("xmpp/include/xmpp.hrl"). %% gen_mod callbacks. @@ -192,7 +194,22 @@ mod_opt_type(pubsub_host) -> econf:either(undefined, econf:host()). mod_doc() -> - #{}. + #{desc => [?T("Exposes s2s information over Pub/Sub"), "", + ?T("Announces support for the ProtoXEP PubSub Server Information, by adding its Service Discovery feature." + "Active S2S connections are published to a local pubsub node as advertised by Service Discovery. Only those connections that support this feature as well are exposed with their domain names, otherwise they are shown as anonymous nodes. At startup a list of well known public servers is being fetched. Those are not shown as anonymous even if they don't support this feature." + "Currently the name of the node is hardcoded as \"serverinfo\". The local service to be used can be configured as `pubsub_host`. Otherwise a good guess is taken." + "This module has a hard dependency on `mod_pubsub` for this reason. Also `mod_disco` must be configured for this feature to work."), "", + ?T("NOTE: The module only shows S2S connections established while the module is running: after installing the module, please run `ejabberdctl stop_s2s_connections`, or restart ejabberd.")], + note => "added in 25.xx", + opts => [{pubsub_host, + #{value => "undefined | string()", + desc => ?T("This option specifies which pubsub host to use to advertise S2S connections. This must be a vhost local to this service and handled by `mod_pubsub`. This is only needed if your configuration has more than one vhost in mod_pubsub's `hosts` option. If there's more than one and this option is not given, we just pick the first one.")} + }], + example => + ["modules:", + " mod_pubsub_serverinfo:", + " pubsub_host: custom.pubsub.domain.local"] + }. in_auth_result(#{server_host := Host, remote_server := RServer} = State, true, _Server) -> gen_server:cast( From c567005241bda343d96d551c4e6cab82378f9236 Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Sat, 5 Jul 2025 14:54:11 +0200 Subject: [PATCH 4/6] mod_pubsub_serverinfo: get pubsub host from server state --- src/mod_pubsub_serverinfo.erl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mod_pubsub_serverinfo.erl b/src/mod_pubsub_serverinfo.erl index f002808bc..8141e243f 100644 --- a/src/mod_pubsub_serverinfo.erl +++ b/src/mod_pubsub_serverinfo.erl @@ -126,6 +126,8 @@ event_to_dir(register_in) -> event_to_dir(register_out) -> outgoing. +handle_call(pubsub_host, _From, #state{pubsub_host = PubsubHost} = State) -> + {reply, {ok, PubsubHost}, State}; handle_call(_Request, _From, State) -> {noreply, State}. @@ -343,12 +345,8 @@ 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. + {ok, PubsubHost} = gen_server:call(gen_mod:get_module_proc(Host, ?MODULE), pubsub_host), + PubsubHost. pubsub_host(Host, Opts) -> case gen_mod:get_opt(pubsub_host, Opts) of From 500af47b7948a2173562276fecd4c787bbf33a80 Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Mon, 7 Jul 2025 17:21:27 +0200 Subject: [PATCH 5/6] mod_pubsub_serverinfo: codec spec moved to p1/xmpp --- include/pubsub_serverinfo_codec.hrl | 17 - mix.exs | 2 +- rebar.config | 2 +- rebar.lock | 32 +- specs/pubsub_serverinfo_codec.spec | 52 -- src/mod_pubsub_serverinfo.erl | 2 - src/pubsub_serverinfo_codec.erl | 734 ----------------------- src/pubsub_serverinfo_codec_external.erl | 12 - 8 files changed, 18 insertions(+), 835 deletions(-) delete mode 100644 include/pubsub_serverinfo_codec.hrl delete mode 100644 specs/pubsub_serverinfo_codec.spec delete mode 100644 src/pubsub_serverinfo_codec.erl delete mode 100644 src/pubsub_serverinfo_codec_external.erl diff --git a/include/pubsub_serverinfo_codec.hrl b/include/pubsub_serverinfo_codec.hrl deleted file mode 100644 index 81b975798..000000000 --- a/include/pubsub_serverinfo_codec.hrl +++ /dev/null @@ -1,17 +0,0 @@ -%% 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(). diff --git a/mix.exs b/mix.exs index c8d6d82bc..308d95c51 100644 --- a/mix.exs +++ b/mix.exs @@ -130,7 +130,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp", ref: "74ed2d87222d3bd5e86f7c41daaa28fae59d4995", override: true}, + {:xmpp, git: "https://github.com/processone/xmpp", ref: "fbaea1bfb4244e4287fe8449144e8e72d9a842d1", override: true}, {:yconf, ">= 1.0.18"}] ++ cond_deps() end diff --git a/rebar.config b/rebar.config index 63c51b8fb..ad3b004c7 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.31", {git, "https://github.com/processone/stringprep", {tag, "1.0.31"}}}, {if_var_true, stun, {stun, "~> 1.2.17", {git, "https://github.com/processone/stun", {tag, "1.2.17"}}}}, - {xmpp, "~> 1.10.0", {git, "https://github.com/processone/xmpp", "74ed2d87222d3bd5e86f7c41daaa28fae59d4995"}}, + {xmpp, "~> 1.10.0", {git, "https://github.com/processone/xmpp", "fbaea1bfb4244e4287fe8449144e8e72d9a842d1"}}, {yconf, "~> 1.0.18", {git, "https://github.com/processone/yconf", {tag, "1.0.18"}}} ]}. diff --git a/rebar.lock b/rebar.lock index 973df5a07..365d3fd3e 100644 --- a/rebar.lock +++ b/rebar.lock @@ -16,23 +16,23 @@ {<<"jiffy">>,{pkg,<<"jiffy">>,<<"1.1.2">>},1}, {<<"jose">>,{pkg,<<"jose">>,<<"1.11.10">>},0}, {<<"luerl">>,{pkg,<<"luerl">>,<<"1.2.3">>},0}, - {<<"mqtree">>,{pkg,<<"mqtree">>,<<"1.0.17">>},0}, + {<<"mqtree">>,{pkg,<<"mqtree">>,<<"1.0.18">>},0}, {<<"p1_acme">>, {git,"https://github.com/processone/p1_acme", {ref,"27a590789add30ff507a49ffd440eeeb28c96ce5"}}, 0}, {<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.26">>},0}, {<<"p1_oauth2">>,{pkg,<<"p1_oauth2">>,<<"0.6.14">>},0}, - {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.32">>},0}, + {<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.33">>},0}, {<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.27">>},0}, {<<"pkix">>,{pkg,<<"pkix">>,<<"1.0.10">>},0}, {<<"sqlite3">>,{pkg,<<"sqlite3">>,<<"1.1.15">>},0}, - {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.31">>},0}, - {<<"stun">>,{pkg,<<"stun">>,<<"1.2.17">>},0}, - {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, + {<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.32">>},0}, + {<<"stun">>,{pkg,<<"stun">>,<<"1.2.19">>},0}, + {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.1">>},1}, {<<"xmpp">>, {git,"https://github.com/processone/xmpp", - {ref,"74ed2d87222d3bd5e86f7c41daaa28fae59d4995"}}, + {ref,"fbaea1bfb4244e4287fe8449144e8e72d9a842d1"}}, 0}, {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.18">>},0}]}. [ @@ -50,16 +50,16 @@ {<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>}, {<<"jose">>, <<"A903F5227417BD2A08C8A00A0CBCC458118BE84480955E8D251297A425723F83">>}, {<<"luerl">>, <<"DF25F41944E57A7C4D9EF09D238BC3E850276C46039CFC12B8BB42ECCF36FCB1">>}, - {<<"mqtree">>, <<"82F54B8F2D22B4445DB1D6CCCB7FE9EAD049D61410C29E32475F3CEB3EE62A89">>}, + {<<"mqtree">>, <<"B004E80BBEE5BC49E774B839F88162BDFF5CB654ABBDB79C8381AE4B13510A1B">>}, {<<"p1_mysql">>, <<"574D07C9936C53B1EC3556DB3CF064CC14A6C39039835B3D940471BFA5AC8E2B">>}, {<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>}, - {<<"p1_pgsql">>, <<"3F95D7E3413FC8F0BE80ABB4BE1A0D7F67066A36905085CD5A423145598B0CB0">>}, + {<<"p1_pgsql">>, <<"585F720C76B9BD27C5313DBB2C3CAD0CA19AB4493DE0B34A7496B51B65F5613A">>}, {<<"p1_utils">>, <<"F468D84C6FFA6E4B12A6160826DCF2D015527189D57865568A78B49C5ED972A1">>}, {<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>}, {<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>}, - {<<"stringprep">>, <<"FA1688C156DD271722AA18C423A4163E710D2F4F475AD0BC220910DF669B53AF">>}, - {<<"stun">>, <<"C54614A592812EA125A2E6827AAC5A438571B591616426EC1419BA9B48252F54">>}, - {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}, + {<<"stringprep">>, <<"63FD7FF5417A4A48DB6BB529C83D678361D34188367C1B13B3EAF39ACDEDB8E5">>}, + {<<"stun">>, <<"FF5BD2D2E3A0C2ADE41FC71A7A069EEBAA492ECDB35ECA35350FFF3C194B381A">>}, + {<<"unicode_util_compat">>, <<"A48703A25C170EEDADCA83B11E88985AF08D35F37C6F664D6DCFB106A97782FC">>}, {<<"yconf">>, <<"E565EDC8AABB8164C3BEBC86969095D296AD315DCBB46AF65DCCBC6C71EAE0F6">>}]}, {pkg_hash_ext,[ {<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>}, @@ -75,15 +75,15 @@ {<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>}, {<<"jose">>, <<"0D6CD36FF8BA174DB29148FC112B5842186B68A90CE9FC2B3EC3AFE76593E614">>}, {<<"luerl">>, <<"1B4B9D0CA5D7D280D1D2787A6A5EE9F5A212641B62BFF91556BAA53805DF3AED">>}, - {<<"mqtree">>, <<"5FE8B7CF8FBC4783D0FCEB94654AC2BBF3242A58CD0397D249DED8AE021BE2A3">>}, + {<<"mqtree">>, <<"F73827CECF9A310670F7D7909FC88EAB40B45290FE48E5C7E45AB7235B29B919">>}, {<<"p1_mysql">>, <<"EA138083F2C54719B9CF549DBF5802A288B0019EA3E5449B354C74CC03FAFDEC">>}, {<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>}, - {<<"p1_pgsql">>, <<"268B01E8F4EB75C211A31495A25C2815C549AECCE2F0DF1A161C6E0A2CDE061E">>}, + {<<"p1_pgsql">>, <<"3FB6A9617DB146419D420FFE7E94B9179A7CB5063D9C9450EF8B13FDAD2A709F">>}, {<<"p1_utils">>, <<"F1AF942B0A62BCFA0D59FBE30679BE4FFEB5E241A0C49ED5F094DB2F5B80F5E0">>}, {<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>}, {<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>}, - {<<"stringprep">>, <<"E9699C88E8DB16B3A41F0E45AC6874A4DA81A6E4854A77D76EDE6D09B08E3530">>}, - {<<"stun">>, <<"6B318244C21E8524A9AAE3AC9A05CD8234EE994C1C2C815DE68D306086AD768D">>}, - {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}, + {<<"stringprep">>, <<"6069CB059F5D18A312C42E5F374E9DE415DF68F7E3090C9C1A5505E2A8532710">>}, + {<<"stun">>, <<"66DC035EBF21DE8ABE51ECCC2C3D4BBF63C78650F74C3AFCAF2E4BB15C555927">>}, + {<<"unicode_util_compat">>, <<"B3A917854CE3AE233619744AD1E0102E05673136776FB2FA76234F3E03B23642">>}, {<<"yconf">>, <<"FA950EC6503F92D6417FB8CC1D982403F041697E8E1BBF4D4588FB919B9562EA">>}]} ]. diff --git a/specs/pubsub_serverinfo_codec.spec b/specs/pubsub_serverinfo_codec.spec deleted file mode 100644 index 44966e9f1..000000000 --- a/specs/pubsub_serverinfo_codec.spec +++ /dev/null @@ -1,52 +0,0 @@ --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]]}}]}). diff --git a/src/mod_pubsub_serverinfo.erl b/src/mod_pubsub_serverinfo.erl index 8141e243f..cc7672dfe 100644 --- a/src/mod_pubsub_serverinfo.erl +++ b/src/mod_pubsub_serverinfo.erl @@ -28,7 +28,6 @@ -behaviour(gen_mod). -behaviour(gen_server). --include("pubsub_serverinfo_codec.hrl"). -include("logger.hrl"). -include("translate.hrl"). @@ -51,7 +50,6 @@ start(Host, Opts) -> {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), diff --git a/src/pubsub_serverinfo_codec.erl b/src/pubsub_serverinfo_codec.erl deleted file mode 100644 index 9b16edeaf..000000000 --- a/src/pubsub_serverinfo_codec.erl +++ /dev/null @@ -1,734 +0,0 @@ -%% 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]). diff --git a/src/pubsub_serverinfo_codec_external.erl b/src/pubsub_serverinfo_codec_external.erl deleted file mode 100644 index 2f2df47e3..000000000 --- a/src/pubsub_serverinfo_codec_external.erl +++ /dev/null @@ -1,12 +0,0 @@ -%% 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]). From 3b972fe4a3acc90b514d97c4e34bc358d18ac9f5 Mon Sep 17 00:00:00 2001 From: Stefan Strigler Date: Mon, 7 Jul 2025 17:58:56 +0200 Subject: [PATCH 6/6] update p1/xmpp to latest --- mix.exs | 2 +- rebar.config | 2 +- rebar.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mix.exs b/mix.exs index 308d95c51..7a12a248a 100644 --- a/mix.exs +++ b/mix.exs @@ -130,7 +130,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp", ref: "fbaea1bfb4244e4287fe8449144e8e72d9a842d1", override: true}, + {:xmpp, git: "https://github.com/processone/xmpp", ref: "9b028c110083e4d979d88c286873d0abf08fa532", override: true}, {:yconf, ">= 1.0.18"}] ++ cond_deps() end diff --git a/rebar.config b/rebar.config index ad3b004c7..eb160ed8b 100644 --- a/rebar.config +++ b/rebar.config @@ -77,7 +77,7 @@ {stringprep, "~> 1.0.31", {git, "https://github.com/processone/stringprep", {tag, "1.0.31"}}}, {if_var_true, stun, {stun, "~> 1.2.17", {git, "https://github.com/processone/stun", {tag, "1.2.17"}}}}, - {xmpp, "~> 1.10.0", {git, "https://github.com/processone/xmpp", "fbaea1bfb4244e4287fe8449144e8e72d9a842d1"}}, + {xmpp, "~> 1.10.0", {git, "https://github.com/processone/xmpp", "9b028c110083e4d979d88c286873d0abf08fa532"}}, {yconf, "~> 1.0.18", {git, "https://github.com/processone/yconf", {tag, "1.0.18"}}} ]}. diff --git a/rebar.lock b/rebar.lock index 365d3fd3e..d4452766d 100644 --- a/rebar.lock +++ b/rebar.lock @@ -32,7 +32,7 @@ {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.1">>},1}, {<<"xmpp">>, {git,"https://github.com/processone/xmpp", - {ref,"fbaea1bfb4244e4287fe8449144e8e72d9a842d1"}}, + {ref,"9b028c110083e4d979d88c286873d0abf08fa532"}}, 0}, {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.18">>},0}]}. [