mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-26 16:26:24 +01:00
Better handling of presence hook and caps clean
SVN Revision: 2015
This commit is contained in:
parent
6b2a838e24
commit
08cbaf8ccf
@ -1,3 +1,12 @@
|
||||
2009-03-20 Christophe Romain <christophe.romain@process-one.net>
|
||||
|
||||
* src/mod_caps.erl: Better handling of presence hook and caps clean
|
||||
* src/ejabberd_c2s.erl: Likewise
|
||||
* src/mod_pubsub/mod_pubsub.erl: Likewise
|
||||
|
||||
* src/mod_pubsub/mod_pubsub.erl: Improve invalid-payload check, send
|
||||
last published item to new resource only, thread message sending.
|
||||
|
||||
2009-04-09 Badlop <badlop@process-one.net>
|
||||
|
||||
* src/msgs/pl.po: Fix some translations (thanks to Andrzej Smyk)
|
||||
|
@ -1062,18 +1062,6 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
||||
allow ->
|
||||
LFrom = jlib:short_prepd_jid(From),
|
||||
LBFrom = jlib:short_prepd_bare_jid(From),
|
||||
%% Note contact availability
|
||||
Els = Packet#xmlel.children,
|
||||
case exmpp_presence:get_type(Packet) of
|
||||
'unavailable' ->
|
||||
%mod_caps:clear_caps(From);
|
||||
% caps clear disabled cause it breaks things
|
||||
ok;
|
||||
_ ->
|
||||
ServerString = binary_to_list(StateData#state.server),
|
||||
Caps = mod_caps:read_caps(Els),
|
||||
mod_caps:note_caps(ServerString, From, Caps)
|
||||
end,
|
||||
case ?SETS:is_element(
|
||||
LFrom, StateData#state.pres_a) orelse
|
||||
?SETS:is_element(
|
||||
|
@ -53,6 +53,10 @@
|
||||
|
||||
-include_lib("exmpp/include/exmpp.hrl").
|
||||
|
||||
%% hook handlers
|
||||
-export([receive_packet/3,
|
||||
receive_packet/4]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
-define(PROCNAME, ejabberd_mod_caps).
|
||||
@ -157,6 +161,35 @@ stop(Host) ->
|
||||
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
||||
gen_server:call(Proc, stop).
|
||||
|
||||
receive_packet(From, To, Packet) when ?IS_PRESENCE(Packet) ->
|
||||
case exmpp_presence:get_type(Packet) of
|
||||
'probe' ->
|
||||
ok;
|
||||
'error' ->
|
||||
ok;
|
||||
'invisible' ->
|
||||
ok;
|
||||
'subscribe' ->
|
||||
ok;
|
||||
'subscribed' ->
|
||||
ok;
|
||||
'unsubscribe' ->
|
||||
ok;
|
||||
'unsubscribed' ->
|
||||
ok;
|
||||
'unavailable' ->
|
||||
clear_caps(From);
|
||||
_ ->
|
||||
ServerString = binary_to_list(StateData#state.server),
|
||||
Els = Packet#xmlel.children,
|
||||
note_caps(ServerString, From, read_caps(Els))
|
||||
end;
|
||||
receive_packet(_, _, _) ->
|
||||
ok.
|
||||
|
||||
receive_packet(_JID, From, To, Packet) ->
|
||||
receive_packet(From, To, Packet).
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
%%====================================================================
|
||||
@ -173,6 +206,10 @@ init([Host, _Opts]) ->
|
||||
{type, bag},
|
||||
{attributes, record_info(fields, user_caps_resources)}]),
|
||||
mnesia:delete_table(user_caps_default),
|
||||
mnesia:clear_table(user_caps),
|
||||
mnesia:clear_table(user_caps_resources),
|
||||
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, receive_packet, 30),
|
||||
ejabberd_hooks:add(s2s_receive_packet, Host, ?MODULE, receive_packet, 30),
|
||||
{ok, #state{host = Host}}.
|
||||
|
||||
maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) ->
|
||||
@ -349,7 +386,10 @@ handle_disco_response(From, To, IQ_Rec) ->
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
terminate(_Reason, State) ->
|
||||
Host = State#state.host,
|
||||
ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, receive_packet, 30),
|
||||
ejabberd_hooks:delete(s2s_receive_packet, Host, ?MODULE, receive_packet, 30),
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
|
@ -76,6 +76,8 @@
|
||||
unsubscribe_node/5,
|
||||
publish_item/6,
|
||||
delete_item/4,
|
||||
send_items/4,
|
||||
broadcast_stanza/6,
|
||||
get_configure/5,
|
||||
set_configure/5,
|
||||
get_items/3,
|
||||
@ -156,6 +158,7 @@ init([ServerHost, Opts]) ->
|
||||
?DEBUG("pubsub init ~p ~p",[ServerHost,Opts]),
|
||||
Host = gen_mod:get_opt_host(ServerHost, Opts, "pubsub.@HOST@"),
|
||||
Access = gen_mod:get_opt(access_createnode, Opts, all),
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
ServerHostB = list_to_binary(ServerHost),
|
||||
mod_disco:register_feature(ServerHost, ?NS_PUBSUB_s),
|
||||
ejabberd_hooks:add(disco_sm_identity, ServerHostB, ?MODULE, disco_sm_identity, 75),
|
||||
@ -164,28 +167,17 @@ init([ServerHost, Opts]) ->
|
||||
ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50),
|
||||
ejabberd_hooks:add(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50),
|
||||
ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50),
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
lists:foreach(
|
||||
fun({NS,Mod,Fun}) ->
|
||||
gen_iq_handler:add_iq_handler(
|
||||
Mod, ServerHostB, NS, ?MODULE, Fun, IQDisc)
|
||||
end,
|
||||
[{?NS_PUBSUB, ejabberd_sm, iq_sm},
|
||||
{?NS_PUBSUB_OWNER, ejabberd_sm, iq_sm}]),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_sm, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_sm, IQDisc),
|
||||
ejabberd_router:register_route(Host),
|
||||
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
|
||||
case lists:member("pep", Plugins) of
|
||||
case lists:member(?PEPNODE, Plugins) of
|
||||
true ->
|
||||
ejabberd_hooks:add(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
|
||||
ejabberd_hooks:add(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
|
||||
ejabberd_hooks:add(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
|
||||
lists:foreach(
|
||||
fun({NS,Mod,Fun}) ->
|
||||
gen_iq_handler:add_iq_handler(
|
||||
Mod, ServerHost, NS, ?MODULE, Fun, IQDisc)
|
||||
end,
|
||||
[{?NS_PUBSUB, ejabberd_local, iq_local},
|
||||
{?NS_PUBSUB_OWNER, ejabberd_local, iq_local}]);
|
||||
ejabberd_hooks:add(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75),
|
||||
ejabberd_hooks:add(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75),
|
||||
ejabberd_hooks:add(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB, ?MODULE, iq_local, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB_OWNER, ?MODULE, iq_local, IQDisc);
|
||||
false ->
|
||||
ok
|
||||
end,
|
||||
@ -494,63 +486,69 @@ handle_call(stop, _From, State) ->
|
||||
handle_cast({presence, JID}, State) ->
|
||||
%% A new resource is available. send last published items
|
||||
Host = State#state.host,
|
||||
LJID = jlib:short_prepd_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({Node, subscribed, SubJID}) ->
|
||||
case tree_action(Host, get_node, [Host, Node, JID]) of
|
||||
#pubsub_node{options = Options} ->
|
||||
case get_option(Options, send_last_published_item) of
|
||||
on_sub_and_presence ->
|
||||
send_last_item(Host, Node, SubJID);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
spawn(fun() ->
|
||||
lists:foreach(fun(Type) ->
|
||||
{result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]),
|
||||
lists:foreach(
|
||||
fun({Node, subscribed, _SubJID}) ->
|
||||
case tree_action(Host, get_node, [Host, Node, JID]) of
|
||||
#pubsub_node{options = Options} ->
|
||||
case get_option(Options, send_last_published_item) of
|
||||
on_sub_and_presence ->
|
||||
send_items(Host, Node, LJID, last);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
(_) ->
|
||||
ok
|
||||
end, Subscriptions)
|
||||
end, State#state.plugins),
|
||||
ok
|
||||
end, Subscriptions)
|
||||
end, State#state.plugins)
|
||||
end),
|
||||
{noreply, State};
|
||||
|
||||
handle_cast({presence, User, Server, Resources, JID}, State) ->
|
||||
%% A new resource is available. send last published PEP items
|
||||
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}) ->
|
||||
case get_option(Options, send_last_published_item) of
|
||||
on_sub_and_presence ->
|
||||
lists:foreach(fun(Resource) ->
|
||||
LJID = {User, Server, Resource},
|
||||
case is_caps_notify(ServerHost, Node, LJID) of
|
||||
true ->
|
||||
Subscribed = case get_option(Options, access_model) of
|
||||
open -> true;
|
||||
presence -> true;
|
||||
whitelist -> false; % subscribers are added manually
|
||||
authorize -> false; % likewise
|
||||
roster ->
|
||||
Grps = get_option(Options, roster_groups_allowed, []),
|
||||
{OU, OS, _} = Owner,
|
||||
element(2, get_roster_info(OU, OS, LJID, Grps))
|
||||
end,
|
||||
if Subscribed ->
|
||||
send_last_item(Owner, Node, LJID);
|
||||
spawn(fun() ->
|
||||
lists:foreach(fun(#pubsub_node{nodeid = {_, Node}, options = Options}) ->
|
||||
case get_option(Options, send_last_published_item) of
|
||||
on_sub_and_presence ->
|
||||
lists:foreach(fun(Resource) ->
|
||||
LJID = {User, Server, Resource},
|
||||
case is_caps_notify(ServerHost, Node, LJID) of
|
||||
true ->
|
||||
Subscribed = case get_option(Options, access_model) of
|
||||
open -> true;
|
||||
presence -> true;
|
||||
whitelist -> false; % subscribers are added manually
|
||||
authorize -> false; % likewise
|
||||
roster ->
|
||||
Grps = get_option(Options, roster_groups_allowed, []),
|
||||
{OU, OS, _} = Owner,
|
||||
element(2, get_roster_info(OU, OS, LJID, Grps))
|
||||
end,
|
||||
if Subscribed ->
|
||||
send_items(Owner, Node, LJID, last);
|
||||
true ->
|
||||
ok
|
||||
end;
|
||||
false ->
|
||||
ok
|
||||
end;
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end, Resources);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end, tree_action(ServerHost, get_nodes, [Owner, JID])),
|
||||
end
|
||||
end, Resources);
|
||||
_ ->
|
||||
ok
|
||||
end
|
||||
end, tree_action(ServerHost, get_nodes, [Owner, JID]))
|
||||
end),
|
||||
{noreply, State};
|
||||
|
||||
handle_cast({remove_user, LUser, LServer}, State) ->
|
||||
@ -611,6 +609,16 @@ terminate(_Reason, #state{host = Host,
|
||||
terminate_plugins(Host, ServerHost, Plugins, TreePlugin),
|
||||
ejabberd_router:unregister_route(Host),
|
||||
ServerHostB = list_to_binary(ServerHost),
|
||||
case lists:member(?PEPNODE, Plugins) of
|
||||
true ->
|
||||
ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75),
|
||||
ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75),
|
||||
ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ServerHostB, ?NS_PUBSUB_OWNER);
|
||||
false ->
|
||||
ok
|
||||
end,
|
||||
ejabberd_hooks:delete(disco_local_identity, ServerHostB, ?MODULE, disco_local_identity, 75),
|
||||
ejabberd_hooks:delete(disco_local_features, ServerHostB, ?MODULE, disco_local_features, 75),
|
||||
ejabberd_hooks:delete(disco_local_items, ServerHostB, ?MODULE, disco_local_items, 75),
|
||||
@ -620,12 +628,8 @@ terminate(_Reason, #state{host = Host,
|
||||
ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50),
|
||||
ejabberd_hooks:delete(roster_out_subscription, ServerHostB, ?MODULE, out_subscription, 50),
|
||||
ejabberd_hooks:delete(remove_user, ServerHostB, ?MODULE, remove_user, 50),
|
||||
lists:foreach(fun({NS,Mod}) ->
|
||||
gen_iq_handler:remove_iq_handler(Mod, ServerHostB, NS)
|
||||
end, [{?NS_PUBSUB, ejabberd_local},
|
||||
{?NS_PUBSUB_OWNER, ejabberd_local},
|
||||
{?NS_PUBSUB, ejabberd_sm},
|
||||
{?NS_PUBSUB_OWNER, ejabberd_sm}]),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, ServerHostB, ?NS_PUBSUB_OWNER),
|
||||
mod_disco:unregister_feature(ServerHost, ?NS_PUBSUB_s),
|
||||
ok.
|
||||
|
||||
@ -851,10 +855,7 @@ iq_disco_items(Host, Item, From) ->
|
||||
transaction(Host, Node, Action, sync_dirty)
|
||||
end.
|
||||
|
||||
iq_local(From, To, #iq{type = Type,
|
||||
payload = SubEl,
|
||||
ns = XMLNS,
|
||||
lang = Lang} = IQ_Rec) ->
|
||||
iq_local(From, To, #iq{type = Type, payload = SubEl, ns = XMLNS, lang = Lang} = IQ_Rec) ->
|
||||
ServerHost = exmpp_jid:ldomain_as_list(To),
|
||||
FromHost = exmpp_jid:ldomain_as_list(To),
|
||||
%% Accept IQs to server only from our own users.
|
||||
@ -1102,14 +1103,14 @@ find_authorization_response(Packet) ->
|
||||
%% @spec (Host, JID, Node, Subscription) -> void
|
||||
%% Host = mod_pubsub:host()
|
||||
%% JID = jlib:jid()
|
||||
%% Node = string()
|
||||
%% SNode = string()
|
||||
%% Subscription = atom()
|
||||
%% Plugins = [Plugin::string()]
|
||||
%% @doc Send a message to JID with the supplied Subscription
|
||||
send_authorization_approval(Host, JID, Node, Subscription) ->
|
||||
send_authorization_approval(Host, JID, SNode, Subscription) ->
|
||||
Stanza = event_stanza(
|
||||
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'subscription', attrs =
|
||||
[?XMLATTR('node', Node),
|
||||
[?XMLATTR('node', SNode),
|
||||
?XMLATTR('jid', exmpp_jid:jid_to_binary(JID)),
|
||||
?XMLATTR('subscription', subscription_to_string(Subscription))]}]),
|
||||
ejabberd_router ! {route, service_jid(Host), JID, Stanza}.
|
||||
@ -1462,7 +1463,7 @@ subscribe_node(Host, Node, From, JID) ->
|
||||
{error, Error} ->
|
||||
{error, Error};
|
||||
{result, {Result, subscribed, send_last}} ->
|
||||
send_last_item(Host, Node, Subscriber),
|
||||
send_items(Host, Node, Subscriber, last),
|
||||
case Result of
|
||||
default -> {result, Reply(subscribed)};
|
||||
_ -> {result, Result}
|
||||
@ -1552,12 +1553,12 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
||||
PayloadSize > PayloadMaxSize ->
|
||||
%% Entity attempts to publish very large payload
|
||||
{error, extended_error('not-acceptable', "payload-too-big")};
|
||||
PayloadCount == 0 ->
|
||||
%% Publisher attempts to publish to payload node with no payload
|
||||
{error, extended_error('bad-request', "payload-required")};
|
||||
PayloadCount > 1 ->
|
||||
%% Entity attempts to publish item with multiple payload elements
|
||||
{error, extended_error('bad-request', "invalid-payload")};
|
||||
Payload == "" ->
|
||||
%% Publisher attempts to publish to payload node with no payload
|
||||
{error, extended_error('bad-request', "payload-required")};
|
||||
(DeliverPayloads == 0) and (PersistItems == 0) and (PayloadSize > 0) ->
|
||||
%% Publisher attempts to publish to transient notification node with item
|
||||
{error, extended_error('bad-request', "item-forbidden")};
|
||||
@ -1773,18 +1774,9 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
|
||||
end,
|
||||
%% Generate the XML response (Item list), limiting the
|
||||
%% number of items sent to MaxItems:
|
||||
ItemsEls = lists:map(
|
||||
fun(#pubsub_item{itemid = {ItemId, _},
|
||||
payload = Payload}) ->
|
||||
ItemAttrs = case ItemId of
|
||||
"" -> [];
|
||||
_ -> [?XMLATTR('id', ItemId)]
|
||||
end,
|
||||
#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = ItemAttrs, children = Payload}
|
||||
end, lists:sublist(SendItems, MaxItems)),
|
||||
{result, [#xmlel{ns = ?NS_PUBSUB, name = 'pubsub', children =
|
||||
[#xmlel{ns = ?NS_PUBSUB, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
|
||||
ItemsEls}]}]}
|
||||
itemsEls(lists:sublist(SendItems, MaxItems))}]}]}
|
||||
end
|
||||
end.
|
||||
|
||||
@ -1794,14 +1786,6 @@ get_items(Host, Node, From) ->
|
||||
_ -> []
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node, LJID) -> any()
|
||||
%% Host = host()
|
||||
%% Node = pubsubNode()
|
||||
%% LJID = {U, S, []}
|
||||
%% @doc <p>Resend the last item of a node to the user.</p>
|
||||
send_last_item(Host, Node, LJID) ->
|
||||
send_items(Host, Node, LJID, last).
|
||||
|
||||
%% @spec (Host, Node, LJID, Number) -> any()
|
||||
%% Host = host()
|
||||
%% Node = pubsubNode()
|
||||
@ -1834,17 +1818,9 @@ send_items(Host, Node, {LU, LS, LR} = LJID, Number) ->
|
||||
Items
|
||||
end
|
||||
end,
|
||||
ItemsEls = lists:map(
|
||||
fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) ->
|
||||
ItemAttrs = case ItemId of
|
||||
"" -> [];
|
||||
_ -> [?XMLATTR('id', ItemId)]
|
||||
end,
|
||||
#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = ItemAttrs, children = Payload}
|
||||
end, ToSend),
|
||||
Stanza = event_stanza(
|
||||
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = [?XMLATTR('node', node_to_string(Node))], children =
|
||||
ItemsEls}]),
|
||||
itemsEls(ToSend)}]),
|
||||
ejabberd_router ! {route, service_jid(Host), exmpp_jid:make_jid(LU, LS, LR), Stanza}.
|
||||
|
||||
%% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response}
|
||||
@ -2229,6 +2205,7 @@ 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
|
||||
@ -2239,15 +2216,10 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) ->
|
||||
true -> Payload;
|
||||
false -> []
|
||||
end,
|
||||
ItemAttrs = case ItemId of
|
||||
"" -> [];
|
||||
_ -> [?XMLATTR('id', ItemId)]
|
||||
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 = ItemAttrs, children = Content}]}]),
|
||||
broadcast_stanza(Host, Options, States, Stanza),
|
||||
broadcast_by_caps(Host, Node, Type, Stanza),
|
||||
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]),
|
||||
broadcast_stanza(Host, Node, Type, Options, States, Stanza),
|
||||
{result, true};
|
||||
_ ->
|
||||
{result, false}
|
||||
@ -2258,6 +2230,7 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) ->
|
||||
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
|
||||
@ -2266,19 +2239,11 @@ broadcast_retract_items(Host, Node, ItemIds, ForceNotify) ->
|
||||
{result, []} ->
|
||||
{result, false};
|
||||
{result, States} ->
|
||||
RetractEls = lists:map(
|
||||
fun(ItemId) ->
|
||||
ItemAttrs = case ItemId of
|
||||
"" -> [];
|
||||
_ -> [?XMLATTR('id', ItemId)]
|
||||
end,
|
||||
#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'retract', attrs = ItemAttrs}
|
||||
end, ItemIds),
|
||||
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, Options, States, Stanza),
|
||||
broadcast_by_caps(Host, Node, Type, Stanza),
|
||||
broadcast_stanza(Host, Node, Type, Options, States, Stanza),
|
||||
{result, true};
|
||||
_ ->
|
||||
{result, false}
|
||||
@ -2290,6 +2255,7 @@ broadcast_retract_items(Host, Node, ItemIds, ForceNotify) ->
|
||||
transaction(Host, Node, Action, sync_dirty).
|
||||
|
||||
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
|
||||
@ -2300,8 +2266,7 @@ broadcast_purge_node(Host, Node) ->
|
||||
{result, States} ->
|
||||
Stanza = event_stanza(
|
||||
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'purge', attrs = [?XMLATTR('node', node_to_string(Node))]}]),
|
||||
broadcast_stanza(Host, Options, States, Stanza),
|
||||
broadcast_by_caps(Host, Node, Type, Stanza),
|
||||
broadcast_stanza(Host, Node, Type, Options, States, Stanza),
|
||||
{result, true};
|
||||
_ ->
|
||||
{result, false}
|
||||
@ -2313,6 +2278,7 @@ broadcast_purge_node(Host, Node) ->
|
||||
transaction(Host, Node, Action, sync_dirty).
|
||||
|
||||
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
|
||||
@ -2323,8 +2289,7 @@ broadcast_removed_node(Host, Node) ->
|
||||
{result, States} ->
|
||||
Stanza = event_stanza(
|
||||
[#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'delete', attrs = [?XMLATTR('node', node_to_string(Node))]}]),
|
||||
broadcast_stanza(Host, Options, States, Stanza),
|
||||
broadcast_by_caps(Host, Node, Type, Stanza),
|
||||
broadcast_stanza(Host, Node, Type, Options, States, Stanza),
|
||||
{result, true};
|
||||
_ ->
|
||||
{result, false}
|
||||
@ -2336,6 +2301,7 @@ broadcast_removed_node(Host, Node) ->
|
||||
transaction(Host, Node, Action, sync_dirty).
|
||||
|
||||
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
|
||||
@ -2355,8 +2321,7 @@ broadcast_config_notification(Host, Node, Lang) ->
|
||||
[#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, Options, States, Stanza),
|
||||
broadcast_by_caps(Host, Node, Type, Stanza),
|
||||
broadcast_stanza(Host, Node, Type, Options, States, Stanza),
|
||||
{result, true};
|
||||
_ ->
|
||||
{result, false}
|
||||
@ -2367,62 +2332,91 @@ broadcast_config_notification(Host, Node, Lang) ->
|
||||
end,
|
||||
transaction(Host, Node, Action, sync_dirty).
|
||||
|
||||
broadcast_stanza(Host, NodeOpts, States, Stanza) ->
|
||||
PresenceDelivery = get_option(NodeOpts, presence_based_delivery),
|
||||
BroadcastAll = get_option(NodeOpts, broadcast_all_resources), %% XXX this is not standard
|
||||
% 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_stanza(Host, Node, _Type, Options, States, 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
|
||||
true ->
|
||||
JIDs = case BroadcastAll of
|
||||
true -> ejabberd_sm:get_user_resources(element(1, LJID), element(2, LJID));
|
||||
false -> [LJID]
|
||||
{U, S, R} = case BroadcastAll of
|
||||
true -> jlib:short_prepd_bare_jid(LJID);
|
||||
false -> LJID
|
||||
end,
|
||||
lists:foreach(fun({U, S, R}) ->
|
||||
ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza}
|
||||
end, JIDs);
|
||||
ejabberd_router ! {route, From, exmpp_jlib:make_jid(U, S, R), Stanza};
|
||||
false ->
|
||||
ok
|
||||
end
|
||||
end, States).
|
||||
|
||||
%% broadcast Stanza to all contacts of the user that are advertising
|
||||
%% interest in this kind of Node.
|
||||
broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) ->
|
||||
SenderResource = case LResource of
|
||||
[] -> hd(user_resources(LUser, LServer));
|
||||
_ -> LResource
|
||||
end,
|
||||
case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of
|
||||
C2SPid when is_pid(C2SPid) ->
|
||||
%% 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
|
||||
Sender = exmpp_jid:make_jid(LUser, LServer),
|
||||
%%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used
|
||||
case catch ejabberd_c2s:get_subscribed(C2SPid) of
|
||||
Contacts when is_list(Contacts) ->
|
||||
lists:foreach(fun({U, S, _}) ->
|
||||
Resources = lists:foldl(fun(R, Acc) ->
|
||||
case is_caps_notify(LServer, Node, {U, S, R}) of
|
||||
true -> [R | Acc];
|
||||
false -> Acc
|
||||
end
|
||||
end, [], user_resources(U, S)),
|
||||
lists:foreach(fun(R) ->
|
||||
ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza}
|
||||
end, Resources)
|
||||
end, Contacts);
|
||||
end, States),
|
||||
%% Handles implicit presence subscriptions
|
||||
case Host of
|
||||
{LUser, LServer, LResource} ->
|
||||
SenderResource = case LResource of
|
||||
[] ->
|
||||
case user_resources(LUser, LServer) of
|
||||
[Resource|_] -> Resource;
|
||||
_ -> ""
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
LResource
|
||||
end,
|
||||
ok;
|
||||
case ejabberd_sm:get_session_pid(LUser, LServer, SenderResource) of
|
||||
C2SPid when is_pid(C2SPid) ->
|
||||
%% 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
|
||||
Sender = exmpp_jid:make_jid(LUser, LServer),
|
||||
%%ReplyTo = jlib:make_jid(LUser, LServer, SenderResource), % This has to be used
|
||||
case catch ejabberd_c2s:get_subscribed(C2SPid) of
|
||||
Contacts when is_list(Contacts) ->
|
||||
lists:foreach(fun({U, S, _}) ->
|
||||
spawn(fun() ->
|
||||
Rs = lists:foldl(fun(R, Acc) ->
|
||||
case is_caps_notify(LServer, Node, {U, S, R}) of
|
||||
true -> [R | Acc];
|
||||
false -> Acc
|
||||
end
|
||||
end, [], user_resources(U, S)),
|
||||
lists:foreach(fun(R) ->
|
||||
ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza}
|
||||
end, Rs)
|
||||
end)
|
||||
end, Contacts);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
ok;
|
||||
_ ->
|
||||
?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]),
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]),
|
||||
ok
|
||||
end;
|
||||
broadcast_by_caps(_, _, _, _) ->
|
||||
ok.
|
||||
end.
|
||||
|
||||
%% If we don't know the resource, just pick first if any
|
||||
%% If no resource available, check if caps anyway (remote online)
|
||||
@ -2877,3 +2871,16 @@ uniqid() ->
|
||||
{T1, T2, T3} = now(),
|
||||
lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])).
|
||||
|
||||
% node attributes
|
||||
nodeAttr(Node) -> %% TODO: to be used
|
||||
[?XMLATTR('node', node_to_string(Node))].
|
||||
|
||||
% item attributes
|
||||
itemAttr([]) -> [];
|
||||
itemAttr(ItemId) -> [?XMLATTR('id', ItemId)].
|
||||
|
||||
% build item elements from item list
|
||||
itemsEls(Items) ->
|
||||
lists:map(fun(#pubsub_item{itemid = {ItemId, _}, payload = Payload}) ->
|
||||
#xmlel{ns = ?NS_PUBSUB, name = 'item', attrs = itemAttr(ItemId), children = Payload}
|
||||
end, Items).
|
||||
|
@ -16,7 +16,7 @@
|
||||
%%% This software is copyright 2006-2009, ProcessOne.
|
||||
%%%
|
||||
%%% @copyright 2006-2009 ProcessOne
|
||||
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||
%%% @author Christophe Romain <christophe.romain@process-one.net>
|
||||
%%% [http://www.process-one.net/]
|
||||
%%% @version {@vsn}, {@date} {@time}
|
||||
%%% @end
|
||||
@ -82,7 +82,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}].
|
||||
|
||||
@ -168,7 +168,7 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId
|
||||
|
||||
get_item(Host, Node, ItemId) ->
|
||||
node_default:get_item(Host, Node, ItemId).
|
||||
|
||||
|
||||
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user