From 8ce1e790ac788b8a0c3a2cab352dbb25f4b374f4 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 20 Oct 2009 15:03:07 +0000 Subject: [PATCH] does not use slash as default separator in nodename (EJAB-667) SVN Revision: 2687 --- src/mod_pubsub/gen_pubsub_node.erl | 4 +- src/mod_pubsub/gen_pubsub_nodetree.erl | 2 +- src/mod_pubsub/mod_pubsub.erl | 140 ++++++++++++------------- src/mod_pubsub/mod_pubsub_odbc.erl | 119 +++++++++------------ src/mod_pubsub/node_buddy.erl | 11 +- src/mod_pubsub/node_club.erl | 11 +- src/mod_pubsub/node_dag.erl | 11 +- src/mod_pubsub/node_dispatch.erl | 11 +- 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 | 10 +- src/mod_pubsub/node_pep.erl | 10 +- src/mod_pubsub/node_pep_odbc.erl | 9 +- src/mod_pubsub/node_private.erl | 11 +- src/mod_pubsub/node_public.erl | 11 +- src/mod_pubsub/nodetree_dag.erl | 9 +- src/mod_pubsub/nodetree_tree.erl | 60 ++++++----- src/mod_pubsub/nodetree_tree_odbc.erl | 59 +++++++---- src/mod_pubsub/nodetree_virtual.erl | 4 +- src/mod_pubsub/pubsub_odbc.patch | 135 +++++++++++++++--------- 22 files changed, 423 insertions(+), 267 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 f55694500..84cf8f61b 100644 --- a/src/mod_pubsub/gen_pubsub_nodetree.erl +++ b/src/mod_pubsub/gen_pubsub_nodetree.erl @@ -51,7 +51,7 @@ behaviour_info(callbacks) -> {get_parentnodes_tree, 3}, {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 a449644f8..d7d1fffe3 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -268,11 +268,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. @@ -403,7 +403,28 @@ 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) -> @@ -548,7 +569,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 @@ -644,7 +665,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> disco_sm_items(Acc, From, To, [], _Lang) -> Host = To#jid.lserver, - case tree_action(Host, get_subnodes, [Host, [], From]) of + case tree_action(Host, get_subnodes, [Host, <<>>, From]) of [] -> Acc; Nodes -> @@ -662,8 +683,9 @@ disco_sm_items(Acc, From, To, [], _Lang) -> {result, NodeItems ++ Items} end; -disco_sm_items(Acc, From, To, Node, _Lang) -> +disco_sm_items(Acc, From, To, SNode, _Lang) -> Host = To#jid.lserver, + Node = string_to_node(SNode), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> % TODO call get_items/6 instead for access control (EJAB-1033) case node_call(Type, get_items, [NodeId, From]) of @@ -677,13 +699,8 @@ disco_sm_items(Acc, From, To, Node, _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]), - {xmlelement, "item", - [{"jid", SBJID}, - {"name", Name}], - []} + {xmlelement, "item", [{"jid", SBJID}, {"name", Name}], []} end, AllItems), {result, NodeItems ++ Items}; _ -> @@ -1066,7 +1083,7 @@ iq_disco_info(Host, SNode, From, Lang) -> end, Node = string_to_node(RealSNode), case Node of - [] -> + <<>> -> {result, [{xmlelement, "identity", [{"category", "pubsub"}, @@ -1085,24 +1102,17 @@ 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 - {xmlelement, "item", [{"jid", Host}, - {"node", SN}, - {"name", RN}], []} - end, tree_action(Host, get_subnodes, [Host, [], From]))}; + fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) -> + {result, Path} = node_call(Type, node_to_path, [SubNode]), + [Name|_] = lists:reverse(Path), + {xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []} + end, tree_action(Host, get_subnodes, [Host, <<>>, From]))}; iq_disco_items(Host, Item, From) -> 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) @@ -1112,17 +1122,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), - {xmlelement, "item", [{"jid", Host}, {"node", SN}, - {"name", RN}], []} + {xmlelement, "item", [{"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, [Host, Node, RN]), - {xmlelement, "item", [{"jid", Host}, {"node", SN}, - {"name", Name}], []} + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), + {xmlelement, "item", [{"jid", Host}, {"name", Name}], []} end, NodeItems), {result, Nodes ++ Items} end, @@ -1178,10 +1183,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> {xmlelement, _, _, SubEls} = SubEl, case xml:remove_cdata(SubEls) of [{xmlelement, Name, Attrs, Els} | Rest] -> - Node = case Host of - {_, _, _} -> xml:get_attr_s("node", Attrs); - _ -> string_to_node(xml:get_attr_s("node", Attrs)) - end, + Node = string_to_node(xml:get_attr_s("node", Attrs)), case {IQType, Name} of {set, "create"} -> Config = case Rest of @@ -1282,10 +1284,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> Action = xml:remove_cdata(SubEls), case Action of [{xmlelement, Name, Attrs, Els}] -> - Node = case Host of - {_, _, _} -> xml:get_attr_s("node", Attrs); - _ -> string_to_node(xml:get_attr_s("node", Attrs)) - end, + Node = string_to_node(xml:get_attr_s("node", Attrs)), case {IQType, Name} of {get, "configure"} -> get_configure(Host, ServerHost, Node, From, Lang); @@ -1521,7 +1520,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> end, Stanza = event_stanza( [{xmlelement, "subscription", - [{"node", SNode}, {"jid", jlib:jid_to_string(JID)}] ++ SubAttrs, + [{"jid", jlib:jid_to_string(JID)}|nodeAttr(SNode)] ++ SubAttrs, []}]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. @@ -1531,10 +1530,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 = jlib:string_to_jid(SSubscriber), Allow = case SAllow of "1" -> true; @@ -1664,21 +1660,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:jid_tolower(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, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [{xmlelement, "create", nodeAttr(NewNode), []}]}]}; - Error -> Error + Error -> + Error end; false -> %% Service does not support instant nodes @@ -1686,7 +1679,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 xml:remove_cdata(Configuration) of [] -> @@ -1711,9 +1703,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}} -> @@ -2499,9 +2500,8 @@ read_sub(Subscriber, Node, NodeID, SubID, Lang) -> {error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; {result, #pubsub_subscription{options = Options}} -> {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), - OptionsEl = {xmlelement, "options", [{"node", node_to_string(Node)}, - {"jid", jlib:jid_to_string(Subscriber)}, - {"subid", SubID}], + OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)}, + {"subid", SubID}|nodeAttr(Node)], [XdataEl]}, PubsubEl = {xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [OptionsEl]}, {result, PubsubEl} @@ -2591,7 +2591,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) -> case Node of - [] -> + <<>> -> [{xmlelement, "subscription", [{"subscription", subscription_to_string(Subscription)}|nodeAttr(SubsNode)], []}]; @@ -2606,7 +2606,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> case Node of - [] -> + <<>> -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(SubJID)}, {"subid", SubID}, @@ -2623,7 +2623,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> case Node of - [] -> + <<>> -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(SubJID)}, {"subscription", subscription_to_string(Subscription)}|nodeAttr(SubsNode)], @@ -2805,14 +2805,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() @@ -3044,7 +3038,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}; % _ -> @@ -3161,7 +3155,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. @@ -3689,6 +3683,8 @@ uniqid() -> lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). % node attributes +nodeAttr(Node) when is_list(Node) -> + [{"node", Node}]; nodeAttr(Node) -> [{"node", node_to_string(Node)}]. diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index ff06097f1..8b3d38f4a 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -266,11 +266,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. @@ -372,7 +372,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 @@ -468,7 +468,7 @@ disco_sm_features(Acc, From, To, Node, _Lang) -> disco_sm_items(Acc, From, To, [], _Lang) -> Host = To#jid.lserver, - case tree_action(Host, get_subnodes, [Host, [], From]) of + case tree_action(Host, get_subnodes, [Host, <<>>, From]) of [] -> Acc; Nodes -> @@ -486,8 +486,9 @@ disco_sm_items(Acc, From, To, [], _Lang) -> {result, NodeItems ++ Items} end; -disco_sm_items(Acc, From, To, Node, _Lang) -> +disco_sm_items(Acc, From, To, SNode, _Lang) -> Host = To#jid.lserver, + Node = string_to_node(SNode), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> % TODO call get_items/6 instead for access control (EJAB-1033) case node_call(Type, get_items, [NodeId, From]) of @@ -501,13 +502,8 @@ disco_sm_items(Acc, From, To, Node, _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]), - {xmlelement, "item", - [{"jid", SBJID}, - {"name", Name}], - []} + {xmlelement, "item", [{"jid", SBJID}, {"name", Name}], []} end, AllItems), {result, NodeItems ++ Items}; _ -> @@ -892,7 +888,7 @@ iq_disco_info(Host, SNode, From, Lang) -> end, Node = string_to_node(RealSNode), case Node of - [] -> + <<>> -> {result, [{xmlelement, "identity", [{"category", "pubsub"}, @@ -912,24 +908,17 @@ 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 - {xmlelement, "item", [{"jid", Host}, - {"node", SN}, - {"name", RN}], []} - end, tree_action(Host, get_subnodes, [Host, [], From]))}; + fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) -> + {result, Path} = node_call(Type, node_to_path, [SubNode]), + [Name|_] = lists:reverse(Path), + {xmlelement, "item", [{"jid", Host}, {"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) @@ -939,17 +928,12 @@ 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), - {xmlelement, "item", [{"jid", Host}, {"node", SN}, - {"name", RN}], []} + {xmlelement, "item", [{"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, [Host, Node, RN]), - {xmlelement, "item", [{"jid", Host}, {"node", SN}, - {"name", Name}], []} + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), + {xmlelement, "item", [{"jid", Host}, {"name", Name}], []} end, NodeItems), {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} end, @@ -1005,10 +989,7 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, Access, Plugins) -> {xmlelement, _, _, SubEls} = SubEl, case xml:remove_cdata(SubEls) of [{xmlelement, Name, Attrs, Els} | Rest] -> - Node = case Host of - {_, _, _} -> xml:get_attr_s("node", Attrs); - _ -> string_to_node(xml:get_attr_s("node", Attrs)) - end, + Node = string_to_node(xml:get_attr_s("node", Attrs)), case {IQType, Name} of {set, "create"} -> Config = case Rest of @@ -1112,10 +1093,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> end, xml:remove_cdata(SubEls)), case Action of [{xmlelement, Name, Attrs, Els}] -> - Node = case Host of - {_, _, _} -> xml:get_attr_s("node", Attrs); - _ -> string_to_node(xml:get_attr_s("node", Attrs)) - end, + Node = string_to_node(xml:get_attr_s("node", Attrs)), case {IQType, Name} of {get, "configure"} -> get_configure(Host, ServerHost, Node, From, Lang); @@ -1352,7 +1330,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) -> end, Stanza = event_stanza( [{xmlelement, "subscription", - [{"node", SNode}, {"jid", jlib:jid_to_string(JID)}] ++ SubAttrs, + [{"jid", jlib:jid_to_string(JID)}|nodeAttr(SNode)] ++ SubAttrs, []}]), ejabberd_router ! {route, service_jid(Host), JID, Stanza}. @@ -1362,10 +1340,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 = jlib:string_to_jid(SSubscriber), Allow = case SAllow of "1" -> true; @@ -1495,21 +1470,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:jid_tolower(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, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [{xmlelement, "create", nodeAttr(NewNode), []}]}]}; - Error -> Error + Error -> + Error end; false -> %% Service does not support instant nodes @@ -1517,7 +1489,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 xml:remove_cdata(Configuration) of [] -> @@ -1542,9 +1513,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}} -> @@ -2329,9 +2309,8 @@ read_sub(Subscriber, Node, NodeID, SubID, Lang) -> {error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; {result, #pubsub_subscription{options = Options}} -> {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), - OptionsEl = {xmlelement, "options", [{"node", node_to_string(Node)}, - {"jid", jlib:jid_to_string(Subscriber)}, - {"subid", SubID}], + OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)}, + {"subid", SubID}|nodeAttr(Node)], [XdataEl]}, PubsubEl = {xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [OptionsEl]}, {result, PubsubEl} @@ -2421,7 +2400,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription}) -> case Node of - [] -> + <<>> -> [{xmlelement, "subscription", [{"subscription", subscription_to_string(Subscription)}|nodeAttr(SubsNode)], []}]; @@ -2436,7 +2415,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> []; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubID, SubJID}) -> case Node of - [] -> + <<>> -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(SubJID)}, {"subid", SubID}, @@ -2453,7 +2432,7 @@ get_subscriptions(Host, Node, JID, Plugins) when is_list(Plugins) -> end; ({#pubsub_node{nodeid = {_, SubsNode}}, Subscription, SubJID}) -> case Node of - [] -> + <<>> -> [{xmlelement, "subscription", [{"jid", jlib:jid_to_string(SubJID)}, {"subscription", subscription_to_string(Subscription)}|nodeAttr(SubsNode)], @@ -2635,14 +2614,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() @@ -2874,7 +2847,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}; % _ -> @@ -2991,7 +2964,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. @@ -3575,6 +3548,8 @@ uniqid() -> lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])). % node attributes +nodeAttr(Node) when is_list(Node) -> + [{"node", Node}]; nodeAttr(Node) -> [{"node", node_to_string(Node)}]. diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl index 20b679ca7..c952252bd 100644 --- a/src/mod_pubsub/node_buddy.erl +++ b/src/mod_pubsub/node_buddy.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 ]). @@ -193,3 +195,10 @@ 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 3c1596cd6..d77cde702 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,10 @@ 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 f28c338d8..b70169460 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,10 @@ 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 8c2c7d0f4..d81848fe3 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 ]). @@ -196,3 +198,10 @@ 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 67b95973a..854e64321 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 ]). @@ -179,3 +181,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 f073c70a8..0e6c8faa1 100644 --- a/src/mod_pubsub/node_flat_odbc.erl +++ b/src/mod_pubsub/node_flat_odbc.erl @@ -63,7 +63,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 ]). @@ -196,3 +198,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 efb14c922..5ce7b9724 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 ]). %% ================ @@ -203,7 +205,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> _ -> case acl:match_rule(ServerHost, Access, LOwner) of allow -> - case Node of + case node_to_path(Node) of ["home", Server, User | _] -> true; _ -> false end; @@ -989,6 +991,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 @@ -1014,3 +1024,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 1401fb0ce..141d3275c 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -81,7 +81,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([ @@ -210,7 +212,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -> _ -> case acl:match_rule(ServerHost, Access, LOwner) of allow -> - case Node of + case node_to_path(Node) of ["home", Server, User | _] -> true; _ -> false end; @@ -1209,6 +1211,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 diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl index c1accca3c..a497c17ba 100644 --- a/src/mod_pubsub/node_mb.erl +++ b/src/mod_pubsub/node_mb.erl @@ -71,7 +71,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) -> @@ -201,3 +203,9 @@ 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 754312b83..5bdb4915f 100644 --- a/src/mod_pubsub/node_pep.erl +++ b/src/mod_pubsub/node_pep.erl @@ -64,7 +64,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) -> @@ -268,6 +270,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 95c737a6a..e24c35a14 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) -> @@ -305,6 +307,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 054485ef5..10f019305 100644 --- a/src/mod_pubsub/node_private.erl +++ b/src/mod_pubsub/node_private.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 ]). @@ -196,3 +198,10 @@ 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 ee440f933..5e26d8273 100644 --- a/src/mod_pubsub/node_public.erl +++ b/src/mod_pubsub/node_public.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 ]). @@ -194,3 +196,10 @@ 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 7ddcaf18a..d7094e3e0 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 ba8168f52..39160e7b5 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 ]). @@ -160,13 +160,13 @@ 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) -> -% mnesia:foldl(fun(#pubsub_node{nodeid = {H, _}, parents = Parents} = N, Acc) -> -% case lists:member(Node, Parents) and (Host == H) of -% true -> [N | Acc]; -% false -> Acc -% end -% end, [], pubsub_node). Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _}, parents = Parents} = N <- mnesia:table(pubsub_node), Host == NHost, @@ -181,12 +181,21 @@ get_subnodes_tree(Host, Node, _From) -> %% Node = mod_pubsub:pubsubNode() %% From = mod_pubsub:jid() 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]; - false -> 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() @@ -194,26 +203,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:jid_tolower(jlib:jid_remove_resource(Owner)), case catch 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; _ -> - case lists:sublist(Node, length(Node) - 1) of - [] -> - {[], true}; - Parent -> + case Parents of + [] -> true; + [Parent|_] -> case catch mnesia:read({pubsub_node, {Host, Parent}}) of - [#pubsub_node{owners = [{[], Host, []}]}] -> {Parent, true}; - [#pubsub_node{owners = Owners}] -> {Parent, lists:member(BJID, Owners)}; - _ -> {Parent, false} - end + [#pubsub_node{owners = [{[], Host, []}]}] -> true; + [#pubsub_node{owners = Owners}] -> lists:member(BJID, Owners); + _ -> false + end; + _ -> + false end end, case ParentExists of @@ -221,7 +231,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 ab7525c60..d8ff30832 100644 --- a/src/mod_pubsub/nodetree_tree_odbc.erl +++ b/src/mod_pubsub/nodetree_tree_odbc.erl @@ -57,7 +57,7 @@ get_parentnodes_tree/3, get_subnodes/3, get_subnodes_tree/3, - create_node/5, + create_node/6, delete_node/2 ]). @@ -209,30 +209,39 @@ get_subnodes_tree(Host, Node) -> %% NodeType = mod_pubsub:nodeType() %% Owner = mod_pubsub:jid() %% Options = list() -create_node(Host, Node, Type, _Owner, Options) -> +%% Parents = list() +create_node(Host, Node, Type, Owner, Options, Parents) -> + BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), case nodeid(Host, Node) of {error, ?ERR_ITEM_NOT_FOUND} -> - {ParentNode, ParentExists} = case Host of - {_U, _S, _R} -> - %% This is special case for PEP handling - %% PEP does not uses hierarchy - {[], true}; - _ -> - case lists:sublist(Node, length(Node) - 1) of - [] -> - {[], true}; - Parent -> - case nodeid(Host, Parent) of - {result, _} -> {Parent, true}; - _ -> {Parent, false} + ParentExists = + case Host of + {_U, _S, _R} -> + %% This is special case for PEP handling + %% PEP does not uses hierarchy + true; + _ -> + case Parents of + [] -> true; + [Parent|_] -> + case nodeid(Host, Parent) of + {result, PNodeId} -> + case nodeowners(PNodeId) of + [{[], Host, []}] -> true; + Owners -> lists:member(BJID, Owners) + end; + _ -> + false + end; + _ -> + false end - 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}; @@ -285,8 +294,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}. @@ -295,7 +304,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)), @@ -352,5 +364,8 @@ nodeid(Host, Node) -> {error, ?ERR_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 24330e506..ec35b91d9 100644 --- a/src/mod_pubsub/nodetree_virtual.erl +++ b/src/mod_pubsub/nodetree_virtual.erl @@ -51,7 +51,7 @@ get_parentnodes_tree/3, get_subnodes/3, get_subnodes_tree/3, - create_node/5, + create_node/6, delete_node/2 ]). @@ -157,7 +157,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) -> {error, {virtual, {Host, Node}}}. %% @spec (Host, Node) -> [mod_pubsub:node()] diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 99c0a7809..a23147bc5 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-10-13 18:30:32.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-10-13 18:30:47.000000000 +0200 +--- mod_pubsub.erl 2009-10-20 16:33:47.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-10-20 16:33:26.000000000 +0200 @@ -42,7 +42,7 @@ %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see %%% XEP-0060 section 12.18. @@ -49,7 +49,18 @@ init_nodes(Host, ServerHost, NodeTree, Plugins), State = #state{host = Host, server_host = ServerHost, -@@ -277,178 +275,6 @@ +@@ -269,207 +267,14 @@ + + init_nodes(Host, ServerHost, _NodeTree, Plugins) -> + %% TODO, this call should be done plugin side +- case lists:member("hometree", Plugins) of ++ case lists:member("hometree_odbc", Plugins) of + true -> +- 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"); ++ 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. @@ -179,7 +190,28 @@ - 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) -> @@ -228,7 +260,7 @@ send_queue(State, Msg) -> Pid = State#state.send_loop, case is_process_alive(Pid) of -@@ -471,17 +297,15 @@ +@@ -492,17 +297,15 @@ %% for each node From is subscribed to %% and if the node is so configured, send the last published item to From lists:foreach(fun(PType) -> @@ -252,7 +284,7 @@ true -> % resource not concerned about that subscription ok -@@ -808,10 +632,10 @@ +@@ -825,10 +628,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -265,7 +297,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -926,7 +750,8 @@ +@@ -943,7 +746,8 @@ sub_el = SubEl} = IQ -> {xmlelement, _, QAttrs, _} = SubEl, Node = xml:get_attr_s("node", QAttrs), @@ -275,7 +307,7 @@ {result, IQRes} -> jlib:iq_to_xml( IQ#iq{type = result, -@@ -1031,7 +856,7 @@ +@@ -1048,7 +852,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -284,7 +316,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1047,8 +872,9 @@ +@@ -1064,8 +868,9 @@ []; true -> [{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} | @@ -296,7 +328,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1076,14 +902,15 @@ +@@ -1093,21 +898,22 @@ {xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []}, {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []}, {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++ @@ -313,19 +345,18 @@ -iq_disco_items(Host, [], From) -> +iq_disco_items(Host, [], From, _RSM) -> {result, lists:map( - fun(#pubsub_node{nodeid = {_, SubNode}}) -> - SN = node_to_string(SubNode), -@@ -1093,7 +920,7 @@ - {"node", SN}, - {"name", RN}], []} - end, tree_action(Host, get_subnodes, [Host, [], From]))}; + fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) -> + {result, Path} = node_call(Type, node_to_path, [SubNode]), + [Name|_] = lists:reverse(Path), + {xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []} + end, tree_action(Host, get_subnodes, [Host, <<>>, From]))}; -iq_disco_items(Host, Item, From) -> +iq_disco_items(Host, Item, From, RSM) -> case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1105,10 +932,10 @@ - %% TODO That is, remove name attribute (or node?, please check for 2.1) +@@ -1115,10 +921,10 @@ + Node = string_to_node(SNode), Action = fun(#pubsub_node{type = Type, id = NodeId}) -> - % TODO call get_items/6 instead for access control (EJAB-1033) @@ -338,16 +369,16 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1124,7 +951,7 @@ - {xmlelement, "item", [{"jid", Host}, {"node", SN}, - {"name", Name}], []} +@@ -1129,7 +935,7 @@ + {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), + {xmlelement, "item", [{"jid", Host}, {"name", Name}], []} end, NodeItems), - {result, Nodes ++ Items} + {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1256,7 +1083,8 @@ +@@ -1258,7 +1064,8 @@ (_, Acc) -> Acc end, [], xml:remove_cdata(Els)), @@ -357,7 +388,7 @@ {get, "subscriptions"} -> get_subscriptions(Host, Node, From, Plugins); {get, "affiliations"} -> -@@ -1279,7 +1107,9 @@ +@@ -1281,7 +1088,9 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> {xmlelement, _, _, SubEls} = SubEl, @@ -367,8 +398,8 @@ + end, xml:remove_cdata(SubEls)), case Action of [{xmlelement, Name, Attrs, Els}] -> - Node = case Host of -@@ -1405,7 +1235,8 @@ + Node = string_to_node(xml:get_attr_s("node", Attrs)), +@@ -1404,7 +1213,8 @@ _ -> [] end end, @@ -378,7 +409,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1445,7 +1276,7 @@ +@@ -1444,7 +1254,7 @@ %%% authorization handling @@ -387,7 +418,7 @@ Lang = "en", %% TODO fix Stanza = {xmlelement, "message", [], -@@ -1474,7 +1305,7 @@ +@@ -1473,7 +1283,7 @@ [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]}, lists:foreach(fun(Owner) -> ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza} @@ -396,7 +427,7 @@ find_authorization_response(Packet) -> {xmlelement, _Name, _Attrs, Els} = Packet, -@@ -1541,8 +1372,8 @@ +@@ -1537,8 +1347,8 @@ "true" -> true; _ -> false end, @@ -407,7 +438,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1728,7 +1559,7 @@ +@@ -1729,7 +1539,7 @@ Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [{xmlelement, "create", nodeAttr(Node), []}]}], @@ -416,7 +447,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1836,7 +1667,7 @@ +@@ -1837,7 +1647,7 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -425,7 +456,7 @@ {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, -@@ -1844,7 +1675,7 @@ +@@ -1845,7 +1655,7 @@ error -> {"", "", ""}; J -> jlib:jid_tolower(J) end, @@ -434,7 +465,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1863,9 +1694,13 @@ +@@ -1864,9 +1674,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -451,7 +482,7 @@ end end, if -@@ -2196,7 +2031,7 @@ +@@ -2197,7 +2011,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -460,7 +491,7 @@ MaxItems = if SMaxItems == "" -> get_max_items_node(Host); -@@ -2235,11 +2070,11 @@ +@@ -2236,11 +2050,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -474,7 +505,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2252,7 +2087,8 @@ +@@ -2253,7 +2067,8 @@ %% number of items sent to MaxItems: {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [{xmlelement, "items", nodeAttr(Node), @@ -484,7 +515,7 @@ Error -> Error end -@@ -2284,16 +2120,27 @@ +@@ -2285,16 +2100,27 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -518,7 +549,7 @@ send_items(Host, Node, NodeId, Type, LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2419,29 +2266,12 @@ +@@ -2420,29 +2246,12 @@ error -> {error, ?ERR_BAD_REQUEST}; _ -> @@ -551,7 +582,7 @@ end, Entities), {result, []}; _ -> -@@ -2494,11 +2324,11 @@ +@@ -2495,11 +2304,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -562,10 +593,10 @@ {result, #pubsub_subscription{options = Options}} -> - {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), + {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), - OptionsEl = {xmlelement, "options", [{"node", node_to_string(Node)}, - {"jid", jlib:jid_to_string(Subscriber)}, - {"subid", SubID}], -@@ -2525,7 +2355,7 @@ + OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)}, + {"subid", SubID}|nodeAttr(Node)], + [XdataEl]}, +@@ -2525,7 +2334,7 @@ end. set_options_helper(Configuration, JID, NodeID, SubID, Type) -> @@ -574,7 +605,7 @@ {result, GoodSubOpts} -> GoodSubOpts; _ -> invalid end, -@@ -2554,7 +2384,7 @@ +@@ -2554,7 +2363,7 @@ write_sub(_Subscriber, _NodeID, _SubID, invalid) -> {error, extended_error(?ERR_BAD_REQUEST, "invalid-options")}; write_sub(Subscriber, NodeID, SubID, Options) -> @@ -583,7 +614,7 @@ {error, notfound} -> {error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; {result, _} -> -@@ -2722,8 +2552,8 @@ +@@ -2722,8 +2531,8 @@ {"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]}, ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza} end, @@ -594,7 +625,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -3013,7 +2843,7 @@ +@@ -3007,7 +2816,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -603,7 +634,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3027,9 +2857,9 @@ +@@ -3021,9 +2830,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -615,7 +646,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3227,6 +3057,30 @@ +@@ -3221,6 +3030,30 @@ Result end. @@ -646,7 +677,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3613,7 +3467,13 @@ +@@ -3607,7 +3440,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -661,7 +692,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3633,13 +3493,13 @@ +@@ -3627,13 +3466,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -677,7 +708,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3652,8 +3512,14 @@ +@@ -3646,8 +3485,14 @@ end end, Trans). @@ -694,7 +725,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3661,6 +3527,15 @@ +@@ -3655,6 +3500,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, ?ERR_INTERNAL_SERVER_ERROR}; @@ -710,7 +741,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, ?ERR_INTERNAL_SERVER_ERROR}; -@@ -3669,6 +3544,17 @@ +@@ -3663,6 +3517,17 @@ {error, ?ERR_INTERNAL_SERVER_ERROR} end.