26
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-28 17:38:54 +01:00

Add roster subscriptions handling and make PEP events sent to all resources

SVN Revision: 1958
This commit is contained in:
Christophe Romain 2009-03-03 23:26:07 +00:00
parent 1db9642e4c
commit facf17e689
3 changed files with 95 additions and 38 deletions

View File

@ -1,3 +1,12 @@
2009-03-04 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: Add roster subscriptions handling
so on_sub_and_presence if fully supported.
* src/mod_pubsub/mod_pubsub.erl: Allow to send PEP events to all
connected ressources, even via s2s.
* src/mod_caps.erl: Likewise
2009-03-03 Badlop <badlop@process-one.net>
* src/ejabberd_listener.erl: Fix report message of 'undef' error

View File

@ -35,7 +35,7 @@
note_caps/3,
clear_caps/1,
get_features/2,
get_user_resource/2,
get_user_resources/2,
handle_disco_response/3]).
%% gen_mod callbacks
@ -62,7 +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(user_caps_resources, {uid, resource}).
-record(state, {host,
disco_requests = ?DICT:new(),
feature_queries = []}).
@ -100,21 +100,17 @@ clear_caps(JID) ->
BJID = exmpp_jid:jid_to_binary(JID),
BUID = exmpp_jid:bare_jid_to_binary(JID),
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.
catch mnesia:dirty_delete_object(#user_caps_resources{uid = BUID, resource = list_to_binary(R)}),
ok.
%% give default user resource
get_user_resource(U, S) ->
get_user_resources(U, S) ->
BUID = exmpp_jid:bare_jid_to_binary(U, S),
case catch mnesia:dirty_read({user_caps_default, BUID}) of
[#user_caps_default{resource=R}] ->
R;
_ ->
[]
case catch mnesia:dirty_read({user_caps_resources, BUID}) of
{'EXIT', _} ->
[];
Resources ->
lists:map(fun(#user_caps_resources{resource=R}) -> binary_to_list(R) end, Resources)
end.
%% note_caps should be called to make the module request disco
@ -171,9 +167,11 @@ init([Host, _Opts]) ->
mnesia:create_table(user_caps,
[{disc_copies, [node()]},
{attributes, record_info(fields, user_caps)}]),
mnesia:create_table(user_caps_default,
mnesia:create_table(user_caps_resources,
[{disc_copies, [node()]},
{attributes, record_info(fields, user_caps_default)}]),
{type, bag},
{attributes, record_info(fields, user_caps_resources)}]),
mnesia:delete_table(user_caps_default),
{ok, #state{host = Host}}.
maybe_get_features(#caps{node = Node, version = Version, exts = Exts}) ->
@ -233,11 +231,11 @@ handle_cast({note_caps, 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
% only store resource of caps aware external contacts
BUID = exmpp_jid:bare_jid_to_binary(From),
mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R})
mnesia:dirty_write(#user_caps_resources{uid = BUID, resource = list_to_binary(R)})
_ ->
ok
end,
SubNodes = [Version | Exts],
%% Now, find which of these are not already in the database.

View File

@ -55,6 +55,7 @@
%% exports for hooks
-export([presence_probe/3,
in_subscription/6,
remove_user/2,
disco_local_identity/5,
disco_local_features/5,
@ -164,6 +165,7 @@ init([ServerHost, Opts]) ->
ejabberd_hooks:add(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:add(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75),
ejabberd_hooks:add(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50),
ejabberd_hooks:add(roster_in_subscription, ServerHostB, ?MODULE, in_subscription, 50),
ejabberd_hooks:add(remove_user, ServerHostB, ?MODULE, remove_user, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
lists:foreach(
@ -418,6 +420,16 @@ presence_probe(JID, JID, Pid) ->
presence_probe(_, _, _) ->
ok.
%% -------
%% subscription hooks handling functions
%%
in_subscription(Acc, User, Server, JID, subscribed, _) ->
Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
gen_server:cast(Proc, {subscribed, User, Server, JID}),
Acc;
in_subscription(Acc, _, _, _, _, _) ->
Acc.
%% -------
%% user remove hook handling function
%%
@ -521,6 +533,42 @@ handle_cast({presence, JID, Pid}, State) ->
end,
{noreply, State};
handle_cast({subscribed, User, Server, JID}, State) ->
%% and send last PEP events published by JID
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 = jlib:short_prepd_jid(exmpp_jid:make_jid(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, []),
element(2, get_roster_info(User, Server, LJID, Grps))
end,
if Subscribed ->
send_last_item(Owner, Node, LJID);
true ->
ok
end;
false ->
ok
end
end, user_resources(User, Server));
_ ->
ok
end
end, tree_action(Host, get_nodes, [Owner])),
{noreply, State};
handle_cast({remove_user, LUser, LServer}, State) ->
Host = State#state.host,
Owner = exmpp_jid:make_jid(LUser, LServer),
@ -586,6 +634,7 @@ terminate(_Reason, #state{host = Host,
ejabberd_hooks:delete(disco_sm_features, ServerHostB, ?MODULE, disco_sm_features, 75),
ejabberd_hooks:delete(disco_sm_items, ServerHostB, ?MODULE, disco_sm_items, 75),
ejabberd_hooks:delete(presence_probe_hook, ServerHostB, ?MODULE, presence_probe, 50),
ejabberd_hooks:delete(roster_in_subscription, ServerHostB, ?MODULE, in_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)
@ -2342,7 +2391,10 @@ broadcast_stanza(Host, NodeOpts, States, Stanza) ->
%% 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 = user_resource(LUser, LServer, LResource),
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
@ -2352,14 +2404,16 @@ 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) ->
lists:foreach(fun({U, S, R}) ->
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, OR), Stanza};
false ->
ok
end
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);
_ ->
ok
@ -2374,15 +2428,11 @@ broadcast_by_caps(_, _, _, _) ->
%% 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, []) ->
case ejabberd_sm:get_user_resources(LUser, LServer) of
[R|_] ->
R;
[] ->
mod_caps:get_user_resource(LUser, LServer)
end;
user_resource(_, _, LResource) ->
LResource.
user_resources(User, Server) ->
case ejabberd_sm:get_user_resources(User, Server) of
[] -> mod_caps:get_user_resources(User, Server);
Rs -> Rs
end.
is_caps_notify(Host, Node, LJID) ->
case mod_caps:get_caps(LJID) of