25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-10-19 15:32:08 +02:00

Unconditionally send presence unavailable to all pres_a recipient

Previously we only send that presence to direct presence recipients if
client also sent general self presence (without to attribute).

This should help with issue #3245
This commit is contained in:
Paweł Chmielowski 2020-05-07 10:40:08 +02:00
parent 41b06cb79e
commit 51e45516a4

View File

@ -293,17 +293,17 @@ process_terminated(#{sid := SID, socket := Socket,
Status = format_reason(State, Reason), Status = format_reason(State, Reason),
?INFO_MSG("(~ts) Closing c2s session for ~ts: ~ts", ?INFO_MSG("(~ts) Closing c2s session for ~ts: ~ts",
[xmpp_socket:pp(Socket), jid:encode(JID), Status]), [xmpp_socket:pp(Socket), jid:encode(JID), Status]),
Pres = #presence{type = unavailable,
from = JID,
to = jid:remove_resource(JID)},
State1 = case maps:is_key(pres_last, State) of State1 = case maps:is_key(pres_last, State) of
true -> true ->
Pres = #presence{type = unavailable,
from = JID,
to = jid:remove_resource(JID)},
ejabberd_sm:close_session_unset_presence(SID, U, S, R, ejabberd_sm:close_session_unset_presence(SID, U, S, R,
Status), Status),
broadcast_presence_unavailable(State, Pres); broadcast_presence_unavailable(State, Pres, true);
false -> false ->
ejabberd_sm:close_session(SID, U, S, R), ejabberd_sm:close_session(SID, U, S, R),
State broadcast_presence_unavailable(State, Pres, false)
end, end,
bounce_message_queue(SID, JID), bounce_message_queue(SID, JID),
State1; State1;
@ -734,7 +734,7 @@ process_self_presence(#{lserver := LServer, sid := SID,
_ = ejabberd_sm:unset_presence(SID, U, S, R, Status), _ = ejabberd_sm:unset_presence(SID, U, S, R, Status),
{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, true),
maps:remove(pres_last, maps:remove(pres_timestamp, State2)); maps:remove(pres_last, maps:remove(pres_timestamp, State2));
process_self_presence(#{lserver := LServer} = State, process_self_presence(#{lserver := LServer} = State,
#presence{type = available} = Pres) -> #presence{type = available} = Pres) ->
@ -755,28 +755,39 @@ update_priority(#{sid := SID, user := U, server := S, resource := R},
Priority = get_priority_from_presence(Pres), Priority = get_priority_from_presence(Pres),
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres). ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres).
-spec broadcast_presence_unavailable(state(), presence()) -> state(). -spec broadcast_presence_unavailable(state(), presence(), boolean()) -> state().
broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) -> broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres,
BroadcastToRoster) ->
#jid{luser = LUser, lserver = LServer} = JID, #jid{luser = LUser, lserver = LServer} = JID,
BareJID = jid:remove_resource(JID), BareJID = jid:tolower(jid:remove_resource(JID)),
Items1 = ejabberd_hooks:run_fold(roster_get, LServer, Items1 = case BroadcastToRoster of
[], [{LUser, LServer}]), true ->
Roster = ejabberd_hooks:run_fold(roster_get, LServer,
[], [{LUser, LServer}]),
lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, Acc)
when Sub == both; Sub == from ->
maps:put(LJID, 1, Acc);
(_, Acc) ->
Acc
end, #{BareJID => 1}, Roster);
_ ->
#{BareJID => 1}
end,
Items2 = ?SETS:fold( Items2 = ?SETS:fold(
fun(LJID, Items) -> fun(LJID, Acc) ->
[#roster{jid = LJID, subscription = from}|Items] maps:put(LJID, 1, Acc)
end, Items1, PresA), end, Items1, PresA),
JIDs = lists:foldl(
fun(#roster{jid = LJID, subscription = Sub}, Tos) JIDs = lists:filtermap(
when Sub == both orelse Sub == from -> fun(LJid) ->
To = jid:make(LJID), To = jid:make(LJid),
P = xmpp:set_to(Pres, jid:make(LJID)), P = xmpp:set_to(Pres, To),
case privacy_check_packet(State, P, out) of case privacy_check_packet(State, P, out) of
allow -> [To|Tos]; allow -> {true, To};
deny -> Tos deny -> false
end; end
(_, Tos) -> end, maps:keys(Items2)),
Tos
end, [BareJID], Items2),
route_multiple(State, JIDs, Pres), route_multiple(State, JIDs, Pres),
State#{pres_a => ?SETS:new()}. State#{pres_a => ?SETS:new()}.