25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-24 17:29:28 +01:00

port previous pubsub changes to _odbc

This commit is contained in:
Christophe Romain 2011-02-08 18:29:52 +01:00
parent f485109c39
commit 024a80d41f
2 changed files with 243 additions and 300 deletions

View File

@ -78,6 +78,7 @@
%% exports for console debug manual use
-export([create_node/5,
create_node/7,
delete_node/3,
subscribe_node/5,
unsubscribe_node/5,
@ -87,7 +88,6 @@
get_items/2,
get_item/3,
get_cached_item/2,
broadcast_stanza/9,
get_configure/5,
set_configure/5,
tree_action/3,
@ -1574,10 +1574,8 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
{result, true} ->
case tree_call(Host, create_node, [Host, Node, Type, Owner, NodeOptions, Parents]) of
{ok, NodeId} ->
ParentTree = tree_call(Host, get_parentnodes_tree, [Host, Node, Owner]),
SubsByDepth = [{Depth, [{N, get_node_subs(N)} || N <- Nodes]} || {Depth, Nodes} <- ParentTree],
case node_call(Type, create_node, [NodeId, Owner]) of
{result, Result} -> {result, {NodeId, SubsByDepth, Result}};
{result, Result} -> {result, {NodeId, Result}};
Error -> Error
end;
{error, {virtual, NodeId}} ->
@ -1596,15 +1594,15 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
[{xmlelement, "create", nodeAttr(Node),
[]}]}],
case transaction(Host, CreateNode, transaction) of
{result, {NodeId, SubsByDepth, {Result, broadcast}}} ->
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth),
{result, {NodeId, {Result, broadcast}}} ->
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions),
case Result of
default -> {result, Reply};
_ -> {result, Result}
end;
{result, {_NodeId, _SubsByDepth, default}} ->
{result, {_NodeId, default}} ->
{result, Reply};
{result, {_NodeId, _SubsByDepth, Result}} ->
{result, {_NodeId, Result}} ->
{result, Result};
Error ->
%% in case we change transaction to sync_dirty...
@ -1636,11 +1634,9 @@ delete_node(Host, Node, Owner) ->
Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
case node_call(Type, get_affiliation, [NodeId, Owner]) of
{result, owner} ->
ParentTree = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]),
SubsByDepth = [{Depth, [{N, get_node_subs(N)} || N <- Nodes]} || {Depth, Nodes} <- ParentTree],
Removed = tree_call(Host, delete_node, [Host, Node]),
case node_call(Type, delete_node, [Removed]) of
{result, Res} -> {result, {SubsByDepth, Res}};
{result, Res} -> {result, Res};
Error -> Error
end;
_ ->
@ -1650,26 +1646,26 @@ delete_node(Host, Node, Owner) ->
end,
Reply = [],
case transaction(Host, Node, Action, transaction) of
{result, {_, {SubsByDepth, {Result, broadcast, Removed}}}} ->
{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, SubsByDepth)
broadcast_removed_node(RH, RN, NodeId, Type, Options)
end, Removed),
case Result of
default -> {result, Reply};
_ -> {result, Result}
end;
{result, {_, {_, {Result, _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};
Error ->
Error
@ -1877,12 +1873,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
NodeId = TNode#pubsub_node.id,
Type = TNode#pubsub_node.type,
Options = TNode#pubsub_node.options,
BroadcastPayload = case Broadcast of
default -> Payload;
BrPayload = case Broadcast of
broadcast -> Payload;
PluginPayload -> PluginPayload
end,
broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, jlib:jid_tolower(Publisher), BroadcastPayload),
broadcast_publish_item(Host, Node, NodeId, Type, Options, ItemId, jlib:jid_tolower(Publisher), BrPayload, Removed),
set_cached_item(Host, NodeId, ItemId, Publisher, Payload),
case Result of
default -> {result, Reply};
@ -2708,21 +2703,20 @@ sub_to_deliver(_LJID, NotifyType, Depth, SubOptions) ->
sub_option_can_deliver(NotifyType, Depth, Option)
end, SubOptions).
node_to_deliver(LJID, NodeOptions) ->
presence_can_deliver(LJID, get_option(NodeOptions, presence_based_delivery)).
sub_option_can_deliver(items, _, {subscription_type, nodes}) -> false;
sub_option_can_deliver(nodes, _, {subscription_type, items}) -> false;
sub_option_can_deliver(_, _, {subscription_depth, all}) -> true;
sub_option_can_deliver(_, Depth, {subscription_depth, D}) -> Depth =< D;
sub_option_can_deliver(_, _, {deliver, false}) -> false;
sub_option_can_deliver(_, _, {expire, When}) -> now() < When;
sub_option_can_deliver(_, _, _) -> true.
node_to_deliver(LJID, NodeOptions) ->
PresenceDelivery = get_option(NodeOptions, presence_based_delivery),
presence_can_deliver(LJID, PresenceDelivery).
sub_option_can_deliver(_, _, {deliver, false}) -> false;
sub_option_can_deliver(_, _, {expire, When}) -> now() < When;
sub_option_can_deliver(_, _, _) -> true.
presence_can_deliver(_, false) -> true;
presence_can_deliver({User, Server, Resource}, true) ->
case mnesia:dirty_match_object({session, '_', '_', {User, Server}, '_', '_'}) of
case ejabberd_sm:get_user_sessions(User, Server) of
[] -> false;
Ss ->
lists:foldl(fun(_, true) -> true;
@ -2740,45 +2734,45 @@ state_can_deliver({U, S, R}, []) -> [{U, S, R}];
state_can_deliver({U, S, R}, SubOptions) ->
%% Check SubOptions for 'show_values'
case lists:keysearch('show_values', 1, SubOptions) of
%% If not in suboptions, item can be delivered, case doesn't apply
false -> [{U, S, R}];
%% If in a suboptions ...
{_, {_, ShowValues}} ->
%% Get subscriber resources
Resources = case R of
%% If the subscriber JID is a bare one, get all its resources
[] -> user_resources(U, S);
%% If the subscriber JID is a full one, use its resource
R -> [R]
end,
%% For each resource, test if the item is allowed to be delivered
%% based on resource state
lists:foldl(
fun(Resource, Acc) ->
get_resource_state({U, S, Resource}, ShowValues, Acc)
end, [], Resources)
%% If not in suboptions, item can be delivered, case doesn't apply
false -> [{U, S, R}];
%% If in a suboptions ...
{_, {_, ShowValues}} ->
%% Get subscriber resources
Resources = case R of
%% If the subscriber JID is a bare one, get all its resources
[] -> user_resources(U, S);
%% If the subscriber JID is a full one, use its resource
R -> [R]
end,
%% For each resource, test if the item is allowed to be delivered
%% based on resource state
lists:foldl(
fun(Resource, Acc) ->
get_resource_state({U, S, Resource}, ShowValues, Acc)
end, [], Resources)
end.
get_resource_state({U, S, R}, ShowValues, JIDs) ->
%% Get user session PID
case ejabberd_sm:get_session_pid(U, S, R) of
%% If no PID, item can be delivered
none -> lists:append([{U, S, R}], JIDs);
%% If PID ...
Pid ->
%% Get user resource state
%% TODO : add a catch clause
Show = case ejabberd_c2s:get_presence(Pid) of
{_, _, "available", _} -> "online";
{_, _, State, _} -> State
end,
%% Is current resource state listed in 'show-values' suboption ?
case lists:member(Show, ShowValues) of %andalso Show =/= "online" of
%% If yes, item can be delivered
true -> lists:append([{U, S, R}], JIDs);
%% If no, item can't be delivered
false -> JIDs
end
%% If no PID, item can be delivered
none -> lists:append([{U, S, R}], JIDs);
%% If PID ...
Pid ->
%% Get user resource state
%% TODO : add a catch clause
Show = case ejabberd_c2s:get_presence(Pid) of
{_, _, "available", _} -> "online";
{_, _, State, _} -> State
end,
%% Is current resource state listed in 'show-values' suboption ?
case lists:member(Show, ShowValues) of %andalso Show =/= "online" of
%% If yes, item can be delivered
true -> lists:append([{U, S, R}], JIDs);
%% If no, item can't be delivered
false -> JIDs
end
end.
%% @spec (Payload) -> int()
@ -2804,223 +2798,149 @@ event_stanza_withmoreels(Els, MoreEls) ->
{xmlelement, "message", [],
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], Els} | MoreEls]}.
event_stanza(Event, EvAttr) ->
event_stanza([{xmlelement, Event, EvAttr, []}]).
event_stanza(Event, EvAttr, Entries) ->
event_stanza([{xmlelement, Event, EvAttr,
[{xmlelement, Entry, EnAttr, []} || {Entry, EnAttr} <- Entries]}]).
event_stanza(Event, EvAttr, Entry, EnAttr, Payload) ->
event_stanza([{xmlelement, Event, EvAttr, [{xmlelement, Entry, EnAttr, Payload}]}]).
event_stanza(Event, EvAttr, Entry, EnAttr, Payload, Publisher) ->
Stanza = event_stanza(Event, EvAttr, Entry, EnAttr, Payload),
add_extended_headers(Stanza, extended_headers([jlib:jid_to_string(Publisher)])).
%%%%%% broadcast functions
broadcast_publish_item(Host, Node, NodeId, Type, NodeOptions, Removed, ItemId, From, Payload) ->
case get_collection_subscriptions(Host, Node) of
SubsByDepth when is_list(SubsByDepth) ->
Content = case get_option(NodeOptions, deliver_payloads) of
true -> Payload;
false -> []
end,
Stanza = event_stanza(
[{xmlelement, "items", nodeAttr(Node),
[{xmlelement, "item", itemAttr(ItemId), Content}]}]),
broadcast_stanza(Host, From, Node, NodeId, Type,
NodeOptions, SubsByDepth, items, Stanza, true),
case Removed of
[] ->
ok;
_ ->
case get_option(NodeOptions, notify_retract) of
true ->
RetractStanza = event_stanza(
[{xmlelement, "items", nodeAttr(Node),
[{xmlelement, "retract", itemAttr(RId), []} || RId <- Removed]}]),
broadcast_stanza(Host, Node, NodeId, Type,
NodeOptions, SubsByDepth,
items, RetractStanza, true);
_ ->
ok
end
end,
{result, true};
broadcast_publish_item(Host, Node, NodeId, Type, NodeOptions, ItemId, Publisher, Payload, Removed) ->
Publish = case get_option(NodeOptions, deliver_payloads) of
true -> event_stanza("items", nodeAttr(Node), "item", itemAttr(ItemId), Payload, Publisher);
false -> event_stanza("items", nodeAttr(Node), "item", itemAttr(ItemId), [], Publisher)
end,
case Removed of
[] ->
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, items, true, Publish, true)};
_ ->
{result, false}
Retract = event_stanza("items", nodeAttr(Node), [{"retract", itemAttr(Rid)} || Rid <- Removed]),
Stanzas = [{true, Publish, true}, {get_option(NodeOptions, notify_retract), Retract, true}],
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, items, Stanzas)}
end.
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds) ->
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, false).
broadcast_retract_items(_Host, _Node, _NodeId, _Type, _NodeOptions, [], _ForceNotify) ->
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, notify_retract).
broadcast_retract_items(_Host, _Node, _NodeId, _Type, _NodeOptions, [], _) ->
{result, false};
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, ForceNotify) ->
case (get_option(NodeOptions, notify_retract) or ForceNotify) of
true ->
case get_collection_subscriptions(Host, Node) of
SubsByDepth when is_list(SubsByDepth) ->
Stanza = event_stanza(
[{xmlelement, "items", nodeAttr(Node),
[{xmlelement, "retract", itemAttr(ItemId), []} || ItemId <- ItemIds]}]),
broadcast_stanza(Host, Node, NodeId, Type,
NodeOptions, SubsByDepth, items, Stanza, true),
{result, true};
_ ->
{result, false}
end;
_ ->
{result, false}
end.
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, false) ->
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, notify_retract);
broadcast_retract_items(Host, Node, NodeId, Type, NodeOptions, ItemIds, Notify) ->
Stanza = event_stanza("items", nodeAttr(Node), [{"retract", itemAttr(Rid)} || Rid <- ItemIds]),
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, items, Notify, Stanza, true)}.
broadcast_purge_node(Host, Node, NodeId, Type, NodeOptions) ->
case get_option(NodeOptions, notify_retract) of
true ->
case get_collection_subscriptions(Host, Node) of
SubsByDepth when is_list(SubsByDepth) ->
Stanza = event_stanza(
[{xmlelement, "purge", nodeAttr(Node),
[]}]),
broadcast_stanza(Host, Node, NodeId, Type,
NodeOptions, SubsByDepth, nodes, Stanza, false),
{result, true};
_ ->
{result, false}
end;
_ ->
{result, false}
end.
Stanza = event_stanza("purge", nodeAttr(Node)),
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, nodes, notify_retract, Stanza, false)}.
broadcast_removed_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth) ->
case get_option(NodeOptions, notify_delete) of
true ->
case SubsByDepth of
[] ->
{result, false};
_ ->
Stanza = event_stanza(
[{xmlelement, "delete", nodeAttr(Node),
[]}]),
broadcast_stanza(Host, Node, NodeId, Type,
NodeOptions, SubsByDepth, nodes, Stanza, false),
{result, true}
end;
_ ->
{result, false}
end.
broadcast_removed_node(Host, Node, NodeId, Type, NodeOptions) ->
Stanza = event_stanza("delete", nodeAttr(Node)),
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, nodes, notify_delete, Stanza, false)}.
broadcast_created_node(_, _, _, _, _, []) ->
{result, false};
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth) ->
Stanza = event_stanza([{xmlelement, "create", nodeAttr(Node), []}]),
broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, nodes, Stanza, true),
{result, true}.
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions) ->
Stanza = event_stanza("create", nodeAttr(Node)),
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, nodes, true, Stanza, true)}.
broadcast_config_notification(Host, Node, NodeId, Type, NodeOptions, Lang) ->
case get_option(NodeOptions, notify_config) of
Stanza = case get_option(NodeOptions, deliver_payloads) of
true ->
case get_collection_subscriptions(Host, Node) of
SubsByDepth when is_list(SubsByDepth) ->
Content = case get_option(NodeOptions, deliver_payloads) of
true ->
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}],
get_configure_xfields(Type, NodeOptions, Lang, [])}];
false ->
[]
end,
Stanza = event_stanza(
[{xmlelement, "configuration", nodeAttr(Node), Content}]),
broadcast_stanza(Host, Node, NodeId, Type,
NodeOptions, SubsByDepth, nodes, Stanza, false),
{result, true};
_ ->
{result, false}
end;
_ ->
{result, false}
end.
get_collection_subscriptions(Host, Node) ->
Action = fun() ->
{result, lists:map(fun({Depth, Nodes}) ->
{Depth, [{N, get_node_subs(N)} || N <- Nodes]}
end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))}
event_stanza("configuration", nodeAttr(Node),
"x", [{"xmlns", ?NS_XDATA}, {"type", "result"}],
get_configure_xfields(Type, NodeOptions, Lang, []));
false ->
event_stanza("configuration", nodeAttr(Node))
end,
case transaction(Host, Action, sync_dirty) of
{result, CollSubs} -> CollSubs;
_ -> []
end.
{result, broadcast(Host, Node, NodeId, Type, NodeOptions, nodes, notify_config, Stanza, false)}.
get_node_subs(#pubsub_node{type = Type,
id = NodeID}) ->
case node_call(Type, get_node_subscriptions, [NodeID]) of
{result, Subs} -> get_options_for_subs(NodeID, Subs);
Other -> Other
end.
broadcast(Host, Node, NodeId, Type, NodeOptions, Notify, Stanzas) ->
Subs = node_subscriptions(Host, Node, NodeId, Type, NodeOptions, Notify),
Result = [broadcast(Host, Node, NodeId, Type, NodeOptions, Subs, Stanza, SHIM) ||
{Cond, Stanza, SHIM} <- Stanzas, Cond =:= true],
lists:member(true, Result).
broadcast(Host, Node, NodeId, Type, NodeOptions, Notify, true, Stanza, SHIM) ->
Subs = node_subscriptions(Host, Node, NodeId, Type, NodeOptions, Notify),
broadcast(Host, Node, NodeId, Type, NodeOptions, Subs, Stanza, SHIM);
broadcast(_Host, _Node, _NodeId, _Type, _NodeOptions, _Notify, false, _Stanza, _SHIM) ->
false;
broadcast(Host, Node, NodeId, Type, NodeOptions, Notify, Condition, Stanza, SHIM) ->
broadcast(Host, Node, NodeId, Type, NodeOptions, Notify, get_option(NodeOptions, Condition), Stanza, SHIM).
get_options_for_subs(NodeID, Subs) ->
lists:foldl(fun({JID, subscribed, SubID}, Acc) ->
case pubsub_subscription_odbc:get_subscription(JID, NodeID, SubID) of
{error, notfound} -> [{JID, SubID, []} | Acc];
{result, #pubsub_subscription{options = Options}} -> [{JID, SubID, Options} | Acc];
_ -> Acc
end;
(_, Acc) ->
Acc
end, [], Subs).
broadcast_stanza(Host, _Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) ->
NotificationType = get_option(NodeOptions, notification_type, headline),
BroadcastAll = get_option(NodeOptions, broadcast_all_resources), %% XXX this is not standard, but usefull
From = service_jid(Host),
Stanza = case NotificationType of
normal -> BaseStanza;
MsgType -> add_message_type(BaseStanza, atom_to_list(MsgType))
end,
%% Handles explicit subscriptions
SubIDsByJID = subscribed_nodes_by_jid(NotifyType, SubsByDepth),
lists:foreach(fun ({LJID, NodeName, SubIDs}) ->
LJIDs = case BroadcastAll of
true ->
{U, S, _} = LJID,
[{U, S, R} || R <- user_resources(U, S)];
false ->
[LJID]
end,
%% Determine if the stanza should have SHIM ('SubID' and 'name') headers
StanzaToSend = case {SHIM, SubIDs} of
{false, _} ->
Stanza;
%% If there's only one SubID, don't add it
{true, [_]} ->
add_shim_headers(Stanza, collection_shim(NodeName));
{true, SubIDs} ->
add_shim_headers(Stanza, lists:append(collection_shim(NodeName), subid_shim(SubIDs)))
end,
lists:foreach(fun(To) ->
ejabberd_router:route(From, jlib:make_jid(To), StanzaToSend)
end, LJIDs)
end, SubIDsByJID).
broadcast_stanza({LUser, LServer, LResource}, Publisher, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) ->
broadcast_stanza({LUser, LServer, LResource}, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM),
%% Handles implicit presence subscriptions
SenderResource = case LResource of
[] ->
case user_resources(LUser, LServer) of
[Resource|_] -> Resource;
_ -> ""
end;
_ ->
LResource
end,
case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of
broadcast({U, S, R}, Node, NodeId, Type, NodeOptions, Subscriptions, Stanza, SHIM) ->
broadcast(S, Node, NodeId, Type, NodeOptions, Subscriptions, Stanza, SHIM)
or case ejabberd_sm:get_session_pid(U, S, user_resource(U, S, R)) of
C2SPid when is_pid(C2SPid) ->
Stanza = case get_option(NodeOptions, notification_type, headline) of
normal -> BaseStanza;
MsgType -> add_message_type(BaseStanza, atom_to_list(MsgType))
end,
%% set the from address on the notification to the bare JID of the account owner
%% Also, add "replyto" if entity has presence subscription to the account owner
%% See XEP-0163 1.1 section 4.3.1
ejabberd_c2s:broadcast(C2SPid,
{pep_message, binary_to_list(Node)++"+notify"},
_Sender = jlib:make_jid(LUser, LServer, ""),
_StanzaToSend = add_extended_headers(Stanza,
_ReplyTo = extended_headers([jlib:jid_to_string(Publisher)])));
Event = {pep_message, binary_to_list(Node)++"+notify"},
Message = case get_option(NodeOptions, notification_type, headline) of
normal -> Stanza;
MsgType -> add_message_type(Stanza, atom_to_list(MsgType))
end,
ejabberd_c2s:broadcast(C2SPid, Event, jlib:make_jid(U, S, ""), Message),
true;
_ ->
?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, BaseStanza])
?DEBUG("~p@~p has no session; can't deliver stanza: ~p", [U, S, Stanza]),
false
end;
broadcast_stanza(Host, _Publisher, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) ->
broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM).
broadcast(_Host, _Node, _NodeId, _Type, _NodeOptions, [], _Stanza, _SHIM) ->
false;
broadcast(Host, _Node, _NodeId, _Type, NodeOptions, Subscriptions, Stanza, SHIM) ->
From = service_jid(Host),
Message = case get_option(NodeOptions, notification_type, headline) of
normal -> Stanza;
MsgType -> add_message_type(Stanza, atom_to_list(MsgType))
end,
lists:foreach(fun({LJID, NodeName, SubIds}) ->
Send = case {SHIM, SubIds} of
{false, _} -> Message;
{true, [_]} -> add_shim_headers(Message, collection_shim(NodeName));
{true, _} -> add_shim_headers(Message, lists:append(collection_shim(NodeName), subid_shim(SubIds)))
end,
ejabberd_router:route(From, jlib:make_jid(LJID), Send)
end, Subscriptions),
true.
node_subscriptions(Host, Node, NodeId, Type, _NodeOptions, Notify) ->
% TODO temporary dirty condition, should be improved using plugin or node options
case Type of
"flat" -> node_subscriptions_bare(Host, Node, NodeId, Type);
"pep" -> node_subscriptions_bare(Host, Node, NodeId, Type);
_ -> node_subscriptions_full(Host, Node, Notify)
end.
node_subscriptions_bare(Host, Node, NodeId, Type) ->
case node_action(Host, Type, get_node_subscriptions, [NodeId]) of
{result, Subs} ->
SubsByJid = lists:foldl(
fun({JID, subscribed, SubId}, Acc) ->
case dict:is_key(JID, Acc) of
true -> dict:append(JID, SubId, Acc);
false -> dict:store(JID, [SubId], Acc)
end;
(_, Acc) ->
Acc
end, dict:new(), Subs),
[{J, Node, S} || {J, S} <- dict:to_list(SubsByJid)];
_ ->
[]
end.
node_subscriptions_full(Host, Node, NotifyType) ->
Action = fun() ->
Collection = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]),
{result, [{Depth, [{N, sub_with_options(N)} || N <- Nodes]} || {Depth, Nodes} <- Collection]}
end,
case transaction(Host, Action, sync_dirty) of
{result, CollSubs} -> subscribed_nodes_by_jid(NotifyType, CollSubs);
_ -> []
end.
subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
NodesToDeliver = fun(Depth, Node, Subs, Acc) ->
@ -3031,7 +2951,7 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
NodeOptions = Node#pubsub_node.options,
lists:foldl(fun({LJID, SubID, SubOptions}, {JIDs, Recipients}) ->
case is_to_deliver(LJID, NotifyType, Depth, NodeOptions, SubOptions) of
true ->
true ->
%% If is to deliver :
case state_can_deliver(LJID, SubOptions) of
[] -> {JIDs, Recipients};
@ -3040,13 +2960,13 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
fun(JIDToDeliver, {JIDsAcc, RecipientsAcc}) ->
case lists:member(JIDToDeliver, JIDs) of
%% check if the JIDs co-accumulator contains the Subscription Jid,
false ->
false ->
%% - if not,
%% - add the Jid to JIDs list co-accumulator ;
%% - create a tuple of the Jid, NodeId, and SubID (as list),
%% and add the tuple to the Recipients list co-accumulator
{[JIDToDeliver | JIDsAcc], [{JIDToDeliver, NodeName, [SubID]} | RecipientsAcc]};
true ->
true ->
%% - if the JIDs co-accumulator contains the Jid
%% get the tuple containing the Jid from the Recipient list co-accumulator
{_, {JIDToDeliver, NodeName1, SubIDs}} = lists:keysearch(JIDToDeliver, 1, RecipientsAcc),
@ -3075,9 +2995,33 @@ subscribed_nodes_by_jid(NotifyType, SubsByDepth) ->
{_, JIDSubs} = lists:foldl(DepthsToDeliver, {[], []}, SubsByDepth),
JIDSubs.
sub_with_options(#pubsub_node{type = Type, id = NodeId}) ->
case node_call(Type, get_node_subscriptions, [NodeId]) of
{result, Subs} ->
lists:foldl(
fun({JID, subscribed, SubId}, Acc) -> [sub_with_options(JID, NodeId, SubId) | Acc];
(_, Acc) -> Acc
end, [], Subs);
_ ->
[]
end.
sub_with_options(JID, NodeId, SubId) ->
case pubsub_subscription_odbc:get_subscription(JID, NodeId, SubId) of
{result, #pubsub_subscription{options = Options}} -> {JID, SubId, Options};
_ -> {JID, SubId, []}
end.
user_resources(User, Server) ->
ejabberd_sm:get_user_resources(User, Server).
user_resource(User, Server, []) ->
case user_resources(User, Server) of
[R|_] -> R;
_ -> []
end;
user_resource(_, _, Resource) ->
Resource.
%%%%%%% Configuration handling
%%<p>There are several reasons why the default node configuration options request might fail:</p>
@ -3736,7 +3680,7 @@ extended_headers(Jids) ->
on_user_offline(_, JID, _) ->
{User, Server, Resource} = jlib:jid_tolower(JID),
case ejabberd_sm:get_user_resources(User, Server) of
case user_resources(User, Server) of
[] -> purge_offline({User, Server, Resource});
_ -> true
end.

View File

@ -1,5 +1,5 @@
--- mod_pubsub.erl 2010-12-07 13:54:26.000000000 +0100
+++ mod_pubsub_odbc.erl 2010-12-07 13:59:56.000000000 +0100
--- mod_pubsub.erl 2011-02-08 16:50:27.000000000 +0100
+++ mod_pubsub_odbc.erl 2011-02-08 18:27:16.000000000 +0100
@@ -42,7 +42,7 @@
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
%%% XEP-0060 section 12.18.
@ -496,16 +496,16 @@
{result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]),
if
not IsApprover ->
@@ -1780,7 +1595,7 @@
@@ -1778,7 +1593,7 @@
Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "create", nodeAttr(Node),
[]}]}],
- case transaction(CreateNode, transaction) of
+ case transaction(Host, CreateNode, transaction) of
{result, {NodeId, SubsByDepth, {Result, broadcast}}} ->
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions, SubsByDepth),
{result, {NodeId, {Result, broadcast}}} ->
broadcast_created_node(Host, Node, NodeId, Type, NodeOptions),
case Result of
@@ -1883,7 +1698,7 @@
@@ -1879,7 +1694,7 @@
%%<li>The node does not exist.</li>
%%</ul>
subscribe_node(Host, Node, From, JID, Configuration) ->
@ -514,7 +514,7 @@
{result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid
end,
@@ -1891,7 +1706,7 @@
@@ -1887,7 +1702,7 @@
error -> {"", "", ""};
J -> jlib:jid_tolower(J)
end,
@ -523,7 +523,7 @@
Features = features(Type),
SubscribeFeature = lists:member("subscribe", Features),
OptionsFeature = lists:member("subscription-options", Features),
@@ -1900,6 +1715,7 @@
@@ -1896,6 +1711,7 @@
AccessModel = get_option(Options, access_model),
SendLast = get_option(Options, send_last_published_item),
AllowedGroups = get_option(Options, roster_groups_allowed, []),
@ -531,7 +531,7 @@
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, Subscriber, Owners, AccessModel, AllowedGroups),
if
not SubscribeFeature ->
@@ -2231,7 +2047,7 @@
@@ -2226,7 +2042,7 @@
%% <p>The permission are not checked in this function.</p>
%% @todo We probably need to check that the user doing the query has the right
%% to read the items.
@ -540,7 +540,7 @@
MaxItems =
if
SMaxItems == "" -> get_max_items_node(Host);
@@ -2245,12 +2061,13 @@
@@ -2240,12 +2056,13 @@
{error, Error} ->
{error, Error};
_ ->
@ -555,7 +555,7 @@
{PresenceSubscription, RosterGroup} = get_presence_and_roster_permissions(Host, From, Owners, AccessModel, AllowedGroups),
if
not RetreiveFeature ->
@@ -2263,11 +2080,11 @@
@@ -2258,11 +2075,11 @@
node_call(Type, get_items,
[NodeId, From,
AccessModel, PresenceSubscription, RosterGroup,
@ -569,7 +569,7 @@
SendItems = case ItemIDs of
[] ->
Items;
@@ -2280,7 +2097,8 @@
@@ -2275,7 +2092,8 @@
%% number of items sent to MaxItems:
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "items", nodeAttr(Node),
@ -579,7 +579,7 @@
Error ->
Error
end
@@ -2302,10 +2120,15 @@
@@ -2297,10 +2115,15 @@
Error -> Error
end.
get_allowed_items_call(Host, NodeIdx, From, Type, Options, Owners) ->
@ -596,7 +596,7 @@
%% @spec (Host, Node, NodeId, Type, LJID, Number) -> any()
@@ -2318,16 +2141,27 @@
@@ -2313,16 +2136,27 @@
%% @doc <p>Resend the items of a node to the user.</p>
%% @todo use cache-last-item feature
send_items(Host, Node, NodeId, Type, LJID, last) ->
@ -630,7 +630,7 @@
send_items(Host, Node, NodeId, Type, LJID, Number) ->
ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
{result, []} ->
@@ -2453,7 +2287,8 @@
@@ -2448,7 +2282,8 @@
error ->
{error, ?ERR_BAD_REQUEST};
_ ->
@ -640,7 +640,7 @@
case lists:member(Owner, Owners) of
true ->
OwnerJID = jlib:make_jid(Owner),
@@ -2463,24 +2298,7 @@
@@ -2458,24 +2293,7 @@
end,
lists:foreach(
fun({JID, Affiliation}) ->
@ -666,7 +666,7 @@
end, FilteredEntities),
{result, []};
_ ->
@@ -2533,11 +2351,11 @@
@@ -2528,11 +2346,11 @@
end.
read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
@ -680,7 +680,7 @@
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
{"subid", SubID}|nodeAttr(Node)],
[XdataEl]},
@@ -2563,7 +2381,7 @@
@@ -2558,7 +2376,7 @@
end.
set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
@ -689,7 +689,7 @@
{result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid
end,
@@ -2592,7 +2410,7 @@
@@ -2587,7 +2405,7 @@
write_sub(_Subscriber, _NodeID, _SubID, invalid) ->
{error, extended_error(?ERR_BAD_REQUEST, "invalid-options")};
write_sub(Subscriber, NodeID, SubID, Options) ->
@ -698,7 +698,7 @@
{error, notfound} ->
{error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
{result, _} ->
@@ -2760,8 +2578,8 @@
@@ -2755,8 +2573,8 @@
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
end,
@ -709,28 +709,27 @@
true ->
Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) ->
@@ -3116,7 +2934,7 @@
{Depth, [{N, get_node_subs(N)} || N <- Nodes]}
end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))}
@@ -3119,7 +2937,7 @@
Collection = tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]),
{result, [{Depth, [{N, sub_with_options(N)} || N <- Nodes]} || {Depth, Nodes} <- Collection]}
end,
- case transaction(Action, sync_dirty) of
+ case transaction(Host, Action, sync_dirty) of
{result, CollSubs} -> CollSubs;
{result, CollSubs} -> subscribed_nodes_by_jid(NotifyType, CollSubs);
_ -> []
end.
@@ -3130,9 +2948,9 @@
@@ -3188,8 +3006,8 @@
[]
end.
sub_with_options(JID, NodeId, SubId) ->
- case pubsub_subscription:read_subscription(JID, NodeId, SubId) of
- #pubsub_subscription{options = Options} -> {JID, SubId, Options};
+ case pubsub_subscription_odbc:get_subscription(JID, NodeId, SubId) of
+ {result, #pubsub_subscription{options = Options}} -> {JID, SubId, Options};
_ -> {JID, SubId, []}
end.
get_options_for_subs(NodeID, Subs) ->
lists:foldl(fun({JID, subscribed, SubID}, Acc) ->
- case pubsub_subscription:read_subscription(JID, NodeID, SubID) of
+ case pubsub_subscription_odbc:get_subscription(JID, NodeID, SubID) of
{error, notfound} -> [{JID, SubID, []} | Acc];
- #pubsub_subscription{options = Options} -> [{JID, SubID, Options} | Acc];
+ {result, #pubsub_subscription{options = Options}} -> [{JID, SubID, Options} | Acc];
_ -> Acc
end;
(_, Acc) ->
@@ -3321,6 +3139,30 @@
@@ -3265,6 +3083,30 @@
Result
end.
@ -761,7 +760,7 @@
%% @spec (Host, Options) -> MaxItems
%% Host = host()
%% Options = [Option]
@@ -3717,7 +3559,13 @@
@@ -3661,7 +3503,13 @@
tree_action(Host, Function, Args) ->
?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]),
Fun = fun() -> tree_call(Host, Function, Args) end,
@ -776,7 +775,7 @@
%% @doc <p>node plugin call.</p>
node_call(Type, Function, Args) ->
@@ -3737,13 +3585,13 @@
@@ -3681,13 +3529,13 @@
node_action(Host, Type, Function, Args) ->
?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]),
@ -792,7 +791,7 @@
case tree_call(Host, get_node, [Host, Node]) of
N when is_record(N, pubsub_node) ->
case Action(N) of
@@ -3755,13 +3603,19 @@
@@ -3699,13 +3547,19 @@
Error
end
end, Trans).
@ -816,7 +815,7 @@
{result, Result} -> {result, Result};
{error, Error} -> {error, Error};
{atomic, {result, Result}} -> {result, Result};
@@ -3769,6 +3623,15 @@
@@ -3713,6 +3567,15 @@
{aborted, Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR};
@ -832,7 +831,7 @@
{'EXIT', Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR};
@@ -3777,6 +3640,17 @@
@@ -3721,6 +3584,17 @@
{error, ?ERR_INTERNAL_SERVER_ERROR}
end.