pubsub notification broadcast bugfix

SVN Revision: 1065
This commit is contained in:
Christophe Romain 2007-12-11 16:19:17 +00:00
parent 4ac9c8dfc5
commit f3322710c0
4 changed files with 169 additions and 168 deletions

View File

@ -1,3 +1,9 @@
2007-12-11 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: notification broadcast bugfix
* src/jlib.hrl: add pubsub namespace
2007-12-11 Badlop <badlop@process-one.net>
* src/msgs/tr.msg: New translation (thanks to Doruk Fisek)
@ -15,8 +21,8 @@
2007-12-10 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: database upgrade bugfix
* src/mod_pubsub/mod_pubsub.erl: auto-create pep node bugfix
* src/mod_pubsub/mod_pubsub.erl: database upgrade and auto-create
pep node bugfix
2007-12-09 Mickael Remond <mremond@process-one.net>

View File

@ -34,6 +34,8 @@
-define(NS_PUBSUB_OWNER, "http://jabber.org/protocol/pubsub#owner").
-define(NS_PUBSUB_NMI, "http://jabber.org/protocol/pubsub#node-meta-info").
-define(NS_PUBSUB_ERRORS,"http://jabber.org/protocol/pubsub#errors").
-define(NS_PUBSUB_NODE_CONFIG, "http://jabber.org/protocol/pubsub#node_config").
-define(NS_PUBSUB_SUB_AUTH, "http://jabber.org/protocol/pubsub#subscribe_authorization").
-define(NS_COMMANDS, "http://jabber.org/protocol/commands").
-define(NS_BYTESTREAMS, "http://jabber.org/protocol/bytestreams").
-define(NS_ADMIN, "http://jabber.org/protocol/admin").

View File

@ -44,6 +44,8 @@
unset_presence/4,
incoming_presence/3,
disco_local_identity/5,
disco_local_features/5,
disco_local_items/5,
disco_sm_identity/5,
disco_sm_features/5,
disco_sm_items/5
@ -143,16 +145,13 @@ init([ServerHost, Opts]) ->
[{disc_copies, [node()]},
{attributes, record_info(fields, pubsub_presence)}]),
mod_disco:register_feature(ServerHost, ?NS_PUBSUB),
ejabberd_hooks:add(disco_local_identity, ServerHost,
?MODULE, disco_local_identity, 75),
ejabberd_hooks:add(disco_sm_identity, ServerHost,
?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost,
?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHost,
?MODULE, disco_sm_items, 75),
ejabberd_hooks:add(incoming_presence_hook, ServerHost,
?MODULE, incoming_presence, 50),
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),
ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
ejabberd_hooks:add(incoming_presence_hook, ServerHost, ?MODULE, incoming_presence, 50),
%%ejabberd_hooks:add(set_presence_hook, ServerHost, ?MODULE, set_presence, 50),
%%ejabberd_hooks:add(unset_presence_hook, ServerHost, ?MODULE, unset_presence, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
@ -291,7 +290,7 @@ update_database(Host) ->
end.
%% -------
%% hooks handling functions
%% disco hooks handling functions
%%
disco_local_identity(Acc, _From, _To, [], _Lang) ->
@ -299,6 +298,21 @@ disco_local_identity(Acc, _From, _To, [], _Lang) ->
disco_local_identity(Acc, _From, _To, _Node, _Lang) ->
Acc.
disco_local_features(Acc, _From, To, Node, _Lang) ->
Host = To#jid.lserver,
Feats = case Acc of
{result, I} -> I;
_ -> []
end,
{result, Feats ++ lists:map(fun(Feature) ->
?NS_PUBSUB++"#"++Feature
end, features(Host, Node))}.
disco_local_items(Acc, _From, _To, [], _Lang) ->
Acc;
disco_local_items(Acc, _From, _To, _Node, _Lang) ->
Acc.
disco_sm_identity(Acc, _From, _To, [], _Lang) ->
Acc ++ [{xmlelement, "identity", [{"category", "pubsub"}, {"type", "pep"}], []} ];
disco_sm_identity(Acc, From, To, Node, _Lang) ->
@ -368,6 +382,9 @@ disco_sm_items(Acc, _From, To, Node, _Lang) ->
{result, NodeItems ++ Items}
end.
%% -------
%% presence hooks handling functions
%%
set_presence(User, Server, Resource, Presence) ->
Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
@ -577,16 +594,13 @@ terminate(_Reason, #state{host = Host,
plugins = Plugins}) ->
terminate_plugins(Host, ServerHost, Plugins, TreePlugin),
ejabberd_router:unregister_route(Host),
ejabberd_hooks:delete(disco_local_identity, ServerHost,
?MODULE, disco_local_identity, 75),
ejabberd_hooks:delete(disco_sm_identity, ServerHost,
?MODULE, disco_sm_identity, 75),
ejabberd_hooks:delete(disco_sm_features, ServerHost,
?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHost,
?MODULE, disco_sm_items, 75),
ejabberd_hooks:delete(incoming_presence_hook, ServerHost,
?MODULE, incoming_presence, 50),
ejabberd_hooks:delete(disco_local_identity, ServerHost, ?MODULE, disco_local_identity, 75),
ejabberd_hooks:delete(disco_local_features, ServerHost, ?MODULE, disco_local_features, 75),
ejabberd_hooks:delete(disco_local_items, ServerHost, ?MODULE, disco_local_items, 75),
ejabberd_hooks:delete(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:delete(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHost, ?MODULE, disco_sm_items, 75),
ejabberd_hooks:delete(incoming_presence_hook, ServerHost, ?MODULE, incoming_presence, 50),
%%ejabberd_hooks:delete(set_presence_hook, ServerHost, ?MODULE, set_presence, 50),
%%ejabberd_hooks:delete(unset_presence_hook, ServerHost, ?MODULE, unset_presence, 50),
lists:foreach(fun({NS,Mod}) ->
@ -772,8 +786,8 @@ iq_disco_info(Host, SNode, From, Lang) ->
{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
lists:map(fun(Feature) ->
{xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []}
end, features(Host, Node))};
{xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []}
end, features(Host, SNode))};
_ ->
node_disco_info(Host, Node, From)
end.
@ -865,7 +879,7 @@ iq_get_vcard(Lang) ->
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
Plugins = case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), plugins) of
[{plugins, PL}] -> PL;
_ -> [?STDNODE]
_ -> [?STDNODE,?PEPNODE]
end,
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, Plugins).
@ -1761,7 +1775,7 @@ get_affiliations(Host, JID, Plugins) when is_list(Plugins) ->
[{"node", node_to_string(Node)},
{"affiliation", affiliation_to_string(Affiliation)}],
[]}]
end, lists:flatten(Affiliations)),
end, lists:usort(lists:flatten(Affiliations))),
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "affiliations", [],
Entities}]}]};
@ -1887,7 +1901,7 @@ get_subscriptions(Host, JID, Plugins) when is_list(Plugins) ->
{"jid", jlib:jid_to_string(SubJID)},
{"subscription", subscription_to_string(Subscription)}],
[]}]
end, lists:flatten(Subscriptions)),
end, lists:usort(lists:flatten(Subscriptions))),
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "subscriptions", [],
Entities}]}]};
@ -2043,6 +2057,19 @@ node_to_string(Node) ->
string_to_node(SNode) ->
string:tokens(SNode, "/").
%% @spec (Host, JID, PresenceDelivery) -> boolean()
%% Host = host()
%% JID = jid()
%% PresenceDelivery = boolean()
%% @doc <p>Check if a notification must be delivered or not
to_be_delivered(_Host, _JID, false) ->
% default is true
true;
to_be_delivered(Host, JID, true) ->
case mnesia:dirty_read(pubsub_presence, {Host, element(1, JID), element(2, JID)}) of
[_] -> true;
[] -> false
end.
%%%%%% broadcast functions
@ -2054,57 +2081,41 @@ broadcast_publish_item(Host, Node, ItemId, _From, Payload) ->
{result, []} -> {result, false};
{result, States} ->
PresenceDelivery = get_option(Options, presence_based_delivery),
DeliverPayloads = get_option(Options, deliver_payloads),
BroadcastAll = get_option(Options, broadcast_all_resources),
Content = case get_option(Options, deliver_payloads) of
true -> Payload;
false -> []
end,
ItemAttrs = case ItemId of
"" -> [];
_ -> [{"id", ItemId}]
end,
Stanza = {xmlelement, "message", [],
[{xmlelement, "event",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "item", ItemAttrs, Content}]}]}]},
lists:foreach(
fun(#pubsub_state{stateid = {JID, _},
subscription = Subscription}) ->
ToBeSent =
case PresenceDelivery of
true ->
case mnesia:dirty_read(
pubsub_presence,
{Host,
element(1, JID),
element(2, JID)}) of
[_] -> true;
[] -> false
end;
false ->
true
end,
if
(Subscription /= none) and
(Subscription /= pending) and
ToBeSent ->
ItemAttrs = case ItemId of
"" -> [];
_ -> [{"id", ItemId}]
end,
Content = case DeliverPayloads of
true -> Payload;
false -> []
end,
DestJIDs = case BroadcastAll of
true -> ejabberd_sm:get_user_resources(element(1, JID), element(2, JID));
false -> [JID]
end,
Stanza =
{xmlelement, "message", [],
[{xmlelement, "event",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "item", ItemAttrs, Content}]}]}]},
lists:foreach(
ToBeSent = to_be_delivered(Host, JID, PresenceDelivery),
if
(Subscription /= none) and
(Subscription /= pending) and
ToBeSent ->
DestJIDs = case BroadcastAll of
true -> ejabberd_sm:get_user_resources(element(1, JID), element(2, JID));
false -> [JID]
end,
lists:foreach(
fun(DestJID) ->
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(DestJID), Stanza)
end, DestJIDs),
broadcast_by_caps(Host, Node, Type, Stanza),
true;
true ->
false
end
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(DestJID), Stanza)
end, DestJIDs);
true ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true}
end
end,
@ -2123,31 +2134,28 @@ broadcast_retract_item(Host, Node, ItemId, ForceNotify) ->
true -> true;
_ -> get_option(Options, notify_retract)
end,
ItemAttrs = case ItemId of
"" -> [];
_ -> [{"id", ItemId}]
end,
Stanza = {xmlelement, "message", [],
[{xmlelement, "x",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "retract", ItemAttrs, []}]}]}]},
case Notify of
true ->
lists:foreach(
fun(#pubsub_state{stateid = {JID, _},
subscription = Subscription}) ->
if (Subscription /= none) and
(Subscription /= pending) ->
ItemAttrs =
case ItemId of
"" -> [];
_ -> [{"id", ItemId}]
end,
Stanza =
{xmlelement, "message", [],
[{xmlelement, "x",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "retract", ItemAttrs, []}]}]}]},
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza),
broadcast_by_caps(Host, Node, Type, Stanza),
true;
true ->
false
end
if (Subscription /= none) and
(Subscription /= pending) ->
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza);
true ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
false ->
{result, false}
@ -2163,25 +2171,24 @@ broadcast_purge_node(Host, Node) ->
{error, _} -> {result, false};
{result, []} -> {result, false};
{result, States} ->
Stanza = {xmlelement, "message", [],
[{xmlelement, "event",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "purge", [{"node", node_to_string(Node)}],
[]}]}]},
case get_option(Options, notify_retract) of
true ->
lists:foreach(
fun(#pubsub_state{stateid = {JID,_},
subscription = Subscription}) ->
if (Subscription /= none) and
(Subscription /= pending) ->
Stanza = {xmlelement, "message", [],
[{xmlelement, "event",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "purge", [{"node", node_to_string(Node)}],
[]}]}]},
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza),
broadcast_by_caps(Host, Node, Type, Stanza),
true;
true ->
false
end
if (Subscription /= none) and
(Subscription /= pending) ->
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza);
true ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
false ->
{result, false}
@ -2195,33 +2202,32 @@ broadcast_removed_node(Host, Removed) ->
fun(Node) ->
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, States} ->
lists:foreach(
Stanza = {xmlelement, "message", [],
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "delete", [{"node", node_to_string(Node)}],
[]}]}]},
case get_option(Options, notify_delete) of
true ->
case node_call(Type, get_states, [Host, Node]) of
{result, States} ->
lists:foreach(
fun(#pubsub_state{stateid = {JID, _},
subscription = Subscription}) ->
if (Subscription /= none) and
(Subscription /= pending) ->
Stanza = {xmlelement, "message", [],
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "delete", [{"node", node_to_string(Node)}],
[]}]}]},
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza),
broadcast_by_caps(Host, Node, Type, Stanza),
true;
true ->
false
end
end, States),
{result, true};
_ ->
{result, false}
end;
_ ->
{result, false}
end
subscription = Subscription}) ->
if (Subscription /= none) and
(Subscription /= pending) ->
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza);
true ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
_ ->
{result, false}
end;
_ ->
{result, false}
end
end,
transaction(Host, Node, Action, sync_dirty)
end, Removed).
@ -2235,41 +2241,32 @@ broadcast_config_notification(Host, Node, Lang) ->
{result, States} ->
case get_option(Options, notify_config) of
true ->
PresenceDelivery = get_option(Options, presence_based_delivery),
Content = case get_option(Options, deliver_payloads) of
true ->
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
get_configure_xfields(Type, Options, Lang, Owners)}];
false ->
[]
end,
Stanza = {xmlelement, "message", [],
[{xmlelement, "x", [{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "item", [{"id", "configuration"}],
Content}]}]}]},
lists:foreach(
fun(#pubsub_state{stateid = {JID, _},
subscription = Subscription}) ->
ToBeSent = case get_option(Options, presence_based_delivery) of
true ->
case mnesia:dirty_read(pubsub_presence,
{Host, element(1, JID), element(2, JID)}) of
[_] -> true;
[] -> false
end;
false ->
true
end,
if (Subscription /= none) and
(Subscription /= pending) and
ToBeSent ->
Content = case get_option(Options, deliver_payloads) of
true ->
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
get_configure_xfields(Type, Options, Lang, Owners)}];
false ->
[]
end,
Stanza = {xmlelement, "message", [],
[{xmlelement, "x", [{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "item", [{"id", "configuration"}],
Content}]}]}]},
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza),
broadcast_by_caps(Host, Node, Type, Stanza),
true;
true ->
false
end
ToBeSent = to_be_delivered(Host, JID, PresenceDelivery),
if (Subscription /= none) and
(Subscription /= pending) and
ToBeSent ->
ejabberd_router:route(?PUBSUB_JID, jlib:make_jid(JID), Stanza);
true ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
_ ->
{result, false}
@ -2690,10 +2687,10 @@ features(Type) ->
Result -> Result
end.
features(_Host, []) ->
features(?STDNODE);
lists:usort(features(?STDNODE) ++ features(?PEPNODE));
features(Host, Node) ->
{result, Features} = node_action(Host, Node, features, []),
features() ++ Features.
lists:usort(features() ++ Features).
%% @doc <p>node tree plugin call.</p>
tree_call({_User, Server, _Resource}, Function, Args) ->

View File

@ -9,10 +9,6 @@
-define(PUBSUB_JID, {jid, "", Host, "", "", Host, ""}).
-define(ERR_EXTENDED(E,C), mod_pubsub:extended_error(E,C)).
% TODO: move to jlib.hrl
-define(NS_PUBSUB_NODE_CONFIG, "http://jabber.org/protocol/pubsub#node_config").
-define(NS_PUBSUB_SUB_AUTH, "http://jabber.org/protocol/pubsub#subscribe_authorization").
%% this is currently a hard limit.
%% Would be nice to have it configurable.
-define(MAXITEMS, 20).