Switch to stand-alone XMPP library

This commit is contained in:
Evgeniy Khramtsov 2016-11-19 13:03:33 +03:00
parent d00a634025
commit 9aff7e52a8
55 changed files with 10 additions and 48194 deletions

View File

@ -108,14 +108,6 @@ edoc:
$(ERL) -noinput +B -eval \
'case edoc:application(ejabberd, ".", []) of ok -> halt(0); error -> halt(1) end.'
spec:
$(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \
'case fxml_gen:compile("specs/xmpp_codec.spec", [{add_type_specs, xmpp_element}, {erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.'
xdata:
$(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \
'case xdata_codec:compile("specs", [{erl_dir, "src"}, {hrl_dir, "include"}]) of ok -> halt(0); _ -> halt(1) end.'
JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1))
VERSIONED_DEP=$(if $(DEP_$(1)_VERSION),$(DEP_$(1)_VERSION),$(1))
@ -347,5 +339,5 @@ quicktest:
$(REBAR) skip_deps=true ct suites=elixir
.PHONY: src edoc dialyzer Makefile TAGS clean clean-rel distclean rel \
install uninstall uninstall-binary uninstall-all translations deps test spec \
install uninstall uninstall-binary uninstall-all translations deps test \
quicktest erlang_plt deps_plt ejabberd_plt

View File

@ -1,10 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: flex_offline.xdata
%% Form type: http://jabber.org/protocol/offline
%% Document: XEP-0013
-type property() :: {'number_of_messages', non_neg_integer()}.
-type result() :: [property()].
-type form() :: [property() | xdata_field()].

View File

@ -1,17 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2016, Evgeny Khramtsov
%%% @doc
%%%
%%% @end
%%% Created : 10 Jul 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
-record(jid, {user = <<"">> :: binary(),
server = <<"">> :: binary(),
resource = <<"">> :: binary(),
luser = <<"">> :: binary(),
lserver = <<"">> :: binary(),
lresource = <<"">> :: binary()}).
-type(jid() :: #jid{}).
-type(ljid() :: {binary(), binary(), binary()}).

View File

@ -1,13 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: mam_query.xdata
%% Form type: urn:xmpp:mam:1
%% Document: XEP-0313
-type property() :: {'with', jid:jid()} |
{'start', erlang:timestamp()} |
{'end', erlang:timestamp()} |
{'withtext', binary()}.
-type result() :: [property()].
-type form() :: [property() | xdata_field()].

View File

@ -1,16 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_register.xdata
%% Form type: http://jabber.org/protocol/muc#register
%% Document: XEP-0045
-type property() :: {'allow', boolean()} |
{'email', binary()} |
{'faqentry', [binary()]} |
{'first', binary()} |
{'last', binary()} |
{'roomnick', binary()} |
{'url', binary()}.
-type result() :: [property()].
-type form() :: [property() | xdata_field()].

View File

@ -1,16 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_request.xdata
%% Form type: http://jabber.org/protocol/muc#request
%% Document: XEP-0045
-type property() :: {'role', participant} |
{'jid', jid:jid()} |
{'roomnick', binary()} |
{'request_allow', boolean()}.
-type result() :: [property()].
-type options(T) :: [{binary(), T}].
-type property_with_options() ::
{'role', participant, options(participant)}.
-type form() :: [property() | property_with_options() | xdata_field()].

View File

@ -1,55 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_roomconfig.xdata
%% Form type: http://jabber.org/protocol/muc#roomconfig
%% Document: XEP-0045
-type 'allow_private_messages_from_visitors'() :: nobody | moderators | anyone.
-type 'maxusers'() :: none | non_neg_integer().
-type 'presencebroadcast'() :: moderator | participant | visitor.
-type 'whois'() :: moderators | anyone.
-type property() :: {'maxhistoryfetch', binary()} |
{'allowpm', binary()} |
{'allow_private_messages', boolean()} |
{'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'()} |
{'allow_visitor_status', boolean()} |
{'allow_visitor_nickchange', boolean()} |
{'allow_voice_requests', boolean()} |
{'allow_subscription', boolean()} |
{'voice_request_min_interval', non_neg_integer()} |
{'captcha_protected', boolean()} |
{'captcha_whitelist', [jid:jid()]} |
{'allow_query_users', boolean()} |
{'allowinvites', boolean()} |
{'changesubject', boolean()} |
{'enablelogging', boolean()} |
{'getmemberlist', [binary()]} |
{'lang', binary()} |
{'pubsub', binary()} |
{'maxusers', 'maxusers'()} |
{'membersonly', boolean()} |
{'moderatedroom', boolean()} |
{'members_by_default', boolean()} |
{'passwordprotectedroom', boolean()} |
{'persistentroom', boolean()} |
{'presencebroadcast', ['presencebroadcast'()]} |
{'publicroom', boolean()} |
{'public_list', boolean()} |
{'roomadmins', [jid:jid()]} |
{'roomdesc', binary()} |
{'roomname', binary()} |
{'roomowners', [jid:jid()]} |
{'roomsecret', binary()} |
{'whois', 'whois'()} |
{'mam', boolean()}.
-type result() :: [property()].
-type options(T) :: [{binary(), T}].
-type property_with_options() ::
{'allowpm', binary(), options(binary())} |
{'allow_private_messages_from_visitors', 'allow_private_messages_from_visitors'(), options('allow_private_messages_from_visitors'())} |
{'getmemberlist', [binary()], options(binary())} |
{'maxusers', 'maxusers'(), options('maxusers'())} |
{'presencebroadcast', ['presencebroadcast'()], options('presencebroadcast'())} |
{'whois', 'whois'(), options('whois'())}.
-type form() :: [property() | property_with_options() | xdata_field()].

View File

@ -1,18 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_roominfo.xdata
%% Form type: http://jabber.org/protocol/muc#roominfo
%% Document: XEP-0045
-type property() :: {'maxhistoryfetch', non_neg_integer()} |
{'contactjid', [jid:jid()]} |
{'description', binary()} |
{'lang', binary()} |
{'ldapgroup', binary()} |
{'logs', binary()} |
{'occupants', non_neg_integer()} |
{'subject', binary()} |
{'subjectmod', boolean()}.
-type result() :: [property()].
-type form() :: [property() | xdata_field()].

View File

@ -1,182 +0,0 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 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.
%%%
%%%----------------------------------------------------------------------
-define(NS_COMPONENT, <<"jabber:component:accept">>).
-define(NS_SERVER, <<"jabber:server">>).
-define(NS_SERVER_DIALBACK, <<"jabber:server:dialback">>).
-define(NS_CLIENT, <<"jabber:client">>).
-define(NS_DISCO_ITEMS,
<<"http://jabber.org/protocol/disco#items">>).
-define(NS_DISCO_INFO,
<<"http://jabber.org/protocol/disco#info">>).
-define(NS_VCARD, <<"vcard-temp">>).
-define(NS_VCARD_UPDATE, <<"vcard-temp:x:update">>).
-define(NS_AUTH, <<"jabber:iq:auth">>).
-define(NS_AUTH_ERROR, <<"jabber:iq:auth:error">>).
-define(NS_REGISTER, <<"jabber:iq:register">>).
-define(NS_SEARCH, <<"jabber:iq:search">>).
-define(NS_ROSTER, <<"jabber:iq:roster">>).
-define(NS_ROSTER_VER,
<<"urn:xmpp:features:rosterver">>).
-define(NS_PRIVACY, <<"jabber:iq:privacy">>).
-define(NS_BLOCKING, <<"urn:xmpp:blocking">>).
-define(NS_PRIVATE, <<"jabber:iq:private">>).
-define(NS_VERSION, <<"jabber:iq:version">>).
-define(NS_TIME, <<"urn:xmpp:time">>).
-define(NS_LAST, <<"jabber:iq:last">>).
-define(NS_XDATA, <<"jabber:x:data">>).
-define(NS_IQDATA, <<"jabber:iq:data">>).
-define(NS_DELAY, <<"urn:xmpp:delay">>).
-define(NS_HINTS, <<"urn:xmpp:hints">>).
-define(NS_EXPIRE, <<"jabber:x:expire">>).
-define(NS_EVENT, <<"jabber:x:event">>).
-define(NS_CHATSTATES,
<<"http://jabber.org/protocol/chatstates">>).
-define(NS_XCONFERENCE, <<"jabber:x:conference">>).
-define(NS_STATS,
<<"http://jabber.org/protocol/stats">>).
-define(NS_MUC, <<"http://jabber.org/protocol/muc">>).
-define(NS_MUC_USER,
<<"http://jabber.org/protocol/muc#user">>).
-define(NS_MUC_ADMIN,
<<"http://jabber.org/protocol/muc#admin">>).
-define(NS_MUC_OWNER,
<<"http://jabber.org/protocol/muc#owner">>).
-define(NS_MUC_UNIQUE,
<<"http://jabber.org/protocol/muc#unique">>).
-define(NS_PUBSUB,
<<"http://jabber.org/protocol/pubsub">>).
-define(NS_PUBSUB_EVENT,
<<"http://jabber.org/protocol/pubsub#event">>).
-define(NS_PUBSUB_META_DATA,
<<"http://jabber.org/protocol/pubsub#meta-data">>).
-define(NS_PUBSUB_OWNER,
<<"http://jabber.org/protocol/pubsub#owner">>).
-define(NS_PUBSUB_NMI,
<<"http://jabber.org/protocol/pubsub#node-meta-info">>).
-define(NS_PUBSUB_ERRORS,
<<"http://jabber.org/protocol/pubsub#errors">>).
-define(NS_PUBSUB_NODE_CONFIG,
<<"http://jabber.org/protocol/pubsub#node_config">>).
-define(NS_PUBSUB_SUB_OPTIONS,
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
-define(NS_PUBSUB_SUBSCRIBE_OPTIONS,
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
-define(NS_PUBSUB_PUBLISH_OPTIONS,
<<"http://jabber.org/protocol/pubsub#publish_options">>).
-define(NS_PUBSUB_SUB_AUTH,
<<"http://jabber.org/protocol/pubsub#subscribe_authorization">>).
-define(NS_PUBSUB_GET_PENDING,
<<"http://jabber.org/protocol/pubsub#get-pending">>).
-define(NS_COMMANDS,
<<"http://jabber.org/protocol/commands">>).
-define(NS_BYTESTREAMS,
<<"http://jabber.org/protocol/bytestreams">>).
-define(NS_ADMIN,
<<"http://jabber.org/protocol/admin">>).
-define(NS_ADMIN_ANNOUNCE,
<<"http://jabber.org/protocol/admin#announce">>).
-define(NS_ADMIN_ANNOUNCE_ALL,
<<"http://jabber.org/protocol/admin#announce-all">>).
-define(NS_ADMIN_SET_MOTD,
<<"http://jabber.org/protocol/admin#set-motd">>).
-define(NS_ADMIN_EDIT_MOTD,
<<"http://jabber.org/protocol/admin#edit-motd">>).
-define(NS_ADMIN_DELETE_MOTD,
<<"http://jabber.org/protocol/admin#delete-motd">>).
-define(NS_ADMIN_ANNOUNCE_ALLHOSTS,
<<"http://jabber.org/protocol/admin#announce-allhosts">>).
-define(NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS,
<<"http://jabber.org/protocol/admin#announce-all-allhosts">>).
-define(NS_ADMIN_SET_MOTD_ALLHOSTS,
<<"http://jabber.org/protocol/admin#set-motd-allhosts">>).
-define(NS_ADMIN_EDIT_MOTD_ALLHOSTS,
<<"http://jabber.org/protocol/admin#edit-motd-allhosts">>).
-define(NS_ADMIN_DELETE_MOTD_ALLHOSTS,
<<"http://jabber.org/protocol/admin#delete-motd-allhosts">>).
-define(NS_SERVERINFO,
<<"http://jabber.org/network/serverinfo">>).
-define(NS_RSM, <<"http://jabber.org/protocol/rsm">>).
-define(NS_EJABBERD_CONFIG, <<"ejabberd:config">>).
-define(NS_STREAM,
<<"http://etherx.jabber.org/streams">>).
-define(NS_STANZAS,
<<"urn:ietf:params:xml:ns:xmpp-stanzas">>).
-define(NS_STREAMS,
<<"urn:ietf:params:xml:ns:xmpp-streams">>).
-define(NS_TLS, <<"urn:ietf:params:xml:ns:xmpp-tls">>).
-define(NS_SASL,
<<"urn:ietf:params:xml:ns:xmpp-sasl">>).
-define(NS_SESSION,
<<"urn:ietf:params:xml:ns:xmpp-session">>).
-define(NS_BIND,
<<"urn:ietf:params:xml:ns:xmpp-bind">>).
-define(NS_FEATURE_IQAUTH,
<<"http://jabber.org/features/iq-auth">>).
-define(NS_FEATURE_IQREGISTER,
<<"http://jabber.org/features/iq-register">>).
-define(NS_FEATURE_COMPRESS,
<<"http://jabber.org/features/compress">>).
-define(NS_FEATURE_MSGOFFLINE, <<"msgoffline">>).
-define(NS_FLEX_OFFLINE, <<"http://jabber.org/protocol/offline">>).
-define(NS_COMPRESS,
<<"http://jabber.org/protocol/compress">>).
-define(NS_CAPS, <<"http://jabber.org/protocol/caps">>).
-define(NS_SHIM, <<"http://jabber.org/protocol/shim">>).
-define(NS_ADDRESS,
<<"http://jabber.org/protocol/address">>).
-define(NS_OOB, <<"jabber:x:oob">>).
-define(NS_CAPTCHA, <<"urn:xmpp:captcha">>).
-define(NS_MEDIA, <<"urn:xmpp:media-element">>).
-define(NS_BOB, <<"urn:xmpp:bob">>).
-define(NS_MAM_TMP, <<"urn:xmpp:mam:tmp">>).
-define(NS_MAM_0, <<"urn:xmpp:mam:0">>).
-define(NS_MAM_1, <<"urn:xmpp:mam:1">>).
-define(NS_SID_0, <<"urn:xmpp:sid:0">>).
-define(NS_PING, <<"urn:xmpp:ping">>).
-define(NS_CARBONS_2, <<"urn:xmpp:carbons:2">>).
-define(NS_CARBONS_1, <<"urn:xmpp:carbons:1">>).
-define(NS_FORWARD, <<"urn:xmpp:forward:0">>).
-define(NS_CLIENT_STATE, <<"urn:xmpp:csi:0">>).
-define(NS_STREAM_MGMT_2, <<"urn:xmpp:sm:2">>).
-define(NS_STREAM_MGMT_3, <<"urn:xmpp:sm:3">>).
-define(NS_HTTP_UPLOAD, <<"urn:xmpp:http:upload">>).
-define(NS_HTTP_UPLOAD_OLD, <<"eu:siacs:conversations:http:upload">>).
-define(NS_THUMBS_1, <<"urn:xmpp:thumbs:1">>).
-define(NS_NICK, <<"http://jabber.org/protocol/nick">>).
-define(NS_SIC_0, <<"urn:xmpp:sic:0">>).
-define(NS_SIC_1, <<"urn:xmpp:sic:1">>).
-define(NS_MIX_0, <<"urn:xmpp:mix:0">>).
-define(NS_MIX_SERVICEINFO_0, <<"urn:xmpp:mix:0#serviceinfo">>).
-define(NS_MIX_NODES_MESSAGES, <<"urn:xmpp:mix:nodes:messages">>).
-define(NS_MIX_NODES_PRESENCE, <<"urn:xmpp:mix:nodes:presence">>).
-define(NS_MIX_NODES_PARTICIPANTS, <<"urn:xmpp:mix:nodes:participants">>).
-define(NS_MIX_NODES_SUBJECT, <<"urn:xmpp:mix:nodes:subject">>).
-define(NS_MIX_NODES_CONFIG, <<"urn:xmpp:mix:nodes:config">>).
-define(NS_PRIVILEGE, <<"urn:xmpp:privilege:1">>).
-define(NS_DELEGATION, <<"urn:xmpp:delegation:1">>).
-define(NS_MUCSUB, <<"urn:xmpp:mucsub:0">>).
-define(NS_MUCSUB_NODES_PRESENCE, <<"urn:xmpp:mucsub:nodes:presence">>).
-define(NS_MUCSUB_NODES_MESSAGES, <<"urn:xmpp:mucsub:nodes:messages">>).
-define(NS_MUCSUB_NODES_PARTICIPANTS, <<"urn:xmpp:mucsub:nodes:participants">>).
-define(NS_MUCSUB_NODES_AFFILIATIONS, <<"urn:xmpp:mucsub:nodes:affiliations">>).
-define(NS_MUCSUB_NODES_SUBJECT, <<"urn:xmpp:mucsub:nodes:subject">>).
-define(NS_MUCSUB_NODES_CONFIG, <<"urn:xmpp:mucsub:nodes:config">>).
-define(NS_MUCSUB_NODES_SYSTEM, <<"urn:xmpp:mucsub:nodes:system">>).

View File

@ -1,13 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_get_pending.xdata
%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization
%% Document: XEP-0060
-type property() :: {'node', binary()}.
-type result() :: [property()].
-type options(T) :: [{binary(), T}].
-type property_with_options() ::
{'node', binary(), options(binary())}.
-type form() :: [property() | property_with_options() | xdata_field()].

View File

@ -1,60 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_node_config.xdata
%% Form type: http://jabber.org/protocol/pubsub#node_config
%% Document: XEP-0060
-type 'access_model'() :: authorize | open | presence | roster | whitelist.
-type 'children_association_policy'() :: all | owners | whitelist.
-type 'itemreply'() :: owner | publisher | none.
-type 'node_type'() :: leaf | collection.
-type 'notification_type'() :: normal | headline.
-type 'publish_model'() :: publishers | subscribers | open.
-type 'send_last_published_item'() :: never | on_sub | on_sub_and_presence.
-type property() :: {'access_model', 'access_model'()} |
{'body_xslt', binary()} |
{'children_association_policy', 'children_association_policy'()} |
{'children_association_whitelist', [jid:jid()]} |
{'children', [binary()]} |
{'children_max', binary()} |
{'collection', [binary()]} |
{'contact', [jid:jid()]} |
{'dataform_xslt', binary()} |
{'deliver_notifications', boolean()} |
{'deliver_payloads', boolean()} |
{'description', binary()} |
{'item_expire', binary()} |
{'itemreply', 'itemreply'()} |
{'language', binary()} |
{'max_items', non_neg_integer()} |
{'max_payload_size', non_neg_integer()} |
{'node_type', 'node_type'()} |
{'notification_type', 'notification_type'()} |
{'notify_config', boolean()} |
{'notify_delete', boolean()} |
{'notify_retract', boolean()} |
{'notify_sub', boolean()} |
{'persist_items', boolean()} |
{'presence_based_delivery', boolean()} |
{'publish_model', 'publish_model'()} |
{'purge_offline', boolean()} |
{'roster_groups_allowed', [binary()]} |
{'send_last_published_item', 'send_last_published_item'()} |
{'tempsub', boolean()} |
{'subscribe', boolean()} |
{'title', binary()} |
{'type', binary()}.
-type result() :: [property()].
-type options(T) :: [{binary(), T}].
-type property_with_options() ::
{'access_model', 'access_model'(), options('access_model'())} |
{'children_association_policy', 'children_association_policy'(), options('children_association_policy'())} |
{'itemreply', 'itemreply'(), options('itemreply'())} |
{'language', binary(), options(binary())} |
{'node_type', 'node_type'(), options('node_type'())} |
{'notification_type', 'notification_type'(), options('notification_type'())} |
{'publish_model', 'publish_model'(), options('publish_model'())} |
{'roster_groups_allowed', [binary()], options(binary())} |
{'send_last_published_item', 'send_last_published_item'(), options('send_last_published_item'())}.
-type form() :: [property() | property_with_options() | xdata_field()].

View File

@ -1,14 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_publish_options.xdata
%% Form type: http://jabber.org/protocol/pubsub#publish-options
%% Document: XEP-0060
-type 'access_model'() :: authorize | open | presence | roster | whitelist.
-type property() :: {'access_model', 'access_model'()}.
-type result() :: [property()].
-type options(T) :: [{binary(), T}].
-type property_with_options() ::
{'access_model', 'access_model'(), options('access_model'())}.
-type form() :: [property() | property_with_options() | xdata_field()].

View File

@ -1,13 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_subscribe_authorization.xdata
%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization
%% Document: XEP-0060
-type property() :: {'allow', boolean()} |
{'node', binary()} |
{'subscriber_jid', jid:jid()} |
{'subid', binary()}.
-type result() :: [property()].
-type form() :: [property() | xdata_field()].

View File

@ -1,25 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_subscribe_options.xdata
%% Form type: http://jabber.org/protocol/pubsub#subscribe_options
%% Document: XEP-0060
-type 'show-values'() :: away | chat | dnd | online | xa.
-type 'subscription_type'() :: items | nodes.
-type 'subscription_depth'() :: 1 | all.
-type property() :: {'deliver', boolean()} |
{'digest', boolean()} |
{'digest_frequency', binary()} |
{'expire', binary()} |
{'include_body', boolean()} |
{'show-values', ['show-values'()]} |
{'subscription_type', 'subscription_type'()} |
{'subscription_depth', 'subscription_depth'()}.
-type result() :: [property()].
-type options(T) :: [{binary(), T}].
-type property_with_options() ::
{'show-values', ['show-values'()], options('show-values'())} |
{'subscription_type', 'subscription_type'(), options('subscription_type'())} |
{'subscription_depth', 'subscription_depth'(), options('subscription_depth'())}.
-type form() :: [property() | property_with_options() | xdata_field()].

View File

@ -1,25 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2015, Evgeny Khramtsov
%%% @doc
%%%
%%% @end
%%% Created : 10 Dec 2015 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
-include("ns.hrl").
-include("jid.hrl").
-include("xmpp_codec.hrl").
-include("fxml.hrl").
-type iq_type() :: get | set | result | error.
-type message_type() :: chat | error | groupchat | headline | normal.
-type presence_type() :: available | error | probe | subscribe |
subscribed | unavailable | unsubscribe |
unsubscribed.
-type stanza() :: iq() | presence() | message().
-define(is_stanza(Pkt),
(is_record(Pkt, iq) or
is_record(Pkt, message) or
is_record(Pkt, presence))).

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.7"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.6"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.16"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.0.2"}}},
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.7"}}},
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.8"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.6"}}},
@ -55,6 +56,7 @@
luerl,
stun,
fast_yaml,
xmpp,
p1_utils,
p1_mysql,
p1_pgsql,
@ -65,7 +67,9 @@
{erl_first_files, ["src/ejabberd_config.erl", "src/gen_mod.erl"]}.
{erl_opts, [nowarn_deprecated_function,
{i, "include"}, {i, "deps/fast_xml/include"},
{i, "include"},
{i, "deps/fast_xml/include"},
{i, "deps/xmpp/include"},
{if_var_false, debug, no_debug_info},
{if_var_true, debug, debug_info},
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
@ -113,8 +117,10 @@
{if_var_false, elixir, "(\"Elixir.*\":_/_)"},
{if_var_false, redis, "(\"eredis\":_/_)"}]}.
{eunit_compile_opts, [{i, "tools"}, {i, "include"},
{i, "deps/fast_xml/include"}]}.
{eunit_compile_opts, [{i, "tools"},
{i, "include"},
{i, "deps/fast_xml/include"},
{i, "deps/xmpp/include"}]}.
{if_version_above, "17", {cover_enabled, true}}.
{cover_export_enabled, true}.

View File

@ -1 +0,0 @@
[{decode, [{<<"number_of_messages">>, {dec_int, [0, infinity]}}]}].

View File

@ -1,12 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/offline</name>
<doc>XEP-0013</doc>
<desc>
Service Discovery extension for number of messages
in an offline message queue.
</desc>
<field
var='number_of_messages'
type='text-single'
label='Number of Offline Messages'/>
</form_type>

View File

@ -1,9 +0,0 @@
[{decode, [{<<"start">>, {xmpp_util, decode_timestamp, []}},
{<<"end">>, {xmpp_util, decode_timestamp, []}}]},
{specs, [{<<"start">>, "erlang:timestamp()"},
{<<"end">>, "erlang:timestamp()"}]}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,23 +0,0 @@
<form_type>
<name>urn:xmpp:mam:1</name>
<doc>XEP-0313</doc>
<desc>Form to query message archives</desc>
<field var='with'
type='jid-single'
label='User JID'/>
<field var='start'
type='text-single'
label='Search from the date'/>
<field var='end'
type='text-single'
label='Search until the date'/>
<field var='withtext'
type='text-single'
label='Search the text'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,2 +0,0 @@
[{prefix, <<"muc#register_">>},
{required, [<<"muc#register_roomnick">>]}].

View File

@ -1,37 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/muc#register</name>
<doc>XEP-0045</doc>
<desc>
Forms enabling user registration with a
Multi-User Chat (MUC) room or admin approval
of user registration requests.
</desc>
<field
var='muc#register_allow'
type='boolean'
label='Allow this person to register with the room?'/>
<field
var='muc#register_email'
type='text-single'
label='Email Address'/>
<field
var='muc#register_faqentry'
type='text-multi'
label='FAQ Entry'/>
<field
var='muc#register_first'
type='text-single'
label='Given Name'/>
<field
var='muc#register_last'
type='text-single'
label='Family Name'/>
<field
var='muc#register_roomnick'
type='text-single'
label='Nickname'/>
<field
var='muc#register_url'
type='text-single'
label='A Web Page'/>
</form_type>

View File

@ -1,2 +0,0 @@
[{prefix, <<"muc#">>},
{required, [<<"muc#role">>]}].

View File

@ -1,31 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/muc#request</name>
<doc>XEP-0045</doc>
<desc>
Forms enabling voice requests in a
Multi-User Chat (MUC) room or admin
approval of such requests.
</desc>
<field var='muc#role'
type='list-single'
label='Requested role'>
<option label='Participant'>
<value>participant</value>
</option>
</field>
<field var='muc#jid'
type='jid-single'
label='User JID'/>
<field var='muc#roomnick'
type='text-single'
label='Nickname'/>
<field var='muc#request_allow'
type='boolean'
label='Grant voice to this person?'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,11 +0,0 @@
[{prefix, <<"muc#roomconfig_">>},
{prefix, <<"muc#">>},
{decode, [{<<"muc#roomconfig_maxusers">>,
{dec_enum_int, [[none], 0, infinity]}},
{<<"voice_request_min_interval">>,
{dec_int, [0, infinity]}}]}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,192 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/muc#roomconfig</name>
<doc>XEP-0045</doc>
<desc>
Forms enabling creation and configuration of
a Multi-User Chat (MUC) room.
</desc>
<field
var='muc#maxhistoryfetch'
type='text-single'
label='Maximum Number of History Messages Returned by Room'/>
<field
var='muc#roomconfig_allowpm'
type='list-single'
label='Roles that May Send Private Messages'/>
<field
var='allow_private_messages'
type='boolean'
label='Allow users to send private messages'/>
<field
var='allow_private_messages_from_visitors'
type='list-single'
label='Allow visitors to send private messages to'>
<option label='nobody'>
<value>nobody</value>
</option>
<option label='moderators only'>
<value>moderators</value>
</option>
<option label='anyone'>
<value>anyone</value>
</option>
</field>
<field
var='allow_visitor_status'
type='boolean'
label='Allow visitors to send status text in presence updates'/>
<field
var='allow_visitor_nickchange'
type='boolean'
label='Allow visitors to change nickname'/>
<field
var='allow_voice_requests'
type='boolean'
label='Allow visitors to send voice requests'/>
<field
var='allow_subscription'
type='boolean'
label='Allow subscription'/>
<field
var='voice_request_min_interval'
type='text-single'
label='Minimum interval between voice requests (in seconds)'/>
<field
var='captcha_protected'
type='boolean'
label='Make room CAPTCHA protected'/>
<field
var='captcha_whitelist'
type='jid-multi'
label='Exclude Jabber IDs from CAPTCHA challenge'/>
<field
var='allow_query_users'
type='boolean'
label='Allow users to query other users'/>
<field
var='muc#roomconfig_allowinvites'
type='boolean'
label='Allow users to send invites'/>
<field
var='muc#roomconfig_changesubject'
type='boolean'
label='Allow users to change the subject'/>
<field
var='muc#roomconfig_enablelogging'
type='boolean'
label='Enable logging'/>
<field
var='muc#roomconfig_getmemberlist'
type='list-multi'
label='Roles and Affiliations that May Retrieve Member List'/>
<field
var='muc#roomconfig_lang'
type='text-single'
label='Natural Language for Room Discussions'/>
<field
var='muc#roomconfig_pubsub'
type='text-single'
label='XMPP URI of Associated Publish-Subscribe Node'/>
<field
var='muc#roomconfig_maxusers'
type='list-single'
label='Maximum Number of Occupants'>
<option label='No limit'>
<value>none</value>
</option>
<option><value>5</value></option>
<option><value>10</value></option>
<option><value>20</value></option>
<option><value>30</value></option>
<option><value>50</value></option>
<option><value>100</value></option>
<option><value>200</value></option>
<option><value>500</value></option>
<option><value>1000</value></option>
<option><value>2000</value></option>
<option><value>5000</value></option>
</field>
<field
var='muc#roomconfig_membersonly'
type='boolean'
label='Make room members-only'/>
<field
var='muc#roomconfig_moderatedroom'
type='boolean'
label='Make room moderated'/>
<field
var='members_by_default'
type='boolean'
label='Default users as participants'/>
<field
var='muc#roomconfig_passwordprotectedroom'
type='boolean'
label='Make room password protected'/>
<field
var='muc#roomconfig_persistentroom'
type='boolean'
label='Make room persistent'/>
<field
var='muc#roomconfig_presencebroadcast'
type='list-multi'
label='Roles for which Presence is Broadcasted'>
<option label='Moderator'>
<value>moderator</value>
</option>
<option label='Participant'>
<value>participant</value>
</option>
<option label='Visitor'>
<value>visitor</value>
</option>
</field>
<field
var='muc#roomconfig_publicroom'
type='boolean'
label='Make room public searchable'/>
<field
var='public_list'
type='boolean'
label='Make participants list public'/>
<field
var='muc#roomconfig_roomadmins'
type='jid-multi'
label='Full List of Room Admins'/>
<field
var='muc#roomconfig_roomdesc'
type='text-single'
label='Room description'/>
<field
var='muc#roomconfig_roomname'
type='text-single'
label='Room title'/>
<field
var='muc#roomconfig_roomowners'
type='jid-multi'
label='Full List of Room Owners'/>
<field
var='muc#roomconfig_roomsecret'
type='text-private'
label='Password'/>
<field
var='muc#roomconfig_whois'
type='list-single'
label='Present real Jabber IDs to'>
<option label='moderators only'>
<value>moderators</value>
</option>
<option label='anyone'>
<value>anyone</value>
</option>
</field>
<field
var='mam'
type='boolean'
label='Enable message archiving'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,11 +0,0 @@
[{prefix, <<"muc#roominfo_">>},
{prefix, <<"muc#">>},
{decode, [{<<"muc#maxhistoryfetch">>,
{dec_int, [0, infinity]}},
{<<"muc#roominfo_occupants">>,
{dec_int, [0, infinity]}}]}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,55 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/muc#roominfo</name>
<doc>XEP-0045</doc>
<desc>
Forms enabling the communication of extended service discovery
information about a Multi-User Chat (MUC) room.
</desc>
<field
var='muc#maxhistoryfetch'
type='text-single'
label='Maximum Number of History Messages Returned by Room'/>
<field
var='muc#roominfo_contactjid'
type='jid-multi'
label='Contact Addresses (normally, room owner or owners)'/>
<field
var='muc#roominfo_description'
type='text-single'
label='Room description'/>
<field
var='muc#roominfo_lang'
type='text-single'
label='Natural Language for Room Discussions'/>
<field
var='muc#roominfo_ldapgroup'
type='text-single'
label='An associated LDAP group that defines
room membership; this should be an LDAP
Distinguished Name according to an
implementation-specific or
deployment-specific definition of a
group.'/>
<field
var='muc#roominfo_logs'
type='text-single'
label='URL for Archived Discussion Logs'/>
<field
var='muc#roominfo_occupants'
type='text-single'
label='Number of occupants'/>
<field
var='muc#roominfo_subject'
type='text-single'
label='Current Discussion Topic'/>
<field
var='muc#roominfo_subjectmod'
type='boolean'
label='The room subject can be modified by participants'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,7 +0,0 @@
[{prefix, <<"pubsub#">>},
{required, [<<"pubsub#node">>]}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,15 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/pubsub#subscribe_authorization</name>
<doc>XEP-0060</doc>
<desc>Forms enabling authorization of subscriptions to pubsub nodes</desc>
<field
var='pubsub#node'
type='list-single'
label='The NodeID of the relevant node'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,8 +0,0 @@
[{prefix, <<"pubsub#">>},
{decode, [{<<"pubsub#max_items">>, {dec_int, [0,infinity]}},
{<<"pubsub#max_payload_size">>, {dec_int, [0,infinity]}}]}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,189 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/pubsub#node_config</name>
<doc>XEP-0060</doc>
<desc>Forms enabling configuration of pubsub nodes</desc>
<field var='pubsub#access_model'
type='list-single'
label='Specify the access model'>
<option label='Subscription requests must be approved and only subscribers may retrieve items'>
<value>authorize</value>
</option>
<option label='Anyone may subscribe and retrieve items'>
<value>open</value>
</option>
<option label='Anyone with a presence subscription of both or from may subscribe and retrieve items'>
<value>presence</value>
</option>
<option label='Anyone in the specified roster group(s) may subscribe and retrieve items'>
<value>roster</value>
</option>
<option label='Only those on a whitelist may subscribe and retrieve items'>
<value>whitelist</value>
</option>
</field>
<field var='pubsub#body_xslt'
type='text-single'
label='The URL of an XSL transformation which can be
applied to payloads in order to generate an
appropriate message body element.'/>
<field var='pubsub#children_association_policy'
type='list-single'
label='Who may associate leaf nodes with a collection'>
<option label='Anyone may associate leaf nodes with the collection'>
<value>all</value>
</option>
<option label='Only collection node owners may associate leaf nodes with the collection'>
<value>owners</value>
</option>
<option label='Only those on a whitelist may associate leaf nodes with the collection'>
<value>whitelist</value>
</option>
</field>
<field var='pubsub#children_association_whitelist'
type='jid-multi'
label='The list of JIDs that may associate leaf nodes with a collection'/>
<field var='pubsub#children'
type='text-multi'
label='The child nodes (leaf or collection) associated with a collection'/>
<field var='pubsub#children_max'
type='text-single'
label='The maximum number of child nodes that can be associated with a collection'/>
<field var='pubsub#collection'
type='text-multi'
label='The collections with which a node is affiliated'/>
<field var='pubsub#contact'
type='jid-multi'
label='The JIDs of those to contact with questions'/>
<field var='pubsub#dataform_xslt'
type='text-single'
label='The URL of an XSL transformation which can be
applied to the payload format in order to generate
a valid Data Forms result that the client could
display using a generic Data Forms rendering
engine'/>
<field var='pubsub#deliver_notifications' type='boolean'
label='Deliver event notifications'>
<value>true</value>
</field>
<field var='pubsub#deliver_payloads'
type='boolean'
label='Deliver payloads with event notifications'/>
<field var='pubsub#description'
type='text-single'
label='A description of the node'/>
<field var='pubsub#item_expire'
type='text-single'
label='Number of seconds after which to automatically purge items'/>
<field var='pubsub#itemreply'
type='list-single'
label='Whether owners or publisher should receive replies to items'>
<option label='Statically specify a replyto of the node owner(s)'>
<value>owner</value>
</option>
<option label='Dynamically specify a replyto of the item publisher'>
<value>publisher</value>
</option>
<option>
<value>none</value>
</option>
</field>
<field var='pubsub#language'
type='list-single'
label='The default language of the node'/>
<field var='pubsub#max_items'
type='text-single'
label='Max # of items to persist'>
</field>
<field var='pubsub#max_payload_size'
type='text-single'
label='Max payload size in bytes'/>
<field var='pubsub#node_type'
type='list-single'
label='Whether the node is a leaf (default) or a collection'>
<option label='The node is a leaf node (default)'>
<value>leaf</value>
</option>
<option label='The node is a collection node'>
<value>collection</value>
</option>
</field>
<field var='pubsub#notification_type' type='list-single'
label='Specify the event message type'>
<option label='Messages of type normal'>
<value>normal</value>
</option>
<option label='Messages of type headline'>
<value>headline</value>
</option>
</field>
<field var='pubsub#notify_config'
type='boolean'
label='Notify subscribers when the node configuration changes'/>
<field var='pubsub#notify_delete'
type='boolean'
label='Notify subscribers when the node is deleted'/>
<field var='pubsub#notify_retract'
type='boolean'
label='Notify subscribers when items are removed from the node'/>
<field var='pubsub#notify_sub'
type='boolean'
label='Whether to notify owners about new subscribers and unsubscribes'/>
<field var='pubsub#persist_items'
type='boolean'
label='Persist items to storage'/>
<field var='pubsub#presence_based_delivery'
type='boolean'
label='Only deliver notifications to available users'/>
<field var='pubsub#publish_model'
type='list-single'
label='Specify the publisher model'>
<option label='Only publishers may publish'>
<value>publishers</value>
</option>
<option label='Subscribers may publish'>
<value>subscribers</value>
</option>
<option label='Anyone may publish'>
<value>open</value>
</option>
</field>
<field var='pubsub#purge_offline'
type='boolean'
label='Purge all items when the relevant publisher goes offline'/>
<field var='pubsub#roster_groups_allowed'
type='list-multi'
label='Roster groups allowed to subscribe'/>
<field var='pubsub#send_last_published_item'
type='list-single'
label='When to send the last published item'>
<option label='Never'>
<value>never</value>
</option>
<option label='When a new subscription is processed'>
<value>on_sub</value>
</option>
<option label='When a new subscription is processed and whenever a subscriber comes online'>
<value>on_sub_and_presence</value>
</option>
</field>
<field var='pubsub#tempsub'
type='boolean'
label='Whether to make all subscriptions temporary, based on subscriber presence'/>
<field var='pubsub#subscribe' type='boolean'
label='Whether to allow subscriptions'>
<value>1</value>
</field>
<field var='pubsub#title'
type='text-single'
label='A friendly name for the node'/>
<field var='pubsub#type'
type='text-single'
label='The type of node data, usually specified by
the namespace of the payload (if any)'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,6 +0,0 @@
[{prefix, <<"pubsub#">>}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,34 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/pubsub#publish-options</name>
<doc>XEP-0060</doc>
<desc>
Forms enabling publication with options; each field must specify whether it
defines METADATA to be attached to the item, a per-item OVERRIDE of the node
configuration, or a PRECONDITION to be checked against the node configuration.
</desc>
<field var='pubsub#access_model'
type='list-single'
label='Specify the access model'>
<option label='Access model of authorize'>
<value>authorize</value>
</option>
<option label='Access model of open'>
<value>open</value>
</option>
<option label='Access model of presence'>
<value>presence</value>
</option>
<option label='Access model of roster'>
<value>roster</value>
</option>
<option label='Access model of whitelist'>
<value>whitelist</value>
</option>
</field>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1,7 +0,0 @@
[{prefix, <<"pubsub#">>},
{required, [<<"pubsub#node">>, <<"pubsub#subscriber_jid">>, <<"pubsub#allow">>]}].
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8:

View File

@ -1,27 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/pubsub#subscribe_authorization</name>
<doc>XEP-0060</doc>
<desc>Forms enabling authorization of subscriptions to pubsub nodes</desc>
<field
var='pubsub#allow'
type='boolean'
label='Allow this Jabber ID to subscribe to this pubsub node?'/>
<field
var='pubsub#node'
type='text-single'
label='Node ID'/>
<field
var='pubsub#subscriber_jid'
type='jid-single'
label='Subscriber Address'/>
<field
var='pubsub#subid'
type='text-single'
label='The subscription identifier associated with the subscription request'/>
</form_type>
<!--
Local Variables:
mode: xml
End:
-->

View File

@ -1 +0,0 @@
[{prefix, <<"pubsub#">>}].

View File

@ -1,70 +0,0 @@
<form_type>
<name>http://jabber.org/protocol/pubsub#subscribe_options</name>
<doc>XEP-0060</doc>
<desc>Forms enabling configuration of subscription options for pubsub nodes</desc>
<field
var='pubsub#deliver'
type='boolean'
label='Whether an entity wants to receive
or disable notifications'/>
<field
var='pubsub#digest'
type='boolean'
label='Whether an entity wants to receive digests
(aggregations) of notifications or all
notifications individually'/>
<field var='pubsub#digest_frequency'
type='text-single'
label='The minimum number of milliseconds between
sending any two notification digests'/>
<field
var='pubsub#expire'
type='text-single'
label='The DateTime at which a leased subscription
will end or has ended'/>
<field
var='pubsub#include_body'
type='boolean'
label='Whether an entity wants to receive an XMPP
message body in addition to the payload
format'/>
<field
var='pubsub#show-values'
type='list-multi'
label='The presence states for which an entity
wants to receive notifications'>
<option label='XMPP Show Value of Away'>
<value>away</value>
</option>
<option label='XMPP Show Value of Chat'>
<value>chat</value>
</option>
<option label='XMPP Show Value of DND (Do Not Disturb)'>
<value>dnd</value>
</option>
<option label='Mere Availability in XMPP (No Show Value)'>
<value>online</value>
</option>
<option label='XMPP Show Value of XA (Extended Away)'>
<value>xa</value>
</option>
</field>
<field var='pubsub#subscription_type'
type='list-single'>
<option label='Receive notification of new items only'>
<value>items</value>
</option>
<option label='Receive notification of new nodes only'>
<value>nodes</value>
</option>
</field>
<field var='pubsub#subscription_depth'
type='list-single'>
<option label='Receive notification from direct child nodes only'>
<value>1</value>
</option>
<option label='Receive notification from all descendent nodes'>
<value>all</value>
</option>
</field>
</form_type>

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: flex_offline.xdata
%% Form type: http://jabber.org/protocol/offline
%% Document: XEP-0013
-module(flex_offline).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("flex_offline.hrl").
-export_type([property/0, result/0, form/0]).
dec_int(Val, Min, Max) ->
case list_to_integer(binary_to_list(Val)) of
Int when Int =< Max, Min == infinity -> Int;
Int when Int =< Max, Int >= Min -> Int
end.
enc_int(Int) -> integer_to_binary(Int).
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, []);
#xdata_field{values =
[<<"http://jabber.org/protocol/offline">>]} ->
decode(Fs, Acc, []);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/offline">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{number_of_messages, Val} ->
[encode_number_of_messages(Val, Translate)];
{number_of_messages, _, _} ->
erlang:error({badarg, Opt});
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/offline">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"number_of_messages">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_int(Value, 0, infinity) of
Result ->
decode(Fs, [{number_of_messages, Result} | Acc],
lists:delete(<<"number_of_messages">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"number_of_messages">>,
<<"http://jabber.org/protocol/offline">>}})
end;
decode([#xdata_field{var = <<"number_of_messages">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"number_of_messages">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"number_of_messages">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"number_of_messages">>,
<<"http://jabber.org/protocol/offline">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/offline">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/offline">>}});
decode([], Acc, []) -> Acc.
encode_number_of_messages(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_int(Value)]
end,
Opts = [],
#xdata_field{var = <<"number_of_messages">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Number of Offline Messages">>)}.

View File

@ -1,266 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% @doc
%%% JID processing library
%%% @end
%%% Created : 24 Nov 2015 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 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(jid).
%% API
-export([start/0,
make/1,
make/2,
make/3,
split/1,
from_string/1,
to_string/1,
is_nodename/1,
nodeprep/1,
nameprep/1,
resourceprep/1,
tolower/1,
remove_resource/1,
replace_resource/2]).
-include("jid.hrl").
-export_type([jid/0]).
-export_type([ljid/0]).
%%%===================================================================
%%% API
%%%===================================================================
-spec start() -> ok.
start() ->
{ok, Owner} = ets_owner(),
SplitPattern = binary:compile_pattern([<<"@">>, <<"/">>]),
%% Table is public to allow ETS insert to fix / update the table even if table already exist
%% with another owner.
catch ets:new(jlib, [named_table, public, set, {keypos, 1}, {heir, Owner, undefined}]),
ets:insert(jlib, {string_to_jid_pattern, SplitPattern}),
ok.
ets_owner() ->
case whereis(jlib_ets) of
undefined ->
Pid = spawn(fun() -> ets_keepalive() end),
case catch register(jlib_ets, Pid) of
true ->
{ok, Pid};
Error -> Error
end;
Pid ->
{ok,Pid}
end.
%% Process used to keep jlib ETS table alive in case the original owner dies.
%% The table need to be public, otherwise subsequent inserts would fail.
ets_keepalive() ->
receive
_ ->
ets_keepalive()
end.
-spec make(binary(), binary(), binary()) -> jid() | error.
make(User, Server, Resource) ->
case nodeprep(User) of
error -> error;
LUser ->
case nameprep(Server) of
error -> error;
LServer ->
case resourceprep(Resource) of
error -> error;
LResource ->
#jid{user = User, server = Server, resource = Resource,
luser = LUser, lserver = LServer,
lresource = LResource}
end
end
end.
-spec make(binary(), binary()) -> jid() | error.
make(User, Server) ->
make(User, Server, <<"">>).
-spec make({binary(), binary(), binary()} | binary()) -> jid() | error.
make({User, Server, Resource}) ->
make(User, Server, Resource);
make(Server) ->
make(<<"">>, Server, <<"">>).
%% This is the reverse of make_jid/1
-spec split(jid()) -> {binary(), binary(), binary()} | error.
split(#jid{user = U, server = S, resource = R}) ->
{U, S, R};
split(_) ->
error.
-spec from_string(binary() | string()) -> jid() | error.
from_string(S) when is_list(S) ->
%% We do not accept list because we want to enforce good practice of
%% using binaries for string. However, we do not let it crash to avoid
%% losing associated ets table.
{error, need_jid_as_binary};
from_string(<<>>) ->
error;
from_string(S) when is_binary(S) ->
SplitPattern = ets:lookup_element(jlib, string_to_jid_pattern, 2),
Size = size(S),
End = Size-1,
case binary:match(S, SplitPattern) of
{0, _} ->
error;
{End, _} ->
error;
{Pos1, _} ->
case binary:at(S, Pos1) of
$/ ->
make(<<>>,
binary:part(S, 0, Pos1),
binary:part(S, Pos1+1, Size-Pos1-1));
_ ->
Pos1N = Pos1+1,
case binary:match(S, SplitPattern, [{scope, {Pos1+1, Size-Pos1-1}}]) of
{End, _} ->
error;
{Pos1N, _} ->
error;
{Pos2, _} ->
case binary:at(S, Pos2) of
$/ ->
make(binary:part(S, 0, Pos1),
binary:part(S, Pos1+1, Pos2-Pos1-1),
binary:part(S, Pos2+1, Size-Pos2-1));
_ -> error
end;
_ ->
make(binary:part(S, 0, Pos1),
binary:part(S, Pos1+1, Size-Pos1-1),
<<>>)
end
end;
_ ->
make(<<>>, S, <<>>)
end.
-spec to_string(jid() | ljid()) -> binary().
to_string(#jid{user = User, server = Server,
resource = Resource}) ->
to_string({User, Server, Resource});
to_string({N, S, R}) ->
Node = iolist_to_binary(N),
Server = iolist_to_binary(S),
Resource = iolist_to_binary(R),
S1 = case Node of
<<"">> -> <<"">>;
_ -> <<Node/binary, "@">>
end,
S2 = <<S1/binary, Server/binary>>,
S3 = case Resource of
<<"">> -> S2;
_ -> <<S2/binary, "/", Resource/binary>>
end,
S3.
-spec is_nodename(binary()) -> boolean().
is_nodename(Node) ->
N = nodeprep(Node),
(N /= error) and (N /= <<>>).
-define(LOWER(Char),
if Char >= $A, Char =< $Z -> Char + 32;
true -> Char
end).
-spec nodeprep(binary()) -> binary() | error.
nodeprep("") -> <<>>;
nodeprep(S) when byte_size(S) < 1024 ->
R = stringprep:nodeprep(S),
if byte_size(R) < 1024 -> R;
true -> error
end;
nodeprep(_) -> error.
-spec nameprep(binary()) -> binary() | error.
nameprep(S) when byte_size(S) < 1024 ->
R = stringprep:nameprep(S),
if byte_size(R) < 1024 -> R;
true -> error
end;
nameprep(_) -> error.
-spec resourceprep(binary()) -> binary() | error.
resourceprep(S) when byte_size(S) < 1024 ->
R = stringprep:resourceprep(S),
if byte_size(R) < 1024 -> R;
true -> error
end;
resourceprep(_) -> error.
-spec tolower(jid() | ljid()) -> error | ljid().
tolower(#jid{luser = U, lserver = S,
lresource = R}) ->
{U, S, R};
tolower({U, S, R}) ->
case nodeprep(U) of
error -> error;
LUser ->
case nameprep(S) of
error -> error;
LServer ->
case resourceprep(R) of
error -> error;
LResource -> {LUser, LServer, LResource}
end
end
end.
-spec remove_resource(jid()) -> jid();
(ljid()) -> ljid().
remove_resource(#jid{} = JID) ->
JID#jid{resource = <<"">>, lresource = <<"">>};
remove_resource({U, S, _R}) -> {U, S, <<"">>}.
-spec replace_resource(jid(), binary()) -> error | jid().
replace_resource(JID, Resource) ->
case resourceprep(Resource) of
error -> error;
LResource ->
JID#jid{resource = Resource, lresource = LResource}
end.
%%%===================================================================
%%% Internal functions
%%%===================================================================

View File

@ -1,220 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: mam_query.xdata
%% Form type: urn:xmpp:mam:1
%% Document: XEP-0313
-module(mam_query).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("mam_query.hrl").
-export_type([property/0, result/0, form/0]).
enc_jid(J) -> jid:to_string(J).
dec_jid(Val) ->
case jid:from_string(Val) of
error -> erlang:error(badarg);
J -> J
end.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, []);
#xdata_field{values = [<<"urn:xmpp:mam:1">>]} ->
decode(Fs, Acc, []);
_ ->
erlang:error({?MODULE,
{form_type_mismatch, <<"urn:xmpp:mam:1">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{with, Val} -> [encode_with(Val, Translate)];
{with, _, _} -> erlang:error({badarg, Opt});
{start, Val} -> [encode_start(Val, Translate)];
{start, _, _} -> erlang:error({badarg, Opt});
{'end', Val} -> [encode_end(Val, Translate)];
{'end', _, _} -> erlang:error({badarg, Opt});
{withtext, Val} -> [encode_withtext(Val, Translate)];
{withtext, _, _} -> erlang:error({badarg, Opt});
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden, values = [<<"urn:xmpp:mam:1">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"with">>, values = [Value]}
| Fs],
Acc, Required) ->
try dec_jid(Value) of
Result ->
decode(Fs, [{with, Result} | Acc],
lists:delete(<<"with">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"with">>, <<"urn:xmpp:mam:1">>}})
end;
decode([#xdata_field{var = <<"with">>, values = []} = F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"with">>, values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"with">>} | _], _, _) ->
erlang:error({?MODULE,
{too_many_values, <<"with">>, <<"urn:xmpp:mam:1">>}});
decode([#xdata_field{var = <<"start">>,
values = [Value]}
| Fs],
Acc, Required) ->
try xmpp_util:decode_timestamp(Value) of
Result ->
decode(Fs, [{start, Result} | Acc],
lists:delete(<<"start">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"start">>, <<"urn:xmpp:mam:1">>}})
end;
decode([#xdata_field{var = <<"start">>, values = []} = F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"start">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"start">>} | _], _, _) ->
erlang:error({?MODULE,
{too_many_values, <<"start">>, <<"urn:xmpp:mam:1">>}});
decode([#xdata_field{var = <<"end">>, values = [Value]}
| Fs],
Acc, Required) ->
try xmpp_util:decode_timestamp(Value) of
Result ->
decode(Fs, [{'end', Result} | Acc],
lists:delete(<<"end">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"end">>, <<"urn:xmpp:mam:1">>}})
end;
decode([#xdata_field{var = <<"end">>, values = []} = F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"end">>, values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"end">>} | _], _, _) ->
erlang:error({?MODULE,
{too_many_values, <<"end">>, <<"urn:xmpp:mam:1">>}});
decode([#xdata_field{var = <<"withtext">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{withtext, Result} | Acc],
lists:delete(<<"withtext">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"withtext">>, <<"urn:xmpp:mam:1">>}})
end;
decode([#xdata_field{var = <<"withtext">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"withtext">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"withtext">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"withtext">>,
<<"urn:xmpp:mam:1">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var, <<"urn:xmpp:mam:1">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var, <<"urn:xmpp:mam:1">>}});
decode([], Acc, []) -> Acc.
encode_with(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_jid(Value)]
end,
Opts = [],
#xdata_field{var = <<"with">>, values = Values,
required = false, type = 'jid-single', options = Opts,
desc = <<>>, label = Translate(<<"User JID">>)}.
encode_start(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"start">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>,
label = Translate(<<"Search from the date">>)}.
encode_end(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"end">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>,
label = Translate(<<"Search until the date">>)}.
encode_withtext(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"withtext">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>, label = Translate(<<"Search the text">>)}.

View File

@ -1,364 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_register.xdata
%% Form type: http://jabber.org/protocol/muc#register
%% Document: XEP-0045
-module(muc_register).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("muc_register.hrl").
-export_type([property/0, result/0, form/0]).
dec_bool(<<"1">>) -> true;
dec_bool(<<"0">>) -> false;
dec_bool(<<"true">>) -> true;
dec_bool(<<"false">>) -> false.
enc_bool(true) -> <<"1">>;
enc_bool(false) -> <<"0">>.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, [<<"muc#register_roomnick">>]);
#xdata_field{values =
[<<"http://jabber.org/protocol/muc#register">>]} ->
decode(Fs, Acc, [<<"muc#register_roomnick">>]);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/muc#register">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{allow, Val} -> [encode_allow(Val, Translate)];
{allow, _, _} -> erlang:error({badarg, Opt});
{email, Val} -> [encode_email(Val, Translate)];
{email, _, _} -> erlang:error({badarg, Opt});
{faqentry, Val} -> [encode_faqentry(Val, Translate)];
{faqentry, _, _} -> erlang:error({badarg, Opt});
{first, Val} -> [encode_first(Val, Translate)];
{first, _, _} -> erlang:error({badarg, Opt});
{last, Val} -> [encode_last(Val, Translate)];
{last, _, _} -> erlang:error({badarg, Opt});
{roomnick, Val} -> [encode_roomnick(Val, Translate)];
{roomnick, _, _} -> erlang:error({badarg, Opt});
{url, Val} -> [encode_url(Val, Translate)];
{url, _, _} -> erlang:error({badarg, Opt});
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/muc#register">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"muc#register_allow">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{allow, Result} | Acc],
lists:delete(<<"muc#register_allow">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_allow">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_allow">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#register_allow">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#register_allow">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#register_allow">>,
<<"http://jabber.org/protocol/muc#register">>}});
decode([#xdata_field{var = <<"muc#register_email">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{email, Result} | Acc],
lists:delete(<<"muc#register_email">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_email">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_email">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#register_email">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#register_email">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#register_email">>,
<<"http://jabber.org/protocol/muc#register">>}});
decode([#xdata_field{var = <<"muc#register_faqentry">>,
values = Values}
| Fs],
Acc, Required) ->
try [Value || Value <- Values] of
Result ->
decode(Fs, [{faqentry, Result} | Acc],
lists:delete(<<"muc#register_faqentry">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_faqentry">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_first">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{first, Result} | Acc],
lists:delete(<<"muc#register_first">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_first">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_first">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#register_first">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#register_first">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#register_first">>,
<<"http://jabber.org/protocol/muc#register">>}});
decode([#xdata_field{var = <<"muc#register_last">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{last, Result} | Acc],
lists:delete(<<"muc#register_last">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_last">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_last">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#register_last">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#register_last">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#register_last">>,
<<"http://jabber.org/protocol/muc#register">>}});
decode([#xdata_field{var = <<"muc#register_roomnick">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{roomnick, Result} | Acc],
lists:delete(<<"muc#register_roomnick">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_roomnick">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_roomnick">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#register_roomnick">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#register_roomnick">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#register_roomnick">>,
<<"http://jabber.org/protocol/muc#register">>}});
decode([#xdata_field{var = <<"muc#register_url">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{url, Result} | Acc],
lists:delete(<<"muc#register_url">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#register_url">>,
<<"http://jabber.org/protocol/muc#register">>}})
end;
decode([#xdata_field{var = <<"muc#register_url">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#register_url">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#register_url">>} | _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#register_url">>,
<<"http://jabber.org/protocol/muc#register">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/muc#register">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/muc#register">>}});
decode([], Acc, []) -> Acc.
encode_allow(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"muc#register_allow">>,
values = Values, required = false, type = boolean,
options = Opts, desc = <<>>,
label =
Translate(<<"Allow this person to register with the "
"room?">>)}.
encode_email(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#register_email">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Email Address">>)}.
encode_faqentry(Value, Translate) ->
Values = case Value of
[] -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#register_faqentry">>,
values = Values, required = false, type = 'text-multi',
options = Opts, desc = <<>>,
label = Translate(<<"FAQ Entry">>)}.
encode_first(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#register_first">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Given Name">>)}.
encode_last(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#register_last">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Family Name">>)}.
encode_roomnick(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#register_roomnick">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Nickname">>)}.
encode_url(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#register_url">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"A Web Page">>)}.

View File

@ -1,269 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_request.xdata
%% Form type: http://jabber.org/protocol/muc#request
%% Document: XEP-0045
-module(muc_request).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("muc_request.hrl").
-export_type([property/0, result/0, form/0]).
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).
dec_bool(<<"1">>) -> true;
dec_bool(<<"0">>) -> false;
dec_bool(<<"true">>) -> true;
dec_bool(<<"false">>) -> false.
enc_bool(true) -> <<"1">>;
enc_bool(false) -> <<"0">>.
enc_jid(J) -> jid:to_string(J).
dec_jid(Val) ->
case jid:from_string(Val) of
error -> erlang:error(badarg);
J -> J
end.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, [<<"muc#role">>]);
#xdata_field{values =
[<<"http://jabber.org/protocol/muc#request">>]} ->
decode(Fs, Acc, [<<"muc#role">>]);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/muc#request">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{role, Val} -> [encode_role(Val, default, Translate)];
{role, Val, Opts} ->
[encode_role(Val, Opts, Translate)];
{jid, Val} -> [encode_jid(Val, Translate)];
{jid, _, _} -> erlang:error({badarg, Opt});
{roomnick, Val} -> [encode_roomnick(Val, Translate)];
{roomnick, _, _} -> erlang:error({badarg, Opt});
{request_allow, Val} ->
[encode_request_allow(Val, Translate)];
{request_allow, _, _} -> erlang:error({badarg, Opt});
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/muc#request">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"muc#role">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_enum(Value, [participant]) of
Result ->
decode(Fs, [{role, Result} | Acc],
lists:delete(<<"muc#role">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#role">>,
<<"http://jabber.org/protocol/muc#request">>}})
end;
decode([#xdata_field{var = <<"muc#role">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#role">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#role">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#role">>,
<<"http://jabber.org/protocol/muc#request">>}});
decode([#xdata_field{var = <<"muc#jid">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_jid(Value) of
Result ->
decode(Fs, [{jid, Result} | Acc],
lists:delete(<<"muc#jid">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#jid">>,
<<"http://jabber.org/protocol/muc#request">>}})
end;
decode([#xdata_field{var = <<"muc#jid">>, values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#jid">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#jid">>} | _], _, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#jid">>,
<<"http://jabber.org/protocol/muc#request">>}});
decode([#xdata_field{var = <<"muc#roomnick">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{roomnick, Result} | Acc],
lists:delete(<<"muc#roomnick">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roomnick">>,
<<"http://jabber.org/protocol/muc#request">>}})
end;
decode([#xdata_field{var = <<"muc#roomnick">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#roomnick">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#roomnick">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roomnick">>,
<<"http://jabber.org/protocol/muc#request">>}});
decode([#xdata_field{var = <<"muc#request_allow">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{request_allow, Result} | Acc],
lists:delete(<<"muc#request_allow">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#request_allow">>,
<<"http://jabber.org/protocol/muc#request">>}})
end;
decode([#xdata_field{var = <<"muc#request_allow">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#request_allow">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#request_allow">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#request_allow">>,
<<"http://jabber.org/protocol/muc#request">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/muc#request">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/muc#request">>}});
decode([], Acc, []) -> Acc.
encode_role(Value, Options, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_enum(Value)]
end,
Opts = if Options == default ->
[#xdata_option{label = Translate(<<"Participant">>),
value = <<"participant">>}];
true ->
[#xdata_option{label = Translate(L),
value = enc_enum(V)}
|| {L, V} <- Options]
end,
#xdata_field{var = <<"muc#role">>, values = Values,
required = false, type = 'list-single', options = Opts,
desc = <<>>, label = Translate(<<"Requested role">>)}.
encode_jid(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_jid(Value)]
end,
Opts = [],
#xdata_field{var = <<"muc#jid">>, values = Values,
required = false, type = 'jid-single', options = Opts,
desc = <<>>, label = Translate(<<"User JID">>)}.
encode_roomnick(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roomnick">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>, label = Translate(<<"Nickname">>)}.
encode_request_allow(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"muc#request_allow">>,
values = Values, required = false, type = boolean,
options = Opts, desc = <<>>,
label = Translate(<<"Grant voice to this person?">>)}.

File diff suppressed because it is too large Load Diff

View File

@ -1,491 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: muc_roominfo.xdata
%% Form type: http://jabber.org/protocol/muc#roominfo
%% Document: XEP-0045
-module(muc_roominfo).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("muc_roominfo.hrl").
-export_type([property/0, result/0, form/0]).
dec_int(Val, Min, Max) ->
case list_to_integer(binary_to_list(Val)) of
Int when Int =< Max, Min == infinity -> Int;
Int when Int =< Max, Int >= Min -> Int
end.
enc_int(Int) -> integer_to_binary(Int).
dec_bool(<<"1">>) -> true;
dec_bool(<<"0">>) -> false;
dec_bool(<<"true">>) -> true;
dec_bool(<<"false">>) -> false.
enc_bool(true) -> <<"1">>;
enc_bool(false) -> <<"0">>.
enc_jid(J) -> jid:to_string(J).
dec_jid(Val) ->
case jid:from_string(Val) of
error -> erlang:error(badarg);
J -> J
end.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, []);
#xdata_field{values =
[<<"http://jabber.org/protocol/muc#roominfo">>]} ->
decode(Fs, Acc, []);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{maxhistoryfetch, Val} ->
[encode_maxhistoryfetch(Val, Translate)];
{maxhistoryfetch, _, _} -> erlang:error({badarg, Opt});
{contactjid, Val} ->
[encode_contactjid(Val, Translate)];
{contactjid, _, _} -> erlang:error({badarg, Opt});
{description, Val} ->
[encode_description(Val, Translate)];
{description, _, _} -> erlang:error({badarg, Opt});
{lang, Val} -> [encode_lang(Val, Translate)];
{lang, _, _} -> erlang:error({badarg, Opt});
{ldapgroup, Val} -> [encode_ldapgroup(Val, Translate)];
{ldapgroup, _, _} -> erlang:error({badarg, Opt});
{logs, Val} -> [encode_logs(Val, Translate)];
{logs, _, _} -> erlang:error({badarg, Opt});
{occupants, Val} -> [encode_occupants(Val, Translate)];
{occupants, _, _} -> erlang:error({badarg, Opt});
{subject, Val} -> [encode_subject(Val, Translate)];
{subject, _, _} -> erlang:error({badarg, Opt});
{subjectmod, Val} ->
[encode_subjectmod(Val, Translate)];
{subjectmod, _, _} -> erlang:error({badarg, Opt});
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/muc#roominfo">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"muc#maxhistoryfetch">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_int(Value, 0, infinity) of
Result ->
decode(Fs, [{maxhistoryfetch, Result} | Acc],
lists:delete(<<"muc#maxhistoryfetch">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#maxhistoryfetch">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var = <<"muc#maxhistoryfetch">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#maxhistoryfetch">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#maxhistoryfetch">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#maxhistoryfetch">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var =
<<"muc#roominfo_contactjid">>,
values = Values}
| Fs],
Acc, Required) ->
try [dec_jid(Value) || Value <- Values] of
Result ->
decode(Fs, [{contactjid, Result} | Acc],
lists:delete(<<"muc#roominfo_contactjid">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_contactjid">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var =
<<"muc#roominfo_description">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{description, Result} | Acc],
lists:delete(<<"muc#roominfo_description">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_description">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var =
<<"muc#roominfo_description">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"muc#roominfo_description">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var =
<<"muc#roominfo_description">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_description">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var = <<"muc#roominfo_lang">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{lang, Result} | Acc],
lists:delete(<<"muc#roominfo_lang">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_lang">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var = <<"muc#roominfo_lang">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#roominfo_lang">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#roominfo_lang">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_lang">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{ldapgroup, Result} | Acc],
lists:delete(<<"muc#roominfo_ldapgroup">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_ldapgroup">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"muc#roominfo_ldapgroup">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#roominfo_ldapgroup">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_ldapgroup">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var = <<"muc#roominfo_logs">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{logs, Result} | Acc],
lists:delete(<<"muc#roominfo_logs">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_logs">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var = <<"muc#roominfo_logs">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#roominfo_logs">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#roominfo_logs">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_logs">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var = <<"muc#roominfo_occupants">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_int(Value, 0, infinity) of
Result ->
decode(Fs, [{occupants, Result} | Acc],
lists:delete(<<"muc#roominfo_occupants">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_occupants">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var = <<"muc#roominfo_occupants">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"muc#roominfo_occupants">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#roominfo_occupants">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_occupants">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var = <<"muc#roominfo_subject">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{subject, Result} | Acc],
lists:delete(<<"muc#roominfo_subject">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_subject">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var = <<"muc#roominfo_subject">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"muc#roominfo_subject">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"muc#roominfo_subject">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_subject">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var =
<<"muc#roominfo_subjectmod">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{subjectmod, Result} | Acc],
lists:delete(<<"muc#roominfo_subjectmod">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"muc#roominfo_subjectmod">>,
<<"http://jabber.org/protocol/muc#roominfo">>}})
end;
decode([#xdata_field{var =
<<"muc#roominfo_subjectmod">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"muc#roominfo_subjectmod">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var =
<<"muc#roominfo_subjectmod">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"muc#roominfo_subjectmod">>,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/muc#roominfo">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/muc#roominfo">>}});
decode([], Acc, []) -> Acc.
encode_maxhistoryfetch(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_int(Value)]
end,
Opts = [],
#xdata_field{var = <<"muc#maxhistoryfetch">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label =
Translate(<<"Maximum Number of History Messages Returned "
"by Room">>)}.
encode_contactjid(Value, Translate) ->
Values = case Value of
[] -> [];
Value -> [enc_jid(V) || V <- Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_contactjid">>,
values = Values, required = false, type = 'jid-multi',
options = Opts, desc = <<>>,
label =
Translate(<<"Contact Addresses (normally, room owner "
"or owners)">>)}.
encode_description(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_description">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Room description">>)}.
encode_lang(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_lang">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label =
Translate(<<"Natural Language for Room Discussions">>)}.
encode_ldapgroup(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_ldapgroup">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label =
Translate(<<"An associated LDAP group that defines "
"room membership; this should be an LDAP "
"Distinguished Name according to an implementa"
"tion-specific or deployment-specific "
"definition of a group.">>)}.
encode_logs(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_logs">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label =
Translate(<<"URL for Archived Discussion Logs">>)}.
encode_occupants(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_int(Value)]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_occupants">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Number of occupants">>)}.
encode_subject(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_subject">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label = Translate(<<"Current Discussion Topic">>)}.
encode_subjectmod(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"muc#roominfo_subjectmod">>,
values = Values, required = false, type = boolean,
options = Opts, desc = <<>>,
label =
Translate(<<"The room subject can be modified by "
"participants">>)}.

View File

@ -1,130 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_get_pending.xdata
%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization
%% Document: XEP-0060
-module(pubsub_get_pending).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("pubsub_get_pending.hrl").
-export_type([property/0, result/0, form/0]).
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, [<<"pubsub#node">>]);
#xdata_field{values =
[<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>]} ->
decode(Fs, Acc, [<<"pubsub#node">>]);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{node, Val} -> [encode_node(Val, default, Translate)];
{node, Val, Opts} ->
[encode_node(Val, Opts, Translate)];
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"pubsub#node">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{node, Result} | Acc],
lists:delete(<<"pubsub#node">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#node">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end;
decode([#xdata_field{var = <<"pubsub#node">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#node">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#node">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#node">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([], Acc, []) -> Acc.
encode_node(Value, Options, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = if Options == default -> [];
true ->
[#xdata_option{label = Translate(L), value = V}
|| {L, V} <- Options]
end,
#xdata_field{var = <<"pubsub#node">>, values = Values,
required = false, type = 'list-single', options = Opts,
desc = <<>>,
label =
Translate(<<"The NodeID of the relevant node">>)}.

File diff suppressed because it is too large Load Diff

View File

@ -1,157 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_publish_options.xdata
%% Form type: http://jabber.org/protocol/pubsub#publish-options
%% Document: XEP-0060
-module(pubsub_publish_options).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("pubsub_publish_options.hrl").
-export_type([property/0, result/0, form/0]).
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).
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, []);
#xdata_field{values =
[<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>]} ->
decode(Fs, Acc, []);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{access_model, Val} ->
[encode_access_model(Val, default, Translate)];
{access_model, Val, Opts} ->
[encode_access_model(Val, Opts, Translate)];
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"pubsub#access_model">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_enum(Value,
[authorize, open, presence, roster, whitelist])
of
Result ->
decode(Fs, [{access_model, Result} | Acc],
lists:delete(<<"pubsub#access_model">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#access_model">>,
<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>}})
end;
decode([#xdata_field{var = <<"pubsub#access_model">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#access_model">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#access_model">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#access_model">>,
<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/pubsub#publish-opt"
"ions">>}});
decode([], Acc, []) -> Acc.
encode_access_model(Value, Options, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_enum(Value)]
end,
Opts = if Options == default ->
[#xdata_option{label =
Translate(<<"Access model of authorize">>),
value = <<"authorize">>},
#xdata_option{label =
Translate(<<"Access model of open">>),
value = <<"open">>},
#xdata_option{label =
Translate(<<"Access model of presence">>),
value = <<"presence">>},
#xdata_option{label =
Translate(<<"Access model of roster">>),
value = <<"roster">>},
#xdata_option{label =
Translate(<<"Access model of whitelist">>),
value = <<"whitelist">>}];
true ->
[#xdata_option{label = Translate(L),
value = enc_enum(V)}
|| {L, V} <- Options]
end,
#xdata_field{var = <<"pubsub#access_model">>,
values = Values, required = false, type = 'list-single',
options = Opts, desc = <<>>,
label = Translate(<<"Specify the access model">>)}.

View File

@ -1,279 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_subscribe_authorization.xdata
%% Form type: http://jabber.org/protocol/pubsub#subscribe_authorization
%% Document: XEP-0060
-module(pubsub_subscribe_authorization).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("pubsub_subscribe_authorization.hrl").
-export_type([property/0, result/0, form/0]).
dec_bool(<<"1">>) -> true;
dec_bool(<<"0">>) -> false;
dec_bool(<<"true">>) -> true;
dec_bool(<<"false">>) -> false.
enc_bool(true) -> <<"1">>;
enc_bool(false) -> <<"0">>.
enc_jid(J) -> jid:to_string(J).
dec_jid(Val) ->
case jid:from_string(Val) of
error -> erlang:error(badarg);
J -> J
end.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false ->
decode(Fs, Acc,
[<<"pubsub#allow">>, <<"pubsub#node">>,
<<"pubsub#subscriber_jid">>]);
#xdata_field{values =
[<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>]} ->
decode(Fs, Acc,
[<<"pubsub#allow">>, <<"pubsub#node">>,
<<"pubsub#subscriber_jid">>]);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{allow, Val} -> [encode_allow(Val, Translate)];
{allow, _, _} -> erlang:error({badarg, Opt});
{node, Val} -> [encode_node(Val, Translate)];
{node, _, _} -> erlang:error({badarg, Opt});
{subscriber_jid, Val} ->
[encode_subscriber_jid(Val, Translate)];
{subscriber_jid, _, _} -> erlang:error({badarg, Opt});
{subid, Val} -> [encode_subid(Val, Translate)];
{subid, _, _} -> erlang:error({badarg, Opt});
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"pubsub#allow">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{allow, Result} | Acc],
lists:delete(<<"pubsub#allow">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#allow">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end;
decode([#xdata_field{var = <<"pubsub#allow">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#allow">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#allow">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#allow">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([#xdata_field{var = <<"pubsub#node">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{node, Result} | Acc],
lists:delete(<<"pubsub#node">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#node">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end;
decode([#xdata_field{var = <<"pubsub#node">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#node">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#node">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#node">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([#xdata_field{var = <<"pubsub#subscriber_jid">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_jid(Value) of
Result ->
decode(Fs, [{subscriber_jid, Result} | Acc],
lists:delete(<<"pubsub#subscriber_jid">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#subscriber_jid">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end;
decode([#xdata_field{var = <<"pubsub#subscriber_jid">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#subscriber_jid">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#subscriber_jid">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#subscriber_jid">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([#xdata_field{var = <<"pubsub#subid">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{subid, Result} | Acc],
lists:delete(<<"pubsub#subid">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#subid">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}})
end;
decode([#xdata_field{var = <<"pubsub#subid">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#subid">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#subid">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#subid">>,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/pubsub#subscribe_a"
"uthorization">>}});
decode([], Acc, []) -> Acc.
encode_allow(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"pubsub#allow">>, values = Values,
required = false, type = boolean, options = Opts,
desc = <<>>,
label =
Translate(<<"Allow this Jabber ID to subscribe to "
"this pubsub node?">>)}.
encode_node(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"pubsub#node">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>, label = Translate(<<"Node ID">>)}.
encode_subscriber_jid(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_jid(Value)]
end,
Opts = [],
#xdata_field{var = <<"pubsub#subscriber_jid">>,
values = Values, required = false, type = 'jid-single',
options = Opts, desc = <<>>,
label = Translate(<<"Subscriber Address">>)}.
encode_subid(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"pubsub#subid">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>,
label =
Translate(<<"The subscription identifier associated "
"with the subscription request">>)}.

View File

@ -1,508 +0,0 @@
%% Created automatically by xdata generator (xdata_codec.erl)
%% Source: pubsub_subscribe_options.xdata
%% Form type: http://jabber.org/protocol/pubsub#subscribe_options
%% Document: XEP-0060
-module(pubsub_subscribe_options).
-export([decode/1, decode/2, encode/1, encode/2,
format_error/1]).
-include("xmpp_codec.hrl").
-include("pubsub_subscribe_options.hrl").
-export_type([property/0, result/0, form/0]).
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).
dec_bool(<<"1">>) -> true;
dec_bool(<<"0">>) -> false;
dec_bool(<<"true">>) -> true;
dec_bool(<<"false">>) -> false.
enc_bool(true) -> <<"1">>;
enc_bool(false) -> <<"0">>.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary,
"' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '",
Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '",
Type/binary, "'">>.
decode(Fs) -> decode(Fs, []).
decode(Fs, Acc) ->
case lists:keyfind(<<"FORM_TYPE">>, #xdata_field.var,
Fs)
of
false -> decode(Fs, Acc, []);
#xdata_field{values =
[<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>]} ->
decode(Fs, Acc, []);
_ ->
erlang:error({?MODULE,
{form_type_mismatch,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end.
encode(Cfg) -> encode(Cfg, fun (Text) -> Text end).
encode(List, Translate) when is_list(List) ->
Fs = [case Opt of
{deliver, Val} -> [encode_deliver(Val, Translate)];
{deliver, _, _} -> erlang:error({badarg, Opt});
{digest, Val} -> [encode_digest(Val, Translate)];
{digest, _, _} -> erlang:error({badarg, Opt});
{digest_frequency, Val} ->
[encode_digest_frequency(Val, Translate)];
{digest_frequency, _, _} -> erlang:error({badarg, Opt});
{expire, Val} -> [encode_expire(Val, Translate)];
{expire, _, _} -> erlang:error({badarg, Opt});
{include_body, Val} ->
[encode_include_body(Val, Translate)];
{include_body, _, _} -> erlang:error({badarg, Opt});
{'show-values', Val} ->
['encode_show-values'(Val, default, Translate)];
{'show-values', Val, Opts} ->
['encode_show-values'(Val, Opts, Translate)];
{subscription_type, Val} ->
[encode_subscription_type(Val, default, Translate)];
{subscription_type, Val, Opts} ->
[encode_subscription_type(Val, Opts, Translate)];
{subscription_depth, Val} ->
[encode_subscription_depth(Val, default, Translate)];
{subscription_depth, Val, Opts} ->
[encode_subscription_depth(Val, Opts, Translate)];
#xdata_field{} -> [Opt];
_ -> []
end
|| Opt <- List],
FormType = #xdata_field{var = <<"FORM_TYPE">>,
type = hidden,
values =
[<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>]},
[FormType | lists:flatten(Fs)].
decode([#xdata_field{var = <<"pubsub#deliver">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{deliver, Result} | Acc],
lists:delete(<<"pubsub#deliver">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#deliver">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var = <<"pubsub#deliver">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#deliver">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#deliver">>} | _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#deliver">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var = <<"pubsub#digest">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{digest, Result} | Acc],
lists:delete(<<"pubsub#digest">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#digest">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var = <<"pubsub#digest">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#digest">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#digest">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#digest">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var =
<<"pubsub#digest_frequency">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{digest_frequency, Result} | Acc],
lists:delete(<<"pubsub#digest_frequency">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#digest_frequency">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var =
<<"pubsub#digest_frequency">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"pubsub#digest_frequency">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var =
<<"pubsub#digest_frequency">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#digest_frequency">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var = <<"pubsub#expire">>,
values = [Value]}
| Fs],
Acc, Required) ->
try Value of
Result ->
decode(Fs, [{expire, Result} | Acc],
lists:delete(<<"pubsub#expire">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#expire">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var = <<"pubsub#expire">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#expire">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#expire">>} | _], _,
_) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#expire">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var = <<"pubsub#include_body">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_bool(Value) of
Result ->
decode(Fs, [{include_body, Result} | Acc],
lists:delete(<<"pubsub#include_body">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#include_body">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var = <<"pubsub#include_body">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var = <<"pubsub#include_body">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var = <<"pubsub#include_body">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#include_body">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var = <<"pubsub#show-values">>,
values = Values}
| Fs],
Acc, Required) ->
try [dec_enum(Value, [away, chat, dnd, online, xa])
|| Value <- Values]
of
Result ->
decode(Fs, [{'show-values', Result} | Acc],
lists:delete(<<"pubsub#show-values">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#show-values">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var =
<<"pubsub#subscription_type">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_enum(Value, [items, nodes]) of
Result ->
decode(Fs, [{subscription_type, Result} | Acc],
lists:delete(<<"pubsub#subscription_type">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#subscription_type">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var =
<<"pubsub#subscription_type">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"pubsub#subscription_type">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var =
<<"pubsub#subscription_type">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#subscription_type">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var =
<<"pubsub#subscription_depth">>,
values = [Value]}
| Fs],
Acc, Required) ->
try dec_enum(Value, ['1', all]) of
Result ->
decode(Fs, [{subscription_depth, Result} | Acc],
lists:delete(<<"pubsub#subscription_depth">>, Required))
catch
_:_ ->
erlang:error({?MODULE,
{bad_var_value, <<"pubsub#subscription_depth">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}})
end;
decode([#xdata_field{var =
<<"pubsub#subscription_depth">>,
values = []} =
F
| Fs],
Acc, Required) ->
decode([F#xdata_field{var =
<<"pubsub#subscription_depth">>,
values = [<<>>]}
| Fs],
Acc, Required);
decode([#xdata_field{var =
<<"pubsub#subscription_depth">>}
| _],
_, _) ->
erlang:error({?MODULE,
{too_many_values, <<"pubsub#subscription_depth">>,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([#xdata_field{var = Var} | Fs], Acc, Required) ->
if Var /= <<"FORM_TYPE">> ->
erlang:error({?MODULE,
{unknown_var, Var,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
true -> decode(Fs, Acc, Required)
end;
decode([], _, [Var | _]) ->
erlang:error({?MODULE,
{missing_required_var, Var,
<<"http://jabber.org/protocol/pubsub#subscribe_o"
"ptions">>}});
decode([], Acc, []) -> Acc.
encode_deliver(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"pubsub#deliver">>,
values = Values, required = false, type = boolean,
options = Opts, desc = <<>>,
label =
Translate(<<"Whether an entity wants to receive or "
"disable notifications">>)}.
encode_digest(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"pubsub#digest">>, values = Values,
required = false, type = boolean, options = Opts,
desc = <<>>,
label =
Translate(<<"Whether an entity wants to receive digests "
"(aggregations) of notifications or all "
"notifications individually">>)}.
encode_digest_frequency(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"pubsub#digest_frequency">>,
values = Values, required = false, type = 'text-single',
options = Opts, desc = <<>>,
label =
Translate(<<"The minimum number of milliseconds between "
"sending any two notification digests">>)}.
encode_expire(Value, Translate) ->
Values = case Value of
<<>> -> [];
Value -> [Value]
end,
Opts = [],
#xdata_field{var = <<"pubsub#expire">>, values = Values,
required = false, type = 'text-single', options = Opts,
desc = <<>>,
label =
Translate(<<"The DateTime at which a leased subscription "
"will end or has ended">>)}.
encode_include_body(Value, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_bool(Value)]
end,
Opts = [],
#xdata_field{var = <<"pubsub#include_body">>,
values = Values, required = false, type = boolean,
options = Opts, desc = <<>>,
label =
Translate(<<"Whether an entity wants to receive an "
"XMPP message body in addition to the "
"payload format">>)}.
'encode_show-values'(Value, Options, Translate) ->
Values = case Value of
[] -> [];
Value -> [enc_enum(V) || V <- Value]
end,
Opts = if Options == default ->
[#xdata_option{label =
Translate(<<"XMPP Show Value of Away">>),
value = <<"away">>},
#xdata_option{label =
Translate(<<"XMPP Show Value of Chat">>),
value = <<"chat">>},
#xdata_option{label =
Translate(<<"XMPP Show Value of DND (Do Not Disturb)">>),
value = <<"dnd">>},
#xdata_option{label =
Translate(<<"Mere Availability in XMPP (No Show Value)">>),
value = <<"online">>},
#xdata_option{label =
Translate(<<"XMPP Show Value of XA (Extended Away)">>),
value = <<"xa">>}];
true ->
[#xdata_option{label = Translate(L),
value = enc_enum(V)}
|| {L, V} <- Options]
end,
#xdata_field{var = <<"pubsub#show-values">>,
values = Values, required = false, type = 'list-multi',
options = Opts, desc = <<>>,
label =
Translate(<<"The presence states for which an entity "
"wants to receive notifications">>)}.
encode_subscription_type(Value, Options, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_enum(Value)]
end,
Opts = if Options == default ->
[#xdata_option{label =
Translate(<<"Receive notification of new items only">>),
value = <<"items">>},
#xdata_option{label =
Translate(<<"Receive notification of new nodes only">>),
value = <<"nodes">>}];
true ->
[#xdata_option{label = Translate(L),
value = enc_enum(V)}
|| {L, V} <- Options]
end,
#xdata_field{var = <<"pubsub#subscription_type">>,
values = Values, required = false, type = 'list-single',
options = Opts, desc = <<>>, label = <<>>}.
encode_subscription_depth(Value, Options, Translate) ->
Values = case Value of
undefined -> [];
Value -> [enc_enum(Value)]
end,
Opts = if Options == default ->
[#xdata_option{label =
Translate(<<"Receive notification from direct child "
"nodes only">>),
value = <<"1">>},
#xdata_option{label =
Translate(<<"Receive notification from all descendent "
"nodes">>),
value = <<"all">>}];
true ->
[#xdata_option{label = Translate(L),
value = enc_enum(V)}
|| {L, V} <- Options]
end,
#xdata_field{var = <<"pubsub#subscription_depth">>,
values = Values, required = false, type = 'list-single',
options = Opts, desc = <<>>, label = <<>>}.

View File

@ -1,648 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2016, Evgeny Khramtsov
%%% @doc
%%%
%%% @end
%%% Created : 27 Sep 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
-module(xdata_codec).
%% API
-export([compile/1, compile/2]).
-export([dec_int/1, dec_int/3, dec_enum/2, dec_bool/1, not_empty/1,
dec_enum_int/2, dec_enum_int/4, enc_int/1, enc_enum/1,
enc_bool/1, enc_enum_int/1, format_error/1, enc_jid/1, dec_jid/1]).
-include("xmpp.hrl").
-record(state, {mod_name :: atom(),
file_name :: string(),
erl = "" :: string(),
hrl = "" :: string(),
dir = "" :: string(),
ns = <<>> :: binary(),
doc = <<>> :: binary(),
erl_dir = "" :: string(),
hrl_dir = "" :: string(),
prefix = [] :: [binary()],
dec_mfas = [] :: [{binary(), mfa()}],
enc_mfas = [] :: [{binary(), mfa()}],
specs = [] :: [{binary(), string()}],
required = [] :: [{binary(), boolean()} | binary()],
defaults = [] :: [{binary(), any()}]}).
-define(is_multi_type(T),
((T == 'list-multi') or (T == 'jid-multi') or (T == 'text-multi'))).
-define(is_list_type(T),
((T == 'list-single') or (T == 'list-multi'))).
%%%===================================================================
%%% API
%%%===================================================================
compile(Path) ->
compile(Path, []).
compile(Path, Opts) ->
case filelib:is_dir(Path) of
true ->
filelib:fold_files(
Path, ".*.xdata", false,
fun(File, ok) ->
compile_file(File, Opts);
(_, Err) ->
Err
end, ok);
false ->
compile_file(Path, Opts)
end.
compile_file(Path, Opts) ->
try
ok = application:ensure_started(fast_xml),
DirName = filename:dirname(Path),
FileName = filename:basename(Path),
RootName = filename:rootname(FileName),
ConfigPath = filename:join(DirName, RootName) ++ ".cfg",
ModName = list_to_atom(RootName),
{ok, Data} = file:read_file(Path),
Config = case file:consult(ConfigPath) of
{ok, Terms} -> lists:flatten(Terms);
{error, enoent} -> []
end,
State = #state{mod_name = ModName,
file_name = FileName,
erl = filename:rootname(FileName) ++ ".erl",
hrl = filename:rootname(FileName) ++ ".hrl",
dir = DirName,
prefix = proplists:get_all_values(prefix, Config),
erl_dir = proplists:get_value(erl_dir, Opts, DirName),
hrl_dir = proplists:get_value(hrl_dir, Opts, DirName),
dec_mfas = proplists:get_value(decode, Config, []),
enc_mfas = proplists:get_value(encode, Config, []),
specs = proplists:get_value(specs, Config, []),
required = proplists:get_value(required, Config, []),
defaults = proplists:get_value(defaults, Config, [])},
#xmlel{} = El = fxml_stream:parse_element(Data),
ok = compile_element(normalize(El), State),
io:format("Compiled ~s~n", [Path])
catch _:{badmatch, Err} ->
io:format(standard_error, "Failed to compile ~s: ~p~n",
[Path, Err]),
Err
end.
emit(Format) ->
emit(Format, []).
emit(Format, Args) ->
put(outbuf, get(outbuf) ++ io_lib:format(Format, Args)).
dec_int(Val) ->
dec_int(Val, infinity, infinity).
dec_int(Val, Min, Max) ->
case list_to_integer(binary_to_list(Val)) of
Int when Int =< Max, Min == infinity ->
Int;
Int when Int =< Max, Int >= Min ->
Int
end.
enc_int(Int) ->
integer_to_binary(Int).
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).
dec_enum_int(Val, Enums) ->
try dec_int(Val)
catch _:_ -> dec_enum(Val, Enums)
end.
dec_enum_int(Val, Enums, Min, Max) ->
try dec_int(Val, Min, Max)
catch _:_ -> dec_enum(Val, Enums)
end.
enc_enum_int(Int) when is_integer(Int) ->
enc_int(Int);
enc_enum_int(Atom) ->
enc_enum(Atom).
dec_bool(<<"1">>) -> true;
dec_bool(<<"0">>) -> false;
dec_bool(<<"true">>) -> true;
dec_bool(<<"false">>) -> false.
enc_bool(true) -> <<"1">>;
enc_bool(false) -> <<"0">>.
enc_jid(J) -> jid:to_string(J).
dec_jid(Val) ->
case jid:from_string(Val) of
error -> erlang:error(badarg);
J -> J
end.
not_empty(<<_, _/binary>> = Val) ->
Val.
format_error({form_type_mismatch, Type}) ->
<<"FORM_TYPE doesn't match '", Type/binary, "'">>;
format_error({bad_var_value, Var, Type}) ->
<<"Bad value of field '", Var/binary, "' of type '", Type/binary, "'">>;
format_error({missing_value, Var, Type}) ->
<<"Missing value of field '", Var/binary, "' of type '", Type/binary, "'">>;
format_error({too_many_values, Var, Type}) ->
<<"Too many values for field '", Var/binary, "' of type '", Type/binary, "'">>;
format_error({unknown_var, Var, Type}) ->
<<"Unknown field '", Var/binary, "' of type '", Type/binary, "'">>;
format_error({missing_required_var, Var, Type}) ->
<<"Missing required field '", Var/binary, "' of type '", Type/binary, "'">>.
%%%===================================================================
%%% Internal functions
%%%===================================================================
compile_element(#xmlel{name = <<"form_type">>, children = Els} = Form,
#state{erl = OutErl, erl_dir = ErlDir,
hrl = OutHrl, hrl_dir = HrlDir} = State0) ->
try
Name = fxml:get_subtag_cdata(Form, <<"name">>),
Doc = fxml:get_subtag_cdata(Form, <<"doc">>),
X = #xmlel{name = <<"x">>,
attrs = [{<<"type">>, <<"form">>},
{<<"xmlns">>, <<"jabber:x:data">>}],
children = Els},
State = State0#state{ns = Name, doc = Doc},
#xdata{fields = Fs} = xmpp_codec:decode(X),
put(outbuf, []),
mk_header(State),
mk_aux_funs(),
mk_top_decoder(Fs, State),
mk_top_encoder(Fs, State),
mk_decoder(Fs, State),
mk_encoders(Fs, State),
ErlData = get(outbuf),
ok = file:write_file(filename:join(ErlDir, OutErl), ErlData),
ok = erl_tidy:file(filename:join(ErlDir, OutErl), [{backups, false}]),
put(outbuf, []),
mk_type_definitions(Fs, State),
HrlData = get(outbuf),
ok = file:write_file(filename:join(HrlDir, OutHrl), HrlData)
catch _:{badmatch, Err} ->
Err
end.
mk_aux_funs() ->
case get_abstract_code_from_myself() of
{ok, AbsCode} ->
AST = lists:filter(
fun(T) ->
case catch erl_syntax_lib:analyze_function(T) of
{format_error, 1} -> true;
{dec_int, 3} -> true;
{dec_int, 1} -> true;
{dec_enum, 2} -> true;
{dec_enum_int, 2} -> true;
{dec_enum_int, 4} -> true;
{enc_int, 1} -> true;
{enc_enum, 1} -> true;
{enc_enum_int, 1} -> true;
{not_empty, 1} -> true;
{dec_bool, 1} -> true;
{enc_bool, 1} -> true;
{enc_jid, 1} -> true;
{dec_jid, 1} -> true;
_ -> false
end
end, AbsCode),
emit(erl_prettypr:format(erl_syntax:form_list(AST)) ++ io_lib:nl());
error ->
erlang:error({no_abstract_code_found, ?MODULE})
end.
get_abstract_code_from_myself() ->
{file, File} = code:is_loaded(?MODULE),
case beam_lib:chunks(File, [abstract_code]) of
{ok, {_, List}} ->
case lists:keyfind(abstract_code, 1, List) of
{abstract_code, {raw_abstract_v1, Abstr}} ->
{ok, Abstr};
_ ->
error
end;
_ ->
error
end.
mk_comment_header(#state{file_name = Source, ns = NS, doc = Doc}) ->
emit("%% Created automatically by xdata generator (xdata_codec.erl)~n"
"%% Source: ~s~n"
"%% Form type: ~s~n", [Source, NS]),
if Doc /= <<>> -> emit("%% Document: ~s~n~n", [Doc]);
true -> emit("~n")
end.
mk_header(#state{mod_name = Mod, hrl = Include} = State) ->
mk_comment_header(State),
emit("~n-module(~s).~n", [Mod]),
emit("-export([decode/1, decode/2, encode/1, encode/2, format_error/1]).~n"),
emit("-include(\"xmpp_codec.hrl\").~n"),
emit("-include(\"~s\").~n", [Include]),
emit("-export_type([property/0, result/0, form/0]).~n").
mk_type_definitions(Fs, State) ->
mk_comment_header(State),
lists:foreach(
fun(#xdata_field{var = Var} = F) ->
Spec = get_typespec(F, State),
case is_complex_type(Spec) of
true ->
emit("-type '~s'() :: ~s.~n",
[var_to_rec_field(Var, State), Spec]);
false ->
ok
end
end, Fs),
emit("~n-type property() :: "),
Fields = lists:map(
fun(#xdata_field{var = Var} = F) ->
RecField = var_to_rec_field(Var, State),
[io_lib:format("{'~s', ~s}",
[RecField, mk_typespec(F, State)])]
end, Fs),
emit(string:join(Fields, " |~n ") ++ ".~n"),
emit("-type result() :: [property()].~n~n"),
VarsWithSpec = lists:flatmap(
fun(#xdata_field{type = T, var = Var} = F)
when ?is_list_type(T) ->
RecName = var_to_rec_field(Var, State),
Spec0 = get_typespec(F, State),
Spec = case is_complex_type(Spec0) of
true ->
io_lib:format("'~s'()", [RecName]);
false ->
Spec0
end,
[{RecName, mk_typespec(F, State), Spec}];
(_) ->
[]
end, Fs),
case VarsWithSpec of
[] ->
emit("-type form() :: [property() | xdata_field()].~n");
_ ->
emit("-type options(T) :: [{binary(), T}].~n"),
emit("-type property_with_options() ::~n "),
Options = [io_lib:format("{'~s', ~s, options(~s)}",
[Var, Spec1, Spec2])
|| {Var, Spec1, Spec2} <- VarsWithSpec],
emit(string:join(Options, " |~n ") ++ ".~n"),
emit("-type form() :: [property() | property_with_options() | xdata_field()].~n")
end.
mk_top_decoder(Fs, State) ->
Required = [Var || #xdata_field{var = Var} <- Fs, is_required(Var, State)],
emit("decode(Fs) -> decode(Fs, []).~n"),
emit("decode(Fs, Acc) ->"
" case lists:keyfind(<<\"FORM_TYPE\">>, #xdata_field.var, Fs) of"
" false ->"
" decode(Fs, Acc, ~p);"
" #xdata_field{values = [~p]} ->"
" decode(Fs, Acc, ~p);"
" _ ->"
" erlang:error({?MODULE, {form_type_mismatch, ~p}})~n"
" end.~n",
[Required, State#state.ns, Required, State#state.ns]).
mk_top_encoder(Fs, State) ->
Clauses = string:join(
lists:map(
fun(#xdata_field{var = Var, type = T}) when ?is_list_type(T) ->
Field = var_to_rec_field(Var, State),
io_lib:format(
"{'~s', Val} -> ['encode_~s'(Val, default, Translate)];"
"{'~s', Val, Opts} -> ['encode_~s'(Val, Opts, Translate)]",
[Field, Field, Field, Field]);
(#xdata_field{var = Var}) ->
Field = var_to_rec_field(Var, State),
io_lib:format(
"{'~s', Val} -> ['encode_~s'(Val, Translate)];"
"{'~s', _, _} -> erlang:error({badarg, Opt})",
[Field, Field, Field])
end, Fs) ++ ["#xdata_field{} -> [Opt]; _ -> []"],
";"),
emit("encode(Cfg) -> encode(Cfg, fun(Text) -> Text end).~n"),
emit("encode(List, Translate) when is_list(List) ->"
" Fs = [case Opt of ~s end || Opt <- List],"
" FormType = #xdata_field{var = <<\"FORM_TYPE\">>, type = hidden,"
" values = [~p]},"
" [FormType|lists:flatten(Fs)].~n",
[Clauses, State#state.ns]).
mk_decoder([#xdata_field{var = Var, type = Type} = F|Fs], State) ->
ValVar = if ?is_multi_type(Type) -> "Values";
true -> "[Value]"
end,
DecFun = if ?is_multi_type(Type) ->
["[", mk_decoding_fun(F, State), " || Value <- Values]"];
true ->
mk_decoding_fun(F, State)
end,
emit("decode([#xdata_field{var = ~p, values = ~s}|Fs], Acc, Required) ->"
" try ~s of"
" Result -> decode(Fs, [{'~s', Result}|Acc],"
" lists:delete(~p, Required))"
" catch _:_ ->"
" erlang:error({?MODULE, {bad_var_value, ~p, ~p}})"
" end;",
[Var, ValVar, DecFun, var_to_rec_field(Var, State),
Var, Var, State#state.ns]),
if not ?is_multi_type(Type) ->
emit("decode([#xdata_field{var = ~p, values = []} = F|Fs],"
" Acc, Required) ->"
" decode([F#xdata_field{var = ~p, values = [<<>>]}|Fs],"
" Acc, Required);",
[Var, Var]),
emit("decode([#xdata_field{var = ~p}|_], _, _) ->"
" erlang:error({?MODULE, {too_many_values, ~p, ~p}});",
[Var, Var, State#state.ns]);
true ->
ok
end,
mk_decoder(Fs, State);
mk_decoder([], State) ->
emit("decode([#xdata_field{var = Var}|Fs], Acc, Required) ->"
" if Var /= <<\"FORM_TYPE\">> ->"
" erlang:error({?MODULE, {unknown_var, Var, ~p}});"
" true ->"
" decode(Fs, Acc, Required)"
" end;",
[State#state.ns]),
emit("decode([], _, [Var|_]) ->"
" erlang:error({?MODULE, {missing_required_var, Var, ~p}});~n",
[State#state.ns]),
emit("decode([], Acc, []) -> Acc.~n").
mk_encoders(Fs, State) ->
lists:foreach(
fun(#xdata_field{var = Var, required = IsRequired, desc = Desc,
label = Label, type = Type} = F) ->
EncVals = mk_encoded_values(F, State),
EncOpts = mk_encoded_options(F, State),
FieldName = var_to_rec_field(Var, State),
DescStr = if Desc == <<>> -> "<<>>";
true -> io_lib:format("Translate(~p)", [Desc])
end,
LabelStr = if Label == <<>> -> "<<>>";
true -> io_lib:format("Translate(~p)", [Label])
end,
if ?is_list_type(Type) ->
emit("'encode_~s'(Value, Options, Translate) ->", [FieldName]);
true ->
emit("'encode_~s'(Value, Translate) ->", [FieldName])
end,
emit(" Values = ~s,"
" Opts = ~s,"
" #xdata_field{var = ~p,"
" values = Values,"
" required = ~p,"
" type = ~p,"
" options = Opts,"
" desc = ~s,"
" label = ~s}.~n",
[EncVals, EncOpts, Var, IsRequired, Type, DescStr, LabelStr])
end, Fs).
mk_encoded_values(#xdata_field{var = Var, type = Type,
options = Options}, State) ->
EncFun =
case get_enc_fun(Var, Type, Options, State) of
{M, Fun, Args} ->
Mod = if M == undefined -> "";
true -> io_lib:format("~s:", [M])
end,
FArgs = [io_lib:format(", ~p", [A]) || A <- Args],
if ?is_multi_type(Type) ->
"[" ++ io_lib:format("~s~s(V~s)", [Mod, Fun, FArgs]) ++
" || V <- Value]";
true ->
"[" ++ io_lib:format("~s~s(Value~s)", [Mod, Fun, FArgs])
++ "]"
end;
undefined ->
"[Value]"
end,
Default = case get_dec_fun(Var, Type, Options, State) of
_ when ?is_multi_type(Type) -> "[]";
undefined -> "<<>>";
_MFA -> "undefined"
end,
io_lib:format(
"case Value of"
" ~s -> [];~n"
" Value -> ~s~n"
"end",
[Default, EncFun]).
mk_encoded_options(#xdata_field{var = Var, type = Type,
options = Options}, State) ->
EncFun = case get_enc_fun(Var, Type, Options, State) of
{M, Fun, Args} ->
Mod = if M == undefined -> "";
true -> io_lib:format("~s:", [M])
end,
FArgs = [io_lib:format(", ~p", [A]) || A <- Args],
io_lib:format("~s~s(V~s)", [Mod, Fun, FArgs]);
undefined ->
"V"
end,
EncOpts = string:join(
[case L of
<<>> ->
io_lib:format("#xdata_option{value = ~p}", [V]);
_ ->
io_lib:format(
"#xdata_option{label = Translate(~p), value = ~p}",
[L, V])
end || #xdata_option{label = L, value = V} <- Options],
","),
if ?is_list_type(Type) ->
io_lib:format(
"if Options == default ->"
" [~s];"
"true ->"
" [#xdata_option{label = Translate(L), value = ~s}"
" || {L, V} <- Options]"
"end",
[EncOpts, EncFun]);
true ->
"[]"
end.
mk_decoding_fun(#xdata_field{var = Var, type = Type,
options = Options}, State) ->
case get_dec_fun(Var, Type, Options, State) of
{M, Fun, Args} ->
Mod = if M == undefined -> "";
true -> io_lib:format("~s:", [M])
end,
FArgs = [io_lib:format(", ~p", [A]) || A <- Args],
io_lib:format("~s~s(Value~s)", [Mod, Fun, FArgs]);
undefined ->
"Value"
end.
var_to_rec_field(Var, #state{prefix = [Prefix|T]} = State) ->
Size = size(Prefix),
case Var of
<<(Prefix):Size/binary, Rest/binary>> ->
binary_to_atom(Rest, utf8);
_ ->
var_to_rec_field(Var, State#state{prefix = T})
end;
var_to_rec_field(Var, #state{prefix = []}) ->
Var.
get_dec_fun(Var, Type, Options, State) ->
case lists:keyfind(Var, 1, State#state.dec_mfas) of
false when Type == 'list-multi'; Type == 'list-single' ->
if Options /= [] ->
Variants = [binary_to_atom(V, utf8)
|| #xdata_option{value = V} <- Options],
{undefined, dec_enum, [Variants]};
true ->
undefined
end;
false when Type == 'jid-multi'; Type == 'jid-single' ->
{undefined, dec_jid, []};
false when Type == boolean ->
{undefined, dec_bool, []};
false ->
undefined;
{Var, {M, F, A}} ->
{M, F, A};
{Var, {dec_bool, []}} ->
{undefined, dec_bool, []};
{Var, {not_empty, []}} ->
{undefined, not_empty, []};
{Var, {dec_enum, [Variants]}} ->
{undefined, dec_enum, [Variants]};
{Var, {dec_int, Args}} ->
{undefined, dec_int, Args};
{Var, {dec_enum_int, Args}} ->
{undefined, dec_enum_int, Args};
{Var, {dec_jid, []}} ->
{undefined, dec_jid, []}
end.
get_enc_fun(Var, Type, Options, State) ->
case get_dec_fun(Var, Type, Options, State) of
{undefined, dec_enum, _} ->
{undefined, enc_enum, []};
{undefined, dec_bool, _} ->
{undefined, enc_bool, []};
{undefined, dec_int, _} ->
{undefined, enc_int, []};
{undefined, dec_enum_int, _} ->
{undefined, enc_enum_int, []};
{undefined, dec_jid, _} ->
{undefined, enc_jid, []};
_ ->
case lists:keyfind(Var, 1, State#state.enc_mfas) of
false ->
undefined;
{Var, {M, F, A}} ->
{M, F, A};
{Var, {enc_bool, []}} ->
{undefined, enc_bool, []};
{Var, {dec_enum, _}} ->
{undefined, enc_enum, []};
{Var, {enc_int, _}} ->
{undefined, enc_int, []};
{Var, {dec_enum_int, _}} ->
{undefined, enc_enum_int, []};
{Var, {enc_jid, _}} ->
{undefined, enc_jid, []}
end
end.
mk_typespec(#xdata_field{type = Type, var = Var} = Field, State) ->
Spec0 = get_typespec(Field, State),
Spec1 = case is_complex_type(Spec0) of
true ->
io_lib:format("'~s'()", [var_to_rec_field(Var, State)]);
false ->
Spec0
end,
if ?is_multi_type(Type) -> "[" ++ Spec1 ++ "]";
true -> Spec1
end.
get_typespec(#xdata_field{var = Var, type = Type, options = Options}, State) ->
case lists:keyfind(Var, 1, State#state.specs) of
false ->
case get_dec_fun(Var, Type, Options, State) of
{undefined, dec_enum, Args} ->
enum_spec(Args);
{undefined, dec_bool, _} ->
"boolean()";
{undefined, dec_jid, _} ->
"jid:jid()";
{undefined, dec_int, Args} ->
int_spec(Args);
{undefined, dec_enum_int, [Variants|T]} ->
enum_spec([Variants]) ++ " | " ++ int_spec(T);
_ ->
"binary()"
end;
{Var, Spec} ->
Spec
end.
-spec is_complex_type(string()) -> boolean().
is_complex_type(Spec) ->
string:chr(Spec, $|) /= 0.
int_spec([]) ->
"integer()";
int_spec([From, To]) ->
if From /= infinity, To /= infinity ->
io_lib:format("~p..~p", [From, To]);
From > 0 ->
"pos_integer()";
From == 0 ->
"non_neg_integer()";
true ->
"integer()"
end.
enum_spec([Variants]) ->
string:join([atom_to_list(V) || V <- Variants], " | ").
is_required(Var, State) ->
lists:member(Var, State#state.required) orelse
proplists:get_bool(Var, State#state.required).
normalize(#xmlel{name = Name, attrs = Attrs, children = Els}) ->
#xmlel{name = Name,
attrs = [normalize(Attr) || Attr <- Attrs],
children = [normalize(El) || El <- Els]};
normalize({Key, Data}) ->
{Key, normalize(Data)};
normalize(Txt) when is_binary(Txt) ->
case re:split(Txt, "[\\s\\r\\n\\t]+", [trim, {return, list}]) of
[""|T] ->
list_to_binary(string:join(T, " "));
T ->
list_to_binary(string:join(T, " "))
end.

View File

@ -1,827 +0,0 @@
%%%-------------------------------------------------------------------
%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2015, Evgeny Khramtsov
%%% @doc
%%%
%%% @end
%%% Created : 9 Dec 2015 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
-module(xmpp).
%% API
-export([make_iq_result/1, make_iq_result/2, make_error/2,
decode/1, decode/3, encode/1, encode/2,
get_type/1, get_to/1, get_from/1, get_id/1,
get_lang/1, get_error/1, get_els/1, get_ns/1,
set_type/2, set_to/2, set_from/2, set_id/2,
set_lang/2, set_error/2, set_els/2, set_from_to/3,
format_error/1, is_stanza/1, set_subtag/2, get_subtag/2,
remove_subtag/2, has_subtag/2, decode_els/1, decode_els/3,
pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2,
is_known_tag/1, is_known_tag/2, append_subtags/2]).
%% XMPP errors
-export([err_bad_request/0, err_bad_request/2,
err_conflict/0, err_conflict/2,
err_feature_not_implemented/0, err_feature_not_implemented/2,
err_forbidden/0, err_forbidden/2,
err_gone/0, err_gone/2,
err_internal_server_error/0, err_internal_server_error/2,
err_item_not_found/0, err_item_not_found/2,
err_jid_malformed/0, err_jid_malformed/2,
err_not_acceptable/0, err_not_acceptable/2,
err_not_allowed/0, err_not_allowed/2,
err_not_authorized/0, err_not_authorized/2,
err_payment_required/0, err_payment_required/2,
err_policy_violation/0, err_policy_violation/2,
err_recipient_unavailable/0, err_recipient_unavailable/2,
err_redirect/0, err_redirect/2,
err_registration_required/0, err_registration_required/2,
err_remote_server_not_found/0, err_remote_server_not_found/2,
err_remote_server_timeout/0, err_remote_server_timeout/2,
err_resource_constraint/0, err_resource_constraint/2,
err_service_unavailable/0, err_service_unavailable/2,
err_subscription_required/0, err_subscription_required/2,
err_undefined_condition/1, err_undefined_condition/3,
err_unexpected_request/0, err_unexpected_request/2]).
%% XMPP stream errors
-export([serr_bad_format/0, serr_bad_format/2,
serr_bad_namespace_prefix/0, serr_bad_namespace_prefix/2,
serr_conflict/0, serr_conflict/2,
serr_connection_timeout/0, serr_connection_timeout/2,
serr_host_gone/0, serr_host_gone/2,
serr_host_unknown/0, serr_host_unknown/2,
serr_improper_addressing/0, serr_improper_addressing/2,
serr_internal_server_error/0, serr_internal_server_error/2,
serr_invalid_from/0, serr_invalid_from/2,
serr_invalid_id/0, serr_invalid_id/2,
serr_invalid_namespace/0, serr_invalid_namespace/2,
serr_invalid_xml/0, serr_invalid_xml/2,
serr_not_authorized/0, serr_not_authorized/2,
serr_not_well_formed/0, serr_not_well_formed/2,
serr_policy_violation/0, serr_policy_violation/2,
serr_remote_connection_failed/0, serr_remote_connection_failed/2,
serr_reset/0, serr_reset/2,
serr_resource_constraint/0, serr_resource_constraint/2,
serr_restricted_xml/0, serr_restricted_xml/2,
serr_see_other_host/0, serr_see_other_host/2,
serr_system_shutdown/0, serr_system_shutdown/2,
serr_undefined_condition/0, serr_undefined_condition/2,
serr_unsupported_encoding/0, serr_unsupported_encoding/2,
serr_unsupported_stanza_type/0, serr_unsupported_stanza_type/2,
serr_unsupported_version/0, serr_unsupported_version/2]).
-include("xmpp.hrl").
%%%===================================================================
%%% API
%%%===================================================================
-spec make_iq_result(iq()) -> iq().
make_iq_result(IQ) ->
make_iq_result(IQ, undefined).
-spec make_iq_result(iq(), xmpp_element() | xmlel() | undefined) -> iq().
make_iq_result(#iq{type = Type, from = From, to = To} = IQ, El)
when Type == get; Type == set ->
SubEls = if El == undefined -> [];
true -> [El]
end,
IQ#iq{type = result, to = From, from = To, sub_els = SubEls}.
-spec make_error(message(), stanza_error() | xmlel()) -> message();
(presence(), stanza_error() | xmlel()) -> presence();
(iq(), stanza_error() | xmlel()) -> iq();
(xmlel(), stanza_error() | xmlel()) -> xmlel().
make_error(#message{type = Type, from = From, to = To, sub_els = Els} = Msg,
Err) when Type /= error ->
Msg#message{type = error, from = To, to = From, sub_els = Els ++ [Err]};
make_error(#presence{type = Type, from = From, to = To, sub_els = Els} = Pres,
Err) when Type /= error ->
Pres#presence{type = error, from = To, to = From, sub_els = Els ++ [Err]};
make_error(#iq{type = Type, from = From, to = To, sub_els = Els} = IQ,
Err) when Type /= result, Type /= error ->
IQ#iq{type = error, from = To, to = From, sub_els = Els ++ [Err]};
make_error(#xmlel{attrs = Attrs, children = Els} = El, Err) ->
To = fxml:get_attr(<<"to">>, Attrs),
From = fxml:get_attr(<<"from">>, Attrs),
Attrs1 = case To of
{value, T} ->
lists:keystore(<<"from">>, 1, Attrs, {<<"from">>, T});
_ ->
Attrs
end,
Attrs2 = case From of
{value, F} ->
lists:keystore(<<"to">>, 1, Attrs1, {<<"to">>, F});
_ ->
Attrs
end,
Attrs3 = lists:keystore(<<"type">>, 1, Attrs2, {<<"type">>, <<"error">>}),
El#xmlel{attrs = Attrs3, children = Els ++ [encode(Err, ?NS_CLIENT)]}.
-spec get_id(iq() | message() | presence() | xmlel()) -> binary().
get_id(#iq{id = ID}) -> ID;
get_id(#message{id = ID}) -> ID;
get_id(#presence{id = ID}) -> ID;
get_id(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"id">>, Attrs).
-spec get_type(iq()) -> iq_type();
(message()) -> message_type();
(presence()) -> presence_type();
(xmlel()) -> binary().
get_type(#iq{type = T}) -> T;
get_type(#message{type = T}) -> T;
get_type(#presence{type = T}) -> T;
get_type(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"type">>, Attrs).
-spec get_lang(iq() | message() | presence() | xmlel()) -> binary().
get_lang(#iq{lang = L}) -> L;
get_lang(#message{lang = L}) -> L;
get_lang(#presence{lang = L}) -> L;
get_lang(#xmlel{attrs = Attrs}) -> fxml:get_attr_s(<<"xml:lang">>, Attrs).
-spec get_from(iq() | message() | presence()) -> undefined | jid:jid().
get_from(#iq{from = J}) -> J;
get_from(#message{from = J}) -> J;
get_from(#presence{from = J}) -> J.
-spec get_to(iq() | message() | presence()) -> undefined | jid:jid().
get_to(#iq{to = J}) -> J;
get_to(#message{to = J}) -> J;
get_to(#presence{to = J}) -> J.
-spec get_error(iq() | message() | presence()) -> undefined | stanza_error().
get_error(Stanza) ->
case get_subtag(Stanza, #stanza_error{}) of
false -> undefined;
Error -> Error
end.
-spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()];
(xmlel()) -> [xmlel()].
get_els(#iq{sub_els = Els}) -> Els;
get_els(#message{sub_els = Els}) -> Els;
get_els(#presence{sub_els = Els}) -> Els;
get_els(#xmlel{children = Els}) -> [El || El = #xmlel{} <- Els].
-spec set_id(iq(), binary()) -> iq();
(message(), binary()) -> message();
(presence(), binary()) -> presence().
set_id(#iq{} = IQ, I) -> IQ#iq{id = I};
set_id(#message{} = Msg, I) -> Msg#message{id = I};
set_id(#presence{} = Pres, I) -> Pres#presence{id = I}.
-spec set_type(iq(), iq_type()) -> iq();
(message(), message_type()) -> message();
(presence(), presence_type()) -> presence().
set_type(#iq{} = IQ, T) -> IQ#iq{type = T};
set_type(#message{} = Msg, T) -> Msg#message{type = T};
set_type(#presence{} = Pres, T) -> Pres#presence{type = T}.
-spec set_lang(iq(), binary()) -> iq();
(message(), binary()) -> message();
(presence(), binary()) -> presence().
set_lang(#iq{} = IQ, L) -> IQ#iq{lang = L};
set_lang(#message{} = Msg, L) -> Msg#message{lang = L};
set_lang(#presence{} = Pres, L) -> Pres#presence{lang = L}.
-spec set_from(iq(), jid:jid()) -> iq();
(message(), jid:jid()) -> message();
(presence(), jid:jid()) -> presence().
set_from(#iq{} = IQ, J) -> IQ#iq{from = J};
set_from(#message{} = Msg, J) -> Msg#message{from = J};
set_from(#presence{} = Pres, J) -> Pres#presence{from = J}.
-spec set_to(iq(), jid:jid()) -> iq();
(message(), jid:jid()) -> message();
(presence(), jid:jid()) -> presence().
set_to(#iq{} = IQ, J) -> IQ#iq{to = J};
set_to(#message{} = Msg, J) -> Msg#message{to = J};
set_to(#presence{} = Pres, J) -> Pres#presence{to = J}.
-spec set_from_to(iq(), undefined | jid:jid(), undefined | jid:jid()) -> iq();
(message(), undefined | jid:jid(), undefined | jid:jid()) -> message();
(presence(), undefined | jid:jid(), undefined | jid:jid()) -> presence().
set_from_to(#iq{} = IQ, F, T) -> IQ#iq{from = F, to = T};
set_from_to(#message{} = Msg, F, T) -> Msg#message{from = F, to = T};
set_from_to(#presence{} = Pres, F, T) -> Pres#presence{from = F, to = T}.
-spec set_error(iq(), stanza_error()) -> iq();
(message(), stanza_error()) -> message();
(presence(), stanza_error()) -> presence().
set_error(Stanza, E) -> set_subtag(Stanza, E).
-spec set_els(iq(), [xmpp_element() | xmlel()]) -> iq();
(message(), [xmpp_element() | xmlel()]) -> message();
(presence(), [xmpp_element() | xmlel()]) -> presence().
set_els(#iq{} = IQ, Els) -> IQ#iq{sub_els = Els};
set_els(#message{} = Msg, Els) -> Msg#message{sub_els = Els};
set_els(#presence{} = Pres, Els) -> Pres#presence{sub_els = Els}.
-spec get_ns(xmpp_element() | xmlel()) -> binary().
get_ns(#xmlel{attrs = Attrs}) ->
fxml:get_attr_s(<<"xmlns">>, Attrs);
get_ns(Pkt) ->
xmpp_codec:get_ns(Pkt).
-spec get_name(xmpp_element() | xmlel()) -> binary().
get_name(#xmlel{name = Name}) ->
Name;
get_name(Pkt) ->
xmpp_codec:get_name(Pkt).
-spec decode(xmlel() | xmpp_element()) -> {ok, xmpp_element()} | {error, any()}.
decode(El) ->
decode(El, ?NS_CLIENT, []).
-spec decode(xmlel() | xmpp_element(), binary(), [proplists:property()]) ->
{ok, xmpp_element()} | {error, any()}.
decode(#xmlel{} = El, TopXMLNS, Opts) ->
xmpp_codec:decode(El, TopXMLNS, Opts);
decode(Pkt, _, _) ->
Pkt.
-spec decode_els(iq()) -> iq();
(message()) -> message();
(presence()) -> presence().
decode_els(Stanza) ->
decode_els(Stanza, ?NS_CLIENT, fun is_known_tag/1).
-type match_fun() :: fun((xmlel()) -> boolean()).
-spec decode_els(iq(), binary(), match_fun()) -> iq();
(message(), binary(), match_fun()) -> message();
(presence(), binary(), match_fun()) -> presence().
decode_els(Stanza, TopXMLNS, MatchFun) ->
Els = lists:map(
fun(#xmlel{} = El) ->
case MatchFun(El) of
true -> decode(El, TopXMLNS, []);
false -> El
end;
(Pkt) ->
Pkt
end, get_els(Stanza)),
set_els(Stanza, Els).
-spec encode(xmpp_element() | xmlel()) -> xmlel().
encode(Pkt) ->
encode(Pkt, <<>>).
-spec encode(xmpp_element() | xmlel(), binary()) -> xmlel().
encode(Pkt, TopXMLNS) ->
xmpp_codec:encode(Pkt, TopXMLNS).
-spec is_known_tag(xmlel()) -> boolean().
is_known_tag(El) ->
is_known_tag(El, ?NS_CLIENT).
-spec is_known_tag(xmlel(), binary()) -> boolean().
is_known_tag(El, TopXMLNS) ->
xmpp_codec:is_known_tag(El, TopXMLNS).
format_error(Reason) ->
xmpp_codec:format_error(Reason).
-spec is_stanza(any()) -> boolean().
is_stanza(#message{}) -> true;
is_stanza(#iq{}) -> true;
is_stanza(#presence{}) -> true;
is_stanza(#xmlel{name = Name}) ->
(Name == <<"iq">>) or (Name == <<"message">>) or (Name == <<"presence">>);
is_stanza(_) -> false.
-spec set_subtag(iq(), xmpp_element()) -> iq();
(message(), xmpp_element()) -> message();
(presence(), xmpp_element()) -> presence().
set_subtag(Stanza, Tag) ->
TagName = xmpp_codec:get_name(Tag),
XMLNS = xmpp_codec:get_ns(Tag),
Els = get_els(Stanza),
NewEls = set_subtag(Els, Tag, TagName, XMLNS),
set_els(Stanza, NewEls).
set_subtag([El|Els], Tag, TagName, XMLNS) ->
case match_tag(El, TagName, XMLNS) of
true ->
[Tag|Els];
false ->
[El|set_subtag(Els, Tag, TagName, XMLNS)]
end;
set_subtag([], Tag, _, _) ->
[Tag].
-spec get_subtag(stanza(), xmpp_element()) -> xmpp_element() | false.
get_subtag(Stanza, Tag) ->
Els = get_els(Stanza),
TagName = xmpp_codec:get_name(Tag),
XMLNS = xmpp_codec:get_ns(Tag),
get_subtag(Els, TagName, XMLNS).
get_subtag([El|Els], TagName, XMLNS) ->
case match_tag(El, TagName, XMLNS) of
true ->
try
decode(El)
catch _:{xmpp_codec, _Why} ->
get_subtag(Els, TagName, XMLNS)
end;
false ->
get_subtag(Els, TagName, XMLNS)
end;
get_subtag([], _, _) ->
false.
-spec remove_subtag(iq(), xmpp_element()) -> iq();
(message(), xmpp_element()) -> message();
(presence(), xmpp_element()) -> presence().
remove_subtag(Stanza, Tag) ->
Els = get_els(Stanza),
TagName = xmpp_codec:get_name(Tag),
XMLNS = xmpp_codec:get_ns(Tag),
NewEls = remove_subtag(Els, TagName, XMLNS),
set_els(Stanza, NewEls).
remove_subtag([El|Els], TagName, XMLNS) ->
case match_tag(El, TagName, XMLNS) of
true ->
remove_subtag(Els, TagName, XMLNS);
false ->
[El|remove_subtag(Els, TagName, XMLNS)]
end;
remove_subtag([], _, _) ->
[].
-spec has_subtag(stanza(), xmpp_element()) -> boolean().
has_subtag(Stanza, Tag) ->
Els = get_els(Stanza),
TagName = xmpp_codec:get_name(Tag),
XMLNS = xmpp_codec:get_ns(Tag),
has_subtag(Els, TagName, XMLNS).
has_subtag([El|Els], TagName, XMLNS) ->
case match_tag(El, TagName, XMLNS) of
true ->
true;
false ->
has_subtag(Els, TagName, XMLNS)
end;
has_subtag([], _, _) ->
false.
-spec append_subtags(stanza(), [xmpp_element() | xmlel()]) -> stanza().
append_subtags(Stanza, Tags) ->
Els = get_els(Stanza),
set_els(Stanza, Els ++ Tags).
-spec get_text([text()]) -> binary().
get_text([]) -> <<"">>;
get_text([#text{data = Data}|_]) -> Data.
-spec mk_text(binary()) -> [text()].
mk_text(Text) ->
mk_text(Text, <<"">>).
-spec mk_text(binary(), binary()) -> [text()].
mk_text(<<"">>, _) ->
[];
mk_text(Text, Lang) ->
[#text{lang = Lang,
data = translate:translate(Lang, Text)}].
-spec pp(any()) -> iodata().
pp(Term) ->
xmpp_codec:pp(Term).
%%%===================================================================
%%% Functions to construct general XMPP errors
%%%===================================================================
-spec err_bad_request() -> stanza_error().
err_bad_request() ->
err(modify, 'bad-request', 400).
-spec err_bad_request(binary(), binary()) -> stanza_error().
err_bad_request(Text, Lang) ->
err(modify, 'bad-request', 400, Text, Lang).
-spec err_conflict() -> stanza_error().
err_conflict() ->
err(cancel, 'conflict', 409).
-spec err_conflict(binary(), binary()) -> stanza_error().
err_conflict(Text, Lang) ->
err(cancel, 'conflict', 409, Text, Lang).
-spec err_feature_not_implemented() -> stanza_error().
err_feature_not_implemented() ->
err(cancel, 'feature-not-implemented', 501).
-spec err_feature_not_implemented(binary(), binary()) -> stanza_error().
err_feature_not_implemented(Text, Lang) ->
err(cancel, 'feature-not-implemented', 501, Text, Lang).
-spec err_forbidden() -> stanza_error().
err_forbidden() ->
err(auth, 'forbidden', 403).
-spec err_forbidden(binary(), binary()) -> stanza_error().
err_forbidden(Text, Lang) ->
err(auth, 'forbidden', 403, Text, Lang).
%% RFC 6120 says error type SHOULD be "cancel".
%% RFC 3920 and XEP-0082 says it SHOULD be "modify".
-spec err_gone() -> stanza_error().
err_gone() ->
err(modify, 'gone', 302).
-spec err_gone(binary(), binary()) -> stanza_error().
err_gone(Text, Lang) ->
err(modify, 'gone', 302, Text, Lang).
%% RFC 6120 sasy error type SHOULD be "cancel".
%% RFC 3920 and XEP-0082 says it SHOULD be "wait".
-spec err_internal_server_error() -> stanza_error().
err_internal_server_error() ->
err(wait, 'internal-server-error', 500).
-spec err_internal_server_error(binary(), binary()) -> stanza_error().
err_internal_server_error(Text, Lang) ->
err(wait, 'internal-server-error', 500, Text, Lang).
-spec err_item_not_found() -> stanza_error().
err_item_not_found() ->
err(cancel, 'item-not-found', 404).
-spec err_item_not_found(binary(), binary()) -> stanza_error().
err_item_not_found(Text, Lang) ->
err(cancel, 'item-not-found', 404, Text, Lang).
-spec err_jid_malformed() -> stanza_error().
err_jid_malformed() ->
err(modify, 'jid-malformed', 400).
-spec err_jid_malformed(binary(), binary()) -> stanza_error().
err_jid_malformed(Text, Lang) ->
err(modify, 'jid-malformed', 400, Text, Lang).
-spec err_not_acceptable() -> stanza_error().
err_not_acceptable() ->
err(modify, 'not-acceptable', 406).
-spec err_not_acceptable(binary(), binary()) -> stanza_error().
err_not_acceptable(Text, Lang) ->
err(modify, 'not-acceptable', 406, Text, Lang).
-spec err_not_allowed() -> stanza_error().
err_not_allowed() ->
err(cancel, 'not-allowed', 405).
-spec err_not_allowed(binary(), binary()) -> stanza_error().
err_not_allowed(Text, Lang) ->
err(cancel, 'not-allowed', 405, Text, Lang).
-spec err_not_authorized() -> stanza_error().
err_not_authorized() ->
err(auth, 'not-authorized', 401).
-spec err_not_authorized(binary(), binary()) -> stanza_error().
err_not_authorized(Text, Lang) ->
err(auth, 'not-authorized', 401, Text, Lang).
-spec err_payment_required() -> stanza_error().
err_payment_required() ->
err(auth, 'not-authorized', 402).
-spec err_payment_required(binary(), binary()) -> stanza_error().
err_payment_required(Text, Lang) ->
err(auth, 'not-authorized', 402, Text, Lang).
%% <policy-violation/> is defined in neither RFC 3920 nor XEP-0086.
%% We choose '403' error code (as in <forbidden/>).
-spec err_policy_violation() -> stanza_error().
err_policy_violation() ->
err(modify, 'policy-violation', 403).
-spec err_policy_violation(binary(), binary()) -> stanza_error().
err_policy_violation(Text, Lang) ->
err(modify, 'policy-violation', 403, Text, Lang).
-spec err_recipient_unavailable() -> stanza_error().
err_recipient_unavailable() ->
err(wait, 'recipient-unavailable', 404).
-spec err_recipient_unavailable(binary(), binary()) -> stanza_error().
err_recipient_unavailable(Text, Lang) ->
err(wait, 'recipient-unavailable', 404, Text, Lang).
-spec err_redirect() -> stanza_error().
err_redirect() ->
err(modify, 'redirect', 302).
-spec err_redirect(binary(), binary()) -> stanza_error().
err_redirect(Text, Lang) ->
err(modify, 'redirect', 302, Text, Lang).
-spec err_registration_required() -> stanza_error().
err_registration_required() ->
err(auth, 'registration-required', 407).
-spec err_registration_required(binary(), binary()) -> stanza_error().
err_registration_required(Text, Lang) ->
err(auth, 'registration-required', 407, Text, Lang).
-spec err_remote_server_not_found() -> stanza_error().
err_remote_server_not_found() ->
err(cancel, 'remote-server-not-found', 404).
-spec err_remote_server_not_found(binary(), binary()) -> stanza_error().
err_remote_server_not_found(Text, Lang) ->
err(cancel, 'remote-server-not-found', 404, Text, Lang).
-spec err_remote_server_timeout() -> stanza_error().
err_remote_server_timeout() ->
err(wait, 'remote-server-timeout', 504).
-spec err_remote_server_timeout(binary(), binary()) -> stanza_error().
err_remote_server_timeout(Text, Lang) ->
err(wait, 'remote-server-timeout', 504, Text, Lang).
-spec err_resource_constraint() -> stanza_error().
err_resource_constraint() ->
err(wait, 'resource-constraint', 500).
-spec err_resource_constraint(binary(), binary()) -> stanza_error().
err_resource_constraint(Text, Lang) ->
err(wait, 'resource-constraint', 500, Text, Lang).
-spec err_service_unavailable() -> stanza_error().
err_service_unavailable() ->
err(cancel, 'service-unavailable', 503).
-spec err_service_unavailable(binary(), binary()) -> stanza_error().
err_service_unavailable(Text, Lang) ->
err(cancel, 'service-unavailable', 503, Text, Lang).
-spec err_subscription_required() -> stanza_error().
err_subscription_required() ->
err(auth, 'subscription-required', 407).
-spec err_subscription_required(binary(), binary()) -> stanza_error().
err_subscription_required(Text, Lang) ->
err(auth, 'subscription-required', 407, Text, Lang).
%% No error type is defined for <undefined-confition/>.
%% Let user provide the type.
-spec err_undefined_condition('auth' | 'cancel' | 'continue' |
'modify' | 'wait') -> stanza_error().
err_undefined_condition(Type) ->
err(Type, 'undefined-condition', 500).
-spec err_undefined_condition('auth' | 'cancel' | 'continue' | 'modify' | 'wait',
binary(), binary()) -> stanza_error().
err_undefined_condition(Type, Text, Lang) ->
err(Type, 'undefined-condition', 500, Text, Lang).
%% RFC 6120 says error type SHOULD be "wait" or "modify".
%% RFC 3920 and XEP-0082 says it SHOULD be "wait".
-spec err_unexpected_request() -> stanza_error().
err_unexpected_request() ->
err(wait, 'unexpected-request', 400).
-spec err_unexpected_request(binary(), binary()) -> stanza_error().
err_unexpected_request(Text, Lang) ->
err(wait, 'unexpected-request', 400, Text, Lang).
%%%===================================================================
%%% Functions to construct stream errors
%%%===================================================================
-spec serr_bad_format() -> stream_error().
serr_bad_format() ->
serr('bad-format').
-spec serr_bad_format(binary(), binary()) -> stream_error().
serr_bad_format(Text, Lang) ->
serr('bad-format', Text, Lang).
-spec serr_bad_namespace_prefix() -> stream_error().
serr_bad_namespace_prefix() ->
serr('bad-namespace-prefix').
-spec serr_bad_namespace_prefix(binary(), binary()) -> stream_error().
serr_bad_namespace_prefix(Text, Lang) ->
serr('bad-namespace-prefix', Text, Lang).
-spec serr_conflict() -> stream_error().
serr_conflict() ->
serr('conflict').
-spec serr_conflict(binary(), binary()) -> stream_error().
serr_conflict(Text, Lang) ->
serr('conflict', Text, Lang).
-spec serr_connection_timeout() -> stream_error().
serr_connection_timeout() ->
serr('connection-timeout').
-spec serr_connection_timeout(binary(), binary()) -> stream_error().
serr_connection_timeout(Text, Lang) ->
serr('connection-timeout', Text, Lang).
-spec serr_host_gone() -> stream_error().
serr_host_gone() ->
serr('host-gone').
-spec serr_host_gone(binary(), binary()) -> stream_error().
serr_host_gone(Text, Lang) ->
serr('host-gone', Text, Lang).
-spec serr_host_unknown() -> stream_error().
serr_host_unknown() ->
serr('host-unknown').
-spec serr_host_unknown(binary(), binary()) -> stream_error().
serr_host_unknown(Text, Lang) ->
serr('host-unknown', Text, Lang).
-spec serr_improper_addressing() -> stream_error().
serr_improper_addressing() ->
serr('improper-addressing').
-spec serr_improper_addressing(binary(), binary()) -> stream_error().
serr_improper_addressing(Text, Lang) ->
serr('improper-addressing', Text, Lang).
-spec serr_internal_server_error() -> stream_error().
serr_internal_server_error() ->
serr('internal-server-error').
-spec serr_internal_server_error(binary(), binary()) -> stream_error().
serr_internal_server_error(Text, Lang) ->
serr('internal-server-error', Text, Lang).
-spec serr_invalid_from() -> stream_error().
serr_invalid_from() ->
serr('invalid-from').
-spec serr_invalid_from(binary(), binary()) -> stream_error().
serr_invalid_from(Text, Lang) ->
serr('invalid-from', Text, Lang).
-spec serr_invalid_id() -> stream_error().
serr_invalid_id() ->
serr('invalid-id').
-spec serr_invalid_id(binary(), binary()) -> stream_error().
serr_invalid_id(Text, Lang) ->
serr('invalid-id', Text, Lang).
-spec serr_invalid_namespace() -> stream_error().
serr_invalid_namespace() ->
serr('invalid-namespace').
-spec serr_invalid_namespace(binary(), binary()) -> stream_error().
serr_invalid_namespace(Text, Lang) ->
serr('invalid-namespace', Text, Lang).
-spec serr_invalid_xml() -> stream_error().
serr_invalid_xml() ->
serr('invalid-xml').
-spec serr_invalid_xml(binary(), binary()) -> stream_error().
serr_invalid_xml(Text, Lang) ->
serr('invalid-xml', Text, Lang).
-spec serr_not_authorized() -> stream_error().
serr_not_authorized() ->
serr('not-authorized').
-spec serr_not_authorized(binary(), binary()) -> stream_error().
serr_not_authorized(Text, Lang) ->
serr('not-authorized', Text, Lang).
-spec serr_not_well_formed() -> stream_error().
serr_not_well_formed() ->
serr('not-well-formed').
-spec serr_not_well_formed(binary(), binary()) -> stream_error().
serr_not_well_formed(Text, Lang) ->
serr('not-well-formed', Text, Lang).
-spec serr_policy_violation() -> stream_error().
serr_policy_violation() ->
serr('policy-violation').
-spec serr_policy_violation(binary(), binary()) -> stream_error().
serr_policy_violation(Text, Lang) ->
serr('policy-violation', Text, Lang).
-spec serr_remote_connection_failed() -> stream_error().
serr_remote_connection_failed() ->
serr('remote-connection-failed').
-spec serr_remote_connection_failed(binary(), binary()) -> stream_error().
serr_remote_connection_failed(Text, Lang) ->
serr('remote-connection-failed', Text, Lang).
-spec serr_reset() -> stream_error().
serr_reset() ->
serr('reset').
-spec serr_reset(binary(), binary()) -> stream_error().
serr_reset(Text, Lang) ->
serr('reset', Text, Lang).
-spec serr_resource_constraint() -> stream_error().
serr_resource_constraint() ->
serr('resource-constraint').
-spec serr_resource_constraint(binary(), binary()) -> stream_error().
serr_resource_constraint(Text, Lang) ->
serr('resource-constraint', Text, Lang).
-spec serr_restricted_xml() -> stream_error().
serr_restricted_xml() ->
serr('restricted-xml').
-spec serr_restricted_xml(binary(), binary()) -> stream_error().
serr_restricted_xml(Text, Lang) ->
serr('restricted-xml', Text, Lang).
-spec serr_see_other_host() -> stream_error().
serr_see_other_host() ->
serr('see-other-host').
-spec serr_see_other_host(binary(), binary()) -> stream_error().
serr_see_other_host(Text, Lang) ->
serr('see-other-host', Text, Lang).
-spec serr_system_shutdown() -> stream_error().
serr_system_shutdown() ->
serr('system-shutdown').
-spec serr_system_shutdown(binary(), binary()) -> stream_error().
serr_system_shutdown(Text, Lang) ->
serr('system-shutdown', Text, Lang).
-spec serr_undefined_condition() -> stream_error().
serr_undefined_condition() ->
serr('undefined-condition').
-spec serr_undefined_condition(binary(), binary()) -> stream_error().
serr_undefined_condition(Text, Lang) ->
serr('undefined-condition', Text, Lang).
-spec serr_unsupported_encoding() -> stream_error().
serr_unsupported_encoding() ->
serr('unsupported-encoding').
-spec serr_unsupported_encoding(binary(), binary()) -> stream_error().
serr_unsupported_encoding(Text, Lang) ->
serr('unsupported-encoding', Text, Lang).
-spec serr_unsupported_stanza_type() -> stream_error().
serr_unsupported_stanza_type() ->
serr('unsupported-stanza-type').
-spec serr_unsupported_stanza_type(binary(), binary()) -> stream_error().
serr_unsupported_stanza_type(Text, Lang) ->
serr('unsupported-stanza-type', Text, Lang).
-spec serr_unsupported_version() -> stream_error().
serr_unsupported_version() ->
serr('unsupported-version').
-spec serr_unsupported_version(binary(), binary()) -> stream_error().
serr_unsupported_version(Text, Lang) ->
serr('unsupported-version', Text, Lang).
%%%===================================================================
%%% Internal functions
%%%===================================================================
-spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait',
atom() | gone() | redirect(), non_neg_integer()) -> stanza_error().
err(Type, Reason, Code) ->
#stanza_error{type = Type, reason = Reason, code = Code}.
-spec err('auth' | 'cancel' | 'continue' | 'modify' | 'wait',
atom() | gone() | redirect(), non_neg_integer(),
binary(), binary()) -> stanza_error().
err(Type, Reason, Code, Text, Lang) ->
#stanza_error{type = Type, reason = Reason, code = Code,
text = #text{lang = Lang,
data = translate:translate(Lang, Text)}}.
-spec serr(atom() | 'see-other-host'()) -> stream_error().
serr(Reason) ->
#stream_error{reason = Reason}.
-spec serr(atom() | 'see-other-host'(), binary(),
binary()) -> stream_error().
serr(Reason, Text, Lang) ->
#stream_error{reason = Reason,
text = #text{lang = Lang,
data = translate:translate(Lang, Text)}}.
-spec match_tag(xmlel() | xmpp_element(), binary(), binary()) -> boolean().
match_tag(El, TagName, XMLNS) ->
get_name(El) == TagName andalso get_ns(El) == XMLNS.

File diff suppressed because it is too large Load Diff