diff options
Diffstat (limited to 'src/mod_caps.erl')
-rw-r--r-- | src/mod_caps.erl | 105 |
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. |