note_caps/3,
clear_caps/1,
get_features/2,
+ get_user_resource/2,
handle_disco_response/3]).
%% gen_mod callbacks
-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 = []}).
%% clear_caps removes user caps from database
clear_caps(JID) ->
- catch mnesia:dirty_delete({user_caps, list_to_binary(jlib:jid_to_string(JID))}).
+ {U, S, R} = jlib:jid_tolower(JID),
+ BJID = list_to_binary(jlib:jid_to_string(JID)),
+ BUID = list_to_binary(jlib:jid_to_string({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(LUser, LServer) ->
+ BUID = list_to_binary(jlib:jid_to_string({LUser, LServer, []})),
+ 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
%% 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})
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}) ->
#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(jlib:jid_to_string(From)),
- caps = Caps}),
+ {_, _, R} = jlib:jid_tolower(From),
+ BJID = list_to_binary(jlib:jid_to_string(From)),
+ BUID = list_to_binary(jlib:jid_to_string(jlib:jid_remove_resource(From))),
+ mnesia:dirty_write(#user_caps{jid = BJID, caps = Caps}),
+ mnesia:dirty_write(#user_caps_default{uid = BUID, resource = R}),
SubNodes = [Version | Exts],
%% Now, find which of these are not already in the database.
Fun = fun() ->
%%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(LJID) ->
+ lists:foreach(fun({U, S, R}) ->
+ LJID = {U, S, user_resource(U, S, R)},
case is_caps_notify(LServer, Node, LJID) of
true ->
ejabberd_router ! {route, Sender, jlib:make_jid(LJID), Stanza};
false ->
ok
end
- end, Online);
+ end, Contacts);
_ ->
ok
end,
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