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