diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index be7460492..d8475f749 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -657,6 +657,7 @@ disco_sm_items(Acc, From, To, [], _Lang) -> disco_sm_items(Acc, From, To, Node, _Lang) -> Host = To#jid.lserver, Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + % TODO call get_items/6 instead for access control (EJAB-1033) case node_call(Type, get_items, [NodeId, From]) of {result, []} -> none; @@ -1092,6 +1093,7 @@ iq_disco_items(Host, Item, From) -> %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + % TODO call get_items/6 instead for access control (EJAB-1033) NodeItems = case node_call(Type, get_items, [NodeId, From]) of {result, I} -> I; _ -> [] diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 1e6a2f764..b6b254172 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -481,6 +481,7 @@ disco_sm_items(Acc, From, To, [], _Lang) -> disco_sm_items(Acc, From, To, Node, _Lang) -> Host = To#jid.lserver, Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + % TODO call get_items/6 instead for access control (EJAB-1033) case node_call(Type, get_items, [NodeId, From]) of {result, []} -> none; @@ -919,6 +920,7 @@ iq_disco_items(Host, Item, From, RSM) -> %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> + %% TODO call get_items/6 instead for access control (EJAB-1033) {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of {result, I} -> I; _ -> {[], none} diff --git a/src/mod_pubsub/node_hometree.erl b/src/mod_pubsub/node_hometree.erl index c4fcde6da..289c720ed 100644 --- a/src/mod_pubsub/node_hometree.erl +++ b/src/mod_pubsub/node_hometree.erl @@ -557,12 +557,30 @@ delete_item(NodeId, Publisher, PublishModel, ItemId) -> case lists:member(ItemId, Items) of true -> del_item(NodeId, ItemId), - NewItems = lists:delete(ItemId, Items), - set_state(GenState#pubsub_state{items = NewItems}), + set_state(GenState#pubsub_state{items = lists:delete(ItemId, Items)}), {result, {default, broadcast}}; false -> - %% Non-existent node or item - {error, ?ERR_ITEM_NOT_FOUND} + case Affiliation of + owner -> + %% Owner can delete other publishers items as well + {result, States} = get_states(NodeId), + lists:foldl( + fun(#pubsub_state{items = PI, affiliation = publisher} = S, Res) -> + case lists:member(ItemId, PI) of + true -> + del_item(NodeId, ItemId), + set_state(S#pubsub_state{items = lists:delete(ItemId, PI)}), + {result, {default, broadcast}}; + false -> + Res + end; + (_, Res) -> + Res + end, {error, ?ERR_ITEM_NOT_FOUND}, States); + _ -> + %% Non-existent node or item + {error, ?ERR_ITEM_NOT_FOUND} + end end end. @@ -576,9 +594,15 @@ purge_node(NodeId, Owner) -> GenKey = jlib:jid_remove_resource(SubKey), GenState = get_state(NodeId, GenKey), case GenState of - #pubsub_state{items = Items, affiliation = owner} -> - del_items(NodeId, Items), - set_state(GenState#pubsub_state{items = []}), + #pubsub_state{affiliation = owner} -> + {result, States} = get_states(NodeId), + lists:foreach( + fun(#pubsub_state{items = []}) -> + ok; + (#pubsub_state{items = Items} = S) -> + del_items(NodeId, Items), + set_state(S#pubsub_state{items = []}) + end, States), {result, {default, broadcast}}; _ -> %% Entity is not owner diff --git a/src/mod_pubsub/node_hometree_odbc.erl b/src/mod_pubsub/node_hometree_odbc.erl index 738b3191f..e102c291a 100644 --- a/src/mod_pubsub/node_hometree_odbc.erl +++ b/src/mod_pubsub/node_hometree_odbc.erl @@ -558,9 +558,12 @@ purge_node(NodeId, Owner) -> GenKey = jlib:jid_remove_resource(SubKey), GenState = get_state(NodeId, GenKey), case GenState of - #pubsub_state{items = Items, affiliation = owner} -> - del_items(NodeId, Items), - %% set new item list use useless + #pubsub_state{affiliation = owner} -> + {result, States} = get_states(NodeId), + lists:foreach( + fun(#pubsub_state{items = []}) -> ok; + (#pubsub_state{items = Items}) -> del_items(NodeId, Items) + end, States), {result, {default, broadcast}}; _ -> %% Entity is not owner diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 5c8e7a4c6..36adf1b7d 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2009-09-01 15:02:18.000000000 +0200 -+++ mod_pubsub_odbc.erl 2009-09-01 15:14:29.000000000 +0200 +--- mod_pubsub.erl 2009-09-09 21:00:22.000000000 +0200 ++++ mod_pubsub_odbc.erl 2009-09-09 23:14:58.000000000 +0200 @@ -45,7 +45,7 @@ %%% TODO %%% plugin: generate Reply (do not use broadcast atom anymore) @@ -252,7 +252,7 @@ true -> % resource not concerned about that subscription ok -@@ -796,10 +620,10 @@ +@@ -797,10 +621,10 @@ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]), lists:foreach(fun ({Node, subscribed, _, JID}) -> @@ -265,7 +265,7 @@ true -> node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]); false -> -@@ -913,7 +737,8 @@ +@@ -914,7 +738,8 @@ sub_el = SubEl} = IQ -> {xmlelement, _, QAttrs, _} = SubEl, Node = xml:get_attr_s("node", QAttrs), @@ -275,7 +275,7 @@ {result, IQRes} -> jlib:iq_to_xml( IQ#iq{type = result, -@@ -1018,7 +843,7 @@ +@@ -1019,7 +844,7 @@ [] -> ["leaf"]; %% No sub-nodes: it's a leaf node _ -> @@ -284,7 +284,7 @@ {result, []} -> ["collection"]; {result, _} -> ["leaf", "collection"]; _ -> [] -@@ -1034,8 +859,9 @@ +@@ -1035,8 +860,9 @@ []; true -> [{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} | @@ -296,7 +296,7 @@ end, features(Type))] end, %% TODO: add meta-data info (spec section 5.4) -@@ -1063,14 +889,15 @@ +@@ -1064,14 +890,15 @@ {xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []}, {xmlelement, "feature", [{"var", ?NS_PUBSUB}], []}, {xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++ @@ -315,7 +315,7 @@ {result, lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> SN = node_to_string(SubNode), -@@ -1080,7 +907,7 @@ +@@ -1081,7 +908,7 @@ {"node", SN}, {"name", RN}], []} end, tree_action(Host, get_subnodes, [Host, [], From]))}; @@ -324,11 +324,13 @@ case string:tokens(Item, "!") of [_SNode, _ItemID] -> {result, []}; -@@ -1092,9 +919,9 @@ +@@ -1093,10 +920,10 @@ %% TODO That is, remove name attribute (or node?, please check for 2.1) Action = fun(#pubsub_node{type = Type, id = NodeId}) -> +- % TODO call get_items/6 instead for access control (EJAB-1033) - NodeItems = case node_call(Type, get_items, [NodeId, From]) of ++ %% TODO call get_items/6 instead for access control (EJAB-1033) + {NodeItems, RsmOut} = case node_call(Type, get_items, [NodeId, From, RSM]) of {result, I} -> I; - _ -> [] @@ -336,7 +338,7 @@ end, Nodes = lists:map( fun(#pubsub_node{nodeid = {_, SubNode}}) -> -@@ -1110,7 +937,7 @@ +@@ -1112,7 +939,7 @@ {xmlelement, "item", [{"jid", Host}, {"node", SN}, {"name", Name}], []} end, NodeItems), @@ -345,7 +347,7 @@ end, case transaction(Host, Node, Action, sync_dirty) of {result, {_, Result}} -> {result, Result}; -@@ -1242,7 +1069,8 @@ +@@ -1244,7 +1071,8 @@ (_, Acc) -> Acc end, [], xml:remove_cdata(Els)), @@ -355,7 +357,7 @@ {get, "subscriptions"} -> get_subscriptions(Host, Node, From, Plugins); {get, "affiliations"} -> -@@ -1265,7 +1093,9 @@ +@@ -1267,7 +1095,9 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) -> {xmlelement, _, _, SubEls} = SubEl, @@ -366,7 +368,7 @@ case Action of [{xmlelement, Name, Attrs, Els}] -> Node = case Host of -@@ -1391,7 +1221,8 @@ +@@ -1393,7 +1223,8 @@ _ -> [] end end, @@ -376,7 +378,7 @@ sync_dirty) of {result, Res} -> Res; Err -> Err -@@ -1431,7 +1262,7 @@ +@@ -1433,7 +1264,7 @@ %%% authorization handling @@ -385,7 +387,7 @@ Lang = "en", %% TODO fix Stanza = {xmlelement, "message", [], -@@ -1460,7 +1291,7 @@ +@@ -1462,7 +1293,7 @@ [{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]}, lists:foreach(fun(Owner) -> ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza} @@ -394,7 +396,7 @@ find_authorization_response(Packet) -> {xmlelement, _Name, _Attrs, Els} = Packet, -@@ -1527,8 +1358,8 @@ +@@ -1529,8 +1360,8 @@ "true" -> true; _ -> false end, @@ -405,7 +407,7 @@ {result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]), if not IsApprover -> -@@ -1714,7 +1545,7 @@ +@@ -1716,7 +1547,7 @@ Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [{xmlelement, "create", nodeAttr(Node), []}]}], @@ -414,7 +416,7 @@ {result, {Result, broadcast}} -> %%Lang = "en", %% TODO: fix %%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), -@@ -1822,12 +1653,12 @@ +@@ -1824,12 +1655,12 @@ %%
  • The node does not exist.
  • %% subscribe_node(Host, Node, From, JID, Configuration) -> @@ -429,7 +431,7 @@ Features = features(Type), SubscribeFeature = lists:member("subscribe", Features), OptionsFeature = lists:member("subscription-options", Features), -@@ -1846,9 +1677,13 @@ +@@ -1848,9 +1679,13 @@ {"", "", ""} -> {false, false}; _ -> @@ -446,7 +448,7 @@ end end, if -@@ -2171,7 +2006,7 @@ +@@ -2173,7 +2008,7 @@ %%

    The permission are not checked in this function.

    %% @todo We probably need to check that the user doing the query has the right %% to read the items. @@ -455,7 +457,7 @@ MaxItems = if SMaxItems == "" -> ?MAXITEMS; -@@ -2210,11 +2045,11 @@ +@@ -2212,11 +2047,11 @@ node_call(Type, get_items, [NodeId, From, AccessModel, PresenceSubscription, RosterGroup, @@ -469,7 +471,7 @@ SendItems = case ItemIDs of [] -> Items; -@@ -2227,7 +2062,8 @@ +@@ -2229,7 +2064,8 @@ %% number of items sent to MaxItems: {result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}], [{xmlelement, "items", nodeAttr(Node), @@ -479,7 +481,7 @@ Error -> Error end -@@ -2259,15 +2095,22 @@ +@@ -2261,15 +2097,22 @@ %% @doc

    Resend the items of a node to the user.

    %% @todo use cache-last-item feature send_items(Host, Node, NodeId, Type, LJID, last) -> @@ -508,7 +510,7 @@ send_items(Host, Node, NodeId, Type, LJID, Number) -> ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of {result, []} -> -@@ -2385,29 +2228,12 @@ +@@ -2387,29 +2230,12 @@ error -> {error, ?ERR_BAD_REQUEST}; _ -> @@ -541,7 +543,7 @@ end, Entities), {result, []}; _ -> -@@ -2460,11 +2286,11 @@ +@@ -2462,11 +2288,11 @@ end. read_sub(Subscriber, Node, NodeID, SubID, Lang) -> @@ -555,7 +557,7 @@ OptionsEl = {xmlelement, "options", [{"node", node_to_string(Node)}, {"jid", jlib:jid_to_string(Subscriber)}, {"subid", SubID}], -@@ -2495,7 +2321,7 @@ +@@ -2497,7 +2323,7 @@ error -> {"", "", ""}; J -> jlib:jid_tolower(J) end, @@ -564,7 +566,7 @@ {result, Subs} = node_call(Type, get_subscriptions, [NodeID, Subscriber]), SubIDs = lists:foldl(fun({subscribed, SID}, Acc) -> -@@ -2515,7 +2341,7 @@ +@@ -2517,7 +2343,7 @@ end. write_sub(Subscriber, NodeID, SubID, Options) -> @@ -573,7 +575,7 @@ {error, notfound} -> {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; {result, _} -> -@@ -2683,8 +2509,8 @@ +@@ -2685,8 +2511,8 @@ {"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]}, ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza} end, @@ -584,7 +586,7 @@ true -> Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) -> -@@ -2966,7 +2792,7 @@ +@@ -2968,7 +2794,7 @@ {Depth, [{N, get_node_subs(N)} || N <- Nodes]} end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))} end, @@ -593,7 +595,7 @@ {result, CollSubs} -> CollSubs; _ -> [] end. -@@ -2980,9 +2806,9 @@ +@@ -2982,9 +2808,9 @@ get_options_for_subs(NodeID, Subs) -> lists:foldl(fun({JID, subscribed, SubID}, Acc) -> @@ -605,7 +607,7 @@ _ -> Acc end; (_, Acc) -> -@@ -3176,6 +3002,30 @@ +@@ -3178,6 +3004,30 @@ Result end. @@ -636,7 +638,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3549,7 +3399,13 @@ +@@ -3551,7 +3401,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -651,7 +653,7 @@ %% @doc

    node plugin call.

    node_call(Type, Function, Args) -> -@@ -3569,13 +3425,13 @@ +@@ -3571,13 +3427,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -667,7 +669,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3588,8 +3444,14 @@ +@@ -3590,8 +3446,14 @@ end end, Trans). @@ -684,7 +686,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3597,6 +3459,15 @@ +@@ -3599,6 +3461,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, ?ERR_INTERNAL_SERVER_ERROR}; @@ -700,7 +702,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, ?ERR_INTERNAL_SERVER_ERROR}; -@@ -3605,6 +3476,17 @@ +@@ -3607,6 +3478,17 @@ {error, ?ERR_INTERNAL_SERVER_ERROR} end. diff --git a/src/mod_pubsub/pubsub_subscription.erl b/src/mod_pubsub/pubsub_subscription.erl index e41acc518..535b37428 100644 --- a/src/mod_pubsub/pubsub_subscription.erl +++ b/src/mod_pubsub/pubsub_subscription.erl @@ -95,6 +95,7 @@ subscribe_node(JID, NodeID, Options) -> case catch mnesia:sync_dirty(fun add_subscription/3, [JID, NodeID, Options]) of {'EXIT', {aborted, Error}} -> Error; + {error, Error} -> {error, Error}; Result -> {result, Result} end. @@ -102,6 +103,7 @@ unsubscribe_node(JID, NodeID, SubID) -> case catch mnesia:sync_dirty(fun delete_subscription/3, [JID, NodeID, SubID]) of {'EXIT', {aborted, Error}} -> Error; + {error, Error} -> {error, Error}; Result -> {result, Result} end. @@ -109,6 +111,7 @@ get_subscription(JID, NodeID, SubID) -> case catch mnesia:sync_dirty(fun read_subscription/3, [JID, NodeID, SubID]) of {'EXIT', {aborted, Error}} -> Error; + {error, Error} -> {error, Error}; Result -> {result, Result} end. @@ -116,6 +119,7 @@ set_subscription(JID, NodeID, SubID, Options) -> case catch mnesia:sync_dirty(fun write_subscription/4, [JID, NodeID, SubID, Options]) of {'EXIT', {aborted, Error}} -> Error; + {error, Error} -> {error, Error}; Result -> {result, Result} end. @@ -160,26 +164,23 @@ create_table() -> add_subscription(_JID, _NodeID, Options) -> SubID = make_subid(), - Record = #pubsub_subscription{subid = SubID, options = Options}, - mnesia:write(Record), + mnesia:write(#pubsub_subscription{subid = SubID, options = Options}), SubID. -delete_subscription(JID, NodeID, SubID) -> - Sub = read_subscription(JID, NodeID, SubID), - mnesia:delete({pubsub_subscription, SubID}), - Sub. +delete_subscription(_JID, _NodeID, SubID) -> + mnesia:delete({pubsub_subscription, SubID}). read_subscription(_JID, _NodeID, SubID) -> - Q = qlc:q([Sub || Sub <- mnesia:table(pubsub_subscription), - Sub#pubsub_subscription.subid == SubID]), - case qlc:e(Q) of - [Sub] -> Sub; - [] -> mnesia:abort({error, notfound}) + case mnesia:read({pubsub_subscription, SubID}) of + [Sub] -> Sub; + _ -> {error, notfound} end. write_subscription(JID, NodeID, SubID, Options) -> - Sub = read_subscription(JID, NodeID, SubID), - mnesia:write(Sub#pubsub_subscription{options = Options}). + case read_subscription(JID, NodeID, SubID) of + {error, notfound} -> {error, notfound}; + Sub -> mnesia:write(Sub#pubsub_subscription{options = Options}) + end. make_subid() -> {T1, T2, T3} = now(),