From 360b4916b1b11fc23f154a5e64f8e1f1e3665966 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Mon, 20 Jul 2009 08:53:56 +0000 Subject: [PATCH] Implement pubsub#get-pending Ad Hoc Command (EJAB-955) (thanks to Brian Cully) SVN Revision: 2372 --- src/jlib.hrl | 1 + src/mod_pubsub/gen_pubsub_node.erl | 1 + src/mod_pubsub/mod_pubsub.erl | 158 +++++++++++++++++++++++++++-- src/mod_pubsub/node.template | 4 + src/mod_pubsub/node_buddy.erl | 4 + src/mod_pubsub/node_club.erl | 4 + src/mod_pubsub/node_dag.erl | 4 + src/mod_pubsub/node_dispatch.erl | 4 + src/mod_pubsub/node_flat.erl | 4 + src/mod_pubsub/node_hometree.erl | 104 ++++++++++++++----- src/mod_pubsub/node_mb.erl | 4 + src/mod_pubsub/node_pep.erl | 4 + src/mod_pubsub/node_private.erl | 4 + src/mod_pubsub/node_public.erl | 4 + 14 files changed, 271 insertions(+), 33 deletions(-) diff --git a/src/jlib.hrl b/src/jlib.hrl index 955670e33..8051fc0a9 100644 --- a/src/jlib.hrl +++ b/src/jlib.hrl @@ -54,6 +54,7 @@ -define(NS_PUBSUB_NODE_CONFIG, "http://jabber.org/protocol/pubsub#node_config"). -define(NS_PUBSUB_SUB_OPTIONS, "http://jabber.org/protocol/pubsub#subscribe_options"). -define(NS_PUBSUB_SUB_AUTH, "http://jabber.org/protocol/pubsub#subscribe_authorization"). +-define(NS_PUBSUB_GET_PENDING, "http://jabber.org/protocol/pubsub#get-pending"). -define(NS_COMMANDS, "http://jabber.org/protocol/commands"). -define(NS_BYTESTREAMS, "http://jabber.org/protocol/bytestreams"). -define(NS_ADMIN, "http://jabber.org/protocol/admin"). diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl index dbf7e25d5..3762d4a44 100644 --- a/src/mod_pubsub/gen_pubsub_node.erl +++ b/src/mod_pubsub/gen_pubsub_node.erl @@ -59,6 +59,7 @@ behaviour_info(callbacks) -> {get_entity_subscriptions, 2}, {get_subscriptions, 2}, {set_subscriptions, 4}, + {get_pending_nodes, 2}, {get_states, 1}, {get_state, 2}, {set_state, 1}, diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 58e571509..d8e193548 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -53,6 +53,7 @@ -behaviour(gen_mod). -include("ejabberd.hrl"). +-include("adhoc.hrl"). -include("jlib.hrl"). -include("pubsub.hrl"). @@ -945,6 +946,15 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) -> sub_el = [{xmlelement, "vCard", [{"xmlns", XMLNS}], iq_get_vcard(Lang)}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); + #iq{type = set, xmlns = ?NS_COMMANDS} = IQ -> + Res = case iq_command(Host, ServerHost, From, IQ, Access, Plugins) of + {error, Error} -> + jlib:make_error_reply(Packet, Error); + {result, IQRes} -> + jlib:iq_to_xml(IQ#iq{type = result, + sub_el = IQRes}) + end, + ejabberd_router:route(To, From, Res); #iq{} -> Err = jlib:make_error_reply( Packet, @@ -1282,6 +1292,140 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> {error, ?ERR_BAD_REQUEST} end. +iq_command(Host, ServerHost, From, IQ, Access, Plugins) -> + case adhoc:parse_request(IQ) of + Req when is_record(Req, adhoc_request) -> + case adhoc_request(Host, ServerHost, From, Req, Access, Plugins) of + Resp when is_record(Resp, adhoc_response) -> + {result, [adhoc:produce_response(Req, Resp)]}; + Error -> + Error + end; + Err -> + Err + end. + +%% @doc

Processes an Ad Hoc Command.

+adhoc_request(Host, _ServerHost, Owner, + #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, + lang = Lang, + action = "execute", + xdata = false}, + _Access, Plugins) -> + send_pending_node_form(Host, Owner, Lang, Plugins); +adhoc_request(Host, _ServerHost, Owner, + #adhoc_request{node = ?NS_PUBSUB_GET_PENDING, + action = "execute", + xdata = XData}, + _Access, _Plugins) -> + ParseOptions = case XData of + {xmlelement, "x", _Attrs, _SubEls} = XEl -> + case jlib:parse_xdata_submit(XEl) of + invalid -> + {error, ?ERR_BAD_REQUEST}; + XData2 -> + case set_xoption(XData2, []) of + NewOpts when is_list(NewOpts) -> + {result, NewOpts}; + Err -> + Err + end + end; + _ -> + ?INFO_MSG("Bad XForm: ~p", [XData]), + {error, ?ERR_BAD_REQUEST} + end, + case ParseOptions of + {result, XForm} -> + case lists:keysearch(node, 1, XForm) of + {value, {_, Node}} -> + send_pending_auth_events(Host, Node, Owner); + false -> + {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "bad-payload")} + end; + Error -> + Error + end; +adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) -> + ?DEBUG("Couldn't process ad hoc command:~n~p", [Other]), + {error, ?ERR_ITEM_NOT_FOUND}. + +%% @spec (Host, Owner) -> iqRes() +%% @doc

Sends the process pending subscriptions XForm for Host to +%% Owner.

+send_pending_node_form(Host, Owner, _Lang, Plugins) -> + Filter = + fun (Plugin) -> + lists:member("get-pending", features(Plugin)) + end, + case lists:filter(Filter, Plugins) of + [] -> + {error, ?ERR_FEATURE_NOT_IMPLEMENTED}; + Ps -> + XOpts = lists:map(fun (Node) -> + {xmlelement, "option", [], + [{xmlelement, "value", [], + [{xmlcdata, node_to_string(Node)}]}]} + end, get_pending_nodes(Host, Owner, Ps)), + XForm = {xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], + [{xmlelement, "field", + [{"type", "list-single"}, {"var", "pubsub#node"}], + lists:usort(XOpts)}]}, + #adhoc_response{status = executing, + defaultaction = "execute", + elements = [XForm]} + end. + +get_pending_nodes(Host, Owner, Plugins) -> + Tr = + fun (Type) -> + case node_call(Type, get_pending_nodes, [Host, Owner]) of + {result, Nodes} -> Nodes; + _ -> [] + end + end, + case transaction(fun () -> {result, lists:flatmap(Tr, Plugins)} end, + sync_dirty) of + {result, Res} -> Res; + Err -> Err + end. + +%% @spec (Host, Node, Owner) -> iqRes() +%% @doc

Send a subscription approval form to Owner for all pending +%% subscriptions on Host and Node.

+send_pending_auth_events(Host, Node, Owner) -> + ?DEBUG("Sending pending auth events for ~s on ~s:~s", + [jlib:jid_to_string(Owner), Host, node_to_string(Node)]), + Action = + fun (#pubsub_node{id = NodeID, type = Type} = N) -> + case lists:member("get-pending", features(Type)) of + true -> + case node_call(Type, get_affiliation, [NodeID, Owner]) of + {result, owner} -> + broadcast_pending_auth_events(N), + {result, ok}; + _ -> + {error, ?ERR_FORBIDDEN} + end; + false -> + {error, ?ERR_FEATURE_NOT_IMPLEMENTED} + end + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, _} -> + #adhoc_response{}; + Err -> + Err + end. + +broadcast_pending_auth_events(#pubsub_node{type = Type, id = NodeID} = Node) -> + {result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]), + lists:foreach(fun ({J, pending, _SubID}) -> + send_authorization_request(Node, jlib:make_jid(J)); + ({J, pending}) -> + send_authorization_request(Node, jlib:make_jid(J)) + end, Subscriptions). + %%% authorization handling send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) -> @@ -2412,19 +2556,19 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({_, none, _}) -> []; - ({#pubsub_node{nodeid = {_, SubsNode}}, subscribed, SubID, SubJID}) -> + ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> case Node of [] -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(SubJID)}, {"subid", SubID}, - {"subscription", subscription_to_string(subscribed)}|nodeAttr(SubsNode)], + {"subscription", subscription_to_string(Subscription)}|nodeAttr(SubsNode)], []}]; SubsNode -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(SubJID)}, {"subid", SubID}, - {"subscription", subscription_to_string(subscribed)}], + {"subscription", subscription_to_string(Subscription)}], []}]; _ -> [] @@ -2468,11 +2612,10 @@ get_subscriptions(Host, Node, JID) -> end end, case transaction(Host, Node, Action, sync_dirty) of - {result, {_, []}} -> - {error, ?ERR_ITEM_NOT_FOUND}; {result, {_, Subscriptions}} -> Entities = lists:flatmap( fun({_, none}) -> []; + ({_, pending, _}) -> []; ({AJID, Subscription}) -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(AJID)}, @@ -3238,6 +3381,9 @@ set_xoption([{"pubsub#body_xslt", Value} | Opts], NewOpts) -> set_xoption([{"pubsub#collection", Value} | Opts], NewOpts) -> NewValue = [string_to_node(V) || V <- Value], ?SET_LIST_XOPT(collection, NewValue); +set_xoption([{"pubsub#node", [Value]} | Opts], NewOpts) -> + NewValue = string_to_node(Value), + ?SET_LIST_XOPT(node, NewValue); set_xoption([_ | Opts], NewOpts) -> % skip unknown field set_xoption(Opts, NewOpts). @@ -3319,7 +3465,7 @@ features() -> % see plugin "delete-items", % RECOMMENDED % see plugin "delete-nodes", % RECOMMENDED % see plugin "filtered-notifications", % RECOMMENDED - %TODO "get-pending", % OPTIONAL + % see plugin "get-pending", % OPTIONAL % see plugin "instant-nodes", % RECOMMENDED "item-ids", % RECOMMENDED "last-published", % RECOMMENDED diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template index 08f2e08ed..59de1dcb3 100644 --- a/src/mod_pubsub/node.template +++ b/src/mod_pubsub/node.template @@ -58,6 +58,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -160,6 +161,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index b3aea6f4a..5283ca5f0 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.erl @@ -59,6 +59,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -162,6 +163,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl index e3c16c630..a268cb9dc 100644 --- a/src/mod_pubsub/node_club.erl +++ b/src/mod_pubsub/node_club.erl @@ -59,6 +59,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -161,6 +162,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_dag.erl b/src/mod_pubsub/node_dag.erl index 2ffb70df2..f28c338d8 100644 --- a/src/mod_pubsub/node_dag.erl +++ b/src/mod_pubsub/node_dag.erl @@ -43,6 +43,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -139,6 +140,9 @@ get_subscriptions(NodeID, Owner) -> set_subscriptions(NodeID, Owner, Subscription, SubID) -> node_hometree:set_subscriptions(NodeID, Owner, Subscription, SubID). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeID) -> node_hometree:get_states(NodeID). diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl index 698d2559a..59a9dd85f 100644 --- a/src/mod_pubsub/node_dispatch.erl +++ b/src/mod_pubsub/node_dispatch.erl @@ -57,6 +57,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -165,6 +166,9 @@ get_subscriptions(_NodeId, _Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl index 4a89abdc6..05c0f9c3b 100644 --- a/src/mod_pubsub/node_flat.erl +++ b/src/mod_pubsub/node_flat.erl @@ -50,6 +50,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -148,6 +149,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index eda7fef7f..604945244 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -66,6 +66,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -155,6 +156,7 @@ features() -> "access-authorize", "delete-nodes", "delete-items", + "get-pending", "instant-nodes", "manage-subscriptions", "modify-affiliations", @@ -658,10 +660,8 @@ get_entity_subscriptions(Host, Owner) -> Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -> case NodeTree:get_node(N) of #pubsub_node{nodeid = {Host, _}} = Node -> - lists:foldl(fun({subscribed, SubID}, Acc2) -> - [{Node, subscribed, SubID, J} | Acc2]; - ({pending, _SubID}, Acc2) -> - [{Node, pending, J} | Acc2]; + lists:foldl(fun({Sub, SubID}, Acc2) -> + [{Node, Sub, SubID, J} | Acc2]; (S, Acc2) -> [{Node, S, J} | Acc2] end, Acc, Ss); @@ -676,10 +676,13 @@ get_node_subscriptions(NodeId) -> %% TODO: get rid of cases to handle non-list subscriptions case Subscriptions of [_|_] -> - lists:map(fun({subscribed, SubID}) -> {J, subscribed, SubID}; - ({pending, _SubID}) -> {J, pending}; - (S) -> {J, S} - end, Subscriptions); + lists:foldl(fun({S, SubID}, Acc) -> + [{J, S, SubID} | Acc]; + (S, Acc) -> + [{J, S} | Acc] + end, [], Subscriptions); + [] -> + []; _ -> [{J, none}] end @@ -695,32 +698,32 @@ set_subscriptions(NodeId, Owner, none, SubId) -> SubKey = jlib:jid_tolower(Owner), SubState = get_state(NodeId, SubKey), case {SubId, SubState#pubsub_state.subscriptions} of - {_, []} -> - {error, ?ERR_ITEM_NOT_FOUND}; - {"", [{_, SID}]} -> - unsub_with_subid(NodeId, SID, SubState); - {"", [_|_]} -> - {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; - _ -> - unsub_with_subid(NodeId, SubId, SubState) + {_, []} -> + {error, ?ERR_ITEM_NOT_FOUND}; + {"", [{_, SID}]} -> + unsub_with_subid(NodeId, SID, SubState); + {"", [_|_]} -> + {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + _ -> + unsub_with_subid(NodeId, SubId, SubState) end; set_subscriptions(NodeId, Owner, Subscription, SubId) -> SubKey = jlib:jid_tolower(Owner), SubState = get_state(NodeId, SubKey), case {SubId, SubState#pubsub_state.subscriptions} of - {_, []} -> - {error, ?ERR_ITEM_NOT_FOUND}; - {"", [{_, SID}]} -> - replace_subscription({Subscription, SID}, SubState); - {"", [_|_]} -> - {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; - _ -> - replace_subscription({Subscription, SubId}, SubState) + {_, []} -> + {error, ?ERR_ITEM_NOT_FOUND}; + {"", [{_, SID}]} -> + replace_subscription({Subscription, SID}, SubState); + {"", [_|_]} -> + {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; + _ -> + replace_subscription({Subscription, SubId}, SubState) end. replace_subscription(NewSub, SubState) -> NewSubs = replace_subscription(NewSub, - SubState#pubsub_state.subscriptions, []), + SubState#pubsub_state.subscriptions, []), set_state(SubState#pubsub_state{subscriptions = NewSubs}). replace_subscription(_, [], Acc) -> @@ -730,9 +733,9 @@ replace_subscription({Sub, SubID}, [{_, SubID} | T], Acc) -> unsub_with_subid(NodeId, SubId, SubState) -> pubsub_subscription:unsubscribe_node(SubState#pubsub_state.stateid, - NodeId, SubId), + NodeId, SubId), NewSubs = lists:filter(fun ({_, SID}) -> SubId =/= SID end, - SubState#pubsub_state.subscriptions), + SubState#pubsub_state.subscriptions), case {NewSubs, SubState#pubsub_state.affiliation} of {[], none} -> del_state(NodeId, element(1, SubState#pubsub_state.stateid)); @@ -740,6 +743,53 @@ unsub_with_subid(NodeId, SubId, SubState) -> set_state(SubState#pubsub_state{subscriptions = NewSubs}) end. +%% @spec (Host, Owner) -> {result, [Node]} | {error, Reason} +%% Host = host() +%% Owner = jid() +%% Node = pubsubNode() +%% @doc

Returns a list of Owner's nodes on Host with pending +%% subscriptions.

+get_pending_nodes(Host, Owner) -> + GenKey = jlib:jid_remove_resource(jlib:jid_tolower(Owner)), + States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, + affiliation = owner, + _ = '_'}), + NodeIDs = [ID || #pubsub_state{stateid = {_, ID}} <- States], + NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of + [{nodetree, N}] -> N; + _ -> nodetree_tree + end, + Reply = mnesia:foldl(fun(#pubsub_state{stateid = {_, NID}} = S, Acc) -> + case lists:member(NID, NodeIDs) of + true -> + case get_nodes_helper(NodeTree, S) of + {value, Node} -> [Node | Acc]; + false -> Acc + end; + false -> + Acc + end + end, [], pubsub_state), + {result, Reply}. + +get_nodes_helper(NodeTree, + #pubsub_state{stateid = {_, N}, subscriptions = Subs}) -> + HasPending = fun ({pending, _}) -> true; + (pending) -> true; + (_) -> false + end, + case lists:any(HasPending, Subs) of + true -> + case NodeTree:get_node(N) of + #pubsub_node{nodeid = {_, Node}} -> + {value, Node}; + _ -> + false + end; + false -> + false + end. + %% @spec (NodeId) -> [States] | [] %% NodeId = mod_pubsub:pubsubNodeId() %% @doc Returns the list of stored states for a given node. diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index b7ac76238..beef44996 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -62,6 +62,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -169,6 +170,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_pep:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_pep:get_states(NodeId). diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl index 57e30fecb..b811ee58b 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -55,6 +55,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -236,6 +237,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl index f4d4c8dea..ba34bcb2f 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.erl @@ -59,6 +59,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -165,6 +166,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId). diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl index fa806b712..c2bbe70e6 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.erl @@ -59,6 +59,7 @@ get_node_subscriptions/1, get_subscriptions/2, set_subscriptions/4, + get_pending_nodes/2, get_states/1, get_state/2, set_state/1, @@ -161,6 +162,9 @@ get_subscriptions(NodeId, Owner) -> set_subscriptions(NodeId, Owner, Subscription, SubId) -> node_hometree:set_subscriptions(NodeId, Owner, Subscription, SubId). +get_pending_nodes(Host, Owner) -> + node_hometree:get_pending_nodes(Host, Owner). + get_states(NodeId) -> node_hometree:get_states(NodeId).