aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2017-05-17 14:47:35 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2017-05-17 14:47:35 +0300
commitf782955c069f1091cd56cc9d139ec0b0e2d62780 (patch)
treecbde7d13046bdc4bdc302511db04331b69d812e0 /src
parentFix use_cache/1 callback (diff)
Implement cache for roster
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_c2s.erl240
-rw-r--r--src/ejabberd_sm.erl2
-rw-r--r--src/mod_block_strangers.erl55
-rw-r--r--src/mod_caps.erl4
-rw-r--r--src/mod_last.erl5
-rw-r--r--src/mod_mam.erl52
-rw-r--r--src/mod_pubsub.erl48
-rw-r--r--src/mod_roster.erl554
-rw-r--r--src/mod_roster_mnesia.erl47
-rw-r--r--src/mod_roster_riak.erl51
-rw-r--r--src/mod_roster_sql.erl86
-rw-r--r--src/mod_shared_roster.erl25
-rw-r--r--src/mod_shared_roster_ldap.erl24
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,