<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/mod_pubsub/node_flat_sdb.erl</filename>
    </added>
    <added>
      <filename>src/mod_pubsub/node_hometree_sdb.erl</filename>
    </added>
    <added>
      <filename>src/mod_pubsub/node_pep_sdb.erl</filename>
    </added>
    <added>
      <filename>src/mod_pubsub/nodetree_tree_s3.erl</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -2813,7 +2813,7 @@ subscription_to_string(_) -&gt; &quot;none&quot;.
 %%	 Node = pubsubNode()
 %%	 NodeStr = string()
 %% @doc &lt;p&gt;Convert a node type from pubsubNode to string.&lt;/p&gt;
-node_to_string(Node) -&gt; binary_to_list(Node).
+node_to_string(Node)  -&gt; binary_to_list(Node).
 string_to_node(SNode) -&gt; list_to_binary(SNode).
 
 %% @spec (Host) -&gt; jid()</diff>
      <filename>src/mod_pubsub/mod_pubsub.erl</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,7 @@
 
 -include(&quot;pubsub.hrl&quot;).
 -include(&quot;jlib.hrl&quot;).
--include(&quot;ejabberd.hrl&quot;).
+
 -behaviour(gen_pubsub_node).
 
 %% API definition
@@ -79,8 +79,6 @@
 	 node_to_path/1,
 	 path_to_node/1
 	]).
--define(DOMAIN, &quot;pubsub&quot;).
--define(PREFIX, &quot;item:&quot;).
 
 %% ================
 %% API definition
@@ -95,26 +93,19 @@
 %% &lt;p&gt;This function is mainly used to trigger the setup task necessary for the
 %% plugin. It can be used for example by the developer to create the specific
 %% module database schema if it does not exists yet.&lt;/p&gt;
-init(Host, ServerHost, Opts) -&gt;
+init(_Host, _ServerHost, _Opts) -&gt;
     pubsub_subscription:init(),
-    erlsdb:start(),
-    Bucket = gen_mod:get_opt(s3_tree_bucket, Opts, ServerHost),
-    s3:start(),
-    {ok, Buckets} = s3:list_buckets(),
-    case lists:member(Bucket, Buckets) of 
-        false -&gt;
-            s3:create_bucket(Bucket),
-            ?INFO_MSG(&quot;S3 bucket ~s created&quot;, [Bucket]);
-        true -&gt; ok
-    end,
-    ets:insert(gen_mod:get_module_proc(Host, config), {s3_bucket, Bucket}),
-    ets:insert(gen_mod:get_module_proc(ServerHost, config), {s3_bucket, Bucket}),
-    {ok, Domains, _Token}  = erlsdb:list_domains(),
-    case lists:member(?DOMAIN, Domains) of 
-        false -&gt;
-            erlsdb:create_domain(?DOMAIN),
-            ?INFO_MSG(&quot;SimpleDB domain ~s created&quot;, [?DOMAIN]);
-        true -&gt; ok
+    mnesia:create_table(pubsub_state,
+			[{disc_copies, [node()]},
+			 {attributes, record_info(fields, pubsub_state)}]),
+    mnesia:create_table(pubsub_item,
+			[{disc_only_copies, [node()]},
+			 {attributes, record_info(fields, pubsub_item)}]),
+    ItemsFields = record_info(fields, pubsub_item),
+    case mnesia:table_info(pubsub_item, attributes) of
+	ItemsFields -&gt; ok;
+	_ -&gt;
+	    mnesia:transform_table(pubsub_item, ignore, ItemsFields)
     end,
     ok.
 
@@ -231,7 +222,6 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) -&gt;
 %% @doc &lt;p&gt;&lt;/p&gt;
 create_node(NodeId, Owner) -&gt;
     OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
-    ?DEBUG(&quot;create node : ~p&quot;,[#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}]),
     set_state(#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}),
     {result, {default, broadcast}}.
 
@@ -632,23 +622,18 @@ purge_node(NodeId, Owner) -&gt;
 get_entity_affiliations(Host, Owner) -&gt;
     SubKey = jlib:jid_tolower(Owner),
     GenKey = jlib:jid_remove_resource(SubKey),
-    SGenKey = jlib:jid_to_string(GenKey),
-    SHost = host_to_string(Host),
-    ?DEBUG(&quot;select * from pubsub where  host='&quot;++SHost ++&quot;' and jid='&quot; ++ SGenKey ++ &quot;'&quot;, []),
-    {ok, Items}=erlsdb:s_all(&quot;select * from pubsub where  host='&quot;++SHost ++&quot;' and jid='&quot; ++ SGenKey ++ &quot;%'&quot;),
-    NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of
-	    [{nodetree, NT}] -&gt; NT;
+    States = mnesia:match_object(#pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
+    NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of
+	    [{nodetree, N}] -&gt; N;
 	    _ -&gt; nodetree_tree
 	end,
-    Affs = lists:foldl(fun(S,Acc)-&gt;
-        #pubsub_state{stateid = {_, {_, N}}, affiliation = A} = sdb_to_record(S),
-        #pubsub_node{nodeid = {H, _}} = Node = NodeTree:get_node(Host, N), %%ECE Can't do any better. Need to change mod_pubsub otherwise.
-        case H of
-		    Host -&gt; [{Node, A}|Acc];
-		    _ -&gt; Acc
-		end
-    end, [],  Items),
-    {result, Affs}.
+    Reply = lists:foldl(fun(#pubsub_state{stateid = {_, N}, affiliation = A}, Acc) -&gt;
+	case NodeTree:get_node(N) of
+	    #pubsub_node{nodeid = {Host, _}} = Node -&gt; [{Node, A}|Acc];
+	    _ -&gt; Acc
+	end
+    end, [], States),
+    {result, Reply}.
 
 get_node_affiliations(NodeId) -&gt;
     {result, States} = get_states(NodeId),
@@ -685,16 +670,21 @@ set_affiliation(NodeId, Owner, Affiliation) -&gt;
 %% that will be added to the affiliation stored in the main
 %% &lt;tt&gt;pubsub_state&lt;/tt&gt; table.&lt;/p&gt;
 get_entity_subscriptions(Host, Owner) -&gt;
-    SubKey = jlib:jid_tolower(Owner),
-    GenKey = jlib:jid_to_string(jlib:jid_remove_resource(SubKey)),
-    SHost = host_to_string(Host),
-    {ok, States}=erlsdb:s_all(&quot;select * from pubsub where host='&quot;++ SHost ++&quot;' and jid like '&quot;++ GenKey ++&quot;%'&quot;),
-	NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of
-	    [{nodetree, NT}] -&gt; NT;
+    {U, D, _} = SubKey = jlib:jid_tolower(Owner),
+    GenKey = jlib:jid_remove_resource(SubKey),
+    States = case SubKey of
+	GenKey -&gt; mnesia:match_object(
+	       #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
+	_ -&gt; mnesia:match_object(
+	       #pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
+	    ++ mnesia:match_object(
+	       #pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
+    end,
+    NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of
+	    [{nodetree, N}] -&gt; N;
 	    _ -&gt; nodetree_tree
 	end,
-	Reply = lists:foldl(fun(Record, Acc) -&gt;
-	#pubsub_state{stateid = {J, N}, subscriptions = Ss} = sdb_to_record(Record),
+    Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -&gt;
 	case NodeTree:get_node(N) of
 	    #pubsub_node{nodeid = {Host, _}} = Node -&gt;
 			lists:foldl(fun({Sub, SubId}, Acc2) -&gt;
@@ -736,7 +726,10 @@ set_subscriptions(NodeId, Owner, Subscription, SubId) -&gt;
     SubState = get_state(NodeId, SubKey),
     case {SubId, SubState#pubsub_state.subscriptions} of
 	{_, []} -&gt;
-	    {error, ?ERR_ITEM_NOT_FOUND};
+	    case Subscription of
+		none -&gt; {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, &quot;not-subscribed&quot;)};
+		_ -&gt; new_subscription(NodeId, Owner, Subscription, SubState)
+	    end;
 	{&quot;&quot;, [{_, SID}]} -&gt;
 	    case Subscription of
 		none -&gt; unsub_with_subid(NodeId, SID, SubState);
@@ -761,6 +754,12 @@ replace_subscription(_, [], Acc) -&gt;
 replace_subscription({Sub, SubId}, [{_, SubID} | T], Acc) -&gt;
     replace_subscription({Sub, SubId}, T, [{Sub, SubID} | Acc]).
 
+new_subscription(NodeId, Owner, Subscription, SubState) -&gt;
+    SubId = pubsub_subscription:add_subscription(Owner, NodeId, []),
+    Subscriptions = SubState#pubsub_state.subscriptions,
+    set_state(SubState#pubsub_state{subscriptions = [{Subscription, SubId} | Subscriptions]}),
+    {Subscription, SubId}.
+
 unsub_with_subid(NodeId, SubId, SubState) -&gt;
     pubsub_subscription:delete_subscription(SubState#pubsub_state.stateid,
 					 NodeId, SubId),
@@ -785,7 +784,7 @@ get_pending_nodes(Host, Owner) -&gt;
 					       affiliation = owner,
 					       _           = '_'}),
     NodeIDs = [ID || #pubsub_state{stateid = {_, ID}} &lt;- States],
-    NodeTree = case ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of
+    NodeTree = case catch ets:lookup(gen_mod:get_module_proc(Host, config), nodetree) of
 		    [{nodetree, N}] -&gt; N;
 		    _               -&gt; nodetree_tree
 	       end,
@@ -820,28 +819,6 @@ get_nodes_helper(NodeTree,
 	    false
     end.
 
-sdb_to_record({_Key, Attrs})-&gt;
-    str(Attrs, #pubsub_state{stateid={nil, {nil, nil}}});
-sdb_to_record(Item)-&gt;
-    str(Item, #pubsub_state{stateid={nil, {nil,nil}}}).
-    
-str([],#pubsub_state{}=State) -&gt; 
-    State;
-str([{&quot;host&quot;, V}|Rest], #pubsub_state{stateid={Jid, {_, Node}}}=N)-&gt;
-    Host = string_to_host(V),
-    str(Rest, N#pubsub_state{stateid={Jid, {Host, Node}}});
-str([{&quot;node&quot;, V}|Rest], #pubsub_state{stateid={Jid, {Host, _}}}=N)-&gt;
-    Node = mod_pubsub:string_to_node(V),
-    str(Rest, N#pubsub_state{stateid={Jid, {Host, Node}}});
-str([{&quot;jid&quot;, V}|Rest], #pubsub_state{stateid={_, {Host, Node}}}=N)-&gt;
-    Jid = jlib:jid_tolower(jlib:string_to_jid(V)),
-    str(Rest, N#pubsub_state{stateid={Jid, {Host, Node}}});    
-str([{&quot;affiliation&quot;, V}|Rest], N)-&gt;
-    str(Rest, N#pubsub_state{affiliation=l2a(V)});
-str([{&quot;subscription&quot;, V}|Rest], N)-&gt;
-    str(Rest, N#pubsub_state{subscriptions=[l2a(V)|N#pubsub_state.subscriptions]});
-str([{_, _ }|Rest], S)-&gt;str(Rest, S).
-
 %% @spec (NodeId) -&gt; [States] | []
 %%	 NodeId = mod_pubsub:pubsubNodeId()
 %% @doc Returns the list of stored states for a given node.
@@ -867,39 +844,18 @@ get_states(NodeId) -&gt;
 %%	 JID = mod_pubsub:jid()
 %%	 State = mod_pubsub:pubsubItems()
 %% @doc &lt;p&gt;Returns a state (one state list), given its reference.&lt;/p&gt;
-get_state({Host, Node}, JID) -&gt;
-    {_SJID, _SHost, _SNode, Key} = make_key({JID, {Host, Node}}),
-    {ok, Attrs} = erlsdb:get_attributes(?DOMAIN, Key), 
-    S = sdb_to_record(Attrs),
-    State = S#pubsub_state{stateid = {JID, {Host, Node}}},
-    %?DEBUG(&quot;state fetched from SDB for JID : ~s / Host: ~s / Node : ~s :~n~p&quot;, [SJID, SHost, SNode, State]),
-    State.
-
-make_key({JID, {Host, Node}})-&gt;
-    SNode = mod_pubsub:node_to_string(Node),
-    SHost = host_to_string(Host),
-    SJID = jlib:jid_to_string(JID),
-    {SJID, SHost, SNode, SHost ++ &quot;:&quot; ++ SNode ++ &quot;:&quot; ++ SJID}.
-
+get_state(NodeId, JID) -&gt;
+    StateId = {JID, NodeId},
+    case catch mnesia:read({pubsub_state, StateId}) of
+	[State] when is_record(State, pubsub_state) -&gt; State;
+	_ -&gt; #pubsub_state{stateid=StateId}
+    end.
 
 %% @spec (State) -&gt; ok | {error, Reason::stanzaError()}
 %%	 State = mod_pubsub:pubsubStates()
 %% @doc &lt;p&gt;Write a state into database.&lt;/p&gt;
-set_state(#pubsub_state{stateid = StateId,
-                      affiliation = Aff,
-                      subscriptions = Subs})-&gt;
-    {SJID, SHost, SNode, Key} = make_key(StateId),
-    SdbSubs = lists:map(fun(S)-&gt;
-        {&quot;subscription&quot;, a2l(S)}
-    end, Subs),
-
-    erlsdb:replace_attributes(?DOMAIN, Key, [{&quot;host&quot;, SHost}, 
-                                         {&quot;node&quot;, SNode},
-                                         {&quot;jid&quot;, SJID},
-                                         {&quot;affiliation&quot;, a2l(Aff)}
-                                         | SdbSubs ]),
-
-    ok;
+set_state(State) when is_record(State, pubsub_state) -&gt;
+    mnesia:write(State);
 set_state(_) -&gt;
     {error, ?ERR_INTERNAL_SERVER_ERROR}.
 
@@ -908,9 +864,7 @@ set_state(_) -&gt;
 %%	 JID = mod_pubsub:jid()
 %% @doc &lt;p&gt;Delete a state from database.&lt;/p&gt;
 del_state(NodeId, JID) -&gt;
-    {_SJID, _SHost, _SNode, Key} = make_key({JID, NodeId}),
-    erlsdb:delete_item(?DOMAIN,Key),
-    ok.
+    mnesia:delete({pubsub_state, {JID, NodeId}}).
 
 %% @spec (NodeId, From) -&gt; [Items] | []
 %%	 NodeId = mod_pubsub:pubsubNodeId()
@@ -925,13 +879,9 @@ del_state(NodeId, JID) -&gt;
 %% they can implement this function like this:
 %% ```get_items(NodeId, From) -&gt;
 %%	   node_default:get_items(NodeId, From).'''&lt;/p&gt;
-get_items({Host, Node}, _From) -&gt;
-    Items = s3:get_objects(get_bucket(Host), [{prefix,build_key(Host, Node,&quot;&quot;)}] ),
-    Items2 = lists:map(fun({_K, Conf, _H})-&gt;
-        binary_to_term(list_to_binary(Conf))
-    end, Items),
-    {result, lists:reverse(lists:keysort(#pubsub_item.modification, Items2))}.
-
+get_items(NodeId, _From) -&gt;
+    Items = mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'}),
+    {result, lists:reverse(lists:keysort(#pubsub_item.modification, Items))}.
 get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -&gt;
     SubKey = jlib:jid_tolower(JID),
     GenKey = jlib:jid_remove_resource(SubKey),
@@ -969,25 +919,17 @@ get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -
 	    get_items(NodeId, JID)
     end.
 
-build_key(Host, Node,ItemId)-&gt;
-    SHost = host_to_string(Host),
-    SNode = mod_pubsub:node_to_string(Node),
-    ?PREFIX++&quot;:&quot;++SHost++&quot;:&quot;++SNode++&quot;:&quot;++ItemId.
-build_key(#pubsub_item{itemid={ItemId, {Host, Node}}})-&gt;
-    build_key(Host, Node,ItemId).
-
-
 %% @spec (NodeId, ItemId) -&gt; [Item] | []
 %%	 NodeId = mod_pubsub:pubsubNodeId()
 %%	 ItemId = string()
 %%	 Item = mod_pubsub:pubsubItems()
 %% @doc &lt;p&gt;Returns an item (one item list), given its reference.&lt;/p&gt;
-get_item({Host, Node}, ItemId) -&gt;
-    case s3:read_object(get_bucket(Host), build_key(Host, Node,ItemId)) of
-        {ok, {Conf, _H}}-&gt;
-            {result, binary_to_term(list_to_binary(Conf))};
-        _ -&gt; 
-            {error, ?ERR_ITEM_NOT_FOUND}
+get_item(NodeId, ItemId) -&gt;
+    case mnesia:read({pubsub_item, {ItemId, NodeId}}) of
+	[Item] when is_record(Item, pubsub_item) -&gt;
+	    {result, Item};
+	_ -&gt;
+	    {error, ?ERR_ITEM_NOT_FOUND}
     end.
 get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -&gt;
     SubKey = jlib:jid_tolower(JID),
@@ -1028,11 +970,8 @@ get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _S
 %% @spec (Item) -&gt; ok | {error, Reason::stanzaError()}
 %%	 Item = mod_pubsub:pubsubItems()
 %% @doc &lt;p&gt;Write an item into database.&lt;/p&gt;
-set_item(#pubsub_item{itemid={_,NodeId}}=Item) when is_record(Item, pubsub_item) -&gt;
-    spawn(fun()-&gt;
-        s3:write_object(get_bucket(NodeId), build_key(Item), term_to_binary(Item), &quot;application/erlang&quot;)
-    end),
-    ok;
+set_item(Item) when is_record(Item, pubsub_item) -&gt;
+    mnesia:write(Item);
 set_item(_) -&gt;
     {error, ?ERR_INTERNAL_SERVER_ERROR}.
 
@@ -1040,11 +979,8 @@ set_item(_) -&gt;
 %%	 NodeId = mod_pubsub:pubsubNodeId()
 %%	 ItemId = string()
 %% @doc &lt;p&gt;Delete an item from database.&lt;/p&gt;
-del_item({Host, Node}=NodeId, ItemId) -&gt;
-    spawn(fun()-&gt;
-        s3:delete_object(get_bucket(NodeId), build_key(Host, Node, ItemId))
-    end),
-    ok.
+del_item(NodeId, ItemId) -&gt;
+    mnesia:delete({pubsub_item, {ItemId, NodeId}}).
 del_items(NodeId, ItemIds) -&gt;
     lists:foreach(fun(ItemId) -&gt;
 	del_item(NodeId, ItemId)
@@ -1075,44 +1011,6 @@ can_fetch_item(outcast,      _)             -&gt; false;
 can_fetch_item(none, Subscriptions) -&gt; is_subscribed(Subscriptions);
 can_fetch_item(_Affiliation, _Subscription) -&gt; false.
 
-%% @spec (NodeId) -&gt; Node
-%% @doc retreive pubsubNode() representation giving a NodeId
-%get_nodename(NodeId) -&gt;
-%    case mnesia:index_read(pubsub_node, NodeId, #pubsub_node.id) of
-%	[#pubsub_node{nodeid = {_, Node}}] -&gt; Node;
-%	_ -&gt; []
-%    end.
-
-a2l([])-&gt;[];    
-a2l(Atom) when is_atom(Atom)-&gt;atom_to_list(Atom).
-l2a(&quot;member&quot;)-&gt;member;
-l2a(&quot;owner&quot;)-&gt;owner;
-l2a(&quot;publisher&quot;)-&gt;publisher;
-l2a(&quot;outcast&quot;)-&gt;outcast;
-l2a(&quot;subscribed&quot;)-&gt;subscribed;
-l2a(&quot;none&quot;)-&gt;none.
-
-host_to_string({_, _, _}=Host)-&gt;
-    jlib:jid_to_string(Host);
-host_to_string(Host) when is_list(Host)-&gt; Host.
-string_to_host(Host) when is_list(Host)-&gt;
-   case jlib:jid_tolower(jlib:string_to_jid(Host)) of
-        {[], PubSub, []} -&gt; PubSub;
-        JID -&gt; JID
-    end.
-    
-get_bucket({_U, S, _R})-&gt;
-    get_bucket(S);
-get_bucket({{_U, S, _R}, _Node})-&gt;
-    get_bucket(S);
-get_bucket({Host, _Node})-&gt;
-    get_bucket(Host);
-get_bucket(Host) when is_list(Host)-&gt;
-    [{s3_bucket, Bucket}] =  ets:lookup(gen_mod:get_module_proc(Host, config), s3_bucket),
-    Bucket;
-get_bucket(Host)-&gt;
-    ?ERROR_MSG(&quot;Unsupported host format : ~p&quot;, [Host]).
-
 is_subscribed(Subscriptions) -&gt;
     lists:any(fun ({subscribed, _SubId}) -&gt; true;
                   (_)                    -&gt; false</diff>
      <filename>src/mod_pubsub/node_hometree.erl</filename>
    </modified>
    <modified>
      <diff>@@ -195,36 +195,36 @@ get_affiliation(NodeId, Owner) -&gt;
 
 set_affiliation(NodeId, Owner, Affiliation) -&gt;
     node_hometree:set_affiliation(NodeId, Owner, Affiliation).
-get_entity_subscriptions(Host, Owner) -&gt;
-    node_default:get_entity_subscriptions(Host, Owner).
-    %{U, D, _} = SubKey = jlib:jid_tolower(Owner),
-    %GenKey = jlib:jid_remove_resource(SubKey),
-    %States = case SubKey of
-	%GenKey -&gt; mnesia:match_object(
-	%       #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
-	%_ -&gt; mnesia:match_object(
-	%       #pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
-	%    ++ mnesia:match_object(
-	%       #pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
-    %end,
-    %NodeTree = case ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of
-	%    [{nodetree, N}] -&gt; N;
-	%    _ -&gt; nodetree_tree
-	%end,
-    %Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -&gt;
-	%case NodeTree:get_node(N) of
-	%    #pubsub_node{nodeid = {{_, D, _}, _}} = Node -&gt;
-	%		lists:foldl(fun({subscribed, SubID}, Acc2) -&gt;
-	%				   [{Node, subscribed, SubID, J} | Acc2];
-	%				({pending, _SubID}, Acc2) -&gt;
-	%				    [{Node, pending, J} | Acc2];
-	%				(S, Acc2) -&gt;
-	%				    [{Node, S, J} | Acc2]
-	%			    end, Acc, Ss);
-	%    _ -&gt; Acc
-	%end
-    %end, [], States),
-    %{result, Reply}.
+
+get_entity_subscriptions(_Host, Owner) -&gt;
+    {U, D, _} = SubKey = jlib:jid_tolower(Owner),
+    GenKey = jlib:jid_remove_resource(SubKey),
+    States = case SubKey of
+	GenKey -&gt; mnesia:match_object(
+	       #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
+	_ -&gt; mnesia:match_object(
+	       #pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
+	    ++ mnesia:match_object(
+	       #pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
+    end,
+    NodeTree = case catch ets:lookup(gen_mod:get_module_proc(D, config), nodetree) of
+	    [{nodetree, N}] -&gt; N;
+	    _ -&gt; nodetree_tree
+	end,
+    Reply = lists:foldl(fun(#pubsub_state{stateid = {J, N}, subscriptions = Ss}, Acc) -&gt;
+	case NodeTree:get_node(N) of
+	    #pubsub_node{nodeid = {{_, D, _}, _}} = Node -&gt;
+			lists:foldl(fun({subscribed, SubID}, Acc2) -&gt;
+					   [{Node, subscribed, SubID, J} | Acc2];
+					({pending, _SubID}, Acc2) -&gt;
+					    [{Node, pending, J} | Acc2];
+					(S, Acc2) -&gt;
+					    [{Node, S, J} | Acc2]
+				    end, Acc, Ss);
+	    _ -&gt; Acc
+	end
+    end, [], States),
+    {result, Reply}.
 
 get_node_subscriptions(NodeId) -&gt;
     %% note: get_node_subscriptions is used for broadcasting</diff>
      <filename>src/mod_pubsub/node_pep.erl</filename>
    </modified>
    <modified>
      <diff>@@ -40,7 +40,7 @@
 
 -include(&quot;pubsub.hrl&quot;).
 -include(&quot;jlib.hrl&quot;).
--include(&quot;ejabberd.hrl&quot;).
+
 -behaviour(gen_pubsub_nodetree).
 
 -export([init/3,
@@ -57,11 +57,9 @@
 	 get_subnodes/3,
 	 get_subnodes_tree/3,
 	 create_node/6,
-	 delete_node/2,
-	 make_key/1
+	 delete_node/2
 	]).
 
--define(PREFIX, &quot;node:&quot;).
 
 %% ================
 %% API definition
@@ -76,18 +74,18 @@
 %% &lt;p&gt;This function is mainly used to trigger the setup task necessary for the
 %% plugin. It can be used for example by the developer to create the specific
 %% module database schema if it does not exists yet.&lt;/p&gt;
-init(Host, ServerHost, Opts) -&gt;
-    Bucket = gen_mod:get_opt(s3_bucket, Opts, ServerHost),
-    s3:start(),
-    {ok, Buckets} = s3:list_buckets(),
-    case lists:member(Bucket, Buckets) of 
-        false -&gt;
-            s3:create_bucket(Bucket),
-            ?INFO_MSG(&quot;S3 bucket ~s created&quot;, [Bucket]);
-        true -&gt; ok
+init(_Host, _ServerHost, _Opts) -&gt;
+    mnesia:create_table(pubsub_node,
+			[{disc_copies, [node()]},
+			 {attributes, record_info(fields, pubsub_node)}]),
+    mnesia:add_table_index(pubsub_node, id),
+    NodesFields = record_info(fields, pubsub_node),
+    case mnesia:table_info(pubsub_node, attributes) of
+	NodesFields -&gt; ok;
+	_ -&gt;
+	    ok
+	    %% mnesia:transform_table(pubsub_state, ignore, StatesFields)
     end,
-    ets:insert(gen_mod:get_module_proc(Host, config), {s3_bucket, Bucket}),
-    ets:insert(gen_mod:get_module_proc(ServerHost, config), {s3_bucket, Bucket}),
     ok.
 terminate(_Host, _ServerHost) -&gt;
     ok.
@@ -100,43 +98,11 @@ options() -&gt;
 
 %% @spec (NodeRecord) -&gt; ok | {error, Reason}
 %%     Record = mod_pubsub:pubsub_node()
-set_node(#pubsub_node{nodeid = NodeId}=N)-&gt;
-    Key = make_key(NodeId),
-    s3:write_term(get_bucket(NodeId), Key, N),
-    ok;
-    
+set_node(Record) when is_record(Record, pubsub_node) -&gt;
+    mnesia:write(Record);
 set_node(_) -&gt;
     {error, ?ERR_INTERNAL_SERVER_ERROR}.
 
-make_key({{_U, _S, _R}=JID, []})-&gt;
-    SHost = jlib:jid_to_string(JID),
-    ?PREFIX++SHost ++ &quot;:&quot;;
-make_key({{_U, _S, _R}=JID, Node})-&gt;
-    SNode = mod_pubsub:node_to_string(Node),
-    SHost = jlib:jid_to_string(JID),
-    ?PREFIX++SHost ++ &quot;:&quot; ++ SNode;
-make_key({Host, []})-&gt;
-    ?PREFIX++Host ++ &quot;:&quot;;
-make_key({Host, Node})-&gt;
-    SNode = mod_pubsub:node_to_string(Node),
-    ?PREFIX++Host ++ &quot;:&quot; ++ SNode.
-parse_key(?PREFIX++Key) -&gt;
-    [Host| R] = string:tokens(Key, &quot;:&quot;),
-    {Host, mod_pubsub:string_to_node(string:join(R, &quot;:&quot;))}.
-    
-    
-get_bucket({_U, S, _R})-&gt;
-    get_bucket(S);
-get_bucket({{_U, S, _R}, _Node})-&gt;
-    get_bucket(S);
-get_bucket({Host, _Node})-&gt;
-    get_bucket(Host);
-get_bucket(Host) when is_list(Host)-&gt;
-    [{s3_bucket, Bucket}] =  ets:lookup(gen_mod:get_module_proc(Host, config), s3_bucket),
-    Bucket;
-get_bucket(Host)-&gt;
-    ?ERROR_MSG(&quot;Unsupported host format : ~p&quot;, [Host]).
-
 get_node(Host, Node, _From) -&gt;
     get_node(Host, Node).
 
@@ -144,17 +110,17 @@ get_node(Host, Node, _From) -&gt;
 %%     Host = mod_pubsub:host()
 %%     Node = mod_pubsub:pubsubNode()
 get_node(Host, Node) -&gt;
-    Key = make_key({Host, Node}),
-    case s3:read_object(get_bucket(Host), Key) of
-        {ok, {Conf, _H}}-&gt;
-            R = binary_to_term(list_to_binary(Conf)),
-            ?DEBUG(&quot;Got node : ~p&quot;, [R]),
-            R;
-        _ -&gt; 
-            {error, ?ERR_ITEM_NOT_FOUND}
-    end.  
-get_node({Host, Node}) -&gt;
-  get_node(Host, Node).
+    case catch mnesia:read({pubsub_node, {Host, Node}}) of
+	[Record] when is_record(Record, pubsub_node) -&gt; Record;
+	[] -&gt; {error, ?ERR_ITEM_NOT_FOUND};
+	Error -&gt; Error
+    end.
+get_node(NodeId) -&gt;
+    case catch mnesia:index_read(pubsub_node, NodeId, #pubsub_node.id) of
+	[Record] when is_record(Record, pubsub_node) -&gt; Record;
+	[] -&gt; {error, ?ERR_ITEM_NOT_FOUND};
+	Error -&gt; Error
+    end.
 
 get_nodes(Host, _From) -&gt;
     get_nodes(Host).
@@ -162,9 +128,7 @@ get_nodes(Host, _From) -&gt;
 %% @spec (Host) -&gt; [pubsubNode()] | {error, Reason}
 %%     Host = mod_pubsub:host() | mod_pubsub:jid()
 get_nodes(Host) -&gt;
-    K=make_key({Host, []}),
-    Nodes =  s3:get_objects(get_bucket(Host), [{prefix, K}]),
-    lists:map(fun({_K, Bin, _H})-&gt; binary_to_term(list_to_binary(Bin)) end, Nodes).
+    mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
 
 %% @spec (Host, Node, From) -&gt; [{Depth, Record}] | {error, Reason}
 %%     Host   = mod_pubsub:host() | mod_pubsub:jid()
@@ -195,70 +159,83 @@ get_parentnodes_tree(Host, Node, From) -&gt;
 %%     Node = mod_pubsub:pubsubNode()
 %%     From = mod_pubsub:jid()
 get_subnodes(Host, Node, _From) -&gt;
-    Key=make_key({Host, Node}),
-    K = case lists:reverse(Key) of
-        [$/|_R] -&gt; Key;
-        _ -&gt; Key ++ &quot;/&quot;
-    end,
-    Nodes = s3:get_objects(get_bucket(Host), [{prefix, K}, {delimiter, &quot;/&quot;}]),
-    lists:map(fun({_K, Bin, _H})-&gt; binary_to_term(list_to_binary(Bin)) end, Nodes).
+    get_subnodes(Host, Node).
+get_subnodes(Host, &lt;&lt;&gt;&gt;) -&gt;
+    Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _},
+				 parents = Parents} = N &lt;- mnesia:table(pubsub_node),
+		       Host == NHost,
+		       Parents == []]),
+    qlc:e(Q);
+get_subnodes(Host, Node) -&gt;
+    Q = qlc:q([N || #pubsub_node{nodeid = {NHost, _},
+				 parents = Parents} = N &lt;- mnesia:table(pubsub_node),
+		       Host == NHost,
+		       lists:member(Node, Parents)]),
+    qlc:e(Q).
 
+get_subnodes_tree(Host, Node, _From) -&gt;
+    get_subnodes_tree(Host, Node).
 
 %% @spec (Host, Index) -&gt; [pubsubNodeIdx()] | {error, Reason}
 %%     Host = mod_pubsub:host()
 %%     Node = mod_pubsub:pubsubNode()
-get_subnodes_tree(Host, Node,_From) -&gt;
-    get_subnodes_tree(Host, Node).
-
-get_subnodes_tree(Host, Node)-&gt;
-    Key=make_key({Host, Node}),
-    {ok, Items} =  s3:list_objects(get_bucket(Host), [{prefix, Key}]),
-    lists:foldl(fun({object_info,{&quot;Key&quot;, K }, _, _,_}, Acc)-&gt; 
-            case parse_key(K) of
-                {_H, Node}-&gt;Acc;
-                {_H, N}-&gt;[N|Acc]
-            end
-         end, [], Items).
+%%     From = mod_pubsub:jid()
+get_subnodes_tree(Host, Node) -&gt;
+    case get_node(Host, Node) of
+    {error, _} -&gt;
+	[];
+    Rec -&gt;
+	BasePlugin = list_to_atom(&quot;node_&quot;++Rec#pubsub_node.type),
+	BasePath = BasePlugin:node_to_path(Node),
+	mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}} = R, Acc) -&gt;
+		Plugin = list_to_atom(&quot;node_&quot;++R#pubsub_node.type),
+		Path = Plugin:node_to_path(N),
+		case lists:prefix(BasePath, Path) and (H == Host) of
+		    true -&gt; [R | Acc];
+		    false -&gt; Acc
+		end
+	    end, [], pubsub_node)
+    end.
 
-%% @spec (Key, Node, Type, Owner, Options) -&gt; ok | {error, Reason}
-%%     Key = mod_pubsub:host() | mod_pubsub:jid()
+%% @spec (Host, Node, Type, Owner, Options) -&gt; 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, Parents) -&gt;
+create_node(Host, Node, Type, Owner, Options, Parents) -&gt;
     BJID = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
-    case get_node(Key, Node) of
-	{error, ?ERR_ITEM_NOT_FOUND} -&gt;
-	    {ParentNode, ParentExists} =
-		case Key of
+    case catch mnesia:read({pubsub_node, {Host, Node}}) of
+	[] -&gt;
+	    ParentExists =
+		case Host of
 		    {_U, _S, _R} -&gt;
 			%% This is special case for PEP handling
 			%% PEP does not uses hierarchy
-			{[], true};
+			true;
 		    _ -&gt;
 			case Parents of
 			[] -&gt; true;
 			[Parent|_] -&gt;
-			    case get_node(Key, Parent) of
-				{error, ?ERR_ITEM_NOT_FOUND} -&gt; false;
-				#pubsub_node{owners = Owners} -&gt; lists:member(BJID, Owners);
-				_ -&gt;  false
-			    end
+			    case catch mnesia:read({pubsub_node, {Host, Parent}}) of
+				[#pubsub_node{owners = [{[], Host, []}]}] -&gt; true;
+				[#pubsub_node{owners = Owners}] -&gt; lists:member(BJID, Owners);
+				_ -&gt; false
+			    end;
+			_ -&gt;
+			    false
 			end
 		end,
 	    case ParentExists of
 		true -&gt;
-		    %% Service requires registration
-		    %%{error, ?ERR_REGISTRATION_REQUIRED};
-		    %NodeId = pubsub_index:new(node),
-		    set_node(#pubsub_node{nodeid = {Key, Node},
+		    NodeId = pubsub_index:new(node),
+		    mnesia:write(#pubsub_node{nodeid = {Host, Node},
+					      id = NodeId,
 					      parents = Parents,
-					      id = {Key, Node},
 					      type = Type,
 					      owners = [BJID],
 					      options = Options}),
-			{ok, {Key, Node}};
+		    {ok, NodeId};
 		false -&gt;
 		    %% Requesting entity is prohibited from creating nodes
 		    {error, ?ERR_FORBIDDEN}
@@ -268,13 +245,13 @@ create_node(Key, Node, Type, Owner, Options, Parents) -&gt;
 	    {error, ?ERR_CONFLICT}
     end.
 
-%% @spec (Key, Node) -&gt; [mod_pubsub:node()]
-%%     Key = mod_pubsub:host() | mod_pubsub:jid()
+%% @spec (Host, Node) -&gt; [mod_pubsub:node()]
+%%     Host = mod_pubsub:host() | mod_pubsub:jid()
 %%     Node = mod_pubsub:pubsubNode()
-delete_node(Key, Node) -&gt;
-    Removed = get_subnodes_tree(Key, Node),
-    lists:foreach(fun(N) -&gt;
-            K = make_key({Key, N}),
-		    s3:delete_object(get_bucket(Key), K)
-		  end, Removed),
+delete_node(Host, Node) -&gt;
+    Removed = get_subnodes_tree(Host, Node),
+    lists:foreach(fun(#pubsub_node{nodeid = {_, N}, id = I}) -&gt;
+	    pubsub_index:free(node, I),
+	    mnesia:delete({pubsub_node, {Host, N}})
+	end, Removed),
     Removed.</diff>
      <filename>src/mod_pubsub/nodetree_tree.erl</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c84889ccd2c33f58265892eb8a4ec69f6206e6fc</id>
    </parent>
  </parents>
  <author>
    <name>Eric Cestari</name>
    <email>ecestari@mac.com</email>
  </author>
  <url>http://github.com/cstar/ejabberd/commit/201526edac8c9040b750621c852602767de8f906</url>
  <id>201526edac8c9040b750621c852602767de8f906</id>
  <committed-date>2009-10-29T07:19:17-07:00</committed-date>
  <authored-date>2009-10-29T07:19:17-07:00</authored-date>
  <message>Moving my AWS code out of the way in mod_pubsub.
Don't have time to maintain it currently.
There are many good optimizations and features in mod_pubsub I'll need to port.</message>
  <tree>aa892d8336496b857942934d93a934602ae5d04c</tree>
  <committer>
    <name>Eric Cestari</name>
    <email>ecestari@mac.com</email>
  </committer>
</commit>
