diff --git a/ChangeLog b/ChangeLog
index 47f9e6eec..964d5a689 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2009-04-30 Christophe Romain
+
+ * src/mod_pubsub/mod_pubsub.erl: API change for major optimization
+ * src/mod_pubsub/pubsub.hrl: Likewise
+ * src/mod_pubsub/nodetree_default.erl: Likewise
+ * src/mod_pubsub/nodetree_virtual.erl: Likewise
+ * src/mod_pubsub/node_mb.erl: Likewise
+ * src/mod_pubsub/node_dispatch.erl: Likewise
+ * src/mod_pubsub/node_buddy.erl: Likewise
+ * src/mod_pubsub/node_private.erl: Likewise
+ * src/mod_pubsub/node_public.erl: Likewise
+ * src/mod_pubsub/node_default.erl: Likewise
+ * src/mod_pubsub/node_pep.erl: Likewise
+ * src/mod_pubsub/node_club.erl: Likewise
+ * src/mod_pubsub/node_flat.erl: Likewise
+ * src/mod_pubsub/node.template: Likewise
+ * src/mod_pubsub/gen_pubsub_node.erl: Likewise
+ * src/mod_pubsub/gen_pubsub_nodetree.erl: Likewise
+
+ * src/mod_caps.erl: Reduce memory consumption and remove mnesia table
+
2009-04-28 Badlop
* src/ejabberd_hooks.erl: Support distributed hooks (EJAB-829)
diff --git a/src/mod_caps.erl b/src/mod_caps.erl
index 536e103a2..3b95cfd22 100644
--- a/src/mod_caps.erl
+++ b/src/mod_caps.erl
@@ -22,6 +22,8 @@
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
+%%% 2009, improvements from Process-One to support correct PEP handling
+%%% through s2s, use less memory, and speedup global caps handling
%%%----------------------------------------------------------------------
-module(mod_caps).
@@ -64,7 +66,7 @@
-define(CAPS_QUERY_TIMEOUT, 60000). % 1mn without answer, consider client never answer
-record(caps, {node, version, exts}).
--record(caps_features, {node_pair, features}).
+-record(caps_features, {node_pair, features = []}).
-record(user_caps, {jid, caps}).
-record(user_caps_resources, {uid, resource}).
-record(state, {host,
@@ -190,19 +192,32 @@ receive_packet(_, _, _) ->
receive_packet(_JID, From, To, Packet) ->
receive_packet(From, To, Packet).
+jid_to_binary(JID) ->
+ list_to_binary(jlib:jid_to_string(JID)).
+
+caps_to_binary(#caps{node = Node, version = Version, exts = Exts}) ->
+ BExts = [list_to_binary(Ext) || Ext <- Exts],
+ #caps{node = list_to_binary(Node), version = list_to_binary(Version), exts = BExts}.
+
+node_to_binary(Node, SubNode) ->
+ {list_to_binary(Node), list_to_binary(SubNode)}.
+
+features_to_binary(L) -> [list_to_binary(I) || I <- L].
+binary_to_features(L) -> [binary_to_list(I) || I <- L].
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
init([Host, _Opts]) ->
mnesia:create_table(caps_features,
- [{ram_copies, [node()]},
+ [{disc_copies, [node()]},
{attributes, record_info(fields, caps_features)}]),
mnesia:create_table(user_caps,
- [{disc_copies, [node()]},
+ [{ram_copies, [node()]},
{attributes, record_info(fields, user_caps)}]),
mnesia:create_table(user_caps_resources,
- [{disc_copies, [node()]},
+ [{ram_copies, [node()]},
{type, bag},
{attributes, record_info(fields, user_caps_resources)}]),
mnesia:delete_table(user_caps_default),
@@ -214,26 +229,21 @@ init([Host, _Opts]) ->
maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) ->
SubNodes = [Version | Exts],
- F = fun() ->
- %% Make sure that we have all nodes we need to know.
- %% If a single one is missing, we wait for more disco
- %% responses.
- lists:foldl(fun(SubNode, Acc) ->
- case Acc of
- fail -> fail;
- _ ->
- case mnesia:read({caps_features, {Node, SubNode}}) of
- [] -> fail;
- [#caps_features{features = Features}] -> Features ++ Acc
- end
- end
- end, [], SubNodes)
- end,
- case mnesia:transaction(F) of
- {atomic, fail} ->
- wait;
- {atomic, Features} ->
- {ok, Features}
+ %% Make sure that we have all nodes we need to know.
+ %% If a single one is missing, we wait for more disco
+ %% responses.
+ case lists:foldl(fun(SubNode, Acc) ->
+ case Acc of
+ fail -> fail;
+ _ ->
+ case mnesia:dirty_read({caps_features, {Node, SubNode}}) of
+ [] -> fail;
+ [#caps_features{features = Features}] -> Features ++ Acc %% TODO binary
+ end
+ end
+ end, [], SubNodes) of
+ fail -> wait;
+ Features -> {ok, Features}
end.
timestamp() ->
@@ -243,7 +253,7 @@ timestamp() ->
handle_call({get_features, Caps}, From, State) ->
case maybe_get_features(Caps) of
{ok, Features} ->
- {reply, Features, State};
+ {reply, binary_to_features(Features), State};
wait ->
gen_server:cast(self(), visit_feature_queries),
Timeout = timestamp() + 10,
@@ -266,7 +276,7 @@ handle_cast({note_caps, From,
S = exmpp_jid:ldomain(From),
R = exmpp_jid:resource(From),
BJID = exmpp_jid:jid_to_binary(From),
- mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}),
+ mnesia:dirty_write(#user_caps{jid = BJID, caps = caps_to_binary(Caps)}),
case ejabberd_sm:get_user_resources(U, S) of
[] ->
% only store resource of caps aware external contacts
@@ -275,20 +285,19 @@ handle_cast({note_caps, From,
_ ->
ok
end,
- SubNodes = [Version | Exts],
%% Now, find which of these are not already in the database.
- Fun = fun() ->
- lists:foldl(fun(SubNode, Acc) ->
- case mnesia:read({caps_features, {Node, SubNode}}) of
- [] ->
- [SubNode | Acc];
- _ ->
- Acc
- end
- end, [], SubNodes)
- end,
- case mnesia:transaction(Fun) of
- {atomic, Missing} ->
+ SubNodes = [Version | Exts],
+ case lists:foldl(fun(SubNode, Acc) ->
+ case mnesia:dirty_read({caps_features, {Node, SubNode}}) of
+ [] ->
+ [SubNode | Acc];
+ _ ->
+ Acc
+ end
+ end, [], SubNodes) of
+ [] ->
+ {noreply, State};
+ Missing ->
%% For each unknown caps "subnode", we send a disco request.
NewRequests = lists:foldl(
fun(SubNode, Dict) ->
@@ -302,30 +311,23 @@ handle_cast({note_caps, From,
ejabberd_router:route(exmpp_jid:make_jid(Host),
From, Stanza),
timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}),
- ?DICT:store(ID, {Node, SubNode}, Dict)
+ ?DICT:store(ID, node_to_binary(Node, SubNode), Dict)
end, Requests, Missing),
- {noreply, State#state{disco_requests = NewRequests}};
- Error ->
- ?ERROR_MSG("Transaction failed: ~p", [Error]),
- {noreply, State}
+ {noreply, State#state{disco_requests = NewRequests}}
end;
handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payload}},
#state{disco_requests = Requests} = State) ->
case {Type, Payload} of
{result, #xmlel{name = 'query', children = Els}} ->
case ?DICT:find(ID, Requests) of
- {ok, {Node, SubNode}} ->
+ {ok, BinaryNode} ->
Features =
lists:flatmap(fun(#xmlel{name = 'feature'} = F) ->
[exmpp_xml:get_attribute_as_list(F, 'var', "")];
(_) ->
[]
end, Els),
- mnesia:transaction(
- fun() ->
- mnesia:write(#caps_features{node_pair = {Node, SubNode},
- features = Features})
- end),
+ mnesia:dirty_write(#caps_features{node_pair = BinaryNode, features = features_to_binary(Features)}),
gen_server:cast(self(), visit_feature_queries);
error ->
?ERROR_MSG("ID '~s' matches no query", [ID])
@@ -333,13 +335,8 @@ handle_cast({disco_response, From, _To, #iq{id = ID, type = Type, payload = Payl
{error, _} ->
%% XXX: if we get error, we cache empty feature not to probe the client continuously
case ?DICT:find(ID, Requests) of
- {ok, {Node, SubNode}} ->
- Features = [],
- mnesia:transaction(
- fun() ->
- mnesia:write(#caps_features{node_pair = {Node, SubNode},
- features = Features})
- end),
+ {ok, BinaryNode} ->
+ mnesia:dirty_write(#caps_features{node_pair = BinaryNode}),
gen_server:cast(self(), visit_feature_queries);
error ->
?ERROR_MSG("ID '~s' matches no query", [ID])
diff --git a/src/mod_pubsub/gen_pubsub_node.erl b/src/mod_pubsub/gen_pubsub_node.erl
index 91b8163bc..b4264f809 100644
--- a/src/mod_pubsub/gen_pubsub_node.erl
+++ b/src/mod_pubsub/gen_pubsub_node.erl
@@ -43,29 +43,29 @@ behaviour_info(callbacks) ->
{options, 0},
{features, 0},
{create_node_permission, 6},
- {create_node, 3},
- {delete_node, 2},
- {purge_node, 3},
- {subscribe_node, 8},
- {unsubscribe_node, 5},
- {publish_item, 7},
- {delete_item, 4},
- {remove_extra_items, 4},
- {get_node_affiliations, 2},
+ {create_node, 2},
+ {delete_node, 1},
+ {purge_node, 2},
+ {subscribe_node, 7},
+ {unsubscribe_node, 4},
+ {publish_item, 6},
+ {delete_item, 3},
+ {remove_extra_items, 3},
+ {get_node_affiliations, 1},
{get_entity_affiliations, 2},
- {get_affiliation, 3},
- {set_affiliation, 4},
- {get_node_subscriptions, 2},
+ {get_affiliation, 2},
+ {set_affiliation, 3},
+ {get_node_subscriptions, 1},
{get_entity_subscriptions, 2},
- {get_subscription, 3},
- {set_subscription, 4},
- {get_states, 2},
- {get_state, 3},
+ {get_subscription, 2},
+ {set_subscription, 3},
+ {get_states, 1},
+ {get_state, 2},
{set_state, 1},
- {get_items, 7},
- {get_items, 3},
- {get_item, 8},
- {get_item, 3},
+ {get_items, 6},
+ {get_items, 2},
+ {get_item, 7},
+ {get_item, 2},
{set_item, 1},
{get_item_name, 3}
];
diff --git a/src/mod_pubsub/gen_pubsub_nodetree.erl b/src/mod_pubsub/gen_pubsub_nodetree.erl
index 8bd35f51d..941748e68 100644
--- a/src/mod_pubsub/gen_pubsub_nodetree.erl
+++ b/src/mod_pubsub/gen_pubsub_nodetree.erl
@@ -47,7 +47,7 @@ behaviour_info(callbacks) ->
{get_nodes, 2},
{get_nodes, 1},
{get_subnodes, 3},
- {get_subnodes_tree, 2},
+ {get_subnodes_tree, 3},
{create_node, 5},
{delete_node, 2}
];
diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
index 21042fcfe..45c8212a6 100644
--- a/src/mod_pubsub/mod_pubsub.erl
+++ b/src/mod_pubsub/mod_pubsub.erl
@@ -39,7 +39,7 @@
-module(mod_pubsub).
-author('christophe.romain@process-one.net').
--version('1.12-04').
+-version('1.12-05').
-behaviour(gen_server).
-behaviour(gen_mod).
@@ -76,13 +76,11 @@
unsubscribe_node/5,
publish_item/6,
delete_item/4,
- send_items/4,
- broadcast_stanza/6,
+ send_items/6,
+ broadcast_stanza/7,
get_configure/5,
set_configure/5,
- get_items/3,
tree_action/3,
- node_action/3,
node_action/4
]).
@@ -167,8 +165,9 @@ init([ServerHost, Opts]) ->
PepOffline = gen_mod:get_opt(pep_sendlast_offline, Opts, false),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
ServerHostB = list_to_binary(ServerHost),
- mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s),
+ pubsub_index:init(Host, ServerHost, Opts),
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
+ mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s),
ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]),
ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}),
ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {plugins, Plugins}),
@@ -195,7 +194,7 @@ init([ServerHost, Opts]) ->
false ->
ok
end,
- update_database(Host),
+ update_database(Host, ServerHost),
init_nodes(Host, ServerHost),
State = #state{host = Host,
server_host = ServerHost,
@@ -204,7 +203,7 @@ init([ServerHost, Opts]) ->
pep_sendlast_offline = PepOffline,
nodetree = NodeTree,
plugins = Plugins},
- SendLoop = spawn(?MODULE, send_loop, [State]), %% TODO supervise that process
+ SendLoop = spawn(?MODULE, send_loop, [State]),
{ok, State#state{send_loop = SendLoop}}.
%% @spec (Host, ServerHost, Opts) -> Plugins
@@ -249,7 +248,7 @@ init_nodes(Host, ServerHost) ->
create_node(Host, ServerHost, ["home", ServerHost], service_jid(Host), ?STDNODE),
ok.
-update_database(Host) ->
+update_database(Host, ServerHost) ->
mnesia:del_table_index(pubsub_node, type),
mnesia:del_table_index(pubsub_node, parentid),
case catch mnesia:table_info(pubsub_node, attributes) of
@@ -257,14 +256,14 @@ update_database(Host) ->
?INFO_MSG("upgrade pubsub tables",[]),
F = fun() ->
lists:foldl(
- fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, RecList) ->
+ fun({pubsub_node, NodeId, ParentId, {nodeinfo, Items, Options, Entities}}, {RecList, NodeIdx}) ->
ItemsList =
lists:foldl(
fun({item, IID, Publisher, Payload}, Acc) ->
- C = {Publisher, unknown},
- M = {Publisher, now()},
+ C = {unknown, Publisher},
+ M = {now(), Publisher},
mnesia:write(
- #pubsub_item{itemid = {IID, NodeId},
+ #pubsub_item{itemid = {IID, NodeIdx},
creation = C,
modification = M,
payload = Payload}),
@@ -282,7 +281,7 @@ update_database(Host) ->
end
end, [], ItemsList),
mnesia:write(
- #pubsub_state{stateid = {JID, NodeId},
+ #pubsub_state{stateid = {JID, NodeIdx},
items = UsrItems,
affiliation = Aff,
subscription = Sub}),
@@ -292,12 +291,13 @@ update_database(Host) ->
end
end, [], Entities),
mnesia:delete({pubsub_node, NodeId}),
- [#pubsub_node{nodeid = NodeId,
- parentid = ParentId,
+ {[#pubsub_node{nodeid = NodeId,
+ id = NodeIdx,
+ parent = element(2, ParentId),
owners = Owners,
options = Options} |
- RecList]
- end, [],
+ RecList], NodeIdx + 1}
+ end, {[], 1},
mnesia:match_object(
{pubsub_node, {Host, '_'}, '_', '_'}))
end,
@@ -316,10 +316,62 @@ update_database(Host) ->
{aborted, Reason} ->
?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason])
end;
+ [nodeid, parentid, type, owners, options] ->
+ F = fun({pubsub_node, NodeId, {_, Parent}, Type, Owners, Options}) ->
+ #pubsub_node{
+ nodeid = NodeId,
+ id = 0,
+ parent = Parent,
+ type = Type,
+ owners = Owners,
+ options = Options}
+ end,
+ mnesia:transform_table(pubsub_node, F, [nodeid, id, parent, type, owners, options]),
+ FNew = fun() ->
+ lists:foldl(fun(#pubsub_node{nodeid = NodeId} = PubsubNode, NodeIdx) ->
+ mnesia:write(PubsubNode#pubsub_node{id = NodeIdx}),
+ lists:foreach(fun(#pubsub_state{stateid = StateId} = State) ->
+ {JID, _} = StateId,
+ mnesia:delete({pubsub_state, StateId}),
+ mnesia:write(State#pubsub_state{stateid = {JID, NodeIdx}})
+ end, mnesia:match_object(#pubsub_state{stateid = {'_', NodeId}, _ = '_'})),
+ lists:foreach(fun(#pubsub_item{itemid = ItemId} = Item) ->
+ {IID, _} = ItemId,
+ {M1, M2} = Item#pubsub_item.modification,
+ {C1, C2} = Item#pubsub_item.creation,
+ mnesia:delete({pubsub_item, ItemId}),
+ mnesia:write(Item#pubsub_item{itemid = {IID, NodeIdx},
+ modification = {M2, M1},
+ creation = {C2, C1}})
+ end, mnesia:match_object(#pubsub_item{itemid = {'_', NodeId}, _ = '_'})),
+ NodeIdx + 1
+ end, 1, mnesia:match_object(
+ {pubsub_node, {Host, '_'}, '_', '_', '_', '_', '_'})
+ ++ mnesia:match_object(
+ {pubsub_node, {{'_', ServerHost, '_'}, '_'}, '_', '_', '_', '_', '_'}))
+ end,
+ case mnesia:transaction(FNew) of
+ {atomic, Result} ->
+ ?INFO_MSG("Pubsub tables updated correctly: ~p", [Result]);
+ {aborted, Reason} ->
+ ?ERROR_MSG("Problem updating Pubsub tables:~n~p", [Reason])
+ end;
_ ->
ok
end.
+send_queue(State, Msg) ->
+ Pid = State#state.send_loop,
+ case is_process_alive(Pid) of
+ true ->
+ Pid ! Msg,
+ State;
+ false ->
+ SendLoop = spawn(?MODULE, send_loop, [State]),
+ SendLoop ! Msg,
+ State#state{send_loop = SendLoop}
+ end.
+
send_loop(State) ->
receive
{presence, JID, Pid} ->
@@ -329,16 +381,16 @@ send_loop(State) ->
BJID = jlib:short_prepd_bare_jid(JID),
%% for each node From is subscribed to
%% and if the node is so configured, send the last published item to From
- lists:foreach(fun(Type) ->
- {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]),
+ lists:foreach(fun(PType) ->
+ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, JID]),
lists:foreach(
fun({Node, subscribed, SubJID}) ->
if (SubJID == LJID) or (SubJID == BJID) ->
case tree_action(Host, get_node, [Host, Node, JID]) of
- #pubsub_node{options = Options} ->
+ #pubsub_node{options = Options, type = Type, id = NodeId} ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
- send_items(Host, Node, SubJID, last);
+ send_items(Host, Node, NodeId, Type, SubJID, last);
_ ->
ok
end;
@@ -392,7 +444,7 @@ send_loop(State) ->
Owner = jlib:short_prepd_bare_jid(JID),
Host = State#state.host,
ServerHost = State#state.server_host,
- lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
+ lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = NodeId, options = Options}) ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
lists:foreach(fun(Resource) ->
@@ -410,7 +462,7 @@ send_loop(State) ->
element(2, get_roster_info(OU, OS, LJID, Grps))
end,
if Subscribed ->
- send_items(Owner, Node, LJID, last);
+ send_items(Owner, Node, NodeId, Type, LJID, last);
true ->
ok
end;
@@ -496,7 +548,7 @@ disco_sm_items(Acc, From, To, <<>>, _Lang) ->
_ -> []
end,
NodeItems = lists:map(
- fun(Node) ->
+ fun(#pubsub_node{nodeid = {_, Node}}) ->
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs =
[?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)),
?XMLATTR('node', node_to_string(Node))]}
@@ -509,24 +561,32 @@ disco_sm_items(Acc, From, To, NodeB, _Lang) ->
%% TODO, use iq_disco_items(Host, Node, From)
Host = exmpp_jid:ldomain_as_list(To),
LJID = jlib:short_prepd_bare_jid(To),
- case get_items(Host, Node, From) of
- [] ->
- Acc;
- AllItems ->
- Items = case Acc of
+ Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
+ case node_call(Type, get_items, [NodeId, From]) of
+ {result, []} ->
+ none;
+ {result, AllItems} ->
+ Items = case Acc of
{result, I} -> I;
_ -> []
end,
- NodeItems = lists:map(
- fun(#pubsub_item{itemid = Id}) ->
+ NodeItems = lists:map(
+ fun(#pubsub_item{itemid = {Id, _}}) ->
%% "jid" is required by XEP-0030, and
%% "node" is forbidden by XEP-0060.
- {result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]),
+ {result, Name} = node_action(Host, Node, get_item_name, [NodeId, Id]),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs =
[?XMLATTR('jid', exmpp_jid:jid_to_binary(LJID)),
?XMLATTR('name', Name)]}
end, AllItems),
- {result, NodeItems ++ Items}
+ {result, NodeItems ++ Items};
+ _ ->
+ none
+ end
+ end,
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, Items}} -> {result, Items};
+ _ -> Acc
end.
%% -------
@@ -602,20 +662,18 @@ handle_call(stop, _From, State) ->
%% @private
handle_cast({presence, JID, Pid}, State) ->
%% A new resource is available. send last published items
- State#state.send_loop ! {presence, JID, Pid},
- {noreply, State};
+ {noreply, send_queue(State, {presence, JID, Pid})};
handle_cast({presence, User, Server, Resources, JID}, State) ->
%% A new resource is available. send last published PEP items
- State#state.send_loop ! {presence, User, Server, Resources, JID},
- {noreply, State};
+ {noreply, send_queue(State, {presence, User, Server, Resources, JID})};
handle_cast({remove_user, LUser, LServer}, State) ->
Host = State#state.host,
Owner = exmpp_jid:make_jid(LUser, LServer),
%% remove user's subscriptions
- lists:foreach(fun(Type) ->
- {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]),
+ lists:foreach(fun(PType) ->
+ {result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Owner]),
lists:foreach(fun
({Node, subscribed, JID}) ->
unsubscribe_node(Host, Node, Owner, JID, all);
@@ -816,17 +874,17 @@ node_disco_features(Host, Node, From) ->
node_disco_info(Host, Node, From, false, true).
node_disco_info(Host, Node, From, Identity, Features) ->
Action =
- fun(#pubsub_node{type = Type}) ->
+ fun(#pubsub_node{type = Type, id = NodeId}) ->
I = case Identity of
false ->
[];
true ->
Types =
- case tree_call(Host, get_subnodes, [Host, Node, From]) of
+ case tree_call(Host, get_subnodes, [NodeId, From]) of
[] ->
["leaf"]; %% No sub-nodes: it's a leaf node
_ ->
- case node_call(Type, get_items, [Host, Node, From]) of
+ case node_call(Type, get_items, [NodeId, From]) of
{result, []} -> ["collection"];
{result, _} -> ["leaf", "collection"];
_ -> []
@@ -849,10 +907,17 @@ node_disco_info(Host, Node, From, Identity, Features) ->
%% TODO: add meta-data info (spec section 5.4)
{result, I ++ F}
end,
- transaction(Host, Node, Action, sync_dirty).
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, Result}} -> {result, Result};
+ Other -> Other
+ end.
iq_disco_info(Host, SNode, From, Lang) ->
- Node = string_to_node(SNode),
+ [RealSNode|_] = case SNode of
+ [] -> [[]];
+ _ -> string:tokens(SNode, "!")
+ end,
+ Node = string_to_node(RealSNode),
case Node of
[] ->
{result,
@@ -866,7 +931,7 @@ iq_disco_info(Host, SNode, From, Lang) ->
#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_VCARD_s)]}] ++
lists:map(fun(Feature) ->
#xmlel{ns = ?NS_DISCO_INFO, name = 'feature', attrs = [?XMLATTR('var', ?NS_PUBSUB_s++"#"++Feature)]}
- end, features(Host, SNode))};
+ end, features(Host, Node))};
_ ->
node_disco_info(Host, Node, From)
end.
@@ -890,10 +955,10 @@ iq_disco_items(Host, Item, From) ->
%% Note: Multiple Node Discovery not supported (mask on pubsub#type)
%% TODO this code is also back-compatible with pubsub v1.8 (for client issue)
%% TODO make it pubsub v1.12 compliant (breaks client compatibility ?)
- %% TODO That is, remove name attribute (or node?, please check)
+ %% TODO That is, remove name attribute (or node?, please check for 2.1)
Action =
- fun(#pubsub_node{type = Type}) ->
- NodeItems = case node_call(Type, get_items, [Host, Node, From]) of
+ fun(#pubsub_node{type = Type, id = NodeId}) ->
+ NodeItems = case node_call(Type, get_items, [NodeId, From]) of
{result, I} -> I;
_ -> []
end,
@@ -903,17 +968,20 @@ iq_disco_items(Host, Item, From) ->
RN = lists:last(SubNode),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN),
?XMLATTR('name', RN)]}
- end, tree_call(Host, get_subnodes, [Host, Node, From])),
+ end, tree_call(Host, get_subnodes, [NodeId, From])),
Items = lists:map(
fun(#pubsub_item{itemid = {RN, _}}) ->
SN = node_to_string(Node) ++ "!" ++ RN,
- {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]),
+ {result, Name} = node_call(Type, get_item_name, [NodeId, RN]),
#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [?XMLATTR('jid', Host), ?XMLATTR('node', SN),
?XMLATTR('name', Name)]}
end, NodeItems),
{result, Nodes ++ Items}
end,
- transaction(Host, Node, Action, sync_dirty)
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, Result}} -> {result, Result};
+ Other -> Other
+ end
end.
iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) ->
@@ -1098,7 +1166,7 @@ iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
%%% authorization handling
-send_authorization_request(Host, Node, Subscriber) ->
+send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}}, Subscriber) ->
Lang = "en", %% TODO fix
{U, S, R} = Subscriber,
Stanza = #xmlel{ns = ?NS_JABBER_CLIENT, name = 'message', children =
@@ -1125,16 +1193,9 @@ send_authorization_request(Host, Node, Subscriber) ->
?XMLATTR('type', <<"boolean">>),
?XMLATTR('label', translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?"))], children =
[#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = <<"false">>}]}]}]}]},
- case tree_action(Host, get_node, [Host, Node, Subscriber]) of
- #pubsub_node{owners = Owners} ->
- lists:foreach(
- fun({U1, S1, R1}) ->
- ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(U1, S1, R1), Stanza}
- end, Owners),
- ok;
- _ ->
- ok
- end.
+ lists:foreach(fun(Owner) ->
+ ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
+ end, Owners).
find_authorization_response(Packet) ->
Els = Packet#xmlel.children,
@@ -1192,11 +1253,9 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
"true" -> true;
_ -> false
end,
- Action = fun(#pubsub_node{type = Type,
- %%options = Options,
- owners = Owners}) ->
+ Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) ->
IsApprover = lists:member(jlib:short_prepd_bare_jid(From), Owners),
- {result, Subscription} = node_call(Type, get_subscription, [Host, Node, Subscriber]),
+ {result, Subscription} = node_call(Type, get_subscription, [NodeId, Subscriber]),
if
not IsApprover ->
{error, 'forbidden'};
@@ -1208,7 +1267,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
false -> none
end,
send_authorization_approval(Host, Subscriber, SNode, NewSubscription),
- node_call(Type, set_subscription, [Host, Node, Subscriber, NewSubscription])
+ node_call(Type, set_subscription, [NodeId, Subscriber, NewSubscription])
end
end,
case transaction(Host, Node, Action, sync_dirty) of
@@ -1216,7 +1275,7 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
ejabberd_router:route(
To, From,
exmpp_stanza:reply_with_error(Packet, Error));
- {result, _NewSubscription} ->
+ {result, _} ->
%% XXX: notify about subscription state change, section 12.11
ok;
_ ->
@@ -1297,7 +1356,6 @@ handle_authorization_response(Host, From, To, Packet, XFields) ->
%%
create_node(Host, ServerHost, Node, Owner, Type) ->
create_node(Host, ServerHost, Node, Owner, Type, all, []).
-
create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
case lists:member("instant-nodes", features(Type)) of
true ->
@@ -1348,13 +1406,10 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
case node_call(Type, create_node_permission, [Host, ServerHost, Node, Parent, Owner, Access]) of
{result, true} ->
case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions]) of
- ok ->
- node_call(Type, create_node, [Host, Node, Owner]);
- {error, 'conflict'} ->
- case proplists:get_value(virtual_tree, tree_call(Host, options, [])) of
- true -> node_call(Type, create_node, [Host, Node, Owner]);
- _ -> {error, 'conflict'}
- end;
+ {ok, NodeId} ->
+ node_call(Type, create_node, [NodeId, Owner]);
+ {error, {virtual, NodeId}} ->
+ node_call(Type, create_node, [NodeId, Owner]);
Error ->
Error
end;
@@ -1365,12 +1420,6 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
Reply = [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB, name = 'create', attrs = [?XMLATTR('node', node_to_string(Node))]}]}],
case transaction(CreateNode, transaction) of
- {error, Error} ->
- %% in case we change transaction to sync_dirty...
- %%node_action:
- %% node_call(Type, delete_node, [Host, Node]),
- %% tree_call(Host, delete_node, [Host, Node]),
- {error, Error};
{result, {Result, broadcast}} ->
%%Lang = "en", %% TODO: fix
%%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
@@ -1385,7 +1434,12 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
{result, default} ->
{result, Reply};
{result, Result} ->
- {result, Result}
+ {result, Result};
+ Error ->
+ %% in case we change transaction to sync_dirty...
+ %% node_call(Type, delete_node, [NodeId]),
+ %% tree_call(Host, delete_node, [NodeId]),
+ Error
end;
Error ->
Error
@@ -1408,11 +1462,11 @@ delete_node(_Host, [], _Owner) ->
%% Node is the root
{error, 'not-allowed'};
delete_node(Host, Node, Owner) ->
- Action = fun(#pubsub_node{type = Type}) ->
- case node_call(Type, get_affiliation, [Host, Node, Owner]) of
+ Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
+ case node_call(Type, get_affiliation, [NodeId, Owner]) of
{result, owner} ->
- Removed = tree_call(Host, delete_node, [Host, Node]),
- node_call(Type, delete_node, [Host, Removed]);
+ Removed = tree_call(Host, delete_node, [NodeId]),
+ node_call(Type, delete_node, [Removed]);
_ ->
%% Entity is not an owner
{error, 'forbidden'}
@@ -1420,28 +1474,29 @@ delete_node(Host, Node, Owner) ->
end,
Reply = [],
case transaction(Host, Node, Action, transaction) of
- {error, Error} ->
- {error, Error};
- {result, {Result, broadcast, Removed}} ->
- lists:foreach(fun(RNode) ->
- broadcast_removed_node(Host, RNode)
+ {result, {_, {Result, broadcast, Removed}}} ->
+ lists:foreach(fun({RNode, RSubscriptions}) ->
+ {RH, RN} = RNode#pubsub_node.nodeid,
+ NodeId = RNode#pubsub_node.id,
+ Type = RNode#pubsub_node.type,
+ Options = RNode#pubsub_node.options,
+ broadcast_removed_node(RH, RN, NodeId, Type, Options, RSubscriptions)
end, Removed),
case Result of
default -> {result, Reply};
_ -> {result, Result}
end;
- {result, {Result, Removed}} ->
- lists:foreach(fun(RNode) ->
- broadcast_removed_node(Host, RNode)
- end, Removed),
+ {result, {_, {Result, _Removed}}} ->
case Result of
default -> {result, Reply};
_ -> {result, Result}
end;
- {result, default} ->
+ {result, {_, default}} ->
{result, Reply};
- {result, Result} ->
- {result, Result}
+ {result, {_, Result}} ->
+ {result, Result};
+ Error ->
+ Error
end.
%% @spec (Host, Node, From, JID) ->
@@ -1474,7 +1529,7 @@ subscribe_node(Host, Node, From, JID) ->
{undefined, undefined, undefined}
end,
SubId = uniqid(),
- Action = fun(#pubsub_node{options = Options, type = Type}) ->
+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
Features = features(Type),
SubscribeFeature = lists:member("subscribe", Features),
SubscribeConfig = get_option(Options, subscribe),
@@ -1502,7 +1557,7 @@ subscribe_node(Host, Node, From, JID) ->
{error, extended_error('feature-not-implemented', unsupported, "subscribe")};
true ->
node_call(Type, subscribe_node,
- [Host, Node, From, Subscriber,
+ [NodeId, From, Subscriber,
AccessModel, SendLast,
PresenceSubscription, RosterGroup])
end
@@ -1521,26 +1576,28 @@ subscribe_node(Host, Node, From, JID) ->
end}]}]
end,
case transaction(Host, Node, Action, sync_dirty) of
- {error, Error} ->
- {error, Error};
- {result, {Result, subscribed, send_last}} ->
- send_items(Host, Node, Subscriber, last),
+ {result, {TNode, {Result, subscribed, send_last}}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ send_items(Host, Node, NodeId, Type, Subscriber, last),
case Result of
default -> {result, Reply(subscribed)};
_ -> {result, Result}
end;
- {result, {Result, Subscription}} ->
+ {result, {TNode, {Result, Subscription}}} ->
case Subscription of
- pending -> send_authorization_request(Host, Node, Subscriber);
+ pending -> send_authorization_request(TNode, Subscriber);
_ -> ok
end,
case Result of
default -> {result, Reply(Subscription)};
_ -> {result, Result}
end;
- {result, Result} ->
+ {result, {_, Result}} ->
%% this case should never occure anyway
- {result, Result}
+ {result, Result};
+ Error ->
+ Error
end.
%% @spec (Host, Noce, From, JID, SubId) -> {error, Reason} | {result, []}
@@ -1567,14 +1624,16 @@ unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) ->
end,
unsubscribe_node(Host, Node, From, Subscriber, SubId);
unsubscribe_node(Host, Node, From, Subscriber, SubId) ->
- case node_action(Host, Node, unsubscribe_node,
- [Host, Node, From, Subscriber, SubId]) of
- {error, Error} ->
- {error, Error};
- {result, default} ->
+ Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
+ node_call(Type, unsubscribe_node, [NodeId, From, Subscriber, SubId])
+ end,
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, default}} ->
{result, []};
- {result, Result} ->
- {result, Result}
+ {result, {_, Result}} ->
+ {result, Result};
+ Error ->
+ Error
end.
%% @spec (Host::host(), ServerHost::host(), JID::jid(), Node::pubsubNode(), ItemId::string(), Payload::term()) ->
@@ -1595,7 +1654,7 @@ publish_item(Host, ServerHost, Node, Publisher, "", Payload) ->
%% if publisher does not specify an ItemId, the service MUST generate the ItemId
publish_item(Host, ServerHost, Node, Publisher, uniqid(), Payload);
publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
- Action = fun(#pubsub_node{options = Options, type = Type}) ->
+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
Features = features(Type),
PublishFeature = lists:member("publish", Features),
PublishModel = get_option(Options, publish_model),
@@ -1627,12 +1686,37 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
%% Publisher attempts to publish to persistent node with no item
{error, extended_error('bad-request', "item-required")};
true ->
- node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload])
+ node_call(Type, publish_item, [NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload])
end
end,
ejabberd_hooks:run(pubsub_publish_item, ServerHost, [ServerHost, Node, Publisher, service_jid(Host), ItemId, Payload]),
Reply = [], %% TODO EJAB-909
case transaction(Host, Node, Action, sync_dirty) of
+ {result, {TNode, {Result, broadcast, Removed}}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ Options = TNode#pubsub_node.options,
+ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:short_prepd_jid(Publisher), Payload),
+ case Result of
+ default -> {result, Reply};
+ _ -> {result, Result}
+ end;
+ {result, {TNode, {default, Removed}}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ Options = TNode#pubsub_node.options,
+ broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed),
+ {result, Reply};
+ {result, {TNode, {Result, Removed}}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ Options = TNode#pubsub_node.options,
+ broadcast_retract_items(Host, Node, NodeId, Type, Options, Removed),
+ {result, Result};
+ {result, {_, default}} ->
+ {result, Reply};
+ {result, {_, Result}} ->
+ {result, Result};
{error, 'item-not-found'} ->
%% handles auto-create feature
%% for automatic node creation. we'll take the default node type:
@@ -1649,25 +1733,8 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
false ->
{error, 'item-not-found'}
end;
- {error, Reason} ->
- {error, Reason};
- {result, {Result, broadcast, Removed}} ->
- broadcast_retract_items(Host, Node, Removed),
- broadcast_publish_item(Host, Node, ItemId, jlib:short_prepd_jid(Publisher), Payload),
- case Result of
- default -> {result, Reply};
- _ -> {result, Result}
- end;
- {result, default, Removed} ->
- broadcast_retract_items(Host, Node, Removed),
- {result, Reply};
- {result, Result, Removed} ->
- broadcast_retract_items(Host, Node, Removed),
- {result, Result};
- {result, default} ->
- {result, Reply};
- {result, Result} ->
- {result, Result}
+ Error ->
+ Error
end.
%% @spec (Host::host(), JID::jid(), Node::pubsubNode(), ItemId::string()) ->
@@ -1690,7 +1757,7 @@ delete_item(_, "", _, _, _) ->
%% Request does not specify a node
{error, extended_error('bad-request', "node-required")};
delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
- Action = fun(#pubsub_node{type = Type}) ->
+ Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
Features = features(Type),
PersistentFeature = lists:member("persistent-items", Features),
DeleteFeature = lists:member("delete-items", Features),
@@ -1705,23 +1772,26 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
%% Service does not support item deletion
{error, extended_error('feature-not-implemented', unsupported, "delete-items")};
true ->
- node_call(Type, delete_item, [Host, Node, Publisher, ItemId])
+ node_call(Type, delete_item, [NodeId, Publisher, ItemId])
end
end,
Reply = [],
case transaction(Host, Node, Action, sync_dirty) of
- {error, Reason} ->
- {error, Reason};
- {result, {Result, broadcast}} ->
- broadcast_retract_items(Host, Node, [ItemId], ForceNotify),
+ {result, {TNode, {Result, broadcast}}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ Options = TNode#pubsub_node.options,
+ broadcast_retract_items(Host, Node, NodeId, Type, Options, [ItemId], ForceNotify),
case Result of
default -> {result, Reply};
_ -> {result, Result}
end;
- {result, default} ->
+ {result, {_, default}} ->
{result, Reply};
- {result, Result} ->
- {result, Result}
+ {result, {_, Result}} ->
+ {result, Result};
+ Error ->
+ Error
end.
%% @spec (Host, JID, Node) ->
@@ -1739,7 +1809,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
%%The specified node does not exist.
%%
purge_node(Host, Node, Owner) ->
- Action = fun(#pubsub_node{type = Type, options = Options}) ->
+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
Features = features(Type),
PurgeFeature = lists:member("purge-nodes", Features),
PersistentFeature = lists:member("persistent-items", Features),
@@ -1755,23 +1825,26 @@ purge_node(Host, Node, Owner) ->
%% Node is not configured for persistent items
{error, extended_error('feature-not-implemented', unsupported, "persistent-items")};
true ->
- node_call(Type, purge_node, [Host, Node, Owner])
+ node_call(Type, purge_node, [NodeId, Owner])
end
end,
Reply = [],
case transaction(Host, Node, Action, sync_dirty) of
- {error, Reason} ->
- {error, Reason};
- {result, {Result, broadcast}} ->
- broadcast_purge_node(Host, Node),
+ {result, {TNode, {Result, broadcast}}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ Options = TNode#pubsub_node.options,
+ broadcast_purge_node(Host, Node, NodeId, Type, Options),
case Result of
default -> {result, Reply};
_ -> {result, Result}
end;
- {result, default} ->
+ {result, {_, default}} ->
{result, Reply};
- {result, Result} ->
- {result, Result}
+ {result, {_, Result}} ->
+ {result, Result};
+ Error ->
+ Error
end.
%% @doc Return the items of a given node.
@@ -1793,7 +1866,7 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
{error, Error} ->
{error, Error};
_ ->
- Action = fun(#pubsub_node{options = Options, type = Type}) ->
+ Action = fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
Features = features(Type),
RetreiveFeature = lists:member("retrieve-items", Features),
PersistentFeature = lists:member("persistent-items", Features),
@@ -1816,15 +1889,13 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
{error, extended_error('feature-not-implemented', unsupported, "persistent-items")};
true ->
node_call(Type, get_items,
- [Host, Node, From,
+ [NodeId, From,
AccessModel, PresenceSubscription, RosterGroup,
SubId])
end
end,
case transaction(Host, Node, Action, sync_dirty) of
- {error, Reason} ->
- {error, Reason};
- {result, Items} ->
+ {result, {_, Items}} ->
SendItems = case ItemIDs of
[] ->
Items;
@@ -1837,47 +1908,46 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
%% number of items sent to MaxItems:
{result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
- itemsEls(lists:sublist(SendItems, MaxItems))}]}]}
+ itemsEls(lists:sublist(SendItems, MaxItems))}]}]};
+ Error ->
+ Error
end
end.
-get_items(Host, Node, From) ->
- case node_action(Host, Node, get_items, [Host, Node, From]) of
- {result, Items} -> Items;
- _ -> []
- end.
-
-%% @spec (Host, Node, LJID, Number) -> any()
+%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
%% Host = host()
-%% Node = pubsubNode()
+%% NodeId = pubsubNodeId()
+%% Type = pubsubNodeType()
%% LJID = {U, S, []}
%% Number = last | integer()
%% @doc Resend the items of a node to the user.
%% @todo use cache-last-item feature
-send_items(Host, Node, {LU, LS, LR} = LJID, Number) ->
- ToSend = case get_items(Host, Node, LJID) of
- [] ->
+send_items(Host, Node, NodeId, Type, {LU, LS, LR} = LJID, Number) ->
+ ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
+ {result, []} ->
[];
- Items ->
+ {result, Items} ->
case Number of
last ->
%%% [lists:last(Items)] does not work on clustered table
[First|Tail] = Items,
[lists:foldl(
fun(CurItem, LastItem) ->
- {_, LTimeStamp} = LastItem#pubsub_item.creation,
- {_, CTimeStamp} = CurItem#pubsub_item.creation,
+ {LTimeStamp, _} = LastItem#pubsub_item.creation,
+ {CTimeStamp, _} = CurItem#pubsub_item.creation,
if
CTimeStamp > LTimeStamp -> CurItem;
true -> LastItem
end
end, First, Tail)];
N when N > 0 ->
- %%% This case is buggy on clustered table due to lake of order
+ %%% This case is buggy on clustered table due to lack of order
lists:nthtail(length(Items)-N, Items);
_ ->
Items
- end
+ end;
+ _ ->
+ []
end,
Stanza = event_stanza(
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
@@ -1901,7 +1971,7 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) ->
%% Service does not support retreive affiliatons
{{error, extended_error('feature-not-implemented', unsupported, "retrieve-affiliations")}, Acc};
true ->
- {result, Affiliations} = node_action(Type, get_entity_affiliations, [Host, JID]),
+ {result, Affiliations} = node_action(Host, Type, get_entity_affiliations, [Host, JID]),
{Status, [Affiliations|Acc]}
end
end, {ok, []}, Plugins),
@@ -1921,10 +1991,10 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) ->
Error
end;
get_affiliations(Host, Node, JID) ->
- Action = fun(#pubsub_node{type = Type}) ->
+ Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
Features = features(Type),
RetrieveFeature = lists:member("modify-affiliations", Features),
- Affiliation = node_call(Type, get_affiliation, [Host, Node, JID]),
+ Affiliation = node_call(Type, get_affiliation, [NodeId, JID]),
if
not RetrieveFeature ->
%% Service does not support modify affiliations
@@ -1933,15 +2003,13 @@ get_affiliations(Host, Node, JID) ->
%% Entity is not an owner
{error, 'forbidden'};
true ->
- node_call(Type, get_node_affiliations, [Host, Node])
+ node_call(Type, get_node_affiliations, [NodeId])
end
end,
case transaction(Host, Node, Action, sync_dirty) of
- {error, Reason} ->
- {error, Reason};
- {result, []} ->
+ {result, {_, []}} ->
{error, 'item-not-found'};
- {result, Affiliations} ->
+ {result, {_, Affiliations}} ->
Entities = lists:flatmap(
fun({_, none}) -> [];
({{AU, AS, AR}, Affiliation}) ->
@@ -1951,7 +2019,9 @@ get_affiliations(Host, Node, JID) ->
end, Affiliations),
{result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'affiliations', attrs = [?XMLATTR('node', node_to_string(Node))], children =
- Entities}]}]}
+ Entities}]}]};
+ Error ->
+ Error
end.
set_affiliations(Host, Node, From, EntitiesEls) ->
@@ -1987,12 +2057,12 @@ set_affiliations(Host, Node, From, EntitiesEls) ->
error ->
{error, 'bad-request'};
_ ->
- Action = fun(#pubsub_node{type = Type, owners = Owners}=N) ->
+ Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}=N) ->
case lists:member(Owner, Owners) of
true ->
lists:foreach(
fun({JID, Affiliation}) ->
- node_call(Type, set_affiliation, [Host, Node, JID, Affiliation]),
+ node_call(Type, set_affiliation, [NodeId, JID, Affiliation]),
case Affiliation of
owner ->
NewOwner = jlib:short_prepd_bare_jid(JID),
@@ -2016,7 +2086,10 @@ set_affiliations(Host, Node, From, EntitiesEls) ->
{error, 'forbidden'}
end
end,
- transaction(Host, Node, Action, sync_dirty)
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, Result}} -> {result, Result};
+ Other -> Other
+ end
end.
@@ -2038,7 +2111,7 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) ->
{{error, extended_error('feature-not-implemented', unsupported, "retrieve-subscriptions")}, Acc};
true ->
Subscriber = jlib:jid_remove_resource(JID),
- {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Subscriber]),
+ {result, Subscriptions} = node_action(Host, Type, get_entity_subscriptions, [Host, Subscriber]),
{Status, [Subscriptions|Acc]}
end
end, {ok, []}, Plugins),
@@ -2064,10 +2137,10 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) ->
Error
end;
get_subscriptions(Host, Node, JID) ->
- Action = fun(#pubsub_node{type = Type}) ->
+ Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
Features = features(Type),
RetrieveFeature = lists:member("manage-subscriptions", Features),
- Affiliation = node_call(Type, get_affiliation, [Host, Node, JID]),
+ Affiliation = node_call(Type, get_affiliation, [NodeId, JID]),
if
not RetrieveFeature ->
%% Service does not support manage subscriptions
@@ -2076,15 +2149,13 @@ get_subscriptions(Host, Node, JID) ->
%% Entity is not an owner
{error, 'forbidden'};
true ->
- node_call(Type, get_node_subscriptions, [Host, Node])
+ node_call(Type, get_node_subscriptions, [NodeId])
end
end,
case transaction(Host, Node, Action, sync_dirty) of
- {error, Reason} ->
- {error, Reason};
- {result, []} ->
+ {result, {_, []}} ->
{error, 'item-not-found'};
- {result, Subscriptions} ->
+ {result, {_, Subscriptions}} ->
Entities = lists:flatmap(
fun({_, none}) -> [];
({{AU, AS, AR}, Subscription}) ->
@@ -2099,7 +2170,9 @@ get_subscriptions(Host, Node, JID) ->
end, Subscriptions),
{result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'subscriptions', attrs = [?XMLATTR('node', node_to_string(Node))], children =
- Entities}]}]}
+ Entities}]}]};
+ Error ->
+ Error
end.
set_subscriptions(Host, Node, From, EntitiesEls) ->
@@ -2136,21 +2209,22 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
error ->
{error, 'bad-request'};
_ ->
- Action = fun(#pubsub_node{type = Type, owners = Owners}) ->
+ Action = fun(#pubsub_node{type = Type, id = NodeId, owners = Owners}) ->
case lists:member(Owner, Owners) of
true ->
lists:foreach(
fun({JID, Subscription}) ->
- node_call(
- Type, set_subscription,
- [Host, Node, JID, Subscription])
+ node_call(Type, set_subscription, [NodeId, JID, Subscription])
end, Entities),
{result, []};
_ ->
{error, 'forbidden'}
end
end,
- transaction(Host, Node, Action, sync_dirty)
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, Result}} -> {result, Result};
+ Other -> Other
+ end
end.
@@ -2265,174 +2339,169 @@ event_stanza(Els) ->
%%%%%% broadcast functions
-broadcast_publish_item(Host, Node, ItemId, _From, Payload) ->
- %broadcast(Host, Node, none, true, 'items', ItemEls)
- Action =
- fun(#pubsub_node{options = Options, type = Type}) ->
- case node_call(Type, get_states, [Host, Node]) of
+broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) ->
+ %broadcast(Host, Node, NodeId, Options, none, true, 'items', ItemEls)
+ case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+ {result, []} ->
+ {result, false};
+ {result, Subs} ->
+ Content = case get_option(Options, deliver_payloads) of
+ true -> Payload;
+ false -> []
+ end,
+ Stanza = event_stanza(
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]),
+ broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+ case Removed of
+ [] ->
+ ok;
+ _ ->
+ case get_option(Options, notify_retract) of
+ true ->
+ RetractStanza = event_stanza(
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(RId)} || RId <- Removed]}]),
+ broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, RetractStanza);
+ _ ->
+ ok
+ end
+ end,
+ {result, true};
+ _ ->
+ {result, false}
+ end.
+
+broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds) ->
+ broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, false).
+broadcast_retract_items(_Host, _Node, _NodeId, _Type, _Options, [], _ForceNotify) ->
+ {result, false};
+broadcast_retract_items(Host, Node, NodeId, Type, Options, ItemIds, ForceNotify) ->
+ %broadcast(Host, Node, NodeId, Options, notify_retract, ForceNotify, 'retract', RetractEls)
+ case (get_option(Options, notify_retract) or ForceNotify) of
+ true ->
+ case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
{result, []} ->
{result, false};
- {result, States} ->
- Content = case get_option(Options, deliver_payloads) of
- true -> Payload;
- false -> []
- end,
+ {result, Subs} ->
Stanza = event_stanza(
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]),
- broadcast_stanza(Host, Node, Type, Options, States, Stanza),
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds]}]),
+ broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
{result, true};
_ ->
{result, false}
- end
- end,
- transaction(Host, Node, Action, sync_dirty).
+ end;
+ _ ->
+ {result, false}
+ end.
-broadcast_retract_items(Host, Node, ItemIds) ->
- broadcast_retract_items(Host, Node, ItemIds, false).
-broadcast_retract_items(Host, Node, ItemIds, ForceNotify) ->
- %broadcast(Host, Node, notify_retract, ForceNotify, 'retract', RetractEls)
- Action =
- fun(#pubsub_node{options = Options, type = Type}) ->
- case (get_option(Options, notify_retract) or ForceNotify) of
- true ->
- case node_call(Type, get_states, [Host, Node]) of
- {result, []} ->
- {result, false};
- {result, States} ->
- RetractEls = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = itemAttr(ItemId)} || ItemId <- ItemIds],
- Stanza = event_stanza(
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))],
- children = RetractEls}]),
- broadcast_stanza(Host, Node, Type, Options, States, Stanza),
- {result, true};
- _ ->
- {result, false}
- end;
- _ ->
+broadcast_purge_node(Host, Node, NodeId, Type, Options) ->
+ %broadcast(Host, Node, NodeId, Options, notify_retract, false, 'purge', [])
+ case get_option(Options, notify_retract) of
+ true ->
+ case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+ {result, []} ->
+ {result, false};
+ {result, Subs} ->
+ Stanza = event_stanza(
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]),
+ broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+ {result, true};
+ _ ->
{result, false}
- end
- end,
- transaction(Host, Node, Action, sync_dirty).
+ end;
+ _ ->
+ {result, false}
+ end.
-broadcast_purge_node(Host, Node) ->
- %broadcast(Host, Node, notify_retract, false, 'purge', [])
- Action =
- fun(#pubsub_node{options = Options, type = Type}) ->
- case get_option(Options, notify_retract) of
- true ->
- case node_call(Type, get_states, [Host, Node]) of
- {result, []} ->
- {result, false};
- {result, States} ->
- Stanza = event_stanza(
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]),
- broadcast_stanza(Host, Node, Type, Options, States, Stanza),
- {result, true};
- _ ->
- {result, false}
- end;
+broadcast_removed_node(Host, Node, NodeId, Type, Options, Subs) ->
+ %broadcast(Host, Node, NodeId, Options, notify_delete, false, 'delete', [])
+ case get_option(Options, notify_delete) of
+ true ->
+ case Subs of
+ [] ->
+ {result, false};
_ ->
- {result, false}
- end
- end,
- transaction(Host, Node, Action, sync_dirty).
+ Stanza = event_stanza(
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]),
+ broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+ {result, true}
+ end;
+ _ ->
+ {result, false}
+ end.
-broadcast_removed_node(Host, Node) ->
- %broadcast(Host, Node, notify_delete, false, 'delete', [])
- Action =
- fun(#pubsub_node{options = Options, type = Type}) ->
- case get_option(Options, notify_delete) of
- true ->
- case node_call(Type, get_states, [Host, Node]) of
- {result, []} ->
- {result, false};
- {result, States} ->
- Stanza = event_stanza(
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]),
- broadcast_stanza(Host, Node, Type, Options, States, Stanza),
- {result, true};
- _ ->
- {result, false}
- end;
- _ ->
+broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang) ->
+ %broadcast(Host, Node, NodeId, Options, notify_config, false, 'items', ConfigEls)
+ case get_option(Options, notify_config) of
+ true ->
+ case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+ {result, []} ->
+ {result, false};
+ {result, Subs} ->
+ Content = case get_option(Options, deliver_payloads) of
+ true ->
+ [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children =
+ get_configure_xfields(Type, Options, Lang, [])}];
+ false ->
+ []
+ end,
+ Stanza = event_stanza(
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
+ [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children =
+ Content}]}]),
+ broadcast_stanza(Host, Node, NodeId, Type, Options, Subs, Stanza),
+ {result, true};
+ _ ->
{result, false}
- end
- end,
- transaction(Host, Node, Action, sync_dirty).
+ end;
+ _ ->
+ {result, false}
+ end.
-broadcast_config_notification(Host, Node, Lang) ->
- %broadcast(Host, Node, notify_config, false, 'items', ConfigEls)
- Action =
- fun(#pubsub_node{options = Options, owners = Owners, type = Type}) ->
- case get_option(Options, notify_config) of
- true ->
- case node_call(Type, get_states, [Host, Node]) of
- {result, []} ->
- {result, false};
- {result, States} ->
- Content = case get_option(Options, deliver_payloads) of
- true ->
- [#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children =
- get_configure_xfields(Type, Options, Lang, Owners, [])}];
- false ->
- []
- end,
- Stanza = event_stanza(
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
- [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = [?XMLATTR('id', <<"configuration">>)], children =
- Content}]}]),
- broadcast_stanza(Host, Node, Type, Options, States, Stanza),
- {result, true};
- _ ->
- {result, false}
- end;
- _ ->
- {result, false}
- end
- end,
- transaction(Host, Node, Action, sync_dirty).
% TODO: merge broadcast code that way
-%broadcast(Host, Node, Feature, Force, ElName, SubEls) ->
-% Action =
-% fun(#pubsub_node{options = Options, type = Type}) ->
-% case (get_option(Options, Feature) or Force) of
-% true ->
-% case node_call(Type, get_states, [Host, Node]) of
-% {result, []} ->
-% {result, false};
-% {result, States} ->
-% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]),
-% broadcast_stanza(Host, Node, Type, Options, States, Stanza),
-% {result, true};
-% _ ->
-% {result, false}
-% end;
-% _ ->
-% {result, false}
-% end
-% end,
-% transaction(Host, Node, Action, sync_dirty).
+%broadcast(Host, Node, NodeId, Type, Options, Feature, Force, ElName, SubEls) ->
+% case (get_option(Options, Feature) or Force) of
+% true ->
+% case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
+% {result, []} ->
+% {result, false};
+% {result, Subs} ->
+% Stanza = event_stanza([{xmlelement, ElName, [{"node", node_to_string(Node)}], SubEls}]),
+% broadcast_stanza(Host, Node, Type, Options, Subs, Stanza),
+% {result, true};
+% _ ->
+% {result, false}
+% end;
+% _ ->
+% {result, false}
+% end
-broadcast_stanza(Host, Node, _Type, Options, States, Stanza) ->
- AccessModel = get_option(Options, access_model),
+broadcast_stanza(Host, Node, _NodeId, _Type, Options, Subscriptions, Stanza) ->
+ %AccessModel = get_option(Options, access_model),
PresenceDelivery = get_option(Options, presence_based_delivery),
BroadcastAll = get_option(Options, broadcast_all_resources), %% XXX this is not standard, but usefull
From = service_jid(Host),
%% Handles explicit subscriptions
- lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) ->
- case is_to_deliver(LJID, Subs, PresenceDelivery) of
+ lists:foreach(fun({LJID, Subscription}) ->
+ case is_to_deliver(LJID, Subscription, PresenceDelivery) of
true ->
- {U, S, R} = case BroadcastAll of
- true -> jlib:short_prepd_bare_jid(LJID);
- false -> LJID
+ LJIDs = case BroadcastAll of
+ true ->
+ {U, S, _} = LJID,
+ [{U, S, R} || R <- user_resources(U, S)];
+ false ->
+ [LJID]
end,
- ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza};
+ lists:foreach(fun(To) ->
+ ejabberd_router ! {route, From, jlib:make_jid(To), Stanza}
+ end, LJIDs);
false ->
ok
end
- end, States),
+ end, Subscriptions),
%% Handles implicit presence subscriptions
case Host of
{LUser, LServer, LResource} ->
@@ -2507,8 +2576,8 @@ is_caps_notify(Host, Node, LJID) ->
%%
get_configure(Host, ServerHost, Node, From, Lang) ->
Action =
- fun(#pubsub_node{options = Options, owners = Owners, type = Type}) ->
- case node_call(Type, get_affiliation, [Host, Node, From]) of
+ fun(#pubsub_node{options = Options, type = Type, id = NodeId}) ->
+ case node_call(Type, get_affiliation, [NodeId, From]) of
{result, owner} ->
Groups = ejabberd_hooks:run_fold(roster_groups, ServerHost, [], [ServerHost]),
{result,
@@ -2517,13 +2586,16 @@ get_configure(Host, ServerHost, Node, From, Lang) ->
[?XMLATTR('node', node_to_string(Node))], children =
[#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs =
[?XMLATTR('type', <<"form">>)], children =
- get_configure_xfields(Type, Options, Lang, Owners, Groups)
+ get_configure_xfields(Type, Options, Lang, Groups)
}]}]}]};
_ ->
{error, 'forbidden'}
end
end,
- transaction(Host, Node, Action, sync_dirty).
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, {_, Result}} -> {result, Result};
+ Other -> Other
+ end.
get_default(Host, Node, _From, Lang) ->
Type = select_type(Host, Host, Node),
@@ -2531,7 +2603,7 @@ get_default(Host, Node, _From, Lang) ->
{result, [#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'pubsub', children =
[#xmlel{ns = ?NS_PUBSUB_OWNER, name = 'default', children =
[#xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children =
- get_configure_xfields(Type, Options, Lang, [], [])
+ get_configure_xfields(Type, Options, Lang, [])
}]}]}]}.
%% Get node option
@@ -2607,7 +2679,7 @@ max_items(Options) ->
?LISTMXFIELD(Label, "pubsub#" ++ atom_to_list(Var),
get_option(Options, Var), Opts)).
-get_configure_xfields(Type, Options, Lang, _Owners, Groups) ->
+get_configure_xfields(Type, Options, Lang, Groups) ->
[?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NODE_CONFIG_s),
?BOOL_CONFIG_FIELD("Deliver payloads with event notifications", deliver_payloads),
?BOOL_CONFIG_FIELD("Deliver event notifications", deliver_notifications),
@@ -2646,9 +2718,8 @@ set_configure(Host, Node, From, Els, Lang) ->
{result, []};
"submit" ->
Action =
- fun(#pubsub_node{options = Options, type = Type}=N) ->
- case node_call(Type, get_affiliation,
- [Host, Node, From]) of
+ fun(#pubsub_node{options = Options, type = Type, id = NodeId} = N) ->
+ case node_call(Type, get_affiliation, [NodeId, From]) of
{result, owner} ->
case jlib:parse_xdata_submit(XEl) of
invalid ->
@@ -2660,8 +2731,7 @@ set_configure(Host, Node, From, Els, Lang) ->
end,
case set_xoption(XData, OldOpts) of
NewOpts when is_list(NewOpts) ->
- tree_call(Host, set_node,
- [N#pubsub_node{options = NewOpts}]),
+ tree_call(Host, set_node, [N#pubsub_node{options = NewOpts}]),
{result, ok};
Err ->
Err
@@ -2672,8 +2742,11 @@ set_configure(Host, Node, From, Els, Lang) ->
end
end,
case transaction(Host, Node, Action, transaction) of
- {result, ok} ->
- broadcast_config_notification(Host, Node, Lang),
+ {result, {TNode, ok}} ->
+ NodeId = TNode#pubsub_node.id,
+ Type = TNode#pubsub_node.type,
+ Options = TNode#pubsub_node.options,
+ broadcast_config_notification(Host, Node, NodeId, Type, Options, Lang),
{result, []};
Other ->
Other
@@ -2845,13 +2918,17 @@ features(Host, []) ->
Acc ++ features(Plugin)
end, [], plugins(Host)));
features(Host, Node) ->
- {result, Features} = node_action(Host, Node, features, []),
- lists:usort(features() ++ Features).
+ Action = fun(#pubsub_node{type = Type}) -> {result, features(Type)} end,
+ case transaction(Host, Node, Action, sync_dirty) of
+ {result, Features} -> lists:usort(features() ++ Features);
+ _ -> features()
+ end.
%% @doc node tree plugin call.
tree_call({_User, Server, _Resource}, Function, Args) ->
tree_call(Server, Function, Args);
tree_call(Host, Function, Args) ->
+ ?DEBUG("tree_call ~p ~p ~p",[Host, Function, Args]),
Module = case ets:lookup(gen_mod:get_module_proc(Host, pubsub_state), nodetree) of
[{nodetree, N}] -> N;
_ -> list_to_atom(?TREE_PREFIX ++ ?STDTREE)
@@ -2863,6 +2940,7 @@ tree_action(Host, Function, Args) ->
%% @doc node plugin call.
node_call(Type, Function, Args) ->
+ ?DEBUG("node_call ~p ~p ~p",[Type, Function, Args]),
Module = list_to_atom(?PLUGIN_PREFIX++Type),
case catch apply(Module, Function, Args) of
{result, Result} -> {result, Result};
@@ -2876,24 +2954,23 @@ node_call(Type, Function, Args) ->
Result -> {result, Result} %% any other return value is forced as result
end.
-node_action(Type, Function, Args) ->
+node_action(_Host, Type, Function, Args) ->
transaction(fun() ->
node_call(Type, Function, Args)
end, sync_dirty).
-node_action(Host, Node, Function, Args) ->
- transaction(fun() ->
- case tree_call(Host, get_node, [Host, Node]) of
- #pubsub_node{type=Type} -> node_call(Type, Function, Args);
- Other -> Other
- end
- end, sync_dirty).
%% @doc plugin transaction handling.
transaction(Host, Node, Action, Trans) ->
transaction(fun() ->
case tree_call(Host, get_node, [Host, Node]) of
- Record when is_record(Record, pubsub_node) -> Action(Record);
- Other -> Other
+ N when is_record(N, pubsub_node) ->
+ case Action(N) of
+ {result, Result} -> {result, {N, Result}};
+ {atomic, {result, Result}} -> {result, {N, Result}};
+ Other -> Other
+ end;
+ Error ->
+ Error
end
end, Trans).
diff --git a/src/mod_pubsub/node.template b/src/mod_pubsub/node.template
index a9f45e1ef..d4fffc474 100644
--- a/src/mod_pubsub/node.template
+++ b/src/mod_pubsub/node.template
@@ -41,29 +41,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1
]).
@@ -87,7 +87,7 @@ options() ->
{roster_groups_allowed, []},
{publish_model, publishers},
{max_payload_size, ?MAX_PAYLOAD_SIZE},
- {send_last_published_item, never},
+ {send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
{presence_based_delivery, false}].
@@ -111,74 +111,74 @@ features() ->
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
- node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+ node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_default:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_default:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(Host, Node, Owner) ->
- node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+ node_default:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId)
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId)
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_buddy.erl b/src/mod_pubsub/node_buddy.erl
index 6d9e1b549..b963fba20 100644
--- a/src/mod_pubsub/node_buddy.erl
+++ b/src/mod_pubsub/node_buddy.erl
@@ -44,29 +44,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -116,74 +116,74 @@ features() ->
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
- node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+ node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_default:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_default:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(Host, Node, Owner) ->
- node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+ node_default:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_club.erl b/src/mod_pubsub/node_club.erl
index b5a04beda..1e3900cc0 100644
--- a/src/mod_pubsub/node_club.erl
+++ b/src/mod_pubsub/node_club.erl
@@ -44,29 +44,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -115,74 +115,74 @@ features() ->
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
- node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+ node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_default:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_default:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(Host, Node, Owner) ->
- node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+ node_default:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_default.erl b/src/mod_pubsub/node_default.erl
index ae0707fcb..be4f3ebfa 100644
--- a/src/mod_pubsub/node_default.erl
+++ b/src/mod_pubsub/node_default.erl
@@ -51,29 +51,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -193,8 +193,8 @@ features() ->
%% PubSub plugins can redefine the PubSub node creation rights as they
%% which. They can simply delegate this check to the {@link node_default}
%% module by implementing this function like this:
-%% ```check_create_user_permission(Host, Node, Owner, Access) ->
-%% node_default:check_create_user_permission(Host, Node, Owner, Access).'''
+%% ```check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
+%% node_default:check_create_user_permission(Host, ServerHost, Node, ParentNode, Owner, Access).'''
create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
LOwner = jlib:short_prepd_jid(Owner),
{User, Server, _Resource} = LOwner,
@@ -215,35 +215,36 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
end,
{result, Allowed}.
-%% @spec (Host, Node, Owner) ->
+%% @spec (NodeId, Owner) ->
%% {result, Result} | exit
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% NodeId = mod_pubsub:pubsubNodeId()
%% Owner = mod_pubsub:jid()
%% @doc
-create_node(Host, Node, Owner) ->
+create_node(NodeId, Owner) ->
OwnerKey = jlib:short_prepd_bare_jid(Owner),
- set_state(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner}),
+ set_state(#pubsub_state{stateid = {OwnerKey, NodeId}, affiliation = owner}),
{result, {default, broadcast}}.
-%% @spec (Host, Removed) -> ok
-%% Host = mod_pubsub:host()
+%% @spec (Removed) -> ok
%% Removed = [mod_pubsub:pubsubNode()]
%% @doc purge items of deleted nodes after effective deletion.
-delete_node(Host, Removed) ->
- lists:foreach(
- fun(Node) ->
- lists:foreach(
- fun(#pubsub_state{stateid = StateId, items = Items}) ->
- del_items(Host, Node, Items),
- del_state(StateId)
- end,
- mnesia:match_object(
- #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}))
- end, Removed),
- {result, {default, broadcast, Removed}}.
+delete_node(Removed) ->
+ Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) ->
+ {J, S}
+ end,
+ Reply = lists:map(
+ fun(#pubsub_node{id = NodeId} = PubsubNode) ->
+ {result, States} = get_states(NodeId),
+ lists:foreach(
+ fun(#pubsub_state{stateid = {LJID, _}, items = Items}) ->
+ del_items(NodeId, Items),
+ del_state(NodeId, LJID)
+ end, States),
+ {PubsubNode, lists:map(Tr, States)}
+ end, Removed),
+ {result, {default, broadcast, Reply}}.
-%% @spec (Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+%% @spec (NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
%% {error, Reason} | {result, Result}
%% @doc Accepts or rejects subcription requests on a PubSub node.
%% The mechanism works as follow:
@@ -276,17 +277,18 @@ delete_node(Host, Removed) ->
%% to completly disable persistance.
%%
%% In the default plugin module, the record is unchanged.
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup) ->
SubKey = jlib:short_prepd_jid(Subscriber),
GenKey = jlib:short_prepd_bare_jid(SubKey),
Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
SubState = case SubKey of
GenKey -> GenState;
- _ -> get_state(Host, Node, SubKey)
+ _ -> get_state(NodeId, SubKey)
end,
Affiliation = GenState#pubsub_state.affiliation,
+ Subscription = SubState#pubsub_state.subscription,
Whitelisted = lists:member(Affiliation, [member, publisher, owner]),
if
not Authorized ->
@@ -295,7 +297,7 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
Affiliation == outcast ->
%% Requesting entity is blocked
{error, 'forbidden'};
- SubState#pubsub_state.subscription == pending ->
+ Subscription == pending ->
%% Requesting entity has pending subscription
{error, ?ERR_EXTENDED('not-authorized', "pending-subscription")};
(AccessModel == presence) and (not PresenceSubscription) ->
@@ -338,23 +340,22 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
end
end.
-%% @spec (Host, Node, Sender, Subscriber, SubID) ->
+%% @spec (NodeId, Sender, Subscriber, SubID) ->
%% {error, Reason} | {result, []}
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% NodeId = mod_pubsub:pubsubNodeId()
%% Sender = mod_pubsub:jid()
%% Subscriber = mod_pubsub:jid()
%% SubID = string()
%% Reason = mod_pubsub:stanzaError()
%% @doc Unsubscribe the Subscriber from the Node.
-unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
+unsubscribe_node(NodeId, Sender, Subscriber, _SubId) ->
SubKey = jlib:short_prepd_jid(Subscriber),
GenKey = jlib:short_prepd_bare_jid(SubKey),
Authorized = (jlib:short_prepd_bare_jid(Sender) == GenKey),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
SubState = case SubKey of
GenKey -> GenState;
- _ -> get_state(Host, Node, SubKey)
+ _ -> get_state(NodeId, SubKey)
end,
if
%% Requesting entity is prohibited from unsubscribing entity
@@ -371,17 +372,16 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
{error, ?ERR_EXTENDED('unexpected-request', "not-subscribed")};
%% Was just subscriber, remove the record
SubState#pubsub_state.affiliation == none ->
- del_state(SubState#pubsub_state.stateid),
+ del_state(NodeId, SubKey),
{result, default};
true ->
set_state(SubState#pubsub_state{subscription = none}),
{result, default}
end.
-%% @spec (Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
+%% @spec (NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
%% {true, PubsubItem} | {result, Reply}
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% NodeId = mod_pubsub:pubsubNodeId()
%% Publisher = mod_pubsub:jid()
%% PublishModel = atom()
%% MaxItems = integer()
@@ -417,13 +417,13 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
%% to completly disable persistance.
%%
%% In the default plugin module, the record is unchanged.
-publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
+publish_item(NodeId, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
SubKey = jlib:short_prepd_jid(Publisher),
GenKey = jlib:short_prepd_bare_jid(SubKey),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
SubState = case SubKey of
GenKey -> GenState;
- _ -> get_state(Host, Node, SubKey)
+ _ -> get_state(NodeId, SubKey)
end,
Affiliation = GenState#pubsub_state.affiliation,
Subscription = SubState#pubsub_state.subscription,
@@ -436,31 +436,31 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
%% Entity does not have sufficient privileges to publish to node
{error, 'forbidden'};
true ->
- PubId = {SubKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824)
%% TODO: check creation, presence, roster
- Item = case get_item(Host, Node, ItemId) of
+ if MaxItems > 0 ->
+ PubId = {now(), SubKey},
+ Item = case get_item(NodeId, ItemId) of
{result, OldItem} ->
OldItem#pubsub_item{modification = PubId,
payload = Payload};
_ ->
- #pubsub_item{itemid = {ItemId, {Host, Node}},
- creation = {GenKey, now()},
+ #pubsub_item{itemid = {ItemId, NodeId},
+ creation = {now(), GenKey},
modification = PubId,
payload = Payload}
end,
- Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
- {result, {NI, OI}} = remove_extra_items(
- Host, Node, MaxItems, Items),
- if MaxItems > 0 -> set_item(Item);
- true -> ok
- end,
- set_state(GenState#pubsub_state{items = NI}),
- {result, {default, broadcast, OI}}
+ Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
+ {result, {NI, OI}} = remove_extra_items(NodeId, MaxItems, Items),
+ set_item(Item),
+ set_state(GenState#pubsub_state{items = NI}),
+ {result, {default, broadcast, OI}};
+ true ->
+ {result, {default, broadcast, []}}
+ end
end.
-%% @spec (Host, Node, MaxItems, ItemIds) -> {NewItemIds,OldItemIds}
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, MaxItems, ItemIds) -> {NewItemIds,OldItemIds}
+%% NodeId = mod_pubsub:pubsubNodeId()
%% MaxItems = integer() | unlimited
%% ItemIds = [ItemId::string()]
%% NewItemIds = [ItemId::string()]
@@ -472,34 +472,33 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
%% rules can be used.
%% If another PubSub plugin wants to delegate the item removal (and if the
%% plugin is using the default pubsub storage), it can implements this function like this:
-%% ```remove_extra_items(Host, Node, MaxItems, ItemIds) ->
-%% node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).'''
-remove_extra_items(_Host, _Node, unlimited, ItemIds) ->
+%% ```remove_extra_items(NodeId, MaxItems, ItemIds) ->
+%% node_default:remove_extra_items(NodeId, MaxItems, ItemIds).'''
+remove_extra_items(_NodeId, unlimited, ItemIds) ->
{result, {ItemIds, []}};
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
NewItems = lists:sublist(ItemIds, MaxItems),
OldItems = lists:nthtail(length(NewItems), ItemIds),
%% Remove extra items:
- del_items(Host, Node, OldItems),
+ del_items(NodeId, OldItems),
%% Return the new items list:
{result, {NewItems, OldItems}}.
-%% @spec (Host, Node, JID, ItemId) ->
+%% @spec (NodeId, JID, ItemId) ->
%% {error, Reason::stanzaError()} |
%% {result, []}
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% NodeId = mod_pubsub:pubsubNodeId()
%% JID = mod_pubsub:jid()
%% ItemId = string()
%% @doc Triggers item deletion.
%% Default plugin: The user performing the deletion must be the node owner
%% or a publisher.
-delete_item(Host, Node, Publisher, ItemId) ->
+delete_item(NodeId, Publisher, ItemId) ->
GenKey = jlib:short_prepd_bare_jid(Publisher),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
#pubsub_state{affiliation = Affiliation, items = Items} = GenState,
Allowed = (Affiliation == publisher) orelse (Affiliation == owner)
- orelse case get_item(Host, Node, ItemId) of
+ orelse case get_item(NodeId, ItemId) of
{result, #pubsub_item{creation = {GenKey, _}}} -> true;
_ -> false
end,
@@ -508,30 +507,30 @@ delete_item(Host, Node, Publisher, ItemId) ->
%% Requesting entity does not have sufficient privileges
{error, 'forbidden'};
true ->
- case get_item(Host, Node, ItemId) of
- {result, _} ->
- del_item(Host, Node, ItemId),
+ case lists:member(ItemId, Items) of
+ true ->
+ del_item(NodeId, ItemId),
NewItems = lists:delete(ItemId, Items),
set_state(GenState#pubsub_state{items = NewItems}),
{result, {default, broadcast}};
- _ ->
+ false ->
%% Non-existent node or item
{error, 'item-not-found'}
end
end.
-%% @spec (Host, Node, Owner) ->
+%% @spec (NodeId, Owner) ->
%% {error, Reason::stanzaError()} |
%% {result, {default, broadcast}}
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% NodeId = mod_pubsub:pubsubNodeId()
%% Owner = mod_pubsub:jid()
-purge_node(Host, Node, Owner) ->
+purge_node(NodeId, Owner) ->
GenKey = jlib:short_prepd_bare_jid(Owner),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
case GenState of
#pubsub_state{items = Items, affiliation = owner} ->
- del_items(Host, Node, Items),
+ del_items(NodeId, Items),
+ set_state(GenState#pubsub_state{items = []}),
{result, {default, broadcast}};
_ ->
%% Entity is not owner
@@ -548,42 +547,40 @@ purge_node(Host, Node, Owner) ->
%% the default PubSub module. Otherwise, it should return its own affiliation,
%% that will be added to the affiliation stored in the main
%% pubsub_state table.
-get_entity_affiliations(Host, Owner) ->
+get_entity_affiliations(_Host, Owner) ->
GenKey = jlib:short_prepd_bare_jid(Owner),
States = mnesia:match_object(
- #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}),
- Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) ->
+ #pubsub_state{stateid = {GenKey, '_'}, _ = '_'}),
+ Tr = fun(#pubsub_state{stateid = {_, N}, affiliation = A}) ->
{N, A}
end,
{result, lists:map(Tr, States)}.
-get_node_affiliations(Host, Node) ->
- {result, States} = get_states(Host, Node),
+get_node_affiliations(NodeId) ->
+ {result, States} = get_states(NodeId),
Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) ->
{J, A}
end,
{result, lists:map(Tr, States)}.
-get_affiliation(Host, Node, Owner) ->
+get_affiliation(NodeId, Owner) ->
GenKey = jlib:short_prepd_bare_jid(Owner),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
{result, GenState#pubsub_state.affiliation}.
-set_affiliation(Host, Node, Owner, Affiliation) ->
+set_affiliation(NodeId, Owner, Affiliation) ->
GenKey = jlib:short_prepd_bare_jid(Owner),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
case {Affiliation, GenState#pubsub_state.subscription} of
{none, none} ->
- del_state(GenState#pubsub_state.stateid);
+ del_state(NodeId, GenKey);
_ ->
set_state(GenState#pubsub_state{affiliation = Affiliation})
- end,
- ok.
+ end.
%% @spec (Host, Owner) -> [{Node,Subscription}]
%% Host = host()
%% Owner = mod_pubsub:jid()
-%% Node = mod_pubsub:pubsubNode()
%% @doc Return the current subscriptions for the given user
%% The default module reads subscriptions in the main Mnesia
%% pubsub_state table. If a plugin stores its data in the same
@@ -591,49 +588,47 @@ set_affiliation(Host, Node, Owner, Affiliation) ->
%% the default PubSub module. Otherwise, it should return its own affiliation,
%% that will be added to the affiliation stored in the main
%% pubsub_state table.
-get_entity_subscriptions(Host, Owner) ->
+get_entity_subscriptions(_Host, Owner) ->
{U, D, _} = SubKey = jlib:short_prepd_jid(Owner),
GenKey = jlib:short_prepd_bare_jid(SubKey),
States = case SubKey of
GenKey -> mnesia:match_object(
- #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'});
+ #pubsub_state{stateid = {{U, D, '_'}, '_'}, _ = '_'});
_ -> mnesia:match_object(
- #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'})
+ #pubsub_state{stateid = {GenKey, '_'}, _ = '_'})
++ mnesia:match_object(
- #pubsub_state{stateid = {SubKey, {Host, '_'}}, _ = '_'})
+ #pubsub_state{stateid = {SubKey, '_'}, _ = '_'})
end,
- Tr = fun(#pubsub_state{stateid = {J, {_, N}}, subscription = S}) ->
+ Tr = fun(#pubsub_state{stateid = {J, N}, subscription = S}) ->
{N, S, J}
end,
{result, lists:map(Tr, States)}.
-get_node_subscriptions(Host, Node) ->
- {result, States} = get_states(Host, Node),
- Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) ->
+get_node_subscriptions(NodeId) ->
+ {result, States} = get_states(NodeId),
+ Tr = fun(#pubsub_state{stateid = {J, _}, subscription = S}) ->
{J, S}
end,
{result, lists:map(Tr, States)}.
-get_subscription(Host, Node, Owner) ->
+get_subscription(NodeId, Owner) ->
SubKey = jlib:short_prepd_jid(Owner),
- SubState = get_state(Host, Node, SubKey),
+ SubState = get_state(NodeId, SubKey),
{result, SubState#pubsub_state.subscription}.
-set_subscription(Host, Node, Owner, Subscription) ->
+set_subscription(NodeId, Owner, Subscription) ->
SubKey = jlib:short_prepd_jid(Owner),
- SubState = get_state(Host, Node, SubKey),
+ SubState = get_state(NodeId, SubKey),
case {Subscription, SubState#pubsub_state.affiliation} of
{none, none} ->
- del_state(SubState#pubsub_state.stateid);
+ del_state(NodeId, SubKey);
_ ->
set_state(SubState#pubsub_state{subscription = Subscription})
end,
ok.
-%% @spec (Host, Node) -> [States] | []
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
-%% Item = mod_pubsub:pubsubItems()
+%% @spec (NodeId) -> [States] | []
+%% NodeId = mod_pubsub:pubsubNodeId()
%% @doc Returns the list of stored states for a given node.
%% For the default PubSub module, states are stored in Mnesia database.
%% We can consider that the pubsub_state table have been created by the main
@@ -642,21 +637,20 @@ set_subscription(Host, Node, Owner, Subscription) ->
%% relational database).
%% If a PubSub plugin wants to delegate the states storage to the default node,
%% they can implement this function like this:
-%% ```get_states(Host, Node) ->
-%% node_default:get_states(Host, Node).'''
-get_states(Host, Node) ->
+%% ```get_states(NodeId) ->
+%% node_default:get_states(NodeId).'''
+get_states(NodeId) ->
States = mnesia:match_object(
- #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}),
+ #pubsub_state{stateid = {'_', NodeId}, _ = '_'}),
{result, States}.
-%% @spec (JID, Host, Node) -> [State] | []
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, JID) -> [State] | []
+%% NodeId = mod_pubsub:pubsubNodeId()
%% JID = mod_pubsub:jid()
%% State = mod_pubsub:pubsubItems()
%% @doc Returns a state (one state list), given its reference.
-get_state(Host, Node, JID) ->
- StateId = {JID, {Host, Node}},
+get_state(NodeId, JID) ->
+ StateId = {JID, NodeId},
case mnesia:read({pubsub_state, StateId}) of
[State] when is_record(State, pubsub_state) -> State;
_ -> #pubsub_state{stateid=StateId}
@@ -673,12 +667,11 @@ set_state(_) ->
%% @spec (StateId) -> ok | {error, Reason::stanzaError()}
%% StateId = mod_pubsub:pubsubStateId()
%% @doc Delete a state from database.
-del_state(StateId) ->
- mnesia:delete({pubsub_state, StateId}).
+del_state(NodeId, JID) ->
+ mnesia:delete({pubsub_state, {JID, NodeId}}).
-%% @spec (Host, Node, From) -> [Items] | []
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, From) -> [Items] | []
+%% NodeId = mod_pubsub:pubsubNodeId()
%% Items = mod_pubsub:pubsubItems()
%% @doc Returns the list of stored items for a given node.
%% For the default PubSub module, items are stored in Mnesia database.
@@ -688,15 +681,15 @@ del_state(StateId) ->
%% relational database), or they can even decide not to persist any items.
%% If a PubSub plugin wants to delegate the item storage to the default node,
%% they can implement this function like this:
-%% ```get_items(Host, Node, From) ->
-%% node_default:get_items(Host, Node, From).'''
-get_items(Host, Node, _From) ->
+%% ```get_items(NodeId, From) ->
+%% node_default:get_items(NodeId, From).'''
+get_items(NodeId, _From) ->
Items = mnesia:match_object(
- #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
+ #pubsub_item{itemid = {'_', NodeId}, _ = '_'}),
{result, Items}.
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
GenKey = jlib:short_prepd_bare_jid(JID),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
Affiliation = GenState#pubsub_state.affiliation,
Subscription = GenState#pubsub_state.subscription,
Whitelisted = can_fetch_item(Affiliation, Subscription),
@@ -726,25 +719,24 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI
%% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED};
true ->
- get_items(Host, Node, JID)
+ get_items(NodeId, JID)
end.
-%% @spec (Host, Node, ItemId) -> [Item] | []
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, ItemId) -> [Item] | []
+%% NodeId = mod_pubsub:pubsubNodeId()
%% ItemId = string()
%% Item = mod_pubsub:pubsubItems()
%% @doc Returns an item (one item list), given its reference.
-get_item(Host, Node, ItemId) ->
- case mnesia:read({pubsub_item, {ItemId, {Host, Node}}}) of
+get_item(NodeId, ItemId) ->
+ case mnesia:read({pubsub_item, {ItemId, NodeId}}) of
[Item] when is_record(Item, pubsub_item) ->
{result, Item};
_ ->
{error, 'item-not-found'}
end.
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
GenKey = jlib:short_prepd_bare_jid(JID),
- GenState = get_state(Host, Node, GenKey),
+ GenState = get_state(NodeId, GenKey),
Affiliation = GenState#pubsub_state.affiliation,
Subscription = GenState#pubsub_state.subscription,
Whitelisted = can_fetch_item(Affiliation, Subscription),
@@ -774,7 +766,7 @@ get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup
%% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED};
true ->
- get_item(Host, Node, ItemId)
+ get_item(NodeId, ItemId)
end.
%% @spec (Item) -> ok | {error, Reason::stanzaError()}
@@ -785,21 +777,20 @@ set_item(Item) when is_record(Item, pubsub_item) ->
set_item(_) ->
{error, 'internal-server-error'}.
-%% @spec (Host, Node, ItemId) -> ok | {error, Reason::stanzaError()}
-%% Host = mod_pubsub:host()
-%% Node = mod_pubsub:pubsubNode()
+%% @spec (NodeId, ItemId) -> ok | {error, Reason::stanzaError()}
+%% NodeId = mod_pubsub:pubsubNodeId()
%% ItemId = string()
%% @doc Delete an item from database.
-del_item(Host, Node, ItemId) ->
- mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}).
-del_items(Host, Node, ItemIds) ->
+del_item(NodeId, ItemId) ->
+ mnesia:delete({pubsub_item, {ItemId, NodeId}}).
+del_items(NodeId, ItemIds) ->
lists:foreach(fun(ItemId) ->
- del_item(Host, Node, ItemId)
+ del_item(NodeId, ItemId)
end, ItemIds).
%% @doc Return the name of the node if known: Default is to return
%% node id.
-get_item_name(_Host, _Node, Id) ->
+get_item_name(_host, _Node, Id) ->
Id.
%% @spec (Affiliation, Subscription) -> true | false
diff --git a/src/mod_pubsub/node_dispatch.erl b/src/mod_pubsub/node_dispatch.erl
index 2d9e245e9..d5b379844 100644
--- a/src/mod_pubsub/node_dispatch.erl
+++ b/src/mod_pubsub/node_dispatch.erl
@@ -42,29 +42,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -112,79 +112,81 @@ features() ->
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(_Host, _Node, _Sender, _Subscriber, _AccessModel,
+subscribe_node(_NodeId, _Sender, _Subscriber, _AccessModel,
_SendLast, _PresenceSubscription, _RosterGroup) ->
{error, 'forbidden'}.
-unsubscribe_node(_Host, _Node, _Sender, _Subscriber, _SubID) ->
+unsubscribe_node(_NodeId, _Sender, _Subscriber, _SubID) ->
{error, 'forbidden'}.
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
lists:foreach(fun(SubNode) ->
node_default:publish_item(
- Host, SubNode, Publisher, Model,
+ SubNode#pubsub_node.id, Publisher, Model,
MaxItems, ItemId, Payload)
- end, nodetree_default:get_subnodes(Host, Node, Publisher)).
+ end, nodetree_default:get_subnodes(NodeId, Publisher)).
-remove_extra_items(_Host, _Node, _MaxItems, ItemIds) ->
+remove_extra_items(_NodeId, _MaxItems, ItemIds) ->
{result, {ItemIds, []}}.
-delete_item(_Host, _Node, _JID, _ItemId) ->
+delete_item(_NodeId, _JID, _ItemId) ->
{error, 'item-not-found'}.
-purge_node(_Host, _Node, _Owner) ->
+purge_node(_NodeId, _Owner) ->
{error, 'forbidden'}.
get_entity_affiliations(_Host, _Owner) ->
{result, []}.
-get_node_affiliations(_Host, _Node) ->
+get_node_affiliations(_NodeId) ->
{result, []}.
-get_affiliation(_Host, _Node, _Owner) ->
+get_affiliation(_NodeId, _Owner) ->
{result, []}.
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(_Host, _Owner) ->
{result, []}.
-get_node_subscriptions(_Host, _Node) ->
+get_node_subscriptions(NodeId) ->
+ %% note: get_node_subscriptions is used for broadcasting
+ %% DO NOT REMOVE
+ node_default:get_node_subscriptions(NodeId).
+
+get_subscription(_NodeId, _Owner) ->
{result, []}.
-get_subscription(_Host, _Node, _Owner) ->
- {result, []}.
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
-
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_flat.erl b/src/mod_pubsub/node_flat.erl
index e9e983aa8..8fb33e447 100644
--- a/src/mod_pubsub/node_flat.erl
+++ b/src/mod_pubsub/node_flat.erl
@@ -35,29 +35,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -103,74 +103,74 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
end,
{result, Allowed}.
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
- node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+ node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_default:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_default:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(Host, Node, Owner) ->
- node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+ node_default:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_mb.erl b/src/mod_pubsub/node_mb.erl
index 90a5cdad2..83413cd39 100644
--- a/src/mod_pubsub/node_mb.erl
+++ b/src/mod_pubsub/node_mb.erl
@@ -47,29 +47,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -120,77 +120,77 @@ features() ->
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
-create_node(Host, Node, Owner) ->
- node_pep:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_pep:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_pep:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_pep:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup) ->
node_pep:subscribe_node(
- Host, Node, Sender, Subscriber, AccessModel, SendLast,
+ NodeId, Sender, Subscriber, AccessModel, SendLast,
PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_pep:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_pep:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_pep:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_pep:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_pep:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_pep:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_pep:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_pep:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_pep:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_pep:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_pep:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_pep:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_pep:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_pep:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_pep:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_pep:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_pep:set_affiliation(NodeId, Owner, Affiliation).
-get_entity_subscriptions(Host,Owner) ->
+get_entity_subscriptions(Host, Owner) ->
node_pep:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_pep:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_pep:get_node_subscriptions(NodeId).
-get_subscription(Host,Node,Owner) ->
- node_pep:get_subscription(Host,Node,Owner).
+get_subscription(NodeId, Owner) ->
+ node_pep:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_pep:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_pep:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_pep:get_states(Host, Node).
+get_states(NodeId) ->
+ node_pep:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_pep:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_pep:get_state(NodeId, JID).
set_state(State) ->
node_pep:set_state(State).
-get_items(Host, Node, From) ->
- node_pep:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_pep:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_pep:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_pep:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_pep:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_pep:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_pep:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_pep:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_pep:set_item(Item).
diff --git a/src/mod_pubsub/node_pep.erl b/src/mod_pubsub/node_pep.erl
index bf13d3520..6c3f83d21 100644
--- a/src/mod_pubsub/node_pep.erl
+++ b/src/mod_pubsub/node_pep.erl
@@ -40,29 +40,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -133,92 +133,92 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
end,
{result, Allowed}.
-create_node(Host, Node, Owner) ->
- case node_default:create_node(Host, Node, Owner) of
+create_node(NodeId, Owner) ->
+ case node_default:create_node(NodeId, Owner) of
{result, _} -> {result, []};
Error -> Error
end.
-delete_node(Host, Removed) ->
- case node_default:delete_node(Host, Removed) of
+delete_node(Removed) ->
+ case node_default:delete_node(Removed) of
{result, {_, _, Removed}} -> {result, {[], Removed}};
Error -> Error
end.
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup) ->
node_default:subscribe_node(
- Host, Node, Sender, Subscriber, AccessModel, SendLast,
+ NodeId, Sender, Subscriber, AccessModel, SendLast,
PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- case node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID) of
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ case node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID) of
{error, Error} -> {error, Error};
{result, _} -> {result, []}
end.
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(_Host, Owner) ->
OwnerKey = jlib:short_prepd_bare_jid(Owner),
node_default:get_entity_affiliations(OwnerKey, Owner).
-get_node_affiliations(Host, Node) ->
- OwnerKey = jlib:short_bare_jid(Host),
- node_default:get_node_affiliations(OwnerKey, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(_Host, Node, Owner) ->
- OwnerKey = jlib:short_prepd_bare_jid(Owner),
- node_default:get_affiliation(OwnerKey, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(_Host, Node, Owner, Affiliation) ->
- OwnerKey = jlib:short_prepd_bare_jid(Owner),
- State = get_state(OwnerKey, Node, OwnerKey),
- set_state(State#pubsub_state{affiliation = Affiliation}),
- ok.
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(_Host, _Owner) ->
{result, []}.
-get_node_subscriptions(_Host, _Node) ->
- {result, []}.
+get_node_subscriptions(NodeId) ->
+ %% note: get_node_subscriptions is used for broadcasting
+ %% there should not have any subscriptions
+ %% but that call returns also all subscription to none
+ %% and this is required for broadcast to occurs
+ %% DO NOT REMOVE
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(_Host, _Node, _Owner) ->
+get_subscription(_NodeId, _Owner) ->
{result, none}.
-set_subscription(_Host, _Node, _Owner, _Subscription) ->
+set_subscription(_NodeId, _Owner, _Subscription) ->
ok.
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_private.erl b/src/mod_pubsub/node_private.erl
index 32f86fbb8..8458d50dc 100644
--- a/src/mod_pubsub/node_private.erl
+++ b/src/mod_pubsub/node_private.erl
@@ -44,29 +44,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -116,76 +116,76 @@ create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_default:create_node_permission(Host, ServerHost, Node, ParentNode,
Owner, Access).
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast,
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast,
PresenceSubscription, RosterGroup) ->
- node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
+ node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_default:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_default:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(Host, Node, Owner) ->
- node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+ node_default:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/node_public.erl b/src/mod_pubsub/node_public.erl
index c8fa085ab..2c8d702be 100644
--- a/src/mod_pubsub/node_public.erl
+++ b/src/mod_pubsub/node_public.erl
@@ -44,29 +44,29 @@
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
- create_node/3,
- delete_node/2,
- purge_node/3,
- subscribe_node/8,
- unsubscribe_node/5,
- publish_item/7,
- delete_item/4,
- remove_extra_items/4,
+ create_node/2,
+ delete_node/1,
+ purge_node/2,
+ subscribe_node/7,
+ unsubscribe_node/4,
+ publish_item/6,
+ delete_item/3,
+ remove_extra_items/3,
get_entity_affiliations/2,
- get_node_affiliations/2,
- get_affiliation/3,
- set_affiliation/4,
+ get_node_affiliations/1,
+ get_affiliation/2,
+ set_affiliation/3,
get_entity_subscriptions/2,
- get_node_subscriptions/2,
- get_subscription/3,
- set_subscription/4,
- get_states/2,
- get_state/3,
+ get_node_subscriptions/1,
+ get_subscription/2,
+ set_subscription/3,
+ get_states/1,
+ get_state/2,
set_state/1,
- get_items/7,
- get_items/3,
- get_item/8,
- get_item/3,
+ get_items/6,
+ get_items/2,
+ get_item/7,
+ get_item/2,
set_item/1,
get_item_name/3
]).
@@ -115,74 +115,74 @@ features() ->
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_default:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
-create_node(Host, Node, Owner) ->
- node_default:create_node(Host, Node, Owner).
+create_node(NodeId, Owner) ->
+ node_default:create_node(NodeId, Owner).
-delete_node(Host, Removed) ->
- node_default:delete_node(Host, Removed).
+delete_node(Removed) ->
+ node_default:delete_node(Removed).
-subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
- node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
+subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
+ node_default:subscribe_node(NodeId, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
-unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
- node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
+unsubscribe_node(NodeId, Sender, Subscriber, SubID) ->
+ node_default:unsubscribe_node(NodeId, Sender, Subscriber, SubID).
-publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
- node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
+publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload) ->
+ node_default:publish_item(NodeId, Publisher, Model, MaxItems, ItemId, Payload).
-remove_extra_items(Host, Node, MaxItems, ItemIds) ->
- node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
+remove_extra_items(NodeId, MaxItems, ItemIds) ->
+ node_default:remove_extra_items(NodeId, MaxItems, ItemIds).
-delete_item(Host, Node, JID, ItemId) ->
- node_default:delete_item(Host, Node, JID, ItemId).
+delete_item(NodeId, JID, ItemId) ->
+ node_default:delete_item(NodeId, JID, ItemId).
-purge_node(Host, Node, Owner) ->
- node_default:purge_node(Host, Node, Owner).
+purge_node(NodeId, Owner) ->
+ node_default:purge_node(NodeId, Owner).
get_entity_affiliations(Host, Owner) ->
node_default:get_entity_affiliations(Host, Owner).
-get_node_affiliations(Host, Node) ->
- node_default:get_node_affiliations(Host, Node).
+get_node_affiliations(NodeId) ->
+ node_default:get_node_affiliations(NodeId).
-get_affiliation(Host, Node, Owner) ->
- node_default:get_affiliation(Host, Node, Owner).
+get_affiliation(NodeId, Owner) ->
+ node_default:get_affiliation(NodeId, Owner).
-set_affiliation(Host, Node, Owner, Affiliation) ->
- node_default:set_affiliation(Host, Node, Owner, Affiliation).
+set_affiliation(NodeId, Owner, Affiliation) ->
+ node_default:set_affiliation(NodeId, Owner, Affiliation).
get_entity_subscriptions(Host, Owner) ->
node_default:get_entity_subscriptions(Host, Owner).
-get_node_subscriptions(Host, Node) ->
- node_default:get_node_subscriptions(Host, Node).
+get_node_subscriptions(NodeId) ->
+ node_default:get_node_subscriptions(NodeId).
-get_subscription(Host, Node, Owner) ->
- node_default:get_subscription(Host, Node, Owner).
+get_subscription(NodeId, Owner) ->
+ node_default:get_subscription(NodeId, Owner).
-set_subscription(Host, Node, Owner, Subscription) ->
- node_default:set_subscription(Host, Node, Owner, Subscription).
+set_subscription(NodeId, Owner, Subscription) ->
+ node_default:set_subscription(NodeId, Owner, Subscription).
-get_states(Host, Node) ->
- node_default:get_states(Host, Node).
+get_states(NodeId) ->
+ node_default:get_states(NodeId).
-get_state(Host, Node, JID) ->
- node_default:get_state(Host, Node, JID).
+get_state(NodeId, JID) ->
+ node_default:get_state(NodeId, JID).
set_state(State) ->
node_default:set_state(State).
-get_items(Host, Node, From) ->
- node_default:get_items(Host, Node, From).
+get_items(NodeId, From) ->
+ node_default:get_items(NodeId, From).
-get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_items(NodeId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
-get_item(Host, Node, ItemId) ->
- node_default:get_item(Host, Node, ItemId).
+get_item(NodeId, ItemId) ->
+ node_default:get_item(NodeId, ItemId).
-get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
- node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
+get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
+ node_default:get_item(NodeId, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_default:set_item(Item).
diff --git a/src/mod_pubsub/nodetree_default.erl b/src/mod_pubsub/nodetree_default.erl
index b8a6b6f26..d529849ff 100644
--- a/src/mod_pubsub/nodetree_default.erl
+++ b/src/mod_pubsub/nodetree_default.erl
@@ -51,7 +51,7 @@
get_nodes/2,
get_nodes/1,
get_subnodes/3,
- get_subnodes_tree/2,
+ get_subnodes_tree/3,
create_node/5,
delete_node/2
]).
@@ -76,9 +76,10 @@ init(_Host, _ServerHost, _Opts) ->
{attributes, record_info(fields, pubsub_node)}]),
NodesFields = record_info(fields, pubsub_node),
case mnesia:table_info(pubsub_node, attributes) of
- [host_node, host_parent, info] -> ok; % old schema, updated later by pubsub
NodesFields -> ok;
- _ -> mnesia:transform_table(pubsub_node, ignore, NodesFields)
+ _ ->
+ ok
+ %% mnesia:transform_table(pubsub_state, ignore, StatesFields)
end,
ok.
terminate(_Host, _ServerHost) ->
@@ -97,12 +98,11 @@ set_node(Record) when is_record(Record, pubsub_node) ->
set_node(_) ->
{error, 'internal-server-error'}.
-get_node(Host, Node, _From) ->
- get_node(Host, Node).
-
%% @spec (Host, Node) -> pubsubNode() | {error, Reason}
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
+get_node(Host, Node, _From) ->
+ get_node(Host, Node).
get_node(Host, Node) ->
case catch mnesia:read({pubsub_node, {Host, Node}}) of
[Record] when is_record(Record, pubsub_node) -> Record;
@@ -110,44 +110,48 @@ get_node(Host, Node) ->
Error -> Error
end.
-get_nodes(Key, _From) ->
- get_nodes(Key).
-
-%% @spec (Key) -> [pubsubNode()] | {error, Reason}
-%% Key = mod_pubsub:host() | mod_pubsub:jid()
-get_nodes(Key) ->
- mnesia:match_object(#pubsub_node{nodeid = {Key, '_'}, _ = '_'}).
+%% @spec (Host) -> [pubsubNode()] | {error, Reason}
+%% Host = mod_pubsub:host() | mod_pubsub:jid()
+get_nodes(Host, _From) ->
+ get_nodes(Host).
+get_nodes(Host) ->
+ mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, _ = '_'}).
%% @spec (Host, Node, From) -> [pubsubNode()] | {error, Reason}
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
get_subnodes(Host, Node, _From) ->
- mnesia:match_object(#pubsub_node{parentid = {Host, Node}, _ = '_'}).
+ get_subnodes(Host, Node).
+get_subnodes(Host, Node) ->
+ mnesia:match_object(#pubsub_node{nodeid = {Host, '_'}, parent = Node, _ = '_'}).
%% @spec (Host, Index) -> [pubsubNode()] | {error, Reason}
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
+%% From = mod_pubsub:jid()
+get_subnodes_tree(Host, Node, _From) ->
+ get_subnodes_tree(Host, Node).
get_subnodes_tree(Host, Node) ->
- mnesia:foldl(fun(#pubsub_node{nodeid = {H, N}}, Acc) ->
+ mnesia:foldl(fun(#pubsub_node{nodeid = {H, N} = R}, Acc) ->
case lists:prefix(Node, N) and (H == Host) of
- true -> [N | Acc];
+ true -> [R | Acc];
_ -> Acc
end
end, [], pubsub_node).
-%% @spec (Key, Node, Type, Owner, Options) -> ok | {error, Reason}
-%% Key = mod_pubsub:host() | mod_pubsub:jid()
+%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason}
+%% Host = mod_pubsub:host() | mod_pubsub:jid()
%% Node = mod_pubsub:pubsubNode()
%% NodeType = mod_pubsub:nodeType()
%% Owner = mod_pubsub:jid()
%% Options = list()
-create_node(Key, Node, Type, Owner, Options) ->
- OwnerKey = jlib:short_prepd_bare_jid(Owner),
- case mnesia:read({pubsub_node, {Key, Node}}) of
+create_node(Host, Node, Type, Owner, Options) ->
+ BJID = jlib:short_prepd_bare_jid(Owner),
+ case mnesia:read({pubsub_node, {Host, Node}}) of
[] ->
{ParentNode, ParentExists} =
- case Key of
+ case Host of
{_U, _S, _R} ->
%% This is special case for PEP handling
%% PEP does not uses hierarchy
@@ -158,7 +162,7 @@ create_node(Key, Node, Type, Owner, Options) ->
[] ->
{[], true};
_ ->
- case mnesia:read({pubsub_node, {Key, Parent}}) of
+ case mnesia:read({pubsub_node, {Host, Parent}}) of
[] -> {Parent, false};
_ -> {Parent, true}
end
@@ -166,13 +170,14 @@ create_node(Key, Node, Type, Owner, Options) ->
end,
case ParentExists of
true ->
- %% Service requires registration
- %%{error, ?ERR_REGISTRATION_REQUIRED};
- mnesia:write(#pubsub_node{nodeid = {Key, Node},
- parentid = {Key, ParentNode},
+ NodeId = pubsub_index:new(node),
+ mnesia:write(#pubsub_node{nodeid = {Host, Node},
+ id = NodeId,
+ parent = ParentNode,
type = Type,
- owners = [OwnerKey],
- options = Options});
+ owners = [BJID],
+ options = Options}),
+ {ok, NodeId};
false ->
%% Requesting entity is prohibited from creating nodes
{error, 'forbidden'}
@@ -182,12 +187,13 @@ create_node(Key, Node, Type, Owner, Options) ->
{error, 'conflict'}
end.
-%% @spec (Key, Node) -> [mod_pubsub:node()]
-%% Key = mod_pubsub:host() | mod_pubsub:jid()
+%% @spec (Host, Node) -> [mod_pubsub:node()]
+%% Host = mod_pubsub:host() | mod_pubsub:jid()
%% Node = mod_pubsub:pubsubNode()
-delete_node(Key, Node) ->
- Removed = get_subnodes_tree(Key, Node),
- lists:foreach(fun(N) ->
- mnesia:delete({pubsub_node, {Key, N}})
- end, Removed),
+delete_node(Host, Node) ->
+ Removed = get_subnodes_tree(Host, Node),
+ lists:foreach(fun(#pubsub_node{nodeid = {_, N}, id = I}) ->
+ pubsub_index:free(node, I),
+ mnesia:delete({pubsub_node, {Host, N}})
+ end, Removed),
Removed.
diff --git a/src/mod_pubsub/nodetree_virtual.erl b/src/mod_pubsub/nodetree_virtual.erl
index a850f26e6..5fb77e217 100644
--- a/src/mod_pubsub/nodetree_virtual.erl
+++ b/src/mod_pubsub/nodetree_virtual.erl
@@ -49,7 +49,7 @@
get_nodes/2,
get_nodes/1,
get_subnodes/3,
- get_subnodes_tree/2,
+ get_subnodes_tree/3,
create_node/5,
delete_node/2
]).
@@ -95,14 +95,13 @@ get_node(Host, Node, _From) ->
get_node(Host, Node) ->
#pubsub_node{nodeid = {Host, Node}}.
-get_nodes(Key, _From) ->
- get_nodes(Key).
-
-%% @spec (Key) -> [pubsubNode()]
+%% @spec (Host) -> [pubsubNode()]
%% Host = mod_pubsub:host() | mod_pubsub:jid()
%% @doc Virtual node tree does not handle a node database. Any node is considered
%% as existing. Nodes list can not be determined.
-get_nodes(_Key) ->
+get_nodes(Host, _From) ->
+ get_nodes(Host).
+get_nodes(_Host) ->
[].
%% @spec (Host, Node, From) -> [pubsubNode()]
@@ -110,13 +109,17 @@ get_nodes(_Key) ->
%% Node = mod_pubsub:pubsubNode()
%% From = mod_pubsub:jid()
%% @doc Virtual node tree does not handle parent/child. Child list is empty.
-get_subnodes(_Host, _Node, _From) ->
+get_subnodes(Host, Node, _From) ->
+ get_subnodes(Host, Node).
+get_subnodes(_Host, _Node) ->
[].
%% @spec (Host, Index) -> [pubsubNode()]
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% @doc Virtual node tree does not handle parent/child. Child list is empty.
+get_subnodes_tree(Host, Node, _From) ->
+ get_subnodes_tree(Host, Node).
get_subnodes_tree(_Host, _Node) ->
[].
@@ -129,11 +132,11 @@ get_subnodes_tree(_Host, _Node) ->
%% @doc No node record is stored on database. Any valid node
%% is considered as already created.
%% default allowed nodes: /home/host/user/any/node/name
-create_node(_Host, Node, _Type, Owner, _Options) ->
+create_node(Host, Node, _Type, Owner, _Options) ->
UserName = exmpp_jid:lnode_as_list(Owner),
UserHost = exmpp_jid:ldomain_as_list(Owner),
case Node of
- ["home", UserHost, UserName | _] -> {error, 'conflict'};
+ ["home", UserHost, UserName | _] -> {error, {virtual, {Host, Node}}};
_ -> {error, 'not-allowed'}
end.
@@ -142,5 +145,5 @@ create_node(_Host, Node, _Type, Owner, _Options) ->
%% Node = mod_pubsub:pubsubNode()
%% @doc Virtual node tree does not handle parent/child.
%% node deletion just affects the corresponding node.
-delete_node(_Host, Node) ->
- [Node].
+delete_node(Host, Node) ->
+ [get_node(Host, Node)].
diff --git a/src/mod_pubsub/pubsub.hrl b/src/mod_pubsub/pubsub.hrl
index 46cbe9b95..87088eb6a 100644
--- a/src/mod_pubsub/pubsub.hrl
+++ b/src/mod_pubsub/pubsub.hrl
@@ -77,24 +77,28 @@
%%% @type affiliation() = none | owner | publisher | outcast.
%%% @type subscription() = none | pending | unconfigured | subscribed.
+%%% internal pubsub index table
+-record(pubsub_index, {index, last, free}).
+
%%% @type pubsubNode() = #pubsub_node{
%%% nodeid = {Host::host(), Node::pubsubNode()},
%%% parentid = {Host::host(), Node::pubsubNode()},
+%%% nodeidx = int().
%%% type = nodeType(),
-%%% owners = [ljid()],
-%%% options = [nodeOption()]}.
+%%% options = [nodeOption()]}
%%% This is the format of the nodes table. The type of the table
%%% is: set,ram/disc.
%%% The parentid and type fields are indexed.
-record(pubsub_node, {nodeid,
- parentid = {},
- type = "",
+ id,
+ parent,
+ type = "default",
owners = [],
options = []
}).
%%% @type pubsubState() = #pubsub_state{
-%%% stateid = {ljid(), {Host::host(), Node::pubsubNode()}},
+%%% stateid = {ljid(), pubsubNodeId()}},
%%% items = [ItemId::string()],
%%% affiliation = affiliation(),
%%% subscription = subscription()}.
@@ -106,11 +110,11 @@
subscription = none
}).
-%% @type pubsubItem() = #pubsub_item{
-%% itemid = {ItemId::string(), {Host::host(),Node::pubsubNode()}},
-%% creation = {ljid(), now()},
-%% modification = {ljid(), now()},
-%% payload = XMLContent::string()}.
+%%% @type pubsubItem() = #pubsub_item{
+%%% itemid = {ItemId::string(), pubsubNodeId()}},
+%%% creation = {ljid(), now()},
+%%% modification = {ljid(), now()},
+%%% payload = XMLContent::string()}.
%%% This is the format of the published items table. The type of the
%%% table is: set,disc,fragmented.
-record(pubsub_item, {itemid,
diff --git a/src/mod_pubsub/pubsub_index.erl b/src/mod_pubsub/pubsub_index.erl
new file mode 100644
index 000000000..2ba5d4b20
--- /dev/null
+++ b/src/mod_pubsub/pubsub_index.erl
@@ -0,0 +1,65 @@
+%%% ====================================================================
+%%% ``The contents of this file are subject to the Erlang Public License,
+%%% Version 1.1, (the "License"); you may not use this file except in
+%%% compliance with the License. You should have received a copy of the
+%%% Erlang Public License along with this software. If not, it can be
+%%% retrieved via the world wide web at http://www.erlang.org/.
+%%%
+%%% Software distributed under the License is distributed on an "AS IS"
+%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%%% the License for the specific language governing rights and limitations
+%%% under the License.
+%%%
+%%% The Initial Developer of the Original Code is ProcessOne.
+%%% Portions created by ProcessOne are Copyright 2006-2009, ProcessOne
+%%% All Rights Reserved.''
+%%% This software is copyright 2006-2009, ProcessOne.
+%%%
+%%%
+%%% @copyright 2006-2009 ProcessOne
+%%% @author Christophe Romain
+%%% [http://www.process-one.net/]
+%%% @version {@vsn}, {@date} {@time}
+%%% @end
+%%% ====================================================================
+
+%% important note:
+%% new/1 and free/2 MUST be called inside a transaction bloc
+
+-module(pubsub_index).
+-author('christophe.romain@process-one.net').
+
+-include("pubsub.hrl").
+
+-export([init/3, new/1, free/2]).
+
+init(_Host, _ServerHost, _Opts) ->
+ mnesia:create_table(pubsub_index,
+ [{disc_copies, [node()]},
+ {attributes, record_info(fields, pubsub_index)}]).
+
+new(Index) ->
+ case mnesia:read({pubsub_index, Index}) of
+ [I] ->
+ case I#pubsub_index.free of
+ [] ->
+ Id = I#pubsub_index.last + 1,
+ mnesia:write(I#pubsub_index{last = Id}),
+ Id;
+ [Id|Free] ->
+ mnesia:write(I#pubsub_index{free = Free}),
+ Id
+ end;
+ _ ->
+ mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
+ 1
+ end.
+
+free(Index, Id) ->
+ case mnesia:read({pubsub_index, Index}) of
+ [I] ->
+ Free = I#pubsub_index.free,
+ mnesia:write(I#pubsub_index{free = [Id|Free]});
+ _ ->
+ ok
+ end.