'presence-subscription-required' | 'subid-required' |
'too-many-subscriptions' | 'unsupported' |
'unsupported-access-model'.
--type ps_error_feature() :: 'access-authorize' | 'access-open' |
- 'access-presence' | 'access-roster' |
- 'access-whitelist' | 'auto-create' |
- 'auto-subscribe' | 'collections' | 'config-node' |
- 'create-and-configure' | 'create-nodes' |
- 'delete-items' | 'delete-nodes' |
- 'filtered-notifications' | 'get-pending' |
- 'instant-nodes' | 'item-ids' | 'last-published' |
- 'leased-subscription' | 'manage-subscriptions' |
- 'member-affiliation' | 'meta-data' |
- 'modify-affiliations' | 'multi-collection' |
- 'multi-subscribe' | 'outcast-affiliation' |
- 'persistent-items' | 'presence-notifications' |
- 'presence-subscribe' | 'publish' |
- 'publish-options' | 'publish-only-affiliation' |
- 'publisher-affiliation' | 'purge-nodes' |
- 'retract-items' | 'retrieve-affiliations' |
- 'retrieve-default' | 'retrieve-items' |
- 'retrieve-subscriptions' | 'subscribe' |
- 'subscription-options' | 'subscription-notifications'.
--record(ps_error, {type :: ps_error_type(), feature :: ps_error_feature()}).
+-type ps_feature() :: 'access-authorize' | 'access-open' |
+ 'access-presence' | 'access-roster' |
+ 'access-whitelist' | 'auto-create' |
+ 'auto-subscribe' | 'collections' | 'config-node' |
+ 'create-and-configure' | 'create-nodes' |
+ 'delete-items' | 'delete-nodes' |
+ 'filtered-notifications' | 'get-pending' |
+ 'instant-nodes' | 'item-ids' | 'last-published' |
+ 'leased-subscription' | 'manage-subscriptions' |
+ 'member-affiliation' | 'meta-data' |
+ 'modify-affiliations' | 'multi-collection' |
+ 'multi-subscribe' | 'outcast-affiliation' |
+ 'persistent-items' | 'presence-notifications' |
+ 'presence-subscribe' | 'publish' |
+ 'publish-options' | 'publish-only-affiliation' |
+ 'publisher-affiliation' | 'purge-nodes' |
+ 'retract-items' | 'retrieve-affiliations' |
+ 'retrieve-default' | 'retrieve-items' |
+ 'retrieve-subscriptions' | 'subscribe' |
+ 'subscription-options' | 'subscription-notifications'.
+-record(ps_error, {type :: ps_error_type(), feature :: ps_feature()}).
-type ps_error() :: #ps_error{}.
-record(chatstate, {type :: active | composing | gone | inactive | paused}).
+++ /dev/null
-%%%----------------------------------------------------------------------
-%%% File : adhoc.erl
-%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
-%%% Purpose : Provide helper functions for ad-hoc commands (XEP-0050)
-%%% Created : 31 Oct 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
-%%%
-%%%
-%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
-%%%
-%%% This program is free software; you can redistribute it and/or
-%%% modify it under the terms of the GNU General Public License as
-%%% published by the Free Software Foundation; either version 2 of the
-%%% License, or (at your option) any later version.
-%%%
-%%% This program is distributed in the hope that it will be useful,
-%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
-%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%%% General Public License for more details.
-%%%
-%%% You should have received a copy of the GNU General Public License along
-%%% with this program; if not, write to the Free Software Foundation, Inc.,
-%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-%%%
-%%%----------------------------------------------------------------------
-
--module(adhoc).
-
--author('henoch@dtek.chalmers.se').
-
--export([
- parse_request/1,
- produce_response/2,
- produce_response/1
-]).
-
--include("ejabberd.hrl").
--include("logger.hrl").
--include("jlib.hrl").
--include("adhoc.hrl").
-
-%% Parse an ad-hoc request. Return either an adhoc_request record or
-%% an {error, ErrorType} tuple.
-%%
--spec parse_request(IQ :: iq_request()) -> adhoc_response() | {error, _}.
-
-parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}) ->
- ?DEBUG("entering parse_request...", []),
- Node = fxml:get_tag_attr_s(<<"node">>, SubEl),
- SessionID = fxml:get_tag_attr_s(<<"sessionid">>, SubEl),
- Action = fxml:get_tag_attr_s(<<"action">>, SubEl),
- XData = find_xdata_el(SubEl),
- #xmlel{children = AllEls} = SubEl,
- Others = case XData of
- false -> AllEls;
- _ -> lists:delete(XData, AllEls)
- end,
- #adhoc_request{
- lang = Lang,
- node = Node,
- sessionid = SessionID,
- action = Action,
- xdata = XData,
- others = Others
- };
-parse_request(#iq{lang = Lang}) ->
- Text = <<"Failed to parse ad-hoc command request">>,
- {error, ?ERRT_BAD_REQUEST(Lang, Text)}.
-
-%% Borrowed from mod_vcard.erl
-find_xdata_el(#xmlel{children = SubEls}) ->
- find_xdata_el1(SubEls).
-
-find_xdata_el1([]) -> false;
-find_xdata_el1([El | Els]) when is_record(El, xmlel) ->
- case fxml:get_tag_attr_s(<<"xmlns">>, El) of
- ?NS_XDATA -> El;
- _ -> find_xdata_el1(Els)
- end;
-find_xdata_el1([_ | Els]) -> find_xdata_el1(Els).
-
-%% Produce a <command/> node to use as response from an adhoc_response
-%% record, filling in values for language, node and session id from
-%% the request.
-%%
--spec produce_response(Adhoc_Request :: adhoc_request(),
- Adhoc_Response :: adhoc_response()) ->
- Xmlel::xmlel().
-
-%% Produce a <command/> node to use as response from an adhoc_response
-%% record.
-produce_response(#adhoc_request{lang = Lang, node = Node, sessionid = SessionID},
- Adhoc_Response) ->
- produce_response(Adhoc_Response#adhoc_response{
- lang = Lang, node = Node, sessionid = SessionID
- }).
-
-%%
--spec produce_response(Adhoc_Response::adhoc_response()) -> Xmlel::xmlel().
-
-produce_response(
- #adhoc_response{
- %lang = _Lang,
- node = Node,
- sessionid = ProvidedSessionID,
- status = Status,
- defaultaction = DefaultAction,
- actions = Actions,
- notes = Notes,
- elements = Elements
- }) ->
- SessionID = if is_binary(ProvidedSessionID),
- ProvidedSessionID /= <<"">> -> ProvidedSessionID;
- true -> jlib:now_to_utc_string(p1_time_compat:timestamp())
- end,
- case Actions of
- [] ->
- ActionsEls = [];
- _ ->
- case DefaultAction of
- <<"">> -> ActionsElAttrs = [];
- _ -> ActionsElAttrs = [{<<"execute">>, DefaultAction}]
- end,
- ActionsEls = [
- #xmlel{
- name = <<"actions">>,
- attrs = ActionsElAttrs,
- children = [
- #xmlel{name = Action, attrs = [], children = []}
- || Action <- Actions]
- }
- ]
- end,
- NotesEls = lists:map(fun({Type, Text}) ->
- #xmlel{
- name = <<"note">>,
- attrs = [{<<"type">>, Type}],
- children = [{xmlcdata, Text}]
- }
- end, Notes),
- #xmlel{
- name = <<"command">>,
- attrs = [
- {<<"xmlns">>, ?NS_COMMANDS},
- {<<"sessionid">>, SessionID},
- {<<"node">>, Node},
- {<<"status">>, iolist_to_binary(atom_to_list(Status))}
- ],
- children = ActionsEls ++ NotesEls ++ Elements
- }.
-include("ejabberd.hrl").
-include("logger.hrl").
-%%-include("adhoc.hrl").
-%%-include("jlib.hrl").
-include("xmpp.hrl").
-include("pubsub.hrl").
iq_pubsub(Host, Access, #iq{from = From, type = IQType, lang = Lang,
sub_els = [SubEl]}) ->
case {IQType, SubEl} of
- {set, #pubsub{create = Node, configure = {_, XData},
+ {set, #pubsub{create = Node, configure = Configure,
_ = undefined}} when is_binary(Node) ->
ServerHost = serverhost(Host),
Plugins = config(ServerHost, plugins),
- Config = get_xdata_fields(XData),
+ Config = case Configure of
+ {_, XData} -> get_xdata_fields(XData);
+ undefined -> []
+ end,
Type = hd(Plugins),
create_node(Host, ServerHost, Node, From, Type, Access, Config);
{set, #pubsub{publish = #ps_publish{node = Node, items = Items},
_ = undefined}} ->
case Items of
[#ps_item{id = ItemId}] ->
- delete_item(Host, Node, From, ItemId, Notify);
+ if ItemId /= <<>> ->
+ delete_item(Host, Node, From, ItemId, Notify);
+ true ->
+ {error, extended_error(xmpp:err_bad_request(),
+ err_item_required())}
+ end;
[] ->
{error, extended_error(xmpp:err_bad_request(), err_item_required())};
_ ->
jid = JID, xdata = XData},
_ = undefined}} ->
set_options(Host, Node, JID, SubId, get_xdata_fields(XData));
+ {set, #pubsub{}} ->
+ {error, xmpp:err_bad_request()};
_ ->
{error, xmpp:err_feature_not_implemented()}
end.
--spec iq_pubsub_owner(binary() | ljid(), iq()) -> {result, pubsub()} | {error, error()}.
+-spec iq_pubsub_owner(binary() | ljid(), iq()) -> {result, pubsub_owner() | undefined} |
+ {error, error()}.
iq_pubsub_owner(Host, #iq{type = IQType, from = From,
lang = Lang, sub_els = [SubEl]}) ->
case {IQType, SubEl} of
undefined ->
{error, xmpp:err_bad_request(<<"No data form found">>, Lang)};
#xdata{type = cancel} ->
- {result, #pubsub{}};
+ {result, #pubsub_owner{}};
#xdata{type = submit} ->
Config = get_xdata_fields(XData),
set_configure(Host, Node, From, Config, Lang);
%%<li>The node is the root collection node, which cannot be deleted.</li>
%%<li>The specified node does not exist.</li>
%%</ul>
--spec delete_node(host(), binary(), jid()) -> {result, pubsub()} | {error, error()}.
+-spec delete_node(host(), binary(), jid()) -> {result, pubsub_owner()} | {error, error()}.
delete_node(_Host, <<>>, _Owner) ->
{error, xmpp:err_not_allowed(<<"No node specified">>, ?MYLANG)};
delete_node(Host, Node, Owner) ->
{error, xmpp:err_forbidden(<<"Owner privileges required">>, ?MYLANG)}
end
end,
- Reply = [],
+ Reply = undefined,
ServerHost = serverhost(Host),
case transaction(Host, Node, Action, transaction) of
{result, {_, {SubsByDepth, {Result, broadcast, Removed}}}} ->
Error
end.
--spec get_subscriptions(binary(), binary(), jid()) -> {result, pubsub()} |
- {error, error()}.
+-spec get_subscriptions(host(), binary(), jid()) -> {result, pubsub_owner()} |
+ {error, error()}.
get_subscriptions(Host, Node, JID) ->
Action = fun (#pubsub_node{type = Type, id = Nidx}) ->
Features = plugin_features(Host, Type),
({AJID, Sub, SubId}) ->
[#ps_subscription{jid = AJID, type = Sub, subid = SubId}]
end, Subs),
- {result, #pubsub{subscriptions = {Node, Entities}}};
+ {result, #pubsub_owner{subscriptions = {Node, Entities}}};
Error ->
Error
end.
get_subscriptions_for_send_last(_Host, _PType, _, _JID, _LJID, _BJID) ->
[].
+-spec set_subscriptions(host(), binary(), jid(), [ps_subscription()]) ->
+ {result, undefined} | {error, error()}.
set_subscriptions(Host, Node, From, Entities) ->
Owner = jid:tolower(jid:remove_resource(From)),
Notify = fun(#ps_subscription{jid = JID, type = Sub}) ->
%%%%%%% Configuration handling
-spec get_configure(host(), binary(), binary(), jid(),
- binary()) -> {error, error()} | {result, pubsub()}.
+ binary()) -> {error, error()} | {result, pubsub_owner()}.
get_configure(Host, ServerHost, Node, From, Lang) ->
Action = fun (#pubsub_node{options = Options, type = Type, id = Nidx}) ->
case node_call(Host, Type, get_affiliation, [Nidx, From]) of
Other -> Other
end.
--spec get_default(host(), binary(), jid(), binary()) -> {result, pubsub()}.
+-spec get_default(host(), binary(), jid(), binary()) -> {result, pubsub_owner()}.
get_default(Host, Node, _From, Lang) ->
Type = select_type(Host, Host, Node),
Options = node_options(Host, Type),
%%</ul>
-spec set_configure(host(), binary(), jid(), [{binary(), [binary()]}],
binary()) -> {result, undefined} | {error, error()}.
+set_configure(_Host, <<>>, _From, _Config, _Lang) ->
+ {error, extended_error(xmpp:err_bad_request(), err_nodeid_required())};
set_configure(Host, Node, From, Config, Lang) ->
Action =
fun(#pubsub_node{options = Options, type = Type, id = Nidx} = N) ->
select_type(ServerHost, Host, Node) ->
select_type(ServerHost, Host, Node, hd(plugins(Host))).
+-spec feature(binary()) -> binary().
feature(<<"rsm">>) -> ?NS_RSM;
feature(Feature) -> <<(?NS_PUBSUB)/binary, "#", Feature/binary>>.
+-spec features() -> [binary()].
features() ->
[% see plugin "access-authorize", % OPTIONAL
- <<"access-open">>, % OPTIONAL this relates to access_model option in node_hometree
- <<"access-presence">>, % OPTIONAL this relates to access_model option in node_pep
- <<"access-whitelist">>, % OPTIONAL
- <<"collections">>, % RECOMMENDED
- <<"config-node">>, % RECOMMENDED
- <<"create-and-configure">>, % RECOMMENDED
- <<"item-ids">>, % RECOMMENDED
- <<"last-published">>, % RECOMMENDED
- <<"member-affiliation">>, % RECOMMENDED
- <<"presence-notifications">>, % OPTIONAL
- <<"presence-subscribe">>, % RECOMMENDED
- <<"publisher-affiliation">>, % RECOMMENDED
- <<"publish-only-affiliation">>, % OPTIONAL
- <<"retrieve-default">>,
- <<"shim">>]. % RECOMMENDED
+ <<"access-open">>, % OPTIONAL this relates to access_model option in node_hometree
+ <<"access-presence">>, % OPTIONAL this relates to access_model option in node_pep
+ <<"access-whitelist">>, % OPTIONAL
+ <<"collections">>, % RECOMMENDED
+ <<"config-node">>, % RECOMMENDED
+ <<"create-and-configure">>, % RECOMMENDED
+ <<"item-ids">>, % RECOMMENDED
+ <<"last-published">>, % RECOMMENDED
+ <<"member-affiliation">>, % RECOMMENDED
+ <<"presence-notifications">>, % OPTIONAL
+ <<"presence-subscribe">>, % RECOMMENDED
+ <<"publisher-affiliation">>, % RECOMMENDED
+ <<"publish-only-affiliation">>, % OPTIONAL
+ <<"retrieve-default">>,
+ <<"shim">>]. % RECOMMENDED
% see plugin "retrieve-items", % RECOMMENDED
% see plugin "retrieve-subscriptions", % RECOMMENDED
err_too_many_subscriptions() ->
#ps_error{type = 'too-many-subscriptions'}.
--spec err_unsupported(ps_error_feature()) -> ps_error().
+-spec err_unsupported(ps_feature()) -> ps_error().
err_unsupported(Feature) ->
#ps_error{type = 'unsupported', feature = Feature}.
-author('bjc@kublai.com').
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1,
case find_opt(node_type, Options) of
collection ->
Txt = <<"Publishing items to collection node is not allowed">>,
- {error,
- ?ERR_EXTENDED(?ERRT_NOT_ALLOWED(?MYLANG, Txt), <<"publish">>)};
+ {error, mod_pubsub:extended_error(
+ xmpp:err_not_allowed(Txt, ?MYLANG),
+ mod_pubsub:err_unsupported('publish'))};
_ ->
node_hometree:publish_item(Nidx, Publisher, Model,
MaxItems, ItemId, Payload, PubOpts)
-author('christophe.romain@process-one.net').
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1,
subscribe_node(_Nidx, _Sender, _Subscriber, _AccessModel, _SendLast, _PresenceSubscription,
_RosterGroup, _Options) ->
- {error, ?ERR_FORBIDDEN}.
+ {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(),
+ mod_pubsub:err_unsupported('subscribe'))}.
unsubscribe_node(_Nidx, _Sender, _Subscriber, _SubId) ->
- {error, ?ERR_FORBIDDEN}.
+ {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(),
+ mod_pubsub:err_unsupported('subscribe'))}.
publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload,
PubOpts) ->
{result, {ItemIds, []}}.
delete_item(_Nidx, _Publisher, _PublishModel, _ItemId) ->
- {error, ?ERR_ITEM_NOT_FOUND}.
+ {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(),
+ mod_pubsub:err_unsupported('delete-items'))}.
purge_node(_Nidx, _Owner) ->
- {error, ?ERR_FORBIDDEN}.
+ {error, mod_pubsub:extended_error(xmpp:err_feature_not_implemented(),
+ mod_pubsub:err_unsupported('purge-nodes'))}.
get_entity_affiliations(_Host, _Owner) ->
{result, []}.
-author('christophe.romain@process-one.net').
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-export([init/3, terminate/2, options/0, features/0,
create_node_permission/6, create_node/2, delete_node/1,
<<"retrieve-items">>,
<<"retrieve-subscriptions">>,
<<"subscribe">>,
+ %%<<"subscription-options">>,
<<"subscription-notifications">>].
-%%<<"subscription-options">>
%% @doc Checks if the current user has the permission to create the requested node
%% <p>In flat node, any unused node name is allowed. The access parameter is also
Owner = Affiliation == owner,
if not Authorized ->
{error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"invalid-jid">>)};
+ mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_invalid_jid())};
(Affiliation == outcast) or (Affiliation == publish_only) ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
PendingSubscription ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"pending-subscription">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_pending_subscription())};
(AccessModel == presence) and (not PresenceSubscription) and (not Owner) ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_presence_subscription_required())};
(AccessModel == roster) and (not RosterGroup) and (not Owner) ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_not_in_roster_group())};
(AccessModel == whitelist) and (not Whitelisted) and (not Owner) ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
+ mod_pubsub:extended_error((xmpp:err_not_allowed()), mod_pubsub:err_closed_node())};
%%MustPay ->
%% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED};
%%ForbiddenAnonymous ->
%% % Requesting entity is anonymous
- %% {error, ?ERR_FORBIDDEN};
+ %% {error, xmpp:err_forbidden()};
true ->
%%SubId = pubsub_subscription:add_subscription(Subscriber, Nidx, Options),
{NewSub, SubId} = case Subscriptions of
if
%% Requesting entity is prohibited from unsubscribing entity
not Authorized ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
%% Entity did not specify SubId
%%SubId == "", ?? ->
- %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
+ %% {error, mod_pubsub:extended_error(xmpp:err_bad_request(), "subid-required")};
%% Invalid subscription identifier
%%InvalidSubId ->
- %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
+ %% {error, mod_pubsub:extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
%% Requesting entity is not a subscriber
Subscriptions == [] ->
{error,
- ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)};
+ mod_pubsub:extended_error(xmpp:err_unexpected_request(), mod_pubsub:err_not_subscribed())};
%% Subid supplied, so use that.
SubIdExists ->
Sub = first_in_list(fun
{result, default};
false ->
{error,
- ?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)}
+ mod_pubsub:extended_error(xmpp:err_unexpected_request(), mod_pubsub:err_not_subscribed())}
end;
%% Asking to remove all subscriptions to the given node
SubId == all ->
%% No subid and more than one possible subscription match.
true ->
{error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)}
+ mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_subid_required())}
end.
delete_subscriptions(SubKey, Nidx, Subscriptions, SubState) ->
or (Affiliation == publisher)
or (Affiliation == publish_only))
or (Subscribed == true)) ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
true ->
if MaxItems > 0 ->
Now = p1_time_compat:timestamp(),
_ -> false
end,
if not Allowed ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
true ->
case lists:member(ItemId, Items) of
true ->
(_, Res) ->
Res
end,
- {error, ?ERR_ITEM_NOT_FOUND}, States);
+ {error, xmpp:err_item_not_found()}, States);
_ ->
- {error, ?ERR_ITEM_NOT_FOUND}
+ {error, xmpp:err_item_not_found()}
end
end
end.
States),
{result, {default, broadcast}};
_ ->
- {error, ?ERR_FORBIDDEN}
+ {error, xmpp:err_forbidden()}
end.
%% @doc <p>Return the current affiliations for the given user</p>
case Subscription of
none ->
{error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"not-subscribed">>)};
+ mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_not_subscribed())};
_ ->
new_subscription(Nidx, Owner, Subscription, SubState)
end;
end;
{<<>>, [_ | _]} ->
{error,
- ?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)};
+ mod_pubsub:extended_error((xmpp:err_bad_request()), mod_pubsub:err_subid_required())};
_ ->
case Subscription of
none -> unsub_with_subid(Nidx, SubId, SubState);
can_fetch_item(Affiliation, FullSubscriptions),
if %%SubId == "", ?? ->
%% Entity has multiple subscriptions to the node but does not specify a subscription ID
- %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
+ %{error, mod_pubsub:extended_error(xmpp:err_bad_request(), "subid-required")};
%%InvalidSubId ->
%% Entity is subscribed but specifies an invalid subscription ID
- %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
+ %{error, mod_pubsub:extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
(Affiliation == outcast) or (Affiliation == publish_only) ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
(AccessModel == presence) and not PresenceSubscription ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_presence_subscription_required())};
(AccessModel == roster) and not RosterGroup ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_not_in_roster_group())};
(AccessModel == whitelist) and not Whitelisted ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
+ mod_pubsub:extended_error((xmpp:err_not_allowed()), mod_pubsub:err_closed_node())};
(AccessModel == authorize) and not Whitelisted ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
%%MustPay ->
%% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED};
get_item(Nidx, ItemId) ->
case mnesia:read({pubsub_item, {ItemId, Nidx}}) of
[Item] when is_record(Item, pubsub_item) -> {result, Item};
- _ -> {error, ?ERR_ITEM_NOT_FOUND}
+ _ -> {error, xmpp:err_item_not_found()}
end.
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
Whitelisted = can_fetch_item(Affiliation, Subscriptions),
if %%SubId == "", ?? ->
%% Entity has multiple subscriptions to the node but does not specify a subscription ID
- %{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
+ %{error, mod_pubsub:extended_error(xmpp:err_bad_request(), "subid-required")};
%%InvalidSubId ->
%% Entity is subscribed but specifies an invalid subscription ID
- %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
+ %{error, mod_pubsub:extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
(Affiliation == outcast) or (Affiliation == publish_only) ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
(AccessModel == presence) and not PresenceSubscription ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_presence_subscription_required())};
(AccessModel == roster) and not RosterGroup ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)};
+ mod_pubsub:extended_error((xmpp:err_not_authorized()), mod_pubsub:err_not_in_roster_group())};
(AccessModel == whitelist) and not Whitelisted ->
{error,
- ?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)};
+ mod_pubsub:extended_error((xmpp:err_not_allowed()), mod_pubsub:err_closed_node())};
(AccessModel == authorize) and not Whitelisted ->
- {error, ?ERR_FORBIDDEN};
+ {error, xmpp:err_forbidden()};
%%MustPay ->
%% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED};
"where exists ( select count(*) as count1 "
"from pubsub_item where nodeid='">>, SNidx,
<<"' and modification > pi.modification having count1 = ">>,
- IncIndex, <<" );">>]) of
+ integer_to_binary(IncIndex), <<" );">>]) of
{selected, [_], [[O]]} ->
[<<"modification">>, <<"'", O/binary, "'">>];
_ ->
end,
Query = fun(mssql, _) ->
ejabberd_sql:sql_query_t(
- [<<"select top ">>, Max,
+ [<<"select top ">>, integer_to_binary(Max),
<<" itemid, publisher, creation, modification, payload "
"from pubsub_item where nodeid='">>, SNidx,
<<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>,
[<<"select itemid, publisher, creation, modification, payload "
"from pubsub_item where nodeid='">>, SNidx,
<<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>,
- AttrName, <<" ">>, Order, <<" limit ">>, Max, <<" ;">>])
+ AttrName, <<" ">>, Order, <<" limit ">>,
+ integer_to_binary(Max), <<" ;">>])
end,
case ejabberd_sql:sql_query_t(Query) of
{selected, [<<"itemid">>, <<"publisher">>, <<"creation">>,
-include_lib("stdlib/include/qlc.hrl").
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-export([init/3, terminate/2, options/0, set_node/1,
get_node/3, get_node/2, get_node/1, get_nodes/2,
Other -> Other
end;
_ ->
- {error, ?ERRT_CONFLICT(?MYLANG, <<"Node already exists">>)}
+ {error, xmpp:err_conflict(<<"Node already exists">>, ?MYLANG)}
end.
delete_node(Key, Node) ->
case find_node(Key, Node) of
false ->
- {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)};
+ {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)};
Record ->
lists:foreach(fun (#pubsub_node{options = Opts} = Child) ->
NewOpts = remove_config_parent(Node, Opts),
get_node(Host, Node) ->
case find_node(Host, Node) of
- false -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)};
+ false -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)};
Record -> Record
end.
get_parentnodes(Host, Node, _From) ->
case find_node(Host, Node) of
false ->
- {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)};
+ {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)};
#pubsub_node{parents = Parents} ->
Q = qlc:q([N
|| #pubsub_node{nodeid = {NHost, NNode}} = N
get_subnodes_helper(Host, <<>>);
get_subnodes(Host, Node) ->
case find_node(Host, Node) of
- false -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)};
+ false -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)};
_ -> get_subnodes_helper(Host, Node)
end.
validate_parentage(Key, Owners, [ParentID | T]) ->
case find_node(Key, ParentID) of
false ->
- {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)};
+ {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)};
#pubsub_node{owners = POwners, options = POptions} ->
NodeType = find_opt(node_type, ?DEFAULT_NODETYPE, POptions),
MutualOwners = [O || O <- Owners, PO <- POwners, O == PO],
case {MutualOwners, NodeType} of
- {[], _} -> {error, ?ERR_FORBIDDEN};
+ {[], _} -> {error, xmpp:err_forbidden()};
{_, collection} -> validate_parentage(Key, Owners, T);
- {_, _} -> {error, ?ERR_NOT_ALLOWED}
+ {_, _} -> {error, xmpp:err_not_allowed()}
end
end.
-include_lib("stdlib/include/qlc.hrl").
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-export([init/3, terminate/2, options/0, set_node/1,
get_node/3, get_node/2, get_node/1, get_nodes/2,
get_node(Host, Node) ->
case mnesia:read({pubsub_node, {Host, Node}}) of
[Record] when is_record(Record, pubsub_node) -> Record;
- _ -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}
+ _ -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}
end.
get_node(Nidx) ->
case mnesia:index_read(pubsub_node, Nidx, #pubsub_node.id) of
[Record] when is_record(Record, pubsub_node) -> Record;
- _ -> {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}
+ _ -> {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}
end.
get_nodes(Host, _From) ->
options = Options}),
{ok, Nidx};
false ->
- {error, ?ERR_FORBIDDEN}
+ {error, xmpp:err_forbidden()}
end;
_ ->
- {error, ?ERRT_CONFLICT(?MYLANG, <<"Node already exists">>)}
+ {error, xmpp:err_conflict(<<"Node already exists">>, ?MYLANG)}
end.
delete_node(Host, Node) ->
-compile([{parse_transform, ejabberd_sql_pt}]).
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-include("ejabberd_sql_pt.hrl").
-export([init/3, terminate/2, options/0, set_node/1,
case Nidx of
none ->
Txt = <<"Node index not found">>,
- {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, Txt)};
+ {error, xmpp:err_internal_server_error(Txt, ?MYLANG)};
_ ->
lists:foreach(fun ({Key, Value}) ->
SKey = iolist_to_binary(atom_to_list(Key)),
{selected, [RItem]} ->
raw_to_node(Host, RItem);
{'EXIT', _Reason} ->
- {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)};
+ {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)};
_ ->
- {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}
+ {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}
end.
get_node(Nidx) ->
{selected, [{Host, Node, Parent, Type}]} ->
raw_to_node(Host, {Node, Parent, Type, Nidx});
{'EXIT', _Reason} ->
- {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)};
+ {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)};
_ ->
- {error, ?ERRT_ITEM_NOT_FOUND(?MYLANG, <<"Node not found">>)}
+ {error, xmpp:err_item_not_found(<<"Node not found">>, ?MYLANG)}
end.
get_nodes(Host, _From) ->
Other -> Other
end;
false ->
- {error, ?ERR_FORBIDDEN}
+ {error, xmpp:err_forbidden()}
end;
{result, _} ->
- {error, ?ERRT_CONFLICT(?MYLANG, <<"Node already exists">>)};
+ {error, xmpp:err_conflict(<<"Node already exists">>, ?MYLANG)};
{error, db_fail} ->
- {error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)}
+ {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}
end.
delete_node(Host, Node) ->
Opts),
ok.
-subscription_opt_from_sql({<<"DELIVER">>, Value}) ->
+subscription_opt_from_sql([<<"DELIVER">>, Value]) ->
{deliver, sql_to_boolean(Value)};
-subscription_opt_from_sql({<<"DIGEST">>, Value}) ->
+subscription_opt_from_sql([<<"DIGEST">>, Value]) ->
{digest, sql_to_boolean(Value)};
-subscription_opt_from_sql({<<"DIGEST_FREQUENCY">>, Value}) ->
+subscription_opt_from_sql([<<"DIGEST_FREQUENCY">>, Value]) ->
{digest_frequency, sql_to_integer(Value)};
-subscription_opt_from_sql({<<"EXPIRE">>, Value}) ->
+subscription_opt_from_sql([<<"EXPIRE">>, Value]) ->
{expire, sql_to_timestamp(Value)};
-subscription_opt_from_sql({<<"INCLUDE_BODY">>, Value}) ->
+subscription_opt_from_sql([<<"INCLUDE_BODY">>, Value]) ->
{include_body, sql_to_boolean(Value)};
%%TODO: might be > than 1 show_values value??.
%% need to use compact all in only 1 opt.
-subscription_opt_from_sql({<<"SHOW_VALUES">>, Value}) ->
+subscription_opt_from_sql([<<"SHOW_VALUES">>, Value]) ->
{show_values, Value};
-subscription_opt_from_sql({<<"SUBSCRIPTION_TYPE">>, Value}) ->
+subscription_opt_from_sql([<<"SUBSCRIPTION_TYPE">>, Value]) ->
{subscription_type,
case Value of
<<"items">> -> items;
<<"nodes">> -> nodes
end};
-subscription_opt_from_sql({<<"SUBSCRIPTION_DEPTH">>, Value}) ->
+subscription_opt_from_sql([<<"SUBSCRIPTION_DEPTH">>, Value]) ->
{subscription_depth,
case Value of
<<"all">> -> all;
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
-define(PUBSUB_DIGEST, <<"pubsub#digest">>).
Keys = [deliver, show_values, subscription_type, subscription_depth],
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
{result,
- #xmlel{name = <<"x">>,
- attrs = [{<<"xmlns">>, ?NS_XDATA}],
- children =
- [#xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"FORM_TYPE">>},
- {<<"type">>, <<"hidden">>}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children =
- [{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
- ++ XFields}}.
+ #xdata{type = form,
+ fields = [#xdata_field{type = hidden,
+ var = <<"FORM_TYPE">>,
+ values = [?NS_PUBSUB_SUB_OPTIONS]}|
+ XFields]}}.
parse_options_xform(XFields) ->
- case fxml:remove_cdata(XFields) of
- [#xmlel{name = <<"x">>} = XEl] ->
- case jlib:parse_xdata_submit(XEl) of
- XData when is_list(XData) ->
- Opts = set_xoption(XData, []),
- {result, Opts};
- Other -> Other
- end;
- _ -> {result, []}
- end.
+ Opts = set_xoption(XFields, []),
+ {result, Opts}.
%%====================================================================
%% Internal functions
_ ->
Txt = <<"Value of '~s' should be integer">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
- {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
+ end;
+val_xfield(expire = Opt, [Val]) ->
+ case jlib:datetime_string_to_timestamp(Val) of
+ undefined ->
+ Txt = <<"Value of '~s' should be datetime string">>,
+ ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)};
+ Timestamp ->
+ Timestamp
end;
-val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val);
val_xfield(show_values, Vals) -> Vals;
val_xfield(subscription_type, [<<"items">>]) -> items;
_ ->
Txt = <<"Value of '~s' should be integer">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
- {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
end.
%% Convert XForm booleans to Erlang booleans.
xopt_to_bool(Option, _) ->
Txt = <<"Value of '~s' should be boolean">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Option])),
- {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}.
-
--spec get_option_xfield(Lang :: binary(), Key :: atom(),
- Options :: mod_pubsub:subOptions()) -> xmlel().
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}.
%% Return a field for an XForm for Key, with data filled in, if
%% applicable, from Options.
{Type, OptEls} = type_and_options(xfield_type(Key), Lang),
Vals = case lists:keysearch(Key, 1, Options) of
{value, {_, Val}} ->
- [tr_xfield_values(Vals)
- || Vals <- xfield_val(Key, Val)];
- false -> []
+ [xfield_val(Key, Val)];
+ false ->
+ []
end,
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, Var}, {<<"type">>, Type},
- {<<"label">>, translate:translate(Lang, Label)}],
- children = OptEls ++ Vals}.
+ #xdata_field{type = Type, var = Var,
+ label = translate:translate(Lang, Label),
+ values = Vals,
+ options = OptEls}.
type_and_options({Type, Options}, Lang) ->
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
type_and_options(Type, _Lang) -> {Type, []}.
tr_xfield_options({Value, Label}, Lang) ->
- #xmlel{name = <<"option">>,
- attrs =
- [{<<"label">>, translate:translate(Lang, Label)}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Value}]}]}.
-
-tr_xfield_values(Value) ->
- %% Return the XForm variable name for a subscription option key.
- %% Return the XForm variable type for a subscription option key.
- #xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Value}]}.
+ #xdata_option{label = translate:translate(Lang, Label),
+ value = Value}.
xfield_var(deliver) -> ?PUBSUB_DELIVER;
%xfield_var(digest) -> ?PUBSUB_DIGEST;
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
-xfield_type(deliver) -> <<"boolean">>;
-%xfield_type(digest) -> <<"boolean">>;
-%xfield_type(digest_frequency) -> <<"text-single">>;
-%xfield_type(expire) -> <<"text-single">>;
-%xfield_type(include_body) -> <<"boolean">>;
+xfield_type(deliver) -> boolean;
+%xfield_type(digest) -> boolean;
+%xfield_type(digest_frequency) -> 'text-single';
+%xfield_type(expire) -> 'text-single';
+%xfield_type(include_body) -> boolean;
xfield_type(show_values) ->
- {<<"list-multi">>,
+ {'list-multi',
[{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
{<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
{<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
{<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
{<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
xfield_type(subscription_type) ->
- {<<"list-single">>,
+ {'list-single',
[{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
{<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
xfield_type(subscription_depth) ->
- {<<"list-single">>,
+ {'list-single',
[{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
{<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
-include("pubsub.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-define(PUBSUB_DELIVER, <<"pubsub#deliver">>).
-define(PUBSUB_DIGEST, <<"pubsub#digest">>).
Keys = [deliver, show_values, subscription_type, subscription_depth],
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
{result,
- #xmlel{name = <<"x">>,
- attrs = [{<<"xmlns">>, ?NS_XDATA}],
- children =
- [#xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"FORM_TYPE">>},
- {<<"type">>, <<"hidden">>}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children =
- [{xmlcdata, ?NS_PUBSUB_SUB_OPTIONS}]}]}]
- ++ XFields}}.
+ #xdata{type = form,
+ fields = [#xdata_field{type = hidden,
+ var = <<"FORM_TYPE">>,
+ values = [?NS_PUBSUB_SUB_OPTIONS]}|
+ XFields]}}.
parse_options_xform(XFields) ->
- case fxml:remove_cdata(XFields) of
- [#xmlel{name = <<"x">>} = XEl] ->
- case jlib:parse_xdata_submit(XEl) of
- XData when is_list(XData) ->
- Opts = set_xoption(XData, []),
- {result, Opts};
- Other -> Other
- end;
- _ -> {result, []}
- end.
+ Opts = set_xoption(XFields, []),
+ {result, Opts}.
%%====================================================================
%% Internal functions
_ ->
Txt = <<"Value of '~s' should be integer">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
- {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
+ end;
+val_xfield(expire = Opt, [Val]) ->
+ case jlib:datetime_string_to_timestamp(Val) of
+ undefined ->
+ Txt = <<"Value of '~s' should be datetime string">>,
+ ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)};
+ Timestamp ->
+ Timestamp
end;
-val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val);
val_xfield(show_values, Vals) -> Vals;
val_xfield(subscription_type, [<<"items">>]) -> items;
_ ->
Txt = <<"Value of '~s' should be integer">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
- {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
end.
%% Convert XForm booleans to Erlang booleans.
xopt_to_bool(Option, _) ->
Txt = <<"Value of '~s' should be boolean">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Option])),
- {error, ?ERRT_NOT_ACCEPTABLE(?MYLANG, ErrTxt)}.
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}.
%% Return a field for an XForm for Key, with data filled in, if
%% applicable, from Options.
Label = xfield_label(Key),
{Type, OptEls} = type_and_options(xfield_type(Key), Lang),
Vals = case lists:keysearch(Key, 1, Options) of
- {value, {_, Val}} ->
- [tr_xfield_values(Vals)
- || Vals <- xfield_val(Key, Val)];
- false -> []
- end,
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, Var}, {<<"type">>, Type},
- {<<"label">>, translate:translate(Lang, Label)}],
- children = OptEls ++ Vals}.
+ {value, {_, Val}} ->
+ [xfield_val(Key, Val)];
+ false ->
+ []
+ end,
+ #xdata_field{type = Type, var = Var,
+ label = translate:translate(Lang, Label),
+ values = Vals,
+ options = OptEls}.
type_and_options({Type, Options}, Lang) ->
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
type_and_options(Type, _Lang) -> {Type, []}.
tr_xfield_options({Value, Label}, Lang) ->
- #xmlel{name = <<"option">>,
- attrs =
- [{<<"label">>, translate:translate(Lang, Label)}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Value}]}]}.
-
-tr_xfield_values(Value) ->
- %% Return the XForm variable name for a subscription option key.
- %% Return the XForm variable type for a subscription option key.
- #xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Value}]}.
+ #xdata_option{label = translate:translate(Lang, Label),
+ value = Value}.
xfield_var(deliver) -> ?PUBSUB_DELIVER;
%xfield_var(digest) -> ?PUBSUB_DIGEST;
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
-xfield_type(deliver) -> <<"boolean">>;
-%xfield_type(digest) -> <<"boolean">>;
-%xfield_type(digest_frequency) -> <<"text-single">>;
-%xfield_type(expire) -> <<"text-single">>;
-%xfield_type(include_body) -> <<"boolean">>;
+xfield_type(deliver) -> boolean;
+%xfield_type(digest) -> boolean;
+%xfield_type(digest_frequency) -> 'text-single';
+%xfield_type(expire) -> 'text-single';
+%xfield_type(include_body) -> boolean;
xfield_type(show_values) ->
- {<<"list-multi">>,
- [{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
- {<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
- {<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
- {<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
- {<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
+ {'list-multi',
+ [{<<"away">>, ?SHOW_VALUE_AWAY_LABEL},
+ {<<"chat">>, ?SHOW_VALUE_CHAT_LABEL},
+ {<<"dnd">>, ?SHOW_VALUE_DND_LABEL},
+ {<<"online">>, ?SHOW_VALUE_ONLINE_LABEL},
+ {<<"xa">>, ?SHOW_VALUE_XA_LABEL}]};
xfield_type(subscription_type) ->
- {<<"list-single">>,
- [{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
- {<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
+ {'list-single',
+ [{<<"items">>, ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
+ {<<"nodes">>, ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
xfield_type(subscription_depth) ->
- {<<"list-single">>,
- [{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
- {<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
+ {'list-single',
+ [{<<"1">>, ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
+ {<<"all">>, ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
%% Return the XForm variable label for a subscription option key.
xfield_label(deliver) -> ?DELIVER_LABEL;
'presence-subscription-required' | 'subid-required' |
'too-many-subscriptions' | 'unsupported' |
'unsupported-access-model'.
--type ps_error_feature() :: 'access-authorize' | 'access-open' |
- 'access-presence' | 'access-roster' |
- 'access-whitelist' | 'auto-create' |
- 'auto-subscribe' | 'collections' | 'config-node' |
- 'create-and-configure' | 'create-nodes' |
- 'delete-items' | 'delete-nodes' |
- 'filtered-notifications' | 'get-pending' |
- 'instant-nodes' | 'item-ids' | 'last-published' |
- 'leased-subscription' | 'manage-subscriptions' |
- 'member-affiliation' | 'meta-data' |
- 'modify-affiliations' | 'multi-collection' |
- 'multi-subscribe' | 'outcast-affiliation' |
- 'persistent-items' | 'presence-notifications' |
- 'presence-subscribe' | 'publish' |
- 'publish-options' | 'publish-only-affiliation' |
- 'publisher-affiliation' | 'purge-nodes' |
- 'retract-items' | 'retrieve-affiliations' |
- 'retrieve-default' | 'retrieve-items' |
- 'retrieve-subscriptions' | 'subscribe' |
- 'subscription-options' | 'subscription-notifications'.
--record(ps_error, {type :: ps_error_type(), feature :: ps_error_feature()}).
+-type ps_feature() :: 'access-authorize' | 'access-open' |
+ 'access-presence' | 'access-roster' |
+ 'access-whitelist' | 'auto-create' |
+ 'auto-subscribe' | 'collections' | 'config-node' |
+ 'create-and-configure' | 'create-nodes' |
+ 'delete-items' | 'delete-nodes' |
+ 'filtered-notifications' | 'get-pending' |
+ 'instant-nodes' | 'item-ids' | 'last-published' |
+ 'leased-subscription' | 'manage-subscriptions' |
+ 'member-affiliation' | 'meta-data' |
+ 'modify-affiliations' | 'multi-collection' |
+ 'multi-subscribe' | 'outcast-affiliation' |
+ 'persistent-items' | 'presence-notifications' |
+ 'presence-subscribe' | 'publish' |
+ 'publish-options' | 'publish-only-affiliation' |
+ 'publisher-affiliation' | 'purge-nodes' |
+ 'retract-items' | 'retrieve-affiliations' |
+ 'retrieve-default' | 'retrieve-items' |
+ 'retrieve-subscriptions' | 'subscribe' |
+ 'subscription-options' | 'subscription-notifications'.
+-record(ps_error, {type :: ps_error_type(), feature :: ps_feature()}).
-type ps_error() :: #ps_error{}.
-xml(pubsub_error_closed_node,