aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Romain <christophe.romain@process-one.net>2013-06-17 16:34:21 +0200
committerChristophe Romain <christophe.romain@process-one.net>2013-06-17 16:34:21 +0200
commit20598c7be41621b9cc9c23ca4b2db1f64b1291b6 (patch)
tree99b2ca66dfffda081964f6f5dbb8ecb29a062e80
parentfix auto-create issue due to bad binary matching (diff)
sync and cleanup pubsub_odbc
-rw-r--r--src/mod_pubsub_odbc.erl2
-rw-r--r--src/pubsub_odbc.patch1189
2 files changed, 1 insertions, 1190 deletions
diff --git a/src/mod_pubsub_odbc.erl b/src/mod_pubsub_odbc.erl
index 153287b74..3a0d13a60 100644
--- a/src/mod_pubsub_odbc.erl
+++ b/src/mod_pubsub_odbc.erl
@@ -2695,7 +2695,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, Access) ->
%% for automatic node creation. we'll take the default node type:
%% first listed into the plugins configuration option, or pep
Type = select_type(ServerHost, Host, Node),
- case lists:member("auto-create", features(Type)) of
+ case lists:member(<<"auto-create">>, features(Type)) of
true ->
case create_node(Host, ServerHost, Node, Publisher, Type, Access, []) of
{result, [#xmlel{name = <<"pubsub">>,
diff --git a/src/pubsub_odbc.patch b/src/pubsub_odbc.patch
deleted file mode 100644
index b29804d09..000000000
--- a/src/pubsub_odbc.patch
+++ /dev/null
@@ -1,1189 +0,0 @@
---- mod_pubsub.erl 2013-06-13 23:58:13.380824021 +0200
-+++ mod_pubsub_odbc.erl 2013-06-14 00:01:11.907478941 +0200
-@@ -43,7 +43,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').
-
-@@ -62,11 +62,11 @@
-
- -include("pubsub.hrl").
-
---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, caps_update/3,
-@@ -101,7 +101,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
- -export([start_link/2, start/2, stop/1, init/1,
-@@ -111,7 +111,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).
-
-@@ -350,8 +350,6 @@
- false -> ok
- end,
- ejabberd_router:register_route(Host),
-- update_node_database(Host, ServerHost),
-- update_state_database(Host, ServerHost),
- put(server_host, ServerHost),
- init_nodes(Host, ServerHost, NodeTree, Plugins),
- State = #state{host = Host, server_host = ServerHost,
-@@ -424,359 +422,14 @@
- ok.
-
- init_nodes(Host, ServerHost, _NodeTree, Plugins) ->
-- 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
-- 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">>,
-- _ = '_'})).
--
--update_state_database(_Host, _ServerHost) ->
-- case catch mnesia:table_info(pubsub_state, attributes) of
-- [stateid, items, affiliation, subscription] ->
-- ?INFO_MSG("upgrade state pubsub tables", []),
-- F = fun ({pubsub_state, {JID, NodeID}, Items, Aff, Sub}, Acc) ->
-- Subs = case Sub of
-- none ->
-- [];
-- _ ->
-- {result, SubID} = pubsub_subscription:subscribe_node(JID, NodeID, []),
-- [{Sub, SubID}]
-- end,
-- NewState = #pubsub_state{stateid = {JID, NodeID},
-- items = Items,
-- affiliation = Aff,
-- subscriptions = Subs},
-- [NewState | Acc]
-- end,
-- {atomic, NewRecs} = mnesia:transaction(fun mnesia:foldl/3,
-- [F, [], pubsub_state]),
-- {atomic, ok} = mnesia:delete_table(pubsub_state),
-- {atomic, ok} = mnesia:create_table(pubsub_state,
-- [{disc_copies, [node()]},
-- {attributes, record_info(fields, pubsub_state)}]),
-- FNew = fun () ->
-- lists:foreach(fun mnesia:write/1, NewRecs)
-- end,
-- case mnesia:transaction(FNew) of
-- {atomic, Result} ->
-- ?INFO_MSG("Pubsub state tables updated correctly: ~p",
-- [Result]);
-- {aborted, Reason} ->
-- ?ERROR_MSG("Problem updating Pubsub state tables:~n~p",
-- [Reason])
-- end;
-- _ ->
-- ok
-- end.
--
- send_loop(State) ->
- receive
- {presence, JID, Pid} ->
-@@ -785,11 +438,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
-@@ -801,24 +456,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
-@@ -1009,7 +654,8 @@
- children = []}];
- disco_identity(Host, Node, From) ->
- 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,
-@@ -1061,7 +707,8 @@
- || Feature <- features(<<"pep">>)]];
- disco_features(Host, Node, From) ->
- 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,
-@@ -1106,9 +753,9 @@
- ).
- disco_items(Host, <<>>, From) ->
- 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">>,
-@@ -1129,13 +776,14 @@
- _ -> Acc
- end
- end,
-- case transaction(Host, Action, sync_dirty) of
-+ case transaction_on_nodes(Host, Action, sync_dirty) of
- {result, Items} -> Items;
- _ -> []
- end;
- disco_items(Host, Node, From) ->
- 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
-@@ -1239,9 +887,6 @@
- lists:foreach(fun ({#pubsub_node{options
- =
- Options,
-- owners
-- =
-- Owners,
- id =
- NodeId},
- subscribed, _,
-@@ -1253,7 +898,7 @@
- presence ->
- case
- lists:member(BJID,
-- Owners)
-+ node_owners(Host, PType, NodeId))
- of
- true ->
- node_action(Host,
-@@ -1503,7 +1148,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 =
-@@ -1630,7 +1276,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">>];
- % _ -> []
-@@ -1652,7 +1298,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">>,
-@@ -1677,7 +1327,7 @@
- [] -> [<<"leaf">>];
- _ ->
- case node_call(Type, get_items,
-- [NodeId, From])
-+ [NodeId, From, none])
- of
- {result, []} ->
- [<<"collection">>];
-@@ -1699,7 +1349,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">>,
-@@ -1743,7 +1397,11 @@
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_VCARD}], children = []}]
- ++
-- lists:map(fun (Feature) ->
-+ lists:map(fun
-+ (<<"rsm">>)->
-+ #xmlel{name = <<"feature">>,
-+ attrs = [{<<"var">>, ?NS_RSM}]};
-+ (Feature) ->
- #xmlel{name = <<"feature">>,
- attrs =
- [{<<"var">>, <<(?NS_PUBSUB)/binary, "#", Feature/binary>>}],
-@@ -1756,14 +1414,15 @@
- _ -> node_disco_info(Host, Node, From)
- 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}) ->
-@@ -1800,7 +1459,7 @@
- % Nodes)};
- % Other -> Other
- % end;
--iq_disco_items(Host, ?NS_COMMANDS, _From) ->
-+iq_disco_items(Host, ?NS_COMMANDS, _From, _RSM) ->
- CommandItems = [#xmlel{name = <<"item">>,
- attrs =
- [{<<"jid">>, Host},
-@@ -1808,22 +1467,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};
--iq_disco_items(Host, Item, From) ->
-+iq_disco_items(Host, Item, From, RSM) ->
- 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},
-@@ -1866,7 +1522,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};
-@@ -2017,7 +1673,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">>} ->
-@@ -2052,7 +1709,9 @@
- ).
- iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
- #xmlel{children = SubEls} = SubEl,
-- Action = xml:remove_cdata(SubEls),
-+ Action = lists:filter(fun(#xmlel{name = <<"set">>, _ = '_'}) -> false;
-+ (_) -> true
-+ end, xml:remove_cdata(SubEls)),
- case Action of
- [#xmlel{name = Name, attrs = Attrs, children = Els}] ->
- Node = xml:get_attr_s(<<"node">>, Attrs),
-@@ -2186,7 +1845,8 @@
- _ -> []
- end
- end,
-- case transaction(fun () ->
-+ case transaction(Host,
-+ fun () ->
- {result, lists:flatmap(Tr, Plugins)}
- end,
- sync_dirty)
-@@ -2231,7 +1891,8 @@
-
- %%% authorization handling
-
--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 = [],
-@@ -2309,7 +1970,7 @@
- ejabberd_router:route(service_jid(Host),
- jlib:make_jid(Owner), Stanza)
- end,
-- Owners).
-+ node_owners(Host, Type, NodeId)).
-
- find_authorization_response(Packet) ->
- #xmlel{children = Els} = Packet,
-@@ -2374,11 +2035,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,
-@@ -2633,7 +2294,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]),
-@@ -2770,7 +2431,7 @@
- %%</ul>
- subscribe_node(Host, Node, From, JID, Configuration) ->
- SubOpts = case
-- pubsub_subscription:parse_options_xform(Configuration)
-+ pubsub_subscription_odbc:parse_options_xform(Configuration)
- of
- {result, GoodSubOpts} -> GoodSubOpts;
- _ -> invalid
-@@ -2784,7 +2445,7 @@
- end
- end,
- 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),
-@@ -2793,6 +2454,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),
-@@ -2947,12 +2609,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),
-@@ -3008,7 +2667,7 @@
- false ->
- ok
- end,
-- set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
-+ set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
- case Result of
- default -> {result, Reply};
- _ -> {result, Result}
-@@ -3201,19 +2860,20 @@
- %% <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.
---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);
- true ->
-@@ -3225,13 +2885,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),
-@@ -3249,11 +2909,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;
- _ ->
-@@ -3271,8 +2931,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.
-@@ -3296,13 +2956,18 @@
- 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};
-+ Error -> Error
-+ end.
-+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]).
-+ [NodeIdx, From, AccessModel, PresenceSubscription, RosterGroup, undefined, RSM]).
-
- %% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
- %% Host = pubsubHost()
-@@ -3313,35 +2978,32 @@
- %% 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) ->
-- 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 ->
-+ % 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(
-+ [#xmlel{name = <<"items">>, attrs = nodeAttr(Node),
-+ children = itemsEls([LastItem])}], ModifNow, ModifUSR);
-+ _ ->
-+ event_stanza(
-+ [#xmlel{name = <<"items">>, attrs = nodeAttr(Node),
-+ children = itemsEls([])}])
-+ 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;
-+ ModifNow, ModifUSR)
-+ end,
-+ ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza);
- send_items(Host, Node, NodeId, Type, {U, S, R} = LJID,
- Number) ->
- ToSend = case node_action(Host, Type, get_items,
-@@ -3369,20 +3031,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,
-- <<((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()
-@@ -3577,9 +3226,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),
-@@ -3592,42 +3242,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, []};
-@@ -3686,11 +3301,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">>)};
- {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 = #xmlel{name = <<"options">>,
- attrs =
- [{<<"jid">>, jlib:jid_to_string(Subscriber)},
-@@ -3724,7 +3339,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,
-@@ -3756,7 +3371,7 @@
- write_sub(_Subscriber, _NodeID, _SubID, invalid) ->
- {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">>)};
- {result, _} ->
-@@ -3977,9 +3592,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},
-@@ -4373,7 +3988,7 @@
- {Depth, [{N, get_node_subs(N)} || N <- Nodes]}
- end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))}
- end,
-- case transaction(Action, sync_dirty) of
-+ case transaction(Host, Action, sync_dirty) of
- {result, CollSubs} -> CollSubs;
- _ -> []
- end.
-@@ -4387,9 +4002,9 @@
-
- get_options_for_subs(NodeID, Subs) ->
- lists:foldl(fun({JID, subscribed, SubID}, Acc) ->
-- case pubsub_subscription:read_subscription(JID, NodeID, SubID) of
-+ case pubsub_subscription_odbc:get_subscription(JID, NodeID, SubID) of
- {error, notfound} -> [{JID, SubID, []} | Acc];
-- #pubsub_subscription{options = Options} -> [{JID, SubID, Options} | Acc];
-+ {result, #pubsub_subscription{options = Options}} -> [{JID, SubID, Options} | Acc];
- _ -> Acc
- end;
- (_, Acc) ->
-@@ -5089,6 +4704,30 @@
- _ -> features()
- end.
-
-+%% @spec (Host, Type, NodeId) -> [ljid()]
-+%% NodeId = pubsubNodeId()
-+%% @doc <p>Return list of node owners.</p>
-+node_owners(Host, Type, NodeId) ->
-+ case node_action(Host, Type, get_node_affiliations, [NodeId]) of
-+ {result, Affiliations} ->
-+ lists:foldl(
-+ fun({LJID, owner}, Acc) -> [LJID|Acc];
-+ (_, Acc) -> Acc
-+ end, [], Affiliations);
-+ _ ->
-+ []
-+ end.
-+node_owners_call(Type, NodeId) ->
-+ case node_call(Type, get_node_affiliations, [NodeId]) of
-+ {result, Affiliations} ->
-+ lists:foldl(
-+ fun({LJID, owner}, Acc) -> [LJID|Acc];
-+ (_, Acc) -> Acc
-+ end, [], Affiliations);
-+ _ ->
-+ []
-+ end.
-+
- %% @doc <p>node tree plugin call.</p>
- tree_call({_User, Server, _Resource}, Function, Args) ->
- tree_call(Server, Function, Args);
-@@ -5108,7 +4747,13 @@
- tree_action(Host, Function, Args) ->
- ?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} ->
-+ Result;
-+ {aborted, Reason} ->
-+ ?ERROR_MSG("transaction return internal error: ~p~n",[{aborted, Reason}]),
-+ {error, ?ERR_INTERNAL_SERVER_ERROR}
-+ end.
-
- %% @doc <p>node plugin call.</p>
- node_call(Type, Function, Args) ->
-@@ -5133,13 +4778,12 @@
- node_action(Host, Type, Function, Args) ->
- ?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 () ->
- case tree_call(Host, get_node, [Host, Node]) of
- N when is_record(N, pubsub_node) ->
- case Action(N) of
-@@ -5153,16 +4797,22 @@
- end,
- Trans).
-
--transaction(Host, Action, Trans) ->
-- transaction(fun () ->
-+transaction_on_nodes(Host, Action, 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
-+transaction(Host, Fun, Trans) ->
-+ transaction_retry(Host, Fun, Trans, 2).
-+transaction_retry(Host, Fun, Trans, Count) ->
-+ SqlFun = case Trans of
-+ transaction -> sql_transaction;
-+ _ -> 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};
-@@ -5171,6 +4821,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}]),
-+ {error, ?ERR_INTERNAL_SERVER_ERROR};
-+ N ->
-+ erlang:yield(),
-+ transaction_retry(Host, Fun, Trans, N-1)
-+ end;
- {'EXIT', Reason} ->
- ?ERROR_MSG("transaction return internal error: ~p~n",
- [{'EXIT', Reason}]),
-@@ -5181,6 +4840,16 @@
- {error, ?ERR_INTERNAL_SERVER_ERROR}
- end.
-
-+odbc_conn({_U, Host, _R})-> Host;
-+odbc_conn(<<$., Host/binary>>) -> Host;
-+odbc_conn(<<_, Host/binary>>) -> odbc_conn(Host).
-+
-+%% escape value for database storage
-+escape({_U, _H, _R}=JID)->
-+ ejabberd_odbc:escape(jlib:jid_to_string(JID));
-+escape(Value)->
-+ ejabberd_odbc:escape(Value).
-+
- %%%% helpers
-
- %% Add pubsub-specific error element