aboutsummaryrefslogtreecommitdiff
path: root/src/mod_caps.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_caps.erl')
-rw-r--r--src/mod_caps.erl105
1 files changed, 104 insertions, 1 deletions
diff --git a/src/mod_caps.erl b/src/mod_caps.erl
index 319e37e6c..10f2f3414 100644
--- a/src/mod_caps.erl
+++ b/src/mod_caps.erl
@@ -53,7 +53,10 @@
]).
%% hook handlers
--export([user_send_packet/3]).
+-export([user_send_packet/3,
+ user_receive_packet/4,
+ c2s_presence_in/2,
+ c2s_broadcast_recipients/5]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -159,6 +162,22 @@ user_send_packet(#jid{luser = User, lserver = Server} = From,
user_send_packet(_From, _To, _Packet) ->
ok.
+user_receive_packet(#jid{lserver = Server}, From, _To,
+ {xmlelement, "presence", Attrs, Els}) ->
+ Type = xml:get_attr_s("type", Attrs),
+ if Type == ""; Type == "available" ->
+ case read_caps(Els) of
+ nothing ->
+ ok;
+ #caps{version = Version, exts = Exts} = Caps ->
+ feature_request(Server, From, Caps, [Version | Exts])
+ end;
+ true ->
+ ok
+ end;
+user_receive_packet(_JID, _From, _To, _Packet) ->
+ ok.
+
caps_stream_features(Acc, MyHost) ->
case make_my_disco_hash(MyHost) of
"" ->
@@ -194,6 +213,65 @@ disco_info(_Acc, Host, Module, ?EJABBERD_URI ++ "#" ++ [_|_], Lang) ->
disco_info(Acc, _Host, _Module, _Node, _Lang) ->
Acc.
+c2s_presence_in(C2SState, {From, To, {_, _, Attrs, Els}}) ->
+ Type = xml:get_attr_s("type", Attrs),
+ Subscription = ejabberd_c2s:get_subscription(From, C2SState),
+ Insert = ((Type == "") or (Type == "available"))
+ and ((Subscription == both) or (Subscription == to)),
+ Delete = (Type == "unavailable") or (Type == "error") or (Type == "invisible"),
+ if Insert or Delete ->
+ LFrom = jlib:jid_tolower(From),
+ Rs = case ejabberd_c2s:get_aux_field(caps_resources, C2SState) of
+ {ok, Rs1} ->
+ Rs1;
+ error ->
+ gb_trees:empty()
+ end,
+ Caps = read_caps(Els),
+ {FromUnavail, NewRs} =
+ case Caps of
+ nothing when Insert == true ->
+ {false, Rs};
+ _ when Insert == true ->
+ case gb_trees:lookup(LFrom, Rs) of
+ none ->
+ {true, gb_trees:insert(LFrom, Caps, Rs)};
+ _ ->
+ {false, gb_trees:update(LFrom, Caps, Rs)}
+ end;
+ _ ->
+ {false, gb_trees:delete_any(LFrom, Rs)}
+ end,
+ if FromUnavail ->
+ ejabberd_hooks:run(caps_user_available, To#jid.lserver,
+ [From, To, get_features(Caps)]);
+ true ->
+ ok
+ end,
+ ejabberd_c2s:set_aux_field(caps_resources, NewRs, C2SState);
+ true ->
+ C2SState
+ end.
+
+c2s_broadcast_recipients(InAcc, C2SState, {pep_message, Feature},
+ _From, _Packet) ->
+ case ejabberd_c2s:get_aux_field(caps_resources, C2SState) of
+ {ok, Rs} ->
+ gb_trees_fold(
+ fun(USR, Caps, Acc) ->
+ case lists:member(Feature, get_features(Caps)) of
+ true ->
+ [USR|Acc];
+ false ->
+ Acc
+ end
+ end, InAcc, Rs);
+ _ ->
+ InAcc
+ end;
+c2s_broadcast_recipients(Acc, _, _, _, _) ->
+ Acc.
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
@@ -214,8 +292,14 @@ init([Host, Opts]) ->
MaxSize = gen_mod:get_opt(cache_size, Opts, 1000),
LifeTime = gen_mod:get_opt(cache_life_time, Opts, timer:hours(24) div 1000),
cache_tab:new(caps_features, [{max_size, MaxSize}, {life_time, LifeTime}]),
+ ejabberd_hooks:add(c2s_presence_in, Host,
+ ?MODULE, c2s_presence_in, 75),
+ ejabberd_hooks:add(c2s_broadcast_recipients, Host,
+ ?MODULE, c2s_broadcast_recipients, 75),
ejabberd_hooks:add(user_send_packet, Host,
?MODULE, user_send_packet, 75),
+ ejabberd_hooks:add(user_receive_packet, Host,
+ ?MODULE, user_receive_packet, 75),
ejabberd_hooks:add(c2s_stream_features, Host,
?MODULE, caps_stream_features, 75),
ejabberd_hooks:add(s2s_stream_features, Host,
@@ -241,8 +325,14 @@ handle_info(_Info, State) ->
terminate(_Reason, State) ->
Host = State#state.host,
+ ejabberd_hooks:delete(c2s_presence_in, Host,
+ ?MODULE, c2s_presence_in, 75),
+ ejabberd_hooks:delete(c2s_broadcast_recipients, Host,
+ ?MODULE, c2s_broadcast_recipients, 75),
ejabberd_hooks:delete(user_send_packet, Host,
?MODULE, user_send_packet, 75),
+ ejabberd_hooks:delete(user_receive_packet, Host,
+ ?MODULE, user_receive_packet, 75),
ejabberd_hooks:delete(c2s_stream_features, Host,
?MODULE, caps_stream_features, 75),
ejabberd_hooks:delete(s2s_stream_features, Host,
@@ -506,3 +596,16 @@ concat_xdata_fields(Fields) ->
Acc
end, ["", []], Fields),
[Form, $<, lists:sort(Res)].
+
+gb_trees_fold(F, Acc, Tree) ->
+ Iter = gb_trees:iterator(Tree),
+ gb_trees_fold_iter(F, Acc, Iter).
+
+gb_trees_fold_iter(F, Acc, Iter) ->
+ case gb_trees:next(Iter) of
+ {Key, Val, NewIter} ->
+ NewAcc = F(Key, Val, Acc),
+ gb_trees_fold_iter(F, NewAcc, NewIter);
+ _ ->
+ Acc
+ end.