From 214ef3105386d982238bba1e315e590d7413c1b2 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Tue, 23 Dec 2008 13:58:38 +0000 Subject: [PATCH] Improve handling of PEP sent to external contacts (EJAB-825) SVN Revision: 1751 --- ChangeLog | 6 +++++ src/mod_caps.erl | 48 ++++++++++++++++++++++++++++++----- src/mod_pubsub/mod_pubsub.erl | 34 +++++++++++++------------ 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index a89077a0d..2ef1596c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2008-12-23 Christophe Romain + + * src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to + external contacts (EJAB-825) + * src/mod_caps.erl: Likewise + 2008-12-19 Christophe Romain * src/mod_pubsub/mod_pubsub.erl: Fix send_last_published_item issue diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 98ebe1ec3..f7aa858cb 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -35,6 +35,7 @@ note_caps/3, clear_caps/1, get_features/2, + get_user_resource/2, handle_disco_response/3]). %% gen_mod callbacks @@ -61,6 +62,7 @@ -record(caps, {node, version, exts}). -record(caps_features, {node_pair, features}). -record(user_caps, {jid, caps}). +-record(user_caps_default, {uid, resource}). -record(state, {host, disco_requests = ?DICT:new(), feature_queries = []}). @@ -84,8 +86,9 @@ read_caps([], Result) -> Result. %% get_caps reads user caps from database -get_caps(JID) -> - case catch mnesia:dirty_read({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}) of +get_caps({U, S, R}) -> + BJID = exmpp_jlib:jid_to_binary(U, S, R), + case catch mnesia:dirty_read({user_caps, BJID}) of [#user_caps{caps=Caps}] -> Caps; _ -> @@ -93,8 +96,26 @@ get_caps(JID) -> end. %% clear_caps removes user caps from database -clear_caps(JID) -> - catch mnesia:dirty_delete({user_caps, list_to_binary(exmpp_jid:jid_to_list(JID))}). +clear_caps({U, S, R}) -> + BJID = exmpp_jlib:jid_to_binary(U, S, R), + BUID = exmpp_jlib:jid_to_binary(U, S), + catch mnesia:dirty_delete({user_caps, BJID}), + case catch mnesia:dirty_read({user_caps_default, BUID}) of + [#user_caps_default{resource=R}] -> + catch mnesia:dirty_delete({user_caps_default, BUID}); + _ -> + ok + end. + +%% give default user resource +get_user_resource(U, S) -> + BUID = exmpp_jlib:bare_jid_to_binary(U, S), + case catch mnesia:dirty_read({user_caps_default, BUID}) of + [#user_caps_default{resource=R}] -> + R; + _ -> + [] + end. %% note_caps should be called to make the module request disco %% information. Host is the host that asks, From is the full JID that @@ -113,7 +134,8 @@ note_caps(Host, From, Caps) -> %% timeout error. get_features(Host, Caps) -> case Caps of - nothing -> []; + nothing -> + []; #caps{} -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), gen_server:call(Proc, {get_features, Caps}) @@ -149,6 +171,9 @@ init([Host, _Opts]) -> mnesia:create_table(user_caps, [{disc_copies, [node()]}, {attributes, record_info(fields, user_caps)}]), + mnesia:create_table(user_caps_default, + [{disc_copies, [node()]}, + {attributes, record_info(fields, user_caps_default)}]), {ok, #state{host = Host}}. maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) -> @@ -200,8 +225,17 @@ handle_cast({note_caps, From, #state{host = Host, disco_requests = Requests} = State) -> %% XXX: this leads to race conditions where ejabberd will send %% lots of caps disco requests. - mnesia:dirty_write(#user_caps{jid = list_to_binary(exmpp_jid:jid_to_list(From)), - caps = Caps}), + #jid{node = U, domain = S, resource = R} = From, + BJID = exmpp_jlib:jid_to_binary(From), + mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}), + case ejabberd_sm:get_user_resources(U, S) of + [] -> + ok; + _ -> + % only store default resource of external contacts + BUID = exmpp_jlib:bare_jid_to_binary(From), + mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R}) + end, SubNodes = [Version | Exts], %% Now, find which of these are not already in the database. Fun = fun() -> diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl index c8eb5e500..da1620e58 100644 --- a/src/mod_pubsub/mod_pubsub.erl +++ b/src/mod_pubsub/mod_pubsub.erl @@ -2389,20 +2389,15 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> %%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) -> - Online = lists:foldl(fun({U, S, R}, Acc) -> - case user_resource(U, S, R) of - [] -> Acc; - OR -> [{U, S, OR}|Acc] - end - end, [], Contacts), lists:foreach(fun({U, S, R}) -> - case is_caps_notify(LServer, Node, {U, S, R}) of + OR = user_resource(U, S, R), + case is_caps_notify(LServer, Node, {U, S, OR}) of true -> - ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, R), Stanza}; + ejabberd_router ! {route, Sender, exmpp_jid:make_jid(U, S, OR), Stanza}; false -> ok end - end, Online); + end, Contacts); _ -> ok end, @@ -2414,20 +2409,27 @@ broadcast_by_caps({LUser, LServer, LResource}, Node, _Type, Stanza) -> broadcast_by_caps(_, _, _, _) -> ok. +%% If we don't know the resource, just pick first if any +%% If no resource available, check if caps anyway (remote online) user_resource(LUser, LServer, []) -> - %% If we don't know the resource, just pick first if any case ejabberd_sm:get_user_resources(LUser, LServer) of - [R|_] -> R; - [] -> [] + [R|_] -> + R; + [] -> + mod_caps:get_user_resource(LUser, LServer) end; user_resource(_, _, LResource) -> LResource. is_caps_notify(Host, Node, LJID) -> - Caps = mod_caps:get_caps(LJID), - case catch mod_caps:get_features(Host, Caps) of - Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); - _ -> false + case mod_caps:get_caps(LJID) of + nothing -> + false; + Caps -> + case catch mod_caps:get_features(Host, Caps) of + Features when is_list(Features) -> lists:member(Node ++ "+notify", Features); + _ -> false + end end. %%%%%%% Configuration handling