25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-28 16:34:13 +01:00

Don't lose carbons on presence change or session resumption

This commit is contained in:
Evgeny Khramtsov 2018-12-10 11:53:27 +03:00
parent f02f44ad3f
commit 6cd8d1025c
3 changed files with 77 additions and 28 deletions

View File

@ -708,13 +708,11 @@ process_presence_out(#{lserver := LServer, jid := JID,
end. end.
-spec process_self_presence(state(), presence()) -> state(). -spec process_self_presence(state(), presence()) -> state().
process_self_presence(#{ip := IP, conn := Conn, lserver := LServer, process_self_presence(#{lserver := LServer, sid := SID,
auth_module := AuthMod, sid := SID,
user := U, server := S, resource := R} = State, user := U, server := S, resource := R} = State,
#presence{type = unavailable} = Pres) -> #presence{type = unavailable} = Pres) ->
Status = xmpp:get_text(Pres#presence.status), Status = xmpp:get_text(Pres#presence.status),
Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthMod}], ejabberd_sm:unset_presence(SID, U, S, R, Status),
ejabberd_sm:unset_presence(SID, U, S, R, Status, Info),
{Pres1, State1} = ejabberd_hooks:run_fold( {Pres1, State1} = ejabberd_hooks:run_fold(
c2s_self_presence, LServer, {Pres, State}, []), c2s_self_presence, LServer, {Pres, State}, []),
State2 = broadcast_presence_unavailable(State1, Pres1), State2 = broadcast_presence_unavailable(State1, Pres1),
@ -732,13 +730,11 @@ process_self_presence(#{lserver := LServer} = State,
process_self_presence(State, _Pres) -> process_self_presence(State, _Pres) ->
State. State.
-spec update_priority(state(), presence()) -> ok. -spec update_priority(state(), presence()) -> ok | {error, notfound}.
update_priority(#{ip := IP, conn := Conn, auth_module := AuthMod, update_priority(#{sid := SID, user := U, server := S, resource := R},
sid := SID, user := U, server := S, resource := R},
Pres) -> Pres) ->
Priority = get_priority_from_presence(Pres), Priority = get_priority_from_presence(Pres),
Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthMod}], ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres).
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres, Info).
-spec broadcast_presence_unavailable(state(), presence()) -> state(). -spec broadcast_presence_unavailable(state(), presence()) -> state().
broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) -> broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) ->

View File

@ -47,8 +47,8 @@
disconnect_removed_user/2, disconnect_removed_user/2,
get_user_resources/2, get_user_resources/2,
get_user_present_resources/2, get_user_present_resources/2,
set_presence/7, set_presence/6,
unset_presence/6, unset_presence/5,
close_session_unset_presence/5, close_session_unset_presence/5,
dirty_get_sessions_list/0, dirty_get_sessions_list/0,
dirty_get_my_sessions_list/0, dirty_get_my_sessions_list/0,
@ -307,26 +307,48 @@ del_user_info(User, Server, Resource, Key) ->
end. end.
-spec set_presence(sid(), binary(), binary(), binary(), -spec set_presence(sid(), binary(), binary(), binary(),
prio(), presence(), info()) -> ok. prio(), presence()) -> ok | {error, notfound}.
set_presence(SID, User, Server, Resource, Priority, set_presence(SID, User, Server, Resource, Priority, Presence) ->
Presence, Info) -> LUser = jid:nodeprep(User),
set_session(SID, User, Server, Resource, Priority, LServer = jid:nameprep(Server),
Info), LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer),
case get_sessions(Mod, LUser, LServer, LResource) of
[] -> {error, notfound};
Ss ->
case lists:keyfind(SID, 1, Ss) of
#session{info = Info} ->
set_session(SID, User, Server, Resource, Priority, Info),
ejabberd_hooks:run(set_presence_hook, ejabberd_hooks:run(set_presence_hook,
jid:nameprep(Server), LServer,
[User, Server, Resource, Presence]). [User, Server, Resource, Presence]);
false ->
{error, notfound}
end
end.
-spec unset_presence(sid(), binary(), binary(), -spec unset_presence(sid(), binary(), binary(),
binary(), binary(), info()) -> ok. binary(), binary()) -> ok | {error, notfound}.
unset_presence(SID, User, Server, Resource, Status, unset_presence(SID, User, Server, Resource, Status) ->
Info) -> LUser = jid:nodeprep(User),
set_session(SID, User, Server, Resource, undefined, LServer = jid:nameprep(Server),
Info), LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer),
case get_sessions(Mod, LUser, LServer, LResource) of
[] -> {error, notfound};
Ss ->
case lists:keyfind(SID, 1, Ss) of
#session{info = Info} ->
set_session(SID, User, Server, Resource, undefined, Info),
ejabberd_hooks:run(unset_presence_hook, ejabberd_hooks:run(unset_presence_hook,
jid:nameprep(Server), LServer,
[User, Server, Resource, Status]). [User, Server, Resource, Status]);
false ->
{error, notfound}
end
end.
-spec close_session_unset_presence(sid(), binary(), binary(), -spec close_session_unset_presence(sid(), binary(), binary(),
binary(), binary()) -> ok. binary(), binary()) -> ok.

View File

@ -38,6 +38,7 @@
iq_handler/1, disco_features/5, iq_handler/1, disco_features/5,
is_carbon_copy/1, mod_opt_type/1, depends/2, is_carbon_copy/1, mod_opt_type/1, depends/2,
mod_options/1]). mod_options/1]).
-export([c2s_copy_session/2, c2s_session_opened/1, c2s_session_resumed/1]).
%% For debugging purposes %% For debugging purposes
-export([list/2]). -export([list/2]).
@ -45,6 +46,7 @@
-include("xmpp.hrl"). -include("xmpp.hrl").
-type direction() :: sent | received. -type direction() :: sent | received.
-type c2s_state() :: ejabberd_c2s:state().
-spec is_carbon_copy(stanza()) -> boolean(). -spec is_carbon_copy(stanza()) -> boolean().
is_carbon_copy(#message{meta = #{carbon_copy := true}}) -> is_carbon_copy(#message{meta = #{carbon_copy := true}}) ->
@ -57,6 +59,9 @@ start(Host, _Opts) ->
%% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90) %% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90)
ejabberd_hooks:add(user_send_packet,Host, ?MODULE, user_send_packet, 89), ejabberd_hooks:add(user_send_packet,Host, ?MODULE, user_send_packet, 89),
ejabberd_hooks:add(user_receive_packet,Host, ?MODULE, user_receive_packet, 89), ejabberd_hooks:add(user_receive_packet,Host, ?MODULE, user_receive_packet, 89),
ejabberd_hooks:add(c2s_copy_session, Host, ?MODULE, c2s_copy_session, 50),
ejabberd_hooks:add(c2s_session_resumed, Host, ?MODULE, c2s_session_resumed, 50),
ejabberd_hooks:add(c2s_session_opened, Host, ?MODULE, c2s_session_opened, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2, ?MODULE, iq_handler). gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2, ?MODULE, iq_handler).
stop(Host) -> stop(Host) ->
@ -64,7 +69,10 @@ stop(Host) ->
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50), ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50),
%% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90) %% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90)
ejabberd_hooks:delete(user_send_packet,Host, ?MODULE, user_send_packet, 89), ejabberd_hooks:delete(user_send_packet,Host, ?MODULE, user_send_packet, 89),
ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89). ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89),
ejabberd_hooks:delete(c2s_copy_session, Host, ?MODULE, c2s_copy_session, 50),
ejabberd_hooks:delete(c2s_session_resumed, Host, ?MODULE, c2s_session_resumed, 50),
ejabberd_hooks:delete(c2s_session_opened, Host, ?MODULE, c2s_session_opened, 50).
reload(_Host, _NewOpts, _OldOpts) -> reload(_Host, _NewOpts, _OldOpts) ->
ok. ok.
@ -123,6 +131,29 @@ user_receive_packet({Packet, #{jid := JID} = C2SState}) ->
Pkt -> {Pkt, C2SState} Pkt -> {Pkt, C2SState}
end. end.
-spec c2s_copy_session(c2s_state(), c2s_state()) -> c2s_state().
c2s_copy_session(State, #{user := U, server := S, resource := R}) ->
case ejabberd_sm:get_user_info(U, S, R) of
offline -> State;
Info ->
case lists:keyfind(carboncopy, 1, Info) of
{_, CC} -> State#{carboncopy => CC};
false -> State
end
end.
-spec c2s_session_resumed(c2s_state()) -> c2s_state().
c2s_session_resumed(#{user := U, server := S, resource := R,
carboncopy := CC} = State) ->
ejabberd_sm:set_user_info(U, S, R, carboncopy, CC),
maps:remove(carboncopy, State);
c2s_session_resumed(State) ->
State.
-spec c2s_session_opened(c2s_state()) -> c2s_state().
c2s_session_opened(State) ->
maps:remove(carboncopy, State).
% Modified from original version: % Modified from original version:
% - registered to the user_send_packet hook, to be called only once even for multicast % - registered to the user_send_packet hook, to be called only once even for multicast
% - do not support "private" message mode, and do not modify the original packet in any way % - do not support "private" message mode, and do not modify the original packet in any way