Rewrite mod_pubsub to use XML codec

This commit is contained in:
Evgeniy Khramtsov 2016-08-30 09:48:08 +03:00
parent 31faa4eb9a
commit 45eb49125b
10 changed files with 5450 additions and 2995 deletions

View File

@ -5,6 +5,47 @@
hash :: binary()}). hash :: binary()}).
-type vcard_xupdate() :: #vcard_xupdate{}. -type vcard_xupdate() :: #vcard_xupdate{}.
-record(ps_affiliation, {xmlns = <<>> :: binary(),
node = <<>> :: binary(),
type :: member | none | outcast |
owner | publisher | 'publish-only',
jid :: jid:jid()}).
-type ps_affiliation() :: #ps_affiliation{}.
-type ps_error_type() :: 'closed-node' | 'configuration-required' |
'invalid-jid' | 'invalid-options' |
'invalid-payload' | 'invalid-subid' |
'item-forbidden' | 'item-required' | 'jid-required' |
'max-items-exceeded' | 'max-nodes-exceeded' |
'nodeid-required' | 'not-in-roster-group' |
'not-subscribed' | 'payload-too-big' |
'payload-required' | 'pending-subscription' |
'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_error() :: #ps_error{}.
-record(chatstate, {type :: active | composing | gone | inactive | paused}). -record(chatstate, {type :: active | composing | gone | inactive | paused}).
-type chatstate() :: #chatstate{}. -type chatstate() :: #chatstate{}.
@ -77,10 +118,10 @@
-record(muc_unsubscribe, {}). -record(muc_unsubscribe, {}).
-type muc_unsubscribe() :: #muc_unsubscribe{}. -type muc_unsubscribe() :: #muc_unsubscribe{}.
-record(pubsub_unsubscribe, {node = <<>> :: binary(), -record(ps_unsubscribe, {node = <<>> :: binary(),
jid :: jid:jid(), jid :: jid:jid(),
subid = <<>> :: binary()}). subid = <<>> :: binary()}).
-type pubsub_unsubscribe() :: #pubsub_unsubscribe{}. -type ps_unsubscribe() :: #ps_unsubscribe{}.
-record(mix_leave, {}). -record(mix_leave, {}).
-type mix_leave() :: #mix_leave{}. -type mix_leave() :: #mix_leave{}.
@ -105,10 +146,6 @@
height :: non_neg_integer()}). height :: non_neg_integer()}).
-type thumbnail() :: #thumbnail{}. -type thumbnail() :: #thumbnail{}.
-record(pubsub_affiliation, {node = <<>> :: binary(),
type :: 'member' | 'none' | 'outcast' | 'owner' | 'publish-only' | 'publisher'}).
-type pubsub_affiliation() :: #pubsub_affiliation{}.
-record(muc_decline, {reason = <<>> :: binary(), -record(muc_decline, {reason = <<>> :: binary(),
from :: jid:jid(), from :: jid:jid(),
to :: jid:jid()}). to :: jid:jid()}).
@ -195,13 +232,16 @@
-record(feature_sm, {xmlns = <<>> :: binary()}). -record(feature_sm, {xmlns = <<>> :: binary()}).
-type feature_sm() :: #feature_sm{}. -type feature_sm() :: #feature_sm{}.
-record(pubsub_item, {id = <<>> :: binary(), -record(ps_item, {xmlns = <<>> :: binary(),
xml_els = [] :: [fxml:xmlel()]}). id = <<>> :: binary(),
-type pubsub_item() :: #pubsub_item{}. xml_els = [] :: [fxml:xmlel()],
node = <<>> :: binary(),
publisher = <<>> :: binary()}).
-type ps_item() :: #ps_item{}.
-record(pubsub_publish, {node = <<>> :: binary(), -record(ps_publish, {node = <<>> :: binary(),
items = [] :: [#pubsub_item{}]}). items = [] :: [#ps_item{}]}).
-type pubsub_publish() :: #pubsub_publish{}. -type ps_publish() :: #ps_publish{}.
-record(roster_item, {jid :: jid:jid(), -record(roster_item, {jid :: jid:jid(),
name = <<>> :: binary(), name = <<>> :: binary(),
@ -214,12 +254,6 @@
ver :: binary()}). ver :: binary()}).
-type roster_query() :: #roster_query{}. -type roster_query() :: #roster_query{}.
-record(pubsub_event_item, {id = <<>> :: binary(),
node = <<>> :: binary(),
publisher = <<>> :: binary(),
xml_els = [] :: [fxml:xmlel()]}).
-type pubsub_event_item() :: #pubsub_event_item{}.
-record(sm_r, {xmlns = <<>> :: binary()}). -record(sm_r, {xmlns = <<>> :: binary()}).
-type sm_r() :: #sm_r{}. -type sm_r() :: #sm_r{}.
@ -263,14 +297,6 @@
xmlns = <<>> :: binary()}). xmlns = <<>> :: binary()}).
-type sm_enabled() :: #sm_enabled{}. -type sm_enabled() :: #sm_enabled{}.
-record(pubsub_event_items, {node = <<>> :: binary(),
retract = [] :: [binary()],
items = [] :: [#pubsub_event_item{}]}).
-type pubsub_event_items() :: #pubsub_event_items{}.
-record(pubsub_event, {items = [] :: [#pubsub_event_items{}]}).
-type pubsub_event() :: #pubsub_event{}.
-record(muc_unique, {name = <<>> :: binary()}). -record(muc_unique, {name = <<>> :: binary()}).
-type muc_unique() :: #muc_unique{}. -type muc_unique() :: #muc_unique{}.
@ -283,9 +309,9 @@
resource :: binary()}). resource :: binary()}).
-type legacy_auth() :: #legacy_auth{}. -type legacy_auth() :: #legacy_auth{}.
-record(pubsub_subscribe, {node = <<>> :: binary(), -record(ps_subscribe, {node = <<>> :: binary(),
jid :: jid:jid()}). jid :: jid:jid()}).
-type pubsub_subscribe() :: #pubsub_subscribe{}. -type ps_subscribe() :: #ps_subscribe{}.
-record(message, {id = <<>> :: binary(), -record(message, {id = <<>> :: binary(),
type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal', type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
@ -325,11 +351,13 @@
-record(muc_subscriptions, {list = [] :: [jid:jid()]}). -record(muc_subscriptions, {list = [] :: [jid:jid()]}).
-type muc_subscriptions() :: #muc_subscriptions{}. -type muc_subscriptions() :: #muc_subscriptions{}.
-record(pubsub_subscription, {jid :: jid:jid(), -record(ps_subscription, {xmlns = <<>> :: binary(),
jid :: jid:jid(),
type :: 'none' | 'pending' | 'subscribed' | 'unconfigured',
node = <<>> :: binary(), node = <<>> :: binary(),
subid = <<>> :: binary(), subid = <<>> :: binary(),
type :: 'none' | 'pending' | 'subscribed' | 'unconfigured'}). expiry :: erlang:timestamp()}).
-type pubsub_subscription() :: #pubsub_subscription{}. -type ps_subscription() :: #ps_subscription{}.
-record(bob_data, {cid = <<>> :: binary(), -record(bob_data, {cid = <<>> :: binary(),
'max-age' :: non_neg_integer(), 'max-age' :: non_neg_integer(),
@ -375,11 +403,13 @@
node = <<>> :: binary()}). node = <<>> :: binary()}).
-type stats() :: #stats{}. -type stats() :: #stats{}.
-record(pubsub_items, {node = <<>> :: binary(), -record(ps_items, {xmlns = <<>> :: binary(),
node = <<>> :: binary(),
items = [] :: [#ps_item{}],
max_items :: non_neg_integer(), max_items :: non_neg_integer(),
subid = <<>> :: binary(), subid = <<>> :: binary(),
items = [] :: [#pubsub_item{}]}). retract :: binary()}).
-type pubsub_items() :: #pubsub_items{}. -type ps_items() :: #ps_items{}.
-record(presence, {id = <<>> :: binary(), -record(presence, {id = <<>> :: binary(),
type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed', type = available :: 'available' | 'error' | 'probe' | 'subscribe' | 'subscribed' | 'unavailable' | 'unsubscribe' | 'unsubscribed',
@ -438,10 +468,10 @@
-record(carbons_received, {forwarded :: #forwarded{}}). -record(carbons_received, {forwarded :: #forwarded{}}).
-type carbons_received() :: #carbons_received{}. -type carbons_received() :: #carbons_received{}.
-record(pubsub_retract, {node = <<>> :: binary(), -record(ps_retract, {node = <<>> :: binary(),
notify = false :: boolean(), notify = false :: boolean(),
items = [] :: [#pubsub_item{}]}). items = [] :: [#ps_item{}]}).
-type pubsub_retract() :: #pubsub_retract{}. -type ps_retract() :: #ps_retract{}.
-record(upload_slot, {get :: binary(), -record(upload_slot, {get :: binary(),
put :: binary(), put :: binary(),
@ -707,22 +737,46 @@
xdata :: #xdata{}}). xdata :: #xdata{}}).
-type mam_query() :: #mam_query{}. -type mam_query() :: #mam_query{}.
-record(pubsub_options, {node = <<>> :: binary(), -record(pubsub_owner, {affiliations :: {binary(),[#ps_affiliation{}]},
configure :: {binary(),'undefined' | #xdata{}},
default :: {binary(),'undefined' | #xdata{}},
delete :: {binary(),binary()},
purge :: binary(),
subscriptions :: {binary(),[#ps_subscription{}]}}).
-type pubsub_owner() :: #pubsub_owner{}.
-record(ps_options, {node = <<>> :: binary(),
jid :: jid:jid(), jid :: jid:jid(),
subid = <<>> :: binary(), subid = <<>> :: binary(),
xdata :: #xdata{}}). xdata :: #xdata{}}).
-type pubsub_options() :: #pubsub_options{}. -type ps_options() :: #ps_options{}.
-record(pubsub, {subscriptions :: {binary(),[#pubsub_subscription{}]}, -record(pubsub, {subscriptions :: {binary(),[#ps_subscription{}]},
affiliations :: [#pubsub_affiliation{}], subscription :: #ps_subscription{},
publish :: #pubsub_publish{}, affiliations :: {binary(),[#ps_affiliation{}]},
subscribe :: #pubsub_subscribe{}, publish :: #ps_publish{},
unsubscribe :: #pubsub_unsubscribe{}, publish_options :: #xdata{},
options :: #pubsub_options{}, subscribe :: #ps_subscribe{},
items :: #pubsub_items{}, unsubscribe :: #ps_unsubscribe{},
retract :: #pubsub_retract{}}). options :: #ps_options{},
items :: #ps_items{},
retract :: #ps_retract{},
create :: binary(),
configure :: {binary(),'undefined' | #xdata{}},
default :: {binary(),'undefined' | #xdata{}},
delete :: {binary(),binary()},
purge :: binary(),
rsm :: #rsm_set{}}).
-type pubsub() :: #pubsub{}. -type pubsub() :: #pubsub{}.
-record(ps_event, {items :: #ps_items{},
purge :: binary(),
subscription :: #ps_subscription{},
delete :: {binary(),binary()},
create :: binary(),
configuration :: {binary(),'undefined' | #xdata{}}}).
-type ps_event() :: #ps_event{}.
-record(register, {registered = false :: boolean(), -record(register, {registered = false :: boolean(),
remove = false :: boolean(), remove = false :: boolean(),
instructions :: binary(), instructions :: binary(),
@ -852,21 +906,27 @@
-type xmpp_element() :: muc_admin() | -type xmpp_element() :: muc_admin() |
compression() | compression() |
pubsub_subscription() | ps_subscription() |
xdata_option() | xdata_option() |
version() | version() |
pubsub_affiliation() | ps_affiliation() |
mam_fin() | mam_fin() |
sm_a() | sm_a() |
bob_data() | bob_data() |
media() | media() |
stanza_id() |
starttls_proceed() |
client_id() |
sm_resumed() |
forwarded() |
xevent() |
privacy_list() |
carbons_sent() | carbons_sent() |
mam_archived() | mam_archived() |
p1_rebind() | p1_rebind() |
sasl_abort() | sasl_abort() |
db_result() | db_result() |
carbons_received() | carbons_received() |
pubsub_retract() |
upload_slot() | upload_slot() |
mix_participant() | mix_participant() |
compressed() | compressed() |
@ -875,31 +935,20 @@
'see-other-host'() | 'see-other-host'() |
hint() | hint() |
stream_start() | stream_start() |
stanza_id() |
starttls_proceed() |
client_id() |
sm_resumed() |
forwarded() |
xevent() |
privacy_list() |
text() | text() |
vcard_org() | vcard_org() |
shim() | shim() |
search_item() | search_item() |
offline_item() | offline_item() |
feature_sm() | feature_sm() |
pubsub_item() |
roster_item() | roster_item() |
pubsub_event_item() |
muc_item() | muc_item() |
vcard_temp() | vcard_temp() |
address() | address() |
sasl_success() | sasl_success() |
addresses() | addresses() |
pubsub_event_items() |
muc_subscriptions() | muc_subscriptions() |
disco_items() | disco_items() |
pubsub_options() |
compress() | compress() |
bytestreams() | bytestreams() |
adhoc_actions() | adhoc_actions() |
@ -912,9 +961,16 @@
vcard_tel() | vcard_tel() |
vcard_geo() | vcard_geo() |
vcard_photo() | vcard_photo() |
pubsub_owner() |
pubsub() | pubsub() |
muc_owner() | muc_owner() |
muc_actor() | muc_actor() |
ps_error() |
starttls_failure() |
sasl_challenge() |
x_conference() |
private() |
sasl_failure() |
vcard_name() | vcard_name() |
adhoc_note() | adhoc_note() |
rosterver_feature() | rosterver_feature() |
@ -924,18 +980,15 @@
bookmark_conference() | bookmark_conference() |
offline() | offline() |
time() | time() |
ps_subscribe() |
sm_enable() | sm_enable() |
starttls_failure() |
sasl_challenge() |
handshake() | handshake() |
x_conference() |
private() |
compress_failure() | compress_failure() |
sasl_failure() |
bookmark_storage() | bookmark_storage() |
muc_decline() | muc_decline() |
legacy_auth() | legacy_auth() |
search() | search() |
ps_publish() |
nick() | nick() |
p1_ack() | p1_ack() |
block() | block() |
@ -946,11 +999,12 @@
xcaptcha() | xcaptcha() |
streamhost() | streamhost() |
bind() | bind() |
ps_retract() |
last() | last() |
redirect() | redirect() |
sm_enabled() | sm_enabled() |
pubsub_event() |
vcard_sound() | vcard_sound() |
ps_event() |
mam_result() | mam_result() |
rsm_first() | rsm_first() |
stat() | stat() |
@ -961,15 +1015,17 @@
ping() | ping() |
privacy_item() | privacy_item() |
disco_item() | disco_item() |
ps_item() |
mam_prefs() |
sasl_mechanisms() |
caps() | caps() |
muc() | muc() |
stream_features() | stream_features() |
stats() | stats() |
pubsub_items() | ps_items() |
sic() | sic() |
ps_options() |
starttls() | starttls() |
mam_prefs() |
sasl_mechanisms() |
media_uri() | media_uri() |
muc_destroy() | muc_destroy() |
vcard_key() | vcard_key() |
@ -990,23 +1046,21 @@
stream_error() | stream_error() |
muc_user() | muc_user() |
vcard_adr() | vcard_adr() |
gone() |
carbons_private() | carbons_private() |
mix_leave() | mix_leave() |
muc_subscribe() | muc_subscribe() |
muc_unique() | muc_unique() |
sasl_response() | sasl_response() |
pubsub_subscribe() |
message() | message() |
presence() | presence() |
gone() |
sm_resume() | sm_resume() |
carbons_enable() | carbons_enable() |
expire() | expire() |
muc_unsubscribe() | muc_unsubscribe() |
pubsub_unsubscribe() | ps_unsubscribe() |
chatstate() | chatstate() |
sasl_auth() | sasl_auth() |
p1_push() | p1_push() |
oob_x() | oob_x() |
pubsub_publish() |
unblock(). unblock().

View File

@ -25,7 +25,7 @@
-module(gen_pubsub_node). -module(gen_pubsub_node).
-include("jlib.hrl"). -include("xmpp.hrl").
-type(host() :: mod_pubsub:host()). -type(host() :: mod_pubsub:host()).
-type(nodeId() :: mod_pubsub:nodeId()). -type(nodeId() :: mod_pubsub:nodeId()).
@ -175,20 +175,13 @@
ok | ok |
{error, xmlel()}. {error, xmlel()}.
-callback get_items(NodeIdx :: nodeIdx(), -callback get_items(nodeIdx(), jid(), accessModel(),
JID :: jid(), boolean(), boolean(), binary(),
AccessModel :: accessModel(), undefined | rsm_set()) ->
Presence_Subscription :: boolean(), {result, {[pubsubItem()], undefined | rsm_set()}} | {error, error()}.
RosterGroup :: boolean(),
SubId :: subId(),
RSM :: none | rsm_in()) ->
{result, {[pubsubItem()], none | rsm_out()}} |
{error, xmlel()}.
-callback get_items(NodeIdx :: nodeIdx(), -callback get_items(nodeIdx(), jid(), undefined | rsm_set()) ->
From :: jid(), {result, {[pubsubItem()], undefined | rsm_set()}}.
RSM :: none | rsm_in()) ->
{result, {[pubsubItem()], none | rsm_out()}}.
-callback get_item(NodeIdx :: nodeIdx(), -callback get_item(NodeIdx :: nodeIdx(),
ItemId :: itemId(), ItemId :: itemId(),

View File

@ -406,13 +406,15 @@ feature_response(_IQResult, Host, From, Caps,
[_SubNode | SubNodes]) -> [_SubNode | SubNodes]) ->
feature_request(Host, From, Caps, SubNodes). feature_request(Host, From, Caps, SubNodes).
-spec caps_read_fun(binary(), {binary(), binary()}) -> function(). -spec caps_read_fun(binary(), {binary(), binary()})
-> fun(() -> {ok, [binary()] | non_neg_integer()} | error).
caps_read_fun(Host, Node) -> caps_read_fun(Host, Node) ->
LServer = jid:nameprep(Host), LServer = jid:nameprep(Host),
Mod = gen_mod:db_mod(LServer, ?MODULE), Mod = gen_mod:db_mod(LServer, ?MODULE),
fun() -> Mod:caps_read(LServer, Node) end. fun() -> Mod:caps_read(LServer, Node) end.
-spec caps_write_fun(binary(), {binary(), binary()}, [binary()]) -> function(). -spec caps_write_fun(binary(), {binary(), binary()},
[binary()] | non_neg_integer()) -> fun().
caps_write_fun(Host, Node, Features) -> caps_write_fun(Host, Node, Features) ->
LServer = jid:nameprep(Host), LServer = jid:nameprep(Host),
Mod = gen_mod:db_mod(LServer, ?MODULE), Mod = gen_mod:db_mod(LServer, ?MODULE),

View File

@ -287,8 +287,8 @@ get_pep_node(#message{from = #jid{luser = <<>>}}) ->
%% It's not PEP. %% It's not PEP.
undefined; undefined;
get_pep_node(#message{} = Msg) -> get_pep_node(#message{} = Msg) ->
case xmpp:get_subtag(Msg, #pubsub_event{}) of case xmpp:get_subtag(Msg, #ps_event{}) of
#pubsub_event{items = [#pubsub_event_items{node = Node}]} -> #ps_event{items = #ps_items{node = Node}} ->
Node; Node;
_ -> _ ->
undefined undefined

View File

@ -4377,12 +4377,12 @@ send_wrapped(From, To, Packet, Node, State) ->
wrap(From, To, Packet, Node) -> wrap(From, To, Packet, Node) ->
El = xmpp:encode(xmpp:set_from_to(Packet, From, To)), El = xmpp:encode(xmpp:set_from_to(Packet, From, To)),
#message{ #message{
sub_els = [#pubsub_event{ sub_els = [#ps_event{
items = [#pubsub_event_items{ items = #ps_items{
node = Node, node = Node,
items = [#pubsub_event_item{ items = [#ps_item{
id = randoms:get_string(), id = randoms:get_string(),
xml_els = [El]}]}]}]}. xml_els = [El]}]}}]}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Multicast %% Multicast

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@
-compile([{parse_transform, ejabberd_sql_pt}]). -compile([{parse_transform, ejabberd_sql_pt}]).
-include("pubsub.hrl"). -include("pubsub.hrl").
-include("jlib.hrl"). -include("xmpp.hrl").
-include("ejabberd_sql_pt.hrl"). -include("ejabberd_sql_pt.hrl").
-export([init/3, terminate/2, options/0, features/0, -export([init/3, terminate/2, options/0, features/0,
@ -81,22 +81,22 @@ create_node(Nidx, Owner) ->
J = encode_jid(OwnerKey), J = encode_jid(OwnerKey),
A = encode_affiliation(owner), A = encode_affiliation(owner),
S = encode_subscriptions([]), S = encode_subscriptions([]),
catch ejabberd_sql:sql_query_t( ejabberd_sql:sql_query_t(
?SQL("insert into pubsub_state(" ?SQL("insert into pubsub_state("
"nodeid, jid, affiliation, subscriptions) " "nodeid, jid, affiliation, subscriptions) "
"values (%(Nidx)d, %(J)s, %(A)s, %(S)s)")), "values (%(Nidx)d, %(J)s, %(A)s, %(S)s)")),
{result, {default, broadcast}}. {result, {default, broadcast}}.
delete_node(Nodes) -> delete_node(Nodes) ->
Reply = lists:map(fun (#pubsub_node{id = Nidx} = PubsubNode) -> Reply = lists:map(
Subscriptions = case catch fun(#pubsub_node{id = Nidx} = PubsubNode) ->
ejabberd_sql:sql_query_t( Subscriptions =
case ejabberd_sql:sql_query_t(
?SQL("select @(jid)s, @(subscriptions)s " ?SQL("select @(jid)s, @(subscriptions)s "
"from pubsub_state where nodeid=%(Nidx)d")) "from pubsub_state where nodeid=%(Nidx)d")) of
of
{selected, RItems} -> {selected, RItems} ->
[{decode_jid(SJID), decode_subscriptions(Subs)} || [{decode_jid(SJID), decode_subscriptions(Subs)}
{SJID, Subs} <- RItems]; || {SJID, Subs} <- RItems];
_ -> _ ->
[] []
end, end,
@ -118,22 +118,25 @@ subscribe_node(Nidx, Sender, Subscriber, AccessModel,
Subscriptions), Subscriptions),
Owner = Affiliation == owner, Owner = Affiliation == owner,
if not Authorized -> if not Authorized ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"invalid-jid">>)}; xmpp:err_bad_request(), mod_pubsub:err_invalid_jid())};
(Affiliation == outcast) or (Affiliation == publish_only) -> (Affiliation == outcast) or (Affiliation == publish_only) ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
PendingSubscription -> PendingSubscription ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"pending-subscription">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_pending_subscription())};
(AccessModel == presence) and (not PresenceSubscription) and (not Owner) -> (AccessModel == presence) and (not PresenceSubscription) and (not Owner) ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_presence_subscription_required())};
(AccessModel == roster) and (not RosterGroup) and (not Owner) -> (AccessModel == roster) and (not RosterGroup) and (not Owner) ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_not_in_roster_group())};
(AccessModel == whitelist) and (not Whitelisted) and (not Owner) -> (AccessModel == whitelist) and (not Whitelisted) and (not Owner) ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; xmpp:err_not_allowed(), mod_pubsub:err_closed_node())};
%%MustPay -> %%MustPay ->
%% % Payment is required for a subscription %% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED}; %% {error, ?ERR_PAYMENT_REQUIRED};
@ -177,7 +180,7 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
if if
%% Requesting entity is prohibited from unsubscribing entity %% Requesting entity is prohibited from unsubscribing entity
not Authorized -> not Authorized ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
%% Entity did not specify SubId %% Entity did not specify SubId
%%SubId == "", ?? -> %%SubId == "", ?? ->
%% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
@ -186,8 +189,9 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
%% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
%% Requesting entity is not a subscriber %% Requesting entity is not a subscriber
Subscriptions == [] -> Subscriptions == [] ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)}; xmpp:err_unexpected_request(),
mod_pubsub:err_not_subscribed())};
%% Subid supplied, so use that. %% Subid supplied, so use that.
SubIdExists -> SubIdExists ->
Sub = first_in_list(fun Sub = first_in_list(fun
@ -200,8 +204,9 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
delete_subscription(SubKey, Nidx, S, Affiliation, Subscriptions), delete_subscription(SubKey, Nidx, S, Affiliation, Subscriptions),
{result, default}; {result, default};
false -> false ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_UNEXPECTED_REQUEST_CANCEL), <<"not-subscribed">>)} xmpp:err_unexpected_request(),
mod_pubsub:err_not_subscribed())}
end; end;
%% Asking to remove all subscriptions to the given node %% Asking to remove all subscriptions to the given node
SubId == all -> SubId == all ->
@ -214,8 +219,8 @@ unsubscribe_node(Nidx, Sender, Subscriber, SubId) ->
{result, default}; {result, default};
%% No subid and more than one possible subscription match. %% No subid and more than one possible subscription match.
true -> true ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)} xmpp:err_bad_request(), mod_pubsub:err_subid_required())}
end. end.
delete_subscription(SubKey, Nidx, {Subscription, SubId}, Affiliation, Subscriptions) -> delete_subscription(SubKey, Nidx, {Subscription, SubId}, Affiliation, Subscriptions) ->
@ -241,7 +246,7 @@ publish_item(Nidx, Publisher, PublishModel, MaxItems, ItemId, Payload,
or (Affiliation == publisher) or (Affiliation == publisher)
or (Affiliation == publish_only)) or (Affiliation == publish_only))
or (Subscribed == true)) -> or (Subscribed == true)) ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
true -> true ->
if MaxItems > 0 -> if MaxItems > 0 ->
PubId = {p1_time_compat:timestamp(), SubKey}, PubId = {p1_time_compat:timestamp(), SubKey},
@ -277,11 +282,11 @@ delete_item(Nidx, Publisher, PublishModel, ItemId) ->
_ -> false _ -> false
end, end,
if not Allowed -> if not Allowed ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
true -> true ->
case del_item(Nidx, ItemId) of case del_item(Nidx, ItemId) of
{updated, 1} -> {result, {default, broadcast}}; {updated, 1} -> {result, {default, broadcast}};
_ -> {error, ?ERR_ITEM_NOT_FOUND} _ -> {error, xmpp:err_item_not_found()}
end end
end. end.
@ -299,7 +304,7 @@ purge_node(Nidx, Owner) ->
States), States),
{result, {default, broadcast}}; {result, {default, broadcast}};
_ -> _ ->
{error, ?ERR_FORBIDDEN} {error, xmpp:err_forbidden()}
end. end.
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
@ -307,48 +312,42 @@ get_entity_affiliations(Host, Owner) ->
GenKey = jid:remove_resource(SubKey), GenKey = jid:remove_resource(SubKey),
H = encode_host(Host), H = encode_host(Host),
J = encode_jid(GenKey), J = encode_jid(GenKey),
Reply = case catch {result,
ejabberd_sql:sql_query_t( case ejabberd_sql:sql_query_t(
?SQL("select @(node)s, @(type)s, @(i.nodeid)d, @(affiliation)s " ?SQL("select @(node)s, @(type)s, @(i.nodeid)d, @(affiliation)s "
"from pubsub_state i, pubsub_node n where " "from pubsub_state i, pubsub_node n where "
"i.nodeid = n.nodeid and jid=%(J)s and host=%(H)s")) "i.nodeid = n.nodeid and jid=%(J)s and host=%(H)s")) of
of
{selected, RItems} -> {selected, RItems} ->
[{nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), decode_affiliation(A)} [{nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}),
|| {N, T, I, A} <- RItems]; decode_affiliation(A)} || {N, T, I, A} <- RItems];
_ -> _ ->
[] []
end, end}.
{result, Reply}.
get_node_affiliations(Nidx) -> get_node_affiliations(Nidx) ->
Reply = case catch {result,
ejabberd_sql:sql_query_t( case ejabberd_sql:sql_query_t(
?SQL("select @(jid)s, @(affiliation)s from pubsub_state " ?SQL("select @(jid)s, @(affiliation)s from pubsub_state "
"where nodeid=%(Nidx)d")) "where nodeid=%(Nidx)d")) of
of
{selected, RItems} -> {selected, RItems} ->
[{decode_jid(J), decode_affiliation(A)} || {J, A} <- RItems]; [{decode_jid(J), decode_affiliation(A)} || {J, A} <- RItems];
_ -> _ ->
[] []
end, end}.
{result, Reply}.
get_affiliation(Nidx, Owner) -> get_affiliation(Nidx, Owner) ->
SubKey = jid:tolower(Owner), SubKey = jid:tolower(Owner),
GenKey = jid:remove_resource(SubKey), GenKey = jid:remove_resource(SubKey),
J = encode_jid(GenKey), J = encode_jid(GenKey),
Reply = case catch {result,
ejabberd_sql:sql_query_t( case ejabberd_sql:sql_query_t(
?SQL("select @(affiliation)s from pubsub_state " ?SQL("select @(affiliation)s from pubsub_state "
"where nodeid=%(Nidx)d and jid=%(J)s")) "where nodeid=%(Nidx)d and jid=%(J)s")) of
of
{selected, [{A}]} -> {selected, [{A}]} ->
decode_affiliation(A); decode_affiliation(A);
_ -> _ ->
none none
end, end}.
{result, Reply}.
set_affiliation(Nidx, Owner, Affiliation) -> set_affiliation(Nidx, Owner, Affiliation) ->
SubKey = jid:tolower(Owner), SubKey = jid:tolower(Owner),
@ -382,26 +381,26 @@ get_entity_subscriptions(Host, Owner) ->
"where i.nodeid = n.nodeid and" "where i.nodeid = n.nodeid and"
" jid in (%(SJ)s, %(GJ)s) and host=%(H)s") " jid in (%(SJ)s, %(GJ)s) and host=%(H)s")
end, end,
Reply = case catch ejabberd_sql:sql_query_t(Query) of {result,
case ejabberd_sql:sql_query_t(Query) of
{selected, RItems} -> {selected, RItems} ->
lists:foldl(fun ({N, T, I, J, S}, Acc) -> lists:foldl(
fun({N, T, I, J, S}, Acc) ->
Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}),
Jid = decode_jid(J), Jid = decode_jid(J),
case decode_subscriptions(S) of case decode_subscriptions(S) of
[] -> [] ->
[{Node, none, Jid} | Acc]; [{Node, none, Jid} | Acc];
Subs -> Subs ->
lists:foldl(fun ({Sub, SubId}, Acc2) -> lists:foldl(
fun({Sub, SubId}, Acc2) ->
[{Node, Sub, SubId, Jid} | Acc2] [{Node, Sub, SubId, Jid} | Acc2]
end, end, Acc, Subs)
Acc, Subs)
end end
end, end, [], RItems);
[], RItems);
_ -> _ ->
[] []
end, end}.
{result, Reply}.
-spec get_entity_subscriptions_for_send_last(Host :: mod_pubsub:hostPubsub(), -spec get_entity_subscriptions_for_send_last(Host :: mod_pubsub:hostPubsub(),
Owner :: jid()) -> Owner :: jid()) ->
@ -435,66 +434,62 @@ get_entity_subscriptions_for_send_last(Host, Owner) ->
"and val='on_sub_and_presence' and" "and val='on_sub_and_presence' and"
" jid in (%(SJ)s, %(GJ)s) and host=%(H)s") " jid in (%(SJ)s, %(GJ)s) and host=%(H)s")
end, end,
Reply = case catch ejabberd_sql:sql_query_t(Query) of {result,
case ejabberd_sql:sql_query_t(Query) of
{selected, RItems} -> {selected, RItems} ->
lists:foldl(fun ({N, T, I, J, S}, Acc) -> lists:foldl(
fun ({N, T, I, J, S}, Acc) ->
Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}), Node = nodetree_tree_sql:raw_to_node(Host, {N, <<"">>, T, I}),
Jid = decode_jid(J), Jid = decode_jid(J),
case decode_subscriptions(S) of case decode_subscriptions(S) of
[] -> [] ->
[{Node, none, Jid} | Acc]; [{Node, none, Jid} | Acc];
Subs -> Subs ->
lists:foldl(fun ({Sub, SubId}, Acc2) -> lists:foldl(
fun ({Sub, SubId}, Acc2) ->
[{Node, Sub, SubId, Jid}| Acc2] [{Node, Sub, SubId, Jid}| Acc2]
end, end, Acc, Subs)
Acc, Subs)
end end
end, end, [], RItems);
[], RItems);
_ -> _ ->
[] []
end, end}.
{result, Reply}.
get_node_subscriptions(Nidx) -> get_node_subscriptions(Nidx) ->
Reply = case catch {result,
ejabberd_sql:sql_query_t( case ejabberd_sql:sql_query_t(
?SQL("select @(jid)s, @(subscriptions)s from pubsub_state " ?SQL("select @(jid)s, @(subscriptions)s from pubsub_state "
"where nodeid=%(Nidx)d")) "where nodeid=%(Nidx)d")) of
of
{selected, RItems} -> {selected, RItems} ->
lists:foldl(fun ({J, S}, Acc) -> lists:foldl(
fun ({J, S}, Acc) ->
Jid = decode_jid(J), Jid = decode_jid(J),
case decode_subscriptions(S) of case decode_subscriptions(S) of
[] -> [] ->
[{Jid, none} | Acc]; [{Jid, none} | Acc];
Subs -> Subs ->
lists:foldl(fun ({Sub, SubId}, Acc2) -> lists:foldl(
fun ({Sub, SubId}, Acc2) ->
[{Jid, Sub, SubId} | Acc2] [{Jid, Sub, SubId} | Acc2]
end, end, Acc, Subs)
Acc, Subs)
end end
end, end, [], RItems);
[], RItems);
_ -> _ ->
[] []
end, end}.
{result, Reply}.
get_subscriptions(Nidx, Owner) -> get_subscriptions(Nidx, Owner) ->
SubKey = jid:tolower(Owner), SubKey = jid:tolower(Owner),
J = encode_jid(SubKey), J = encode_jid(SubKey),
Reply = case catch {result,
ejabberd_sql:sql_query_t( case ejabberd_sql:sql_query_t(
?SQL("select @(subscriptions)s from pubsub_state" ?SQL("select @(subscriptions)s from pubsub_state"
" where nodeid=%(Nidx)d and jid=%(J)s")) " where nodeid=%(Nidx)d and jid=%(J)s")) of
of
{selected, [{S}]} -> {selected, [{S}]} ->
decode_subscriptions(S); decode_subscriptions(S);
_ -> _ ->
[] []
end, end}.
{result, Reply}.
set_subscriptions(Nidx, Owner, Subscription, SubId) -> set_subscriptions(Nidx, Owner, Subscription, SubId) ->
SubKey = jid:tolower(Owner), SubKey = jid:tolower(Owner),
@ -503,8 +498,9 @@ set_subscriptions(Nidx, Owner, Subscription, SubId) ->
{_, []} -> {_, []} ->
case Subscription of case Subscription of
none -> none ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"not-subscribed">>)}; xmpp:err_bad_request(),
mod_pubsub:err_not_subscribed())};
_ -> _ ->
new_subscription(Nidx, Owner, Subscription, SubState) new_subscription(Nidx, Owner, Subscription, SubState)
end; end;
@ -514,8 +510,9 @@ set_subscriptions(Nidx, Owner, Subscription, SubId) ->
_ -> replace_subscription({Subscription, SID}, SubState) _ -> replace_subscription({Subscription, SID}, SubState)
end; end;
{<<>>, [_ | _]} -> {<<>>, [_ | _]} ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_BAD_REQUEST), <<"subid-required">>)}; xmpp:err_bad_request(),
mod_pubsub:err_subid_required())};
_ -> _ ->
case Subscription of case Subscription of
none -> unsub_with_subid(Nidx, SubId, SubState); none -> unsub_with_subid(Nidx, SubId, SubState);
@ -585,21 +582,19 @@ get_nodes_helper(NodeTree, #pubsub_state{stateid = {_, N}, subscriptions = Subs}
end. end.
get_states(Nidx) -> get_states(Nidx) ->
case catch case ejabberd_sql:sql_query_t(
ejabberd_sql:sql_query_t(
?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s " ?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s "
"from pubsub_state where nodeid=%(Nidx)d")) "from pubsub_state where nodeid=%(Nidx)d")) of
of
{selected, RItems} -> {selected, RItems} ->
{result, {result,
lists:map(fun ({SJID, Aff, Subs}) -> lists:map(
fun({SJID, Aff, Subs}) ->
JID = decode_jid(SJID), JID = decode_jid(SJID),
#pubsub_state{stateid = {JID, Nidx}, #pubsub_state{stateid = {JID, Nidx},
items = itemids(Nidx, JID), items = itemids(Nidx, JID),
affiliation = decode_affiliation(Aff), affiliation = decode_affiliation(Aff),
subscriptions = decode_subscriptions(Subs)} subscriptions = decode_subscriptions(Subs)}
end, end, RItems)};
RItems)};
_ -> _ ->
{result, []} {result, []}
end. end.
@ -614,12 +609,10 @@ get_state(Nidx, JID) ->
get_state_without_itemids(Nidx, JID) -> get_state_without_itemids(Nidx, JID) ->
J = encode_jid(JID), J = encode_jid(JID),
case catch case ejabberd_sql:sql_query_t(
ejabberd_sql:sql_query_t(
?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s " ?SQL("select @(jid)s, @(affiliation)s, @(subscriptions)s "
"from pubsub_state " "from pubsub_state "
"where nodeid=%(Nidx)d and jid=%(J)s")) "where nodeid=%(Nidx)d and jid=%(J)s")) of
of
{selected, [{SJID, Aff, Subs}]} -> {selected, [{SJID, Aff, Subs}]} ->
#pubsub_state{stateid = {decode_jid(SJID), Nidx}, #pubsub_state{stateid = {decode_jid(SJID), Nidx},
affiliation = decode_affiliation(Aff), affiliation = decode_affiliation(Aff),
@ -653,51 +646,38 @@ del_state(Nidx, JID) ->
" where jid=%(J)s and nodeid=%(Nidx)d")), " where jid=%(J)s and nodeid=%(Nidx)d")),
ok. ok.
%get_items(Nidx, _From) -> get_items(Nidx, From, undefined) ->
% case catch MaxItems = case ejabberd_sql:sql_query_t(
% ejabberd_sql:sql_query_t([<<"select itemid, publisher, creation, modification, payload "
% "from pubsub_item where nodeid='">>, Nidx,
% <<"' order by modification desc;">>])
% of
% {selected,
% [<<"itemid">>, <<"publisher">>, <<"creation">>, <<"modification">>, <<"payload">>], RItems} ->
% {result, [raw_to_item(Nidx, RItem) || RItem <- RItems]};
% _ ->
% {result, []}
% end.
get_items(Nidx, From, none) ->
MaxItems = case catch
ejabberd_sql:sql_query_t(
?SQL("select @(val)s from pubsub_node_option " ?SQL("select @(val)s from pubsub_node_option "
"where nodeid=%(Nidx)d and name='max_items'")) "where nodeid=%(Nidx)d and name='max_items'")) of
of
{selected, [{Value}]} -> {selected, [{Value}]} ->
jlib:expr_to_term(Value); jlib:expr_to_term(Value);
_ -> _ ->
?MAXITEMS ?MAXITEMS
end, end,
get_items(Nidx, From, #rsm_in{max = MaxItems}); get_items(Nidx, From, #rsm_set{max = MaxItems});
get_items(Nidx, _From, get_items(Nidx, _From, #rsm_set{max = Max, index = IncIndex,
#rsm_in{max = M, direction = Direction, id = I, index = IncIndex}) -> 'after' = After, before = Before}) ->
Max = ejabberd_sql:escape(jlib:i2l(M)), {Way, Order} = if After == <<>> -> {<<"is not">>, <<"desc">>};
{Way, Order} = case Direction of After /= undefined -> {<<"<">>, <<"desc">>};
aft when I == <<>> -> {<<"is not">>, <<"desc">>}; Before == <<>> -> {<<"is not">>, <<"asc">>};
aft -> {<<"<">>, <<"desc">>}; Before /= undefined -> {<<">">>, <<"asc">>};
before when I == <<>> -> {<<"is not">>, <<"asc">>}; true -> {<<"is not">>, <<"desc">>}
before -> {<<">">>, <<"asc">>};
_ -> {<<"is not">>, <<"desc">>}
end, end,
SNidx = integer_to_binary(Nidx), SNidx = integer_to_binary(Nidx),
[AttrName, Id] = case I of I = if After /= undefined -> After;
Before /= undefined -> Before;
true -> undefined
end,
[AttrName, Id] =
case I of
undefined when IncIndex =/= undefined -> undefined when IncIndex =/= undefined ->
case catch case ejabberd_sql:sql_query_t(
ejabberd_sql:sql_query_t([<<"select modification from pubsub_item pi " [<<"select modification from pubsub_item pi "
"where exists ( select count(*) as count1 " "where exists ( select count(*) as count1 "
"from pubsub_item where nodeid='">>, SNidx, "from pubsub_item where nodeid='">>, SNidx,
<<"' and modification > pi.modification having count1 = ">>, <<"' and modification > pi.modification having count1 = ">>,
ejabberd_sql:escape(jlib:i2l(IncIndex)), <<" );">>]) IncIndex, <<" );">>]) of
of
{selected, [_], [[O]]} -> {selected, [_], [[O]]} ->
[<<"modification">>, <<"'", O/binary, "'">>]; [<<"modification">>, <<"'", O/binary, "'">>];
_ -> _ ->
@ -708,18 +688,18 @@ get_items(Nidx, _From,
<<>> -> <<>> ->
[<<"modification">>, <<"null">>]; [<<"modification">>, <<"null">>];
I -> I ->
[A, B] = str:tokens(ejabberd_sql:escape(jlib:i2l(I)), <<"@">>), [A, B] = str:tokens(ejabberd_sql:escape(I), <<"@">>),
[A, <<"'", B/binary, "'">>] [A, <<"'", B/binary, "'">>]
end, end,
Count = case catch Count = case ejabberd_sql:sql_query_t(
ejabberd_sql:sql_query_t([<<"select count(*) from pubsub_item where nodeid='">>, SNidx, <<"';">>]) [<<"select count(*) from pubsub_item where nodeid='">>,
of SNidx, <<"';">>]) of
{selected, [_], [[C]]} -> C; {selected, [_], [[C]]} -> binary_to_integer(C);
_ -> <<"0">> _ -> 0
end, end,
Query = fun(mssql, _) -> Query = fun(mssql, _) ->
ejabberd_sql:sql_query_t( ejabberd_sql:sql_query_t(
[<<"select top ">>, jlib:i2l(Max), [<<"select top ">>, Max,
<<" itemid, publisher, creation, modification, payload " <<" itemid, publisher, creation, modification, payload "
"from pubsub_item where nodeid='">>, SNidx, "from pubsub_item where nodeid='">>, SNidx,
<<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>, <<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>,
@ -729,32 +709,33 @@ get_items(Nidx, _From,
[<<"select itemid, publisher, creation, modification, payload " [<<"select itemid, publisher, creation, modification, payload "
"from pubsub_item where nodeid='">>, SNidx, "from pubsub_item where nodeid='">>, SNidx,
<<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>, <<"' and ">>, AttrName, <<" ">>, Way, <<" ">>, Id, <<" order by ">>,
AttrName, <<" ">>, Order, <<" limit ">>, jlib:i2l(Max), <<" ;">>]) AttrName, <<" ">>, Order, <<" limit ">>, Max, <<" ;">>])
end, end,
case catch ejabberd_sql:sql_query_t(Query) of case ejabberd_sql:sql_query_t(Query) of
{selected, {selected, [<<"itemid">>, <<"publisher">>, <<"creation">>,
[<<"itemid">>, <<"publisher">>, <<"creation">>, <<"modification">>, <<"payload">>], RItems} -> <<"modification">>, <<"payload">>], RItems} ->
case RItems of case RItems of
[[_, _, _, F, _]|_] -> [[_, _, _, F, _]|_] ->
Index = case catch Index = case catch ejabberd_sql:sql_query_t(
ejabberd_sql:sql_query_t([<<"select count(*) from pubsub_item " [<<"select count(*) from pubsub_item "
"where nodeid='">>, SNidx, <<"' and ">>, "where nodeid='">>, SNidx, <<"' and ">>,
AttrName, <<" > '">>, F, <<"';">>]) AttrName, <<" > '">>, F, <<"';">>]) of
of {selected, [_], [[In]]} -> binary_to_integer(In);
%{selected, [_], [{C}, {In}]} -> [string:strip(C, both, $"), string:strip(In, both, $")]; _ -> 0
{selected, [_], [[In]]} -> In;
_ -> <<"0">>
end, end,
[_, _, _, L, _] = lists:last(RItems), [_, _, _, L, _] = lists:last(RItems),
RsmOut = #rsm_out{count = Count, index = Index, RsmOut = #rsm_set{count = Count,
first = <<"modification@", F/binary>>, index = Index,
last = <<"modification@", (jlib:i2l(L))/binary>>}, first = #rsm_first{
index = Index,
data = <<"modification@", F/binary>>},
last = <<"modification@", L/binary>>},
{result, {[raw_to_item(Nidx, RItem) || RItem <- RItems], RsmOut}}; {result, {[raw_to_item(Nidx, RItem) || RItem <- RItems], RsmOut}};
[] -> [] ->
{result, {[], #rsm_out{count = Count}}} {result, {[], #rsm_set{count = Count}}}
end; end;
_ -> _ ->
{result, {[], none}} {result, {[], undefined}}
end. end.
get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM) -> get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM) ->
@ -769,18 +750,20 @@ get_items(Nidx, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId, RSM
%% Entity is subscribed but specifies an invalid subscription ID %% Entity is subscribed but specifies an invalid subscription ID
%{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
(Affiliation == outcast) or (Affiliation == publish_only) -> (Affiliation == outcast) or (Affiliation == publish_only) ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
(AccessModel == presence) and not PresenceSubscription -> (AccessModel == presence) and not PresenceSubscription ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_presence_subscription_required())};
(AccessModel == roster) and not RosterGroup -> (AccessModel == roster) and not RosterGroup ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_not_in_roster_group())};
(AccessModel == whitelist) and not Whitelisted -> (AccessModel == whitelist) and not Whitelisted ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; xmpp:err_not_allowed(), mod_pubsub:err_closed_node())};
(AccessModel == authorize) and not Whitelisted -> (AccessModel == authorize) and not Whitelisted ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
%%MustPay -> %%MustPay ->
%% % Payment is required for a subscription %% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED}; %% {error, ?ERR_PAYMENT_REQUIRED};
@ -820,9 +803,9 @@ get_item(Nidx, ItemId) ->
{selected, [RItem]} -> {selected, [RItem]} ->
{result, raw_to_item(Nidx, RItem)}; {result, raw_to_item(Nidx, RItem)};
{selected, []} -> {selected, []} ->
{error, ?ERR_ITEM_NOT_FOUND}; {error, xmpp:err_item_not_found()};
{'EXIT', _} -> {'EXIT', _} ->
{error, ?ERRT_INTERNAL_SERVER_ERROR(?MYLANG, <<"Database failure">>)} {error, xmpp:err_internal_server_error(<<"Database failure">>, ?MYLANG)}
end. end.
get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
@ -837,18 +820,20 @@ get_item(Nidx, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _Sub
%% Entity is subscribed but specifies an invalid subscription ID %% Entity is subscribed but specifies an invalid subscription ID
%{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; %{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
(Affiliation == outcast) or (Affiliation == publish_only) -> (Affiliation == outcast) or (Affiliation == publish_only) ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
(AccessModel == presence) and not PresenceSubscription -> (AccessModel == presence) and not PresenceSubscription ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"presence-subscription-required">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_presence_subscription_required())};
(AccessModel == roster) and not RosterGroup -> (AccessModel == roster) and not RosterGroup ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_AUTHORIZED), <<"not-in-roster-group">>)}; xmpp:err_not_authorized(),
mod_pubsub:err_not_in_roster_group())};
(AccessModel == whitelist) and not Whitelisted -> (AccessModel == whitelist) and not Whitelisted ->
{error, {error, mod_pubsub:extended_error(
?ERR_EXTENDED((?ERR_NOT_ALLOWED), <<"closed-node">>)}; xmpp:err_not_allowed(), mod_pubsub:err_closed_node())};
(AccessModel == authorize) and not Whitelisted -> (AccessModel == authorize) and not Whitelisted ->
{error, ?ERR_FORBIDDEN}; {error, xmpp:err_forbidden()};
%%MustPay -> %%MustPay ->
%% % Payment is required for a subscription %% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED}; %% {error, ?ERR_PAYMENT_REQUIRED};

View File

@ -10,7 +10,7 @@
%% API %% API
-export([make_iq_result/1, make_iq_result/2, make_error/2, -export([make_iq_result/1, make_iq_result/2, make_error/2,
decode/1, decode/2, decode_tags_by_ns/2, encode/1, decode/1, decode/2, encode/1,
get_type/1, get_to/1, get_from/1, get_id/1, get_type/1, get_to/1, get_from/1, get_id/1,
get_lang/1, get_error/1, get_els/1, get_ns/1, get_lang/1, get_error/1, get_els/1, get_ns/1,
set_type/2, set_to/2, set_from/2, set_id/2, set_type/2, set_to/2, set_from/2, set_id/2,
@ -252,6 +252,10 @@ decode(Pkt, _Opts) ->
decode_els(Stanza) -> decode_els(Stanza) ->
decode_els(Stanza, fun xmpp_codec:is_known_tag/1). decode_els(Stanza, fun xmpp_codec:is_known_tag/1).
-type match_fun() :: fun((xmlel()) -> boolean()).
-spec decode_els(iq(), match_fun()) -> iq();
(message(), match_fun()) -> message();
(presence(), match_fun()) -> presence().
decode_els(Stanza, MatchFun) -> decode_els(Stanza, MatchFun) ->
Els = lists:map( Els = lists:map(
fun(#xmlel{} = El) -> fun(#xmlel{} = El) ->
@ -268,10 +272,6 @@ decode_els(Stanza, MatchFun) ->
encode(Pkt) -> encode(Pkt) ->
xmpp_codec:encode(Pkt). xmpp_codec:encode(Pkt).
-spec decode_tags_by_ns([xmpp_element() | xmlel()], [binary()]) -> [xmpp_element()].
decode_tags_by_ns(Els, NSList) ->
[xmpp_codec:decode(El) || El <- Els, lists:member(get_ns(El), NSList)].
format_error(Reason) -> format_error(Reason) ->
xmpp_codec:format_error(Reason). xmpp_codec:format_error(Reason).

File diff suppressed because it is too large Load Diff

View File

@ -1646,10 +1646,13 @@
-xml(pubsub_subscription, -xml(pubsub_subscription,
#elem{name = <<"subscription">>, #elem{name = <<"subscription">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = [<<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_subscription, '$jid', '$node', '$subid', <<"http://jabber.org/protocol/pubsub#owner">>,
'$type'}, <<"http://jabber.org/protocol/pubsub#event">>],
attrs = [#attr{name = <<"jid">>, result = {ps_subscription, '$xmlns', '$jid', '$type',
'$node', '$subid', '$expiry'},
attrs = [#attr{name = <<"xmlns">>},
#attr{name = <<"jid">>,
required = true, required = true,
dec = {dec_jid, []}, dec = {dec_jid, []},
enc = {enc_jid, []}}, enc = {enc_jid, []}},
@ -1659,14 +1662,24 @@
label = '$type', label = '$type',
dec = {dec_enum, [[none, pending, subscribed, dec = {dec_enum, [[none, pending, subscribed,
unconfigured]]}, unconfigured]]},
enc = {enc_enum, []}}]}). enc = {enc_enum, []}},
#attr{name = <<"expiry">>,
dec = {dec_utc, []},
enc = {enc_utc, []}}]}).
-record(ps_affiliation, {xmlns = <<>> :: binary(),
node = <<>> :: binary(),
type :: member | none | outcast |
owner | publisher | 'publish-only',
jid :: jid:jid()}).
-type ps_affiliation() :: #ps_affiliation{}.
-xml(pubsub_affiliation, -xml(pubsub_affiliation,
#elem{name = <<"affiliation">>, #elem{name = <<"affiliation">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_affiliation, '$node', '$type'}, result = {ps_affiliation, '$xmlns', '$node', '$type', '$_'},
attrs = [#attr{name = <<"node">>, attrs = [#attr{name = <<"node">>, required = true},
required = true}, #attr{name = <<"xmlns">>},
#attr{name = <<"affiliation">>, #attr{name = <<"affiliation">>,
label = '$type', label = '$type',
required = true, required = true,
@ -1674,24 +1687,28 @@
publisher, 'publish-only']]}, publisher, 'publish-only']]},
enc = {enc_enum, []}}]}). enc = {enc_enum, []}}]}).
-xml(pubsub_item, -xml(pubsub_owner_affiliation,
#elem{name = <<"item">>, #elem{name = <<"affiliation">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub#owner">>,
result = {pubsub_item, '$id', '$_xmls'}, result = {ps_affiliation, '$xmlns', '$_', '$type', '$jid'},
attrs = [#attr{name = <<"id">>}]}). attrs = [#attr{name = <<"jid">>,
required = true,
dec = {dec_jid, []},
enc = {enc_jid, []}},
#attr{name = <<"xmlns">>},
#attr{name = <<"affiliation">>,
label = '$type',
required = true,
dec = {dec_enum, [[member, none, outcast, owner,
publisher, 'publish-only']]},
enc = {enc_enum, []}}]}).
-xml(pubsub_items, -xml(pubsub_event_configuration,
#elem{name = <<"items">>, #elem{name = <<"configuration">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub#event">>,
result = {pubsub_items, '$node', '$max_items', result = {'$node', '$xdata'},
'$subid', '$items'}, attrs = [#attr{name = <<"node">>, required = true}],
attrs = [#attr{name = <<"max_items">>, refs = [#ref{name = xdata, min = 0, max = 1}]}).
dec = {dec_int, [0, infinity]},
enc = {enc_int, []}},
#attr{name = <<"node">>,
required = true},
#attr{name = <<"subid">>}],
refs = [#ref{name = pubsub_item, label = '$items'}]}).
-xml(pubsub_event_retract, -xml(pubsub_event_retract,
#elem{name = <<"retract">>, #elem{name = <<"retract">>,
@ -1699,32 +1716,55 @@
result = '$id', result = '$id',
attrs = [#attr{name = <<"id">>, required = true}]}). attrs = [#attr{name = <<"id">>, required = true}]}).
-xml(pubsub_event_item, -xml(pubsub_item,
#elem{name = <<"item">>, #elem{name = <<"item">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>, xmlns = [<<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_event_item, '$id', '$node', '$publisher', '$_xmls'}, <<"http://jabber.org/protocol/pubsub#event">>],
result = {ps_item, '$xmlns', '$id', '$_xmls', '$node', '$publisher'},
attrs = [#attr{name = <<"id">>}, attrs = [#attr{name = <<"id">>},
#attr{name = <<"xmlns">>},
#attr{name = <<"node">>}, #attr{name = <<"node">>},
#attr{name = <<"publisher">>}]}). #attr{name = <<"publisher">>}]}).
-xml(pubsub_event_items, -xml(pubsub_items,
#elem{name = <<"items">>, #elem{name = <<"items">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>, xmlns = [<<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_event_items, '$node', '$retract', '$items'}, <<"http://jabber.org/protocol/pubsub#event">>],
attrs = [#attr{name = <<"node">>, result = {ps_items, '$xmlns', '$node', '$items', '$max_items',
required = true}], '$subid', '$retract'},
refs = [#ref{name = pubsub_event_retract, label = '$retract'}, attrs = [#attr{name = <<"xmlns">>},
#ref{name = pubsub_event_item, label = '$items'}]}). #attr{name = <<"max_items">>,
dec = {dec_int, [0, infinity]},
enc = {enc_int, []}},
#attr{name = <<"node">>,
required = true},
#attr{name = <<"subid">>}],
refs = [#ref{name = pubsub_event_retract, label = '$retract',
min = 0, max = 1},
#ref{name = pubsub_item, label = '$items'}]}).
-xml(pubsub_event, -xml(pubsub_event,
#elem{name = <<"event">>, #elem{name = <<"event">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>, xmlns = <<"http://jabber.org/protocol/pubsub#event">>,
result = {pubsub_event, '$items'}, result = {ps_event, '$items', '$purge', '$subscription', '$delete',
refs = [#ref{name = pubsub_event_items, label = '$items'}]}). '$create', '$configuration'},
refs = [#ref{name = pubsub_items, label = '$items',
min = 0, max = 1},
#ref{name = pubsub_subscription, min = 0, max = 1,
label = '$subscription'},
#ref{name = pubsub_purge, min = 0, max = 1,
label = '$purge'},
#ref{name = pubsub_delete, min = 0, max = 1,
label = '$delete'},
#ref{name = pubsub_create, min = 0, max = 1,
label = '$create'},
#ref{name = pubsub_event_configuration, min = 0, max = 1,
label = '$configuration'}]}).
-xml(pubsub_subscriptions, -xml(pubsub_subscriptions,
#elem{name = <<"subscriptions">>, #elem{name = <<"subscriptions">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>],
result = {'$node', '$subscriptions'}, result = {'$node', '$subscriptions'},
attrs = [#attr{name = <<"node">>}], attrs = [#attr{name = <<"node">>}],
refs = [#ref{name = pubsub_subscription, label = '$subscriptions'}]}). refs = [#ref{name = pubsub_subscription, label = '$subscriptions'}]}).
@ -1732,13 +1772,21 @@
-xml(pubsub_affiliations, -xml(pubsub_affiliations,
#elem{name = <<"affiliations">>, #elem{name = <<"affiliations">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = '$affiliations', result = {'$node', '$affiliations'},
attrs = [#attr{name = <<"node">>}],
refs = [#ref{name = pubsub_affiliation, label = '$affiliations'}]}). refs = [#ref{name = pubsub_affiliation, label = '$affiliations'}]}).
-xml(pubsub_owner_affiliations,
#elem{name = <<"affiliations">>,
xmlns = <<"http://jabber.org/protocol/pubsub#owner">>,
result = {'$node', '$affiliations'},
attrs = [#attr{name = <<"node">>}],
refs = [#ref{name = pubsub_owner_affiliation, label = '$affiliations'}]}).
-xml(pubsub_subscribe, -xml(pubsub_subscribe,
#elem{name = <<"subscribe">>, #elem{name = <<"subscribe">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_subscribe, '$node', '$jid'}, result = {ps_subscribe, '$node', '$jid'},
attrs = [#attr{name = <<"node">>}, attrs = [#attr{name = <<"node">>},
#attr{name = <<"jid">>, #attr{name = <<"jid">>,
required = true, required = true,
@ -1748,7 +1796,7 @@
-xml(pubsub_unsubscribe, -xml(pubsub_unsubscribe,
#elem{name = <<"unsubscribe">>, #elem{name = <<"unsubscribe">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_unsubscribe, '$node', '$jid', '$subid'}, result = {ps_unsubscribe, '$node', '$jid', '$subid'},
attrs = [#attr{name = <<"node">>}, attrs = [#attr{name = <<"node">>},
#attr{name = <<"subid">>}, #attr{name = <<"subid">>},
#attr{name = <<"jid">>, #attr{name = <<"jid">>,
@ -1759,7 +1807,7 @@
-xml(pubsub_publish, -xml(pubsub_publish,
#elem{name = <<"publish">>, #elem{name = <<"publish">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_publish, '$node', '$items'}, result = {ps_publish, '$node', '$items'},
attrs = [#attr{name = <<"node">>, attrs = [#attr{name = <<"node">>,
required = true}], required = true}],
refs = [#ref{name = pubsub_item, label = '$items'}]}). refs = [#ref{name = pubsub_item, label = '$items'}]}).
@ -1767,7 +1815,7 @@
-xml(pubsub_options, -xml(pubsub_options,
#elem{name = <<"options">>, #elem{name = <<"options">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_options, '$node', '$jid', '$subid', '$xdata'}, result = {ps_options, '$node', '$jid', '$subid', '$xdata'},
attrs = [#attr{name = <<"node">>}, attrs = [#attr{name = <<"node">>},
#attr{name = <<"subid">>}, #attr{name = <<"subid">>},
#attr{name = <<"jid">>, #attr{name = <<"jid">>,
@ -1780,7 +1828,7 @@
-xml(pubsub_retract, -xml(pubsub_retract,
#elem{name = <<"retract">>, #elem{name = <<"retract">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_retract, '$node', '$notify', '$items'}, result = {ps_retract, '$node', '$notify', '$items'},
attrs = [#attr{name = <<"node">>, attrs = [#attr{name = <<"node">>,
required = true}, required = true},
#attr{name = <<"notify">>, #attr{name = <<"notify">>,
@ -1789,12 +1837,69 @@
enc = {enc_bool, []}}], enc = {enc_bool, []}}],
refs = [#ref{name = pubsub_item, label = '$items'}]}). refs = [#ref{name = pubsub_item, label = '$items'}]}).
-xml(pubsub_create,
#elem{name = <<"create">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = '$node',
attrs = [#attr{name = <<"node">>}]}).
-xml(pubsub_configure,
#elem{name = <<"configure">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>],
result = {'$node', '$xdata'},
attrs = [#attr{name = <<"node">>}],
refs = [#ref{name = xdata, min = 0, max = 1}]}).
-xml(pubsub_publish_options,
#elem{name = <<"publish-options">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = '$xdata',
refs = [#ref{name = xdata, min = 0, max = 1}]}).
-xml(pubsub_default,
#elem{name = <<"default">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>],
result = {'$node', '$xdata'},
attrs = [#attr{name = <<"node">>}],
refs = [#ref{name = xdata, min = 0, max = 1}]}).
-xml(pubsub_redirect,
#elem{name = <<"redirect">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = '$uri',
attrs = [#attr{name = <<"uri">>, required = true}]}).
-xml(pubsub_delete,
#elem{name = <<"delete">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = {'$node', '$uri'},
attrs = [#attr{name = <<"node">>, required = true}],
refs = [#ref{name = pubsub_redirect, min = 0, max = 1,
label = '$uri', default = <<>>}]}).
-xml(pubsub_purge,
#elem{name = <<"purge">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = '$node',
attrs = [#attr{name = <<"node">>, required = true}]}).
-xml(pubsub, -xml(pubsub,
#elem{name = <<"pubsub">>, #elem{name = <<"pubsub">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>, xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub, '$subscriptions', '$affiliations', '$publish', result = {pubsub, '$subscriptions', '$subscription',
'$affiliations', '$publish', '$publish_options',
'$subscribe', '$unsubscribe', '$options', '$items', '$subscribe', '$unsubscribe', '$options', '$items',
'$retract'}, '$retract', '$create', '$configure', '$default', '$delete',
'$purge', '$rsm'},
refs = [#ref{name = pubsub_subscriptions, label = '$subscriptions', refs = [#ref{name = pubsub_subscriptions, label = '$subscriptions',
min = 0, max = 1}, min = 0, max = 1},
#ref{name = pubsub_affiliations, label = '$affiliations', #ref{name = pubsub_affiliations, label = '$affiliations',
@ -1809,9 +1914,209 @@
min = 0, max = 1}, min = 0, max = 1},
#ref{name = pubsub_retract, label = '$retract', #ref{name = pubsub_retract, label = '$retract',
min = 0, max = 1}, min = 0, max = 1},
#ref{name = pubsub_create, label = '$create',
min = 0, max = 1},
#ref{name = pubsub_configure, label = '$configure',
min = 0, max = 1},
#ref{name = pubsub_publish_options, min = 0, max = 1,
label = '$publish_options'},
#ref{name = pubsub_default, label = '$default',
min = 0, max = 1},
#ref{name = pubsub_delete, label = '$delete',
min = 0, max = 1},
#ref{name = pubsub_purge, label = '$purge',
min = 0, max = 1},
#ref{name = pubsub_subscription, label = '$subscription',
min = 0, max = 1},
#ref{name = rsm_set, min = 0, max = 1, label = '$rsm'},
#ref{name = pubsub_publish, label = '$publish', #ref{name = pubsub_publish, label = '$publish',
min = 0, max = 1}]}). min = 0, max = 1}]}).
-xml(pubsub_owner,
#elem{name = <<"pubsub">>,
xmlns = <<"http://jabber.org/protocol/pubsub#owner">>,
result = {pubsub_owner, '$affiliations', '$configure', '$default',
'$delete', '$purge', '$subscriptions'},
refs = [#ref{name = pubsub_owner_affiliations,
label = '$affiliations', min = 0, max = 1},
#ref{name = pubsub_configure, label = '$configure',
min = 0, max = 1},
#ref{name = pubsub_default, label = '$default',
min = 0, max = 1},
#ref{name = pubsub_delete, label = '$delete',
min = 0, max = 1},
#ref{name = pubsub_purge, label = '$purge',
min = 0, max = 1},
#ref{name = pubsub_subscriptions,
label = '$subscriptions', min = 0, max = 1}]}).
-type ps_error_type() :: 'closed-node' | 'configuration-required' |
'invalid-jid' | 'invalid-options' |
'invalid-payload' | 'invalid-subid' |
'item-forbidden' | 'item-required' | 'jid-required' |
'max-items-exceeded' | 'max-nodes-exceeded' |
'nodeid-required' | 'not-in-roster-group' |
'not-subscribed' | 'payload-too-big' |
'payload-required' | 'pending-subscription' |
'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_error() :: #ps_error{}.
-xml(pubsub_error_closed_node,
#elem{name = <<"closed-node">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'closed-node', '$_'}}).
-xml(pubsub_error_configuration_required,
#elem{name = <<"configuration-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'configuration-required', '$_'}}).
-xml(pubsub_error_invalid_jid,
#elem{name = <<"invalid-jid">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'invalid-jid', '$_'}}).
-xml(pubsub_error_invalid_options,
#elem{name = <<"invalid-options">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'invalid-options', '$_'}}).
-xml(pubsub_error_invalid_payload,
#elem{name = <<"invalid-payload">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'invalid-payload', '$_'}}).
-xml(pubsub_error_invalid_subid,
#elem{name = <<"invalid-subid">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'invalid-subid', '$_'}}).
-xml(pubsub_error_item_forbidden,
#elem{name = <<"item-forbidden">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'item-forbidden', '$_'}}).
-xml(pubsub_error_item_required,
#elem{name = <<"item-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'item-required', '$_'}}).
-xml(pubsub_error_jid_required,
#elem{name = <<"jid-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'jid-required', '$_'}}).
-xml(pubsub_error_max_items_exceeded,
#elem{name = <<"max-items-exceeded">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'max-items-exceeded', '$_'}}).
-xml(pubsub_error_max_nodes_exceeded,
#elem{name = <<"max-nodes-exceeded">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'max-nodes-exceeded', '$_'}}).
-xml(pubsub_error_nodeid_required,
#elem{name = <<"nodeid-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'nodeid-required', '$_'}}).
-xml(pubsub_error_not_in_roster_group,
#elem{name = <<"not-in-roster-group">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'not-in-roster-group', '$_'}}).
-xml(pubsub_error_not_subscribed,
#elem{name = <<"not-subscribed">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'not-subscribed', '$_'}}).
-xml(pubsub_error_payload_too_big,
#elem{name = <<"payload-too-big">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'payload-too-big', '$_'}}).
-xml(pubsub_error_payload_required,
#elem{name = <<"payload-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'payload-required', '$_'}}).
-xml(pubsub_error_pending_subscription,
#elem{name = <<"pending-subscription">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'pending-subscription', '$_'}}).
-xml(pubsub_error_presence_subscription_required,
#elem{name = <<"presence-subscription-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'presence-subscription-required', '$_'}}).
-xml(pubsub_error_subid_required,
#elem{name = <<"subid-required">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'subid-required', '$_'}}).
-xml(pubsub_error_too_many_subscriptions,
#elem{name = <<"too-many-subscriptions">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'too-many-subscriptions', '$_'}}).
-xml(pubsub_error_unsupported,
#elem{name = <<"unsupported">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'unsupported', '$feature'},
attrs = [#attr{name = <<"feature">>, required = true,
dec = {dec_enum, [['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']]},
enc = {enc_enum, []}}]}).
-xml(pubsub_error_unsupported_access_model,
#elem{name = <<"unsupported-access-model">>,
xmlns = <<"http://jabber.org/protocol/pubsub#errors">>,
result = {ps_error, 'unsupported-access-model', '$_'}}).
-xml(shim_header, -xml(shim_header,
#elem{name = <<"header">>, #elem{name = <<"header">>,
xmlns = <<"http://jabber.org/protocol/shim">>, xmlns = <<"http://jabber.org/protocol/shim">>,