PubSub/PEP API change for major optimization
authorChristophe Romain <christophe.romain@process-one.net>
Thu, 30 Apr 2009 05:18:06 +0000 (05:18 +0000)
committerChristophe Romain <christophe.romain@process-one.net>
Thu, 30 Apr 2009 05:18:06 +0000 (05:18 +0000)
SVN Revision: 2048

18 files changed:
ChangeLog
src/mod_pubsub/gen_pubsub_node.erl
src/mod_pubsub/gen_pubsub_nodetree.erl
src/mod_pubsub/mod_pubsub.erl
src/mod_pubsub/node.template
src/mod_pubsub/node_buddy.erl
src/mod_pubsub/node_club.erl
src/mod_pubsub/node_default.erl
src/mod_pubsub/node_dispatch.erl
src/mod_pubsub/node_flat.erl
src/mod_pubsub/node_mb.erl
src/mod_pubsub/node_pep.erl
src/mod_pubsub/node_private.erl
src/mod_pubsub/node_public.erl
src/mod_pubsub/nodetree_default.erl
src/mod_pubsub/nodetree_virtual.erl
src/mod_pubsub/pubsub.hrl
src/mod_pubsub/pubsub_index.erl [new file with mode: 0644]

index 7b0ba705d18bbff3fe63c3c7ceb8f34188cc89e3..a71eebde244238cff32963f4225ef372b5f7c869 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2009-04-24  Christophe Romain <christophe.romain@process-one.net>
+
+       * src/mod_pubsub/mod_pubsub.erl: API change for major optimization
+       * src/mod_pubsub/pubsub.hrl: Likewise
+       * src/mod_pubsub/nodetree_default.erl: Likewise
+       * src/mod_pubsub/nodetree_virtual.erl: Likewise
+       * src/mod_pubsub/node_mb.erl: Likewise
+       * src/mod_pubsub/node_dispatch.erl: Likewise
+       * src/mod_pubsub/node_buddy.erl: Likewise
+       * src/mod_pubsub/node_private.erl: Likewise
+       * src/mod_pubsub/node_public.erl: Likewise
+       * src/mod_pubsub/node_default.erl: Likewise
+       * src/mod_pubsub/node_pep.erl: Likewise
+       * src/mod_pubsub/node_club.erl: Likewise
+       * src/mod_pubsub/node_flat.erl: Likewise
+       * src/mod_pubsub/node.template: Likewise
+       * src/mod_pubsub/gen_pubsub_node.erl: Likewise
+       * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise
+
 2009-04-28  Badlop  <badlop@process-one.net>
 
        * src/ejabberd_hooks.erl: Support distributed hooks (EJAB-829)
index 91b8163bcc1d18f444be682a66d76fcde819b007..b4264f809a62f344936f1cf333cc51e049cb5b65 100644 (file)
@@ -43,29 +43,29 @@ behaviour_info(callbacks) ->
      {options, 0},
      {features, 0},
      {create_node_permission, 6},
-     {create_node, 3},
-     {delete_node, 2},
-     {purge_node, 3},
-     {subscribe_node, 8},
-     {unsubscribe_node, 5},
-     {publish_item, 7},
-     {delete_item, 4},
-     {remove_extra_items, 4},
-     {get_node_affiliations, 2},
+     {create_node, 2},
+     {delete_node, 1},
+     {purge_node, 2},
+     {subscribe_node, 7},
+     {unsubscribe_node, 4},
+     {publish_item, 6},
+     {delete_item, 3},
+     {remove_extra_items, 3},
+     {get_node_affiliations, 1},
      {get_entity_affiliations, 2},
-     {get_affiliation, 3},
-     {set_affiliation, 4},
-     {get_node_subscriptions, 2},
+     {get_affiliation, 2},
+     {set_affiliation, 3},
+     {get_node_subscriptions, 1},
      {get_entity_subscriptions, 2},
-     {get_subscription, 3},
-     {set_subscription, 4},
-     {get_states, 2},
-     {get_state, 3},
+     {get_subscription, 2},
+     {set_subscription, 3},
+     {get_states, 1},
+     {get_state, 2},
      {set_state, 1},
-     {get_items, 7},
-     {get_items, 3},
-     {get_item, 8},
-     {get_item, 3},
+     {get_items, 6},
+     {get_items, 2},
+     {get_item, 7},
+     {get_item, 2},
      {set_item, 1},
      {get_item_name, 3}
     ];
index 8bd35f51d50ab71f2b43dc57ce40aa3cf2985c4f..941748e680a1097dd7dbfccb8d4c1b366991dc74 100644 (file)
@@ -47,7 +47,7 @@ behaviour_info(callbacks) ->
         {get_nodes, 2},
         {get_nodes, 1},
         {get_subnodes, 3},
-        {get_subnodes_tree, 2},
+        {get_subnodes_tree, 3},
         {create_node, 5},
         {delete_node, 2}
        ];
index 98ae6b950e94006ea77e737e15d6656cc071d3b1..b51d7dfeb6b3cec63095e6bc2e020b35a524c8be 100644 (file)
@@ -39,7 +39,7 @@
 
 -module(mod_pubsub).
 -author('christophe.romain@process-one.net').
--version('1.12-04').
+-version('1.12-05').
 
 -behaviour(gen_server).
 -behaviour(gen_mod).
         unsubscribe_node/5,
         publish_item/6,
         delete_item/4,
-        send_items/4,
-        broadcast_stanza/6,
+        send_items/6,
+        broadcast_stanza/7,
         get_configure/5,
         set_configure/5,
-        get_items/3,
         tree_action/3,
-        node_action/3,
         node_action/4
        ]).
 
@@ -165,8 +163,9 @@ init([ServerHost, Opts]) ->
     Access = gen_mod:get_opt(access_createnode, Opts, all),
     PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false),
     IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
-    mod_disco:register_feature(ServerHost, ?NS_PUBSUB),
+    pubsub_index:init(Host, ServerHost, Opts),
     {Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
+    mod_disco:register_feature(ServerHost, ?NS_PUBSUB),
     ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]),
     ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}),
     ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}),
@@ -193,7 +192,7 @@ init([ServerHost, Opts]) ->
            ok
     end,
     ejabberd_router:register_route(Host),
-    update_database(Host),
+    update_database(Host, ServerHost),
     init_nodes(Host, ServerHost),
     State = #state{host = Host,
                server_host = ServerHost,
@@ -202,7 +201,7 @@ init([ServerHost, Opts]) ->
                pep_sendlast_offline = PepOffline,
                nodetree = NodeTree,
                plugins = Plugins},
-    SendLoop = spawn(?MODULE, send_loop, [State]),  %% TODO supervise that process
+    SendLoop = spawn(?MODULE, send_loop, [State]),
     {ok, State#state{send_loop = SendLoop}}.
 
 %% @spec (Host, ServerHost, Opts) -> Plugins
@@ -247,7 +246,7 @@ init_nodes(Host, ServerHost) ->
     create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), ?STDNODE),
     ok.
 
-update_database(Host) ->
+update_database(Host, ServerHost) ->
     mnesia:del_table_index(pubsub_node, type),
     mnesia:del_table_index(pubsub_node, parentid),
     case catch mnesia:table_info(pubsub_node, attributes) of
@@ -255,14 +254,14 @@ update_database(Host) ->
            ?INFO_MSG("upgrade pubsub tables",[]),
            F = fun() ->
                        lists:foldl(
-                         fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, RecList) ->
+                         fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) ->
                                  ItemsList =
                                      lists:foldl(
                                        fun({item, IID, Publisher, Payload}, Acc) ->
-                                               C = {Publisher, unknown},
-                                               M = {Publisher, now()},
+                                               C = {unknown, Publisher},
+                                               M = {now(), Publisher},
                                                mnesia:write(
-                                                 #pubsub_item{itemid = {IID, NodeId},
+                                                 #pubsub_item{itemid = {IID, NodeIdx},
                                                               creation = C,
                                                               modification = M,
                                                               payload = Payload}),
@@ -280,7 +279,7 @@ update_database(Host) ->
                                                              end
                                                      end, [], ItemsList),
                                                mnesia:write(
-                                                 #pubsub_state{stateid = {JID, NodeId},
+                                                 #pubsub_state{stateid = {JID, NodeIdx},
                                                                items = UsrItems,
                                                                affiliation = Aff,
                                                                subscription = Sub}),
@@ -290,12 +289,13 @@ update_database(Host) ->
                                                end
                                        end, [], Entities),
                                  mnesia:delete({pubsub_node, NodeId}),
-                                 [#pubsub_node{nodeid = NodeId,
-                                               parentid = ParentId,
+                                 {[#pubsub_node{nodeid = NodeId,
+                                               id = NodeIdx,
+                                               parent = element(2, ParentId),
                                                owners = Owners,
                                                options = Options} |
-                                  RecList]
-                         end, [],
+                                  RecList], NodeIdx + 1}
+                         end, {[], 1},
                          mnesia:match_object(
                            {pubsub_node, {Host, '_'}, '_', '_'}))
                end,
@@ -314,10 +314,62 @@ update_database(Host) ->
                {aborted, Reason} ->
                    ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason])
            end;
+       [nodeid, parentid, type, owners, options] ->
+           F = fun({pubsub_node, NodeId, {_, Parent}, Type, Owners, Options}) ->
+                   #pubsub_node{
+                       nodeid = NodeId,
+                       id = 0,
+                       parent = Parent,
+                       type = Type,
+                       owners = Owners,
+                       options = Options}
+               end,
+           mnesia:transform_table(pubsub_node, F, [nodeid, id, parent, type, owners, options]),
+           FNew = fun() ->
+               lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) ->
+                   mnesia:write(PubsubNode#pubsub_node{id = NodeIdx}),
+                   lists:foreach(fun(#pubsub_state{stateid = StateId} = State) ->
+                       {JID, _} = StateId,
+                       mnesia:delete({pubsub_state, StateId}),
+                       mnesia:write(State#pubsub_state{stateid = {JID, NodeIdx}})
+                   end, mnesia:match_object(#pubsub_state{stateid = {'_', NodeId}, _ = '_'})),
+                   lists:foreach(fun(#pubsub_item{itemid = ItemId} = Item) ->
+                       {IID, _} = ItemId,
+                       {M1, M2} = Item#pubsub_item.modification,
+                       {C1, C2} = Item#pubsub_item.creation,
+                       mnesia:delete({pubsub_item, ItemId}),
+                       mnesia:write(Item#pubsub_item{itemid = {IID, NodeIdx},
+                                                   modification = {M2, M1},
+                                                   creation = {C2, C1}})
+                   end, mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'})),
+                   NodeIdx + 1
+               end, 1, mnesia:match_object(
+                       {pubsub_node, {Host, '_'}, '_', '_', '_', '_', '_'})
+                   ++  mnesia:match_object(
+                       {pubsub_node, {{'_', ServerHost, '_'}, '_'}, '_', '_', '_', '_', '_'}))
+               end,
+           case mnesia:transaction(FNew) of
+               {atomic, Result} ->
+                   ?INFO_MSG("Pubsub tables updated correctly: ~p", [Result]);
+               {aborted, Reason} ->
+                   ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason])
+           end;
        _ ->
            ok
     end.
 
+send_queue(State, Msg) ->
+    Pid = State#state.send_loop,
+    case is_process_alive(Pid) of
+    true ->
+       Pid ! Msg,
+       State;
+    false ->
+       SendLoop = spawn(?MODULE, send_loop, [State]),
+       SendLoop ! Msg,
+       State#state{send_loop = SendLoop}
+    end.
+
 send_loop(State) ->
     receive
     {presence, JID, Pid} ->
@@ -327,16 +379,16 @@ send_loop(State) ->
        BJID = jlib:jid_remove_resource(LJID),
        %% for each node From is subscribed to
        %% and if the node is so configured, send the last published item to From
-       lists:foreach(fun(Type) ->
-           {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]),
+       lists:foreach(fun(PType) ->
+           {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]),
            lists:foreach(
                fun({Node, subscribed, SubJID}) -> 
                    if (SubJID == LJID) or (SubJID == BJID) ->
                        case tree_action(Host, get_node, [Host, Node, JID]) of
-                           #pubsub_node{options = Options} ->
+                           #pubsub_node{options = Options, type = Type, id = NodeId} ->
                                case get_option(Options, send_last_published_item) of
                                    on_sub_and_presence ->
-                                       send_items(Host, Node, SubJID, last);
+                                       send_items(Host, Node, NodeId, Type, SubJID, last);
                                    _ ->
                                        ok
                                end;
@@ -390,7 +442,7 @@ send_loop(State) ->
        Owner = jlib:jid_remove_resource(jlib:jid_tolower(JID)),
        Host = State#state.host,
        ServerHost = State#state.server_host,
-       lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
+       lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) ->
            case get_option(Options, send_last_published_item) of
                on_sub_and_presence ->
                    lists:foreach(fun(Resource) ->
@@ -408,7 +460,7 @@ send_loop(State) ->
                                            element(2, get_roster_info(OU, OS, LJID, Grps))
                                end,
                                if Subscribed ->
-                                   send_items(Owner, Node, LJID, last);
+                                   send_items(Owner, Node, NodeId, Type, LJID, last);
                                true ->
                                    ok
                                end;
@@ -482,21 +534,20 @@ disco_sm_features(Acc, From, To, Node, _Lang) ->
     end.
 
 disco_sm_items(Acc, From, To, [], _Lang) ->
-    %% TODO, use iq_disco_items(Host, [], From)
     Host = To#jid.lserver,
-    LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
     case tree_action(Host, get_nodes, [Host, From]) of
        [] ->
            Acc;
        Nodes ->
+           SBJID = jlib:jid_to_string(jlib:jid_remove_resource(To)),
            Items = case Acc of
                        {result, I} -> I;
                        _ -> []
                    end,
            NodeItems = lists:map(
-                         fun(Node) ->
+                         fun(#pubsub_node{nodeid = {_, Node}}) ->
                                  {xmlelement, "item",
-                                  [{"jid", jlib:jid_to_string(LJID)},
+                                  [{"jid", SBJID},
                                    {"node", node_to_string(Node)}],
                                   []}
                          end, Nodes),
@@ -504,28 +555,35 @@ disco_sm_items(Acc, From, To, [], _Lang) ->
     end;
 
 disco_sm_items(Acc, From, To, Node, _Lang) ->
-    %% TODO, use iq_disco_items(Host, Node, From)
     Host = To#jid.lserver,
-    LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
-    case get_items(Host, Node, From) of
-       [] ->
-           Acc;
-       AllItems ->
-           Items = case Acc of
+    Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
+       case node_call(Type, get_items, [NodeId, From]) of
+           {result, []} ->
+               none;
+           {result, AllItems} ->
+               SBJID = jlib:jid_to_string(jlib:jid_remove_resource(To)),
+               Items = case Acc of
                        {result, I} -> I;
                        _ -> []
                    end,
-           NodeItems = lists:map(
-                         fun(#pubsub_item{itemid = Id}) ->
+               NodeItems = lists:map(
+                         fun(#pubsub_item{itemid = {Id, _}}) ->
                                  %% "jid" is required by XEP-0030, and
                                  %% "node" is forbidden by XEP-0060.
-                                 {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]),
+                                 {result, Name} = node_call(Type, get_item_name, [Host, Node, Id]),
                                  {xmlelement, "item",
-                                  [{"jid", jlib:jid_to_string(LJID)},
+                                  [{"jid", SBJID},
                                    {"name", Name}],
                                   []}
                          end, AllItems),
-           {result, NodeItems ++ Items}
+               {result, NodeItems ++ Items};
+           _ ->
+               none
+       end
+    end,
+    case transaction(Host, Node, Action, sync_dirty) of
+       {result, {_, Items}} -> {result, Items};
+       _ -> Acc
     end.
 
 %% -------
@@ -597,20 +655,18 @@ handle_call(stop, _From, State) ->
 %% @private
 handle_cast({presence, JID, Pid}, State) ->
     %% A new resource is available. send last published items
-    State#state.send_loop ! {presence, JID, Pid},
-    {noreply, State};
+    {noreply, send_queue(State, {presence, JID, Pid})};
 
 handle_cast({presence, User, Server, Resources, JID}, State) ->
     %% A new resource is available. send last published PEP items
-    State#state.send_loop ! {presence, User, Server, Resources, JID},
-    {noreply, State};
+    {noreply, send_queue(State, {presence, User, Server, Resources, JID})};
 
 handle_cast({remove_user, LUser, LServer}, State) ->
     Host = State#state.host,
     Owner = jlib:make_jid(LUser, LServer, ""),
     %% remove user's subscriptions
-    lists:foreach(fun(Type) ->
-       {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]),
+    lists:foreach(fun(PType) ->
+       {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]),
        lists:foreach(fun
            ({Node, subscribed, JID}) ->
                unsubscribe_node(Host, Node, Owner, JID, all);
@@ -807,7 +863,7 @@ node_disco_features(Host, Node, From) ->
     node_disco_info(Host, Node, From, false, true).
 node_disco_info(Host, Node, From, Identity, Features) ->
     Action =
-       fun(#pubsub_node{type = Type}) ->
+       fun(#pubsub_node{type = Type, id = NodeId}) ->
                I = case Identity of
                        false ->
                            [];
@@ -817,7 +873,7 @@ node_disco_info(Host, Node, From, Identity, Features) ->
                                    [] ->
                                        ["leaf"]; %% No sub-nodes: it's a leaf node
                                    _ ->
-                                       case node_call(Type, get_items, [Host, Node, From]) of
+                                       case node_call(Type, get_items, [NodeId, From]) of
                                            {result, []} -> ["collection"];
                                            {result, _} -> ["leaf", "collection"];
                                            _ -> []
@@ -840,10 +896,17 @@ node_disco_info(Host, Node, From, Identity, Features) ->
                %% TODO: add meta-data info (spec section 5.4)
                {result, I ++ F}
        end,
-    transaction(Host, Node, Action, sync_dirty).
+    case transaction(Host, Node, Action, sync_dirty) of
+       {result, {_, Result}} -> {result, Result};
+       Other -> Other
+    end.
 
 iq_disco_info(Host, SNode, From, Lang) ->
-    Node = string_to_node(SNode),
+    [RealSNode|_] = case SNode of
+       [] -> [[]];
+       _ -> string:tokens(SNode, "!")
+    end,
+    Node = string_to_node(RealSNode),
     case Node of
        [] ->
            {result,
@@ -857,7 +920,7 @@ iq_disco_info(Host, SNode, From, Lang) ->
                {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
             lists:map(fun(Feature) ->
                 {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []}
-            end, features(Host, SNode))};
+            end, features(Host, Node))};
        _ ->
            node_disco_info(Host, Node, From)
     end.
@@ -881,10 +944,10 @@ iq_disco_items(Host, Item, From) ->
            %% 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)
+           %% TODO That is, remove name attribute (or node?, please check for 2.1)
            Action =
-               fun(#pubsub_node{type = Type}) ->
-                       NodeItems = case node_call(Type, get_items, [Host, Node, From]) of
+               fun(#pubsub_node{type = Type, id = NodeId}) ->
+                       NodeItems = case node_call(Type, get_items, [NodeId, From]) of
                                        {result, I} -> I;
                                        _ -> []
                                    end,
@@ -904,7 +967,10 @@ iq_disco_items(Host, Item, From) ->
                                  end, NodeItems),
                        {result, Nodes ++ Items}
                end,
-           transaction(Host, Node, Action, sync_dirty)
+           case transaction(Host, Node, Action, sync_dirty) of
+               {result, {_, Result}} -> {result, Result};
+               Other -> Other
+           end
     end.
 
 iq_local(From, To, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang} = IQ) ->
@@ -1087,7 +1153,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
 
 %%% authorization handling
 
-send_authorization_request(Host, Node, Subscriber) ->
+send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) ->
     Lang = "en", %% TODO fix
     Stanza = {xmlelement, "message",
              [],
@@ -1114,16 +1180,9 @@ send_authorization_request(Host, Node, Subscriber) ->
                   {"type", "boolean"},
                   {"label", translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?")}],
                  [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
-    case tree_action(Host, get_node, [Host, Node, Subscriber]) of
-       #pubsub_node{owners = Owners} ->
-           lists:foreach(
-             fun(Owner) ->
-                     ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
-             end, Owners),
-           ok;
-       _ ->
-           ok
-    end.
+    lists:foreach(fun(Owner) ->
+       ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
+    end, Owners).
 
 find_authorization_response(Packet) ->
     {xmlelement, _Name, _Attrs, Els} = Packet,
@@ -1188,11 +1247,9 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
                        "true" -> true;
                        _ -> false
                    end,
-           Action = fun(#pubsub_node{type = Type,
-                                     %%options = Options,
-                                     owners = Owners}) ->
+           Action = fun(#pubsub_node{type = Type, owners = Owners, id = NodeId}) ->
                             IsApprover = lists:member(jlib:jid_tolower(jlib:jid_remove_resource(From)), Owners),
-                            {result, Subscription} = node_call(Type, get_subscription, [Host, Node, Subscriber]),
+                            {result, Subscription} = node_call(Type, get_subscription, [NodeId, Subscriber]),
                             if
                                 not IsApprover ->
                                     {error, ?ERR_FORBIDDEN};
@@ -1204,7 +1261,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
                                                           false -> none
                                                       end,
                                     send_authorization_approval(Host, Subscriber, SNode, NewSubscription),
-                                    node_call(Type, set_subscription, [Host, Node, Subscriber, NewSubscription])
+                                    node_call(Type, set_subscription, [NodeId, Subscriber, NewSubscription])
                             end
                     end,
            case transaction(Host, Node, Action, sync_dirty) of
@@ -1212,7 +1269,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
                    ejabberd_router:route(
                     To, From,
                     jlib:make_error_reply(Packet, Error));
-               {result, _NewSubscription} ->
+               {result, {_, _NewSubscription}} ->
                    %% XXX: notify about subscription state change, section 12.11
                    ok;
                _ ->
@@ -1292,7 +1349,6 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
 %%</ul>
 create_node(Host, ServerHost, Node, Owner, Type) ->
     create_node(Host, ServerHost, Node, Owner, Type, all, []).
-
 create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
     case lists:member("instant-nodes", features(Type)) of
        true ->
@@ -1343,13 +1399,10 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
                        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
-                                   ok ->
-                                       node_call(Type, create_node, [Host, Node, Owner]);
-                                   {error, ?ERR_CONFLICT} ->
-                                       case proplists:get_value(virtual_tree, tree_call(Host, options, [])) of
-                                           true -> node_call(Type, create_node, [Host, Node, Owner]);
-                                           _ -> {error, ?ERR_CONFLICT}
-                                       end;
+                                   {ok, NodeId} ->
+                                       node_call(Type, create_node, [NodeId, Owner]);
+                                   {error, {virtual, NodeId}} ->
+                                       node_call(Type, create_node, [NodeId, Owner]);
                                    Error ->
                                        Error
                                end;
@@ -1361,12 +1414,6 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
                      [{xmlelement, "create", [{"node", node_to_string(Node)}],
                        []}]}],
            case transaction(CreateNode, transaction) of
-               {error, Error} ->
-                   %% in case we change transaction to sync_dirty...
-                   %%node_action:
-                   %%  node_call(Type, delete_node, [Host, Node]),
-                   %%  tree_call(Host, delete_node, [Host, Node]),
-                   {error, Error};
                {result, {Result, broadcast}} ->
                    %%Lang = "en", %% TODO: fix
                    %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
@@ -1381,7 +1428,12 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
                {result, default} ->
                    {result, Reply};
                {result, Result} ->
-                   {result, Result}
+                   {result, Result};
+               Error ->
+                   %% in case we change transaction to sync_dirty...
+                   %%  node_call(Type, delete_node, [Host, Node]),
+                   %%  tree_call(Host, delete_node, [Host, Node]),
+                   Error
            end;
        Error ->
            Error
@@ -1404,11 +1456,11 @@ delete_node(_Host, [], _Owner) ->
     %% Node is the root
     {error, ?ERR_NOT_ALLOWED};
 delete_node(Host, Node, Owner) ->
-    Action = fun(#pubsub_node{type = Type}) ->
-                    case node_call(Type, get_affiliation, [Host, Node, Owner]) of
+    Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
+                    case node_call(Type, get_affiliation, [NodeId, Owner]) of
                         {result, owner} ->
                             Removed = tree_call(Host, delete_node, [Host, Node]),
-                            node_call(Type, delete_node, [Host, Removed]);
+                            node_call(Type, delete_node, [Removed]);
                         _ ->
                             %% Entity is not an owner
                             {error, ?ERR_FORBIDDEN}
@@ -1416,28 +1468,29 @@ delete_node(Host, Node, Owner) ->
             end,
     Reply = [],
     case transaction(Host, Node, Action, transaction) of
-       {error, Error} ->
-           {error, Error};
-       {result, {Result, broadcast, Removed}} ->
-           lists:foreach(fun(RNode) ->
-               broadcast_removed_node(Host, RNode)
+       {result, {_, {Result, broadcast, Removed}}} ->
+           lists:foreach(fun({RNode, RSubscriptions}) ->
+               {RH, RN} = RNode#pubsub_node.nodeid,
+               NodeId = RNode#pubsub_node.id,
+               Type = RNode#pubsub_node.type,
+               Options = RNode#pubsub_node.options,
+               broadcast_removed_node(RH, RN, NodeId, Type, Options, RSubscriptions)
            end, Removed),
            case Result of
                default -> {result, Reply};
                _ -> {result, Result}
            end;
-       {result, {Result, Removed}} ->
-           lists:foreach(fun(RNode) ->
-               broadcast_removed_node(Host, RNode)
-           end, Removed),
+       {result, {_, {Result, _Removed}}} ->
            case Result of
                default -> {result, Reply};
                _ -> {result, Result}
            end;
-       {result, default} ->
+       {result, {_, default}} ->
            {result, Reply};
-       {result, Result} ->
-           {result, Result}
+       {result, {_, Result}} ->
+           {result, Result};
+       Error ->
+           Error
     end.
 
 %% @spec (Host, Node, From, JID) ->
@@ -1468,7 +1521,7 @@ subscribe_node(Host, Node, From, JID) ->
                     J -> jlib:jid_tolower(J)
                 end,
     SubId = uniqid(),
-    Action = fun(#pubsub_node{options = Options, type = Type}) ->
+    Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
                     Features = features(Type),
                     SubscribeFeature = lists:member("subscribe", Features),
                     SubscribeConfig = get_option(Options, subscribe),
@@ -1496,7 +1549,7 @@ subscribe_node(Host, Node, From, JID) ->
                             {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "subscribe")};
                         true ->
                             node_call(Type, subscribe_node,
-                                      [Host, Node, From, Subscriber,
+                                      [NodeId, From, Subscriber,
                                        AccessModel, SendLast,
                                        PresenceSubscription, RosterGroup])
                     end
@@ -1515,26 +1568,28 @@ subscribe_node(Host, Node, From, JID) ->
                            end, []}]}]
            end,
     case transaction(Host, Node, Action, sync_dirty) of
-       {error, Error} ->
-           {error, Error};
-       {result, {Result, subscribed, send_last}} ->
-           send_items(Host, Node, Subscriber, last),
+       {result, {TNode, {Result, subscribed, send_last}}} ->
+           NodeId = TNode#pubsub_node.id,
+           Type = TNode#pubsub_node.type,
+           send_items(Host, Node, NodeId, Type, Subscriber, last),
            case Result of
                default -> {result, Reply(subscribed)};
                _ -> {result, Result}
            end;
-       {result, {Result, Subscription}} ->
+       {result, {TNode, {Result, Subscription}}} ->
            case Subscription of
-               pending -> send_authorization_request(Host, Node, Subscriber);
+               pending -> send_authorization_request(TNode, Subscriber);
                _ -> ok
            end,
            case Result of
                default -> {result, Reply(Subscription)};
                _ -> {result, Result}
            end;
-       {result, Result} ->
+       {result, {_, Result}} ->
            %% this case should never occure anyway
-           {result, Result}
+           {result, Result};
+       Error ->
+           Error
     end.
 
 %% @spec (Host, Noce, From, JID, SubId) -> {error, Reason} | {result, []}
@@ -1560,14 +1615,16 @@ unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) ->
                 end,
     unsubscribe_node(Host, Node, From, Subscriber, SubId);
 unsubscribe_node(Host, Node, From, Subscriber, SubId) ->
-    case node_action(Host, Node, unsubscribe_node,
-                    [Host, Node, From, Subscriber, SubId]) of
-       {error, Error} ->
-           {error, Error};
-       {result, default} ->
+    Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
+                   node_call(Type, unsubscribe_node, [NodeId, From, Subscriber, SubId])
+    end,
+    case transaction(Host, Node, Action, sync_dirty) of
+       {result, {_, default}} ->
            {result, []};
-       {result, Result} ->
-           {result, Result}
+       {result, {_, Result}} ->
+           {result, Result};
+       Error ->
+           Error
     end.
 
 %% @spec (Host::host(), ServerHost::host(), JID::jid(), Node::pubsubNode(), ItemId::string(), Payload::term())  ->
@@ -1588,7 +1645,7 @@ publish_item(Host, ServerHost, Node, Publisher, "", Payload) ->
     %% if publisher does not specify an ItemId, the service MUST generate the ItemId
     publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload);
 publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
-    Action = fun(#pubsub_node{options = Options, type = Type}) ->
+    Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
                    Features = features(Type),
                    PublishFeature = lists:member("publish", Features),
                    PublishModel = get_option(Options, publish_model),
@@ -1620,12 +1677,37 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
                            %% Publisher attempts to publish to persistent node with no item
                            {error, extended_error(?ERR_BAD_REQUEST, "item-required")};
                        true ->
-                           node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload])
+                           node_call(Type, publish_item, [NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload])
                    end
            end,
     ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]),
     Reply = [], %% TODO EJAB-909
     case transaction(Host, Node, Action, sync_dirty) of
+       {result, {TNode, {Result, broadcast, Removed}}} ->
+           NodeId = TNode#pubsub_node.id,
+           Type = TNode#pubsub_node.type,
+           Options = TNode#pubsub_node.options,
+           broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:jid_tolower(Publisher), Payload),
+           case Result of
+               default -> {result, Reply};
+               _ -> {result, Result}
+           end;
+       {result, {TNode, {default, Removed}}} ->
+           NodeId = TNode#pubsub_node.id,
+           Type = TNode#pubsub_node.type,
+           Options = TNode#pubsub_node.options,
+           broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed),
+           {result, Reply};
+       {result, {TNode, {Result, Removed}}} ->
+           NodeId = TNode#pubsub_node.id,
+           Type = TNode#pubsub_node.type,
+           Options = TNode#pubsub_node.options,
+           broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed),
+           {result, Result};
+       {result, {_, default}} ->
+           {result, Reply};
+       {result, {_, Result}} ->
+           {result, Result};
        {error, ?ERR_ITEM_NOT_FOUND} ->
            %% handles auto-create feature
            %% for automatic node creation. we'll take the default node type:
@@ -1642,25 +1724,8 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
                false ->
                    {error, ?ERR_ITEM_NOT_FOUND}
            end;
-       {error, Reason} ->
-           {error, Reason};
-       {result, {Result, broadcast, Removed}} ->
-           broadcast_retract_items(Host, Node, Removed),
-           broadcast_publish_item(Host, Node, ItemId, jlib:jid_tolower(Publisher), Payload),
-           case Result of
-               default -> {result, Reply};
-               _ -> {result, Result}
-           end;
-       {result, default, Removed} ->
-           broadcast_retract_items(Host, Node, Removed),
-           {result, Reply};
-       {result, Result, Removed} ->
-           broadcast_retract_items(Host, Node, Removed),
-           {result, Result};
-       {result, default} ->
-           {result, Reply};
-       {result, Result} ->
-           {result, Result}
+       Error ->
+           Error
     end.
 
 %% @spec (Host::host(), JID::jid(), Node::pubsubNode(), ItemId::string()) ->
@@ -1683,7 +1748,7 @@ delete_item(_, "", _, _, _) ->
     %% Request does not specify a node
     {error, extended_error(?ERR_BAD_REQUEST, "node-required")};
 delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
-    Action = fun(#pubsub_node{type = Type}) ->
+    Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
                     Features = features(Type),
                     PersistentFeature = lists:member("persistent-items", Features),
                     DeleteFeature = lists:member("delete-items", Features),
@@ -1698,23 +1763,26 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
                             %% Service does not support item deletion
                             {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "delete-items")};
                         true ->
-                            node_call(Type, delete_item, [Host, Node, Publisher, ItemId])
+                            node_call(Type, delete_item, [NodeId, Publisher, ItemId])
                     end
             end,
     Reply = [],
     case transaction(Host, Node, Action, sync_dirty) of
-       {error, Reason} ->
-           {error, Reason};
-       {result, {Result, broadcast}} ->
-           broadcast_retract_items(Host, Node, [ItemId], ForceNotify),
+       {result, {TNode, {Result, broadcast}}} ->
+           NodeId = TNode#pubsub_node.id,
+           Type = TNode#pubsub_node.type,
+           Options = TNode#pubsub_node.options,
+           broadcast_retract_items(Host, Node, NodeId, Type, Options, [ItemId], ForceNotify),
            case Result of
                default -> {result, Reply};
                _ -> {result, Result}
            end;
-       {result, default} ->
+       {result, {_, default}} ->
            {result, Reply};
-       {result, Result} ->
-           {result, Result}
+       {result, {_, Result}} ->
+           {result, Result};
+       Error ->
+           Error
     end.
 
 %% @spec (Host, JID, Node) ->
@@ -1732,7 +1800,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
 %%<li>The specified node does not exist.</li>
 %%</ul>
 purge_node(Host, Node, Owner) ->
-    Action = fun(#pubsub_node{type = Type, options = Options}) ->
+    Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
                     Features = features(Type),
                     PurgeFeature = lists:member("purge-nodes", Features),
                     PersistentFeature = lists:member("persistent-items", Features),
@@ -1748,23 +1816,26 @@ purge_node(Host, Node, Owner) ->
                             %% Node is not configured for persistent items
                             {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")};
                         true ->
-                            node_call(Type, purge_node, [Host, Node, Owner])
+                            node_call(Type, purge_node, [NodeId, Owner])
                     end
             end,
     Reply = [],
     case transaction(Host, Node, Action, sync_dirty) of
-       {error, Reason} ->
-           {error, Reason};
-       {result, {Result, broadcast}} ->
-           broadcast_purge_node(Host, Node),
+       {result, {TNode, {Result, broadcast}}} ->
+           NodeId = TNode#pubsub_node.id,
+           Type = TNode#pubsub_node.type,
+           Options = TNode#pubsub_node.options,
+           broadcast_purge_node(Host, Node, NodeId, Type, Options),
            case Result of
                default -> {result, Reply};
                _ -> {result, Result}
            end;
-       {result, default} ->
+       {result, {_, default}} ->
            {result, Reply};
-       {result, Result} ->
-           {result, Result}
+       {result, {_, Result}} ->
+           {result, Result};
+       Error ->
+           Error
     end.
 
 %% @doc <p>Return the items of a given node.</p>
@@ -1786,7 +1857,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
        {error, Error} ->
            {error, Error};
        _ ->
-           Action = fun(#pubsub_node{options = Options, type = Type}) ->
+           Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
                     Features = features(Type),
                     RetreiveFeature = lists:member("retrieve-items", Features),
                     PersistentFeature = lists:member("persistent-items", Features),
@@ -1809,15 +1880,13 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
                             {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")};
                         true ->
                             node_call(Type, get_items,
-                                      [Host, Node, From,
+                                      [NodeId, From,
                                        AccessModel, PresenceSubscription, RosterGroup,
                                        SubId])
                     end
             end,
             case transaction(Host, Node, Action, sync_dirty) of
-               {error, Reason} ->
-                   {error, Reason};
-               {result, Items} ->
+               {result, {_, Items}} ->
                    SendItems = case ItemIDs of
                        [] -> 
                            Items;
@@ -1830,47 +1899,46 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
                    %% number of items sent to MaxItems:
                    {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
                                [{xmlelement, "items", [{"node", node_to_string(Node)}],
-                                 itemsEls(lists:sublist(SendItems, MaxItems))}]}]}
+                                 itemsEls(lists:sublist(SendItems, MaxItems))}]}]};
+               Error ->
+                   Error
            end
     end.
 
-get_items(Host, Node, From) ->
-    case node_action(Host, Node, get_items, [Host, Node, From]) of
-       {result, Items} -> Items;
-       _ -> []
-    end.
-
-%% @spec (Host, Node, LJID, Number) -> any()
-%%      Host = host()
-%%      Node = pubsubNode()
+%% @spec (Host, NodeId, Type LJID, Number) -> any()
+%%      Host = pubsubHost()
+%%      NodeId = pubsubNodeId()
+%%      Type = pubsubNodeType()
 %%      LJID = {U, S, []}
 %%      Number = last | integer()
 %% @doc <p>Resend the items of a node to the user.</p>
 %% @todo use cache-last-item feature
-send_items(Host, Node, LJID, Number) ->
-    ToSend = case get_items(Host, Node, LJID) of
-       [] -> 
+send_items(Host, Node, NodeId, Type, LJID, Number) ->
+    ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
+       {result, []} -> 
            [];
-       Items ->
+       {result, Items} ->
            case Number of
                last ->
                    %%% [lists:last(Items)]  does not work on clustered table
                    [First|Tail] = Items,
                    [lists:foldl(
                        fun(CurItem, LastItem) ->
-                           {_, LTimeStamp} = LastItem#pubsub_item.creation,
-                           {_, CTimeStamp} = CurItem#pubsub_item.creation,
+                           {LTimeStamp, _} = LastItem#pubsub_item.creation,
+                           {CTimeStamp, _} = CurItem#pubsub_item.creation,
                            if
                                CTimeStamp > LTimeStamp -> CurItem;
                                true -> LastItem
                            end
                        end, First, Tail)];
                N when N > 0 ->
-                   %%% This case is buggy on clustered table due to lake of order
+                   %%% This case is buggy on clustered table due to lack of order
                    lists:nthtail(length(Items)-N, Items);
-               _ -> 
+               _ ->
                    Items
-           end
+           end;
+       _ ->
+           []
     end,
     Stanza = event_stanza(
        [{xmlelement, "items", [{"node", node_to_string(Node)}],
@@ -1894,7 +1962,7 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) ->
                               %% Service does not support retreive affiliatons
                               {{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-affiliations")}, Acc};
                           true ->
-                              {result, Affiliations} = node_action(Type, get_entity_affiliations, [Host, JID]),
+                              {result, Affiliations} = node_action(Host, Type, get_entity_affiliations, [Host, JID]),
                               {Status, [Affiliations|Acc]}
                       end
               end, {ok, []}, Plugins),
@@ -1915,10 +1983,10 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) ->
            Error
     end;
 get_affiliations(Host, Node, JID) ->
-    Action = fun(#pubsub_node{type = Type}) ->
+    Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
                     Features = features(Type),
                     RetrieveFeature = lists:member("modify-affiliations", Features),
-                    Affiliation = node_call(Type, get_affiliation, [Host, Node, JID]),
+                    Affiliation = node_call(Type, get_affiliation, [NodeId, JID]),
                     if
                         not RetrieveFeature ->
                             %% Service does not support modify affiliations
@@ -1927,15 +1995,13 @@ get_affiliations(Host, Node, JID) ->
                             %% Entity is not an owner
                             {error, ?ERR_FORBIDDEN};
                         true ->
-                            node_call(Type, get_node_affiliations, [Host, Node])
+                            node_call(Type, get_node_affiliations, [NodeId])
                     end
             end,
     case transaction(Host, Node, Action, sync_dirty) of
-       {error, Reason} ->
-           {error, Reason};
-       {result, []} ->
+       {result, {_, []}} ->
            {error, ?ERR_ITEM_NOT_FOUND};
-       {result, Affiliations} ->
+       {result, {_, Affiliations}} ->
            Entities = lists:flatmap(
                         fun({_, none}) -> [];
                            ({AJID, Affiliation}) ->
@@ -1946,7 +2012,9 @@ get_affiliations(Host, Node, JID) ->
                         end, Affiliations),
            {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}],
                       [{xmlelement, "affiliations", [{"node", node_to_string(Node)}],
-                        Entities}]}]}
+                        Entities}]}]};
+       Error ->
+           Error
     end.
 
 set_affiliations(Host, Node, From, EntitiesEls) ->
@@ -1978,12 +2046,12 @@ set_affiliations(Host, Node, From, EntitiesEls) ->
        error ->
            {error, ?ERR_BAD_REQUEST};
        _ ->
-           Action = fun(#pubsub_node{type = Type, owners = Owners}=N) ->
+           Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}=N) ->
                        case lists:member(Owner, Owners) of
                            true ->
                                lists:foreach(
                                    fun({JID, Affiliation}) ->
-                                       node_call(Type, set_affiliation, [Host, Node, JID, Affiliation]),
+                                       node_call(Type, set_affiliation, [NodeId, JID, Affiliation]),
                                        case Affiliation of
                                            owner ->
                                                NewOwner = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
@@ -2007,7 +2075,10 @@ set_affiliations(Host, Node, From, EntitiesEls) ->
                                {error, ?ERR_FORBIDDEN}
                        end
                     end,
-           transaction(Host, Node, Action, sync_dirty)
+           case transaction(Host, Node, Action, sync_dirty) of
+               {result, {_, Result}} -> {result, Result};
+               Other -> Other
+           end
     end.
 
 
@@ -2029,7 +2100,7 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) ->
                               {{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-subscriptions")}, Acc};
                           true ->
                               Subscriber = jlib:jid_remove_resource(JID),
-                              {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Subscriber]),
+                              {result, Subscriptions} = node_action(Host, Type, get_entity_subscriptions, [Host, Subscriber]),
                               {Status, [Subscriptions|Acc]}
                       end
               end, {ok, []}, Plugins),
@@ -2057,10 +2128,10 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) ->
            Error
     end;
 get_subscriptions(Host, Node, JID) ->
-    Action = fun(#pubsub_node{type = Type}) ->
+    Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
                     Features = features(Type),
                     RetrieveFeature = lists:member("manage-subscriptions", Features),
-                    Affiliation = node_call(Type, get_affiliation, [Host, Node, JID]),
+                    Affiliation = node_call(Type, get_affiliation, [NodeId, JID]),
                     if
                         not RetrieveFeature ->
                             %% Service does not support manage subscriptions
@@ -2069,15 +2140,13 @@ get_subscriptions(Host, Node, JID) ->
                             %% Entity is not an owner
                             {error, ?ERR_FORBIDDEN};
                         true ->
-                            node_call(Type, get_node_subscriptions, [Host, Node])
+                            node_call(Type, get_node_subscriptions, [NodeId])
                     end
             end,
     case transaction(Host, Node, Action, sync_dirty) of
-       {error, Reason} ->
-           {error, Reason};
-       {result, []} ->
+       {result, {_, []}} ->
            {error, ?ERR_ITEM_NOT_FOUND};
-       {result, Subscriptions} ->
+       {result, {_, Subscriptions}} ->
            Entities = lists:flatmap(
                         fun({_, none}) -> [];
                            ({AJID, Subscription}) ->
@@ -2094,7 +2163,9 @@ get_subscriptions(Host, Node, JID) ->
                         end, Subscriptions),
            {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}],
                       [{xmlelement, "subscriptions", [{"node", node_to_string(Node)}],
-                        Entities}]}]}
+                        Entities}]}]};
+       Error ->
+           Error
     end.
 
 set_subscriptions(Host, Node, From, EntitiesEls) ->
@@ -2126,18 +2197,21 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
        error ->
            {error, ?ERR_BAD_REQUEST};
        _ ->
-           Action = fun(#pubsub_node{type = Type, owners = Owners}) ->
+           Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) ->
                             case lists:member(Owner, Owners) of
                                 true ->
                                     lists:foreach(fun({JID, Subscription}) ->
-                                                          node_call(Type, set_subscription, [Host, Node, JID, Subscription])
+                                                          node_call(Type, set_subscription, [NodeId, JID, Subscription])
                                                   end, Entities),
                                     {result, []};
                                 _ ->
                                     {error, ?ERR_FORBIDDEN}
                             end
                     end,
-           transaction(Host, Node, Action, sync_dirty)
+           case transaction(Host, Node, Action, sync_dirty) of
+               {result, {_, Result}} -> {result, Result};
+               Other -> Other
+           end
     end.
 
 
@@ -2252,175 +2326,169 @@ event_stanza(Els) ->
 
 %%%%%% broadcast functions
 
-broadcast_publish_item(Host, Node, ItemId, _From, Payload) ->
-    %broadcast(Host, Node, none, true, "items", ItemEls)
-    Action =
-       fun(#pubsub_node{options = Options, type = Type}) ->
-           case node_call(Type, get_states, [Host, Node]) of
+broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) ->
+    %broadcast(Host, Node, NodeId, Options, none, true, "items", ItemEls)
+    case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+       {result, []} -> 
+           {result, false};
+       {result, Subs} ->
+           Content = case get_option(Options, deliver_payloads) of
+               true -> Payload;
+               false -> []
+           end,
+           Stanza = event_stanza(
+               [{xmlelement, "items", [{"node", node_to_string(Node)}],
+                   [{xmlelement, "item", itemAttr(ItemId), Content}]}]),
+           broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+           case Removed of
+               [] ->
+                   ok;
+               _ ->
+                   case get_option(Options, notify_retract) of
+                       true ->
+                           RetractStanza = event_stanza(
+                               [{xmlelement, "items", [{"node", node_to_string(Node)}],
+                                   [{xmlelement, "retract", itemAttr(RId), []} || RId <- Removed]}]),
+                           broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, RetractStanza);
+                       _ ->
+                           ok
+                   end
+           end,
+           {result, true};
+       _ ->
+           {result, false}
+    end.
+
+broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds) ->
+    broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, false).
+broadcast_retract_items(_Host, _Node, _NodeId, _Type, _Options, [], _ForceNotify) ->
+    {result, false};
+broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) ->
+    %broadcast(Host, Node, NodeId, Options, notify_retract, ForceNotify, "retract", RetractEls)
+    case (get_option(Options, notify_retract) or ForceNotify) of
+       true ->
+           case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
                {result, []} -> 
                    {result, false};
-               {result, States} ->
-                   Content = case get_option(Options, deliver_payloads) of
-                       true -> Payload;
-                       false -> []
-                   end,
+               {result, Subs} ->
                    Stanza = event_stanza(
                        [{xmlelement, "items", [{"node", node_to_string(Node)}],
-                        [{xmlelement, "item", itemAttr(ItemId), Content}]}]),
-                   broadcast_stanza(Host, Node, Type, Options, States, Stanza),
+                           [{xmlelement, "retract", itemAttr(ItemId), []} || ItemId <- ItemIds]}]),
+                   broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
                    {result, true};
                _ ->
                    {result, false}
-           end
-       end,
-    transaction(Host, Node, Action, sync_dirty).
-
-broadcast_retract_items(Host, Node, ItemIds) ->
-    broadcast_retract_items(Host, Node, ItemIds, false).
-broadcast_retract_items(Host, Node, ItemIds, ForceNotify) ->
-    %broadcast(Host, Node, notify_retract, ForceNotify, "retract", RetractEls)
-    Action =
-       fun(#pubsub_node{options = Options, type = Type}) ->
-           case (get_option(Options, notify_retract) or ForceNotify) of
-               true ->
-                   case node_call(Type, get_states, [Host, Node]) of
-                       {result, []} -> 
-                           {result, false};
-                       {result, States} ->
-                           RetractEls = [{xmlelement, "retract", itemAttr(ItemId), []} || ItemId <- ItemIds],
-                           Stanza = event_stanza(
-                               [{xmlelement, "items", [{"node", node_to_string(Node)}],
-                                RetractEls}]),
-                           broadcast_stanza(Host, Node, Type, Options, States, Stanza),
-                           {result, true};
-                       _ ->
-                           {result, false}
-                   end;
-               _ ->
-                   {result, false}
-           end
-       end,
-    transaction(Host, Node, Action, sync_dirty).
+           end;
+       _ ->
+           {result, false}
+    end.
 
-broadcast_purge_node(Host, Node) ->
-    %broadcast(Host, Node, notify_retract, false, "purge", [])
-    Action =
-       fun(#pubsub_node{options = Options, type = Type}) ->
-           case get_option(Options, notify_retract) of
-               true ->
-                   case node_call(Type, get_states, [Host, Node]) of
-                       {result, []} -> 
-                           {result, false};
-                       {result, States} ->
-                           Stanza = event_stanza(
-                               [{xmlelement, "purge", [{"node", node_to_string(Node)}],
-                                []}]),
-                           broadcast_stanza(Host, Node, Type, Options, States, Stanza),
-                           {result, true};
-                       _ -> 
-                           {result, false}
-                   end;
-               _ ->
+broadcast_purge_node(Host, Node, NodeId, Type, Options) ->
+    %broadcast(Host, Node, NodeId, Options, notify_retract, false, "purge", [])
+    case get_option(Options, notify_retract) of
+       true ->
+           case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+               {result, []} -> 
+                   {result, false};
+               {result, Subs} ->
+                   Stanza = event_stanza(
+                       [{xmlelement, "purge", [{"node", node_to_string(Node)}],
+                           []}]),
+                   broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+                   {result, true};
+               _ -> 
                    {result, false}
-           end
-       end,
-    transaction(Host, Node, Action, sync_dirty).
+           end;
+       _ ->
+           {result, false}
+    end.
 
-broadcast_removed_node(Host, Node) ->
-    %broadcast(Host, Node, notify_delete, false, "delete", [])
-    Action =
-       fun(#pubsub_node{options = Options, type = Type}) ->
-           case get_option(Options, notify_delete) of
-               true ->
-                   case node_call(Type, get_states, [Host, Node]) of
-                       {result, []} -> 
-                           {result, false};
-                       {result, States} ->
-                           Stanza = event_stanza(
-                               [{xmlelement, "delete", [{"node", node_to_string(Node)}],
-                                []}]),
-                           broadcast_stanza(Host, Node, Type, Options, States, Stanza),
-                           {result, true};
-                       _ ->
-                           {result, false}
-                   end;
+broadcast_removed_node(Host, Node, NodeId, Type, Options, Subs) ->
+    %broadcast(Host, Node, NodeId, Options, notify_delete, false, "delete", [])
+    case get_option(Options, notify_delete) of
+       true ->
+           case Subs of
+               [] -> 
+                   {result, false};
                _ ->
-                   {result, false}
-           end
-       end,
-    transaction(Host, Node, Action, sync_dirty).
+                   Stanza = event_stanza(
+                       [{xmlelement, "delete", [{"node", node_to_string(Node)}],
+                           []}]),
+                   broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+                   {result, true}
+           end;
+       _ ->
+           {result, false}
+    end.
 
-broadcast_config_notification(Host, Node, Lang) ->
-    %broadcast(Host, Node, notify_config, false, "items", ConfigEls)
-    Action =
-       fun(#pubsub_node{options = Options, owners = Owners, type = Type}) ->
-           case get_option(Options, notify_config) of
-               true ->
-                   case node_call(Type, get_states, [Host, Node]) of
-                       {result, []} -> 
-                           {result, false};
-                       {result, States} ->
-                           Content = case get_option(Options, deliver_payloads) of
-                               true ->
-                                   [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
-                                    get_configure_xfields(Type, Options, Lang, Owners, [])}];
-                               false ->
-                                   []
-                           end,
-                           Stanza = event_stanza(
-                               [{xmlelement, "items", [{"node", node_to_string(Node)}],
-                                [{xmlelement, "item", itemAttr("configuration"), Content}]}]),
-                           broadcast_stanza(Host, Node, Type, Options, States, Stanza),
-                           {result, true};
-                       _ -> 
-                           {result, false}
-                   end;
-               _ ->
+broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) ->
+    %broadcast(Host, Node, NodeId, Options, notify_config, false, "items", ConfigEls)
+    case get_option(Options, notify_config) of
+       true ->
+           case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+               {result, []} -> 
+                   {result, false};
+               {result, Subs} ->
+                   Content = case get_option(Options, deliver_payloads) of
+                       true ->
+                           [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
+                               get_configure_xfields(Type, Options, Lang, [])}];
+                       false ->
+                           []
+                   end,
+                   Stanza = event_stanza(
+                       [{xmlelement, "items", [{"node", node_to_string(Node)}],
+                           [{xmlelement, "item", itemAttr("configuration"), Content}]}]),
+                   broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+                   {result, true};
+               _ -> 
                    {result, false}
-           end
-       end,
-    transaction(Host, Node, Action, sync_dirty).
+           end;
+       _ ->
+           {result, false}
+    end.
 
 % TODO: merge broadcast code that way
-%broadcast(Host, Node, Feature, Force, ElName, SubEls) ->
-%    Action =
-%      fun(#pubsub_node{options = Options, type = Type}) ->
-%          case (get_option(Options, Feature) or Force) of
-%              true ->
-%                  case node_call(Type, get_states, [Host, Node]) of
-%                      {result, []} -> 
-%                          {result, false};
-%                      {result, States} ->
-%                          Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]),
-%                          broadcast_stanza(Host, Node, Type, Options, States, Stanza),
-%                          {result, true};
-%                      _ ->
-%                          {result, false}
-%                  end;
+%broadcast(Host, Node, NodeId, Type, Options, Feature, Force, ElName, SubEls) ->
+%    case (get_option(Options, Feature) or Force) of
+%      true ->
+%          case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+%              {result, []} -> 
+%                  {result, false};
+%              {result, Subs} ->
+%                  Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]),
+%                  broadcast_stanza(Host, Node, Type, Options, Subs, Stanza),
+%                  {result, true};
 %              _ ->
 %                  {result, false}
-%          end
-%      end,
-%    transaction(Host, Node, Action, sync_dirty).
+%          end;
+%      _ ->
+%          {result, false}
+%    end
 
-broadcast_stanza(Host, Node, _Type, Options, States, Stanza) ->
-    AccessModel = get_option(Options, access_model),
+broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) ->
+    %AccessModel = get_option(Options, access_model),
     PresenceDelivery = get_option(Options, presence_based_delivery),
     BroadcastAll = get_option(Options, broadcast_all_resources), %% XXX this is not standard, but usefull
     From = service_jid(Host),
     %% Handles explicit subscriptions
-    lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) ->
-       case is_to_deliver(LJID, Subs, PresenceDelivery) of
+    lists:foreach(fun({LJID, Subscription}) ->
+       case is_to_deliver(LJID, Subscription, PresenceDelivery) of
            true ->
-               To = case BroadcastAll of
-                   true -> jlib:jid_remove_resource(LJID);
-                   false -> LJID
+               LJIDs = case BroadcastAll of
+                   true ->
+                       {U, S, _} = LJID,
+                       [{U, S, R} || R <- user_resources(U, S)];
+                   false ->
+                       [LJID]
                end,
-               ejabberd_router ! {route, From, jlib:make_jid(To), Stanza};
+               lists:foreach(fun(To) ->
+                   ejabberd_router ! {route, From, jlib:make_jid(To), Stanza}
+               end, LJIDs);
            false ->
                ok
        end
-    end, States),
+    end, Subscriptions),
     %% Handles implicit presence subscriptions
     case Host of
        {LUser, LServer, LResource} ->
@@ -2444,16 +2512,16 @@ broadcast_stanza(Host, Node, _Type, Options, States, Stanza) ->
                        Contacts when is_list(Contacts) ->
                            lists:foreach(fun({U, S, _}) ->
                                spawn(fun() ->
-                                   JIDs = lists:foldl(fun(R, Acc) ->
+                                   LJIDs = lists:foldl(fun(R, Acc) ->
                                        LJID = {U, S, R}, 
                                        case is_caps_notify(LServer, Node, LJID) of
                                            true -> [LJID | Acc];
                                            false -> Acc
                                        end
                                    end, [], user_resources(U, S)),
-                                   lists:foreach(fun(JID) ->
-                                       ejabberd_router ! {route, Sender, jlib:make_jid(JID), Stanza}
-                                   end, JIDs)
+                                   lists:foreach(fun(To) ->
+                                       ejabberd_router ! {route, Sender, jlib:make_jid(To), Stanza}
+                                   end, LJIDs)
                                end)
                            end, Contacts);
                        _ ->
@@ -2496,8 +2564,8 @@ is_caps_notify(Host, Node, LJID) ->
 %%</ul>
 get_configure(Host, ServerHost, Node, From, Lang) ->
     Action =
-       fun(#pubsub_node{options = Options, owners = Owners, type = Type}) ->
-               case node_call(Type, get_affiliation, [Host, Node, From]) of
+       fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
+               case node_call(Type, get_affiliation, [NodeId, From]) of
                    {result, owner} ->
                        Groups = ejabberd_hooks:run_fold(roster_groups, ServerHost, [], [ServerHost]),
                        {result,
@@ -2507,13 +2575,16 @@ get_configure(Host, ServerHost, Node, From, Lang) ->
                             [{"node", node_to_string(Node)}],
                             [{xmlelement, "x",
                               [{"xmlns", ?NS_XDATA}, {"type", "form"}],
-                              get_configure_xfields(Type, Options, Lang, Owners, Groups)
+                              get_configure_xfields(Type, Options, Lang, Groups)
                              }]}]}]};
                    _ ->
                        {error, ?ERR_FORBIDDEN}
                end
        end,
-    transaction(Host, Node, Action, sync_dirty).
+    case transaction(Host, Node, Action, sync_dirty) of
+       {result, {_, Result}} -> {result, Result};
+       Other -> Other
+    end.
 
 get_default(Host, Node, _From, Lang) ->
     Type = select_type(Host, Host, Node),
@@ -2521,7 +2592,7 @@ get_default(Host, Node, _From, Lang) ->
     {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}],
                [{xmlelement, "default", [],
                    [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
-                       get_configure_xfields(Type, Options, Lang, [], [])
+                       get_configure_xfields(Type, Options, Lang, [])
                }]}]}]}.
 
 %% Get node option
@@ -2597,7 +2668,7 @@ max_items(Options) ->
        ?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var),
                     get_option(Options, Var), Opts)).
 
-get_configure_xfields(_Type, Options, Lang, _Owners, Groups) ->
+get_configure_xfields(_Type, Options, Lang, Groups) ->
     [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG),
      ?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads),
      ?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications),
@@ -2636,9 +2707,8 @@ set_configure(Host, Node, From, Els, Lang) ->
                    {result, []};
                {?NS_XDATA, "submit"} ->
                    Action =
-                       fun(#pubsub_node{options = Options, type = Type}=N) ->
-                               case node_call(Type, get_affiliation,
-                                              [Host, Node, From]) of
+                       fun(#pubsub_node{options = Options, type = Type, id = NodeId} = N) ->
+                               case node_call(Type, get_affiliation, [NodeId, From]) of
                                    {result, owner} ->
                                        case jlib:parse_xdata_submit(XEl) of
                                            invalid ->
@@ -2650,8 +2720,7 @@ set_configure(Host, Node, From, Els, Lang) ->
                                                          end,
                                                case set_xoption(XData, OldOpts) of
                                                    NewOpts when is_list(NewOpts) ->
-                                                       tree_call(Host, set_node,
-                                                                 [N#pubsub_node{options = NewOpts}]),
+                                                       tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]),
                                                        {result, ok};
                                                    Err ->
                                                        Err
@@ -2662,8 +2731,11 @@ set_configure(Host, Node, From, Els, Lang) ->
                                end
                        end,
                    case transaction(Host, Node, Action, transaction) of
-                       {result, ok} ->
-                           broadcast_config_notification(Host, Node, Lang),
+                       {result, {TNode, ok}} ->
+                           NodeId = TNode#pubsub_node.id,
+                           Type = TNode#pubsub_node.type,
+                           Options = TNode#pubsub_node.options,
+                           broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang),
                            {result, []};
                        Other ->
                            Other
@@ -2835,13 +2907,17 @@ features(Host, []) ->
        Acc ++ features(Plugin)
     end, [], plugins(Host)));
 features(Host, Node) ->
-    {result, Features} = node_action(Host, Node, features, []),
-    lists:usort(features() ++ Features).
+    Action = fun(#pubsub_node{type = Type}) -> {result, features(Type)} end,
+    case transaction(Host, Node, Action, sync_dirty) of
+    {result, Features} -> lists:usort(features() ++ Features);
+    _ -> features()
+    end.
 
 %% @doc <p>node tree plugin call.</p>
 tree_call({_User, Server, _Resource}, Function, Args) ->
     tree_call(Server, Function, Args);
 tree_call(Host, Function, Args) ->
+    ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]),
     Module = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of
        [{nodetree, N}] -> N;
        _ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE)
@@ -2853,6 +2929,7 @@ tree_action(Host, Function, Args) ->
 
 %% @doc <p>node plugin call.</p>
 node_call(Type, Function, Args) ->
+    ?DEBUG("node_call ~p ~p ~p",[Type, Function, Args]),
     Module = list_to_atom(?PLUGIN_PREFIX++Type),
     case catch apply(Module, Function, Args) of
        {result, Result} -> {result, Result};
@@ -2866,24 +2943,23 @@ node_call(Type, Function, Args) ->
        Result -> {result, Result} %% any other return value is forced as result
     end.
 
-node_action(Type, Function, Args) ->
+node_action(_Host, Type, Function, Args) ->
     transaction(fun() ->
                        node_call(Type, Function, Args)
                end, sync_dirty).
-node_action(Host, Node, Function, Args) ->
-    transaction(fun() ->
-                       case tree_call(Host, get_node, [Host, Node]) of
-                           #pubsub_node{type=Type} -> node_call(Type, Function, Args);
-                           Other -> Other
-                       end
-               end, sync_dirty).
 
 %% @doc <p>plugin transaction handling.</p>
 transaction(Host, Node, Action, Trans) ->
     transaction(fun() ->
                        case tree_call(Host, get_node, [Host, Node]) of
-                           Record when is_record(Record, pubsub_node) -> Action(Record);
-                           Other -> Other
+                           N when is_record(N, pubsub_node) ->
+                               case Action(N) of
+                                   {result, Result} -> {result, {N, Result}};
+                                   {atomic, {result, Result}} -> {result, {N, Result}};
+                                   Other -> Other
+                               end;
+                           Error ->
+                               Error
                        end
                end, Trans).
 
index 536f1775bd814af51e04712c7c19cf358d2a8ab1..3879266a9f9b03b92abfea27dc846fa7d503825c 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1
        ]).
 
@@ -88,7 +88,7 @@ options() ->
      {roster_groups_allowed, []},
      {publish_model, publishers},
      {max_payload_size, ?MAX_PAYLOAD_SIZE},
-     {send_last_published_item, never},
+     {send_last_published_item, on_sub_and_presence},
      {deliver_notifications, true},
      {presence_based_delivery, false}].
 
@@ -112,74 +112,74 @@ features() ->
 create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
-    node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+    node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_default:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-    node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(Host, Owner) ->
     node_default:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(Host, Node, Owner) ->
-    node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+    node_default:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId)
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId)
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
 set_item(Item) ->
     node_default:set_item(Item).
index 029543dc2698d8e69da353f4faa39511623f38dd..4caa922f30e859eeb6d94af1abc6f0c4f35b127b 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -115,74 +115,74 @@ features() ->
 create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
-    node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+    node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_default:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-    node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(Host, Owner) ->
     node_default:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(Host, Node, Owner) ->
-    node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+    node_default:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
 set_item(Item) ->
     node_default:set_item(Item).
index c164b36b3889b3256f2b645f38e600dea0b8f24a..a7de3e8558f43a815a32eb43692f22f0bf7f51e3 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -114,74 +114,74 @@ features() ->
 create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
-    node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+    node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_default:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-    node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(Host, Owner) ->
     node_default:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(Host, Node, Owner) ->
-    node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+    node_default:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
 set_item(Item) ->
     node_default:set_item(Item).
index cafd2f3e364fe930e46e51b5be7144f7ce3d3de1..ac23cf20ffc4e8152dbe3296ec49e65af2fb155a 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -192,8 +192,8 @@ features() ->
 %% <p>PubSub plugins can redefine the PubSub node creation rights as they
 %% which. They can simply delegate this check to the {@link node_default}
 %% module by implementing this function like this:
-%% ```check_create_user_permission(Host, Node, Owner, Access) ->
-%%        node_default:check_create_user_permission(Host, Node, Owner, Access).'''</p>
+%% ```check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
+%%        node_default:check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access).'''</p>
 create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
     LOwner = jlib:jid_tolower(Owner),
     {User, Server, _Resource} = LOwner,
@@ -213,35 +213,36 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
     end,
     {result, Allowed}.
 
-%% @spec (Host, Node, Owner) ->
+%% @spec (NodeId, Owner) ->
 %%               {result, Result} | exit
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      Owner = mod_pubsub:jid()
 %% @doc <p></p>
-create_node(Host, Node, Owner) ->
+create_node(NodeId, Owner) ->
     OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
-    set_state(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner}),
+    set_state(#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}),
     {result, {default, broadcast}}.
 
-%% @spec (Host, Removed) -> ok
-%%      Host = mod_pubsub:host()
+%% @spec (Removed) -> ok
 %%      Removed = [mod_pubsub:pubsubNode()]
 %% @doc <p>purge items of deleted nodes after effective deletion.</p>
-delete_node(Host, Removed) ->
-    lists:foreach(
-      fun(Node) ->
-             lists:foreach(
-               fun(#pubsub_state{stateid = StateId, items = Items}) ->
-                       del_items(Host, Node, Items),
-                       del_state(StateId)
-               end,
-               mnesia:match_object(
-                 #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}))
-      end, Removed),
-    {result, {default, broadcast, Removed}}.
-
-%% @spec (Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+delete_node(Removed) ->
+    Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) ->
+                {J, S}
+        end,
+    Reply = lists:map(
+       fun(#pubsub_node{id = NodeId} = PubsubNode) ->
+           {result, States} = get_states(NodeId),
+           lists:foreach(
+               fun(#pubsub_state{stateid = {LJID, _}, items = Items}) ->
+                   del_items(NodeId, Items),
+                   del_state(NodeId, LJID)
+           end, States),
+           {PubsubNode, lists:map(Tr, States)}
+       end, Removed),
+    {result, {default, broadcast, Reply}}.
+
+%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
 %%              {error, Reason} | {result, Result}
 %% @doc <p>Accepts or rejects subcription requests on a PubSub node.</p>
 %% <p>The mechanism works as follow:
@@ -274,17 +275,18 @@ delete_node(Host, Removed) ->
 %%   to completly disable persistance.</li></ul>
 %% </p>
 %% <p>In the default plugin module, the record is unchanged.</p>
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel,
               SendLast, PresenceSubscription, RosterGroup) ->
     SubKey = jlib:jid_tolower(Subscriber),
     GenKey = jlib:jid_remove_resource(SubKey),
     Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     SubState = case SubKey of
        GenKey -> GenState;
-       _ -> get_state(Host, Node, SubKey)
+       _ -> get_state(NodeId, SubKey)
        end,
     Affiliation = GenState#pubsub_state.affiliation,
+    Subscription = SubState#pubsub_state.subscription,
     Whitelisted = lists:member(Affiliation, [member, publisher, owner]),
     if
        not Authorized ->
@@ -293,7 +295,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
        Affiliation == outcast ->
            %% Requesting entity is blocked
            {error, ?ERR_FORBIDDEN};
-       SubState#pubsub_state.subscription == pending ->
+       Subscription == pending ->
            %% Requesting entity has pending subscription
            {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "pending-subscription")};
        (AccessModel == presence) and (not PresenceSubscription) ->
@@ -336,23 +338,22 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
            end
     end.
 
-%% @spec (Host, Node, Sender, Subscriber, SubID) ->
+%% @spec (NodeId, Sender, Subscriber, SubID) ->
 %%                     {error, Reason} | {result, []}
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      Sender = mod_pubsub:jid()
 %%      Subscriber = mod_pubsub:jid()
 %%      SubID = string()
 %%      Reason = mod_pubsub:stanzaError()
 %% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p>
-unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
+unsubscribe_node(NodeId, Sender, Subscriber, _SubId) ->
     SubKey = jlib:jid_tolower(Subscriber),
     GenKey = jlib:jid_remove_resource(SubKey),
     Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     SubState = case SubKey of
        GenKey -> GenState;
-       _ -> get_state(Host, Node, SubKey)
+       _ -> get_state(NodeId, SubKey)
        end,
     if
        %% Requesting entity is prohibited from unsubscribing entity
@@ -369,17 +370,16 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
            {error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")};
        %% Was just subscriber, remove the record
        SubState#pubsub_state.affiliation == none ->
-           del_state(SubState#pubsub_state.stateid),
+           del_state(NodeId, SubKey),
            {result, default};
        true ->
            set_state(SubState#pubsub_state{subscription = none}),
            {result, default}
     end.
 
-%% @spec (Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
+%% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
 %%              {true, PubsubItem} | {result, Reply}
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      Publisher = mod_pubsub:jid()
 %%      PublishModel = atom()
 %%      MaxItems = integer()
@@ -415,13 +415,13 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
 %%   to completly disable persistance.</li></ul>
 %% </p>
 %% <p>In the default plugin module, the record is unchanged.</p>
-publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
+publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
     SubKey = jlib:jid_tolower(Publisher),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     SubState = case SubKey of
        GenKey -> GenState;
-       _ -> get_state(Host, Node, SubKey)
+       _ -> get_state(NodeId, SubKey)
        end,
     Affiliation = GenState#pubsub_state.affiliation,
     Subscription = SubState#pubsub_state.subscription,
@@ -434,31 +434,31 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
            %% Entity does not have sufficient privileges to publish to node
            {error, ?ERR_FORBIDDEN};
        true ->
-           PubId = {SubKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824)
            %% TODO: check creation, presence, roster
-           Item = case get_item(Host, Node, ItemId) of
+           if MaxItems > 0 ->
+               PubId = {now(), SubKey},
+               Item = case get_item(NodeId, ItemId) of
                       {result, OldItem} ->
                           OldItem#pubsub_item{modification = PubId,
                                               payload = Payload};
                       _ ->
-                          #pubsub_item{itemid = {ItemId, {Host, Node}},
-                                       creation = {GenKey, now()},
+                          #pubsub_item{itemid = {ItemId, NodeId},
+                                       creation = {now(), GenKey},
                                        modification = PubId,
                                        payload = Payload}
                   end,
-           Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
-           {result, {NI, OI}} = remove_extra_items(
-                                  Host, Node, MaxItems, Items),
-           if MaxItems > 0 -> set_item(Item);
-              true -> ok
-           end,
-           set_state(GenState#pubsub_state{items = NI}),
-           {result, {default, broadcast, OI}}
+               Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
+               {result, {NI, OI}} = remove_extra_items(NodeId, MaxItems, Items),
+               set_item(Item),
+               set_state(GenState#pubsub_state{items = NI}),
+               {result, {default, broadcast, OI}};
+              true ->
+               {result, {default, broadcast, []}}
+           end
     end.
 
-%% @spec (Host, Node, MaxItems, ItemIds) -> {NewItemIds,OldItemIds}
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, MaxItems, ItemIds) -> {NewItemIds,OldItemIds}
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      MaxItems = integer() | unlimited
 %%      ItemIds = [ItemId::string()]
 %%      NewItemIds = [ItemId::string()]
@@ -470,35 +470,34 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
 %% rules can be used.</p>
 %% <p>If another PubSub plugin wants to delegate the item removal (and if the
 %% plugin is using the default pubsub storage), it can implements this function like this:
-%% ```remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-%%        node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).'''</p>
-remove_extra_items(_Host, _Node, unlimited, ItemIds) ->
+%% ```remove_extra_items(NodeId, MaxItems, ItemIds) ->
+%%        node_default:remove_extra_items(NodeId, MaxItems, ItemIds).'''</p>
+remove_extra_items(_NodeId, unlimited, ItemIds) ->
     {result, {ItemIds, []}};
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
     NewItems = lists:sublist(ItemIds, MaxItems),
     OldItems = lists:nthtail(length(NewItems), ItemIds),
     %% Remove extra items:
-    del_items(Host, Node, OldItems),
+    del_items(NodeId, OldItems),
     %% Return the new items list:
     {result, {NewItems, OldItems}}.
 
-%% @spec (Host, Node, JID, ItemId) ->
+%% @spec (NodeId, JID, ItemId) ->
 %%               {error, Reason::stanzaError()} |
 %%               {result, []}
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      JID = mod_pubsub:jid()
 %%      ItemId = string()
 %% @doc <p>Triggers item deletion.</p>
 %% <p>Default plugin: The user performing the deletion must be the node owner
 %% or a publisher.</p>
-delete_item(Host, Node, Publisher, ItemId) ->
+delete_item(NodeId, Publisher, ItemId) ->
     SubKey = jlib:jid_tolower(Publisher),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     #pubsub_state{affiliation = Affiliation, items = Items} = GenState,
     Allowed = (Affiliation == publisher) orelse (Affiliation == owner)
-       orelse case get_item(Host, Node, ItemId) of
+       orelse case get_item(NodeId, ItemId) of
                   {result, #pubsub_item{creation = {GenKey, _}}} -> true;
                   _ -> false
               end,
@@ -507,31 +506,31 @@ delete_item(Host, Node, Publisher, ItemId) ->
            %% Requesting entity does not have sufficient privileges
            {error, ?ERR_FORBIDDEN};
        true ->
-           case get_item(Host, Node, ItemId) of
-               {result, _} ->
-                   del_item(Host, Node, ItemId),
+           case lists:member(ItemId, Items) of
+               true ->
+                   del_item(NodeId, ItemId),
                    NewItems = lists:delete(ItemId, Items),
                    set_state(GenState#pubsub_state{items = NewItems}),
                    {result, {default, broadcast}};
-               _ ->
+               false ->
                    %% Non-existent node or item
                    {error, ?ERR_ITEM_NOT_FOUND}
            end
     end.
 
-%% @spec (Host, Node, Owner) ->
+%% @spec (NodeId, Owner) ->
 %%               {error, Reason::stanzaError()} |
 %%               {result, {default, broadcast}}
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      Owner = mod_pubsub:jid()
-purge_node(Host, Node, Owner) ->
+purge_node(NodeId, Owner) ->
     SubKey = jlib:jid_tolower(Owner),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     case GenState of
        #pubsub_state{items = Items, affiliation = owner} ->
-           del_items(Host, Node, Items),
+           del_items(NodeId, Items),
+           set_state(GenState#pubsub_state{items = []}),
            {result, {default, broadcast}};
        _ ->
            %% Entity is not owner
@@ -548,45 +547,44 @@ purge_node(Host, Node, Owner) ->
 %% the default PubSub module. Otherwise, it should return its own affiliation,
 %% that will be added to the affiliation stored in the main
 %% <tt>pubsub_state</tt> table.</p>
-get_entity_affiliations(Host, Owner) ->
+get_entity_affiliations(_Host, Owner) ->
     SubKey = jlib:jid_tolower(Owner),
     GenKey = jlib:jid_remove_resource(SubKey),
     States = mnesia:match_object(
-              #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}),
-    Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) ->
+               %% TODO check if Host needed
+              #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
+    Tr = fun(#pubsub_state{stateid = {_, N}, affiliation = A}) ->
                 {N, A}
         end,
     {result, lists:map(Tr, States)}.
 
-get_node_affiliations(Host, Node) ->
-    {result, States} = get_states(Host, Node),
-    Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) ->
+get_node_affiliations(NodeId) ->
+    {result, States} = get_states(NodeId),
+    Tr = fun(#pubsub_state{stateid = {J, _}, affiliation = A}) ->
                 {J, A}
         end,
     {result, lists:map(Tr, States)}.
 
-get_affiliation(Host, Node, Owner) ->
+get_affiliation(NodeId, Owner) ->
     SubKey = jlib:jid_tolower(Owner),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     {result, GenState#pubsub_state.affiliation}.
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
+set_affiliation(NodeId, Owner, Affiliation) ->
     SubKey = jlib:jid_tolower(Owner),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     case {Affiliation, GenState#pubsub_state.subscription} of
        {none, none} ->
-           del_state(GenState#pubsub_state.stateid);
+           del_state(NodeId, GenKey);
        _ ->
            set_state(GenState#pubsub_state{affiliation = Affiliation})
-    end,
-    ok.
+    end.
 
 %% @spec (Host, Owner) -> [{Node,Subscription}]
 %%      Host = host()
 %%      Owner = mod_pubsub:jid()
-%%      Node = mod_pubsub:pubsubNode()
 %% @doc <p>Return the current subscriptions for the given user</p>
 %% <p>The default module reads subscriptions in the main Mnesia
 %% <tt>pubsub_state</tt> table. If a plugin stores its data in the same
@@ -594,49 +592,46 @@ set_affiliation(Host, Node, Owner, Affiliation) ->
 %% the default PubSub module. Otherwise, it should return its own affiliation,
 %% that will be added to the affiliation stored in the main
 %% <tt>pubsub_state</tt> table.</p>
-get_entity_subscriptions(Host, Owner) ->
+get_entity_subscriptions(_Host, Owner) ->
     {U, D, _} = SubKey = jlib:jid_tolower(Owner),
     GenKey = jlib:jid_remove_resource(SubKey),
     States = case SubKey of
        GenKey -> mnesia:match_object(
-              #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'});
+              #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
        _ -> mnesia:match_object(
-              #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'})
+              #pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
            ++ mnesia:match_object(
-              #pubsub_state{stateid = {SubKey, {Host, '_'}}, _ = '_'})
+              #pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
     end,
-    Tr = fun(#pubsub_state{stateid = {J, {_, N}}, subscription = S}) ->
+    Tr = fun(#pubsub_state{stateid = {J, N}, subscription = S}) ->
                 {N, S, J}
         end,
     {result, lists:map(Tr, States)}.
 
-get_node_subscriptions(Host, Node) ->
-    {result, States} = get_states(Host, Node),
-    Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) ->
+get_node_subscriptions(NodeId) ->
+    {result, States} = get_states(NodeId),
+    Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) ->
                 {J, S}
         end,
     {result, lists:map(Tr, States)}.
 
-get_subscription(Host, Node, Owner) ->
+get_subscription(NodeId, Owner) ->
     SubKey = jlib:jid_tolower(Owner),
-    SubState = get_state(Host, Node, SubKey),
+    SubState = get_state(NodeId, SubKey),
     {result, SubState#pubsub_state.subscription}.
 
-set_subscription(Host, Node, Owner, Subscription) ->
+set_subscription(NodeId, Owner, Subscription) ->
     SubKey = jlib:jid_tolower(Owner),
-    SubState = get_state(Host, Node, SubKey),
+    SubState = get_state(NodeId, SubKey),
     case {Subscription, SubState#pubsub_state.affiliation} of
        {none, none} ->
-           del_state(SubState#pubsub_state.stateid);
+           del_state(NodeId, SubKey);
        _ ->
            set_state(SubState#pubsub_state{subscription = Subscription})
-    end,
-    ok.
+    end.
 
-%% @spec (Host, Node) -> [States] | []
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
-%%      Item = mod_pubsub:pubsubItems()
+%% @spec (NodeId) -> [States] | []
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %% @doc Returns the list of stored states for a given node.
 %% <p>For the default PubSub module, states are stored in Mnesia database.</p>
 %% <p>We can consider that the pubsub_state table have been created by the main
@@ -645,21 +640,20 @@ set_subscription(Host, Node, Owner, Subscription) ->
 %% relational database).</p>
 %% <p>If a PubSub plugin wants to delegate the states storage to the default node,
 %% they can implement this function like this:
-%% ```get_states(Host, Node) ->
-%%        node_default:get_states(Host, Node).'''</p>
-get_states(Host, Node) ->
+%% ```get_states(NodeId) ->
+%%        node_default:get_states(NodeId).'''</p>
+get_states(NodeId) ->
     States = mnesia:match_object(
-              #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}),
+              #pubsub_state{stateid = {'_', NodeId}, _ = '_'}),
     {result, States}.
 
-%% @spec (JID, Host, Node) -> [State] | []
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, JID) -> [State] | []
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      JID = mod_pubsub:jid()
 %%      State = mod_pubsub:pubsubItems()
 %% @doc <p>Returns a state (one state list), given its reference.</p>
-get_state(Host, Node, JID) ->
-    StateId = {JID, {Host, Node}},
+get_state(NodeId, JID) ->
+    StateId = {JID, NodeId},
     case mnesia:read({pubsub_state, StateId}) of
        [State] when is_record(State, pubsub_state) -> State;
        _ -> #pubsub_state{stateid=StateId}
@@ -676,12 +670,11 @@ set_state(_) ->
 %% @spec (StateId) -> ok | {error, Reason::stanzaError()}
 %%      StateId = mod_pubsub:pubsubStateId()
 %% @doc <p>Delete a state from database.</p>
-del_state(StateId) ->
-    mnesia:delete({pubsub_state, StateId}).
+del_state(NodeId, JID) ->
+    mnesia:delete({pubsub_state, {JID, NodeId}}).
 
-%% @spec (Host, Node, From) -> [Items] | []
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, From) -> [Items] | []
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      Items = mod_pubsub:pubsubItems()
 %% @doc Returns the list of stored items for a given node.
 %% <p>For the default PubSub module, items are stored in Mnesia database.</p>
@@ -691,16 +684,16 @@ del_state(StateId) ->
 %% relational database), or they can even decide not to persist any items.</p>
 %% <p>If a PubSub plugin wants to delegate the item storage to the default node,
 %% they can implement this function like this:
-%% ```get_items(Host, Node, From) ->
-%%        node_default:get_items(Host, Node, From).'''</p>
-get_items(Host, Node, _From) ->
+%% ```get_items(NodeId, From) ->
+%%        node_default:get_items(NodeId, From).'''</p>
+get_items(NodeId, _From) ->
     Items = mnesia:match_object(
-             #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
+             #pubsub_item{itemid = {'_', NodeId}, _ = '_'}),
     {result, Items}.
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
     SubKey = jlib:jid_tolower(JID),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     Affiliation = GenState#pubsub_state.affiliation,
     Subscription = GenState#pubsub_state.subscription,
     Whitelisted = can_fetch_item(Affiliation, Subscription),
@@ -730,26 +723,25 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI
        %%      % Payment is required for a subscription
        %%      {error, ?ERR_PAYMENT_REQUIRED};
        true ->
-           get_items(Host, Node, JID)
+           get_items(NodeId, JID)
     end.
 
-%% @spec (Host, Node, ItemId) -> [Item] | []
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, ItemId) -> [Item] | []
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      ItemId = string()
 %%      Item = mod_pubsub:pubsubItems()
 %% @doc <p>Returns an item (one item list), given its reference.</p>
-get_item(Host, Node, ItemId) ->
-    case mnesia:read({pubsub_item, {ItemId, {Host, Node}}}) of
+get_item(NodeId, ItemId) ->
+    case mnesia:read({pubsub_item, {ItemId, NodeId}}) of
        [Item] when is_record(Item, pubsub_item) ->
            {result, Item};
        _ ->
            {error, ?ERR_ITEM_NOT_FOUND}
     end.
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
     SubKey = jlib:jid_tolower(JID),
     GenKey = jlib:jid_remove_resource(SubKey),
-    GenState = get_state(Host, Node, GenKey),
+    GenState = get_state(NodeId, GenKey),
     Affiliation = GenState#pubsub_state.affiliation,
     Subscription = GenState#pubsub_state.subscription,
     Whitelisted = can_fetch_item(Affiliation, Subscription),
@@ -779,7 +771,7 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup
        %%      % Payment is required for a subscription
        %%      {error, ?ERR_PAYMENT_REQUIRED};
        true ->
-           get_item(Host, Node, ItemId)
+           get_item(NodeId, ItemId)
     end.
 
 %% @spec (Item) -> ok | {error, Reason::stanzaError()}
@@ -790,16 +782,15 @@ set_item(Item) when is_record(Item, pubsub_item) ->
 set_item(_) ->
     {error, ?ERR_INTERNAL_SERVER_ERROR}.
 
-%% @spec (Host, Node, ItemId) -> ok | {error, Reason::stanzaError()}
-%%      Host = mod_pubsub:host()
-%%      Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, ItemId) -> ok | {error, Reason::stanzaError()}
+%%      NodeId = mod_pubsub:pubsubNodeId()
 %%      ItemId = string()
 %% @doc <p>Delete an item from database.</p>
-del_item(Host, Node, ItemId) ->
-    mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}).
-del_items(Host, Node, ItemIds) ->
+del_item(NodeId, ItemId) ->
+    mnesia:delete({pubsub_item, {ItemId, NodeId}}).
+del_items(NodeId, ItemIds) ->
     lists:foreach(fun(ItemId) ->
-       del_item(Host, Node, ItemId)
+       del_item(NodeId, ItemId)
     end, ItemIds).
 
 %% @doc <p>Return the name of the node if known: Default is to return
index 3368fd640f47bf415f2f5fd34cbf917ff4e33b95..3ef07877d54f429e0af0d298a08d002de2a13315 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -111,79 +111,81 @@ features() ->
 create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(_Host, _Node, _Sender, _Subscriber, _AccessModel,
+subscribe_node(_NodeId, _Sender, _Subscriber, _AccessModel,
               _SendLast, _PresenceSubscription, _RosterGroup) ->
     {error, ?ERR_FORBIDDEN}.
 
-unsubscribe_node(_Host, _Node, _Sender, _Subscriber, _SubID) ->
+unsubscribe_node(_NodeId, _Sender, _Subscriber, _SubID) ->
     {error, ?ERR_FORBIDDEN}.
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
     lists:foreach(fun(SubNode) ->
                          node_default:publish_item(
-                           Host, SubNode, Publisher, Model,
+                           SubNode#pubsub_node.id, Publisher, Model,
                            MaxItems, ItemId, Payload)
-                 end, nodetree_default:get_subnodes(Host, Node, Publisher)).
+                 end, nodetree_default:get_subnodes(NodeId, Publisher)).
 
-remove_extra_items(_Host, _Node, _MaxItems, ItemIds) ->
+remove_extra_items(_NodeId, _MaxItems, ItemIds) ->
     {result, {ItemIds, []}}.
 
-delete_item(_Host, _Node, _JID, _ItemId) ->
+delete_item(_NodeId, _JID, _ItemId) ->
     {error, ?ERR_ITEM_NOT_FOUND}.
 
-purge_node(_Host, _Node, _Owner) ->
+purge_node(_NodeId, _Owner) ->
     {error, ?ERR_FORBIDDEN}.
 
 get_entity_affiliations(_Host, _Owner) ->
     {result, []}.
 
-get_node_affiliations(_Host, _Node) ->
+get_node_affiliations(_NodeId) ->
     {result, []}.
 
-get_affiliation(_Host, _Node, _Owner) ->
+get_affiliation(_NodeId, _Owner) ->
     {result, []}.
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(_Host, _Owner) ->
     {result, []}.
 
-get_node_subscriptions(_Host, _Node) ->
-    {result, []}.
+get_node_subscriptions(NodeId) ->
+    %% note: get_node_subscriptions is used for broadcasting
+    %% DO NOT REMOVE
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(_Host, _Node, _Owner) ->
+get_subscription(_NodeId, _Owner) ->
     {result, []}.
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
 set_item(Item) ->
     node_default:set_item(Item).
index a5abb26c1dafe6e4dd17dbe00721b9e01d6d5717..db8fed519602ff416bc09f9026b04890df462194 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -101,74 +101,74 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
     end,
     {result, Allowed}.
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
-    node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+    node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_default:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-    node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(Host, Owner) ->
     node_default:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(Host, Node, Owner) ->
-    node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+    node_default:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
 set_item(Item) ->
     node_default:set_item(Item).
index a092102ad53ca46c57a689bed597b29a58fc6f95..9116f0f12b5f053680f79e075c65ff0888ddefee 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -119,77 +119,77 @@ features() ->
 create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
     
-create_node(Host, Node, Owner) ->
-        node_pep:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+        node_pep:create_node(NodeId, Owner).
        
-delete_node(Host, Removed) ->
-    node_pep:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_pep:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel,
               SendLast, PresenceSubscription, RosterGroup) ->
     node_pep:subscribe_node(
-      Host, Node, Sender, Subscriber, AccessModel, SendLast,
+      NodeId, Sender, Subscriber, AccessModel, SendLast,
       PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_pep:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_pep:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_pep:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_pep:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_pep:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_pep:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_pep:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_pep:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_pep:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_pep:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_pep:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-       node_pep:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+       node_pep:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_pep:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_pep:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-       node_pep:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+       node_pep:set_affiliation(NodeId, Owner, Affiliation).
 
-get_entity_subscriptions(Host,Owner) ->
+get_entity_subscriptions(Host, Owner) ->
     node_pep:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_pep:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_pep:get_node_subscriptions(NodeId).
 
-get_subscription(Host,Node,Owner) ->
-    node_pep:get_subscription(Host,Node,Owner).
+get_subscription(NodeId, Owner) ->
+    node_pep:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_pep:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_pep:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_pep:get_states(Host, Node).
+get_states(NodeId) ->
+    node_pep:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_pep:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_pep:get_state(NodeId, JID).
 
 set_state(State) ->
     node_pep:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_pep:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_pep:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_pep:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_pep:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
-get_item(Host, Node, ItemId) ->
-    node_pep:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_pep:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_pep:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_pep:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
 set_item(Item) ->
     node_pep:set_item(Item).
index 8fd6fa7775f167d5577d21535cf5da815c3a49d5..6a89aa1ec9bab5e6a228594b64bd76ad98537888 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -131,92 +131,92 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
     end,
     {result, Allowed}.
 
-create_node(Host, Node, Owner) ->
-    case node_default:create_node(Host, Node, Owner) of
+create_node(NodeId, Owner) ->
+    case node_default:create_node(NodeId, Owner) of
        {result, _} -> {result, []};
        Error -> Error
     end.
 
-delete_node(Host, Removed) ->
-    case node_default:delete_node(Host, Removed) of
+delete_node(Removed) ->
+    case node_default:delete_node(Removed) of
        {result, {_, _, Removed}} -> {result, {[], Removed}};
        Error -> Error
     end.
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel,
               SendLast, PresenceSubscription, RosterGroup) ->
     node_default:subscribe_node(
-      Host, Node, Sender, Subscriber, AccessModel, SendLast,
+      NodeId, Sender, Subscriber, AccessModel, SendLast,
       PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    case node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID) of
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    case node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of
        {error, Error} -> {error, Error};
        {result, _} -> {result, []}
     end.
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(_Host, Owner) ->
     OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
     node_default:get_entity_affiliations(OwnerKey, Owner).
 
-get_node_affiliations(Host, Node) ->
-    OwnerKey = jlib:jid_remove_resource(Host),
-    node_default:get_node_affiliations(OwnerKey, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(_Host, Node, Owner) ->
-    OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
-    node_default:get_affiliation(OwnerKey, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(_Host, Node, Owner, Affiliation) ->
-    OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
-    State = get_state(OwnerKey, Node, OwnerKey),
-    set_state(State#pubsub_state{affiliation = Affiliation}),
-    ok. 
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(_Host, _Owner) ->
     {result, []}.
 
-get_node_subscriptions(_Host, _Node) ->
-    {result, []}.
+get_node_subscriptions(NodeId) ->
+    %% note: get_node_subscriptions is used for broadcasting
+    %% there should not have any subscriptions
+    %% but that call returns also all subscription to none
+    %% and this is required for broadcast to occurs
+    %% DO NOT REMOVE
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(_Host, _Node, _Owner) ->
+get_subscription(_NodeId, _Owner) ->
     {result, none}.
 
-set_subscription(_Host, _Node, _Owner, _Subscription) ->
+set_subscription(_NodeId, _Owner, _Subscription) ->
     ok.
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
 
 set_item(Item) ->
     node_default:set_item(Item).
index 963e40ad25aed3e64ef091ce44f12dfd010f14ca..0a0e1e5f837020193a65142da649a37afa992a3a 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -115,76 +115,76 @@ create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_default:create_node_permission(Host, ServerHost, Node, ParentNode,
                                        Owner, Access).
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast,
               PresenceSubscription, RosterGroup) ->
-    node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+    node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel,
                                SendLast, PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_default:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-    node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(Host, Owner) ->
     node_default:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(Host, Node, Owner) ->
-    node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+    node_default:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
 set_item(Item) ->
     node_default:set_item(Item).
index e237f17e3480b3d3fe3b3cb8a347660c8336bfa2..6efe41d337457abeb388cf3ee83db10fbb4bdc40 100644 (file)
 -export([init/3, terminate/2,
         options/0, features/0,
         create_node_permission/6,
-        create_node/3,
-        delete_node/2,
-        purge_node/3,
-        subscribe_node/8,
-        unsubscribe_node/5,
-        publish_item/7,
-        delete_item/4,
-        remove_extra_items/4,
+        create_node/2,
+        delete_node/1,
+        purge_node/2,
+        subscribe_node/7,
+        unsubscribe_node/4,
+        publish_item/6,
+        delete_item/3,
+        remove_extra_items/3,
         get_entity_affiliations/2,
-        get_node_affiliations/2,
-        get_affiliation/3,
-        set_affiliation/4,
+        get_node_affiliations/1,
+        get_affiliation/2,
+        set_affiliation/3,
         get_entity_subscriptions/2,
-        get_node_subscriptions/2,
-        get_subscription/3,
-        set_subscription/4,
-        get_states/2,
-        get_state/3,
+        get_node_subscriptions/1,
+        get_subscription/2,
+        set_subscription/3,
+        get_states/1,
+        get_state/2,
         set_state/1,
-        get_items/7,
-        get_items/3,
-        get_item/8,
-        get_item/3,
+        get_items/6,
+        get_items/2,
+        get_item/7,
+        get_item/2,
         set_item/1,
         get_item_name/3
        ]).
@@ -114,74 +114,74 @@ features() ->
 create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
     node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
 
-create_node(Host, Node, Owner) ->
-    node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+    node_default:create_node(NodeId, Owner).
 
-delete_node(Host, Removed) ->
-    node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+    node_default:delete_node(Removed).
 
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
-    node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+    node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
 
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
-    node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+    node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
 
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
-    node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+    node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
 
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-    node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+    node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
 
-delete_item(Host, Node, JID, ItemId) ->
-    node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+    node_default:delete_item(NodeId, JID, ItemId).
 
-purge_node(Host, Node, Owner) ->
-    node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+    node_default:purge_node(NodeId, Owner).
 
 get_entity_affiliations(Host, Owner) ->
     node_default:get_entity_affiliations(Host, Owner).
 
-get_node_affiliations(Host, Node) ->
-    node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+    node_default:get_node_affiliations(NodeId).
 
-get_affiliation(Host, Node, Owner) ->
-    node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+    node_default:get_affiliation(NodeId, Owner).
 
-set_affiliation(Host, Node, Owner, Affiliation) ->
-    node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+    node_default:set_affiliation(NodeId, Owner, Affiliation).
 
 get_entity_subscriptions(Host, Owner) ->
     node_default:get_entity_subscriptions(Host, Owner).
 
-get_node_subscriptions(Host, Node) ->
-    node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+    node_default:get_node_subscriptions(NodeId).
 
-get_subscription(Host, Node, Owner) ->
-    node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+    node_default:get_subscription(NodeId, Owner).
 
-set_subscription(Host, Node, Owner, Subscription) ->
-    node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+    node_default:set_subscription(NodeId, Owner, Subscription).
 
-get_states(Host, Node) ->
-    node_default:get_states(Host, Node).
+get_states(NodeId) ->
+    node_default:get_states(NodeId).
 
-get_state(Host, Node, JID) ->
-    node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+    node_default:get_state(NodeId, JID).
 
 set_state(State) ->
     node_default:set_state(State).
 
-get_items(Host, Node, From) ->
-    node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+    node_default:get_items(NodeId, From).
 
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
-get_item(Host, Node, ItemId) ->
-    node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+    node_default:get_item(NodeId, ItemId).
 
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
-    node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+    node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
     
 set_item(Item) ->
     node_default:set_item(Item).
index eff49727e5d540d0c21ad2a368b8cdc076ba4a2a..fa3516950f7ac1fa03dcffc2c3b266b3c9c8502a 100644 (file)
@@ -50,7 +50,7 @@
         get_nodes/2,
         get_nodes/1,
         get_subnodes/3,
-        get_subnodes_tree/2,
+        get_subnodes_tree/3,
         create_node/5,
         delete_node/2
        ]).
@@ -75,9 +75,10 @@ init(_Host, _ServerHost, _Opts) ->
                         {attributes, record_info(fields, pubsub_node)}]),
     NodesFields = record_info(fields, pubsub_node),
     case mnesia:table_info(pubsub_node, attributes) of
-       [host_node, host_parent, info] -> ok;  % old schema, updated later by pubsub
        NodesFields -> ok;
-       _ -> mnesia:transform_table(pubsub_node, ignore, NodesFields)
+       _ ->
+           ok
+           %% mnesia:transform_table(pubsub_state, ignore, StatesFields)
     end,
     ok.
 terminate(_Host, _ServerHost) ->
@@ -96,12 +97,11 @@ set_node(Record) when is_record(Record, pubsub_node) ->
 set_node(_) ->
     {error, ?ERR_INTERNAL_SERVER_ERROR}.
 
-get_node(Host, Node, _From) ->
-    get_node(Host, Node).
-
 %% @spec (Host, Node) -> pubsubNode() | {error, Reason}
 %%     Host = mod_pubsub:host()
 %%     Node = mod_pubsub:pubsubNode()
+get_node(Host, Node, _From) ->
+    get_node(Host, Node).
 get_node(Host, Node) ->
     case catch mnesia:read({pubsub_node, {Host, Node}}) of
        [Record] when is_record(Record, pubsub_node) -> Record;
@@ -109,44 +109,48 @@ get_node(Host, Node) ->
        Error -> Error
     end.
 
-get_nodes(Key, _From) ->
-    get_nodes(Key).
-
-%% @spec (Key) -> [pubsubNode()] | {error, Reason}
-%%     Key = mod_pubsub:host() | mod_pubsub:jid()
-get_nodes(Key) ->
-    mnesia:match_object(#pubsub_node{nodeid = {Key, '_'}, _ = '_'}).
+%% @spec (Host) -> [pubsubNode()] | {error, Reason}
+%%     Host = mod_pubsub:host() | mod_pubsub:jid()
+get_nodes(Host, _From) ->
+    get_nodes(Host).
+get_nodes(Host) ->
+    mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
 
 %% @spec (Host, Node, From) -> [pubsubNode()] | {error, Reason}
 %%     Host = mod_pubsub:host()
 %%     Node = mod_pubsub:pubsubNode()
 %%     From = mod_pubsub:jid()
 get_subnodes(Host, Node, _From) ->
-    mnesia:match_object(#pubsub_node{parentid = {Host, Node}, _ = '_'}).
+    get_subnodes(Host, Node).
+get_subnodes(Host, Node) ->
+    mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, parent = Node, _ = '_'}).
 
-%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason}
+%% @spec (Host, Index) -> [pubsubNodeIdx()] | {error, Reason}
 %%     Host = mod_pubsub:host()
 %%     Node = mod_pubsub:pubsubNode()
+%%     From = mod_pubsub:jid()
+get_subnodes_tree(Host, Node, _From) ->
+    get_subnodes_tree(Host, Node).
 get_subnodes_tree(Host, Node) ->
-    mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}}, Acc) ->
+    mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) ->
                         case lists:prefix(Node, N) and (H == Host) of
-                            true -> [N | Acc];
+                            true -> [R | Acc];
                             _ -> Acc
                         end
                 end, [], pubsub_node).
 
-%% @spec (Key, Node, Type, Owner, Options) -> ok | {error, Reason}
-%%     Key = mod_pubsub:host() | mod_pubsub:jid()
+%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason}
+%%     Host = mod_pubsub:host() | mod_pubsub:jid()
 %%     Node = mod_pubsub:pubsubNode()
 %%     NodeType = mod_pubsub:nodeType()
 %%     Owner = mod_pubsub:jid()
 %%     Options = list()
-create_node(Key, Node, Type, Owner, Options) ->
-    OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
-    case mnesia:read({pubsub_node, {Key, Node}}) of
+create_node(Host, Node, Type, Owner, Options) ->
+    BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
+    case mnesia:read({pubsub_node, {Host, Node}}) of
        [] ->
            {ParentNode, ParentExists} =
-               case Key of
+               case Host of
                    {_U, _S, _R} ->
                        %% This is special case for PEP handling
                        %% PEP does not uses hierarchy
@@ -157,7 +161,7 @@ create_node(Key, Node, Type, Owner, Options) ->
                        [] -> 
                            {[], true};
                        _ ->
-                           case mnesia:read({pubsub_node, {Key, Parent}}) of
+                           case mnesia:read({pubsub_node, {Host, Parent}}) of
                                [] -> {Parent, false};
                                _ -> {Parent, true}
                            end
@@ -165,13 +169,14 @@ create_node(Key, Node, Type, Owner, Options) ->
                end,
            case ParentExists of
                true ->
-                   %% Service requires registration
-                   %%{error, ?ERR_REGISTRATION_REQUIRED};
-                   mnesia:write(#pubsub_node{nodeid = {Key, Node},
-                                             parentid = {Key, ParentNode},
+                   NodeId = pubsub_index:new(node),
+                   mnesia:write(#pubsub_node{nodeid = {Host, Node},
+                                             id = NodeId,
+                                             parent = ParentNode,
                                              type = Type,
-                                             owners = [OwnerKey],
-                                             options = Options});
+                                             owners = [BJID],
+                                             options = Options}),
+                   {ok, NodeId};
                false ->
                    %% Requesting entity is prohibited from creating nodes
                    {error, ?ERR_FORBIDDEN}
@@ -181,12 +186,13 @@ create_node(Key, Node, Type, Owner, Options) ->
            {error, ?ERR_CONFLICT}
     end.
 
-%% @spec (Key, Node) -> [mod_pubsub:node()]
-%%     Key = mod_pubsub:host() | mod_pubsub:jid()
+%% @spec (Host, Node) -> [mod_pubsub:node()]
+%%     Host = mod_pubsub:host() | mod_pubsub:jid()
 %%     Node = mod_pubsub:pubsubNode()
-delete_node(Key, Node) ->
-    Removed = get_subnodes_tree(Key, Node),
-    lists:foreach(fun(N) ->
-                         mnesia:delete({pubsub_node, {Key, N}})
-                 end, Removed),
+delete_node(Host, Node) ->
+    Removed = get_subnodes_tree(Host, Node),
+    lists:foreach(fun(#pubsub_node{nodeid = {_, N}, id = I}) ->
+           pubsub_index:free(node, I),
+           mnesia:delete({pubsub_node, {Host, N}})
+       end, Removed),
     Removed.
index dcfd9e5efe8e730ef53675e8da5f4af4e60aaab3..6913b6e43ca490b4695e0f2ec443d7e34ac5ab77 100644 (file)
@@ -48,7 +48,7 @@
         get_nodes/2,
         get_nodes/1,
         get_subnodes/3,
-        get_subnodes_tree/2,
+        get_subnodes_tree/3,
         create_node/5,
         delete_node/2
        ]).
@@ -94,14 +94,13 @@ get_node(Host, Node, _From) ->
 get_node(Host, Node) ->
     #pubsub_node{nodeid = {Host, Node}}.
 
-get_nodes(Key, _From) ->
-    get_nodes(Key).
-
-%% @spec (Key) -> [pubsubNode()]
+%% @spec (Host) -> [pubsubNode()]
 %%     Host = mod_pubsub:host() | mod_pubsub:jid()
 %% @doc <p>Virtual node tree does not handle a node database. Any node is considered
 %% as existing. Nodes list can not be determined.</p>
-get_nodes(_Key) ->
+get_nodes(Host, _From) ->
+    get_nodes(Host).
+get_nodes(_Host) ->
     [].
 
 %% @spec (Host, Node, From) -> [pubsubNode()]
@@ -109,13 +108,17 @@ get_nodes(_Key) ->
 %%     Node = mod_pubsub:pubsubNode()
 %%     From = mod_pubsub:jid()
 %% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
-get_subnodes(_Host, _Node, _From) ->
+get_subnodes(Host, Node, _From) ->
+    get_subnodes(Host, Node).
+get_subnodes(_Host, _Node) ->
     [].
 
 %% @spec (Host, Index) -> [pubsubNode()]
 %%     Host = mod_pubsub:host()
 %%     Node = mod_pubsub:pubsubNode()
 %% @doc <p>Virtual node tree does not handle parent/child. Child list is empty.</p>
+get_subnodes_tree(Host, Node, _From) ->
+    get_subnodes_tree(Host, Node).
 get_subnodes_tree(_Host, _Node) ->
     [].
 
@@ -128,11 +131,11 @@ get_subnodes_tree(_Host, _Node) ->
 %% @doc <p>No node record is stored on database. Any valid node
 %% is considered as already created.</p>
 %% <p>default allowed nodes: /home/host/user/any/node/name</p>
-create_node(_Host, Node, _Type, Owner, _Options) ->
+create_node(Host, Node, _Type, Owner, _Options) ->
     UserName = Owner#jid.luser,
     UserHost = Owner#jid.lserver,
     case Node of
-       ["home", UserHost, UserName | _] -> {error, ?ERR_CONFLICT};
+       ["home", UserHost, UserName | _] -> {error, {virtual, {Host, Node}}};
        _ -> {error, ?ERR_NOT_ALLOWED}
     end.
 
@@ -141,5 +144,5 @@ create_node(_Host, Node, _Type, Owner, _Options) ->
 %%     Node = mod_pubsub:pubsubNode()
 %% @doc <p>Virtual node tree does not handle parent/child.
 %% node deletion just affects the corresponding node.</p>
-delete_node(_Host, Node) ->
-    [Node].
+delete_node(Host, Node) ->
+    [get_node(Host, Node)].
index 46cbe9b95ef3e3628c1e791e3b1fe0c84dc58f24..87088eb6a6cb1a13b16f535e3c84d06ab9b04eb7 100644 (file)
 %%% @type affiliation() = none | owner | publisher | outcast.
 %%% @type subscription() = none | pending | unconfigured | subscribed.
 
+%%% internal pubsub index table
+-record(pubsub_index, {index, last, free}).
+
 %%% @type pubsubNode() = #pubsub_node{
 %%%    nodeid = {Host::host(), Node::pubsubNode()},
 %%%    parentid = {Host::host(), Node::pubsubNode()},
+%%%    nodeidx = int().
 %%%    type = nodeType(),
-%%%    owners = [ljid()],
-%%%    options = [nodeOption()]}.
+%%%    options = [nodeOption()]}
 %%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
 %%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
 %%% <p>The <tt>parentid</tt> and <tt>type</tt> fields are indexed.</p>
 -record(pubsub_node, {nodeid,
-                     parentid = {},
-                     type = "",
+                     id,
+                     parent,
+                     type = "default",
                      owners = [],
                      options = []
                     }).
 
 %%% @type pubsubState() = #pubsub_state{
-%%%    stateid = {ljid(), {Host::host(), Node::pubsubNode()}},
+%%%    stateid = {ljid(), pubsubNodeId()}},
 %%%    items = [ItemId::string()],
 %%%    affiliation = affiliation(),
 %%%    subscription = subscription()}.
                       subscription = none
 }).
 
-%% @type pubsubItem() = #pubsub_item{
-%%        itemid = {ItemId::string(), {Host::host(),Node::pubsubNode()}},
-%%     creation = {ljid(), now()},
-%%     modification = {ljid(), now()},
-%%     payload = XMLContent::string()}.
+%%% @type pubsubItem() = #pubsub_item{
+%%%    itemid = {ItemId::string(), pubsubNodeId()}},
+%%%    creation = {ljid(), now()},
+%%%    modification = {ljid(), now()},
+%%%    payload = XMLContent::string()}.
 %%% <p>This is the format of the <tt>published items</tt> table. The type of the
 %%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>
 -record(pubsub_item, {itemid,
diff --git a/src/mod_pubsub/pubsub_index.erl b/src/mod_pubsub/pubsub_index.erl
new file mode 100644 (file)
index 0000000..2ba5d4b
--- /dev/null
@@ -0,0 +1,65 @@
+%%% ====================================================================
+%%% ``The contents of this file are subject to the Erlang Public License,
+%%% Version 1.1, (the "License"); you may not use this file except in
+%%% compliance with the License. You should have received a copy of the
+%%% Erlang Public License along with this software. If not, it can be
+%%% retrieved via the world wide web at http://www.erlang.org/.
+%%% 
+%%% Software distributed under the License is distributed on an "AS IS"
+%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%%% the License for the specific language governing rights and limitations
+%%% under the License.
+%%% 
+%%% The Initial Developer of the Original Code is ProcessOne.
+%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne
+%%% All Rights Reserved.''
+%%% This software is copyright 2006-2009, ProcessOne.
+%%%
+%%%
+%%% @copyright 2006-2009 ProcessOne
+%%% @author Christophe Romain <christophe.romain@process-one.net>
+%%%   [http://www.process-one.net/]
+%%% @version {@vsn}, {@date} {@time}
+%%% @end
+%%% ====================================================================
+
+%% important note:
+%% new/1 and free/2 MUST be called inside a transaction bloc
+
+-module(pubsub_index).
+-author('christophe.romain@process-one.net').
+
+-include("pubsub.hrl").
+
+-export([init/3, new/1, free/2]).
+
+init(_Host, _ServerHost, _Opts) ->
+    mnesia:create_table(pubsub_index,
+                       [{disc_copies, [node()]},
+                        {attributes, record_info(fields, pubsub_index)}]).
+
+new(Index) ->
+    case mnesia:read({pubsub_index, Index}) of
+    [I] ->
+       case I#pubsub_index.free of
+       [] ->
+           Id = I#pubsub_index.last + 1,
+           mnesia:write(I#pubsub_index{last = Id}),
+           Id;
+       [Id|Free] ->
+           mnesia:write(I#pubsub_index{free = Free}),
+           Id
+       end;
+    _ ->
+       mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
+       1
+    end.
+
+free(Index, Id) ->
+    case mnesia:read({pubsub_index, Index}) of
+    [I] ->
+       Free = I#pubsub_index.free,
+       mnesia:write(I#pubsub_index{free = [Id|Free]});
+    _ ->
+       ok
+    end.