diff options
author | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2017-05-17 14:47:35 +0300 |
---|---|---|
committer | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2017-05-17 14:47:35 +0300 |
commit | f782955c069f1091cd56cc9d139ec0b0e2d62780 (patch) | |
tree | cbde7d13046bdc4bdc302511db04331b69d812e0 /src | |
parent | Fix use_cache/1 callback (diff) |
Implement cache for roster
Diffstat (limited to 'src')
-rw-r--r-- | src/ejabberd_c2s.erl | 240 | ||||
-rw-r--r-- | src/ejabberd_sm.erl | 2 | ||||
-rw-r--r-- | src/mod_block_strangers.erl | 55 | ||||
-rw-r--r-- | src/mod_caps.erl | 4 | ||||
-rw-r--r-- | src/mod_last.erl | 5 | ||||
-rw-r--r-- | src/mod_mam.erl | 52 | ||||
-rw-r--r-- | src/mod_pubsub.erl | 48 | ||||
-rw-r--r-- | src/mod_roster.erl | 554 | ||||
-rw-r--r-- | src/mod_roster_mnesia.erl | 47 | ||||
-rw-r--r-- | src/mod_roster_riak.erl | 51 | ||||
-rw-r--r-- | src/mod_roster_sql.erl | 86 | ||||
-rw-r--r-- | src/mod_shared_roster.erl | 25 | ||||
-rw-r--r-- | src/mod_shared_roster_ldap.erl | 24 |
13 files changed, 580 insertions, 613 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 0ac39518f..00a2bad80 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -46,7 +46,7 @@ reject_unauthenticated_packet/2, process_closed/2, process_terminated/2, process_info/2]). %% API --export([get_presence/1, get_subscription/2, get_subscribed/1, +-export([get_presence/1, resend_presence/1, resend_presence/2, open_session/1, call/3, send/2, close/1, close/2, stop/1, reply/2, copy_state/2, set_timeout/2, route/2, host_up/1, host_down/1]). @@ -54,6 +54,7 @@ -include("ejabberd.hrl"). -include("xmpp.hrl"). -include("logger.hrl"). +-include("mod_roster.hrl"). -define(SETS, gb_sets). @@ -93,23 +94,13 @@ reply(Ref, Reply) -> get_presence(Ref) -> call(Ref, get_presence, 1000). --spec get_subscription(jid() | ljid(), state()) -> both | from | to | none. -get_subscription(#jid{} = From, State) -> - get_subscription(jid:tolower(From), State); -get_subscription(LFrom, #{pres_f := PresF, pres_t := PresT}) -> - LBFrom = jid:remove_resource(LFrom), - F = ?SETS:is_element(LFrom, PresF) orelse ?SETS:is_element(LBFrom, PresF), - T = ?SETS:is_element(LFrom, PresT) orelse ?SETS:is_element(LBFrom, PresT), - if F and T -> both; - F -> from; - T -> to; - true -> none - end. +-spec resend_presence(pid()) -> ok. +resend_presence(Pid) -> + resend_presence(Pid, undefined). --spec get_subscribed(pid()) -> [ljid()]. -%% Return list of all available resources of contacts -get_subscribed(Ref) -> - call(Ref, get_subscribed, 1000). +-spec resend_presence(pid(), jid() | undefined) -> ok. +resend_presence(Pid, To) -> + route(Pid, {resend_presence, To}). -spec close(pid()) -> ok; (state()) -> state(). @@ -183,8 +174,7 @@ host_down(Host) -> copy_state(#{owner := Owner} = NewState, #{jid := JID, resource := Resource, sid := {Time, _}, auth_module := AuthModule, lserver := LServer, - pres_t := PresT, pres_a := PresA, - pres_f := PresF} = OldState) -> + pres_a := PresA} = OldState) -> State1 = case OldState of #{pres_last := Pres, pres_timestamp := PresTS} -> NewState#{pres_last => Pres, pres_timestamp => PresTS}; @@ -196,8 +186,7 @@ copy_state(#{owner := Owner} = NewState, conn => Conn, sid => {Time, Owner}, auth_module => AuthModule, - pres_t => PresT, pres_a => PresA, - pres_f => PresF}, + pres_a => PresA}, ejabberd_hooks:run_fold(c2s_copy_session, LServer, State2, [OldState]). -spec open_session(state()) -> {ok, state()} | state(). @@ -238,10 +227,17 @@ process_info(#{lserver := LServer} = State, {route, Packet}) -> true -> State1 end; -process_info(State, force_update_presence) -> +process_info(#{jid := JID} = State, {resend_presence, To}) -> case maps:get(pres_last, State, error) of error -> State; - Pres -> process_self_presence(State, Pres) + Pres when To == undefined -> + process_self_presence(State, Pres); + Pres when To#jid.luser == JID#jid.luser andalso + To#jid.lserver == JID#jid.lserver andalso + To#jid.lresource == <<"">> -> + process_self_presence(State, Pres); + Pres -> + process_presence_out(State, xmpp:set_to(Pres, To)) end; process_info(State, Info) -> ?WARNING_MSG("got unexpected info: ~p", [Info]), @@ -390,15 +386,11 @@ bind(R, #{user := U, server := S, access := Access, lang := Lang, allow -> State1 = open_session(State#{resource => Resource, sid => ejabberd_sm:make_sid()}), - LBJID = jid:remove_resource(jid:tolower(JID)), - PresF = ?SETS:add_element(LBJID, maps:get(pres_f, State1)), - PresT = ?SETS:add_element(LBJID, maps:get(pres_t, State1)), - State2 = State1#{pres_f => PresF, pres_t => PresT}, - State3 = ejabberd_hooks:run_fold( - c2s_session_opened, LServer, State2, []), + State2 = ejabberd_hooks:run_fold( + c2s_session_opened, LServer, State1, []), ?INFO_MSG("(~s) Opened c2s session for ~s", [SockMod:pp(Socket), jid:encode(JID)]), - {ok, State3}; + {ok, State2}; deny -> ejabberd_hooks:run(forbidden_session_hook, LServer, [JID]), ?INFO_MSG("(~s) Forbidden c2s session for ~s", @@ -513,8 +505,6 @@ init([State, Opts]) -> tls_enabled => TLSEnabled, tls_verify => TLSVerify, pres_a => ?SETS:new(), - pres_f => ?SETS:new(), - pres_t => ?SETS:new(), zlib => Zlib, lang => ?MYLANG, server => ?MYNAME, @@ -532,9 +522,6 @@ handle_call(get_presence, From, #{jid := JID} = State) -> end, reply(From, Pres), State; -handle_call(get_subscribed, From, #{pres_f := PresF} = State) -> - reply(From, ?SETS:to_list(PresF)), - State; handle_call(Request, From, #{lserver := LServer} = State) -> ejabberd_hooks:run_fold( c2s_handle_call, LServer, State, [Request, From]). @@ -589,36 +576,36 @@ process_message_in(State, #message{type = T} = Msg) -> -spec process_presence_in(state(), presence()) -> {boolean(), state()}. process_presence_in(#{lserver := LServer, pres_a := PresA} = State0, - #presence{from = From, to = To, type = T} = Pres) -> + #presence{from = From, type = T} = Pres) -> State = ejabberd_hooks:run_fold(c2s_presence_in, LServer, State0, [Pres]), case T of probe -> - NewState = add_to_pres_a(State, From), - route_probe_reply(From, To, NewState), - {false, NewState}; + route_probe_reply(From, State), + {false, State}; error -> A = ?SETS:del_element(jid:tolower(From), PresA), {true, State#{pres_a => A}}; _ -> case privacy_check_packet(State, Pres, in) of allow -> - NewState = add_to_pres_a(State, From), - {true, NewState}; + {true, State}; deny -> {false, State} end end. --spec route_probe_reply(jid(), jid(), state()) -> ok. -route_probe_reply(From, To, #{lserver := LServer, pres_f := PresF, - pres_last := LastPres, - pres_timestamp := TS} = State) -> - LFrom = jid:tolower(From), - LBFrom = jid:remove_resource(LFrom), - case ?SETS:is_element(LFrom, PresF) - orelse ?SETS:is_element(LBFrom, PresF) of - true -> - %% To is my JID +-spec route_probe_reply(jid(), state()) -> ok. +route_probe_reply(From, #{jid := To, + pres_last := LastPres, + pres_timestamp := TS} = State) -> + {LUser, LServer, LResource} = jid:tolower(To), + IsAnotherResource = case jid:tolower(From) of + {LUser, LServer, R} when R /= LResource -> true; + _ -> false + end, + Subscription = get_subscription(To, From), + if IsAnotherResource orelse + Subscription == both orelse Subscription == from -> Packet = xmpp_util:add_delay_info(LastPres, To, TS), case privacy_check_packet(State, Packet, out) of deny -> @@ -627,19 +614,12 @@ route_probe_reply(From, To, #{lserver := LServer, pres_f := PresF, ejabberd_hooks:run(presence_probe_hook, LServer, [From, To, self()]), - %% Don't route a presence probe to oneself - case From == To of - false -> - ejabberd_router:route( - xmpp:set_from_to(Packet, To, From)); - true -> - ok - end + ejabberd_router:route(xmpp:set_from_to(Packet, To, From)) end; - false -> + true -> ok end; -route_probe_reply(_, _, _) -> +route_probe_reply(_, _) -> ok. -spec process_presence_out(state(), presence()) -> state(). @@ -675,11 +655,22 @@ process_presence_out(#{user := User, server := Server, lserver := LServer, State; allow -> ejabberd_router:route(Pres), - A = case Type of - available -> ?SETS:add_element(LTo, PresA); - unavailable -> ?SETS:del_element(LTo, PresA) - end, - State#{pres_a => A} + LBareTo = jid:remove_resource(LTo), + LBareFrom = jid:remove_resource(jid:tolower(From)), + if LBareTo /= LBareFrom -> + Subscription = get_subscription(From, To), + if Subscription /= both andalso Subscription /= from -> + A = case Type of + available -> ?SETS:add_element(LTo, PresA); + unavailable -> ?SETS:del_element(LTo, PresA) + end, + State#{pres_a => A}; + true -> + State + end; + true -> + State + end end. -spec process_self_presence(state(), presence()) -> state(). @@ -716,24 +707,81 @@ update_priority(#{ip := IP, conn := Conn, auth_module := AuthMod, ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres, Info). -spec broadcast_presence_unavailable(state(), presence()) -> state(). -broadcast_presence_unavailable(#{pres_a := PresA} = State, Pres) -> - JIDs = filter_blocked(State, Pres, PresA), +broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) -> + #jid{luser = LUser, lserver = LServer} = JID, + BareJID = jid:remove_resource(JID), + Items1 = ejabberd_hooks:run_fold(roster_get, LServer, + [], [{LUser, LServer}]), + Items2 = ?SETS:fold( + fun(LJID, Items) -> + [#roster{jid = LJID, subscription = from}|Items] + end, Items1, PresA), + JIDs = lists:foldl( + fun(#roster{jid = LJID, subscription = Sub}, Tos) + when Sub == both orelse Sub == from -> + To = jid:make(LJID), + P = xmpp:set_to(Pres, jid:make(LJID)), + case privacy_check_packet(State, P, out) of + allow -> [To|Tos]; + deny -> Tos + end; + (_, Tos) -> + Tos + end, [BareJID], Items2), route_multiple(State, JIDs, Pres), State#{pres_a => ?SETS:new()}. -spec broadcast_presence_available(state(), presence(), boolean()) -> state(). -broadcast_presence_available(#{pres_a := PresA, pres_f := PresF, - pres_t := PresT, jid := JID} = State, +broadcast_presence_available(#{jid := JID} = State, Pres, _FromUnavailable = true) -> Probe = #presence{from = JID, type = probe}, - TJIDs = filter_blocked(State, Probe, PresT), - FJIDs = filter_blocked(State, Pres, PresF), + #jid{luser = LUser, lserver = LServer} = JID, + BareJID = jid:remove_resource(JID), + Items = ejabberd_hooks:run_fold(roster_get, LServer, + [], [{LUser, LServer}]), + {FJIDs, TJIDs} = + lists:foldl( + fun(#roster{jid = LJID, subscription = Sub}, {F, T}) -> + To = jid:make(LJID), + F1 = if Sub == both orelse Sub == from -> + Pres1 = xmpp:set_to(Pres, To), + case privacy_check_packet(State, Pres1, out) of + allow -> [To|F]; + deny -> F + end; + true -> F + end, + T1 = if Sub == both orelse Sub == to -> + Probe1 = xmpp:set_to(Probe, To), + case privacy_check_packet(State, Probe1, out) of + allow -> [To|T]; + deny -> T + end; + true -> T + end, + {F1, T1} + end, {[BareJID], [BareJID]}, Items), route_multiple(State, TJIDs, Probe), route_multiple(State, FJIDs, Pres), - State#{pres_a => ?SETS:union(PresA, PresF)}; -broadcast_presence_available(#{pres_a := PresA, pres_f := PresF} = State, + State; +broadcast_presence_available(#{jid := JID} = State, Pres, _FromUnavailable = false) -> - JIDs = filter_blocked(State, Pres, ?SETS:intersection(PresA, PresF)), + #jid{luser = LUser, lserver = LServer} = JID, + BareJID = jid:remove_resource(JID), + Items = ejabberd_hooks:run_fold( + roster_get, LServer, [], [{LUser, LServer}]), + JIDs = lists:foldl( + fun(#roster{jid = LJID, subscription = Sub}, Tos) + when Sub == both orelse Sub == from -> + To = jid:make(LJID), + P = xmpp:set_to(Pres, jid:make(LJID)), + case privacy_check_packet(State, P, out) of + allow -> [To|Tos]; + deny -> Tos + end; + (_, Tos) -> + Tos + end, [BareJID], Items), route_multiple(State, JIDs, Pres), State. @@ -761,23 +809,17 @@ get_priority_from_presence(#presence{priority = Prio}) -> _ -> Prio end. --spec filter_blocked(state(), presence(), ?SETS:set()) -> [jid()]. -filter_blocked(#{jid := From} = State, Pres, LJIDSet) -> - ?SETS:fold( - fun(LJID, Acc) -> - To = jid:make(LJID), - Pkt = xmpp:set_from_to(Pres, From, To), - case privacy_check_packet(State, Pkt, out) of - allow -> [To|Acc]; - deny -> Acc - end - end, [], LJIDSet). - -spec route_multiple(state(), [jid()], stanza()) -> ok. route_multiple(#{lserver := LServer}, JIDs, Pkt) -> From = xmpp:get_from(Pkt), ejabberd_router_multicast:route_multicast(From, LServer, JIDs, Pkt). +get_subscription(#jid{luser = LUser, lserver = LServer}, JID) -> + {Subscription, _} = ejabberd_hooks:run_fold( + roster_get_jid_info, LServer, {none, []}, + [LUser, LServer, JID]), + Subscription. + -spec resource_conflict_action(binary(), binary(), binary()) -> {accept_resource, binary()} | closenew. resource_conflict_action(U, S, R) -> @@ -855,30 +897,6 @@ change_shaper(#{shaper := ShaperName, ip := IP, lserver := LServer, LServer), xmpp_stream_in:change_shaper(State, Shaper). --spec add_to_pres_a(state(), jid()) -> state(). -add_to_pres_a(#{pres_a := PresA, pres_f := PresF} = State, From) -> - LFrom = jid:tolower(From), - LBFrom = jid:remove_resource(LFrom), - case (?SETS):is_element(LFrom, PresA) orelse - (?SETS):is_element(LBFrom, PresA) of - true -> - State; - false -> - case (?SETS):is_element(LFrom, PresF) of - true -> - A = (?SETS):add_element(LFrom, PresA), - State#{pres_a => A}; - false -> - case (?SETS):is_element(LBFrom, PresF) of - true -> - A = (?SETS):add_element(LBFrom, PresA), - State#{pres_a => A}; - false -> - State - end - end - end. - -spec format_reason(state(), term()) -> binary(). format_reason(#{stop_reason := Reason}, _) -> xmpp_stream_in:format_error(Reason); diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 9ab38a763..ea19f832f 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -858,7 +858,7 @@ force_update_presence({LUser, LServer}) -> Mod = get_sm_backend(LServer), Ss = online(get_sessions(Mod, LUser, LServer)), lists:foreach(fun (#session{sid = {_, Pid}}) -> - ejabberd_c2s:route(Pid, force_update_presence) + ejabberd_c2s:resend_presence(Pid) end, Ss). diff --git a/src/mod_block_strangers.erl b/src/mod_block_strangers.erl index 6a4a96bf9..636d5077b 100644 --- a/src/mod_block_strangers.erl +++ b/src/mod_block_strangers.erl @@ -57,39 +57,40 @@ filter_packet({#message{} = Msg, State} = Acc) -> From = xmpp:get_from(Msg), LFrom = jid:tolower(From), LBFrom = jid:remove_resource(LFrom), - #{pres_a := PresA, - pres_t := PresT, - pres_f := PresF} = State, + #{pres_a := PresA, jid := JID, lserver := LServer} = State, case (Msg#message.body == [] andalso Msg#message.subject == []) orelse ejabberd_router:is_my_route(From#jid.lserver) orelse (?SETS):is_element(LFrom, PresA) orelse (?SETS):is_element(LBFrom, PresA) - orelse sets_bare_member(LBFrom, PresA) - orelse (?SETS):is_element(LFrom, PresT) - orelse (?SETS):is_element(LBFrom, PresT) - orelse (?SETS):is_element(LFrom, PresF) - orelse (?SETS):is_element(LBFrom, PresF) of - true -> - Acc; + orelse sets_bare_member(LBFrom, PresA) of false -> - #{lserver := LServer} = State, - Drop = gen_mod:get_module_opt(LServer, ?MODULE, drop, true), - Log = gen_mod:get_module_opt(LServer, ?MODULE, log, false), - if - Log -> - ?INFO_MSG("Drop packet: ~s", - [fxml:element_to_binary( - xmpp:encode(Msg, ?NS_CLIENT))]); - true -> - ok - end, - if - Drop -> - {stop, {drop, State}}; - true -> - Acc - end + {Sub, _} = ejabberd_hooks:run_fold( + roster_get_jid_info, LServer, + {none, []}, [JID#jid.luser, LServer, From]), + case Sub of + none -> + Drop = gen_mod:get_module_opt(LServer, ?MODULE, drop, true), + Log = gen_mod:get_module_opt(LServer, ?MODULE, log, false), + if + Log -> + ?INFO_MSG("Drop packet: ~s", + [fxml:element_to_binary( + xmpp:encode(Msg, ?NS_CLIENT))]); + true -> + ok + end, + if + Drop -> + {stop, {drop, State}}; + true -> + Acc + end; + _ -> + Acc + end; + true -> + Acc end; filter_packet(Acc) -> Acc. diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 5609030d3..87fdebbc8 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -203,7 +203,9 @@ disco_info(Acc, _, _, _Node, _Lang) -> -spec c2s_presence_in(ejabberd_c2s:state(), presence()) -> ejabberd_c2s:state(). c2s_presence_in(C2SState, #presence{from = From, to = To, type = Type} = Presence) -> - Subscription = ejabberd_c2s:get_subscription(From, C2SState), + {Subscription, _} = ejabberd_hooks:run_fold( + roster_get_jid_info, To#jid.lserver, + {none, []}, [To#jid.luser, To#jid.lserver, From]), Insert = (Type == available) and ((Subscription == both) or (Subscription == to)), Delete = (Type == unavailable) or (Type == error), diff --git a/src/mod_last.erl b/src/mod_last.erl index 052c17c02..79b3d614f 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -157,7 +157,10 @@ privacy_check_packet(allow, C2SState, when T == get; T == set -> case xmpp:has_subtag(IQ, #last{}) of true -> - Sub = ejabberd_c2s:get_subscription(From, C2SState), + #jid{luser = LUser, lserver = LServer} = To, + {Sub, _} = ejabberd_hooks:run_fold( + roster_get_jid_info, LServer, + {none, []}, [LUser, LServer, From]), if Sub == from; Sub == both -> Pres = #presence{from = To, to = From}, case ejabberd_hooks:run_fold( diff --git a/src/mod_mam.erl b/src/mod_mam.erl index c84cb907b..eb2082fe2 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -255,7 +255,7 @@ set_room_option(_Acc, {mam, Val}, _Lang) -> set_room_option(Acc, _Property, _Lang) -> Acc. --spec user_receive_packet({stanza(), ejabberd_c2s:state()}) -> {stanza(), ejabberd_c2s:state()}. +-spec user_receive_packet({stanza(), c2s_state()}) -> {stanza(), c2s_state()}. user_receive_packet({Pkt, #{jid := JID} = C2SState}) -> Peer = xmpp:get_from(Pkt), LUser = JID#jid.luser, @@ -263,7 +263,7 @@ user_receive_packet({Pkt, #{jid := JID} = C2SState}) -> Pkt2 = case should_archive(Pkt, LServer) of true -> Pkt1 = strip_my_archived_tag(Pkt, LServer), - case store_msg(C2SState, Pkt1, LUser, LServer, Peer, recv) of + case store_msg(Pkt1, LUser, LServer, Peer, recv) of {ok, ID} -> set_stanza_id(Pkt1, JID, ID); _ -> @@ -274,7 +274,7 @@ user_receive_packet({Pkt, #{jid := JID} = C2SState}) -> end, {Pkt2, C2SState}. --spec user_send_packet({stanza(), ejabberd_c2s:state()}) -> {stanza(), ejabberd_c2s:state()}. +-spec user_send_packet({stanza(), c2s_state()}) -> {stanza(), c2s_state()}. user_send_packet({Pkt, #{jid := JID} = C2SState}) -> Peer = xmpp:get_to(Pkt), LUser = JID#jid.luser, @@ -282,7 +282,7 @@ user_send_packet({Pkt, #{jid := JID} = C2SState}) -> Pkt2 = case should_archive(Pkt, LServer) of true -> Pkt1 = strip_my_archived_tag(Pkt, LServer), - case store_msg(C2SState, xmpp:set_from_to(Pkt1, JID, Peer), + case store_msg(xmpp:set_from_to(Pkt1, JID, Peer), LUser, LServer, Peer, send) of {ok, ID} -> set_stanza_id(Pkt1, JID, ID); @@ -301,7 +301,7 @@ offline_message({_Action, #message{from = Peer, to = To} = Pkt} = Acc) -> case should_archive(Pkt, LServer) of true -> Pkt1 = strip_my_archived_tag(Pkt, LServer), - case store_msg(undefined, Pkt1, LUser, LServer, Peer, recv) of + case store_msg(Pkt1, LUser, LServer, Peer, recv) of {ok, ID} -> {archived, set_stanza_id(Pkt1, To, ID)}; _ -> @@ -311,8 +311,8 @@ offline_message({_Action, #message{from = Peer, to = To} = Pkt} = Acc) -> Acc end. --spec user_send_packet_strip_tag({stanza(), ejabberd_c2s:state()}) -> - {stanza(), ejabberd_c2s:state()}. +-spec user_send_packet_strip_tag({stanza(), c2s_state()}) -> + {stanza(), c2s_state()}. user_send_packet_strip_tag({Pkt, #{jid := JID} = C2SState}) -> LServer = JID#jid.lserver, {strip_my_archived_tag(Pkt, LServer), C2SState}. @@ -415,16 +415,16 @@ disco_sm_features({result, OtherFeatures}, disco_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. --spec message_is_archived(boolean(), ejabberd_c2s:state(), message()) -> boolean(). +-spec message_is_archived(boolean(), c2s_state(), message()) -> boolean(). message_is_archived(true, _C2SState, _Pkt) -> true; -message_is_archived(false, #{jid := JID} = C2SState, Pkt) -> +message_is_archived(false, #{jid := JID}, Pkt) -> #jid{luser = LUser, lserver = LServer} = JID, Peer = xmpp:get_from(Pkt), case gen_mod:get_module_opt(LServer, ?MODULE, assume_mam_usage, false) of true -> should_archive(strip_my_archived_tag(Pkt, LServer), LServer) - andalso should_archive_peer(C2SState, LUser, LServer, + andalso should_archive_peer(LUser, LServer, get_prefs(LUser, LServer), Peer); false -> @@ -615,9 +615,9 @@ strip_x_jid_tags(Pkt) -> end, Els), xmpp:set_els(Pkt, NewEls). --spec should_archive_peer(c2s_state() | undefined, binary(), binary(), +-spec should_archive_peer(binary(), binary(), #archive_prefs{}, jid()) -> boolean(). -should_archive_peer(C2SState, LUser, LServer, +should_archive_peer(LUser, LServer, #archive_prefs{default = Default, always = Always, never = Never}, @@ -635,23 +635,11 @@ should_archive_peer(C2SState, LUser, LServer, always -> true; never -> false; roster -> - Sub = case C2SState of - undefined -> - {S, _} = ejabberd_hooks:run_fold( - roster_get_jid_info, - LServer, {none, []}, - [LUser, LServer, Peer]), - S; - _ -> - ejabberd_c2s:get_subscription( - LPeer, C2SState) - end, - case Sub of - both -> true; - from -> true; - to -> true; - _ -> false - end + {Sub, _} = ejabberd_hooks:run_fold( + roster_get_jid_info, + LServer, {none, []}, + [LUser, LServer, Peer]), + Sub == both orelse Sub == from orelse Sub == to end end end. @@ -719,12 +707,12 @@ may_enter_room(From, may_enter_room(From, MUCState) -> mod_muc_room:is_occupant_or_admin(From, MUCState). --spec store_msg(c2s_state() | undefined, stanza(), +-spec store_msg(stanza(), binary(), binary(), jid(), send | recv) -> {ok, binary()} | pass. -store_msg(C2SState, Pkt, LUser, LServer, Peer, Dir) -> +store_msg(Pkt, LUser, LServer, Peer, Dir) -> Prefs = get_prefs(LUser, LServer), - case should_archive_peer(C2SState, LUser, LServer, Prefs, Peer) of + case should_archive_peer(LUser, LServer, Prefs, Peer) of true -> US = {LUser, LServer}, case ejabberd_hooks:run_fold(store_mam_message, LServer, Pkt, diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl index 2a9fa18c7..91d2f928a 100644 --- a/src/mod_pubsub.erl +++ b/src/mod_pubsub.erl @@ -43,6 +43,7 @@ -include("logger.hrl"). -include("xmpp.hrl"). -include("pubsub.hrl"). +-include("mod_roster.hrl"). -define(STDTREE, <<"tree">>). -define(STDNODE, <<"flat">>). @@ -405,9 +406,19 @@ terminate_plugins(Host, ServerHost, Plugins, TreePlugin) -> TreePlugin:terminate(Host, ServerHost), ok. +get_subscribed(User, Server) -> + Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]), + lists:filtermap( + fun(#roster{jid = LJID, subscription = Sub}) + when Sub == both orelse Sub == from -> + {true, LJID}; + (_) -> + false + end, Items). + send_loop(State) -> receive - {presence, JID, Pid} -> + {presence, JID, _Pid} -> Host = State#state.host, ServerHost = State#state.server_host, DBType = State#state.db_type, @@ -429,26 +440,21 @@ send_loop(State) -> State#state.plugins), if not State#state.ignore_pep_from_offline -> {User, Server, Resource} = LJID, - case catch ejabberd_c2s:get_subscribed(Pid) of - Contacts when is_list(Contacts) -> - lists:foreach( - fun({U, S, R}) when S == ServerHost -> - case user_resources(U, S) of - [] -> %% offline - PeerJID = jid:make(U, S, R), - self() ! {presence, User, Server, [Resource], PeerJID}; - _ -> %% online - % this is already handled by presence probe - ok - end; - (_) -> - % we can not do anything in any cases - ok - end, - Contacts); - _ -> - ok - end; + Contacts = get_subscribed(User, Server), + lists:foreach( + fun({U, S, R}) when S == ServerHost -> + case user_resources(U, S) of + [] -> %% offline + PeerJID = jid:make(U, S, R), + self() ! {presence, User, Server, [Resource], PeerJID}; + _ -> %% online + %% this is already handled by presence probe + ok + end; + (_) -> + %% we can not do anything in any cases + ok + end, Contacts); true -> ok end, diff --git a/src/mod_roster.erl b/src/mod_roster.erl index f2bfc59de..b256f107d 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -43,8 +43,8 @@ -export([start/2, stop/1, reload/3, process_iq/1, export/1, import_info/0, process_local_iq/1, get_user_roster/2, - import/5, c2s_session_opened/1, get_roster/2, - import_start/2, import_stop/2, user_receive_packet/1, + import/5, get_roster/2, + import_start/2, import_stop/2, c2s_self_presence/1, in_subscription/6, out_subscription/4, set_items/3, remove_user/2, get_jid_info/4, encode_item/1, webadmin_page/3, @@ -63,38 +63,41 @@ -include("ejabberd_web_admin.hrl"). --define(SETS, gb_sets). +-define(ROSTER_CACHE, roster_cache). +-define(ROSTER_ITEM_CACHE, roster_item_cache). +-define(ROSTER_VERSION_CACHE, roster_version_cache). -export_type([subscription/0]). -callback init(binary(), gen_mod:opts()) -> any(). -callback import(binary(), binary(), #roster{} | [binary()]) -> ok. --callback read_roster_version(binary(), binary()) -> binary() | error. +-callback read_roster_version(binary(), binary()) -> {ok, binary()} | error. -callback write_roster_version(binary(), binary(), boolean(), binary()) -> any(). --callback get_roster(binary(), binary()) -> [#roster{}]. --callback get_roster_by_jid(binary(), binary(), ljid()) -> #roster{}. --callback get_only_items(binary(), binary()) -> [#roster{}]. +-callback get_roster(binary(), binary()) -> {ok, [#roster{}]} | error. +-callback get_roster_item(binary(), binary(), ljid()) -> {ok, #roster{}} | error. +-callback read_subscription_and_groups(binary(), binary(), ljid()) + -> {ok, {subscription(), [binary()]}} | error. -callback roster_subscribe(binary(), binary(), ljid(), #roster{}) -> any(). -callback transaction(binary(), function()) -> {atomic, any()} | {aborted, any()}. --callback get_roster_by_jid_with_groups(binary(), binary(), ljid()) -> #roster{}. --callback remove_user(binary(), binary()) -> {atomic, any()}. +-callback remove_user(binary(), binary()) -> any(). -callback update_roster(binary(), binary(), ljid(), #roster{}) -> any(). -callback del_roster(binary(), binary(), ljid()) -> any(). --callback read_subscription_and_groups(binary(), binary(), ljid()) -> - {subscription(), [binary()]}. +-callback use_cache(binary(), roster | roster_version) -> boolean(). +-callback cache_nodes(binary()) -> [node()]. + +-optional_callbacks([use_cache/2, cache_nodes/1]). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, gen_iq_handler:iqdisc(Host)), Mod = gen_mod:db_mod(Host, Opts, ?MODULE), Mod:init(Host, Opts), + init_cache(Mod, Host, Opts), ejabberd_hooks:add(roster_get, Host, ?MODULE, get_user_roster, 50), ejabberd_hooks:add(roster_in_subscription, Host, ?MODULE, in_subscription, 50), ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:add(c2s_session_opened, Host, ?MODULE, - c2s_session_opened, 50), ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 50), ejabberd_hooks:add(remove_user, Host, ?MODULE, @@ -107,8 +110,6 @@ start(Host, Opts) -> webadmin_page, 50), ejabberd_hooks:add(webadmin_user, Host, ?MODULE, webadmin_user, 50), - ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, - user_receive_packet, 50), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ROSTER, ?MODULE, process_iq, IQDisc). @@ -119,8 +120,6 @@ stop(Host) -> ?MODULE, in_subscription, 50), ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 50), - ejabberd_hooks:delete(c2s_session_opened, Host, ?MODULE, - c2s_session_opened, 50), ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 50), ejabberd_hooks:delete(remove_user, Host, ?MODULE, @@ -133,8 +132,6 @@ stop(Host) -> webadmin_page, 50), ejabberd_hooks:delete(webadmin_user, Host, ?MODULE, webadmin_user, 50), - ejabberd_hooks:delete(user_receive_packet, Host, ?MODULE, - user_receive_packet, 50), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ROSTER). @@ -244,7 +241,7 @@ roster_version(LServer, LUser) -> true -> case read_roster_version(LUser, LServer) of error -> not_found; - V -> V + {ok, V} -> V end; false -> roster_hash(ejabberd_hooks:run_fold(roster_get, LServer, @@ -252,8 +249,12 @@ roster_version(LServer, LUser) -> end. read_roster_version(LUser, LServer) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:read_roster_version(LUser, LServer). + ets_cache:lookup( + ?ROSTER_VERSION_CACHE, {LUser, LServer}, + fun() -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Mod:read_roster_version(LUser, LServer) + end). write_roster_version(LUser, LServer) -> write_roster_version(LUser, LServer, false). @@ -265,6 +266,11 @@ write_roster_version(LUser, LServer, InTransaction) -> Ver = str:sha(term_to_binary(p1_time_compat:unique_integer())), Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:write_roster_version(LUser, LServer, InTransaction, Ver), + if InTransaction -> ok; + true -> + ets_cache:delete(?ROSTER_VERSION_CACHE, {LUser, LServer}, + cache_nodes(Mod, LServer)) + end, Ver. %% Load roster from DB only if neccesary. @@ -289,9 +295,9 @@ process_iq_get(#iq{to = To, lang = Lang, ejabberd_hooks:run_fold( roster_get, To#jid.lserver, [], [US])), RosterVersion}; - RequestedVersion -> + {ok, RequestedVersion} -> {false, false}; - NewVersion -> + {ok, NewVersion} -> {lists:map(fun encode_item/1, ejabberd_hooks:run_fold( roster_get, To#jid.lserver, [], [US])), @@ -343,18 +349,72 @@ get_user_roster(Acc, {LUser, LServer}) -> get_roster(LUser, LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:get_roster(LUser, LServer). + R = case use_cache(Mod, LServer, roster) of + true -> + ets_cache:lookup( + ?ROSTER_CACHE, {LUser, LServer}, + fun() -> Mod:get_roster(LUser, LServer) end); + false -> + Mod:get_roster(LUser, LServer) + end, + case R of + {ok, Items} -> Items; + error -> [] + end. + +get_roster_item(LUser, LServer, LJID) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + case Mod:get_roster_item(LUser, LServer, LJID) of + {ok, Item} -> + Item; + error -> + #roster{usj = {LUser, LServer, LJID}, + us = {LUser, LServer}, jid = LJID} + end. + +get_subscription_and_groups(LUser, LServer, LJID) -> + Mod = gen_mod:db_mod(LServer, ?MODULE), + Res = case use_cache(Mod, LServer, roster) of + true -> + LBJID = jid:remove_resource(LJID), + ets_cache:lookup( + ?ROSTER_ITEM_CACHE, {LUser, LServer, LBJID}, + fun() -> + Items = get_roster(LUser, LServer), + case lists:keyfind(LBJID, #roster.jid, Items) of + #roster{subscription = Sub, groups = Groups} -> + {ok, {Sub, Groups}}; + false when element(3, LJID) == <<"">> -> + error; + false -> + case lists:keyfind(LJID, #roster.jid, Items) of + {Sub, Groups} -> + {ok, {Sub, Groups}}; + false -> + error + end + end + end); + false -> + Mod:read_subscription_and_groups(LUser, LServer, LJID) + end, + case Res of + {ok, SubAndGroups} -> + SubAndGroups; + error -> + {none, []} + end. set_roster(#roster{us = {LUser, LServer}, jid = LJID} = Item) -> transaction( - LServer, + LUser, LServer, [LJID], fun() -> update_roster_t(LUser, LServer, LJID, Item) end). del_roster(LUser, LServer, LJID) -> transaction( - LServer, + LUser, LServer, [LJID], fun() -> del_roster_t(LUser, LServer, LJID) end). @@ -387,46 +447,36 @@ decode_item(Item, R, Managed) -> end, groups = Item#roster_item.groups}. -get_roster_by_jid_t(LUser, LServer, LJID) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:get_roster_by_jid(LUser, LServer, LJID). - process_iq_set(#iq{from = From, to = To, - sub_els = [#roster_query{items = QueryItems}]} = IQ) -> + sub_els = [#roster_query{items = [QueryItem]}]} = IQ) -> #jid{user = User, luser = LUser, lserver = LServer} = To, Managed = {From#jid.luser, From#jid.lserver} /= {LUser, LServer}, + LJID = jid:tolower(QueryItem#roster_item.jid), F = fun () -> - lists:map( - fun(#roster_item{jid = JID1} = QueryItem) -> - LJID = jid:tolower(JID1), - Item = get_roster_by_jid_t(LUser, LServer, LJID), - Item2 = decode_item(QueryItem, Item, Managed), - Item3 = ejabberd_hooks:run_fold(roster_process_item, - LServer, Item2, - [LServer]), - case Item3#roster.subscription of - remove -> del_roster_t(LUser, LServer, LJID); - _ -> update_roster_t(LUser, LServer, LJID, Item3) - end, - case roster_version_on_db(LServer) of - true -> write_roster_version_t(LUser, LServer); - false -> ok - end, - {Item, Item3} - end, QueryItems) + Item = get_roster_item(LUser, LServer, LJID), + Item2 = decode_item(QueryItem, Item, Managed), + Item3 = ejabberd_hooks:run_fold(roster_process_item, + LServer, Item2, + [LServer]), + case Item3#roster.subscription of + remove -> del_roster_t(LUser, LServer, LJID); + _ -> update_roster_t(LUser, LServer, LJID, Item3) + end, + case roster_version_on_db(LServer) of + true -> write_roster_version_t(LUser, LServer); + false -> ok + end, + {Item, Item3} end, - case transaction(LServer, F) of - {atomic, ItemPairs} -> - lists:foreach( - fun({OldItem, Item}) -> - push_item(User, LServer, To, Item), - case Item#roster.subscription of - remove -> - send_unsubscribing_presence(To, OldItem); - _ -> - ok - end - end, ItemPairs), + case transaction(LUser, LServer, [LJID], F) of + {atomic, {OldItem, Item}} -> + push_item(User, LServer, To, OldItem, Item), + case Item#roster.subscription of + remove -> + send_unsubscribing_presence(To, OldItem); + _ -> + ok + end, xmpp:make_iq_result(IQ); E -> ?ERROR_MSG("roster set failed:~nIQ = ~s~nError = ~p", @@ -434,126 +484,66 @@ process_iq_set(#iq{from = From, to = To, xmpp:make_error(IQ, xmpp:err_internal_server_error()) end. -push_item(User, Server, From, Item) -> +push_item(User, Server, From, OldItem, NewItem) -> case roster_versioning_enabled(Server) of - true -> - push_item_version(Server, User, From, Item, - roster_version(Server, User)); - false -> - lists:foreach(fun (Resource) -> - push_item(User, Server, Resource, From, Item) - end, - ejabberd_sm:get_user_resources(User, Server)) + true -> + push_item_version(Server, User, From, OldItem, NewItem, + roster_version(Server, User)); + false -> + lists:foreach( + fun(Resource) -> + push_item(User, Server, Resource, From, OldItem, NewItem) + end, ejabberd_sm:get_user_resources(User, Server)) end. -push_item(User, Server, Resource, From, Item) -> - push_item(User, Server, Resource, From, Item, - not_found). +push_item(User, Server, Resource, From, OldItem, NewItem) -> + push_item(User, Server, Resource, From, OldItem, NewItem, undefined). -push_item(User, Server, Resource, From, Item, - RosterVersion) -> - Ver = case RosterVersion of - not_found -> undefined; - _ -> RosterVersion - end, +push_item(User, Server, Resource, From, OldItem, NewItem, Ver) -> To = jid:make(User, Server, Resource), + route_presence_change(To, OldItem, NewItem), ResIQ = #iq{type = set, from = From, to = To, id = <<"push", (randoms:get_string())/binary>>, sub_els = [#roster_query{ver = Ver, - items = [encode_item(Item)]}]}, - ejabberd_router:route(xmpp:put_meta(ResIQ, roster_item, Item)). - -push_item_version(Server, User, From, Item, - RosterVersion) -> - lists:foreach(fun (Resource) -> - push_item(User, Server, Resource, From, Item, - RosterVersion) - end, - ejabberd_sm:get_user_resources(User, Server)). - --spec user_receive_packet({stanza(), ejabberd_c2s:state()}) -> {stanza(), ejabberd_c2s:state()}. -user_receive_packet({#iq{type = set, meta = #{roster_item := Item}} = IQ, State}) -> - {IQ, roster_change(State, Item)}; -user_receive_packet(Acc) -> - Acc. - --spec roster_change(ejabberd_c2s:state(), #roster{}) -> ejabberd_c2s:state(). -roster_change(#{user := U, server := S, resource := R, - pres_a := PresA, pres_f := PresF, pres_t := PresT} = State, - #roster{jid = IJID, subscription = ISubscription}) -> - LIJID = jid:tolower(IJID), - IsFrom = (ISubscription == both) or (ISubscription == from), - IsTo = (ISubscription == both) or (ISubscription == to), - OldIsFrom = ?SETS:is_element(LIJID, PresF), - FSet = if IsFrom -> ?SETS:add_element(LIJID, PresF); - true -> ?SETS:del_element(LIJID, PresF) - end, - TSet = if IsTo -> ?SETS:add_element(LIJID, PresT); - true -> ?SETS:del_element(LIJID, PresT) - end, - State1 = State#{pres_f => FSet, pres_t => TSet}, - case maps:get(pres_last, State, undefined) of - undefined -> - State1; - LastPres -> - From = jid:make(U, S, R), - To = jid:make(IJID), - Cond1 = IsFrom andalso not OldIsFrom, - Cond2 = not IsFrom andalso OldIsFrom andalso - ?SETS:is_element(LIJID, PresA), - if Cond1 -> - case ejabberd_hooks:run_fold( - privacy_check_packet, allow, - [State1, LastPres, out]) of - deny -> - ok; - allow -> - Pres = xmpp:set_from_to(LastPres, From, To), - ejabberd_router:route(Pres) - end, - A = ?SETS:add_element(LIJID, PresA), - State1#{pres_a => A}; - Cond2 -> - PU = #presence{from = From, to = To, type = unavailable}, - case ejabberd_hooks:run_fold( - privacy_check_packet, allow, - [State1, PU, out]) of - deny -> - ok; - allow -> - ejabberd_router:route(PU) - end, - A = ?SETS:del_element(LIJID, PresA), - State1#{pres_a => A}; - true -> - State1 - end + items = [encode_item(NewItem)]}]}, + ejabberd_router:route(ResIQ). + +push_item_version(Server, User, From, OldItem, NewItem, RosterVersion) -> + lists:foreach( + fun(Resource) -> + push_item(User, Server, Resource, From, + OldItem, NewItem, RosterVersion) + end, ejabberd_sm:get_user_resources(User, Server)). + +-spec route_presence_change(jid(), #roster{}, #roster{}) -> ok. +route_presence_change(From, OldItem, NewItem) -> + OldSub = OldItem#roster.subscription, + NewSub = NewItem#roster.subscription, + To = jid:make(NewItem#roster.jid), + NewIsFrom = NewSub == both orelse NewSub == from, + OldIsFrom = OldSub == both orelse OldSub == from, + if NewIsFrom andalso not OldIsFrom -> + case ejabberd_sm:get_session_pid( + From#jid.luser, From#jid.lserver, From#jid.lresource) of + none -> + ok; + Pid -> + ejabberd_c2s:resend_presence(Pid, To) + end; + OldIsFrom andalso not NewIsFrom -> + PU = #presence{from = From, to = To, type = unavailable}, + case ejabberd_hooks:run_fold( + privacy_check_packet, allow, + [From, PU, out]) of + deny -> + ok; + allow -> + ejabberd_router:route(PU) + end; + true -> + ok end. --spec c2s_session_opened(ejabberd_c2s:state()) -> ejabberd_c2s:state(). -c2s_session_opened(#{jid := #jid{luser = LUser, lserver = LServer}, - pres_f := PresF, pres_t := PresT} = State) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Items = Mod:get_only_items(LUser, LServer), - {F, T} = fill_subscription_lists(Items, PresF, PresT), - State#{pres_f => F, pres_t => T}. - -fill_subscription_lists([I | Is], F, T) -> - J = element(3, I#roster.usj), - {F1, T1} = case I#roster.subscription of - both -> - {?SETS:add_element(J, F), ?SETS:add_element(J, T)}; - from -> - {?SETS:add_element(J, F), T}; - to -> - {F, ?SETS:add_element(J, T)}; - _ -> - {F, T} - end, - fill_subscription_lists(Is, F1, T1); -fill_subscription_lists([], F, T) -> - {F, T}. - ask_to_pending(subscribe) -> out; ask_to_pending(unsubscribe) -> none; ask_to_pending(Ask) -> Ask. @@ -562,9 +552,15 @@ roster_subscribe_t(LUser, LServer, LJID, Item) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:roster_subscribe(LUser, LServer, LJID, Item). -transaction(LServer, F) -> +transaction(LUser, LServer, LJIDs, F) -> Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:transaction(LServer, F). + case Mod:transaction(LServer, F) of + {atomic, _} = Result -> + delete_cache(Mod, LUser, LServer, LJIDs), + Result; + Err -> + Err + end. -spec in_subscription(boolean(), binary(), binary(), jid(), subscribe | subscribed | unsubscribe | unsubscribed, @@ -579,18 +575,13 @@ in_subscription(_, User, Server, JID, Type, Reason) -> out_subscription(User, Server, JID, Type) -> process_subscription(out, User, Server, JID, Type, <<"">>). -get_roster_by_jid_with_groups_t(LUser, LServer, LJID) -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:get_roster_by_jid_with_groups(LUser, LServer, LJID). - process_subscription(Direction, User, Server, JID1, Type, Reason) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), LJID = jid:tolower(JID1), F = fun () -> - Item = get_roster_by_jid_with_groups_t(LUser, LServer, - LJID), + Item = get_roster_item(LUser, LServer, LJID), NewState = case Direction of out -> out_state_change(Item#roster.subscription, @@ -611,46 +602,48 @@ process_subscription(Direction, User, Server, JID1, _ -> <<"">> end, case NewState of - none -> {none, AutoReply}; - {none, none} - when Item#roster.subscription == none, - Item#roster.ask == in -> - del_roster_t(LUser, LServer, LJID), {none, AutoReply}; - {Subscription, Pending} -> - NewItem = Item#roster{subscription = Subscription, - ask = Pending, - askmessage = AskMessage}, - roster_subscribe_t(LUser, LServer, LJID, NewItem), - case roster_version_on_db(LServer) of - true -> write_roster_version_t(LUser, LServer); - false -> ok - end, - {{push, NewItem}, AutoReply} + none -> + {none, AutoReply}; + {none, none} when Item#roster.subscription == none, + Item#roster.ask == in -> + del_roster_t(LUser, LServer, LJID), {none, AutoReply}; + {Subscription, Pending} -> + NewItem = Item#roster{subscription = Subscription, + ask = Pending, + askmessage = AskMessage}, + roster_subscribe_t(LUser, LServer, LJID, NewItem), + case roster_version_on_db(LServer) of + true -> write_roster_version_t(LUser, LServer); + false -> ok + end, + {{push, Item, NewItem}, AutoReply} end end, - case transaction(LServer, F) of - {atomic, {Push, AutoReply}} -> - case AutoReply of - none -> ok; - _ -> - ejabberd_router:route( - #presence{type = AutoReply, - from = jid:make(User, Server), - to = JID1}) - end, - case Push of - {push, Item} -> - if Item#roster.subscription == none, - Item#roster.ask == in -> - ok; - true -> - push_item(User, Server, - jid:make(User, Server), Item) - end, - true; - none -> false - end; - _ -> false + case transaction(LUser, LServer, [LJID], F) of + {atomic, {Push, AutoReply}} -> + case AutoReply of + none -> ok; + _ -> + ejabberd_router:route( + #presence{type = AutoReply, + from = jid:make(User, Server), + to = JID1}) + end, + case Push of + {push, OldItem, NewItem} -> + if NewItem#roster.subscription == none, + NewItem#roster.ask == in -> + ok; + true -> + push_item(User, Server, + jid:make(User, Server), OldItem, NewItem) + end, + true; + none -> + false + end; + _ -> + false end. %% in_state_change(Subscription, Pending, Type) -> NewState @@ -772,16 +765,16 @@ in_auto_reply(_, _, _) -> none. remove_user(User, Server) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), - send_unsubscription_to_rosteritems(LUser, LServer), + Items = get_user_roster([], {LUser, LServer}), + send_unsubscription_to_rosteritems(LUser, LServer, Items), Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:remove_user(LUser, LServer), - ok. + delete_cache(Mod, LUser, LServer, [Item#roster.jid || Item <- Items]). %% For each contact with Subscription: %% Both or From, send a "unsubscribed" presence stanza; %% Both or To, send a "unsubscribe" presence stanza. -send_unsubscription_to_rosteritems(LUser, LServer) -> - RosterItems = get_user_roster([], {LUser, LServer}), +send_unsubscription_to_rosteritems(LUser, LServer, RosterItems) -> From = jid:make({LUser, LServer, <<"">>}), lists:foreach(fun (RosterItem) -> send_unsubscribing_presence(From, RosterItem) @@ -821,12 +814,14 @@ send_unsubscribing_presence(From, Item) -> set_items(User, Server, #roster_query{items = Items}) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), + LJIDs = [jid:tolower(Item#roster_item.jid) || Item <- Items], F = fun () -> - lists:foreach(fun (Item) -> - process_item_set_t(LUser, LServer, Item) - end, Items) + lists:foreach( + fun(Item) -> + process_item_set_t(LUser, LServer, Item) + end, Items) end, - transaction(LServer, F). + transaction(LUser, LServer, LJIDs, F). update_roster_t(LUser, LServer, LJID, Item) -> Mod = gen_mod:db_mod(LServer, ?MODULE), @@ -856,8 +851,7 @@ c2s_self_presence({#presence{type = available} = Pkt, #{lserver := LServer} = State}) -> Prio = get_priority_from_presence(Pkt), if Prio >= 0 -> - Mod = gen_mod:db_mod(LServer, ?MODULE), - State1 = resend_pending_subscriptions(State, Mod), + State1 = resend_pending_subscriptions(State), {Pkt, State1}; true -> {Pkt, State} @@ -865,10 +859,10 @@ c2s_self_presence({#presence{type = available} = Pkt, c2s_self_presence(Acc) -> Acc. --spec resend_pending_subscriptions(ejabberd_c2s:state(), module()) -> ejabberd_c2s:state(). -resend_pending_subscriptions(#{jid := JID} = State, Mod) -> +-spec resend_pending_subscriptions(ejabberd_c2s:state()) -> ejabberd_c2s:state(). +resend_pending_subscriptions(#{jid := JID} = State) -> BareJID = jid:remove_resource(JID), - Result = Mod:get_only_items(JID#jid.luser, JID#jid.lserver), + Result = get_roster(JID#jid.luser, JID#jid.lserver), lists:foldl( fun(#roster{ask = Ask} = R, AccState) when Ask == in; Ask == both -> Message = R#roster.askmessage, @@ -892,30 +886,13 @@ get_priority_from_presence(#presence{priority = Prio}) -> end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -read_subscription_and_groups(User, Server, LJID) -> - LUser = jid:nodeprep(User), - LServer = jid:nameprep(Server), - Mod = gen_mod:db_mod(LServer, ?MODULE), - Mod:read_subscription_and_groups(LUser, LServer, LJID). - -spec get_jid_info({subscription(), [binary()]}, binary(), binary(), jid()) -> {subscription(), [binary()]}. get_jid_info(_, User, Server, JID) -> + LUser = jid:nodeprep(User), + LServer = jid:nameprep(Server), LJID = jid:tolower(JID), - case read_subscription_and_groups(User, Server, LJID) of - {Subscription, Groups} -> {Subscription, Groups}; - error -> - LRJID = jid:tolower(jid:remove_resource(JID)), - if LRJID == LJID -> {none, []}; - true -> - case read_subscription_and_groups(User, Server, LRJID) - of - {Subscription, Groups} -> {Subscription, Groups}; - error -> {none, []} - end - end - end. + get_subscription_and_groups(LUser, LServer, LJID). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1118,6 +1095,81 @@ has_duplicated_groups(Groups) -> GroupsPrep = lists:usort([jid:resourceprep(G) || G <- Groups]), not (length(GroupsPrep) == length(Groups)). +-spec init_cache(module(), binary(), gen_mod:opts()) -> ok. +init_cache(Mod, Host, Opts) -> + CacheOpts = cache_opts(Host, Opts), + case use_cache(Mod, Host, roster_version) of + true -> + ets_cache:new(?ROSTER_VERSION_CACHE, CacheOpts); + false -> + ets_cache:delete(?ROSTER_VERSION_CACHE) + end, + case use_cache(Mod, Host, roster) of + true -> + ets_cache:new(?ROSTER_CACHE, CacheOpts), + ets_cache:new(?ROSTER_ITEM_CACHE, CacheOpts); + false -> + ets_cache:delete(?ROSTER_CACHE), + ets_cache:delete(?ROSTER_ITEM_CACHE) + end. + +-spec cache_opts(binary(), gen_mod:opts()) -> [proplists:property()]. +cache_opts(Host, Opts) -> + MaxSize = gen_mod:get_opt( + cache_size, Opts, + ejabberd_config:cache_size(Host)), + CacheMissed = gen_mod:get_opt( + cache_missed, Opts, + ejabberd_config:cache_missed(Host)), + LifeTime = case gen_mod:get_opt( + cache_life_time, Opts, + ejabberd_config:cache_life_time(Host)) of + infinity -> infinity; + I -> timer:seconds(I) + end, + [{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}]. + +-spec use_cache(module(), binary(), roster | roster_version) -> boolean(). +use_cache(Mod, Host, Table) -> + case erlang:function_exported(Mod, use_cache, 2) of + true -> Mod:use_cache(Host, Table); + false -> + gen_mod:get_module_opt( + Host, ?MODULE, use_cache, + ejabberd_config:use_cache(Host)) + end. + +-spec cache_nodes(module(), binary()) -> [node()]. +cache_nodes(Mod, Host) -> + case erlang:function_exported(Mod, cache_nodes, 1) of + true -> Mod:cache_nodes(Host); + false -> ejabberd_cluster:get_nodes() + end. + +-spec delete_cache(module(), binary(), binary(), [ljid()]) -> ok. +delete_cache(Mod, LUser, LServer, LJIDs) -> + case use_cache(Mod, LServer, roster_version) of + true -> + ets_cache:delete(?ROSTER_VERSION_CACHE, {LUser, LServer}, + cache_nodes(Mod, LServer)); + false -> + ok + end, + case use_cache(Mod, LServer, roster) of + true -> + Nodes = cache_nodes(Mod, LServer), + ets_cache:delete(?ROSTER_CACHE, {LUser, LServer}, Nodes), + lists:foreach( + fun(LJID) -> + ets_cache:delete( + ?ROSTER_ITEM_CACHE, + {LUser, LServer, jid:remove_resource(LJID)}, + Nodes) + end, LJIDs); + false -> + ok + end. + export(LServer) -> Mod = gen_mod:db_mod(LServer, ?MODULE), Mod:export(LServer). diff --git a/src/mod_roster_mnesia.erl b/src/mod_roster_mnesia.erl index 0207b6dc5..723c1722e 100644 --- a/src/mod_roster_mnesia.erl +++ b/src/mod_roster_mnesia.erl @@ -28,10 +28,10 @@ %% API -export([init/2, read_roster_version/2, write_roster_version/4, - get_roster/2, get_roster_by_jid/3, get_only_items/2, - roster_subscribe/4, get_roster_by_jid_with_groups/3, + get_roster/2, get_roster_item/3, roster_subscribe/4, remove_user/2, update_roster/4, del_roster/3, transaction/2, - read_subscription_and_groups/3, import/3, create_roster/1]). + read_subscription_and_groups/3, import/3, create_roster/1, + use_cache/2]). -export([need_transform/1, transform/1]). -include("mod_roster.hrl"). @@ -42,18 +42,28 @@ %%%=================================================================== init(_Host, _Opts) -> ejabberd_mnesia:create(?MODULE, roster, - [{disc_copies, [node()]}, + [{disc_only_copies, [node()]}, {attributes, record_info(fields, roster)}, {index, [us]}]), ejabberd_mnesia:create(?MODULE, roster_version, - [{disc_copies, [node()]}, + [{disc_only_copies, [node()]}, {attributes, record_info(fields, roster_version)}]). +use_cache(Host, Table) -> + case mnesia:table_info(Table, storage_type) of + disc_only_copies -> + gen_mod:get_module_opt( + Host, ?MODULE, use_cache, + ejabberd_config:use_cache(Host)); + _ -> + false + end. + read_roster_version(LUser, LServer) -> US = {LUser, LServer}, case mnesia:dirty_read(roster_version, US) of - [#roster_version{version = V}] -> V; + [#roster_version{version = V}] -> {ok, V}; [] -> error end. @@ -66,32 +76,17 @@ write_roster_version(LUser, LServer, InTransaction, Ver) -> end. get_roster(LUser, LServer) -> - mnesia:dirty_index_read(roster, {LUser, LServer}, #roster.us). + {ok, mnesia:dirty_index_read(roster, {LUser, LServer}, #roster.us)}. -get_roster_by_jid(LUser, LServer, LJID) -> +get_roster_item(LUser, LServer, LJID) -> case mnesia:read({roster, {LUser, LServer, LJID}}) of - [] -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; - [I] -> - I#roster{jid = LJID, name = <<"">>, groups = [], - xs = []} + [I] -> {ok, I}; + [] -> error end. -get_only_items(LUser, LServer) -> - get_roster(LUser, LServer). - roster_subscribe(_LUser, _LServer, _LJID, Item) -> mnesia:write(Item). -get_roster_by_jid_with_groups(LUser, LServer, LJID) -> - case mnesia:read({roster, {LUser, LServer, LJID}}) of - [] -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; - [I] -> I - end. - remove_user(LUser, LServer) -> US = {LUser, LServer}, F = fun () -> @@ -110,7 +105,7 @@ del_roster(LUser, LServer, LJID) -> read_subscription_and_groups(LUser, LServer, LJID) -> case mnesia:dirty_read(roster, {LUser, LServer, LJID}) of [#roster{subscription = Subscription, groups = Groups}] -> - {Subscription, Groups}; + {ok, {Subscription, Groups}}; _ -> error end. diff --git a/src/mod_roster_riak.erl b/src/mod_roster_riak.erl index 25788cddf..c457e02f5 100644 --- a/src/mod_roster_riak.erl +++ b/src/mod_roster_riak.erl @@ -28,10 +28,10 @@ %% API -export([init/2, read_roster_version/2, write_roster_version/4, - get_roster/2, get_roster_by_jid/3, create_roster/1, - roster_subscribe/4, get_roster_by_jid_with_groups/3, - remove_user/2, update_roster/4, del_roster/3, transaction/2, - read_subscription_and_groups/3, get_only_items/2, import/3]). + get_roster/2, get_roster_item/3, create_roster/1, + roster_subscribe/4, remove_user/2, update_roster/4, + del_roster/3, read_subscription_and_groups/3, transaction/2, + import/3]). -include("mod_roster.hrl"). @@ -44,7 +44,7 @@ init(_Host, _Opts) -> read_roster_version(LUser, LServer) -> case ejabberd_riak:get(roster_version, roster_version_schema(), {LUser, LServer}) of - {ok, #roster_version{version = V}} -> V; + {ok, #roster_version{version = V}} -> {ok, V}; _Err -> error end. @@ -56,24 +56,10 @@ write_roster_version(LUser, LServer, _InTransaction, Ver) -> get_roster(LUser, LServer) -> case ejabberd_riak:get_by_index(roster, roster_schema(), <<"us">>, {LUser, LServer}) of - {ok, Items} -> Items; - _Err -> [] - end. - -get_roster_by_jid(LUser, LServer, LJID) -> - case ejabberd_riak:get(roster, roster_schema(), {LUser, LServer, LJID}) of - {ok, I} -> - I#roster{jid = LJID, name = <<"">>, groups = [], xs = []}; - {error, notfound} -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; - Err -> - exit(Err) + {ok, Items} -> {ok, Items}; + _Err -> error end. -get_only_items(LUser, LServer) -> - get_roster(LUser, LServer). - roster_subscribe(LUser, LServer, _LJID, Item) -> ejabberd_riak:put(Item, roster_schema(), [{'2i', [{<<"us">>, {LUser, LServer}}]}]). @@ -81,19 +67,16 @@ roster_subscribe(LUser, LServer, _LJID, Item) -> transaction(_LServer, F) -> {atomic, F()}. -get_roster_by_jid_with_groups(LUser, LServer, LJID) -> +get_roster_item(LUser, LServer, LJID) -> case ejabberd_riak:get(roster, roster_schema(), {LUser, LServer, LJID}) of {ok, I} -> - I; - {error, notfound} -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; - Err -> - exit(Err) + {ok, I}; + {error, _} -> + error end. remove_user(LUser, LServer) -> - {atomic, ejabberd_riak:delete_by_index(roster, <<"us">>, {LUser, LServer})}. + ejabberd_riak:delete_by_index(roster, <<"us">>, {LUser, LServer}). update_roster(LUser, LServer, _LJID, Item) -> ejabberd_riak:put(Item, roster_schema(), @@ -104,11 +87,11 @@ del_roster(LUser, LServer, LJID) -> read_subscription_and_groups(LUser, LServer, LJID) -> case ejabberd_riak:get(roster, roster_schema(), {LUser, LServer, LJID}) of - {ok, #roster{subscription = Subscription, - groups = Groups}} -> - {Subscription, Groups}; - _ -> - error + {ok, #roster{subscription = Subscription, + groups = Groups}} -> + {ok, {Subscription, Groups}}; + _ -> + error end. create_roster(#roster{us = {LUser, LServer}} = RItem) -> diff --git a/src/mod_roster_sql.erl b/src/mod_roster_sql.erl index 112c13a72..7c516568c 100644 --- a/src/mod_roster_sql.erl +++ b/src/mod_roster_sql.erl @@ -30,10 +30,9 @@ %% API -export([init/2, read_roster_version/2, write_roster_version/4, - get_roster/2, get_roster_by_jid/3, - roster_subscribe/4, get_roster_by_jid_with_groups/3, - remove_user/2, update_roster/4, del_roster/3, transaction/2, - read_subscription_and_groups/3, get_only_items/2, + get_roster/2, get_roster_item/3, roster_subscribe/4, + read_subscription_and_groups/3, remove_user/2, + update_roster/4, del_roster/3, transaction/2, import/3, export/1, raw_to_record/2]). -include("mod_roster.hrl"). @@ -48,7 +47,7 @@ init(_Host, _Opts) -> read_roster_version(LUser, LServer) -> case sql_queries:get_roster_version(LServer, LUser) of - {selected, [{Version}]} -> Version; + {selected, [{Version}]} -> {ok, Version}; {selected, []} -> error end. @@ -77,55 +76,22 @@ get_roster(LUser, LServer) -> dict:append(J, G, Acc) end, dict:new(), JIDGroups), - lists:flatmap( - fun(I) -> - case raw_to_record(LServer, I) of - %% Bad JID in database: - error -> []; - R -> - SJID = jid:encode(R#roster.jid), - Groups = case dict:find(SJID, GroupsDict) of - {ok, Gs} -> Gs; - error -> [] - end, - [R#roster{groups = Groups}] - end - end, Items); + {ok, lists:flatmap( + fun(I) -> + case raw_to_record(LServer, I) of + %% Bad JID in database: + error -> []; + R -> + SJID = jid:encode(R#roster.jid), + Groups = case dict:find(SJID, GroupsDict) of + {ok, Gs} -> Gs; + error -> [] + end, + [R#roster{groups = Groups}] + end + end, Items)}; _ -> - [] - end. - -get_roster_by_jid(LUser, LServer, LJID) -> - {selected, Res} = - sql_queries:get_roster_by_jid(LServer, LUser, jid:encode(LJID)), - case Res of - [] -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; - [I] -> - R = raw_to_record(LServer, I), - case R of - %% Bad JID in database: - error -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; - _ -> - R#roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID, name = <<"">>} - end - end. - -get_only_items(LUser, LServer) -> - case catch sql_queries:get_roster(LServer, LUser) of - {selected, Is} when is_list(Is) -> - lists:flatmap( - fun(I) -> - case raw_to_record(LServer, I) of - error -> []; - R -> [R] - end - end, Is); - _ -> [] + error end. roster_subscribe(_LUser, _LServer, _LJID, Item) -> @@ -135,14 +101,13 @@ roster_subscribe(_LUser, _LServer, _LJID, Item) -> transaction(LServer, F) -> ejabberd_sql:sql_transaction(LServer, F). -get_roster_by_jid_with_groups(LUser, LServer, LJID) -> +get_roster_item(LUser, LServer, LJID) -> SJID = jid:encode(LJID), case sql_queries:get_roster_by_jid(LServer, LUser, SJID) of {selected, [I]} -> case raw_to_record(LServer, I) of error -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID}; + error; R -> Groups = case sql_queries:get_roster_groups(LServer, LUser, SJID) of @@ -150,16 +115,15 @@ get_roster_by_jid_with_groups(LUser, LServer, LJID) -> [JGrp || {JGrp} <- JGrps]; _ -> [] end, - R#roster{groups = Groups} + {ok, R#roster{groups = Groups}} end; {selected, []} -> - #roster{usj = {LUser, LServer, LJID}, - us = {LUser, LServer}, jid = LJID} + error end. remove_user(LUser, LServer) -> sql_queries:del_user_roster_t(LServer, LUser), - {atomic, ok}. + ok. update_roster(LUser, LServer, LJID, Item) -> SJID = jid:encode(LJID), @@ -194,7 +158,7 @@ read_subscription_and_groups(LUser, LServer, LJID) -> [JGrp || {JGrp} <- JGrps]; _ -> [] end, - {Subscription, Groups}; + {ok, {Subscription, Groups}}; _ -> error end. diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index c25b13f66..5f95266b8 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -31,7 +31,7 @@ -export([start/2, stop/1, reload/3, export/1, import_info/0, webadmin_menu/3, webadmin_page/3, - get_user_roster/2, c2s_session_opened/1, + get_user_roster/2, get_jid_info/4, import/5, process_item/2, import_start/2, in_subscription/6, out_subscription/4, c2s_self_presence/1, unset_presence/4, register_user/2, remove_user/2, @@ -54,8 +54,6 @@ -include("mod_shared_roster.hrl"). --define(SETS, gb_sets). - -type group_options() :: [{atom(), any()}]. -callback init(binary(), gen_mod:opts()) -> any(). -callback import(binary(), binary(), [binary()]) -> ok. @@ -86,8 +84,6 @@ start(Host, Opts) -> ?MODULE, in_subscription, 30), ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:add(c2s_session_opened, Host, - ?MODULE, c2s_session_opened, 70), ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70), ejabberd_hooks:add(roster_process_item, Host, ?MODULE, @@ -112,8 +108,6 @@ stop(Host) -> ?MODULE, in_subscription, 30), ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:delete(c2s_session_opened, - Host, ?MODULE, c2s_session_opened, 70), ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70), ejabberd_hooks:delete(roster_process_item, Host, @@ -300,23 +294,6 @@ set_item(User, Server, Resource, Item) -> items = [mod_roster:encode_item(Item)]}]}, ejabberd_router:route(ResIQ). -c2s_session_opened(#{jid := #jid{luser = LUser, lserver = LServer}, - pres_f := PresF, pres_t := PresT} = State) -> - US = {LUser, LServer}, - DisplayedGroups = get_user_displayed_groups(US), - SRUsers = lists:flatmap(fun(Group) -> - get_group_users(LServer, Group) - end, - DisplayedGroups), - PresBoth = lists:foldl( - fun({U, S, _}, Acc) -> - ?SETS:add_element({U, S, <<"">>}, Acc); - ({U, S}, Acc) -> - ?SETS:add_element({U, S, <<"">>}, Acc) - end, ?SETS:new(), SRUsers), - State#{pres_f => ?SETS:union(PresBoth, PresF), - pres_t => ?SETS:union(PresBoth, PresT)}. - -spec get_jid_info({subscription(), [binary()]}, binary(), binary(), jid()) -> {subscription(), [binary()]}. get_jid_info({Subscription, Groups}, User, Server, diff --git a/src/mod_shared_roster_ldap.erl b/src/mod_shared_roster_ldap.erl index 24bd3233c..30cd44568 100644 --- a/src/mod_shared_roster_ldap.erl +++ b/src/mod_shared_roster_ldap.erl @@ -39,7 +39,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([get_user_roster/2, c2s_session_opened/1, +-export([get_user_roster/2, get_jid_info/4, process_item/2, in_subscription/6, out_subscription/4, mod_opt_type/1, opt_type/1, depends/2, transform_module_options/1]). @@ -50,7 +50,6 @@ -include("mod_roster.hrl"). -include("eldap.hrl"). --define(SETS, gb_sets). -define(USER_CACHE, shared_roster_ldap_user_cache). -define(GROUP_CACHE, shared_roster_ldap_group_cache). -define(LDAP_SEARCH_TIMEOUT, 5). %% Timeout for LDAP search queries in seconds @@ -160,23 +159,6 @@ process_item(RosterItem, _Host) -> _ -> RosterItem#roster{subscription = both, ask = none} end. -c2s_session_opened(#{jid := #jid{luser = LUser, lserver = LServer}, - pres_f := PresF, pres_t := PresT} = State) -> - US = {LUser, LServer}, - DisplayedGroups = get_user_displayed_groups(US), - SRUsers = lists:flatmap(fun(Group) -> - get_group_users(LServer, Group) - end, - DisplayedGroups), - PresBoth = lists:foldl( - fun({U, S, _}, Acc) -> - ?SETS:add_element({U, S, <<"">>}, Acc); - ({U, S}, Acc) -> - ?SETS:add_element({U, S, <<"">>}, Acc) - end, ?SETS:new(), SRUsers), - State#{pres_f => ?SETS:union(PresBoth, PresF), - pres_t => ?SETS:union(PresBoth, PresT)}. - -spec get_jid_info({subscription(), [binary()]}, binary(), binary(), jid()) -> {subscription(), [binary()]}. get_jid_info({Subscription, Groups}, User, Server, @@ -245,8 +227,6 @@ init([Host, Opts]) -> ?MODULE, in_subscription, 30), ejabberd_hooks:add(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:add(c2s_session_opened, Host, - ?MODULE, c2s_session_opened, 70), ejabberd_hooks:add(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70), ejabberd_hooks:add(roster_process_item, Host, ?MODULE, @@ -276,8 +256,6 @@ terminate(_Reason, State) -> ?MODULE, in_subscription, 30), ejabberd_hooks:delete(roster_out_subscription, Host, ?MODULE, out_subscription, 30), - ejabberd_hooks:delete(c2s_session_opened, - Host, ?MODULE, c2s_session_opened, 70), ejabberd_hooks:delete(roster_get_jid_info, Host, ?MODULE, get_jid_info, 70), ejabberd_hooks:delete(roster_process_item, Host, |