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

View File

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

View File

@ -406,13 +406,15 @@ feature_response(_IQResult, Host, From, Caps,
[_SubNode | 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) ->
LServer = jid:nameprep(Host),
Mod = gen_mod:db_mod(LServer, ?MODULE),
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) ->
LServer = jid:nameprep(Host),
Mod = gen_mod:db_mod(LServer, ?MODULE),

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -10,7 +10,7 @@
%% API
-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_lang/1, get_error/1, get_els/1, get_ns/1,
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, 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) ->
Els = lists:map(
fun(#xmlel{} = El) ->
@ -268,10 +272,6 @@ decode_els(Stanza, MatchFun) ->
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) ->
xmpp_codec:format_error(Reason).

File diff suppressed because it is too large Load Diff

View File

@ -1646,27 +1646,40 @@
-xml(pubsub_subscription,
#elem{name = <<"subscription">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_subscription, '$jid', '$node', '$subid',
'$type'},
attrs = [#attr{name = <<"jid">>,
required = true,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = {ps_subscription, '$xmlns', '$jid', '$type',
'$node', '$subid', '$expiry'},
attrs = [#attr{name = <<"xmlns">>},
#attr{name = <<"jid">>,
required = true,
dec = {dec_jid, []},
enc = {enc_jid, []}},
#attr{name = <<"node">>},
#attr{name = <<"node">>},
#attr{name = <<"subid">>},
#attr{name = <<"subscription">>,
label = '$type',
dec = {dec_enum, [[none, pending, subscribed,
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,
#elem{name = <<"affiliation">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_affiliation, '$node', '$type'},
attrs = [#attr{name = <<"node">>,
required = true},
result = {ps_affiliation, '$xmlns', '$node', '$type', '$_'},
attrs = [#attr{name = <<"node">>, required = true},
#attr{name = <<"xmlns">>},
#attr{name = <<"affiliation">>,
label = '$type',
required = true,
@ -1674,24 +1687,28 @@
publisher, 'publish-only']]},
enc = {enc_enum, []}}]}).
-xml(pubsub_item,
#elem{name = <<"item">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_item, '$id', '$_xmls'},
attrs = [#attr{name = <<"id">>}]}).
-xml(pubsub_owner_affiliation,
#elem{name = <<"affiliation">>,
xmlns = <<"http://jabber.org/protocol/pubsub#owner">>,
result = {ps_affiliation, '$xmlns', '$_', '$type', '$jid'},
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,
#elem{name = <<"items">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_items, '$node', '$max_items',
'$subid', '$items'},
attrs = [#attr{name = <<"max_items">>,
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_configuration,
#elem{name = <<"configuration">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>,
result = {'$node', '$xdata'},
attrs = [#attr{name = <<"node">>, required = true}],
refs = [#ref{name = xdata, min = 0, max = 1}]}).
-xml(pubsub_event_retract,
#elem{name = <<"retract">>,
@ -1699,32 +1716,55 @@
result = '$id',
attrs = [#attr{name = <<"id">>, required = true}]}).
-xml(pubsub_event_item,
-xml(pubsub_item,
#elem{name = <<"item">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>,
result = {pubsub_event_item, '$id', '$node', '$publisher', '$_xmls'},
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = {ps_item, '$xmlns', '$id', '$_xmls', '$node', '$publisher'},
attrs = [#attr{name = <<"id">>},
#attr{name = <<"xmlns">>},
#attr{name = <<"node">>},
#attr{name = <<"publisher">>}]}).
-xml(pubsub_event_items,
-xml(pubsub_items,
#elem{name = <<"items">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>,
result = {pubsub_event_items, '$node', '$retract', '$items'},
attrs = [#attr{name = <<"node">>,
required = true}],
refs = [#ref{name = pubsub_event_retract, label = '$retract'},
#ref{name = pubsub_event_item, label = '$items'}]}).
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#event">>],
result = {ps_items, '$xmlns', '$node', '$items', '$max_items',
'$subid', '$retract'},
attrs = [#attr{name = <<"xmlns">>},
#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,
#elem{name = <<"event">>,
xmlns = <<"http://jabber.org/protocol/pubsub#event">>,
result = {pubsub_event, '$items'},
refs = [#ref{name = pubsub_event_items, label = '$items'}]}).
result = {ps_event, '$items', '$purge', '$subscription', '$delete',
'$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,
#elem{name = <<"subscriptions">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
xmlns = [<<"http://jabber.org/protocol/pubsub">>,
<<"http://jabber.org/protocol/pubsub#owner">>],
result = {'$node', '$subscriptions'},
attrs = [#attr{name = <<"node">>}],
refs = [#ref{name = pubsub_subscription, label = '$subscriptions'}]}).
@ -1732,13 +1772,21 @@
-xml(pubsub_affiliations,
#elem{name = <<"affiliations">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = '$affiliations',
result = {'$node', '$affiliations'},
attrs = [#attr{name = <<"node">>}],
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,
#elem{name = <<"subscribe">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_subscribe, '$node', '$jid'},
result = {ps_subscribe, '$node', '$jid'},
attrs = [#attr{name = <<"node">>},
#attr{name = <<"jid">>,
required = true,
@ -1748,7 +1796,7 @@
-xml(pubsub_unsubscribe,
#elem{name = <<"unsubscribe">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_unsubscribe, '$node', '$jid', '$subid'},
result = {ps_unsubscribe, '$node', '$jid', '$subid'},
attrs = [#attr{name = <<"node">>},
#attr{name = <<"subid">>},
#attr{name = <<"jid">>,
@ -1759,7 +1807,7 @@
-xml(pubsub_publish,
#elem{name = <<"publish">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_publish, '$node', '$items'},
result = {ps_publish, '$node', '$items'},
attrs = [#attr{name = <<"node">>,
required = true}],
refs = [#ref{name = pubsub_item, label = '$items'}]}).
@ -1767,7 +1815,7 @@
-xml(pubsub_options,
#elem{name = <<"options">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_options, '$node', '$jid', '$subid', '$xdata'},
result = {ps_options, '$node', '$jid', '$subid', '$xdata'},
attrs = [#attr{name = <<"node">>},
#attr{name = <<"subid">>},
#attr{name = <<"jid">>,
@ -1780,7 +1828,7 @@
-xml(pubsub_retract,
#elem{name = <<"retract">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub_retract, '$node', '$notify', '$items'},
result = {ps_retract, '$node', '$notify', '$items'},
attrs = [#attr{name = <<"node">>,
required = true},
#attr{name = <<"notify">>,
@ -1789,12 +1837,69 @@
enc = {enc_bool, []}}],
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,
#elem{name = <<"pubsub">>,
xmlns = <<"http://jabber.org/protocol/pubsub">>,
result = {pubsub, '$subscriptions', '$affiliations', '$publish',
'$subscribe', '$unsubscribe', '$options', '$items',
'$retract'},
result = {pubsub, '$subscriptions', '$subscription',
'$affiliations', '$publish', '$publish_options',
'$subscribe', '$unsubscribe', '$options', '$items',
'$retract', '$create', '$configure', '$default', '$delete',
'$purge', '$rsm'},
refs = [#ref{name = pubsub_subscriptions, label = '$subscriptions',
min = 0, max = 1},
#ref{name = pubsub_affiliations, label = '$affiliations',
@ -1809,9 +1914,209 @@
min = 0, max = 1},
#ref{name = pubsub_retract, label = '$retract',
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',
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,
#elem{name = <<"header">>,
xmlns = <<"http://jabber.org/protocol/shim">>,