diff options
Diffstat (limited to 'src/mod_pubsub_ng/pubsub_options.erl')
-rw-r--r-- | src/mod_pubsub_ng/pubsub_options.erl | 3369 |
1 files changed, 3369 insertions, 0 deletions
diff --git a/src/mod_pubsub_ng/pubsub_options.erl b/src/mod_pubsub_ng/pubsub_options.erl new file mode 100644 index 000000000..46c9c2dd4 --- /dev/null +++ b/src/mod_pubsub_ng/pubsub_options.erl @@ -0,0 +1,3369 @@ +%%% ==================================================================== +%%% ``The contents of this file are subject to the Erlang Public License, +%%% Version 1.1, (the "License"); you may not use this file except in +%%% compliance with the License. You should have received a copy of the +%%% Erlang Public License along with this software. If not, it can be +%%% retrieved via the world wide web at http://www.erlang.org/. +%%% +%%% Software distributed under the License is distributed on an "AS IS" +%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%%% the License for the specific language governing rights and limitations +%%% under the License. +%%% +%%% The Initial Developer of the Original Code is ProcessOne. +%%% Portions created by ProcessOne are Copyright 2006-2011, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2011, ProcessOne. +%%% +%%% @copyright 2006-2011 ProcessOne +%%% @author Karim Gemayel <karim.gemayel@process-one.net> +%%% [http://www.process-one.net/] +%%% @version {@vsn}, {@date} {@time} +%%% @end +%%% ==================================================================== + +%%% @headerfile "pubsub_dev.hrl" + +-module(pubsub_options). +-author('karim.gemayel@process-one.net'). + +-compile(export_all). + +-include("pubsub_dev.hrl"). + +-import(xml, +[ + get_tag_cdata/1, + get_tag_attr_s/2, + remove_cdata/1 +]). + + +-import(pubsub_tools, +[ + get_entity_roster/1, + is_jid/1 +]). + + +%% -------------------------------------------------------------------- +%% Documentation / type definitions. +%% -------------------------------------------------------------------- + +%% Node Options +% pubsub#node_config FORM_TYPE + +% Defined options values + +%-- Access Model --% +-export_type([ + access_model/0, + access_model_open/0, + access_model_presence/0, + access_model_roster/0, + access_model_authorize/0, + access_model_whitelist/0 +]). + +%% @type access_model_open() = 'open'. +-type(access_model_open() :: 'open'). + +%% @type access_model_presence() = 'presence'. +-type(access_model_presence() :: 'presence'). + +%% @type access_model_roster() = 'roster'. +-type(access_model_roster() :: 'roster'). + +%% @type access_model_authorize() = 'authorize'. +-type(access_model_authorize() :: 'authorize'). + +%% @type access_model_whitelist() = 'whitelist'. +-type(access_model_whitelist() :: 'whitelist'). + +%% @type access_model() = Open | Presence | Roster | Authorize | Whitelist +%% Open = pubsub_options:access_model_open() +%% Presence = pubsub_options:access_model_presence() +%% Roster = pubsub_options:access_model_roster() +%% Authorize = pubsub_options:access_model_authorize() +%% Whitelist = pubsub_options:access_model_whitelist(). +-type(access_model() :: pubsub_options:access_model_open() + | pubsub_options:access_model_presence() + | pubsub_options:access_model_roster() + | pubsub_options:access_model_authorize() + | pubsub_options:access_model_whitelist() +). + +%% + +%-- Children_Association_Policy --% +-export_type([ + children_association_policy/0, + %% + children_association_policy_all/0, + children_association_policy_owners/0, + children_association_policy_whitelist/0 +]). + +%% @type children_association_policy_all() = 'all'. +-type(children_association_policy_all() :: 'all'). + +%% @type children_association_policy_owners() = 'owners'. +-type(children_association_policy_owners() :: 'owners'). + +%% @type children_association_policy_whitelist() = 'whitelist'. +-type(children_association_policy_whitelist() :: 'whitelist'). + +%% @type children_association_policy() = All | Owners | Whitelist +%% All = pubsub_options:children_association_policy_all() +%% Owners = pubsub_options:children_association_policy_owners() +%% Whitelist = pubsub_options:children_association_policy_whitelist(). +-type(children_association_policy() + :: pubsub_options:children_association_policy_all() + | pubsub_options:children_association_policy_owners() + | pubsub_options:children_association_policy_whitelist() +). + +%% + +%-- ItemReply -- %% +-export_type([ + item_reply/0, + item_reply_owner/0, + item_reply_publisher/0 +]). + +%% @type(item_reply_owner() = 'owner'). +-type(item_reply_owner() :: 'owner'). + +%% @type(item_reply_publisher() = 'publisher'). +-type(item_reply_publisher() :: 'publisher'). + +%% @type(item_reply() = Owner | Publisher). +-type(item_reply() :: pubsub_options:item_reply_owner() + | pubsub_options:item_reply_publisher() +). + + +-export_type([ + language/0, + description/0, + title/0 +]). + +-type(language() :: binary()). + +-type(description() :: binary()). + +-type(title() :: binary()). + +%% + +%-- Node types --%% + +-export_type([ + node_type/0, + node_type_leaf/0, + node_type_collection/0 +]). + +%% @type node_type_collection() = 'collection'. +-type(node_type_collection() :: 'collection'). + +%% @type node_type_leaf() = 'leaf'. +-type(node_type_leaf() :: 'leaf'). + +%% @type node_type() = Leaf | Collection +%% Leaf = pubsub_options:node_type_leaf() +%% Collection = pubsub_options:node_type_collection() +-type(node_type() :: pubsub_options:node_type_leaf() + | pubsub_options:node_type_collection() +). + +%% + +%-- Notification Types --%% +-export_type([ + notification_type/0, + notification_type_chat/0, + notification_type_headline/0, + notification_type_normal/0 +]). + +-type(notification_type_chat() :: 'chat'). + +-type(notification_type_headline() :: 'headline'). + +-type(notification_type_normal() :: 'normal'). + +-type(notification_type() + :: pubsub_options:notification_type_headline() + | pubsub_options:notification_type_normal() + %| pubsub_options:notification_type_chat() +). + +%% + +%-- Publish Model --% +-export_type([ + publish_model/0, + publish_model_publishers/0, + publish_model_subscribers/0, + publish_model_open/0 +]). + +%% @type publish_model_publishers() = 'publishers'. +-type(publish_model_publishers() :: 'publishers'). + +%% @type publish_model_subscribers() = 'subscribers'. +-type(publish_model_subscribers() :: 'subscribers'). + +%% @type publish_model_open() = 'open'. +-type(publish_model_open() :: 'open'). + +%% @type publish_model() = Publishers | Subscribers | Open +%% Publishers = pubsub_options:publish_model_publishers() +%% Subscribers = pubsub_options:publish_model_subscribers() +%% Open = pubsub_options:publish_model_open() +-type(publish_model() :: pubsub_options:publish_model_publishers() + | pubsub_options:publish_model_subscribers() + | pubsub_options:publish_model_open() +). + + +-export_type([ + roster_group/0, + roster_groups/0, + roster_groups_allowed/0, + rosters_groups_allowed/0 +]). + +-type(roster_group() :: binary()). +-type(roster_groups() :: [pubsub_options:roster_group()]). +-type(roster_groups_allowed() + :: {Node_Owner::xmpp_jid:usr_bare(), + Roster_Groups::pubsub_options:roster_groups()} +). +-type(rosters_groups_allowed() + :: [Roster_Group_Allowed::pubsub_options:roster_groups_allowed()] +). + +%% + +%-- Send Last Published Item --% +-export_type([ + send_last_published_item/0, + %% + send_last_published_item_never/0, + send_last_published_item_on_sub/0, + send_last_published_item_on_sub_and_presence/0 +]). + +%% @type send_last_published_item_never() = 'never'. +-type(send_last_published_item_never() :: 'never'). + +%% @type send_last_published_item_on_sub() = 'on_sub'. +-type(send_last_published_item_on_sub() :: 'on_sub'). + +%% @type send_last_published_item_on_sub_and_presence() = 'on_sub_and_presence'. +-type(send_last_published_item_on_sub_and_presence() :: 'on_sub_and_presence'). + +%% @type send_last_published_item() = Never | On_Sub | On_Sub_And_Presence +%% Never = pubsub_options:send_last_published_item_never() +%% On_Sub = pubsub_options:send_last_published_item_on_sub() +%% On_Sub_And_Presence = pubsub_options:send_last_published_item_on_sub_and_presence(). +-type(send_last_published_item() + :: pubsub_options:send_last_published_item_never() + | pubsub_options:send_last_published_item_on_sub() + | pubsub_options:send_last_published_item_on_sub_and_presence() +). + +%% + + +-export_type([ + option_node_access_model/0, + option_node_children_association_policy/0, + option_node_children_association_whitelist/0, + option_node_children/0, + option_node_children_max/0, + option_node_collections/0, + option_node_children_max_collections/0, + option_node_children_max_multi_collections/0, + option_node_contact/0, + option_node_deliver_notifications/0, + option_node_deliver_payloads/0, + option_node_description/0, + option_node_item_expire/0, + option_node_itemreply/0, + option_node_language/0, + option_node_max_items/0, + option_node_max_payload_size/0, + option_node_node_type_leaf/0, + option_node_node_type_collection/0, + option_node_node_type/0, + option_node_notification_type/0, + option_node_notify_config/0, + option_node_notify_delete/0, + option_node_notify_retract/0, + option_node_notify_sub/0, + option_node_persist_items/0, + option_node_presence_based_delivery/0, + option_node_publish_model/0, + option_node_purge_offline/0, + option_node_roster_groups_allowed/0, + option_node_send_last_published_item/0, + option_node_tempsub/0, + option_node_subscribe/0, + option_node_title/0, + option_node_type/0 +]). + +-type(option_node_access_model() :: + {Key :: 'access_model', + Value :: pubsub_options:access_model()} +). + +%-type(option_node_body_xslt() :: +% {Key :: 'body_xslt(', +% Value :: binary()} +%). + +-type(option_node_children_association_policy() :: + {Key :: 'children_association_policy', + Value :: pubsub_options:children_association_policy()} +). + +-type(option_node_children_association_whitelist() :: + {Key :: 'children_association_whitelist', + Value :: [Jid_Entity::xmpp_jid:raw_jid_entity_bare()]} +). + +-type(option_node_children() :: + {Key :: 'children', + Value :: [NodeId::exmpp_pubsub:nodeId()]} +). + +-type(option_node_children_max() :: + {Key :: 'children_max', + Value :: undefined | non_neg_integer()} +). + +-type(option_node_children_max_collections() :: + {Key :: 'children_max', + Value :: undefined | 0..1} +). + +-type(option_node_children_max_multi_collections() :: + {Key :: 'children_max', + Value :: undefined | non_neg_integer()} +). + + +-type(option_node_collections() :: + {Key :: 'collection', + Value :: [NodeId::exmpp_pubsub:nodeId()]} +). + +-type(option_node_contact() :: + {Key :: 'contact', + Value :: [Jid_Entity::xmpp_jid:raw_jid_entity()]} +). + +%-type(option_node_dataform_xslt() :: +% {Key :: 'dataform_xslt', +% Value :: binary()} +%). + +-type(option_node_deliver_notifications() :: + {Key :: 'deliver_notifications', + Value :: boolean()} +). + +-type(option_node_deliver_payloads() :: + {Key :: 'deliver_payloads', + Value :: boolean()} +). + +-type(option_node_description() :: + {Key :: 'description', + Value :: undefined | pubsub_options:description()} +). + +-type(option_node_item_expire() :: + {Key :: 'item_expire', + Value :: undefined | non_neg_integer()} +). + +-type(option_node_itemreply() :: + {Key :: 'itemreply', + Value :: pubsub_options:item_reply()} +). + +-type(option_node_language() :: + {Key :: 'language', + Value :: undefined | pubsub_options:language()} +). + +-type(option_node_max_items() :: + {Key :: 'max_items', + Value :: undefined | non_neg_integer()} +). + +-type(option_node_max_payload_size() :: + {Key :: 'max_payload_size', + Value :: undefined | non_neg_integer()} +). + +-type(option_node_node_type_leaf() :: + {Key :: 'node_type', + Value :: pubsub_options:node_type_leaf()} +). + +-type(option_node_node_type_collection() :: + {Key :: 'node_type', + Value :: pubsub_options:node_type_collection()} +). + +-type(option_node_node_type() + :: pubsub_options:option_node_node_type_leaf() + | pubsub_options:option_node_node_type_collection() +). + +-type(option_node_notification_type() :: + {Key :: 'notification_type', + Value :: pubsub_options:notification_type()} +). + +-type(option_node_notify_config() :: + {Key :: 'notify_config', + Value :: boolean()} +). + +-type(option_node_notify_delete() :: + {Key :: 'notify_delete', + Value :: boolean()} +). + +-type(option_node_notify_retract() :: + {Key :: 'notify_retract', + Value :: boolean()} +). + +-type(option_node_notify_sub() :: + {Key :: 'notify_sub', + Value :: boolean()} +). + +-type(option_node_persist_items() :: + {Key :: 'persist_items', + Value :: boolean()} +). + +-type(option_node_presence_based_delivery() :: + {Key :: 'presence_based_delivery', + Value :: boolean()} +). + +-type(option_node_publish_model() :: + {Key :: 'publish_model', + Value :: pubsub_options:publish_model()} +). + +-type(option_node_purge_offline() :: + {Key :: 'purge_offline', + Value :: boolean()} +). + +-type(option_node_roster_groups_allowed() :: + {Key :: 'roster_groups_allowed', + Value :: pubsub_options:rosters_groups_allowed()} +). + +-type(option_node_send_last_published_item() :: + {Key :: 'send_last_published_item', + Value :: pubsub_options:send_last_published_item()} +). + +-type(option_node_tempsub() :: + {Key :: 'tempsub', + Value :: boolean()} +). + +-type(option_node_subscribe() :: + {Key :: 'subscribe', + Value :: boolean()} +). + +-type(option_node_title() :: + {Key :: 'title', + Value :: undefined | pubsub_options:title()} +). + +-type(option_node_type() :: + {Key :: 'type', + Value :: undefined | binary()} +). + + + +%-- Node Option Type (local or remote user ; leaf or collection node) --% +-export_type([ + option_node/0, + options_node/0, + %% + option_node_leaf/0, + option_node_collection/0, + %% + options_node_leaf/0, + options_node_collection/0 +]). + +-type(option_node_leaf() + :: pubsub_options:option_node_access_model() + | pubsub_options:option_node_collections() + | pubsub_options:option_node_contact() + | pubsub_options:option_node_deliver_notifications() + | pubsub_options:option_node_deliver_payloads() + | pubsub_options:option_node_description() + | pubsub_options:option_node_item_expire() + | pubsub_options:option_node_itemreply() + | pubsub_options:option_node_language() + | pubsub_options:option_node_max_items() + | pubsub_options:option_node_max_payload_size() + | pubsub_options:option_node_node_type_leaf() + | pubsub_options:option_node_notification_type() + | pubsub_options:option_node_notify_config() + | pubsub_options:option_node_notify_delete() + | pubsub_options:option_node_notify_retract() + | pubsub_options:option_node_notify_sub() + | pubsub_options:option_node_persist_items() + | pubsub_options:option_node_presence_based_delivery() + | pubsub_options:option_node_publish_model() + | pubsub_options:option_node_purge_offline() + | pubsub_options:option_node_roster_groups_allowed() + | pubsub_options:option_node_send_last_published_item() + | pubsub_options:option_node_tempsub() + | pubsub_options:option_node_subscribe() + | pubsub_options:option_node_title() + | pubsub_options:option_node_type() +). + +%% +-type(option_node_collection() + :: pubsub_options:option_node_access_model() + | pubsub_options:option_node_children_association_policy() + | pubsub_options:option_node_children_association_whitelist() + | pubsub_options:option_node_children() + | pubsub_options:option_node_children_max() + | pubsub_options:option_node_collections() + | pubsub_options:option_node_contact() + | pubsub_options:option_node_deliver_notifications() + | pubsub_options:option_node_deliver_payloads() + | pubsub_options:option_node_description() + | pubsub_options:option_node_item_expire() + | pubsub_options:option_node_itemreply() + | pubsub_options:option_node_language() + | pubsub_options:option_node_max_items() + | pubsub_options:option_node_max_payload_size() + | pubsub_options:option_node_node_type_collection() + | pubsub_options:option_node_notification_type() + | pubsub_options:option_node_notify_config() + | pubsub_options:option_node_notify_delete() + | pubsub_options:option_node_notify_retract() + | pubsub_options:option_node_notify_sub() + | pubsub_options:option_node_persist_items() + | pubsub_options:option_node_presence_based_delivery() + | pubsub_options:option_node_publish_model() + | pubsub_options:option_node_purge_offline() + | pubsub_options:option_node_roster_groups_allowed() + | pubsub_options:option_node_send_last_published_item() + | pubsub_options:option_node_tempsub() + | pubsub_options:option_node_subscribe() + | pubsub_options:option_node_title() + | pubsub_options:option_node_type() +). + +%% +-type(option_node() + :: pubsub_options:option_node_leaf() + | pubsub_options:option_node_collection() +). + +%% +-type(options_node_leaf() + :: [pubsub_options:option_node_leaf(),...] +). + +%% +-type(options_node_collection() + :: [pubsub_options:option_node_collection(),...] +). + +%% +-type(options_node() + :: pubsub_options:options_node_leaf() + | pubsub_options:options_node_collection() +). + +%-- Publish-Options --% +%% pubsub#publish-options FORM_TYPE +-export_type([ + option_item_access_model/0, + option_item_deliver_notifications/0, + option_item_deliver_payloads/0, + option_item_item_expire/0, + option_item_itemreply/0, +%%option_item_max_payload_size/0, + option_item_notification_type/0, + option_item_notify_config/0, + option_item_notify_retract/0, + option_item_persist_items/0, + option_item_presence_based_delivery/0, + option_item_publish_model/0, + option_item_purge_offline/0, + option_item_roster_groups_allowed/0, + option_item_send_last_published_item/0, + option_item_type/0 +]). + +-type(option_item_access_model() :: + {Key :: 'access_model', + Value :: pubsub_options:access_model()} +). + +-type(option_item_deliver_notifications() :: + {Key :: 'deliver_notifications', + Value :: boolean()} +). + +-type(option_item_deliver_payloads() :: + {Key :: 'deliver_payloads', + Value :: boolean()} +). + +-type(option_item_item_expire() :: + {Key :: 'item_expire', + Value :: undefined | non_neg_integer()} +). + +-type(option_item_itemreply() :: + {Key :: 'itemreply', + Value :: pubsub_options:item_reply()} +). + +%-type(option_item_max_payload_size() :: +% {Key :: 'max_payload_size', +% Value :: undefined | non_neg_integer()} +%). + +-type(option_item_notification_type() :: + {Key :: 'notification_type', + Value :: pubsub_options:notification_type()} +). + +-type(option_item_notify_config() :: + {Key :: 'notify_config', + Value :: boolean()} +). + +-type(option_item_notify_retract() :: + {Key :: 'notify_retract', + Value :: boolean()} +). + +-type(option_item_persist_items() :: + {Key :: 'persist_items', + Value :: boolean()} +). + +-type(option_item_presence_based_delivery() :: + {Key :: 'presence_based_delivery', + Value :: boolean()} +). + +-type(option_item_publish_model() :: + {Key :: 'publish_model', + Value :: pubsub_options:publish_model()} +). + +-type(option_item_purge_offline() :: + {Key :: 'purge_offline', + Value :: boolean()} +). + +-type(option_item_roster_groups_allowed() :: + {Key :: 'roster_groups_allowed', + Value :: pubsub_options:rosters_groups_allowed()} +). + +-type(option_item_send_last_published_item() :: + {Key :: 'send_last_published_item', + Value :: pubsub_options:send_last_published_item()} +). + +-type(option_item_type() :: + {Key :: 'type', + Value :: undefined | binary()} +). + +-export_type([ + option_item/0, + options_item/0 +]). + +-type(option_item() + :: pubsub_options:option_item_access_model() + | pubsub_options:option_item_deliver_notifications() + | pubsub_options:option_item_deliver_payloads() + | pubsub_options:option_item_item_expire() + | pubsub_options:option_item_itemreply() +%% | pubsub_options:option_item_max_payload_size() + | pubsub_options:option_item_notification_type() + | pubsub_options:option_item_notify_config() + | pubsub_options:option_item_notify_retract() + | pubsub_options:option_item_persist_items() + | pubsub_options:option_item_presence_based_delivery() + | pubsub_options:option_item_publish_model() + | pubsub_options:option_item_purge_offline() + | pubsub_options:option_item_roster_groups_allowed() + | pubsub_options:option_item_send_last_published_item() + | pubsub_options:option_item_type() +). + +%% +-type(options_item() + :: [pubsub_options:option_item(),...] +). + + +%-- Subscription Options --%% +-export_type([ + option_subscription_deliver/0, + option_subscription_expire/0, + option_subscription_expire_presence/0, + option_subscription_expire_datetime/0, + option_subscription_include_body/0, + option_subscription_show_values/0, + option_subscription_subscription_type/0, + option_subscription_subscription_depth/0 +]). + +%% +-type(option_subscription_deliver() :: + {Key :: 'deliver', + Value :: boolean()} +). + +%-type(option_subscription_digest() :: +% {Key :: 'digest', +% Value :: boolean()} +%). + +%-type(option_subscription_digest_frequency() :: +% {Key :: 'digest_frequency', +% Value :: undefined | non_neg_integer()} +%). + +-type(option_subscription_expire_presence() :: + {Key :: 'expire', + Value :: undefined | 'presence'} +). + +-type(option_subscription_expire_datetime() :: + {Key :: 'expire', + Value :: undefined | erlang:timestamp()} +). + +-type(option_subscription_expire() + :: pubsub_options:option_subscription_expire_presence() + | pubsub_options:option_subscription_expire_datetime() +). + +-type(option_subscription_include_body() :: + {Key :: 'include_body', + Value :: boolean()} +). + +-type(option_subscription_show_values() :: + {Key :: 'show-values', + Value :: ['away' | 'chat' | 'dnd' | 'online' | 'xa']} +). + +-type(option_subscription_subscription_type() :: + {Key :: 'subscription_type', + Value :: 'all' | 'items' | 'nodes'} +). + +-type(option_subscription_subscription_depth() :: + {Key :: 'subscription_depth', + Value :: 'all' | exmpp_pubsub:level()} +). + + +-export_type([ + option_subscription/0, + %% + option_subscription_leaf/0, + option_subscription_collection/0, + %% + option_subscription_leaf_local/0, + option_subscription_leaf_remote/0, + %% + option_subscription_collection_local/0, + option_subscription_collection_remote/0 +]). + +%% +-type(option_subscription_leaf_local() + :: pubsub_options:option_subscription_deliver() + | pubsub_options:option_subscription_expire() + % | pubsub_options:option_subscription_include_body() + | pubsub_options:option_subscription_show_values() +). + +%% +-type(option_subscription_leaf_remote() + :: pubsub_options:option_subscription_deliver() + % | pubsub_options:option_subscription_expire_datetime() + % | pubsub_options:option_subscription_include_body() +). + +%% +-type(option_subscription_collection_local() + :: pubsub_options:option_subscription_deliver() + | pubsub_options:option_subscription_expire() + | pubsub_options:option_subscription_expire_presence() + | pubsub_options:option_subscription_expire_datetime() + %| pubsub_options:option_subscription_include_body() + | pubsub_options:option_subscription_show_values() + | pubsub_options:option_subscription_subscription_type() + | pubsub_options:option_subscription_subscription_depth() +). + +%% +-type(option_subscription_collection_remote() + :: pubsub_options:option_subscription_deliver() + | pubsub_options:option_subscription_expire_datetime() + | pubsub_options:option_subscription_include_body() + | pubsub_options:option_subscription_subscription_type() + | pubsub_options:option_subscription_subscription_depth() +). + +%% +-type(option_subscription_leaf() + :: pubsub_options:option_subscription_leaf_local() + | pubsub_options:option_subscription_leaf_remote() +). + +%% +-type(option_subscription_collection() + :: pubsub_options:option_subscription_collection_local() + | pubsub_options:option_subscription_collection_remote() +). + + +%% +-type(option_subscription() + :: pubsub_options:option_subscription_leaf() + | pubsub_options:option_subscription_collection() +). + + +-export_type([ + options_subscription/0, + %% + options_subscription_leaf/0, + options_subscription_collection/0, + %% + options_subscription_local/0, + options_subscription_remote/0, + %% + options_subscription_leaf_local/0, + options_subscription_leaf_remote/0, + %% + options_subscription_collection_local/0, + options_subscription_collection_remote/0 +]). + +%% +-type(options_subscription_leaf_local() + :: [pubsub_options:options_subscription_leaf_local(),...] +). + +%% +-type(options_subscription_leaf_remote() + :: [pubsub_options:options_subscription_leaf_remote(),...] +). + +%% +-type(options_subscription_collection_local() + :: [pubsub_options:options_subscription_collection_local(),...] +). + +%% +-type(options_subscription_collection_remote() + :: [pubsub_options:options_subscription_collection_remote(),...] +). + +%% +-type(options_subscription_leaf() + :: pubsub_options:options_subscription_leaf_local() + | pubsub_options:options_subscription_leaf_remote() +). + +%% +-type(options_subscription_collection() + :: pubsub_options:options_subscription_collection_local() + | pubsub_options:options_subscription_collection_remote() +). + +%% +-type(options_subscription_local() + :: pubsub_options:options_subscription_leaf_local() + | pubsub_options:options_subscription_collection_local() +). + +%% +-type(options_subscription_remote() + :: pubsub_options:options_subscription_leaf_remote() + | pubsub_options:options_subscription_collection_remote() +). + +-type(options_subscription() + :: pubsub_options:options_subscription_leaf() + | pubsub_options:options_subscription_collection() +). + +%% -------------------------------------------------------------------- +%% Functions. +%% -------------------------------------------------------------------- + + +xmlns(Xmlel) -> + get_tag_attr_s(<<"xmlns">>, Xmlel). + + +-define(Is_Xmlel_Field(Xmlel), +( + Xmlel#xmlel.name == <<"field">> +)). + +-define(Is_Xmlel_Value(Xmlel), +( + Xmlel#xmlel.name == <<"value">> andalso + Xmlel#xmlel.attrs == [] +)). + +-define(Is_Xmlel_X(Xmlel), +( + Xmlel#xmlel.name == <<"x">> +)). + +-define(Is_Xmlel_X_Submit(Xmlel), +( + %Xmlel#xmlel.ns == 'jabber:x:data' andalso + Xmlel#xmlel.name == <<"x">> % andalso + % Xmlel#xmlel.attrs == [#xmlattr{name = <<"type">>, value = <<"submit">>}] +)). + +-define(Is_Xmlel_X_Form(Xmlel), +( + %Xmlel#xmlel.ns == 'jabber:x:data' andalso + Xmlel#xmlel.name == <<"x">> andalso + Xmlel#xmlel.attrs == [{<<"type">>, <<"form">>}] +)). + + + +%% +%% +-define(Is_Default_Subscribe_Option(Option), +( + Option == {'deliver', true} + orelse + Option == {'expire', undefined} + orelse + Option == {'include_body', false} + orelse + Option == {'show-values', ['away' , 'chat' , 'dnd' , 'online' , 'xa']} +)). + + +%% +-spec(trim_subscription_options/1 :: +( + Subscription_Options::pubsub_options:options_subscription()) + -> Subscription_Options::pubsub_options:options_subscription() +). + +trim_subscription_options(Subscription_Options) -> + trim_subscription_options(Subscription_Options, []). + +%% +-spec(trim_subscription_options/2 :: +( + Options :: [] | pubsub_options:options_subscription(), + Subscription_Options :: [] | pubsub_options:options_subscription()) + -> Subscription_Options :: [] | pubsub_options:options_subscription() +). + +trim_subscription_options([] = _Options, Subscription_Options) -> + Subscription_Options; +%% +trim_subscription_options([Option | Options], Subscription_Options) + when ?Is_Default_Subscribe_Option(Option) -> + trim_subscription_options(Options, Subscription_Options); +%% +trim_subscription_options([Option | Options], Subscription_Options) -> + trim_subscription_options(Options, [Option | Subscription_Options]). + +%% +-spec(parse_xmlel_x/5 :: +( + Plugin :: exmpp_pubsub:plugin(), + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Entity :: xmpp_jid:usr_entity(), + Form_Type :: 'node_config' | 'publish-options', + Xmlels :: [Xmlel_X::xmlel(),...] + | [Xmlel::xmlel()] + | []) + -> {ok, + Options :: pubsub_options:options_node() + | pubsub_options:options_item()} + %%% + | {error, 'not-acceptable'} + | {error, 'feature-not-implemented', 'collections'} + %%% + | {error, 'invalid-options'} + | {error, 'jid-malformed'} + % + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} + % + | {error, 'feature-not-implemented', 'collections'} + | {error, 'feature-not-implemented', 'multi-collections'} +). + +parse_xmlel_x(Plugin, _Pubsub_Features, _Entity, 'node_config', []) -> + {ok, Plugin:node_options('leaf')}; +parse_xmlel_x(_Plugin, _Pubsub_Features, _Entity, 'publish-options', []) -> + {ok, []}; +%% +parse_xmlel_x(Plugin, Pubsub_Features, {U,S,_} = _Entity, Form_Type, [Xmlel_X]) + when ?Is_Xmlel_X(Xmlel_X) -> + case + {xmlns(Xmlel_X), + options_type(remove_cdata(Xmlel_X#xmlel.children), Pubsub_Features)} + of + {?NS_XDATA, {ok, 'node_config' = Form_Type, Node_Type, Xmlels}} -> + parse_xmlels_field(Form_Type, Node_Type, Pubsub_Features, + {U,S,undefined}, Xmlels, Plugin:node_options(Node_Type)); + %% + {?NS_XDATA, {ok, 'publish-options' = Form_Type, Node_Type, Xmlels}} -> + parse_xmlels_field(Form_Type, Node_Type, Pubsub_Features, + {U,S,undefined}, Xmlels, Plugin:item_options()); + %% + {?NS_XDATA, Error} -> + Error; + _ -> + {error, 'invalid-options'} + end; +parse_xmlel_x(_Plugin, _Pubsub_Features, _Entity, _Form_Type, _Xmlels) -> + {error, 'invalid-options'}. + +%% +-spec(parse_xmlel_x/7 :: +( + Plugin :: exmpp_pubsub:plugin(), + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Entity :: xmpp_jid:usr_entity(), + Entity_Type :: 'local' | 'remote', + Form_Type :: 'subscribe_options', + Node_Type :: 'leaf' | 'collection', + Xmlels :: [Xmlel_X::xmlel(),...] + | [Xmlel::xmlel()] + | []) + -> {ok, + Subscription_Options :: [] | pubsub_options:options_subscription_leaf()} + %%% + | {error, 'invalid-options'} + | {error, 'not-acceptable'} +). + +parse_xmlel_x(Plugin, _Pubsub_Features, _Entity, Entity_Type, 'subscribe_options', + Node_Type, []) -> + {ok, Plugin:subscription_options(Entity_Type, Node_Type)}; +%% +parse_xmlel_x(Plugin, Pubsub_Features, {U,S,_} = _Entity, Entity_Type, + 'subscribe_options' = Form_Type, Node_Type, [Xmlel_X]) + when ?Is_Xmlel_X(Xmlel_X) -> + case + {xmlns(Xmlel_X), + options_type(remove_cdata(Xmlel_X#xmlel.children), 'subscribe_options', [])} + of + {?NS_XDATA, {ok, 'subscribe_options', Xmlels}} -> + parse_xmlels_field(Form_Type, Node_Type, Pubsub_Features, + {U,S,undefined}, Entity_Type, Xmlels, + Plugin:default_subscription_options(Entity_Type, Node_Type)); + {?NS_XDATA, Error} -> + Error; + _ -> + {error, 'invalid-options'} + end; +%% +parse_xmlel_x(_Plugin, _Pubsub_Features, _Entity, _Entity_Type, 'subscribe_options', + _Node_Type, _Xmlels) -> + {error, 'invalid-options'}. + +%% +-spec(options_type/3 :: +( + Xmlels :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()], + Form_Type :: 'subscribe_options', + Xmlels_Fields :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()]) + -> {ok, + Form_Type :: 'subscribe_options', + Xmlels_Field :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()]} + %%% + | {error, 'not-acceptable'} +). + +options_type([] = _Xmlels_Field, 'subscribe_options', _Xmlels) -> + {error, 'not-acceptable'}; +%% +options_type([Xmlel_Field | Xmlels_Field], 'subscribe_options', Xmlels) + when ?Is_Xmlel_Field(Xmlel_Field) -> + case {xmlns(Xmlel_Field), get_tag_attr_s(<<"var">>, Xmlel_Field)} of + {_, <<>>} -> + {error, 'not-acceptable'}; + {?NS_XDATA, <<"FORM_TYPE">>} -> + case remove_cdata(Xmlel_Field#xmlel.children) of + [Xmlel_Value] when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, ?NS_PUBSUB_SUBSCRIBE_OPTIONS} -> + {ok, 'subscribe_options', Xmlels ++ Xmlels_Field}; + _ -> + {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; + {?NS_XDATA, _} -> + options_type(Xmlels_Field, 'subscribe_options', + [Xmlel_Field | Xmlels]); + _ -> + {error, 'not-acceptable'} + end. + +%% +-spec(options_type/2 :: +( + Xmlels :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()], + Pubsub_Features :: exmpp_pubsub:pubsub_features()) + -> {ok, + Form_Type :: 'node_config' | 'publish-options', + Node_Type :: 'leaf' | 'collection', + Xmlels_Field :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()]} + %%% + | {error, 'not-acceptable'} + | {error, 'feature-not-implemented', 'collections'} +). + +options_type(Xmlels, Pubsub_Features) -> + options_type(Xmlels, + lists:member(<<"collections">>, Pubsub_Features), undefined, undefined, []). + +%% +-spec(options_type/5 :: +( + Xmlels :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()], + Collections :: boolean(), + Form_Type :: undefined | 'node_config' | 'publish-options', + Node_Type :: undefined | 'leaf' | 'collection', + Xmlels_Fields :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()]) + -> {ok, + Form_Type :: 'node_config' | 'publish-options', + Node_Type :: 'leaf' | 'collection', + Xmlels_Field :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()]} + %%% + | {error, 'not-acceptable'} + | {error, 'feature-not-implemented', 'collections'} +). + +options_type([] = _Xmlels, _Collections, Form_Type, undefined = _Node_Type, + Xmlels_Field) + when Form_Type =/= undefined -> + {ok, Form_Type, 'leaf', Xmlels_Field}; +%% +options_type([] = _Xmlels, _Collections, Form_Type, Node_Type, Xmlels_Field) + when Form_Type =/= undefined -> + {ok, Form_Type, Node_Type, Xmlels_Field}; +%% +options_type([] = _Xmlels, _Collections, undefined = _Form_Type, _Node_Type, + _Xmlels_Field) -> + {error, 'bad-options'}; +%% +options_type(Xmlels, _Collections, Form_Type, Node_Type, Xmlels_Field) + when Form_Type =/= undefined andalso Node_Type =/= undefined -> + {ok, Form_Type, Node_Type, Xmlels ++ Xmlels_Field}; +%% +options_type([Xmlel_Field | Xmlels_Field], Collections, Form_Type, Node_Type, + Xmlels) + when ?Is_Xmlel_Field(Xmlel_Field) -> + case {xmlns(Xmlel_Field), get_tag_attr_s(<<"var">>, Xmlel_Field)} of + {_, <<>>} -> + {error, 'not-acceptable'}; + {?NS_XDATA, <<"FORM_TYPE">>} -> + case remove_cdata(Xmlel_Field#xmlel.children) of + [Xmlel_Value] when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, ?NS_PUBSUB_NODE_CONFIG} -> + options_type(Xmlels_Field, Collections, 'node_config', + Node_Type, Xmlels); + {?NS_XDATA, ?NS_PUBSUB_PUBLISH_OPTIONS} -> + options_type(Xmlels_Field, Collections, + 'publish-options', Node_Type, Xmlels); + _ -> + {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; + {?NS_XDATA, <<"pubsub#node_type">>} -> + case remove_cdata(Xmlel_Field#xmlel.children) of + [Xmlel_Value] when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<"leaf">>} -> + options_type(Xmlels_Field, Collections, Form_Type, + 'leaf', Xmlels); + {?NS_XDATA, <<"collection">>} -> + case Collections of + true -> + options_type(Xmlels_Field, Collections, + Form_Type, 'collection', Xmlels); + false -> + {error, + 'feature-not-implemented', 'collections'} + end; + _ -> + {error, 'not-acceptable'} + end + end; + {?NS_XDATA, _Xmlattr} -> + options_type(Xmlels_Field, Collections, Form_Type, Node_Type, + [Xmlel_Field | Xmlels]); + _ -> + {error, 'not-acceptable'} + end. + +%% +-spec(parse_xmlels_field/6 :: +( + Options_Type :: 'node_config' | 'publish-options', + Node_Type :: 'leaf' | 'collection', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Entity :: xmpp_jid:usr_entity(), + Xmlels :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()], + Options :: pubsub_options:options_node() + | pubsub_options:options_item() + %% + | {error, 'invalid-options'} + | {error, 'jid-malformed'} + % + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} + % + | {error, 'feature-not-implemented', 'collections'} + | {error, 'feature-not-implemented', 'multi-collections'}) + -> {ok, + Options :: pubsub_options:options_node() + | pubsub_options:options_item()} + %%% + | {error, 'invalid-options'} + | {error, 'jid-malformed'} + % + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} + % + | {error, 'feature-not-implemented', 'collections'} + | {error, 'feature-not-implemented', 'multi-collections'} +). + +%% +parse_xmlels_field(_Options_Type, _Node_Type, _Pubsub_Features, _Entity, + _Xmlels, Error) + when is_tuple(Error) -> + Error; +parse_xmlels_field(_Options_Type, _Node_Type, _Pubsub_Features, _Entity, + [] = _Xmlels, Options) -> + {ok, Options}; +%% +parse_xmlels_field(Options_Type, Node_Type, Pubsub_Features, Entity, + [Xmlel_Field | Xmlels], Options) + when ?Is_Xmlel_Field(Xmlel_Field) -> + case xmlns(Xmlel_Field) of + ?NS_XDATA -> + parse_xmlels_field(Options_Type, Node_Type, Pubsub_Features, Entity, + Xmlels, + parse_xmlel_field_attrs( + get_tag_attr_s(<<"var">>, Xmlel_Field), + Options_Type, Node_Type, Pubsub_Features, Entity, + remove_cdata(Xmlel_Field#xmlel.children), + Options)); + _ -> + {error, 'invalid-options'} + end; +%% +parse_xmlels_field(_Options_Type, _Node_Type, _Pubsub_Feature, _Entity, + _Xmlels, _Options) -> + {error, 'invalid-options'}. + +%% +-spec(parse_xmlels_field/7 :: +( + Options_Type :: 'subscribe_options', + Node_Type :: 'leaf' | 'collection', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Entity :: xmpp_jid:usr_entity(), + Entity_Type :: 'local' | 'remote', + Xmlels :: [Xmlel_Field::xmlel()] + | [Xmlel::xmlel()], + Options :: pubsub_options:options_subscription() + % + | {error, 'invalid-options'} + | {error, 'not-acceptable'}) + -> {ok, + Options :: pubsub_options:options_node() + | pubsub_options:options_item()} + %%% + | {error, 'invalid-options'} + | {error, 'not-acceptable'} +). + +%% +parse_xmlels_field(_Options_Type, _Node_Type, _Pubsub_Features, _Entity, + _Entity_Type, _Xmlels, Error) + when is_tuple(Error) -> + Error; +parse_xmlels_field(_Options_Type, _Node_Type, _Pubsub_Features, _Entity, + _Entity_Type, [] = _Xmlels, Options) -> + {ok, trim_subscription_options(Options)}; +%% +parse_xmlels_field(Options_Type, Node_Type, Pubsub_Features, Entity, + Entity_Type, [Xmlel_Field | Xmlels], Options) + when ?Is_Xmlel_Field(Xmlel_Field) -> + case xmlns(Xmlel_Field) of + ?NS_XDATA -> + parse_xmlels_field(Options_Type, Node_Type, Pubsub_Features, Entity, + Entity_Type, + Xmlels, + parse_xmlel_field_attrs( + get_tag_attr_s(<<"var">>, Xmlel_Field), + Options_Type, Node_Type, Pubsub_Features, Entity, Entity_Type, + remove_cdata(Xmlel_Field#xmlel.children), + Options)); + _ -> + {error, 'invalid-options'} + end; +%% +parse_xmlels_field(_Options_Type, _Node_Type, _Pubsub_Feature, _Entity, + _Entity_Type, _Xmlels, _Options) -> + {error, 'invalid-options'}. + +%% +-spec(parse_xmlel_field_attrs/7 :: +( + Pubsub_Option :: binary(), + Options_Type :: 'node_config' | 'publish-options', + Node_Type :: 'leaf' | 'collection', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Entity :: xmpp_jid:usr_entity(), + Xmlels :: [Xmlel_Value::xmlel(),...] + | [Xmlel::xmlel(),...], + Options :: pubsub_options:options_node() + | pubsub_options:options_item()) + -> Options :: pubsub_options:options_node() + | pubsub_options:options_item() + %%% + | {error, 'invalid-options'} + | {error, 'jid-malformed'} + % + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} + % + | {error, 'feature-not-implemented', 'collections'} + | {error, 'feature-not-implemented', 'multi-collections'} +). + +parse_xmlel_field_attrs(<<"pubsub#roster_groups_allowed">>, Options_Type, + Node_Type, Pubsub_Features, Entity, Xmlels, Options) + when (Options_Type == 'node_config' orelse Options_Type == 'publish-options') + andalso (Node_Type == 'leaf' orelse Node_Type == 'collection') -> + case lists:member(<<"access-roster">>, Pubsub_Features) of + true -> + case + case Options_Type of + 'node_config' -> + parse_pubsub_option_node(<<"roster_groups_allowed">>, + Node_Type, Pubsub_Features, Xmlels); + 'publish-options' -> + parse_pubsub_option_item(<<"roster_groups_allowed">>, + Pubsub_Features, Xmlels) + end + + of + {ok, Roster_Groups_Allowed} -> + case lists:keyfind('roster_groups_allowed', 1, Options) of + false -> + [{Entity, Roster_Groups_Allowed} | Options]; + {'roster_groups_allowed', Rosters_Groups_Allowed} -> + lists:keyreplace('roster_groups_allowed', 1, Options, + {'roster_groups_allowed', + _New_Rosters_Groups_Allowed = + case + lists:keyreplace(Entity, 1, + Rosters_Groups_Allowed, + {Entity, Roster_Groups_Allowed}) + of + Rosters_Groups_Allowed -> + [{Entity, Roster_Groups_Allowed} + | Rosters_Groups_Allowed]; + New_Rosters_Groups_Allowed -> + New_Rosters_Groups_Allowed + end}) + end; + Error -> + Error + end; + false -> + {error, 'invalid-options'} + end; +%% +parse_xmlel_field_attrs(<<"pubsub#", Pubsub_Option/binary>>, + 'node_config' = _Options_Type, Node_Type, Pubsub_Features, _Entity, Xmlels, + Node_Options) -> + case + lists:keymember( + Key = list_to_atom(binary_to_list(Pubsub_Option)), 1, Node_Options) + of + true -> + case + parse_pubsub_option_node(Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + of + {ok, Value} -> + lists:keyreplace(Key, 1, Node_Options, {Key, Value}); + Error -> + Error + end; + false -> + Node_Options%{error, 'invalid-options'} + end; +%% +parse_xmlel_field_attrs(<<"pubsub#", Pubsub_Option/binary>>, + 'publish-options' = _Options_Type, _Node_Type, Pubsub_Features, _Entity, Xmlels, + Item_Options) -> + case parse_pubsub_option_item(Pubsub_Option, Pubsub_Features, Xmlels) of + {ok, Value} + when Value == undefined + orelse Value == [] -> + lists:keydelete(_Key = list_to_atom(binary_to_list(Pubsub_Option)), + 1, Item_Options); + {ok, Value} -> + Key = list_to_atom(binary_to_list(Pubsub_Option)), + case lists:keyreplace(Key, 1, Item_Options, {Key, Value}) of + Item_Options -> [{Key, Value} | Item_Options]; + New_Item_Options -> New_Item_Options + end; + Error -> + Error + end; +%% +parse_xmlel_field_attrs(_Xmlattr_value, _Options_Type, _Node_Type, + _Pubsub_Features, _Entity, _Xmlels, _Options) -> + {error, 'invalid-options'}. + +%% +-spec(parse_xmlel_field_attrs/8 :: +( + Pubsub_Option :: binary(), + Options_Type :: 'subscribe_options', + Node_Type :: 'leaf' | 'collection', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Entity :: xmpp_jid:usr_entity(), + Entity_Type :: 'local' | 'remote', + Xmlels :: [Xmlel_Value::xmlel(),...] + | [Xmlel::xmlel(),...], + Subscription_Options :: pubsub_options:options_subscription()) + -> Subscription_Options :: pubsub_options:options_subscription() + %%% + | {error, 'invalid-options'} +). + +parse_xmlel_field_attrs(<<"pubsub#", Pubsub_Option/binary>>, + 'subscribe_options' = _Options_Type, Node_Type, Pubsub_Features, _Entity, + Entity_Type, Xmlels, Subscription_Options) -> + case + lists:keymember(Key = list_to_atom(binary_to_list(Pubsub_Option)), 1, + Subscription_Options) + of + true -> + case + parse_pubsub_option_subscription(Pubsub_Option, Node_Type, + Entity_Type, Pubsub_Features, Xmlels) + of + {ok, Value} + when ?Is_Default_Subscribe_Option({Key, Value}) -> + lists:keydelete(Key, 1, Subscription_Options); + {ok, Value} -> + lists:keyreplace(Key, 1, Subscription_Options, {Key, Value}); + Error -> + Error + end; + false -> + {error, 'invalid-options'} + end; +%% +parse_xmlel_field_attrs(_Xmlattr_value, _Options_Type, _Node_Type, + _Pubsub_Features, _Entity, _Entity_Type, _Xmlels, _Options) -> + {error, 'invalid-options'}. + + +%% +%% +-spec(parse_pubsub_option_node/4 :: +( + Pubsub_Option :: binary(), + Node_Type :: 'collection' | 'leaf', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Xmlels :: [Xmlel_Value::xmlel()] + | [Xmlel::xmlel()]) + -> {ok, Access_Model :: pubsub_options:access_model()} + % | {ok, Body_XSLT :: undefined | binary()} + | {ok, Children_Association_Policy :: 'all' | 'owners' | 'whitelist'} + | {ok, Children_Association_Whitelist :: [Jid::xmpp_jid:raw_jid_entity_bare()]} + | {ok, Children :: [Child_NodeId::exmpp_pubsub:nodeId()]} + | {ok, Children_Max :: undefined | non_neg_integer()} + | {ok, Collection :: [Parent_NodeId::exmpp_pubsub:nodeId()]} + | {ok, Contact :: [Jid::xmpp_jid:raw_jid_entity()]} + % | {ok, Dataform_XSLT :: undefined | binary()} + | {ok, Deliver_Notifications :: boolean()} + | {ok, Deliver_Payloads :: boolean()} + | {ok, Description :: undefined | binary()} + | {ok, Item_Expire :: undefined | non_neg_integer()} + | {ok, ItemReply :: pubsub_options:item_reply()} + | {ok, Language :: undefined | binary()} + | {ok, Max_Items :: undefined | non_neg_integer()} + | {ok, Max_Payload_Size :: undefined | non_neg_integer()} + | {ok, Node_Type :: pubsub_options:node_type()} + | {ok, Notification_Type :: pubsub_options:notification_type()} + | {ok, Notify_Config :: boolean()} + | {ok, Notify_Delete :: boolean()} + | {ok, Notify_Retract :: boolean()} + | {ok, Notify_Sub :: boolean()} + | {ok, Persist_Items :: boolean()} + | {ok, Presence_Based_Delivery :: boolean()} + | {ok, Publish_Model :: pubsub_options:publish_model()} + | {ok, Purge_Offline :: boolean()} + | {ok, Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed()} + | {ok, Send_Last_Published_Item :: pubsub_options:send_last_published_item()} + | {ok, Tempsub :: boolean()} + | {ok, Subscribe :: boolean()} + | {ok, Title :: undefined | binary()} + | {ok, Type :: undefined | atom()} + %%% + | {error, 'invalid-options'} + | {error, 'jid-malformed'} + % + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} + % + | {error, 'feature-not-implemented', 'collections'} + | {error, 'feature-not-implemented', 'multi-collections'} +). + +parse_pubsub_option_node(<<"access_model">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + parse_xmlel_value({'access_model', Pubsub_Features}, Xmlels); +%% +%%parse_pubsub_option_node(<<"pubsub#body_xslt">> = _Pubsub_Option, +%% 'leaf' = _Node_Type, Pusbub_Features, Xmlels) -> +%% case lists:member(<<"publish">>, Pubsub_Features) of +%% true -> +%% parse_xmlel_value('text-single', Xmlels); +%% false -> +%% {error, 'invalid-options'} +%% end; +%% +parse_pubsub_option_node(<<"children_association_policy">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, Xmlels) -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = ['all', 'owners', 'whitelist']}, Xmlels); +%% +parse_pubsub_option_node(<<"children_association_whitelist">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, [] = _Xmlels) -> + {ok, []}; +parse_pubsub_option_node(<<"children_association_whitelist">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, Xmlels) -> + parse_xmlel_value({'jid-multi', 'bare'}, Xmlels); +%% +%% +parse_pubsub_option_node(<<"children">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, [] = Xmlels) -> + parse_xmlel_value('text-multi', Xmlels); +parse_pubsub_option_node(<<"children">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, [_] = Xmlels) -> + parse_xmlel_value('text-multi', Xmlels); +parse_pubsub_option_node(<<"children">> = _Pubsub_Option, + 'collection' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"multi-collections">>, Pubsub_Features) of + true -> parse_xmlel_value('text-multi', Xmlels); + false -> {error, 'feature-not-implemented', 'multi-collections'} + end; +%% +%% +parse_pubsub_option_node(<<"children_max">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, [] = _Xmlels) -> + {ok, undefined}; +parse_pubsub_option_node(<<"children_max">> = _Pubsub_Option, + 'collection' = _Node_Type, Pubsub_Features, [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + {ok, undefined}; + {?NS_XDATA, CData} -> + case catch list_to_integer(binary_to_list(CData)) of + Integer when Integer == 0 orelse Integer == 1 -> + {ok, Integer}; + Integer when is_integer(Integer) andalso Integer > 1 -> + case + lists:member(<<"multi-collections">>, Pubsub_Features) + of + true -> {ok, Integer}; + false -> {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; +parse_pubsub_option_node(<<"children_max">> = _Pubsub_Option, + 'collection' = _Node_Type, _Pubsub_Features, _Xmlels) -> + {error, 'not-acceptable'}; +%% +parse_pubsub_option_node(<<"collection">> = _Pubsub_Option, Node_Type, + Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"collections">>, Pubsub_Features) of + true -> {ok, []}; + false -> {error, 'feature-not-implemented', 'collections'} + end; +parse_pubsub_option_node(<<"collection">> = _Pubsub_Option, Node_Type, + Pubsub_Features, [_] = Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"collections">>, Pubsub_Features) of + true -> parse_xmlel_value('text-multi', Xmlels); + false -> {error, 'feature-not-implemented', 'collections'} + end; +parse_pubsub_option_node(<<"collection">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"collections">>, Pubsub_Features) of + true -> + case lists:member(<<"multi-collections">>, Pubsub_Features) of + true -> parse_xmlel_value('text-multi', Xmlels); + false -> {error, 'feature-not-implemented', 'multi-collections'} + end; + false -> + {error, 'feature-not-implemented', 'collections'} + end; +%% +parse_pubsub_option_node(<<"contact">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + {ok, []}; +parse_pubsub_option_node(<<"contact">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + parse_xmlel_value({'jid-multi', 'full'}, Xmlels); +%% +%%parse_pubsub_option_node(<<"pubsub#dataform_xslt">> = _Pubsub_Option, +%% 'leaf' = _Node_Type, Pusbub_Features, Xmlels) -> +%% case lists:member(<<"publish">>, Pubsub_Features) of +%% true -> +%% parse_xmlel_value('text-single', Xmlels); +%% false -> +%% {error, 'invalid-options'} +%% end; +%% +parse_pubsub_option_node(<<"deliver_notifications">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"deliver_payloads">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"description">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + {ok, undefined}; +parse_pubsub_option_node(<<"description">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + parse_xmlel_value('text-single', Xmlels); +%% +parse_pubsub_option_node(<<"item_expire">> = _Pubsub_Option, 'leaf' = _Node_Type, + Pubsub_Features, [] = _Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_node(<<"item_expire">> = _Pubsub_Option, 'leaf' = _Node_Type, + Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> parse_xmlel_value({'text-single', 'integer'}, Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"itemreply">> = _Pubsub_Option, 'leaf' = _Node_Type, + Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = ['owner', 'publisher']}, Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"language">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + {ok, undefined}; +parse_pubsub_option_node(<<"language">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + parse_xmlel_value('text-single', Xmlels); +%% +parse_pubsub_option_node(<<"max_items">> = _Pubsub_Option, 'leaf' = _Node_Type, + Pubsub_Features, [] = _Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_node(<<"max_items">> = _Pubsub_Option, 'leaf' = _Node_Type, + Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> parse_xmlel_value({'text-single', 'integer'}, Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"max_payload_size">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, [] = _Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_node(<<"max_payload_size">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> parse_xmlel_value({'text-single', 'integer'}, Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"notification_type">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = ['headline', 'normal']}, Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"notify_config">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"config-node">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"notify_delete">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"delete-nodes">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"notify_retract">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"delete-items">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"notify_sub">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"persist_items">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"persistent-items">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"presence_based_delivery">> = _Pubsub_Option, + Node_Type, Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"presence-notifications">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"publish_model">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = ['open', 'publishers', 'subscribers']}, + Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"purge_offline">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"purge-nodes">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"roster_groups_allowed">> = _Pubsub_Option, + Node_Type, Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"access-roster">>, Pubsub_Features) of + true -> {ok, []}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_node(<<"roster_groups_allowed">> = _Pubsub_Option, + Node_Type, Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"access-roster">>, Pubsub_Features) of + true -> parse_xmlel_value('list-multi', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"send_last_published_item">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"last-published">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = case + lists:member(<<"presence-notifications">>, Pubsub_Features) + of + true -> ['never', 'on_sub', 'on_sub_and_presence']; + false -> ['never', 'on_sub'] + end}, + Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"tempsub">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> + case lists:member(<<"presence-notifications">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"subscribe">> = _Pubsub_Option, Node_Type, + Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(<<"title">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + {ok, undefined}; +parse_pubsub_option_node(<<"title">> = _Pubsub_Option, Node_Type, + _Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + parse_xmlel_value('text-single', Xmlels); +%% +parse_pubsub_option_node(<<"type">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, [] = _Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_node(<<"type">> = _Pubsub_Option, + 'leaf' = _Node_Type, Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> parse_xmlel_value({'text-single', 'atom'}, Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_node(_Pubsub_Option, _Node_Type, _Pubsub_Features, _Xmlels) -> + {error, 'invalid-options'}. + +%% +%% +-spec(parse_pubsub_option_item/3 :: +( + Pubsub_Option :: binary(), + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Xmlels :: [Xmlel_Value::xmlel()] + | [Xmlel::xmlel()]) + -> {ok, Access_Model :: pubsub_options:access_model()} + % | {ok, Body_XSLT :: undefined | binary()} + % | {ok, Dataform_XSLT :: undefined | binary()} + | {ok, Deliver_Notifications :: boolean()} + | {ok, Deliver_Payloads :: boolean()} + | {ok, Item_Expire :: undefined | non_neg_integer()} + | {ok, ItemReply :: pubsub_options:item_reply()} +%% | {ok, Max_Payload_Size :: undefined | non_neg_integer()} + | {ok, Notification_Type :: pubsub_options:notification_type()} + | {ok, Notify_Config :: boolean()} + | {ok, Notify_Retract :: boolean()} + | {ok, Persist_Items :: boolean()} + | {ok, Presence_Based_Delivery :: boolean()} +% | {ok, Publish_Model :: pubsub_options:publish_model()} + | {ok, Purge_Offline :: boolean()} + | {ok, Rosters_Groups_Allowed :: pubsub_options:rosters_groups_allowed()} + | {ok, Send_Last_Published_Item :: pubsub_options:send_last_published_item()} + | {ok, Type :: undefined | atom()} + %%% + | {error, 'invalid-options'} + % + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} +). + +parse_pubsub_option_item(<<"access_model">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + parse_xmlel_value({'access_model', Pubsub_Features}, Xmlels); +%% +%%parse_pubsub_option_item(<<"pubsub#body_xslt">> = _Pubsub_Option, +%% Pusbub_Features, Xmlels) -> +%% case lists:member(<<"publish">>, Pubsub_Features) of +%% true -> +%% parse_xmlel_value('text-single', Xmlels); +%% false -> +%% {error, 'invalid-options'} +%% end; +%% +%%parse_pubsub_option_item(<<"pubsub#dataform_xslt">> = _Pubsub_Option, +%% Pusbub_Features, Xmlels) -> +%% case lists:member(<<"publish">>, Pubsub_Features) of +%% true -> +%% parse_xmlel_value('text-single', Xmlels); +%% false -> +%% {error, 'invalid-options'} +%% end; +%% +parse_pubsub_option_item(<<"deliver_notifications">> = _Pubsub_Option, + Pubsub_Features, Xmlels) -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"deliver_payloads">> = _Pubsub_Option, + Pubsub_Features, Xmlels) -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"item_expire">> = _Pubsub_Option, Pubsub_Features, + [] = _Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_item(<<"item_expire">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> parse_xmlel_value({'text-single', 'integer'}, Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"itemreply">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = ['owner', 'publisher']}, Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +%parse_pubsub_option_item(<<"max_payload_size">> = _Pubsub_Option, +% Pubsub_Features, Xmlels) -> +% case lists:member(<<"publish">>, Pubsub_Features) of +% true -> +% parse_xmlel_value({'text-single', 'integer'}, Xmlels); +% false -> +% {error, 'invalid-options'} +% end; +%% +parse_pubsub_option_item(<<"notification_type">> = _Pubsub_Option, + Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = ['headline', 'normal']}, Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"notify_config">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + case lists:member(<<"config-node">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"notify_retract">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + case lists:member(<<"delete-items">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"persist_items">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + case lists:member(<<"persistent-items">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"presence_based_delivery">> = _Pubsub_Option, + Pubsub_Features, Xmlels) -> + case lists:member(<<"presence-notifications">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +%parse_pubsub_option_item(<<"publish_model">> = _Pubsub_Option, +% Pubsub_Features, Xmlels) -> +% case lists:member(<<"publish">>, Pubsub_Features) of +% true -> +% parse_xmlel_value({'list-single', 'atom', +% _Default_Values = ['open', 'publishers', 'subscribers']}, +% Xmlels); +% false -> +% {error, 'invalid-options'} +% end; +%% +parse_pubsub_option_item(<<"purge_offline">> = _Pubsub_Option, Pubsub_Features, + Xmlels) -> + case lists:member(<<"purge-nodes">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"roster_groups_allowed">> = _Pubsub_Option, + Pubsub_Features, [] = _Xmlels) -> + case lists:member(<<"access-roster">>, Pubsub_Features) of + true -> {ok, []}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_item(<<"roster_groups_allowed">> = _Pubsub_Option, + Pubsub_Features, Xmlels) -> + case lists:member(<<"access-roster">>, Pubsub_Features) of + true -> parse_xmlel_value('list-multi', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"send_last_published_item">> = _Pubsub_Option, + Pubsub_Features, Xmlels) -> + case lists:member(<<"last-published">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-single', 'atom', + _Default_Values = case + lists:member(<<"presence-notifications">>, Pubsub_Features) + of + true -> ['never', 'on_sub', 'on_sub_and_presence']; + false -> ['never', 'on_sub'] + end}, + Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(<<"type">> = _Pubsub_Option, Pubsub_Features, + [] = _Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_item(<<"type">> = _Pubsub_Option, Pubsub_Features, Xmlels) -> + case lists:member(<<"publish">>, Pubsub_Features) of + true -> parse_xmlel_value({'text-single', 'atom'}, Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_item(_Pubsub_Option, _Pubsub_Features, _Xmlels) -> + {error, 'invalid-options'}. + +%% +%% +-spec(parse_pubsub_option_subscription/5 :: +( + Pubsub_Option :: binary(), + Node_Type :: 'collection' | 'leaf', + Entity_Type :: 'local' | 'remote', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Xmlels :: [Xmlel_Value::xmlel()] + | [Xmlel::xmlel()]) + -> + % {ok, Digest :: boolean()} + % | {ok, Digest_Frequency :: undefined | non_neg_integer()} + {ok, Deliver :: boolean()} + | {ok, Expire :: undefined | 'presence' | erlang:timestamp()} +% | {ok, Include_Body :: boolean()} + | {ok, Show_Values :: ['away' | 'chat' | 'dnd' | 'online' | 'xa']} +% | {ok, Subscription_Type :: 'all' | 'items' | 'nodes'} +% | {ok, Subscription_Depth :: 'all' | non_neg_integer()} + %%% + | {error, 'invalid-options'} + % + | {error, 'not-acceptable'} +). + +%% parse_pubsub_option_subscription(<<"digest">> = _Pubsub_Option, +%% 'leaf' = _Node_Type, _Entity_Type, Pubsub_Features, Xmlels) -> +%% case lists:member(<<"subscribe">>, Pubsub_Features) of +%% true -> +%% parse_xmlel_value('boolean', Xmlels); +%% false -> +%% {error, 'invalid-options'} +%% end; +%% +%% parse_pubsub_option_subscription(<<"digest_frequency">> = _Pubsub_Option, +%% 'leaf' = _Node_Type, _Entity_Type, Pubsub_Features, Xmlels) -> +%% case lists:member(<<"subscribe">>, Pubsub_Features) of +%% true -> +%% parse_xmlel_value({'text-single', 'integer'}, Xmlels); +%% false -> +%% {error, 'invalid-options'} +%% end; +%% +parse_pubsub_option_subscription(<<"deliver">> = _Pubsub_Option, Node_Type, + _Entity_Type, Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"subscribe">>, Pubsub_Features) of + true -> parse_xmlel_value('boolean', Xmlels); + false -> {error, 'invalid-options'} + end; +%% +parse_pubsub_option_subscription(<<"expire">> = _Pubsub_Option, Node_Type, + 'local' = _Entity_Type, Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case + lists:member(<<"presence-notifications">>, Pubsub_Features) + orelse + lists:member(<<"leased-subscriptions">>, Pubsub_Features) + of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_subscription(<<"expire">> = _Pubsub_Option, Node_Type, + 'local' = _Entity_Type, Pubsub_Features, [Xmlel_Value]) + when Node_Type == 'collection' orelse Node_Type == 'leaf' + andalso ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + {ok, undefined}; + {?NS_XDATA, <<"presence">>} -> + case lists:member(<<"presence-notifications">>, Pubsub_Features) of + true -> {ok, 'presence'}; + false -> {error, 'invalid-options'} + end; + {?NS_XDATA, CData} -> + case lists:member(<<"leased-subscriptions">>, Pubsub_Features) of + true -> + case jlib:datetime_string_to_timestamp(CData) of + undefined -> {error, 'not-acceptable'}; + DateTime -> {ok, DateTime} + end; + false -> + {error, 'invalid-options'} + end; + _ -> + {error, 'invalid-options'} + end; +% +parse_pubsub_option_subscription(<<"expire">> = _Pubsub_Option, Node_Type, + 'remote' = _Entity_Type, Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"leased-subscriptions">>, Pubsub_Features) of + true -> {ok, undefined}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_subscription(<<"expire">> = _Pubsub_Option, Node_Type, + 'remote' = _Entity_Type, Pubsub_Features, [Xmlel_Value]) + when Node_Type == 'collection' orelse Node_Type == 'leaf' + andalso ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + {ok, undefined}; + {?NS_XDATA, <<"presence">>} -> + {error, 'invalid-options'}; + {?NS_XDATA, CData} -> + case lists:member(<<"leased-subscriptions">>, Pubsub_Features) of + true -> + case jlib:datetime_string_to_timestamp(CData) of + undefined -> {error, 'not-acceptable'}; + DateTime -> {ok, DateTime} + end; + false -> + {error, 'invalid-options'} + end; + _ -> + {error, 'invalid-options'} + end; +%% +%parse_pubsub_option_subscription(<<"include_body">> = _Pubsub_Option, +% 'leaf' = _Node_Type, _Entity_Type, Pubsub_Features, Xmlels) -> +% case lists:member(<<"subscribe">>, Pubsub_Features) of +% true -> +% parse_xmlel_value('boolean', Xmlels); +% false -> +% {error, 'invalid-options'} +% end; +%% +parse_pubsub_option_subscription(<<"show-values">> = _Pubsub_Option, Node_Type, + 'local' = _Entity_Type, Pubsub_Features, [] = _Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"presence-notifications">>, Pubsub_Features) of + true -> {ok, []}; + false -> {error, 'invalid-options'} + end; +parse_pubsub_option_subscription(<<"show-values">> = _Pubsub_Option, Node_Type, + 'local' = _Entity_Type, Pubsub_Features, Xmlels) + when Node_Type == 'collection' orelse Node_Type == 'leaf' -> + case lists:member(<<"presence-notifications">>, Pubsub_Features) of + true -> + parse_xmlel_value({'list-multi', 'atom', + _Default_Values = ['away' ,'chat', 'dnd', 'online', 'xa']}, + Xmlels); + false -> + {error, 'invalid-options'} + end; +%% +parse_pubsub_option_subscription(<<"show-values">> = _Pubsub_Option, _Node_Type, + 'remote' = _Entity_Type, _Pubsub_Features, _Xmlels) -> + {error, 'invalid-options'}; +%% +%parse_pubsub_option_subscription(<<"subscription_type">> = _Pubsub_Option, +% 'collection' = _Node_Type, _Entity_Type, _Pubsub_Features, Xmlels) -> +% parse_xmlel_value({'list-single', 'atom', +% _Default_Values = ['all', 'items', 'nodes']}, Xmlels); +%% +%parse_pubsub_option_subscription(<<"subscription_depth">> = _Pubsub_Option, +% 'collection' = _Node_Type, _Entity_Type, _Pubsub_Features, Xmlels) -> +% case Xmlels of +% [] -> +% {ok, 0}; +% [Xmlel_Value] when ?Is_Xmlel_Value(Xmlel_Value) -> +% case {Xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of +% {?NS_XDATA, <<>>} -> +% {ok, 0}; +% {?NS_XDATA, <<"all">>} -> +% {ok, 'all'}; +% {?NS_XDATA, CData} -> +% case catch list_to_integer(binary_to_list(CData)) of +% Integer +% when is_integer(Integer) andalso Integer > -1 -> +% {ok, Integer}; +% _Error -> +% {error, 'not-acceptable'} +% end; +% _ -> +% {error, 'not-acceptable'} +% end; +% _Xmlels -> +% {error, 'not-acceptable'} +% end; +%% +parse_pubsub_option_subscription(_Pubsub_Option, _Node_Type, _Entity_Type, + _Pubsub_Features, _Xmlels) -> + {error, 'invalid-options'}. + + +-spec(parse_xmlel_value/2 :: +( + DataType :: {'jid-multi', 'bare'} + | {'jid-multi', 'full'} + | {'list-multi', 'atom', Default_Values::[Default_Value::atom(),...]} + | 'list-multi' + | 'text-multi' + | {'access_model', Pubsub_Features::exmpp_pubsub:pubsub_features()} + | 'boolean' + | 'text-single' + | {'text-single', 'atom'} + | {'text-single', 'integer'} + | {'list-single', 'atom', Default_Values::[Default_Value::atom(),...]}, + Xmlels :: [Xmlel_Value::xmlel()] + | [Xmlel::xmlel()]) + -> %% + {ok, Values :: [] + | [Value::binary()] + | [Value::atom()] + | [Value::xmpp_jid:raw_jid_entity_bare()] + | [Value::xmpp_jid:raw_jid_entity()]} + | {ok, Value :: atom() + | binary() + | boolean() + | non_neg_integer() + | undefined} + %%% + | {error, 'invalid-options'} + | {error, 'jid-malformed'} + | {error, 'not-acceptable'} + | {error, 'not-acceptable', 'unsupported-access-model'} +). + +%% +parse_xmlel_value({'jid-multi', 'bare'}, [] = _Xmlels) -> + {ok, []}; +%% +parse_xmlel_value({'jid-multi', 'bare'}, Xmlels) -> + parse_xmlel_value({'jid-multi', 'bare'}, Xmlels, []); +%% +parse_xmlel_value({'jid-multi', 'full'}, [] = _Xmlels) -> + {ok, []}; +%% +parse_xmlel_value({'jid-multi', 'full'}, Xmlels) -> + parse_xmlel_value({'jid-multi', 'full'}, Xmlels, []); +%% +%% +parse_xmlel_value({'list-multi', 'atom', _Default_Values}, [] = _Xmlels) -> + {error, 'not-acceptable'}; +%% +parse_xmlel_value({'list-multi', 'atom', Default_Values}, Xmlels) -> + parse_xmlel_value({'list-multi', 'atom', Default_Values}, Xmlels, []); +%% +parse_xmlel_value('list-multi', Xmlels) -> + parse_xmlel_value('list-multi', Xmlels, []); +%% +%% +parse_xmlel_value('text-multi', [] = _Xmlels) -> + {ok, []}; +%% +parse_xmlel_value('text-multi', Xmlels) -> + parse_xmlel_value('text-multi', Xmlels, []); +%% + +parse_xmlel_value({'access_model', Pubsub_Features}, [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<"authorize">>} -> + case lists:member(<<"access-authorize">>, Pubsub_Features) of + true -> + {ok, 'authorize'}; + false -> + {error, 'not-acceptable', 'unsupported-access-model'} + end; + %% + {?NS_XDATA, <<"open">>} -> + case lists:member(<<"access-open">>, Pubsub_Features) of + true -> + {ok, 'open'}; + false -> + {error, 'not-acceptable', 'unsupported-access-model'} + end; + %% + {?NS_XDATA, <<"presence">>} -> + case lists:member(<<"access-presence">>, Pubsub_Features) of + true -> + {ok, 'presence'}; + false -> + {error, 'not-acceptable', 'unsupported-access-model'} + end; + %% + {?NS_XDATA, <<"roster">>} -> + case lists:member(<<"access-roster">>, Pubsub_Features) of + true -> + {ok, 'roster'}; + false -> + {error, 'not-acceptable', 'unsupported-access-model'} + end; + %% + {?NS_XDATA, <<"whitelist">>} -> + case lists:member(<<"access-whitelist">>, Pubsub_Features) of + true -> + {ok, 'whitelist'}; + false -> + {error, 'not-acceptable', 'unsupported-access-model'} + end; + %% + _ -> + {error, 'not-acceptable'} + end; +parse_xmlel_value({'access_model', _Pubsub_Features}, _Xmlels) -> + {error, 'not-acceptable'}; +%% +%% +parse_xmlel_value('boolean', [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, False} + when False == <<"0">> + orelse False == <<"false">> -> + {ok, false}; + {?NS_XDATA, True} + when True == <<"1">> + orelse True == <<"true">> -> + {ok, true}; + _ -> + {error, 'not-acceptable'} + end; +parse_xmlel_value('boolean', _Xmlels) -> + {error, 'not-acceptable'}; +%% +%% +parse_xmlel_value('text-single', [] = _Xmlels) -> + {ok, undefined}; +parse_xmlel_value('text-single', [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> {ok, undefined}; + {?NS_XDATA, CData} -> {ok, CData}; + _ -> {error, 'not-acceptable'} + end; +parse_xmlel_value('text-single', _Xmlels) -> + {error, 'not-acceptable'}; +%% +%% +parse_xmlel_value({'text-single', 'atom'}, [] = _Xmlels) -> + {ok, undefined}; +parse_xmlel_value({'text-single', 'atom'}, [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> {ok, undefined}; + {?NS_XDATA, CData} -> {ok, list_to_atom(binary_to_list(CData))}; + _ -> {error, 'not-acceptable'} + end; +parse_xmlel_value({'text-single', 'atom'}, _Xmlels) -> + {error, 'not-acceptable'}; +%% +%% +parse_xmlel_value({'text-single', 'integer'}, [] = _Xmlels) -> + {ok, undefined}; +parse_xmlel_value({'text-single', 'integer'}, [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + {ok, undefined}; + {?NS_XDATA, CData} -> + case catch list_to_integer(binary_to_list(CData)) of + Integer when is_integer(Integer) andalso Integer > -1 -> + {ok, Integer}; + _ -> + {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; +parse_xmlel_value({'text-single', 'integer'}, _Xmlels) -> + {error, 'not-acceptable'}; +%% +%% +parse_xmlel_value({'list-single', 'atom', Default_Values}, [Xmlel_Value]) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {_, <<>>} -> + {error, 'not-acceptable'}; + {?NS_XDATA, CData} -> + case + lists:member(Value = list_to_atom(binary_to_list(CData)), + Default_Values) + of + true -> + {ok, Value}; + false -> + {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; +parse_xmlel_value({'list-single', 'atom', _Default_Values}, _Xmlels) -> + {error, 'not-acceptable'}; +%% +parse_xmlel_value({_DataType, _Default_Values}, _Xmlels) -> + {error, 'not-acceptable'}. +%% + +%% +-spec(parse_xmlel_value/3 :: +( + DataType :: {'list-multi', 'atom', Default_Values::[Default_Value::atom(),...]} + | 'list-multi' + | 'text-multi' + | {'jid-multi', 'full'} + | {'jid-multi', 'bare'}, + Xmlels :: [Xmlel_Value::xmlel()] + | [Xmlel::xmlel()], + Values :: [Value::binary()] + | [Value::atom()] + | [Value::xmpp_jid:raw_jid_entity_bare()] + | [Value::xmpp_jid:raw_jid_entity_full()]) + -> {ok, + Values :: [Value::binary()] + | [Value::atom()] + | [Value::xmpp_jid:raw_jid_entity_bare()] + | [Value::xmpp_jid:raw_jid_entity_full()]} + %%% + | {error, 'not-acceptable'} + | {error, 'jid-malformed'} +). + +parse_xmlel_value(_DataType, _Xmlels = [], Values) -> + {ok, lists:usort(Values)}; +%% +%% +parse_xmlel_value({'list-multi', 'atom', Default_Values}, + [Xmlel_Value | Xmlels], Values) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + parse_xmlel_value({'list-multi', 'atom', Default_Values}, + Xmlels, Values); + {?NS_XDATA, CData} -> + case + lists:member(Value = list_to_atom(binary_to_list(CData)), + Default_Values) + of + true -> + parse_xmlel_value({'list-multi', 'atom', Default_Values}, + Xmlels, [Value | Values]); + false -> + {error, 'not-acceptable'} + end; + _ -> + {error, 'not-acceptable'} + end; +%% +%% +parse_xmlel_value('list-multi', [Xmlel_Value | Xmlels], Values) + when ?Is_Xmlel_Value(Xmlel_Value) -> + parse_xmlel_value('list-multi', Xmlels, + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> Values; + {?NS_XDATA, CData} -> [CData | Values]; + _ -> {error, 'not-acceptable'} + end); +%% +%% +parse_xmlel_value('text-multi', [Xmlel_Value | Xmlels] , Values) + when ?Is_Xmlel_Value(Xmlel_Value) -> + parse_xmlel_value('text-multi', Xmlels, + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> Values; + {?NS_XDATA, CData} -> [_Value = CData | Values]; + _ -> {error, 'not-acceptable'} + end); +%% +%% +parse_xmlel_value({'jid-multi', 'full'}, [Xmlel_Value | Xmlels], Values) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + parse_xmlel_value({'jid-multi', 'full'}, Xmlels, Values); + {?NS_XDATA, CData} -> + case is_jid(CData) of + #jid{} = Jid -> + parse_xmlel_value({'jid-multi', 'full'}, Xmlels, + [jlib:jid_to_string(Jid) | Values]); + Error -> + Error + end; + _ -> + {error, 'not-acceptable'} + end; +%% +parse_xmlel_value({'jid-multi', 'bare'}, [Xmlel_Value | Xmlels], Values) + when ?Is_Xmlel_Value(Xmlel_Value) -> + case {xmlns(Xmlel_Value), get_tag_cdata(Xmlel_Value)} of + {?NS_XDATA, <<>>} -> + parse_xmlel_value({'jid-multi', 'bare'}, Xmlels, Values); + {?NS_XDATA, CData} -> + case is_jid(CData) of + #jid{} = Jid -> + parse_xmlel_value({'jid-multi', 'bare'}, Xmlels, + [jlib:jid_to_string(Jid#jid{resource = <<>>, lresource = <<>>}) + | Values]); + Error -> + Error + end; + _ -> + {error, 'not-acceptable'} + end; +%% +parse_xmlel_value(_Data_Type, _Xmlels, _Values) -> + {error, 'not-acceptable'}. + +%% +%% +-spec(xdata_x/6 :: +( + Options_Type :: 'node_config' | 'subscribe_options', + Form_Type :: 'form' | 'result', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Host :: xmpp_jid:raw_jid_component_bare(), + Entity :: xmpp_jid:usr_bare(), + Options :: pubsub_options:options_node() + | pubsub_options:options_subscription()) + -> Xmlel_X::xmlel() +). + +xdata_x('node_config', 'form', Pubsub_Features, Host, Entity, Node_Options) -> + xmpp_xdata:xmlel_x(<<"form">>, + _Xmlels_Field = [ + xmpp_xdata:xmlel_field(<<"FORM_TYPE">>, <<"hidden">>, + [?NS_PUBSUB_NODE_CONFIG]) + |xdata_field(Pubsub_Features, Host, Entity, Node_Options, []) + ]); + +xdata_x('subscribe_options', 'form', Pubsub_Features, Host, Entity, + Subscription_Options) -> + xmpp_xdata:xmlel_x(<<"form">>, + _Xmlels_Field = [ + xmpp_xdata:xmlel_field(<<"FORM_TYPE">>, <<"hidden">>, + [?NS_PUBSUB_SUBSCRIBE_OPTIONS]) + |xdata_field(Pubsub_Features, Host, Entity, Subscription_Options, []) + ]); + +xdata_x('subscribe_options', 'result', Pubsub_Features, Host, Entity, + Subscription_Options) -> + xmpp_xdata:xmlel_x(<<"result">>, + _Xmlels_Field = [ + xmpp_xdata:xmlel_field(<<"FORM_TYPE">>, <<"hidden">>, + [?NS_PUBSUB_SUBSCRIBE_OPTIONS]) + |xdata_field(Pubsub_Features, Host, Entity, Subscription_Options, []) + ]). + +%% +%% +-spec(xdata_x/7 :: +( + Options_Type :: 'subscribe_options', + Form_Type :: 'form', + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Host :: xmpp_jid:raw_jid_component_bare(), + Entity :: xmpp_jid:usr_bare(), + Subscription_Options :: [] | pubsub_options:options_subscription(), + Default_Subscription_Options :: pubsub_options:options_subscription()) + -> Xmlel_X::xmlel() +). + + +%% +xdata_x('subscribe_options', 'form', Pubsub_Features, Host, Entity, + Subscription_Options, Default_Subscription_Options) -> + xmpp_xdata:xmlel_x(<<"form">>, + _Xmlels_Field = [ + xmpp_xdata:xmlel_field(<<"FORM_TYPE">>, <<"hidden">>, + [?NS_PUBSUB_SUBSCRIBE_OPTIONS]) + |xdata_field(Pubsub_Features, Host, Entity, + filter_subscription_options(Subscription_Options, + Default_Subscription_Options, []), + []) + ]). + +%% +-spec(filter_subscription_options/3 :: +( + Options :: [] | pubsub_options:options_subscription(), + Default_Subscription_Options :: pubsub_options:options_subscription(), + Subscription_Options :: [] | pubsub_options:options_subscription()) + -> Subscription_Options::pubsub_options:options_subscription() +). + +filter_subscription_options([] = _Options, Default_Subscription_Options, + Subscription_Options) -> + Default_Subscription_Options ++ Subscription_Options; +%% +filter_subscription_options([{Key, Value} | Options], Default_Subscription_Options, + Subscription_Options) -> + filter_subscription_options(Options, + lists:keydelete(Key, 1, Default_Subscription_Options), + [{Key, Value} | Subscription_Options]). + + +-define(Label_Deliver, <<"Enable delivery ?">>). +-define(Label_Digest, <<"Receive digest notifications ?">>). +-define(Label_Digest_Frequency, <<"Receive digest notifications (approx. one per day)?">>). +-define(Label_Expire, <<"Requested lease period">>). +-define(Label_Include_Body, <<"Receive message body in addition to payload ?">>). +-define(Label_Show_Values, <<"Select the presence types which are allowed to receive event notifications">>). + +%% +%% pubsub#subscribe_options +%% +-spec(xdata_field/5 :: +( + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Host :: xmpp_jid:raw_jid_component_bare(), + Entity :: xmpp_jid:usr_bare(), + Options :: [] | pubsub_options:options_subscription(), + Xmlels_Field :: [] | [Xmlel_Field::xmlel(),...]) + -> Xmlels_Field::[Xmlel_Field::xmlel(),...] +). +%% +xdata_field(_Pubsub_Features, _Host, _Entity, [] = _Options, Xmlels_Field) -> + lists:sort(Xmlels_Field); +%% 'pubsub#deliver' +xdata_field(Pubsub_Features, Host, Entity, [{'deliver', Deliver} | Options], + Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#deliver">>, + <<"Enable delivery?">>, + xdata_value('boolean', Deliver)) + | Xmlels_Field]); +%% 'pubsub#digest' +xdata_field(Pubsub_Features, Host, Entity, [{'digest', Digest} | Options], + Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#digest">>, + <<"Receive digest notifications (approx. one per day)?">>, + xdata_value('boolean', Digest)) + | Xmlels_Field]); +%% 'pubsub#digest_frequency' +xdata_field(Pubsub_Features, Host, Entity, + [{'digest_frequency', Digest_Frequency} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#digest_frequency">>, + <<"Receive digest notifications (approx. one per day)?">>, + xdata_value('integer', Digest_Frequency)) + | Xmlels_Field]); +%% 'pubsub#expire' +xdata_field(Pubsub_Features, Host, Entity, + [{'expire', Expire} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#expire">>, + <<"Requested lease period">>, + case is_atom(Expire) of + true -> xdata_value('atom', Expire); + false -> xdata_value('date', Expire) + end) + | Xmlels_Field]); +%% 'pubsub#include_body' +xdata_field(Pubsub_Features, Host, Entity, + [{'include_body', Include_Body} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#include_body">>, + <<"Receive message body in addition to payload?">>, + xdata_value('boolean', Include_Body)) + | Xmlels_Field]); +%% 'pubsub#show-values' +xdata_field(Pubsub_Features, Host, Entity, + [{'show-values', Show_Values} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_multi( + <<"pubsub#show-values">>, + <<"Select the presence types which are allowed to receive event notifications">>, + lists:map(fun + ('away') -> <<"away">>; + ('chat') -> <<"chat">>; + ('dnd') -> <<"dnd">>; + ('online') -> <<"online">>; + ('xa') -> <<"xa">> + end, Show_Values), + [{<<"away">>, <<"Away">>}, + {<<"chat">>, <<"Want to Chat">>}, + {<<"dnd">>, <<"Do Not Disturb">>}, + {<<"online">>, <<"Available">>}, + {<<"xa">>, <<"Extended Away">>}]) + | Xmlels_Field]); +%% 'pubsub#subscription_type' +xdata_field(Pubsub_Features, Host, Entity, + [{'subscription_type', Subscription_Type} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#subscription_type">>, + <<"Subscription Type">>, + case Subscription_Type of + undefined -> <<"items">>; + 'items' -> <<"items">>; + 'nodes' -> <<"nodes">>; + 'all' -> <<"all">> + end, + [{<<"items">>, <<"Receive notification of items only">>}, + {<<"nodes">>, <<"Receive notification of new nodes only">>}, + {<<"all">>, <<"Receive notification of items and nodes">>}]) + | Xmlels_Field]); +%% 'pubsub#subscription_depth' +xdata_field(Pubsub_Features, Host, Entity, + [{'subscription_depth', Subscription_Depth} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#subscription_depth">>, + <<"How far to traverse the node graph for notifications">>, + case Subscription_Depth of + undefined -> <<"1">>; + 'all' -> <<"all">>; + _ -> xdata_value('integer', Subscription_Depth) + + end, + [{<<"1">>, <<"Receive notification from direct child nodes only">>}, + {<<"all">>, <<"Receive notification from all descendent nodes">>}]) + | Xmlels_Field]); +%% +%% pubsub#node_config +%% +%% 'pubsub#access_model' +xdata_field(Pubsub_Features, Host, Entity, + [{'access_model', Access_Model} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#access_model">>, + <<"Specify the subscriber model">>, + case Access_Model of + % undefined -> <<"open">>; + 'authorize' -> <<"authorize">>; + 'open' -> <<"open">>; + 'presence' -> <<"presence">>; + 'roster' -> <<"roster">>; + 'whitelist' -> <<"whitelist">> + end, + xdata_access_model(Pubsub_Features, + ['authorize', 'open', 'presence', 'roster', 'whitelist'])) + | Xmlels_Field]); +%% 'pubsub#body_xslt' +xdata_field(Pubsub_Features, Host, Entity, + [{'body_xslt', Xslt} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#body_xslt">>, + <<"The URL of an XSL transformation which can be applied to " + "payloads in order to generate an appropriate message body element">>, + Xslt) + | Xmlels_Field]); +%% 'pubsub#children_association_policy' +xdata_field(Pubsub_Features, Host, Entity, + [{'children_association_policy', Children_Association_Policy} | Options], + Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#children_association_policy">>, + <<"Who may associate leaf nodes with a collection">>, + case Children_Association_Policy of + undefined -> <<"owners">>; + 'owners' -> <<"owners">>; + 'all' -> <<"all">>; + 'whitelist' -> <<"whitelist">> + end, + [{<<"all">>, <<"Anyone may associate leaf nodes with the collection">>}, + {<<"owners">>, <<"Only collection node owners may associate leaf" + " nodes with the collection">>}, + {<<"whitelist">>, <<"Only those on a whitelist may associate leaf " + "nodes with the collection">>}]) + | Xmlels_Field]); +%% 'pubsub#children_association_whitelist' +xdata_field(Pubsub_Features, Host, Entity, + [{'children_association_whitelist', Children_Association_Whitelist} + | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_jid_multi( + <<"pubsub#children_association_whitelist">>, + <<"The list of JIDs that may associate leaf nodes with a collection">>, + Children_Association_Whitelist) + | Xmlels_Field]); +%% 'pubsub#children' +xdata_field(Pubsub_Features, Host, Entity, + [{'children', Children} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_multi( + <<"pubsub#children">>, + <<"The child nodes (leaf or collection) associated with a collection">>, + Children) + | Xmlels_Field]); +%% 'pubsub#children_max' +xdata_field(Pubsub_Features, Host, Entity, + [{'children_max', Children_Max} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#children_max">>, + <<"The maximum number of child nodes that can be associated with a collection">>, + xdata_value('integer', Children_Max)) + | Xmlels_Field]); +%% 'pubsub#collection' +xdata_field(Pubsub_Features, Host, Entity, + [{'collection', Collection} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_multi( + <<"pubsub#collection">>, + <<"The collection(s) with which a node is affiliated">>, + Collection) + | Xmlels_Field]); +%% 'pubsub#contact' +xdata_field(Pubsub_Features, Host, Entity, + [{'contact', Contacts} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_jid_multi( + <<"pubsub#contact">>, + <<"The JIDs of those to contact with questions">>, + Contacts) + | Xmlels_Field]); +%% 'pubsub#dataform_xslt' +xdata_field(Pubsub_Features, Host, Entity, + [{'dataform_xslt', Dataform_Xslt} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#dataform_xslt">>, + <<"Payload XSLT">>, + xdata_value({'text-multi', 'atom'}, Dataform_Xslt)) + | Xmlels_Field]); +%% 'pubsub#deliver_notifications' +xdata_field(Pubsub_Features, Host, Entity, + [{'deliver_notifications', Deliver_Notifications} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#deliver_notifications">>, + <<"Whether to deliver event notifications">>, + xdata_value('boolean', Deliver_Notifications)) + | Xmlels_Field]); +%% 'pubsub#deliver_payloads' +xdata_field(Pubsub_Features, Host, Entity, + [{'deliver_payloads', Deliver_Payloads} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#deliver_payloads">>, + <<"Whether to deliver payloads with event notifications">>, + xdata_value('boolean', Deliver_Payloads)) + | Xmlels_Field]); +%% 'pubsub#description' +xdata_field(Pubsub_Features, Host, Entity, + [{'description', Description} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#description">>, + <<"A description of the node">>, + Description) + | Xmlels_Field]); +%% 'pubsub#item_expire' +xdata_field(Pubsub_Features, Host, Entity, + [{'item_expire', Item_Expire} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#item_expire">>, + <<"Number of seconds after which to automatically purge items">>, + xdata_value('integer', Item_Expire)) + | Xmlels_Field]); +%% 'pubsub#itemreply' +xdata_field(Pubsub_Features, Host, Entity, + [{'itemreply', ItemReply} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#itemreply">>, + <<"Whether owners or publisher should receive replies to items">>, + case ItemReply of + undefined -> <<"publisher">>; + 'owner' -> <<"owner">>; + 'publisher' -> <<"publisher">> + end, + [{<<"owner">>, <<"Statically specify a replyto of the node owner(s)">>}, + {<<"publisher">>, <<"Dynamically specify a replyto of the item publisher">>}]) + | Xmlels_Field]); +%% 'pubsub#language' +xdata_field(Pubsub_Features, Host, Entity, + [{'language', Language} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#language">>, + <<"The default language of the node">>, + case Language of + undefined -> <<"en">>; + _Language -> Language + end, + [{<<"en">>, <<"English">>} + %{<<"es">>, <<"Español">>}, + %{<<"fr">>, <<"Français">>}, + %{<<"pl">>, <<"Polski">>}, + %{<<"ru">>, <<"Русский">>} + ]) + | Xmlels_Field]); +%% 'pubsub#max_items' +xdata_field(Pubsub_Features, Host, Entity, + [{'max_items', Max_Items} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#max_items">>, + <<"The maximum number of items to persist">>, + xdata_value('integer', Max_Items)) + | Xmlels_Field]); +%% 'pubsub#max_payload_size' +xdata_field(Pubsub_Features, Host, Entity, + [{'max_payload_size', Max_Payload_Size} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#max_payload_size">>, + <<"The maximum payload size in bytes">>, + xdata_value('integer', Max_Payload_Size)) + | Xmlels_Field]); +%% 'pubsub#node_type' +xdata_field(Pubsub_Features, Host, Entity, + [{'node_type', Node_Type} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, + Entity, Options, + [case lists:member(<<"collections">>, Pubsub_Features) of + true -> + xmpp_xdata:xmlel_field_list_single( + <<"pubsub#node_type">>, + <<"Whether the node is a leaf (default) or a collection">>, + case Node_Type of + undefined -> <<"leaf">>; + 'leaf' -> <<"leaf">>; + 'collection' -> <<"collection">> + end, + [{<<"leaf">>, <<"The node is a leaf node (default)">>}, + {<<"collection">>, <<"The node is a collection node">>}]); + false -> + %% Collections not supported -> non-modifiable field +% xmpp_xdata:xmlel_field_fixed( +% <<"pubsub#node_type">>, +% <<"The node is a leaf node (default)">>, +% <<"leaf">>) + xmpp_xdata:xmlel_field_list_single( + <<"pubsub#node_type">>, + <<"Whether the node is a leaf (default) or a collection">>, + <<"leaf">>, + [{<<"leaf">>, <<"The node is a leaf node (default)">>}]) + end + |Xmlels_Field]); +%% 'pubsub#notification_type' +xdata_field(Pubsub_Features, Host, Entity, + [{'notification_type', Notification_Type} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#notification_type">>, + <<"Specify the delivery style for event notifications">>, + case Notification_Type of + undefined -> <<"headline">>; + 'headline' -> <<"headline">>; + 'normal' -> <<"normal">>; + 'chat' -> <<"chat">> + end, + [{<<"headline">>, <<"Messages of type headline">>}, + {<<"normal">>, <<"Messages of type normal">>} + %{<<"chat">>, <<"Messages of type chat">>} + %{<<"presence">>, <<"Presence">>} + %{<<"iq">>, <<"Iq">>} + ]) + | Xmlels_Field]); +%% 'pubsub#notify_config' +xdata_field(Pubsub_Features, Host, Entity, + [{'notify_config', Notify_Config} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#notify_config">>, + <<"Notify owners and subscribers when the node configuration changes">>, + xdata_value('boolean', Notify_Config)) + | Xmlels_Field]); +%% 'pubsub#notify_delete' +xdata_field(Pubsub_Features, Host, Entity, + [{'notify_delete', Notify_Delete} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#notify_delete">>, + <<"Notify owners and subscribers when the node is deleted">>, + xdata_value('boolean', Notify_Delete)) + | Xmlels_Field]); +%% 'pubsub#notify_retract' +xdata_field(Pubsub_Features, Host, Entity, + [{'notify_retract', Notify_Retract} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#notify_retract">>, + <<"Notify subscribers when items are removed from the node">>, + xdata_value('boolean', Notify_Retract)) + | Xmlels_Field]); +%% 'pubsub#notify_sub' +xdata_field(Pubsub_Features, Host, Entity, + [{'notify_sub', Notify_Sub} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#notify_sub">>, + <<"Notify owners about new subscribers and unsubscribes">>, + xdata_value('boolean', Notify_Sub)) + | Xmlels_Field]); +%% 'pubsub#persist_items' +xdata_field(Pubsub_Features, Host, Entity, + [{'persist_items', Persist_Items} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#persist_items">>, + <<"Persist items to storage">>, + xdata_value('boolean', Persist_Items)) + | Xmlels_Field]); +%% 'pubsub#presence_based_delivery' +xdata_field(Pubsub_Features, Host, Entity, + [{'presence_based_delivery', Presence_Based_Delivery} | Options] + , Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#presence_based_delivery">>, + <<"Deliver event notifications only to available users">>, + xdata_value('boolean', Presence_Based_Delivery)) + | Xmlels_Field]); +%% 'pubsub#publish_model' +xdata_field(Pubsub_Features, Host, Entity, + [{'publish_model', Publish_Model} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#publish_model">>, + <<"Specify the publisher model">>, + case Publish_Model of + % undefined -> <<"open">>; + 'open' -> <<"open">>; + 'publishers' -> <<"publishers">>; + 'subscribers' -> <<"subscribers">> + end, + [{<<"publishers">>, <<"Only publishers may publish">>}, + {<<"subscribers">>, <<"Subscribers may publish">>}, + {<<"open">>, <<"Anyone may publish">>}]) + | Xmlels_Field]); +%% 'pubsub#purge_offline' +xdata_field(Pubsub_Features, Host, Entity, + [{'purge_offline', Purge_Offline} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#purge_offline">>, + <<"Purge all items when the relevant publisher goes offline ?">>, + xdata_value('boolean', Purge_Offline)) + | Xmlels_Field]); +%% 'pubsub#roster_groups_allowed' +xdata_field(Pubsub_Features, Host, Entity, + [{'roster_groups_allowed', Rosters_Groups_Allowed} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_multi( + <<"pubsub#roster_groups_allowed">>, + <<"Roster group(s) allowed to subscribe and retrieve items">>, + case lists:keyfind(Entity, 1, Rosters_Groups_Allowed) of + false -> []; + {_Entity, Roster_Groups} -> Roster_Groups + end, + xdata_roster(Host, Entity)) + | Xmlels_Field]); +%% 'pubsub#send_last_published_item' +xdata_field(Pubsub_Features, Host, Entity, + [{'send_last_published_item', Send_Last_Published_Item} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_list_single( + <<"pubsub#send_last_published_item">>, + <<"When to send the last published item">>, + case Send_Last_Published_Item of + undefined -> <<"on_sub_and_presence">>; + 'never' -> <<"never">>; + 'on_sub_and_presence' -> <<"on_sub_and_presence">>; + 'on_sub' -> <<"on_sub">> + end, + [{<<"never">>, <<"Never">>}, + {<<"on_sub">>, <<"When a new subscription is processed">>}, + {<<"on_sub_and_presence">>, <<"When a new subscription is processed " + "and whenever a subscriber comes online">>}]) + | Xmlels_Field]); +%% 'pubsub#subscribe' +xdata_field(Pubsub_Features, Host, Entity, + [{'subscribe', Subscribe} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#subscribe">>, + <<"Whether to allow subscriptions">>, + xdata_value('boolean', Subscribe)) + | Xmlels_Field]); +%% 'pubsub#tempsub' +xdata_field(Pubsub_Features, Host, Entity, + [{'tempsub', Tempsub} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_boolean( + <<"pubsub#tempsub">>, + <<"Make all subscriptions temporary, based on subscriber presence">>, + xdata_value('boolean', Tempsub)) + | Xmlels_Field]); +%% 'pubsub#title' +xdata_field(Pubsub_Features, Host, Entity, + [{'title', Title} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#title">>, + <<"A friendly name for the node">>, + Title) + | Xmlels_Field]); +%% 'pubsub#type' +xdata_field(Pubsub_Features, Host, Entity, + [{'type', Type} | Options], Xmlels_Field) -> + xdata_field(Pubsub_Features, Host, Entity, Options, + [xmpp_xdata:xmlel_field_text_single( + <<"pubsub#type">>, + <<"Specify the type of payload data to be provided at this node">>, + Type) + | Xmlels_Field]). + + + +%% +-spec(xdata_value/2 :: +( + DataType :: 'atom' + | 'boolean' + | 'date' + | 'integer' + | {'text-multi', 'atom'}, + Value :: undefined + | atom() + | boolean() + | erlang:timestamp() + | non_neg_integer() + | [atom()]) + -> Xdata_Value :: binary() | [binary(),...] +). + +xdata_value(_, undefined) -> undefined; +%% +xdata_value('atom', Value) -> list_to_binary(atom_to_list(Value)); +%% +xdata_value('boolean', false) -> <<"false">>; +xdata_value('boolean', true) -> <<"true">>; +%% +xdata_value('date', TimeStamp) -> + {DateTime, _} = jlib:timestamp_to_iso(calendar:now_to_datetime(TimeStamp), utc), + list_to_binary(DateTime ++ "Z"); +%% +xdata_value('integer', Value) -> list_to_binary(integer_to_list(Value)); +%% +xdata_value({'text-multi', 'atom'}, Values) -> + [list_to_binary(atom_to_list(Value)) || Value <- Values]. + +%% +-spec(xdata_access_model/3 :: +( + Access_Model :: pubsub_options:access_model(), + Pubsub_Feature :: boolean(), + Access_Models :: [{binary(), binary()}]) + -> Access_Models :: [{binary(), binary()}] +). + +xdata_access_model(_Access_Model, false, Access_Models) -> + Access_Models; +%% +xdata_access_model('authorize' = _Access_Model, true, Access_Models) -> + [{<<"authorize">>, <<"Subscription requests must be approved and only " + "subscribers may retrieve items">>} + | Access_Models]; +%% +xdata_access_model('open' = _Access_Model, true, Access_Models) -> + [{<<"open">>, <<"Anyone may subscribe and retrieve items">>} + | Access_Models]; +%% +xdata_access_model('presence' = _Access_Model, true, Access_Models) -> + [{<<"presence">>, <<"Anyone with a presence subscription of both or from may " + "subscribe and retrieve items">>} + | Access_Models]; +%% +xdata_access_model('roster' = _Access_Model, true, Access_Models) -> + [{<<"roster">>, <<"Anyone in the specified roster group(s) may subscribe and " + "retrieve items">>} + | Access_Models]; +%% +xdata_access_model('whitelist' = _Access_Model, true, Access_Models) -> + [{<<"whitelist">>, <<"Only those on a whitelist may subscribe and retrieve items">>} + | Access_Models]. + +%% +-spec(xdata_access_model/2 :: +( + Pubsub_Features :: exmpp_pubsub:pubsub_features(), + Default_Access_Model :: ['authorize'|'open'|'presence'|'roster'|'whitelist',...]) + -> Access_Models :: [{binary(), binary()},...] +). + +xdata_access_model(Pubsub_Features, Default_Access_Models) -> + lists:foldr(fun + ('authorize', Access_Models) -> + xdata_access_model('authorize', + lists:member(<<"access-authorize">>, Pubsub_Features), Access_Models); + %% + ('open', Access_Models) -> + xdata_access_model('open', + lists:member(<<"access-open">>, Pubsub_Features), Access_Models); + %% + ('presence', Access_Models) -> + xdata_access_model('presence', + lists:member(<<"access-presence">>, Pubsub_Features), Access_Models); + %% + ('roster', Access_Models) -> + xdata_access_model('roster', + lists:member(<<"access-roster">>, Pubsub_Features), Access_Models); + %% + ('whitelist', Access_Models) -> + xdata_access_model('whitelist', + lists:member(<<"access-whitelist">>, Pubsub_Features), Access_Models) + % + end, [], Default_Access_Models). + +%% + +%% Local Entity +-spec(xdata_roster/2 :: +( + Host :: binary(), + Entity :: xmpp_jid:usr_bare()) + -> Roster_Groups :: [Roster_Group::binary()] +). + +xdata_roster(Host, {_, Host, _} = Entity) -> + _Roster_Groups = lists:usort(lists:foldl(fun + (#roster{groups = Groups}, Roster_Groups) -> + lists:foldl(fun + (Group, Roster_Groups_Bis) -> + [Group | Roster_Groups_Bis] + end, Roster_Groups, Groups) + end, [], _Roster = get_entity_roster(Entity))); +%% Remote Entity +xdata_roster(_Host, _Entity) -> + []. |