From 306cff729c88c016fb0637d7b55b2e829d11c296 Mon Sep 17 00:00:00 2001
From: Pablo Polvorin
Date: Tue, 20 Oct 2009 22:09:43 +0000
Subject: [PATCH] Merge with trunk #2687 (EJAB-667) (untested)
SVN Revision: 2690
---
src/mod_pubsub/gen_pubsub_node.erl | 4 +-
src/mod_pubsub/gen_pubsub_nodetree.erl | 2 +-
src/mod_pubsub/mod_pubsub.erl | 136 ++++++++++++-------------
src/mod_pubsub/mod_pubsub_odbc.erl | 117 +++++++++------------
src/mod_pubsub/node_buddy.erl | 10 +-
src/mod_pubsub/node_club.erl | 10 +-
src/mod_pubsub/node_dag.erl | 10 +-
src/mod_pubsub/node_dispatch.erl | 9 +-
src/mod_pubsub/node_flat.erl | 17 +++-
src/mod_pubsub/node_flat_odbc.erl | 17 +++-
src/mod_pubsub/node_hometree.erl | 15 ++-
src/mod_pubsub/node_hometree_odbc.erl | 14 ++-
src/mod_pubsub/node_mb.erl | 9 +-
src/mod_pubsub/node_pep.erl | 10 +-
src/mod_pubsub/node_pep_odbc.erl | 9 +-
src/mod_pubsub/node_private.erl | 10 +-
src/mod_pubsub/node_public.erl | 10 +-
src/mod_pubsub/nodetree_dag.erl | 9 +-
src/mod_pubsub/nodetree_tree.erl | 54 ++++++----
src/mod_pubsub/nodetree_tree_odbc.erl | 49 +++++----
src/mod_pubsub/nodetree_virtual.erl | 4 +-
21 files changed, 327 insertions(+), 198 deletions(-)
diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl
index 3762d4a44..64464bcac 100644
--- a/src/mod_pubsub/gen_pubsub_node.erl
+++ b/src/mod_pubsub/gen_pubsub_node.erl
@@ -68,7 +68,9 @@ behaviour_info(callbacks) ->
{get_item, 7},
{get_item, 2},
{set_item, 1},
- {get_item_name, 3}
+ {get_item_name, 3},
+ {node_to_path, 1},
+ {path_to_node, 1}
];
behaviour_info(_Other) ->
undefined.
diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl
index f012b3d0b..480b7e60b 100644
--- a/src/mod_pubsub/gen_pubsub_nodetree.erl
+++ b/src/mod_pubsub/gen_pubsub_nodetree.erl
@@ -49,7 +49,7 @@ behaviour_info(callbacks) ->
{get_nodes, 1},
{get_subnodes, 3},
{get_subnodes_tree, 3},
- {create_node, 5},
+ {create_node, 6},
{delete_node, 2}
];
behaviour_info(_Other) ->
diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
index 444175548..cce677b29 100644
--- a/src/mod_pubsub/mod_pubsub.erl
+++ b/src/mod_pubsub/mod_pubsub.erl
@@ -277,11 +277,11 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) ->
ok.
init_nodes(Host, ServerHost, _NodeTree, Plugins) ->
- %% TODO, this call should be done PLugin side
+ %% TODO, this call should be done plugin side
case lists:member("hometree", Plugins) of
true ->
- create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"),
- create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree");
+ create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree"),
+ create_node(Host, ServerHost, string_to_node("/home" ++ ServerHost), service_jid(Host), "hometree");
false ->
ok
end.
@@ -412,8 +412,29 @@ update_node_database(Host, ServerHost) ->
rename_default_nodeplugin();
_ ->
ok
- end.
-
+ end,
+ mnesia:transaction(fun() ->
+ case catch mnesia:first(pubsub_node) of
+ {_, L} when is_list(L) ->
+ lists:foreach(
+ fun({H, N}) when is_list(N) ->
+ [Node] = mnesia:read({pubsub_node, {H, N}}),
+ Type = Node#pubsub_node.type,
+ BN = element(2, node_call(Type, path_to_node, [N])),
+ BP = case [element(2, node_call(Type, path_to_node, [P])) || P <- Node#pubsub_node.parents] of
+ [<<>>] -> [];
+ Parents -> Parents
+ end,
+ mnesia:write(Node#pubsub_node{nodeid={H, BN}, parents=BP}),
+ mnesia:delete({pubsub_node, {H, N}});
+ (_) ->
+ ok
+ end, mnesia:all_keys(pubsub_node));
+ _ ->
+ ok
+ end
+ end).
+
rename_default_nodeplugin() ->
lists:foreach(fun(Node) ->
mnesia:dirty_write(Node#pubsub_node{type = "hometree"})
@@ -557,7 +578,7 @@ send_loop(State) ->
on_sub_and_presence ->
lists:foreach(fun({Resource, Caps}) ->
CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of
- Features when is_list(Features) -> lists:member(Node ++ "+notify", Features);
+ Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features);
_ -> false
end,
case CapsNotify of
@@ -653,7 +674,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) ->
disco_sm_items(Acc, From, To, <<>>, _Lang) ->
Host = exmpp_jid:prep_domain_as_list(To),
- case tree_action(Host, get_subnodes, [Host, [], From]) of
+ case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
[] ->
Acc;
Nodes ->
@@ -671,7 +692,8 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) ->
end;
disco_sm_items(Acc, From, To, NodeB, _Lang) ->
- Node = binary_to_list(NodeB),
+ SNode = binary_to_list(NodeB),
+ Node = string_to_node(SNode),
%% TODO, use iq_disco_items(Host, Node, From)
Host = exmpp_jid:prep_domain_as_list(To),
LJID = jlib:short_prepd_bare_jid(To),
@@ -687,8 +709,6 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) ->
end,
NodeItems = lists:map(
fun(#pubsub_item{itemid = {Id, _}}) ->
- %% "jid" is required by XEP-0030, and
- %% "node" is forbidden by XEP-0060.
{result, Name} = node_call(Type, get_item_name, [Host, Node, Id]),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs =
[?XMLATTR('jid', exmpp_jid:to_binary(LJID)),
@@ -1085,7 +1105,7 @@ iq_disco_info(Host, SNode, From, Lang) ->
end,
Node = string_to_node(RealSNode),
case Node of
- [] ->
+ <<>> ->
{result,
[#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs =
[?XMLATTR('category', "pubsub"),
@@ -1104,13 +1124,11 @@ iq_disco_info(Host, SNode, From, Lang) ->
iq_disco_items(Host, [], From) ->
{result, lists:map(
- fun(#pubsub_node{nodeid = {_, SubNode}}) ->
- SN = node_to_string(SubNode),
- RN = lists:last(SubNode),
- %% remove name attribute
+ fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
+ {result, Path} = node_call(Type, node_to_path, [SubNode]),
+ [Name | _] = lists:reverse(Path),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host),
- ?XMLATTR('node', SN),
- ?XMLATTR('name', RN)]}
+ ?XMLATTR('name', Name) | nodeAttr(SubNode)]}
end, tree_action(Host, get_subnodes, [Host, [], From]))};
iq_disco_items(Host, Item, From) ->
case string:tokens(Item, "!") of
@@ -1118,10 +1136,6 @@ iq_disco_items(Host, Item, From) ->
{result, []};
[SNode] ->
Node = string_to_node(SNode),
- %% Note: Multiple Node Discovery not supported (mask on pubsub#type)
- %% TODO this code is also back-compatible with pubsub v1.8 (for client issue)
- %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?)
- %% TODO That is, remove name attribute (or node?, please check for 2.1)
Action =
fun(#pubsub_node{type = Type, id = NodeId}) ->
% TODO call get_items/6 instead for access control (EJAB-1033)
@@ -1131,17 +1145,12 @@ iq_disco_items(Host, Item, From) ->
end,
Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}}) ->
- SN = node_to_string(SubNode),
- RN = lists:last(SubNode),
- #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN),
- ?XMLATTR('name', RN)]}
+ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host) | nodeAttr(SubNode)]}
end, tree_call(Host, get_subnodes, [Host, Node, From])),
Items = lists:map(
fun(#pubsub_item{itemid = {RN, _}}) ->
- SN = node_to_string(Node) ++ "!" ++ RN,
- {result, Name} = node_call(Type, get_item_name, [NodeId, RN]),
- #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN),
- ?XMLATTR('name', Name)]}
+ {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]),
+ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('name', Name)]}
end, NodeItems),
{result, Nodes ++ Items}
end,
@@ -1199,10 +1208,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) ->
case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of
[#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] ->
- Node = case Host of
- {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false);
- _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false))
- end,
+ Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(attrs, 'node', false)),
case {IQType, Name} of
{set, 'create'} ->
Config = case Rest of
@@ -1303,10 +1309,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
Action = exmpp_xml:remove_cdata_from_list(SubEls),
case Action of
[#xmlel{name = Name, attrs = Attrs, children = Els}] ->
- Node = case Host of
- {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "");
- _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', ""))
- end,
+ Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")),
case {IQType, Name} of
{get, 'configure'} ->
get_configure(Host, ServerHost, Node, From, Lang);
@@ -1547,8 +1550,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) ->
end,
Stanza = event_stanza(
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs =
- [?XMLATTR('node', SNode),
- ?XMLATTR('jid', exmpp_jid:to_binary(JID))] ++ SubAttrs
+ [ ?XMLATTR('jid', exmpp_jid:to_binary(JID)) | nodeAttr(SNode)] ++ SubAttrs
}]),
ejabberd_router ! {route, service_jid(Host), JID, Stanza}.
@@ -1558,10 +1560,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
lists:keysearch("pubsub#allow", 1, XFields)} of
{{value, {_, [SNode]}}, {value, {_, [SSubscriber]}},
{value, {_, [SAllow]}}} ->
- Node = case Host of
- {_, _, _} -> [SNode];
- _ -> string:tokens(SNode, "/")
- end,
+ Node = string_to_node(SNode),
Subscriber = exmpp_jid:parse(SSubscriber),
Allow = case SAllow of
"1" -> true;
@@ -1696,21 +1695,18 @@ update_auth(Host, Node, Type, NodeId, Subscriber,
%%
create_node(Host, ServerHost, Node, Owner, Type) ->
create_node(Host, ServerHost, Node, Owner, Type, all, []).
-create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
+create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) ->
case lists:member("instant-nodes", features(Type)) of
true ->
- {LOU, LOS, _} = jlib:short_prepd_jid(Owner),
- HomeNode = ["home", LOS, LOU],
- create_node(Host, ServerHost,
- HomeNode, Owner, Type, Access, Configuration),
- NewNode = HomeNode ++ [randoms:get_string()],
+ NewNode = string_to_node(randoms:get_string()),
case create_node(Host, ServerHost,
NewNode, Owner, Type, Access, Configuration) of
{result, []} ->
{result,
[#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(NewNode)}]}]};
- Error -> Error
+ Error ->
+ Error
end;
false ->
%% Service does not support instant nodes
@@ -1718,7 +1714,6 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
end;
create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
Type = select_type(ServerHost, Host, Node, GivenType),
- Parent = lists:sublist(Node, length(Node) - 1),
%% TODO, check/set node_type = Type
ParseOptions = case exmpp_xml:remove_cdata_from_list(Configuration) of
[] ->
@@ -1743,9 +1738,18 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
{result, NodeOptions} ->
CreateNode =
fun() ->
+ SNode = node_to_string(Node),
+ Parent = case node_call(Type, node_to_path, [Node]) of
+ {result, [SNode]} -> <<>>;
+ {result, Path} -> element(2, node_call(Type, path_to_node, [lists:sublist(Path, length(Path)-1)]))
+ end,
+ Parents = case Parent of
+ <<>> -> [];
+ _ -> [Parent]
+ end,
case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of
{result, true} ->
- case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of
+ case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions, Parents]) of
{ok, NodeId} ->
node_call(Type, create_node, [NodeId, Owner]);
{error, {virtual, NodeId}} ->
@@ -2543,9 +2547,8 @@ read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
{result, #pubsub_subscription{options = Options}} ->
{result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options),
OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options',
- attrs = [?XMLATTR('node', node_to_string(Node)),
- ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)),
- ?XMLATTR('Subid', SubID)],
+ attrs = [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)),
+ ?XMLATTR('Subid', SubID) | nodeAttr(Node)],
children = [XdataEl]},
PubsubEl = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [OptionsEl]},
{result, PubsubEl}
@@ -2636,7 +2639,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) ->
[];
({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) ->
case Node of
- [] ->
+ <<>> ->
[#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs =
[?XMLATTR('node', node_to_string(SubsNode)),
?XMLATTR('subscription', subscription_to_string(Subscription))]}];
@@ -2650,7 +2653,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) ->
[];
({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) ->
case Node of
- [] ->
+ <<>> ->
[#xmlel{ns = ?NS_PUBSUB, name='subscription',
attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)),
?XMLATTR('subid', SubID),
@@ -2665,7 +2668,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) ->
end;
({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) ->
case Node of
- [] ->
+ <<>> ->
[#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs =
[?XMLATTR('node', node_to_string(SubsNode)),
?XMLATTR('jid', exmpp_jid:to_binary(SubJID)),
@@ -2857,14 +2860,8 @@ subscription_to_string(_) -> "none".
%% Node = pubsubNode()
%% NodeStr = string()
%% @doc Convert a node type from pubsubNode to string.
-node_to_string([]) -> "/";
-node_to_string(Node) ->
- case Node of
- [[_ | _] | _] -> string:strip(lists:flatten(["/", lists:map(fun(S) -> [S, "/"] end, Node)]), right, $/);
- [Head | _] when is_integer(Head) -> Node
- end.
-string_to_node(SNode) ->
- string:tokens(SNode, "/").
+node_to_string(Node) -> binary_to_list(Node).
+string_to_node(SNode) -> list_to_binary(SNode).
%% @spec (Host) -> jid()
%% Host = host()
@@ -3093,6 +3090,7 @@ get_options_for_subs(NodeID, Subs) ->
end, [], Subs).
% TODO: merge broadcast code that way
+% TODO: pablo: Why is this commented? Seems to be present on trunk.
%broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) ->
% case (get_option(NodeOptions, Feature) or Force) of
% true ->
@@ -3100,7 +3098,7 @@ get_options_for_subs(NodeID, Subs) ->
% {result, []} ->
% {result, false};
% {result, Subs} ->
-% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]),
+% Stanza = event_stanza([{xmlelement, ElName, nodeAttr(Node), SubEls}]),
% broadcast_stanza(Host, Node, Type, NodeOptions, SubOpts, Stanza),
% {result, true};
% _ ->
@@ -3217,7 +3215,7 @@ is_caps_notify(Host, Node, LJID) ->
false;
Caps ->
case catch mod_caps:get_features(Host, Caps) of
- Features when is_list(Features) -> lists:member(Node ++ "+notify", Features);
+ Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features);
_ -> false
end
end.
@@ -3748,6 +3746,8 @@ uniqid() ->
lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])).
% node attributes
+nodeAttr(Node) when is_list(Node) ->
+ [?XMLATTR('node', Node)];
nodeAttr(Node) ->
[?XMLATTR('node', node_to_string(Node))].
diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl
index 93e07c172..92e7275ea 100644
--- a/src/mod_pubsub/mod_pubsub_odbc.erl
+++ b/src/mod_pubsub/mod_pubsub_odbc.erl
@@ -275,11 +275,11 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) ->
ok.
init_nodes(Host, ServerHost, _NodeTree, Plugins) ->
- %% TODO, this call should be done PLugin side
- case lists:member("hometree", Plugins) of
+ %% TODO, this call should be done plugin side
+ case lists:member("hometree_odbc", Plugins) of
true ->
- create_node(Host, ServerHost, ["home"], service_jid(Host), "hometree"),
- create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), "hometree");
+ create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree_odbc"),
+ create_node(Host, ServerHost, string_to_node("/home/" ++ ServerHost), service_jid(Host), "hometree_odbc");
false ->
ok
end.
@@ -383,7 +383,7 @@ send_loop(State) ->
on_sub_and_presence ->
lists:foreach(fun({Resource, Caps}) ->
CapsNotify = case catch mod_caps:get_features(ServerHost, Caps) of
- Features when is_list(Features) -> lists:member(Node ++ "+notify", Features);
+ Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features);
_ -> false
end,
case CapsNotify of
@@ -479,7 +479,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) ->
disco_sm_items(Acc, From, To, <<>>, _Lang) ->
Host = exmpp_jid:prep_domain_as_list(To),
- case tree_action(Host, get_subnodes, [Host, [], From]) of
+ case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
[] ->
Acc;
Nodes ->
@@ -497,7 +497,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) ->
end;
disco_sm_items(Acc, From, To, NodeB, _Lang) ->
- Node = binary_to_list(NodeB),
+ Node = string_to_node(binary_to_list(NodeB)),
%% TODO, use iq_disco_items(Host, Node, From)
Host = exmpp_jid:prep_domain_as_list(To),
LJID = jlib:short_prepd_bare_jid(To),
@@ -513,8 +513,6 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) ->
end,
NodeItems = lists:map(
fun(#pubsub_item{itemid = {Id, _}}) ->
- %% "jid" is required by XEP-0030, and
- %% "node" is forbidden by XEP-0060.
{result, Name} = node_call(Type, get_item_name, [Host, Node, Id]),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs =
[?XMLATTR('jid', exmpp_jid:to_binary(LJID)),
@@ -913,7 +911,7 @@ iq_disco_info(Host, SNode, From, Lang) ->
end,
Node = string_to_node(RealSNode),
case Node of
- [] ->
+ <<>> ->
{result,
[#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs =
[?XMLATTR('category', "pubsub"),
@@ -933,24 +931,18 @@ iq_disco_info(Host, SNode, From, Lang) ->
iq_disco_items(Host, [], From, _RSM) ->
{result, lists:map(
- fun(#pubsub_node{nodeid = {_, SubNode}}) ->
- SN = node_to_string(SubNode),
- RN = lists:last(SubNode),
- %% remove name attribute
+ fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
+ {result, Path} = node_call(Type, node_path, [SubNode]),
+ [Name | _] = lists:reverse(Path),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host),
- ?XMLATTR('node', SN),
- ?XMLATTR('name', RN)]}
- end, tree_action(Host, get_subnodes, [Host, [], From]))};
+ ?XMLATTR('name', Name) | nodeAttr(SubNode)]}
+ end, tree_action(Host, get_subnodes, [Host, <<>>, From]))};
iq_disco_items(Host, Item, From, RSM) ->
case string:tokens(Item, "!") of
[_SNode, _ItemID] ->
{result, []};
[SNode] ->
Node = string_to_node(SNode),
- %% Note: Multiple Node Discovery not supported (mask on pubsub#type)
- %% TODO this code is also back-compatible with pubsub v1.8 (for client issue)
- %% TODO make it pubsub v1.12 compliant (breaks client compatibility ?)
- %% TODO That is, remove name attribute (or node?, please check for 2.1)
Action =
fun(#pubsub_node{type = Type, id = NodeId}) ->
%% TODO call get_items/6 instead for access control (EJAB-1033)
@@ -960,17 +952,13 @@ iq_disco_items(Host, Item, From, RSM) ->
end,
Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}}) ->
- SN = node_to_string(SubNode),
- RN = lists:last(SubNode),
- #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN),
- ?XMLATTR('name', RN)]}
+ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host) | nodeAttr(SubNode)]}
end, tree_call(Host, get_subnodes, [Host, Node, From])),
Items = lists:map(
fun(#pubsub_item{itemid = {RN, _}}) ->
- SN = node_to_string(Node) ++ "!" ++ RN,
- {result, Name} = node_call(Type, get_item_name, [NodeId, RN]),
- #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN),
- ?XMLATTR('name', Name)]}
+ {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]),
+ #xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host),
+ ?XMLATTR('name', Name)]}
end, NodeItems),
{result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)}
end,
@@ -1028,10 +1016,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) ->
case exmpp_xml:remove_cdata_from_list(SubEl#xmlel.children) of
[#xmlel{name = Name, attrs = Attrs, children = Els} | Rest] ->
- Node = case Host of
- {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false);
- _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false))
- end,
+ Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', false)),
case {IQType, Name} of
{set, 'create'} ->
Config = case Rest of
@@ -1134,10 +1119,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
end, exmpp_xml:get_child_elements(SubEl)),
case Action of
[#xmlel{name = Name, attrs = Attrs, children = Els}] ->
- Node = case Host of
- {_, _, _} -> exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "");
- _ -> string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', ""))
- end,
+ Node = string_to_node(exmpp_xml:get_attribute_from_list_as_list(Attrs, 'node', "")),
case {IQType, Name} of
{get, 'configure'} ->
get_configure(Host, ServerHost, Node, From, Lang);
@@ -1379,8 +1361,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) ->
end,
Stanza = event_stanza(
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs =
- [?XMLATTR('node', SNode),
- ?XMLATTR('jid', exmpp_jid:to_binary(JID))] ++ SubAttrs
+ [?XMLATTR('jid', exmpp_jid:to_binary(JID)) | nodeAttr(SNode)] ++ SubAttrs
}]),
ejabberd_router ! {route, service_jid(Host), JID, Stanza}.
@@ -1390,11 +1371,8 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
lists:keysearch("pubsub#allow", 1, XFields)} of
{{value, {_, [SNode]}}, {value, {_, [SSubscriber]}},
{value, {_, [SAllow]}}} ->
- Node = case Host of
- {_, _, _} -> [SNode];
- _ -> string:tokens(SNode, "/")
- end,
- Subscriber = exmpp_jid:parse(SSubscriber),
+ Node = string_to_node(SNode),
+ Subscriber = exmpp_jid:parse(SSubscriber),
Allow = case SAllow of
"1" -> true;
"true" -> true;
@@ -1528,21 +1506,18 @@ update_auth(Host, Node, Type, NodeId, Subscriber,
%%
create_node(Host, ServerHost, Node, Owner, Type) ->
create_node(Host, ServerHost, Node, Owner, Type, all, []).
-create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
+create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) ->
case lists:member("instant-nodes", features(Type)) of
true ->
- {LOU, LOS, _} = jlib:short_prepd_jid(Owner),
- HomeNode = ["home", LOS, LOU],
- create_node(Host, ServerHost,
- HomeNode, Owner, Type, Access, Configuration),
- NewNode = HomeNode ++ [randoms:get_string()],
+ NewNode = string_to_node(randoms:get_string()),
case create_node(Host, ServerHost,
NewNode, Owner, Type, Access, Configuration) of
{result, []} ->
{result,
[#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = nodeAttr(NewNode)}]}]};
- Error -> Error
+ Error ->
+ Error
end;
false ->
%% Service does not support instant nodes
@@ -1550,7 +1525,6 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
end;
create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
Type = select_type(ServerHost, Host, Node, GivenType),
- Parent = lists:sublist(Node, length(Node) - 1),
%% TODO, check/set node_type = Type
ParseOptions = case exmpp_xml:remove_cdata_from_list(Configuration) of
[] ->
@@ -1575,9 +1549,18 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
{result, NodeOptions} ->
CreateNode =
fun() ->
+ SNode = node_to_string(Node),
+ Parent = case node_call(Type, node_to_path, [Node]) of
+ {result, [SNode]} -> <<>>;
+ {result, Path} -> element(2, node_call(Type, path_to_node, [lists:sublist(Path, length(Path)-1)]))
+ end,
+ Parents = case Parent of
+ <<>> -> [];
+ _ -> [Parent]
+ end,
case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of
{result, true} ->
- case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of
+ case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions, Parents]) of
{ok, NodeId} ->
node_call(Type, create_node, [NodeId, Owner]);
{error, {virtual, NodeId}} ->
@@ -2374,9 +2357,8 @@ read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
{result, #pubsub_subscription{options = Options}} ->
{result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options),
OptionsEl = #xmlel{ns = ?NS_PUBSUB, name = 'options',
- attrs = [?XMLATTR('node', node_to_string(Node)),
- ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)),
- ?XMLATTR('Subid', SubID)],
+ attrs = [ ?XMLATTR('jid', exmpp_jid:to_binary(Subscriber)),
+ ?XMLATTR('Subid', SubID) | nodeAttr(Node)],
children = [XdataEl]},
PubsubEl = #xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children = [OptionsEl]},
{result, PubsubEl}
@@ -2467,7 +2449,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) ->
[];
({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) ->
case Node of
- [] ->
+ <<>> ->
[#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs =
[?XMLATTR('node', node_to_string(SubsNode)),
?XMLATTR('subscription', subscription_to_string(Subscription))]}];
@@ -2481,7 +2463,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) ->
[];
({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) ->
case Node of
- [] ->
+ <<>> ->
[#xmlel{ns = ?NS_PUBSUB, name='subscription',
attrs = [?XMLATTR('jid', exmpp_jid:jid_to_binary(SubJID)),
?XMLATTR('subid', SubID),
@@ -2496,7 +2478,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) ->
end;
({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) ->
case Node of
- [] ->
+ <<>> ->
[#xmlel{ns = ?NS_PUBSUB, name = 'subscription', attrs =
[?XMLATTR('node', node_to_string(SubsNode)),
?XMLATTR('jid', exmpp_jid:to_binary(SubJID)),
@@ -2688,14 +2670,8 @@ subscription_to_string(_) -> "none".
%% Node = pubsubNode()
%% NodeStr = string()
%% @doc Convert a node type from pubsubNode to string.
-node_to_string([]) -> "/";
-node_to_string(Node) ->
- case Node of
- [[_ | _] | _] -> string:strip(lists:flatten(["/", lists:map(fun(S) -> [S, "/"] end, Node)]), right, $/);
- [Head | _] when is_integer(Head) -> Node
- end.
-string_to_node(SNode) ->
- string:tokens(SNode, "/").
+node_to_string(Node) -> binary_to_list(Node).
+string_to_node(SNode) -> list_to_binary(SNode).
%% @spec (Host) -> jid()
%% Host = host()
@@ -2924,6 +2900,7 @@ get_options_for_subs(NodeID, Subs) ->
end, [], Subs).
% TODO: merge broadcast code that way
+% TODO: pablo: why is this commented?
%broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) ->
% case (get_option(NodeOptions, Feature) or Force) of
% true ->
@@ -2931,7 +2908,7 @@ get_options_for_subs(NodeID, Subs) ->
% {result, []} ->
% {result, false};
% {result, Subs} ->
-% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]),
+% Stanza = event_stanza([{xmlelement, ElName, nodeAttr(Node), SubEls}]),
% broadcast_stanza(Host, Node, Type, NodeOptions, SubOpts, Stanza),
% {result, true};
% _ ->
@@ -3048,7 +3025,7 @@ is_caps_notify(Host, Node, LJID) ->
false;
Caps ->
case catch mod_caps:get_features(Host, Caps) of
- Features when is_list(Features) -> lists:member(Node ++ "+notify", Features);
+ Features when is_list(Features) -> lists:member(node_to_string(Node) ++ "+notify", Features);
_ -> false
end
end.
@@ -3635,6 +3612,8 @@ uniqid() ->
lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])).
% node attributes
+nodeAttr(Node) when is_list(Node) ->
+ [?XMLATTR('node', Node)];
nodeAttr(Node) ->
[?XMLATTR('node', node_to_string(Node))].
diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl
index 0d672a748..4d0a75710 100644
--- a/src/mod_pubsub/node_buddy.erl
+++ b/src/mod_pubsub/node_buddy.erl
@@ -69,7 +69,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -195,3 +197,9 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+
+node_to_path(Node) ->
+ node_flat:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat:path_to_node(Path).
diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl
index 3e27e2013..536c39d9f 100644
--- a/src/mod_pubsub/node_club.erl
+++ b/src/mod_pubsub/node_club.erl
@@ -68,7 +68,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -192,3 +194,9 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+
+node_to_path(Node) ->
+ node_flat:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat:path_to_node(Path).
diff --git a/src/mod_pubsub/node_dag.erl b/src/mod_pubsub/node_dag.erl
index df654433e..439be2205 100644
--- a/src/mod_pubsub/node_dag.erl
+++ b/src/mod_pubsub/node_dag.erl
@@ -52,7 +52,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3]).
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1]).
init(Host, ServerHost, Opts) ->
@@ -173,3 +175,9 @@ set_item(Item) ->
get_item_name(Host, Node, ID) ->
node_hometree:get_item_name(Host, Node, ID).
+
+node_to_path(Node) ->
+ node_hometree:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_hometree:path_to_node(Path).
diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl
index 2dc1d3f30..05e7d8494 100644
--- a/src/mod_pubsub/node_dispatch.erl
+++ b/src/mod_pubsub/node_dispatch.erl
@@ -66,7 +66,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -197,3 +199,8 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+node_to_path(Node) ->
+ node_flat:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat:path_to_node(Path).
diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl
index 6e5c2372a..3e3617f54 100644
--- a/src/mod_pubsub/node_flat.erl
+++ b/src/mod_pubsub/node_flat.erl
@@ -59,7 +59,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -180,3 +182,16 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+
+node_to_path(Node) ->
+ [binary_to_list(Node)].
+
+path_to_node(Path) ->
+ case Path of
+ % default slot
+ [Node] -> list_to_binary(Node);
+ % handle old possible entries, used when migrating database content to new format
+ [Node|_] when is_list(Node) -> list_to_binary(string:join([""|Path], "/"));
+ % default case (used by PEP for example)
+ _ -> list_to_binary(Path)
+ end.
diff --git a/src/mod_pubsub/node_flat_odbc.erl b/src/mod_pubsub/node_flat_odbc.erl
index 08d818a41..973ee5018 100644
--- a/src/mod_pubsub/node_flat_odbc.erl
+++ b/src/mod_pubsub/node_flat_odbc.erl
@@ -60,7 +60,9 @@
get_item/2,
set_item/1,
get_item_name/3,
- get_last_items/3
+ get_last_items/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -186,3 +188,16 @@ get_item_name(Host, Node, Id) ->
get_last_items(NodeId, From, Count) ->
node_hometree_odbc:get_last_items(NodeId, From, Count).
+
+node_to_path(Node) ->
+ [binary_to_list(Node)].
+
+path_to_node(Path) ->
+ case Path of
+ % default slot
+ [Node] -> list_to_binary(Node);
+ % handle old possible entries, used when migrating database content to new format
+ [Node|_] when is_list(Node) -> list_to_binary(string:join([""|Path], "/"));
+ % default case (used by PEP for example)
+ _ -> list_to_binary(Path)
+ end.
diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl
index c3fa6e293..c8bb61982 100644
--- a/src/mod_pubsub/node_hometree.erl
+++ b/src/mod_pubsub/node_hometree.erl
@@ -75,7 +75,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
%% ================
@@ -204,7 +206,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
{LU, LS, LR} = LOwner,
case acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) of
allow ->
- case Node of
+ case node_to_path(Node) of
["home", Server, User | _] -> true;
_ -> false
end;
@@ -981,6 +983,14 @@ del_items(NodeId, ItemIds) ->
get_item_name(_Host, _Node, Id) ->
Id.
+node_to_path(Node) ->
+ string:tokens(binary_to_list(Node), "/").
+
+path_to_node([]) ->
+ <<>>;
+path_to_node(Path) ->
+ list_to_binary(string:join([""|Path], "/")).
+
%% @spec (Affiliation, Subscription) -> true | false
%% Affiliation = owner | member | publisher | outcast | none
%% Subscription = subscribed | none
@@ -1006,3 +1016,4 @@ first_in_list(Pred, [H | T]) ->
true -> {value, H};
_ -> first_in_list(Pred, T)
end.
+
diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl
index 4bac466db..9e4414077 100644
--- a/src/mod_pubsub/node_hometree_odbc.erl
+++ b/src/mod_pubsub/node_hometree_odbc.erl
@@ -80,7 +80,9 @@
get_item/2,
set_item/1,
get_item_name/3,
- get_last_items/3
+ get_last_items/3,
+ path_to_node/1,
+ node_to_path/1
]).
-export([
@@ -209,7 +211,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
{LU, LS, LR} = LOwner,
case acl:match_rule(ServerHost, Access, exmpp_jid:make(LU, LS, LR)) of
allow ->
- case Node of
+ case node_to_path(Node) of
["home", Server, User | _] -> true;
_ -> false
end;
@@ -1372,3 +1374,11 @@ i2l(L, N) when is_list(L) ->
C when C > N -> L;
_ -> i2l([$0|L], N)
end.
+
+node_to_path(Node) ->
+ string:tokens(binary_to_list(Node), "/").
+
+path_to_node([]) ->
+ <<>>;
+path_to_node(Path) ->
+ list_to_binary(string:join([""|Path], "/")).
diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl
index 6fdebef43..9495a3bc5 100644
--- a/src/mod_pubsub/node_mb.erl
+++ b/src/mod_pubsub/node_mb.erl
@@ -72,7 +72,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
init(Host, ServerHost, Opts) ->
@@ -202,3 +204,8 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_pep:get_item_name(Host, Node, Id).
+node_to_path(Node) ->
+ node_pep:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_pep:path_to_node(Path).
diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl
index 00d0c4095..ff397c8d2 100644
--- a/src/mod_pubsub/node_pep.erl
+++ b/src/mod_pubsub/node_pep.erl
@@ -65,7 +65,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
init(Host, ServerHost, Opts) ->
@@ -270,6 +272,12 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+node_to_path(Node) ->
+ node_flat:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat:path_to_node(Path).
+
%%%
%%% Internal
diff --git a/src/mod_pubsub/node_pep_odbc.erl b/src/mod_pubsub/node_pep_odbc.erl
index 0b16eaa60..a92e522aa 100644
--- a/src/mod_pubsub/node_pep_odbc.erl
+++ b/src/mod_pubsub/node_pep_odbc.erl
@@ -70,7 +70,9 @@
get_item/2,
set_item/1,
get_item_name/3,
- get_last_items/3
+ get_last_items/3,
+ node_to_path/1,
+ path_to_node/1
]).
init(Host, ServerHost, Opts) ->
@@ -306,6 +308,11 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree_odbc:get_item_name(Host, Node, Id).
+node_to_path(Node) ->
+ node_flat_odbc:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat_odbc:path_to_node(Path).
%%%
%%% Internal
diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl
index 1cff4c11b..cdc50cd62 100644
--- a/src/mod_pubsub/node_private.erl
+++ b/src/mod_pubsub/node_private.erl
@@ -69,7 +69,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -197,3 +199,9 @@ set_item(Item) ->
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+
+node_to_path(Node) ->
+ node_flat:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat:path_to_node(Path).
diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl
index d227f6b89..7872bea02 100644
--- a/src/mod_pubsub/node_public.erl
+++ b/src/mod_pubsub/node_public.erl
@@ -69,7 +69,9 @@
get_item/7,
get_item/2,
set_item/1,
- get_item_name/3
+ get_item_name/3,
+ node_to_path/1,
+ path_to_node/1
]).
@@ -196,3 +198,9 @@ set_item(Item) ->
%% node id.
get_item_name(Host, Node, Id) ->
node_hometree:get_item_name(Host, Node, Id).
+
+node_to_path(Node) ->
+ node_flat:node_to_path(Node).
+
+path_to_node(Path) ->
+ node_flat:path_to_node(Path).
diff --git a/src/mod_pubsub/nodetree_dag.erl b/src/mod_pubsub/nodetree_dag.erl
index 64b4adde1..0c749fb51 100644
--- a/src/mod_pubsub/nodetree_dag.erl
+++ b/src/mod_pubsub/nodetree_dag.erl
@@ -32,7 +32,7 @@
get_parentnodes_tree/3,
get_subnodes/3,
get_subnodes_tree/3,
- create_node/5,
+ create_node/6,
delete_node/2]).
-include_lib("stdlib/include/qlc.hrl").
@@ -53,14 +53,12 @@
%% API
%%====================================================================
init(Host, ServerHost, Opts) ->
- nodetree_tree:init(Host, ServerHost, Opts),
- mnesia:transaction(fun create_node/5,
- [Host, [], "default", service_jid(ServerHost), []]).
+ nodetree_tree:init(Host, ServerHost, Opts).
terminate(Host, ServerHost) ->
nodetree_tree:terminate(Host, ServerHost).
-create_node(Key, NodeID, Type, Owner, Options) ->
+create_node(Key, NodeID, Type, Owner, Options, Parents) ->
OwnerJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
case find_node(Key, NodeID) of
false ->
@@ -68,6 +66,7 @@ create_node(Key, NodeID, Type, Owner, Options) ->
N = #pubsub_node{nodeid = oid(Key, NodeID),
id = ID,
type = Type,
+ parents = Parents,
owners = [OwnerJID],
options = Options},
case set_node(N) of
diff --git a/src/mod_pubsub/nodetree_tree.erl b/src/mod_pubsub/nodetree_tree.erl
index 9ea51658e..610a9851e 100644
--- a/src/mod_pubsub/nodetree_tree.erl
+++ b/src/mod_pubsub/nodetree_tree.erl
@@ -56,7 +56,7 @@
get_parentnodes_tree/3,
get_subnodes/3,
get_subnodes_tree/3,
- create_node/5,
+ create_node/6,
delete_node/2
]).
@@ -158,6 +158,12 @@ get_parentnodes_tree(Host, Node, From) ->
%% From = mod_pubsub:jid()
get_subnodes(Host, Node, _From) ->
get_subnodes(Host, Node).
+get_subnodes(Host, <<>>) ->
+ Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _},
+ parents = Parents} = N <- mnesia:table(pubsub_node),
+ Host == NHost,
+ Parents == []]),
+ qlc:e(Q);
get_subnodes(Host, Node) ->
Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _},
parents = Parents} = N <- mnesia:table(pubsub_node),
@@ -172,12 +178,21 @@ get_subnodes(Host, Node) ->
get_subnodes_tree(Host, Node, _From) ->
get_subnodes_tree(Host, Node).
get_subnodes_tree(Host, Node) ->
- mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) ->
- case lists:prefix(Node, N) and (H == Host) of
- true -> [R | Acc];
- _ -> Acc
- end
- end, [], pubsub_node).
+ case get_node(Host, Node) of
+ {error, _} ->
+ [];
+ Rec ->
+ BasePlugin = list_to_atom("node_"++Rec#pubsub_node.type),
+ BasePath = BasePlugin:node_to_path(Node),
+ mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) ->
+ Plugin = list_to_atom("node_"++R#pubsub_node.type),
+ Path = Plugin:node_to_path(N),
+ case lists:prefix(BasePath, Path) and (H == Host) of
+ true -> [R | Acc];
+ false -> Acc
+ end
+ end, [], pubsub_node)
+ end.
%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason}
%% Host = mod_pubsub:host() | mod_pubsub:jid()
@@ -185,26 +200,27 @@ get_subnodes_tree(Host, Node) ->
%% NodeType = mod_pubsub:nodeType()
%% Owner = mod_pubsub:jid()
%% Options = list()
-create_node(Host, Node, Type, Owner, Options) ->
+create_node(Host, Node, Type, Owner, Options, Parents) ->
BJID = jlib:short_prepd_bare_jid(Owner),
case mnesia:read({pubsub_node, {Host, Node}}) of
[] ->
- {ParentNode, ParentExists} =
+ ParentExists =
case Host of
{_U, _S, _R} ->
%% This is special case for PEP handling
%% PEP does not uses hierarchy
- {[], true};
+ true;
_ ->
- Parent = lists:sublist(Node, length(Node) - 1),
- case Parent of
- [] ->
- {[], true};
- _ ->
+ case Parents of
+ [] -> true;
+ [Parent | _] ->
case mnesia:read({pubsub_node, {Host, Parent}}) of
- [] -> {Parent, false};
- _ -> {Parent, lists:member(BJID, Parent#pubsub_node.owners)}
- end
+ [#pubsub_node{owners = [{[], Host, []}]}] -> true;
+ [#pubsub_node{owners = Owners}] -> lists:member(BJID, Owners);
+ _ -> false
+ end;
+ _ ->
+ false
end
end,
case ParentExists of
@@ -212,7 +228,7 @@ create_node(Host, Node, Type, Owner, Options) ->
NodeId = pubsub_index:new(node),
mnesia:write(#pubsub_node{nodeid = {Host, Node},
id = NodeId,
- parents = [ParentNode],
+ parents = Parents,
type = Type,
owners = [BJID],
options = Options}),
diff --git a/src/mod_pubsub/nodetree_tree_odbc.erl b/src/mod_pubsub/nodetree_tree_odbc.erl
index 4d1995f1f..4853992d3 100644
--- a/src/mod_pubsub/nodetree_tree_odbc.erl
+++ b/src/mod_pubsub/nodetree_tree_odbc.erl
@@ -59,7 +59,7 @@
get_parentnodes_tree/3,
get_subnodes/3,
get_subnodes_tree/3,
- create_node/5,
+ create_node/6,
delete_node/2
]).
@@ -208,30 +208,37 @@ get_subnodes_tree(Host, Node) ->
%% NodeType = mod_pubsub:nodeType()
%% Owner = mod_pubsub:jid()
%% Options = list()
-create_node(Host, Node, Type, _Owner, Options) ->
+create_node(Host, Node, Type, Owner, Options, Parents) ->
+ BJID = jlib:short_prepd_bare_jid(Owner),
case nodeid(Host, Node) of
{error, 'item_not_found'} ->
- {ParentNode, ParentExists} = case Host of
- {_U, _S, _R} ->
+ ParentExists = case Host of
+ {_, _, _} ->
%% This is special case for PEP handling
%% PEP does not uses hierarchy
- {[], true};
+ true;
_ ->
- case lists:sublist(Node, length(Node) - 1) of
- [] ->
- {[], true};
- Parent ->
+ case Parents of
+ [] -> true;
+ [Parent | _] ->
case nodeid(Host, Parent) of
- {result, _} -> {Parent, true};
- _ -> {Parent, false}
- end
+ {result, PNodeId} ->
+ case nodeowners(PNodeId) of
+ [{[], Host, []}] -> true;
+ Owners -> lists:member(BJID, Owners)
+ end;
+ _ ->
+ false
+ end;
+ _ ->
+ false
end
end,
case ParentExists of
true ->
case set_node(#pubsub_node{
nodeid={Host, Node},
- parents=[ParentNode],
+ parents=Parents,
type=Type,
options=Options}) of
{result, NodeId} -> {ok, NodeId};
@@ -286,8 +293,8 @@ raw_to_node(Host, {Node, Parent, Type, NodeId}) ->
[]
end,
#pubsub_node{
- nodeid = {Host, string_to_node(Host, Node)},
- parents = [string_to_node(Host, Parent)],
+ nodeid = {Host, ?PUBSUB:string_to_node(Node)},
+ parents = [?PUBSUB:string_to_node(Parent)],
id = NodeId,
type = Type,
options = Options}.
@@ -296,7 +303,10 @@ raw_to_node(Host, {Node, Parent, Type, NodeId}) ->
%% Record = mod_pubsub:pubsub_node()
set_node(Record) ->
{Host, Node} = Record#pubsub_node.nodeid,
- [Parent] = Record#pubsub_node.parents,
+ Parent = case Record#pubsub_node.parents of
+ [] -> <<>>;
+ [First | _] -> First
+ end,
Type = Record#pubsub_node.type,
H = ?PUBSUB:escape(Host),
N = ?PUBSUB:escape(?PUBSUB:node_to_string(Node)),
@@ -353,5 +363,8 @@ nodeid(Host, Node) ->
{error, 'item_not_found'}
end.
-string_to_node({_, _, _}, Node) -> Node;
-string_to_node(_, Node) -> ?PUBSUB:string_to_node(Node).
+nodeowners(NodeId) ->
+ {result, Res} = node_hometree_odbc:get_node_affiliations(NodeId),
+ lists:foldl(fun({LJID, owner}, Acc) -> [LJID|Acc];
+ (_, Acc) -> Acc
+ end, [], Res).
diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl
index 6285d724c..5dddd4aab 100644
--- a/src/mod_pubsub/nodetree_virtual.erl
+++ b/src/mod_pubsub/nodetree_virtual.erl
@@ -50,7 +50,7 @@
get_nodes/1,
get_subnodes/3,
get_subnodes_tree/3,
- create_node/5,
+ create_node/6,
delete_node/2
]).
@@ -133,7 +133,7 @@ get_subnodes_tree(_Host, _Node) ->
%% @doc No node record is stored on database. Any valid node
%% is considered as already created.
%% default allowed nodes: /home/host/user/any/node/name
-create_node(Host, Node, _Type, Owner, _Options) ->
+create_node(Host, Node, _Type, Owner, _Options, _Parents) ->
UserName = exmpp_jid:prep_node_as_list(Owner),
UserHost = exmpp_jid:prep_domain_as_list(Owner),
case Node of