From 7d497615a19d4a59963759cadccac8c74ea48d80 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Fri, 5 Mar 2010 18:33:12 +0100 Subject: [PATCH] add extended stanza addressing 'replyto' on PEP (EJAB-1198) (thanks karim) --- src/mod_pubsub/mod_pubsub.erl | 114 ++++++++++++++++------------- src/mod_pubsub/mod_pubsub_odbc.erl | 113 ++++++++++++++++------------ src/mod_pubsub/pubsub_odbc.patch | 19 +++-- 3 files changed, 139 insertions(+), 107 deletions(-) diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index 9e19c5de1..39c0f51e1 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2963,7 +2963,7 @@ event_stanza_withmoreels(Els, MoreEls) -> %%%%%% broadcast functions -broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) -> +broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, From, Payload) -> %broadcast(Host, Node, NodeId, Options, none, true, 'items', ItemEls) case get_collection_subscriptions(Host, Node) of [] -> @@ -2977,7 +2977,7 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, Stanza, true), + broadcast_stanza(Host, From, Node, NodeId, Type, Options, SubsByDepth, items, Stanza, true), case Removed of [] -> ok; @@ -3116,7 +3116,6 @@ get_options_for_subs(NodeID, Subs) -> end, [], Subs). % TODO: merge broadcast code that way -% TODO: pablo: Why is this commented? Seems to be present on trunk. %broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> % case (get_option(NodeOptions, Feature) or Force) of % true -> @@ -3153,56 +3152,60 @@ broadcast_stanza(Host, _Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTy [LJID] end, %% Determine if the stanza should have SHIM ('SubID' and 'name') headers - StanzaToSend = case SHIM of - true -> - Headers = lists:append(collection_shim(NodeName), subid_shim(SubIDs)), - add_headers(Stanza, Headers); - false -> - Stanza + StanzaToSend = case {SHIM, SubIDs} of + {false, _} -> + Stanza; + {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({TU, TS, TR}) -> - ejabberd_router:route(From, exmpp_jid:make(TU, TS, TR), StanzaToSend) + lists:foreach(fun(To) -> + ejabberd_router:route(From, exmpp_jid:make(To), StanzaToSend) end, LJIDs) - end, SubIDsByJID), + 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), + SenderResource = case LResource of + undefined -> + case user_resources(LUser, LServer) of + [Resource|_] -> Resource; + _ -> <<"">> + end; + _ -> + LResource + end, %% Handles implicit presence subscriptions - case Host of - {LUser, LServer, LResource} -> - SenderResource = case LResource of - undefined -> - case user_resources(LUser, LServer) of - [Resource|_] -> Resource; - _ -> <<"">> - end; + case ejabberd_sm:get_session_pid({LUser, LServer, SenderResource}) 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 + Sender = exmpp_jid:make(LUser, LServer), + ReplyTo = exmpp_jid:to_binary(exmpp_jid:make(Publisher)), + StanzaToSend = add_extended_headers(Stanza, extended_headers([ReplyTo])), + case catch ejabberd_c2s:get_subscribed(C2SPid) of + Contacts when is_list(Contacts) -> + lists:foreach(fun({U, S, _}) -> + spawn(fun() -> + lists:foreach(fun(R) -> + ejabberd_router:route(Sender, exmpp_jid:make(U, S, R), StanzaToSend) + end, user_resources(U, S)) + end) + end, Contacts); _ -> - 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(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() -> - lists:foreach(fun(R) -> - ejabberd_router:route(Sender, exmpp_jid:make(U, S, R), Stanza) - end, user_resources(U, S)) - end) - end, Contacts); - _ -> - ok - end, - ok; - _ -> - ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), ok end; _ -> - ok - end. + ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, BaseStanza]) + end; +broadcast_stanza(Host, _Publisher, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) -> + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM). subscribed_nodes_by_jid(NotifyType, SubsByDepth) -> NodesToDeliver = fun(Depth, Node, Subs, Acc) -> @@ -3811,9 +3814,16 @@ add_message_type(El, _Type) -> El. %% %% "[SHIM Headers] SHOULD be included after the event notification information %% (i.e., as the last child of the stanza)". -add_headers(#xmlel{} = El, HeaderEls) -> - HeaderEl = #xmlel{ns = ?NS_SHIM, name = 'headers', children = HeaderEls}, - exmpp_xml:append_child(El, HeaderEl). + +add_shim_headers(Stanza, HeaderEls) -> + add_headers(Stanza, "headers", ?NS_SHIM, HeaderEls). + +add_extended_headers(Stanza, HeaderEls) -> + add_headers(Stanza, "addresses", ?NS_ADDRESS, HeaderEls). + +add_headers(#xmlel{children = Els} = Stanza, HeaderName, HeaderNS, HeaderEls) -> + HeaderEl = #xmlel{name = HeaderName, ns = HeaderNS, children = HeaderEls}, + Stanza#xmlel{children = lists:append(Els, [HeaderEl])}. %% Removed multiple
Foo
elements %% Didn't seem compliant, but not sure. Confirmation required. @@ -3838,6 +3848,12 @@ subid_shim(SubIDs) -> children = [?XMLCDATA(SubID)]} || SubID <- SubIDs]. + +extended_headers(Jids) -> + [#xmlel{ns = ?NS_ADDRESS, name = 'address', + attrs = [?XMLATTR('type', <<"replyto">>), ?XMLATTR('jid', Jid)]} + || Jid <- Jids]. + feature_check_packet(allow, _User, Server, Pres, {From, _To, El}, in) -> Host = host(Server), case exmpp_jid:prep_domain_as_list(From) of diff --git a/src/mod_pubsub/mod_pubsub_odbc.erl b/src/mod_pubsub/mod_pubsub_odbc.erl index 5a6c04328..7dd9becaa 100644 --- a/src/mod_pubsub/mod_pubsub_odbc.erl +++ b/src/mod_pubsub/mod_pubsub_odbc.erl @@ -2774,7 +2774,7 @@ event_stanza_withmoreels(Els, MoreEls) -> %%%%%% broadcast functions -broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From, Payload) -> +broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, From, Payload) -> %broadcast(Host, Node, NodeId, Options, none, true, 'items', ItemEls) case get_collection_subscriptions(Host, Node) of [] -> @@ -2788,7 +2788,7 @@ broadcast_publish_item(Host, Node, NodeId, Type, Options, Removed, ItemId, _From Stanza = event_stanza( [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'items', attrs = nodeAttr(Node), children = [#xmlel{ns = ?NS_PUBSUB_EVENT, name = 'item', attrs = itemAttr(ItemId), children = Content}]}]), - broadcast_stanza(Host, Node, NodeId, Type, Options, SubsByDepth, items, Stanza, true), + broadcast_stanza(Host, From, Node, NodeId, Type, Options, SubsByDepth, items, Stanza, true), case Removed of [] -> ok; @@ -2964,56 +2964,60 @@ broadcast_stanza(Host, _Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTy [LJID] end, %% Determine if the stanza should have SHIM ('SubID' and 'name') headers - StanzaToSend = case SHIM of - true -> - Headers = lists:append(collection_shim(NodeName), subid_shim(SubIDs)), - add_headers(Stanza, Headers); - false -> - Stanza + StanzaToSend = case {SHIM, SubIDs} of + {false, _} -> + Stanza; + {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({TU, TS, TR}) -> - ejabberd_router:route(From, exmpp_jid:make(TU, TS, TR), StanzaToSend) + lists:foreach(fun(To) -> + ejabberd_router:route(From, exmpp_jid:make(To), StanzaToSend) end, LJIDs) - end, SubIDsByJID), + 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), + SenderResource = case LResource of + undefined -> + case user_resources(LUser, LServer) of + [Resource|_] -> Resource; + _ -> <<"">> + end; + _ -> + LResource + end, %% Handles implicit presence subscriptions - case Host of - {LUser, LServer, LResource} -> - SenderResource = case LResource of - undefined -> - case user_resources(LUser, LServer) of - [Resource|_] -> Resource; - _ -> <<"">> - end; + case ejabberd_sm:get_session_pid({LUser, LServer, SenderResource}) 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 + Sender = exmpp_jid:make(LUser, LServer), + ReplyTo = exmpp_jid:to_binary(exmpp_jid:make(Publisher)), + StanzaToSend = add_extended_headers(Stanza, extended_headers([ReplyTo])), + case catch ejabberd_c2s:get_subscribed(C2SPid) of + Contacts when is_list(Contacts) -> + lists:foreach(fun({U, S, _}) -> + spawn(fun() -> + lists:foreach(fun(R) -> + ejabberd_router:route(Sender, exmpp_jid:make(U, S, R), StanzaToSend) + end, user_resources(U, S)) + end) + end, Contacts); _ -> - 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(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() -> - lists:foreach(fun(R) -> - ejabberd_router:route(Sender, exmpp_jid:make(U, S, R), Stanza) - end, user_resources(U, S)) - end) - end, Contacts); - _ -> - ok - end, - ok; - _ -> - ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, Stanza]), ok end; _ -> - ok - end. + ?DEBUG("~p@~p has no session; can't deliver ~p to contacts", [LUser, LServer, BaseStanza]) + end; +broadcast_stanza(Host, _Publisher, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) -> + broadcast_stanza(Host, Node, NodeId, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM). subscribed_nodes_by_jid(NotifyType, SubsByDepth) -> NodesToDeliver = fun(Depth, Node, Subs, Acc) -> @@ -3678,9 +3682,16 @@ add_message_type(El, _Type) -> El. %% %% "[SHIM Headers] SHOULD be included after the event notification information %% (i.e., as the last child of the stanza)". -add_headers(#xmlel{} = El, HeaderEls) -> - HeaderEl = #xmlel{ns = ?NS_SHIM, name = 'headers', children = HeaderEls}, - exmpp_xml:append_child(El, HeaderEl). + +add_shim_headers(Stanza, HeaderEls) -> + add_headers(Stanza, "headers", ?NS_SHIM, HeaderEls). + +add_extended_headers(Stanza, HeaderEls) -> + add_headers(Stanza, "addresses", ?NS_ADDRESS, HeaderEls). + +add_headers(#xmlel{children = Els} = Stanza, HeaderName, HeaderNS, HeaderEls) -> + HeaderEl = #xmlel{name = HeaderName, ns = HeaderNS, children = HeaderEls}, + Stanza#xmlel{children = lists:append(Els, [HeaderEl])}. %% Removed multiple
Foo
elements %% Didn't seem compliant, but not sure. Confirmation required. @@ -3705,6 +3716,12 @@ subid_shim(SubIDs) -> children = [?XMLCDATA(SubID)]} || SubID <- SubIDs]. + +extended_headers(Jids) -> + [#xmlel{ns = ?NS_ADDRESS, name = 'address', + attrs = [?XMLATTR('type', <<"replyto">>), ?XMLATTR('jid', Jid)]} + || Jid <- Jids]. + feature_check_packet(allow, _User, Server, Pres, {From, _To, El}, in) -> Host = host(Server), case exmpp_jid:prep_domain_as_list(From) of diff --git a/src/mod_pubsub/pubsub_odbc.patch b/src/mod_pubsub/pubsub_odbc.patch index 6bfb4e35f..b7b5252ef 100644 --- a/src/mod_pubsub/pubsub_odbc.patch +++ b/src/mod_pubsub/pubsub_odbc.patch @@ -1,5 +1,5 @@ ---- mod_pubsub.erl 2010-03-05 16:08:38.000000000 +0100 -+++ mod_pubsub_odbc.erl 2010-03-05 16:08:56.000000000 +0100 +--- mod_pubsub.erl 2010-03-05 18:31:50.000000000 +0100 ++++ mod_pubsub_odbc.erl 2010-03-05 18:32:08.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. @@ -707,16 +707,15 @@ _ -> Acc end; (_, Acc) -> -@@ -3116,7 +2927,7 @@ +@@ -3116,6 +2927,7 @@ end, [], Subs). % TODO: merge broadcast code that way --% TODO: pablo: Why is this commented? Seems to be present on trunk. +% TODO: pablo: why is this commented? %broadcast(Host, Node, NodeId, Type, NodeOptions, Feature, Force, ElName, SubEls) -> % case (get_option(NodeOptions, Feature) or Force) of % true -> -@@ -3315,6 +3126,30 @@ +@@ -3318,6 +3130,30 @@ Result end. @@ -747,7 +746,7 @@ %% @spec (Host, Options) -> MaxItems %% Host = host() %% Options = [Option] -@@ -3713,7 +3548,13 @@ +@@ -3716,7 +3552,13 @@ tree_action(Host, Function, Args) -> ?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]), Fun = fun() -> tree_call(Host, Function, Args) end, @@ -762,7 +761,7 @@ %% @doc

node plugin call.

node_call(Type, Function, Args) -> -@@ -3733,13 +3574,13 @@ +@@ -3736,13 +3578,13 @@ node_action(Host, Type, Function, Args) -> ?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]), @@ -778,7 +777,7 @@ case tree_call(Host, get_node, [Host, Node]) of N when is_record(N, pubsub_node) -> case Action(N) of -@@ -3752,8 +3593,15 @@ +@@ -3755,8 +3597,15 @@ end end, Trans). @@ -796,7 +795,7 @@ {result, Result} -> {result, Result}; {error, Error} -> {error, Error}; {atomic, {result, Result}} -> {result, Result}; -@@ -3761,6 +3609,15 @@ +@@ -3764,6 +3613,15 @@ {aborted, Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]), {error, 'internal-server-error'}; @@ -812,7 +811,7 @@ {'EXIT', Reason} -> ?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]), {error, 'internal-server-error'}; -@@ -3769,6 +3626,16 @@ +@@ -3772,6 +3630,16 @@ {error, 'internal-server-error'} end.