diff options
Diffstat (limited to 'src/mod_pubsub/pubsub_odbc.patch')
-rw-r--r-- | src/mod_pubsub/pubsub_odbc.patch | 1571 |
1 files changed, 920 insertions, 651 deletions
diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index b7c18bac..986c6fe0 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,222 +1,376 @@ ---- mod_pubsub.erl 2012-04-11 16:47:33.620900390 +0200 -+++ mod_pubsub_odbc.erl 2012-04-11 16:47:53.390899087 +0200 -@@ -42,7 +42,7 @@ +--- mod_pubsub.erl 2013-03-03 23:32:53.669953265 +0100 ++++ mod_pubsub_odbc.erl 2013-03-03 23:37:10.128953065 +0100 +@@ -41,7 +41,7 @@ %%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see %%% XEP-0060 section 12.18. --module(mod_pubsub). +-module(mod_pubsub_odbc). + -author('christophe.romain@process-one.net'). - -version('1.13-0'). -@@ -54,9 +54,9 @@ - -include("jlib.hrl"). +@@ -59,11 +59,11 @@ + -include("pubsub.hrl"). ---define(STDTREE, "tree"). ---define(STDNODE, "flat"). ---define(PEPNODE, "pep"). -+-define(STDTREE, "tree_odbc"). -+-define(STDNODE, "flat_odbc"). -+-define(PEPNODE, "pep_odbc"). +--define(STDTREE, <<"tree">>). ++-define(STDTREE, <<"tree_odbc">>). + +--define(STDNODE, <<"flat">>). ++-define(STDNODE, <<"flat_odbc">>). + +--define(PEPNODE, <<"pep">>). ++-define(PEPNODE, <<"pep_odbc">>). %% exports for hooks - -export([presence_probe/3, -@@ -103,7 +103,7 @@ - string_to_affiliation/1, - extended_error/2, - extended_error/3, -- rename_default_nodeplugin/0 -+ escape/1 - ]). + -export([presence_probe/3, caps_update/3, +@@ -98,7 +98,7 @@ + -export([subscription_to_string/1, affiliation_to_string/1, + string_to_subscription/1, string_to_affiliation/1, + extended_error/2, extended_error/3, +- rename_default_nodeplugin/0]). ++ escape/1]). %% API and gen_server callbacks -@@ -122,7 +122,7 @@ - -export([send_loop/1 - ]). + -export([start_link/2, start/2, stop/1, init/1, +@@ -108,7 +108,7 @@ + %% calls for parallel sending of last items + -export([send_loop/1]). --define(PROCNAME, ejabberd_mod_pubsub). +-define(PROCNAME, ejabberd_mod_pubsub_odbc). + -define(LOOPNAME, ejabberd_mod_pubsub_loop). - -define(PLUGIN_PREFIX, "node_"). - -define(TREE_PREFIX, "nodetree_"). -@@ -217,8 +217,6 @@ - ok + +@@ -333,8 +333,6 @@ + false -> ok end, ejabberd_router:register_route(Host), - update_node_database(Host, ServerHost), - update_state_database(Host, ServerHost), - put(server_host, ServerHost), % not clean, but needed to plug hooks at any location + put(server_host, ServerHost), init_nodes(Host, ServerHost, NodeTree, Plugins), - State = #state{host = Host, -@@ -283,207 +281,14 @@ + State = #state{host = Host, server_host = ServerHost, +@@ -394,359 +392,14 @@ + ok. init_nodes(Host, ServerHost, _NodeTree, Plugins) -> - %% TODO, this call should be done plugin side -- case lists:member("hometree", Plugins) of -+ case lists:member("hometree_odbc", Plugins) of - true -> -- create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree"), -- create_node(Host, ServerHost, string_to_node("/home/"++ServerHost), service_jid(Host), "hometree"); -+ create_node(Host, ServerHost, string_to_node("/home"), service_jid(Host), "hometree_odbc"), -+ create_node(Host, ServerHost, string_to_node("/home/"++ServerHost), service_jid(Host), "hometree_odbc"); - false -> - ok +- case lists:member(<<"hometree">>, Plugins) of ++ case lists:member(<<"hometree_odbc">>, Plugins) of + true -> +- create_node(Host, ServerHost, <<"/home">>, service_jid(Host), <<"hometree">>), ++ create_node(Host, ServerHost, <<"/home">>, service_jid(Host), <<"hometree_odbc">>), + create_node(Host, ServerHost, <<"/home/", ServerHost/binary>>, service_jid(Host), +- <<"hometree">>); ++ <<"hometree_odbc">>); + false -> ok end. -update_node_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 -- [host_node, host_parent, info] -> -- ?INFO_MSG("upgrade node pubsub tables",[]), -- F = fun() -> -- {Result, LastIdx} = lists:foldl( -- fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) -> -- ItemsList = -- lists:foldl( -- fun({item, IID, Publisher, Payload}, Acc) -> -- C = {unknown, Publisher}, -- M = {now(), Publisher}, -- mnesia:write( -- #pubsub_item{itemid = {IID, NodeIdx}, -- creation = C, -- modification = M, -- payload = Payload}), -- [{Publisher, IID} | Acc] -- end, [], Items), -- Owners = -- dict:fold( -- fun(JID, {entity, Aff, Sub}, Acc) -> -- UsrItems = -- lists:foldl( -- fun({P, I}, IAcc) -> -- case P of -- JID -> [I | IAcc]; -- _ -> IAcc -- end -- end, [], ItemsList), -- mnesia:write({pubsub_state, -- {JID, NodeIdx}, -- UsrItems, -- Aff, -- Sub}), -- case Aff of -- owner -> [JID | Acc]; -- _ -> Acc -- end -- end, [], Entities), -- mnesia:delete({pubsub_node, NodeId}), -- {[#pubsub_node{nodeid = NodeId, -- id = NodeIdx, -- parents = [element(2, ParentId)], -- owners = Owners, -- options = Options} | -- RecList], NodeIdx + 1} -- end, {[], 1}, -- mnesia:match_object( -- {pubsub_node, {Host, '_'}, '_', '_'})), -- mnesia:write(#pubsub_index{index = node, last = LastIdx, free = []}), -- Result -- end, -- {atomic, NewRecords} = mnesia:transaction(F), -- {atomic, ok} = mnesia:delete_table(pubsub_node), -- {atomic, ok} = mnesia:create_table(pubsub_node, -- [{disc_copies, [node()]}, -- {attributes, record_info(fields, pubsub_node)}]), -- FNew = fun() -> lists:foreach(fun(Record) -> -- mnesia:write(Record) -- end, NewRecords) -- end, -- case mnesia:transaction(FNew) of -- {atomic, Result} -> -- ?INFO_MSG("Pubsub node tables updated correctly: ~p", [Result]); -- {aborted, Reason} -> -- ?ERROR_MSG("Problem updating Pubsub node 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, -- parents = [Parent], -- type = Type, -- owners = Owners, -- options = Options} -- end, -- mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), -- FNew = fun() -> -- LastIdx = 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, '_'}, '_'}, '_', '_', '_', '_', '_'})), -- mnesia:write(#pubsub_index{index = node, last = LastIdx, free = []}) -- end, -- case mnesia:transaction(FNew) of -- {atomic, Result} -> -- rename_default_nodeplugin(), -- ?INFO_MSG("Pubsub node tables updated correctly: ~p", [Result]); -- {aborted, Reason} -> -- ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", [Reason]) -- end; -- [nodeid, id, parent, type, owners, options] -> -- F = fun({pubsub_node, NodeId, Id, Parent, Type, Owners, Options}) -> -- #pubsub_node{ -- nodeid = NodeId, -- id = Id, -- parents = [Parent], -- type = Type, -- owners = Owners, -- options = Options} -- end, -- mnesia:transform_table(pubsub_node, F, [nodeid, id, parents, type, owners, options]), -- rename_default_nodeplugin(); -- _ -> -- ok +- [host_node, host_parent, info] -> +- ?INFO_MSG("upgrade node pubsub tables", []), +- F = fun () -> +- {Result, LastIdx} = lists:foldl(fun ({pubsub_node, +- NodeId, ParentId, +- {nodeinfo, Items, +- Options, +- Entities}}, +- {RecList, +- NodeIdx}) -> +- ItemsList = +- lists:foldl(fun +- ({item, +- IID, +- Publisher, +- Payload}, +- Acc) -> +- C = +- {unknown, +- Publisher}, +- M = +- {now(), +- Publisher}, +- mnesia:write(#pubsub_item{itemid +- = +- {IID, +- NodeIdx}, +- creation +- = +- C, +- modification +- = +- M, +- payload +- = +- Payload}), +- [{Publisher, +- IID} +- | Acc] +- end, +- [], +- Items), +- Owners = +- dict:fold(fun +- (JID, +- {entity, +- Aff, +- Sub}, +- Acc) -> +- UsrItems = +- lists:foldl(fun +- ({P, +- I}, +- IAcc) -> +- case +- P +- of +- JID -> +- [I +- | IAcc]; +- _ -> +- IAcc +- end +- end, +- [], +- ItemsList), +- mnesia:write({pubsub_state, +- {JID, +- NodeIdx}, +- UsrItems, +- Aff, +- Sub}), +- case +- Aff +- of +- owner -> +- [JID +- | Acc]; +- _ -> +- Acc +- end +- end, +- [], +- Entities), +- mnesia:delete({pubsub_node, +- NodeId}), +- {[#pubsub_node{nodeid +- = +- NodeId, +- id +- = +- NodeIdx, +- parents +- = +- [element(2, +- ParentId)], +- owners +- = +- Owners, +- options +- = +- Options} +- | RecList], +- NodeIdx + 1} +- end, +- {[], 1}, +- mnesia:match_object({pubsub_node, +- {Host, +- '_'}, +- '_', +- '_'})), +- mnesia:write(#pubsub_index{index = node, last = LastIdx, +- free = []}), +- Result +- end, +- {atomic, NewRecords} = mnesia:transaction(F), +- {atomic, ok} = mnesia:delete_table(pubsub_node), +- {atomic, ok} = mnesia:create_table(pubsub_node, +- [{disc_copies, [node()]}, +- {attributes, +- record_info(fields, +- pubsub_node)}]), +- FNew = fun () -> +- lists:foreach(fun (Record) -> mnesia:write(Record) end, +- NewRecords) +- end, +- case mnesia:transaction(FNew) of +- {atomic, Result} -> +- ?INFO_MSG("Pubsub node tables updated correctly: ~p", +- [Result]); +- {aborted, Reason} -> +- ?ERROR_MSG("Problem updating Pubsub node 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, +- parents = [Parent], type = Type, +- owners = Owners, options = Options} +- end, +- mnesia:transform_table(pubsub_node, F, +- [nodeid, id, parents, type, owners, options]), +- FNew = fun () -> +- LastIdx = 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, +- '_'}, +- '_'}, +- '_', '_', +- '_', '_', +- '_'})), +- mnesia:write(#pubsub_index{index = node, +- last = LastIdx, free = []}) +- end, +- case mnesia:transaction(FNew) of +- {atomic, Result} -> +- rename_default_nodeplugin(), +- ?INFO_MSG("Pubsub node tables updated correctly: ~p", +- [Result]); +- {aborted, Reason} -> +- ?ERROR_MSG("Problem updating Pubsub node tables:~n~p", +- [Reason]) +- end; +- [nodeid, id, parent, type, owners, options] -> +- F = fun ({pubsub_node, NodeId, Id, Parent, Type, Owners, +- Options}) -> +- #pubsub_node{nodeid = NodeId, id = Id, +- parents = [Parent], type = Type, +- owners = Owners, options = Options} +- end, +- mnesia:transform_table(pubsub_node, F, +- [nodeid, id, parents, type, owners, options]), +- rename_default_nodeplugin(); +- _ -> ok - end, -- mnesia:transaction(fun() -> -- case catch mnesia:first(pubsub_node) of -- {_, L} when is_list(L) -> -- lists:foreach( -- fun({H, N}) when is_list(N) -> -- [Node] = mnesia:read({pubsub_node, {H, N}}), -- Type = Node#pubsub_node.type, -- BN = element(2, node_call(Type, path_to_node, [N])), -- BP = case [element(2, node_call(Type, path_to_node, [P])) || P <- Node#pubsub_node.parents] of -- [<<>>] -> []; -- Parents -> Parents -- end, -- mnesia:write(Node#pubsub_node{nodeid={H, BN}, parents=BP}), -- mnesia:delete({pubsub_node, {H, N}}); -- (_) -> -- ok -- end, mnesia:all_keys(pubsub_node)); -- _ -> -- ok -- end -- end). +- mnesia:transaction(fun () -> +- case catch mnesia:first(pubsub_node) of +- {_, L} when is_binary(L) -> +- lists:foreach(fun ({H, N}) +- when is_binary(N) -> +- [Node] = +- mnesia:read({pubsub_node, +- {H, +- N}}), +- Type = +- Node#pubsub_node.type, +- BN = element(2, +- node_call(Type, +- path_to_node, +- [N])), +- BP = case [element(2, +- node_call(Type, +- path_to_node, +- [P])) +- || P +- <- Node#pubsub_node.parents] +- of +- [<<>>] -> []; +- Parents -> +- Parents +- end, +- mnesia:write(Node#pubsub_node{nodeid +- = +- {H, +- BN}, +- parents +- = +- BP}), +- mnesia:delete({pubsub_node, +- {H, +- N}}); +- (_) -> ok +- end, +- mnesia:all_keys(pubsub_node)); +- _ -> ok +- end +- end). - -rename_default_nodeplugin() -> -- lists:foreach(fun(Node) -> -- mnesia:dirty_write(Node#pubsub_node{type = "hometree"}) -- end, mnesia:dirty_match_object(#pubsub_node{type = "default", _ = '_'})). +- lists:foreach(fun (Node) -> +- mnesia:dirty_write(Node#pubsub_node{type = +- <<"hometree">>}) +- end, +- mnesia:dirty_match_object(#pubsub_node{type = +- <<"default">>, +- _ = '_'})). - -update_state_database(_Host, _ServerHost) -> - case catch mnesia:table_info(pubsub_state, attributes) of @@ -259,293 +413,367 @@ - send_loop(State) -> receive - {presence, JID, Pid} -> -@@ -494,17 +299,15 @@ - %% for each node From is subscribed to - %% and if the node is so configured, send the last published item to From - lists:foreach(fun(PType) -> -- {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]), -+ Subscriptions = case catch node_action(Host, PType, get_entity_subscriptions_for_send_last, [Host, JID]) of -+ {result, S} -> S; -+ _ -> [] -+ end, - lists:foreach( - fun({Node, subscribed, _, SubJID}) -> - if (SubJID == LJID) or (SubJID == BJID) -> -- #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId, options = Options} = Node, -- case get_option(Options, send_last_published_item) of -- on_sub_and_presence -> -- send_items(H, N, NodeId, Type, LJID, last); -- _ -> -- ok -- end; -+ #pubsub_node{nodeid = {H, N}, type = Type, id = NodeId} = Node, -+ send_items(H, N, NodeId, Type, LJID, last); - true -> - % resource not concerned about that subscription - ok -@@ -623,7 +426,8 @@ - disco_identity(_Host, <<>>, _From) -> - [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []}]; + {presence, JID, Pid} -> +@@ -755,11 +408,13 @@ + LJID = jlib:jid_tolower(JID), + BJID = jlib:jid_remove_resource(LJID), + lists:foreach(fun (PType) -> +- {result, Subscriptions} = node_action(Host, ++ {result, Subscriptions} = case catch node_action(Host, + PType, +- get_entity_subscriptions, +- [Host, +- JID]), ++ get_entity_subscriptions_for_send_last, ++ [Host, JID]) of ++ {result, S} -> S; ++ _ -> [] ++ end, + lists:foreach(fun ({Node, subscribed, _, + SubJID}) -> + if (SubJID == LJID) or +@@ -771,24 +426,14 @@ + type = + Type, + id = +- NodeId, +- options +- = +- Options} = ++ NodeId} = + Node, +- case +- get_option(Options, +- send_last_published_item) +- of +- on_sub_and_presence -> +- send_items(H, ++ send_items(H, + N, + NodeId, + Type, + LJID, + last); +- _ -> ok +- end; + true -> + % resource not concerned about that subscription + ok +@@ -979,7 +624,8 @@ + children = []}]; disco_identity(Host, Node, From) -> -- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) -> -+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) -> -+ Owners = node_owners_call(Type, Idx), - case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of - {result, _} -> - {result, [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []}, -@@ -658,7 +462,8 @@ - [?NS_PUBSUB - | [?NS_PUBSUB++"#"++Feature || Feature <- features("pep")]]; + Action = fun (#pubsub_node{id = Idx, type = Type, +- options = Options, owners = Owners}) -> ++ options = Options}) -> ++ Owners = node_owners_call(Type, Idx), + case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of + {result, _} -> + {result, +@@ -1031,7 +677,8 @@ + || Feature <- features(<<"pep">>)]]; disco_features(Host, Node, From) -> -- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) -> -+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) -> -+ Owners = node_owners_call(Type, Idx), - case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of - {result, _} -> - {result, [?NS_PUBSUB -@@ -683,7 +488,8 @@ - Acc. - + Action = fun (#pubsub_node{id = Idx, type = Type, +- options = Options, owners = Owners}) -> ++ options = Options}) -> ++ Owners = node_owners_call(Type, Idx), + case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of + {result, _} -> + {result, +@@ -1076,9 +723,9 @@ + ). disco_items(Host, <<>>, From) -> -- Action = fun(#pubsub_node{nodeid ={_, NodeID}, options = Options, type = Type, id = Idx, owners = Owners}, Acc) -> -+ Action = fun(#pubsub_node{nodeid ={_, NodeID}, options = Options, type = Type, id = Idx}, Acc) -> -+ Owners = node_owners_call(Type, Idx), - case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of - {result, _} -> - [{xmlelement, "item", -@@ -701,13 +507,14 @@ - _ -> Acc - end - end, + Action = fun (#pubsub_node{nodeid = {_, NodeID}, +- options = Options, type = Type, id = Idx, +- owners = Owners}, ++ options = Options, type = Type, id = Idx}, + Acc) -> ++ Owners = node_owners_call(Type, Idx), + case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of + {result, _} -> + [#xmlel{name = <<"item">>, +@@ -1099,13 +746,14 @@ + _ -> Acc + end + end, - case transaction(Host, Action, sync_dirty) of + case transaction_on_nodes(Host, Action, sync_dirty) of - {result, Items} -> Items; - _ -> [] + {result, Items} -> Items; + _ -> [] end; - disco_items(Host, Node, From) -> -- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) -> -+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) -> -+ Owners = node_owners_call(Type, Idx), - case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of - {result, Items} -> - {result, [{xmlelement, "item", -@@ -793,10 +600,10 @@ - lists:foreach(fun(PType) -> - {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Entity]), - lists:foreach(fun -- ({#pubsub_node{options = Options, owners = Owners, id = NodeId}, subscribed, _, JID}) -> -+ ({#pubsub_node{options = Options, id = NodeId}, subscribed, _, JID}) -> - case get_option(Options, access_model) of - presence -> -- case lists:member(BJID, Owners) of -+ case lists:member(BJID, node_owners(Host, PType, NodeId)) of - true -> - node_action(Host, PType, unsubscribe_node, [NodeId, Entity, JID, all]); - false -> -@@ -964,7 +771,8 @@ - sub_el = SubEl} = IQ -> - {xmlelement, _, QAttrs, _} = SubEl, - Node = xml:get_attr_s("node", QAttrs), -- Res = case iq_disco_items(Host, Node, From) of -+ Rsm = jlib:rsm_decode(IQ), -+ Res = case iq_disco_items(Host, Node, From, Rsm) of - {result, IQRes} -> - jlib:iq_to_xml( - IQ#iq{type = result, -@@ -1077,7 +885,7 @@ - [] -> - ["leaf"]; %% No sub-nodes: it's a leaf node - _ -> -- case node_call(Type, get_items, [NodeId, From]) of -+ case node_call(Type, get_items, [NodeId, From, none]) of - {result, []} -> ["collection"]; - {result, _} -> ["leaf", "collection"]; - _ -> [] -@@ -1093,8 +901,9 @@ - []; - true -> - [{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} | -- lists:map(fun(T) -> -- {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++T}], []} -+ lists:map(fun -+ ("rsm")-> {xmlelement, "feature", [{"var", ?NS_RSM}], []}; -+ (T) -> {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++T}], []} - end, features(Type))] - end, - %% TODO: add meta-data info (spec section 5.4) -@@ -1123,8 +932,9 @@ - {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []}, - {xmlelement, "feature", [{"var", ?NS_COMMANDS}], []}, - {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++ -- lists:map(fun(Feature) -> -- {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []} + Action = fun (#pubsub_node{id = Idx, type = Type, +- options = Options, owners = Owners}) -> ++ options = Options}) -> ++ Owners = node_owners_call(Type, Idx), + case get_allowed_items_call(Host, Idx, From, Type, + Options, Owners) + of +@@ -1209,9 +857,6 @@ + lists:foreach(fun ({#pubsub_node{options + = + Options, +- owners +- = +- Owners, + id = + NodeId}, + subscribed, _, +@@ -1223,7 +868,7 @@ + presence -> + case + lists:member(BJID, +- Owners) ++ node_owners(Host, PType, NodeId)) + of + true -> + node_action(Host, +@@ -1442,7 +1087,8 @@ + IQ -> + #xmlel{attrs = QAttrs} = SubEl, + Node = xml:get_attr_s(<<"node">>, QAttrs), +- Res = case iq_disco_items(Host, Node, From) of ++ Rsm = jlib:rsm_decode(IQ), ++ Res = case iq_disco_items(Host, Node, From, Rsm) of + {result, IQRes} -> + jlib:iq_to_xml(IQ#iq{type = result, + sub_el = +@@ -1569,7 +1215,7 @@ + % [] -> + % [<<"leaf">>]; %% No sub-nodes: it's a leaf node + % _ -> +-% case node_call(Type, get_items, [NodeId, From]) of ++% case node_call(Type, get_items, [NodeId, From, none]) of + % {result, []} -> [<<"collection">>]; + % {result, _} -> [<<"leaf">>, <<"collection">>]; + % _ -> [] +@@ -1591,7 +1237,11 @@ + % [#xmlel{name = <<"feature">>, + % attrs = [{<<"var">>, ?NS_PUBSUB}], + % children = []} +-% | lists:map(fun (T) -> ++% | lists:map(fun ++% (<<"rsm">>)-> ++% #xmlel{name = <<"feature">>, ++% attrs = [{<<"var">>, ?NS_RSM}]}; ++% (T) -> + % #xmlel{name = <<"feature">>, + % attrs = + % [{<<"var">>, +@@ -1616,7 +1266,7 @@ + [] -> [<<"leaf">>]; + _ -> + case node_call(Type, get_items, +- [NodeId, From]) ++ [NodeId, From, none]) + of + {result, []} -> + [<<"collection">>]; +@@ -1638,7 +1288,11 @@ + F = [#xmlel{name = <<"feature">>, + attrs = [{<<"var">>, ?NS_PUBSUB}], + children = []} +- | lists:map(fun (T) -> ++ | lists:map(fun ++ (<<"rsm">>)-> ++ #xmlel{name = <<"feature">>, ++ attrs = [{<<"var">>, ?NS_RSM}]}; ++ (T) -> + #xmlel{name = <<"feature">>, + attrs = + [{<<"var">>, +@@ -1682,7 +1336,11 @@ + #xmlel{name = <<"feature">>, + attrs = [{<<"var">>, ?NS_VCARD}], children = []}] + ++ +- lists:map(fun (Feature) -> + lists:map(fun -+ ("rsm")-> {xmlelement, "feature", [{"var", ?NS_RSM}], []}; -+ (T) -> {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++T}], []} - end, features(Host, Node))}; - <<?NS_COMMANDS>> -> - command_disco_info(Host, Node, From); -@@ -1134,7 +944,7 @@ - node_disco_info(Host, Node, From) ++ (<<"rsm">>)-> ++ #xmlel{name = <<"feature">>, ++ attrs = [{<<"var">>, ?NS_RSM}]}; ++ (Feature) -> + #xmlel{name = <<"feature">>, + attrs = + [{<<"var">>, <<(?NS_PUBSUB)/binary, "#", Feature/binary>>}], +@@ -1695,14 +1353,15 @@ + _ -> node_disco_info(Host, Node, From) end. --iq_disco_items(Host, [], From) -> -+iq_disco_items(Host, [], From, _RSM) -> - case tree_action(Host, get_subnodes, [Host, <<>>, From]) of - Nodes when is_list(Nodes) -> - {result, lists:map( -@@ -1151,23 +961,24 @@ - Other -> - Other - end; +--spec(iq_disco_items/3 :: ++-spec(iq_disco_items/4 :: + ( + Host :: mod_pubsub:host(), + NodeId :: <<>> | mod_pubsub:nodeId(), +- From :: jid()) ++ From :: jid(), ++ Rsm :: any()) + -> {result, [xmlel()]} + ). +-iq_disco_items(Host, <<>>, From) -> ++iq_disco_items(Host, <<>>, From, _RSM) -> + {result, + lists:map(fun (#pubsub_node{nodeid = {_, SubNode}, + options = Options}) -> +@@ -1739,7 +1398,7 @@ + % Nodes)}; + % Other -> Other + % end; -iq_disco_items(Host, ?NS_COMMANDS, _From) -> +iq_disco_items(Host, ?NS_COMMANDS, _From, _RSM) -> - %% TODO: support localization of this string - CommandItems = [{xmlelement, "item", [{"jid", Host}, {"node", ?NS_PUBSUB_GET_PENDING}, {"name", "Get Pending"}], []}], + CommandItems = [#xmlel{name = <<"item">>, + attrs = + [{<<"jid">>, Host}, +@@ -1747,22 +1406,19 @@ + {<<"name">>, <<"Get Pending">>}], + children = []}], {result, CommandItems}; -iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From) -> +iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From, _RSM) -> - CommandItems = [], - {result, CommandItems}; + CommandItems = [], {result, CommandItems}; -iq_disco_items(Host, Item, From) -> +iq_disco_items(Host, Item, From, RSM) -> - case string:tokens(Item, "!") of - [_SNode, _ItemID] -> - {result, []}; - [SNode] -> - Node = string_to_node(SNode), -- Action = fun(#pubsub_node{id = Idx, type = Type, options = Options, owners = Owners}) -> -- NodeItems = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners) of -+ Action = fun(#pubsub_node{id = Idx, type = Type, options = Options}) -> -+ Owners = node_owners_call(Type, Idx), -+ {NodeItems, RsmOut} = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners, RSM) of - {result, R} -> R; -- _ -> [] -+ _ -> {[], none} - end, - Nodes = lists:map( - fun(#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) -> -@@ -1185,7 +996,7 @@ - {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), - {xmlelement, "item", [{"jid", Host}, {"name", Name}], []} - end, NodeItems), -- {result, Nodes ++ Items} -+ {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} - end, - case transaction(Host, Node, Action, sync_dirty) of - {result, {_, Result}} -> {result, Result}; -@@ -1296,7 +1107,8 @@ - (_, Acc) -> - Acc - end, [], xml:remove_cdata(Els)), -- get_items(Host, Node, From, SubId, MaxItems, ItemIDs); -+ RSM = jlib:rsm_decode(SubEl), -+ get_items(Host, Node, From, SubId, MaxItems, ItemIDs, RSM); - {get, "subscriptions"} -> - get_subscriptions(Host, Node, From, Plugins); - {get, "affiliations"} -> -@@ -1319,7 +1131,9 @@ - + case str:tokens(Item, <<"!">>) of + [_Node, _ItemID] -> {result, []}; + [Node] -> + % Node = string_to_node(SNode), + Action = fun (#pubsub_node{id = Idx, type = Type, +- options = Options, owners = Owners}) -> +- NodeItems = case get_allowed_items_call(Host, Idx, +- From, Type, +- Options, +- Owners) +- of ++ options = Options}) -> ++ Owners = node_owners_call(Type, Idx), ++ {NodeItems, RsmOut} = case get_allowed_items_call(Host, Idx, From, Type, Options, Owners, RSM) of + {result, R} -> R; +- _ -> [] ++ _ -> {[], none} + end, + Nodes = lists:map(fun (#pubsub_node{nodeid = + {_, SubNode}, +@@ -1805,7 +1461,7 @@ + children = []} + end, + NodeItems), +- {result, Nodes ++ Items} ++ {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)} + end, + case transaction(Host, Node, Action, sync_dirty) of + {result, {_, Result}} -> {result, Result}; +@@ -1956,7 +1612,8 @@ + (_, Acc) -> Acc + end, + [], xml:remove_cdata(Els)), +- get_items(Host, Node, From, SubId, MaxItems, ItemIDs); ++ RSM = jlib:rsm_decode(SubEl), ++ get_items(Host, Node, From, SubId, MaxItems, ItemIDs, RSM); + {get, <<"subscriptions">>} -> + get_subscriptions(Host, Node, From, Plugins); + {get, <<"affiliations">>} -> +@@ -1991,7 +1648,9 @@ + ). iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> - {xmlelement, _, _, SubEls} = SubEl, + #xmlel{children = SubEls} = SubEl, - Action = xml:remove_cdata(SubEls), -+ Action = lists:filter(fun({xmlelement, "set", _, _}) -> false; -+ (_) -> true -+ end, xml:remove_cdata(SubEls)), ++ Action = lists:filter(fun(#xmlel{name = <<"set">>, _ = '_'}) -> false; ++ (_) -> true ++ end, xml:remove_cdata(SubEls)), case Action of - [{xmlelement, Name, Attrs, Els}] -> - Node = string_to_node(xml:get_attr_s("node", Attrs)), -@@ -1449,7 +1263,8 @@ - _ -> [] - end - end, -- case transaction(fun () -> {result, lists:flatmap(Tr, Plugins)} end, + [#xmlel{name = Name, attrs = Attrs, children = Els}] -> + Node = xml:get_attr_s(<<"node">>, Attrs), +@@ -2121,7 +1780,8 @@ + _ -> [] + end + end, +- case transaction(fun () -> + case transaction(Host, -+ fun () -> {result, lists:flatmap(Tr, Plugins)} end, - sync_dirty) of - {result, Res} -> Res; - Err -> Err -@@ -1488,7 +1303,7 @@ ++ fun () -> + {result, lists:flatmap(Tr, Plugins)} + end, + sync_dirty) +@@ -2163,7 +1823,8 @@ %%% authorization handling --send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) -> -+send_authorization_request(#pubsub_node{nodeid = {Host, Node}, type = Type, id = NodeId}, Subscriber) -> - Lang = "en", %% TODO fix - Stanza = {xmlelement, "message", - [], -@@ -1517,7 +1332,7 @@ - [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]}, - lists:foreach(fun(Owner) -> - ejabberd_router:route(service_jid(Host), jlib:make_jid(Owner), Stanza) -- end, Owners). -+ end, node_owners(Host, Type, NodeId)). +-send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, ++send_authorization_request(#pubsub_node{nodeid = {Host, Node}, ++ type = Type, id = NodeId}, + Subscriber) -> + Lang = <<"en">>, + Stanza = #xmlel{name = <<"message">>, attrs = [], +@@ -2241,7 +1902,7 @@ + ejabberd_router:route(service_jid(Host), + jlib:make_jid(Owner), Stanza) + end, +- Owners). ++ node_owners(Host, Type, NodeId)). find_authorization_response(Packet) -> - {xmlelement, _Name, _Attrs, Els} = Packet, -@@ -1581,8 +1396,8 @@ - "true" -> true; - _ -> false - end, -- Action = fun(#pubsub_node{type = Type, owners = Owners, id = NodeId}) -> -- IsApprover = lists:member(jlib:jid_tolower(jlib:jid_remove_resource(From)), Owners), -+ Action = fun(#pubsub_node{type = Type, id = NodeId}) -> -+ IsApprover = lists:member(jlib:jid_tolower(jlib:jid_remove_resource(From)), node_owners_call(Type, NodeId)), - {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), - if - not IsApprover -> -@@ -1781,7 +1596,7 @@ - Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "create", nodeAttr(Node), - []}]}], + #xmlel{children = Els} = Packet, +@@ -2300,11 +1961,11 @@ + <<"true">> -> true; + _ -> false + end, +- Action = fun (#pubsub_node{type = Type, owners = Owners, ++ Action = fun (#pubsub_node{type = Type, + id = NodeId}) -> + IsApprover = + lists:member(jlib:jid_tolower(jlib:jid_remove_resource(From)), +- Owners), ++ node_owners_call(Type, NodeId)), + {result, Subscriptions} = node_call(Type, + get_subscriptions, + [NodeId, +@@ -2539,7 +2200,7 @@ + children = [#xmlel{name = <<"create">>, + attrs = nodeAttr(Node), + children = []}]}], - case transaction(CreateNode, transaction) of + case transaction(Host, CreateNode, transaction) of {result, {NodeId, SubsByDepth, {Result, broadcast}}} -> broadcast_created_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth), ejabberd_hooks:run(pubsub_create_node, ServerHost, [ServerHost, Host, Node, NodeId, NodeOptions]), -@@ -1898,7 +1713,7 @@ - %%<li>The node does not exist.</li> +@@ -2663,7 +2324,7 @@ %%</ul> subscribe_node(Host, Node, From, JID, Configuration) -> -- SubOpts = case pubsub_subscription:parse_options_xform(Configuration) of -+ SubOpts = case pubsub_subscription_odbc:parse_options_xform(Configuration) of - {result, GoodSubOpts} -> GoodSubOpts; - _ -> invalid - end, -@@ -1906,7 +1721,7 @@ - error -> {"", "", ""}; - J -> jlib:jid_tolower(J) + SubOpts = case +- pubsub_subscription:parse_options_xform(Configuration) ++ pubsub_subscription_odbc:parse_options_xform(Configuration) + of + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid +@@ -2677,7 +2338,7 @@ + end end, -- Action = fun(#pubsub_node{options = Options, owners = Owners, type = Type, id = NodeId}) -> -+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) -> - Features = features(Type), - SubscribeFeature = lists:member("subscribe", Features), - OptionsFeature = lists:member("subscription-options", Features), -@@ -1915,6 +1730,7 @@ - AccessModel = get_option(Options, access_model), - SendLast = get_option(Options, send_last_published_item), - AllowedGroups = get_option(Options, roster_groups_allowed, []), -+ Owners = node_owners_call(Type, NodeId), - {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups), - if - not SubscribeFeature -> -@@ -2036,12 +1852,9 @@ - Features = features(Type), - PublishFeature = lists:member("publish", Features), - PublishModel = get_option(Options, publish_model), -+ MaxItems = max_items(Host, Options), - DeliverPayloads = get_option(Options, deliver_payloads), - PersistItems = get_option(Options, persist_items), -- MaxItems = case PersistItems of -- false -> 0; -- true -> max_items(Host, Options) -- end, - PayloadCount = payload_xmlelements(Payload), - PayloadSize = size(term_to_binary(Payload))-2, % size(term_to_binary([])) == 2 - PayloadMaxSize = get_option(Options, max_payload_size), -@@ -2092,7 +1905,7 @@ + Action = fun (#pubsub_node{options = Options, +- owners = Owners, type = Type, id = NodeId}) -> ++ type = Type, id = NodeId}) -> + Features = features(Type), + SubscribeFeature = lists:member(<<"subscribe">>, Features), + OptionsFeature = lists:member(<<"subscription-options">>, Features), +@@ -2686,6 +2347,7 @@ + AccessModel = get_option(Options, access_model), + SendLast = get_option(Options, send_last_published_item), + AllowedGroups = get_option(Options, roster_groups_allowed, []), ++ Owners = node_owners_call(Type, NodeId), + {PresenceSubscription, RosterGroup} = + get_presence_and_roster_permissions(Host, Subscriber, + Owners, AccessModel, AllowedGroups), +@@ -2808,12 +2470,9 @@ + Features = features(Type), + PublishFeature = lists:member(<<"publish">>, Features), + PublishModel = get_option(Options, publish_model), ++ MaxItems = max_items(Host, Options), + DeliverPayloads = get_option(Options, deliver_payloads), + PersistItems = get_option(Options, persist_items), +- MaxItems = case PersistItems of +- false -> 0; +- true -> max_items(Host, Options) +- end, + PayloadCount = payload_xmlelements(Payload), + PayloadSize = byte_size(term_to_binary(Payload)) - 2, + PayloadMaxSize = get_option(Options, max_payload_size), +@@ -2869,7 +2528,7 @@ false -> ok end, @@ -554,57 +782,74 @@ case Result of default -> {result, Reply}; _ -> {result, Result} -@@ -2258,7 +2071,7 @@ - %% <p>The permission are not checked in this function.</p> - %% @todo We probably need to check that the user doing the query has the right - %% to read the items. +@@ -3040,19 +2699,20 @@ + Error -> Error + end. + +--spec(get_items/6 :: ++-spec(get_items/7 :: + ( + Host :: mod_pubsub:host(), + Node :: mod_pubsub:nodeId(), + From :: jid(), + SubId :: mod_pubsub:subId(), + SMaxItems :: binary(), +- ItemIDs :: [mod_pubsub:itemId()]) ++ ItemIDs :: [mod_pubsub:itemId()], ++ Rsm :: any()) + -> {result, [xmlel(),...]} + %%% + | {error, xmlel()} + ). -get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) -> +get_items(Host, Node, From, SubId, SMaxItems, ItemIDs, RSM) -> - MaxItems = - if - SMaxItems == "" -> get_max_items_node(Host); -@@ -2272,12 +2085,13 @@ - {error, Error} -> - {error, Error}; - _ -> -- Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId, owners = Owners}) -> -+ 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), - AccessModel = get_option(Options, access_model), - AllowedGroups = get_option(Options, roster_groups_allowed, []), -+ Owners = node_owners_call(Type, NodeId), - {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups), - if - not RetreiveFeature -> -@@ -2290,11 +2104,11 @@ - node_call(Type, get_items, - [NodeId, From, - AccessModel, PresenceSubscription, RosterGroup, -- SubId]) -+ SubId, RSM]) - end - end, - case transaction(Host, Node, Action, sync_dirty) of -- {result, {_, Items}} -> -+ {result, {_, {Items, RSMOut}}} -> - SendItems = case ItemIDs of - [] -> - Items; -@@ -2307,7 +2121,8 @@ - %% number of items sent to MaxItems: - {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], - [{xmlelement, "items", nodeAttr(Node), -- itemsEls(lists:sublist(SendItems, MaxItems))}]}]}; -+ itemsEls(lists:sublist(SendItems, MaxItems))} -+ | jlib:rsm_encode(RSMOut)]}]}; - Error -> - Error - end -@@ -2329,10 +2144,15 @@ - Error -> Error + MaxItems = if SMaxItems == <<"">> -> + get_max_items_node(Host); + true -> +@@ -3064,13 +2724,13 @@ + case MaxItems of + {error, Error} -> {error, Error}; + _ -> +- Action = fun (#pubsub_node{options = Options, type = Type, id = NodeId, +- owners = Owners}) -> ++ 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), + AccessModel = get_option(Options, access_model), + AllowedGroups = get_option(Options, roster_groups_allowed, []), ++ Owners = node_owners_call(Type, NodeId), + {PresenceSubscription, RosterGroup} = + get_presence_and_roster_permissions(Host, From, Owners, + AccessModel, AllowedGroups), +@@ -3088,11 +2748,11 @@ + node_call(Type, get_items, + [NodeId, From, AccessModel, + PresenceSubscription, RosterGroup, +- SubId]) ++ SubId, RSM]) + end + end, + case transaction(Host, Node, Action, sync_dirty) of +- {result, {_, Items}} -> ++ {result, {_, {Items, RSMOut}}} -> + SendItems = case ItemIDs of + [] -> Items; + _ -> +@@ -3110,8 +2770,8 @@ + children = + [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), + children = +- itemsEls(lists:sublist(SendItems, +- MaxItems))}]}]}; ++ itemsEls(lists:sublist(SendItems, MaxItems))} ++ | jlib:rsm_encode(RSMOut)]}]}; + Error -> Error + end end. +@@ -3135,43 +2795,45 @@ + end. + get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) -> + case get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners, none) of + {result, {I, _}} -> {result, I}; @@ -613,165 +858,187 @@ +get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners, RSM) -> AccessModel = get_option(Options, access_model), AllowedGroups = get_option(Options, roster_groups_allowed, []), - {PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups), -- node_call(Type, get_items, [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined]). -+ node_call(Type, get_items, [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined, RSM]). + {PresenceSubscription, RosterGroup} = + get_presence_and_roster_permissions(Host, From, Owners, AccessModel, + AllowedGroups), + node_call(Type, get_items, +- [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined]). ++ [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined, RSM]). - - %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any() -@@ -2344,31 +2164,29 @@ - %% 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, NodeId, Type, {U,S,R} = LJID, last) -> +-send_items(Host, Node, NodeId, Type, {U, S, R} = LJID, last) -> - case get_cached_item(Host, NodeId) of +- undefined -> +- send_items(Host, Node, NodeId, Type, LJID, 1); +send_items(Host, Node, NodeId, Type, LJID, last) -> + Stanza = case get_cached_item(Host, NodeId) of - undefined -> -- send_items(Host, Node, NodeId, Type, LJID, 1); ++ undefined -> + % special ODBC optimization, works only with node_hometree_odbc, node_flat_odbc and node_pep_odbc + case node_action(Host, Type, get_last_items, [NodeId, LJID, 1]) of + {result, [LastItem]} -> + {ModifNow, ModifUSR} = LastItem#pubsub_item.modification, + event_stanza_with_delay( -+ [{xmlelement, "items", nodeAttr(Node), -+ itemsEls([LastItem])}], ModifNow, ModifUSR); ++ [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), ++ children = itemsEls([LastItem])}], ModifNow, ModifUSR); + _ -> + event_stanza( -+ [{xmlelement, "items", nodeAttr(Node), -+ itemsEls([])}]) ++ [#xmlel{name = <<"items">>, attrs = nodeAttr(Node), ++ children = itemsEls([])}]) + end; - LastItem -> - {ModifNow, ModifUSR} = LastItem#pubsub_item.modification, -- Stanza = event_stanza_with_delay( -+ event_stanza_with_delay( - [{xmlelement, "items", nodeAttr(Node), -- itemsEls([LastItem])}], ModifNow, ModifUSR), -- case is_tuple(Host) of -- false -> -- ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza); -- true -> -- case ejabberd_sm:get_session_pid(U,S,R) of -- C2SPid when is_pid(C2SPid) -> -- ejabberd_c2s:broadcast(C2SPid, -- {pep_message, binary_to_list(Node)++"+notify"}, -- _Sender = service_jid(Host), -- Stanza); -- _ -> -- ok -- end -- end + LastItem -> + {ModifNow, ModifUSR} = + LastItem#pubsub_item.modification, +- Stanza = event_stanza_with_delay([#xmlel{name = ++ event_stanza_with_delay([#xmlel{name = + <<"items">>, + attrs = nodeAttr(Node), + children = + itemsEls([LastItem])}], +- ModifNow, ModifUSR), +- case is_tuple(Host) of +- false -> +- ejabberd_router:route(service_jid(Host), +- jlib:make_jid(LJID), Stanza); +- true -> +- case ejabberd_sm:get_session_pid(U, S, R) of +- C2SPid when is_pid(C2SPid) -> +- ejabberd_c2s:broadcast(C2SPid, +- {pep_message, +- <<((Node))/binary, "+notify">>}, +- _Sender = service_jid(Host), +- Stanza); +- _ -> ok +- end +- end - end; --send_items(Host, Node, NodeId, Type, {U,S,R} = LJID, Number) -> -+ itemsEls([LastItem])}], ModifNow, ModifUSR) ++ ModifNow, ModifUSR) + end, + ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza); -+send_items(Host, Node, NodeId, Type, LJID, Number) -> - ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of - {result, []} -> - []; -@@ -2391,20 +2209,7 @@ - [{xmlelement, "items", nodeAttr(Node), - itemsEls(ToSend)}]) - end, + send_items(Host, Node, NodeId, Type, {U, S, R} = LJID, + Number) -> + ToSend = case node_action(Host, Type, get_items, +@@ -3199,20 +2861,7 @@ + attrs = nodeAttr(Node), + children = itemsEls(ToSend)}]) + end, - case is_tuple(Host) of -- false -> -- ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza); -- true -> -- case ejabberd_sm:get_session_pid(U,S,R) of -- C2SPid when is_pid(C2SPid) -> -- ejabberd_c2s:broadcast(C2SPid, -- {pep_message, binary_to_list(Node)++"+notify"}, -- _Sender = service_jid(Host), -- Stanza); -- _ -> -- ok -- end +- false -> +- ejabberd_router:route(service_jid(Host), +- jlib:make_jid(LJID), Stanza); +- true -> +- case ejabberd_sm:get_session_pid(U, S, R) of +- C2SPid when is_pid(C2SPid) -> +- ejabberd_c2s:broadcast(C2SPid, +- {pep_message, +- <<((Node))/binary, "+notify">>}, +- _Sender = service_jid(Host), Stanza); +- _ -> ok +- end - end. + ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza). - %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} - %% Host = host() -@@ -2540,7 +2345,8 @@ - error -> - {error, ?ERR_BAD_REQUEST}; - _ -> -- Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}=N) -> -+ Action = fun(#pubsub_node{type = Type, id = NodeId}) -> -+ Owners = node_owners_call(Type, NodeId), - case lists:member(Owner, Owners) of - true -> - OwnerJID = jlib:make_jid(Owner), -@@ -2550,24 +2356,7 @@ - end, - lists:foreach( - fun({JID, Affiliation}) -> -- node_call(Type, set_affiliation, [NodeId, JID, Affiliation]), -- case Affiliation of -- owner -> -- NewOwner = jlib:jid_tolower(jlib:jid_remove_resource(JID)), -- NewOwners = [NewOwner|Owners], -- tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); -- none -> -- OldOwner = jlib:jid_tolower(jlib:jid_remove_resource(JID)), -- case lists:member(OldOwner, Owners) of -- true -> -- NewOwners = Owners--[OldOwner], -- tree_call(Host, set_node, [N#pubsub_node{owners = NewOwners}]); -- _ -> -- ok -- end; -- _ -> -- ok -- end -+ node_call(Type, set_affiliation, [NodeId, JID, Affiliation]) - end, FilteredEntities), - {result, []}; - _ -> -@@ -2620,11 +2409,11 @@ + -spec(get_affiliations/4 :: + ( +@@ -3400,9 +3049,10 @@ + case Entities of + error -> {error, ?ERR_BAD_REQUEST}; + _ -> +- Action = fun (#pubsub_node{owners = Owners, type = Type, ++ Action = fun (#pubsub_node{type = Type, + id = NodeId} = + N) -> ++ Owners = node_owners_call(Type, NodeId), + case lists:member(Owner, Owners) of + true -> + OwnerJID = jlib:make_jid(Owner), +@@ -3415,42 +3065,7 @@ + _ -> Entities + end, + lists:foreach(fun ({JID, Affiliation}) -> +- node_call(Type, +- set_affiliation, +- [NodeId, JID, +- Affiliation]), +- case Affiliation of +- owner -> +- NewOwner = +- jlib:jid_tolower(jlib:jid_remove_resource(JID)), +- NewOwners = +- [NewOwner +- | Owners], +- tree_call(Host, +- set_node, +- [N#pubsub_node{owners +- = +- NewOwners}]); +- none -> +- OldOwner = +- jlib:jid_tolower(jlib:jid_remove_resource(JID)), +- case +- lists:member(OldOwner, +- Owners) +- of +- true -> +- NewOwners = +- Owners -- +- [OldOwner], +- tree_call(Host, +- set_node, +- [N#pubsub_node{owners +- = +- NewOwners}]); +- _ -> ok +- end; +- _ -> ok +- end ++ node_call(Type, set_affiliation, [NodeId, JID, Affiliation]) + end, + FilteredEntities), + {result, []}; +@@ -3509,11 +3124,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> - case pubsub_subscription:get_subscription(Subscriber, NodeID, SubID) of + case pubsub_subscription_odbc:get_subscription(Subscriber, NodeID, SubID) of {error, notfound} -> - {error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + {error, extended_error(?ERR_NOT_ACCEPTABLE, <<"invalid-subid">>)}; {result, #pubsub_subscription{options = Options}} -> - {result, XdataEl} = pubsub_subscription:get_options_xform(Lang, Options), + {result, XdataEl} = pubsub_subscription_odbc:get_options_xform(Lang, Options), - OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)}, - {"subid", SubID}|nodeAttr(Node)], - [XdataEl]}, -@@ -2650,7 +2439,7 @@ + OptionsEl = #xmlel{name = <<"options">>, + attrs = + [{<<"jid">>, jlib:jid_to_string(Subscriber)}, +@@ -3547,7 +3162,7 @@ end. set_options_helper(Configuration, JID, NodeID, SubID, Type) -> - SubOpts = case pubsub_subscription:parse_options_xform(Configuration) of + SubOpts = case pubsub_subscription_odbc:parse_options_xform(Configuration) of - {result, GoodSubOpts} -> GoodSubOpts; - _ -> invalid - end, -@@ -2679,7 +2468,7 @@ + {result, GoodSubOpts} -> GoodSubOpts; + _ -> invalid + end, +@@ -3579,7 +3194,7 @@ write_sub(_Subscriber, _NodeID, _SubID, invalid) -> - {error, extended_error(?ERR_BAD_REQUEST, "invalid-options")}; + {error, extended_error(?ERR_BAD_REQUEST, <<"invalid-options">>)}; write_sub(Subscriber, NodeID, SubID, Options) -> - case pubsub_subscription:set_subscription(Subscriber, NodeID, SubID, Options) of + case pubsub_subscription_odbc:set_subscription(Subscriber, NodeID, SubID, Options) of {error, notfound} -> - {error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; + {error, extended_error(?ERR_NOT_ACCEPTABLE, <<"invalid-subid">>)}; {result, _} -> -@@ -2847,8 +2636,8 @@ - {"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]}, - ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza) - end, -- Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) -> -- case lists:member(Owner, Owners) of -+ Action = fun(#pubsub_node{type = Type, id = NodeId}) -> -+ case lists:member(Owner, node_owners_call(Type, NodeId)) of - true -> - Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> - -@@ -3203,7 +2992,7 @@ +@@ -3800,9 +3415,9 @@ + ejabberd_router:route(service_jid(Host), + jlib:make_jid(JID), Stanza) + end, +- Action = fun (#pubsub_node{owners = Owners, type = Type, ++ Action = fun (#pubsub_node{type = Type, + id = NodeId}) -> +- case lists:member(Owner, Owners) of ++ case lists:member(Owner, node_owners_call(Type, NodeId)) of + true -> + Result = lists:foldl(fun ({JID, Subscription, + SubId}, +@@ -4181,7 +3796,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -780,7 +1047,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -3217,9 +3006,9 @@ +@@ -4195,9 +3810,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -792,8 +1059,8 @@ _ -> Acc end; (_, Acc) -> -@@ -3408,6 +3197,30 @@ - Result +@@ -4870,6 +4485,30 @@ + _ -> features() end. +%% @spec (Host, Type, NodeId) -> [ljid()] @@ -820,13 +1087,13 @@ + [] + end. + - %% @spec (Host, Options) -> MaxItems - %% Host = host() - %% Options = [Option] -@@ -3804,7 +3617,13 @@ + tree_call({_User, Server, _Resource}, Function, Args) -> + tree_call(Server, Function, Args); + tree_call(Host, Function, Args) -> +@@ -4888,7 +4527,13 @@ tree_action(Host, Function, Args) -> - ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), - Fun = fun() -> tree_call(Host, Function, Args) end, + ?DEBUG("tree_action ~p ~p ~p", [Host, Function, Args]), + Fun = fun () -> tree_call(Host, Function, Args) end, - catch mnesia:sync_dirty(Fun). + case catch ejabberd_odbc:sql_bloc(odbc_conn(Host), Fun) of + {atomic, Result} -> @@ -836,34 +1103,36 @@ + {error, ?ERR_INTERNAL_SERVER_ERROR} + end. - %% @doc <p>node plugin call.</p> node_call(Type, Function, Args) -> -@@ -3824,13 +3643,13 @@ - + ?DEBUG("node_call ~p ~p ~p", [Type, Function, Args]), +@@ -4912,12 +4557,11 @@ node_action(Host, Type, Function, Args) -> - ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), -- transaction(fun() -> -+ transaction(Host, fun() -> - node_call(Type, Function, Args) - end, sync_dirty). + ?DEBUG("node_action ~p ~p ~p ~p", + [Host, Type, Function, Args]), +- transaction(fun () -> node_call(Type, Function, Args) +- end, ++ transaction(Host, fun () -> node_call(Type, Function, Args) end, + sync_dirty). - %% @doc <p>plugin transaction handling.</p> transaction(Host, Node, Action, Trans) -> -- transaction(fun() -> -+ transaction(Host, fun() -> +- transaction(fun () -> ++ transaction(Host, fun () -> case tree_call(Host, get_node, [Host, Node]) of - N when is_record(N, pubsub_node) -> - case Action(N) of -@@ -3842,13 +3661,19 @@ - Error - end - end, Trans). + N when is_record(N, pubsub_node) -> + case Action(N) of +@@ -4931,16 +4575,22 @@ + end, + Trans). + -transaction(Host, Action, Trans) -> -- transaction(fun() -> +- transaction(fun () -> +transaction_on_nodes(Host, Action, Trans) -> -+ transaction(Host, fun() -> - {result, lists:foldl(Action, [], tree_call(Host, get_nodes, [Host]))} - end, Trans). ++ transaction(Host, fun () -> + {result, + lists:foldl(Action, [], + tree_call(Host, get_nodes, [Host]))} + end, + Trans). -transaction(Fun, Trans) -> - case catch mnesia:Trans(Fun) of @@ -875,14 +1144,14 @@ + _ -> sql_bloc + end, + case catch ejabberd_odbc:SqlFun(odbc_conn(Host), Fun) of - {result, Result} -> {result, Result}; - {error, Error} -> {error, Error}; - {atomic, {result, Result}} -> {result, Result}; -@@ -3856,6 +3681,15 @@ - {aborted, Reason} -> - ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR}; -+ {'EXIT', {timeout, _} = Reason} -> + {result, Result} -> {result, Result}; + {error, Error} -> {error, Error}; + {atomic, {result, Result}} -> {result, Result}; +@@ -4949,6 +4599,15 @@ + ?ERROR_MSG("transaction return internal error: ~p~n", + [{aborted, Reason}]), + {error, ?ERR_INTERNAL_SERVER_ERROR}; ++ {'EXIT', {timeout, _} = Reason} -> + case Count of + 0 -> + ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), @@ -891,11 +1160,11 @@ + erlang:yield(), + transaction_retry(Host, Fun, Trans, N-1) + end; - {'EXIT', Reason} -> - ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), - {error, ?ERR_INTERNAL_SERVER_ERROR}; -@@ -3864,6 +3698,17 @@ - {error, ?ERR_INTERNAL_SERVER_ERROR} + {'EXIT', Reason} -> + ?ERROR_MSG("transaction return internal error: ~p~n", + [{'EXIT', Reason}]), +@@ -4959,6 +4618,17 @@ + {error, ?ERR_INTERNAL_SERVER_ERROR} end. +odbc_conn({_U, Host, _R})-> @@ -911,4 +1180,4 @@ + %%%% helpers - %% Add pubsub-specific error element + extended_error(Error, Ext) -> |