25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-22 17:28:25 +01:00

Link MUC subscription to bare JID

This commit is contained in:
Evgeniy Khramtsov 2016-09-07 10:33:37 +03:00
parent 1edca899ff
commit 3803a8de3c
2 changed files with 148 additions and 198 deletions

View File

@ -77,11 +77,15 @@
jid :: jid(),
nick :: binary(),
role :: role(),
is_subscriber = false :: boolean(),
subscriptions = [] :: [binary()],
%%is_subscriber = false :: boolean(),
%%subscriptions = [] :: [binary()],
last_presence :: xmlel()
}).
-record(subscriber, {jid :: jid(),
nick = <<>> :: binary(),
nodes = [] :: [binary()]}).
-record(activity,
{
message_time = 0 :: integer(),
@ -101,6 +105,7 @@
jid = #jid{} :: jid(),
config = #config{} :: config(),
users = (?DICT):new() :: ?TDICT,
subscribers = (?DICT):new() :: ?TDICT,
last_voice_request_time = treap:empty() :: treap:treap(),
robots = (?DICT):new() :: ?TDICT,
nicks = (?DICT):new() :: ?TDICT,

View File

@ -678,7 +678,7 @@ handle_event({service_message, Msg}, _StateName,
children = [{xmlcdata, Msg}]}]},
send_wrapped_multiple(
StateData#state.jid,
StateData#state.users,
get_users_and_subscribers(StateData),
MessagePkt,
?NS_MUCSUB_NODES_MESSAGES,
StateData),
@ -750,12 +750,8 @@ handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData
NSD = process_item_change(Item, StateData, UJID),
{reply, {ok, NSD}, StateName, NSD};
handle_sync_event(get_subscribers, _From, StateName, StateData) ->
JIDs = dict:fold(
fun(_, #user{is_subscriber = true, jid = J}, Acc) ->
[J|Acc];
(_, _, Acc) ->
Acc
end, [], StateData#state.users),
JIDs = lists:map(fun jid:make/1,
?DICT:fetch_keys(StateData#state.subscribers)),
{reply, {ok, JIDs}, StateName, StateData};
handle_sync_event({muc_subscribe, From, Nick, Nodes}, _From,
StateName, StateData) ->
@ -936,7 +932,7 @@ terminate(Reason, _StateName, StateData) ->
end,
tab_remove_online_user(LJID, StateData)
end,
[], StateData#state.users),
[], get_users_and_subscribers(StateData)),
add_to_log(room_existence, stopped, StateData),
mod_muc:room_destroyed(StateData#state.host, StateData#state.room, self(),
StateData#state.server_host),
@ -953,11 +949,12 @@ process_groupchat_message(From,
#xmlel{name = <<"message">>, attrs = Attrs} = Packet,
StateData) ->
Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs),
case is_user_online(From, StateData) orelse
IsSubscriber = is_subscriber(From, StateData),
case is_user_online(From, StateData) orelse IsSubscriber orelse
is_user_allowed_message_nonparticipant(From, StateData)
of
true ->
{FromNick, Role, IsSubscriber} = get_participant_data(From, StateData),
{FromNick, Role} = get_participant_data(From, StateData),
if (Role == moderator) or (Role == participant) or IsSubscriber or
((StateData#state.config)#config.moderated == false) ->
Subject = check_subject(Packet),
@ -1000,7 +997,7 @@ process_groupchat_message(From,
end,
send_wrapped_multiple(
jid:replace_resource(StateData#state.jid, FromNick),
StateData#state.users,
get_users_and_subscribers(StateData),
NewPacket, Node, NewStateData1),
NewStateData2 = case has_body_or_subject(NewPacket) of
true ->
@ -1068,9 +1065,9 @@ get_participant_data(From, StateData) ->
case (?DICT):find(jid:tolower(From),
StateData#state.users)
of
{ok, #user{nick = FromNick, role = Role, is_subscriber = IsSubscriber}} ->
{FromNick, Role, IsSubscriber};
error -> {<<"">>, moderator, false}
{ok, #user{nick = FromNick, role = Role}} ->
{FromNick, Role};
error -> {<<"">>, moderator}
end.
process_presence(From, Nick,
@ -1078,7 +1075,6 @@ process_presence(From, Nick,
StateData) ->
Type0 = fxml:get_attr_s(<<"type">>, Attrs0),
IsOnline = is_user_online(From, StateData),
IsSubscriber = is_subscriber(From, StateData),
if Type0 == <<"">>;
IsOnline and ((Type0 == <<"unavailable">>) or (Type0 == <<"error">>)) ->
case ejabberd_hooks:run_fold(muc_filter_presence,
@ -1115,7 +1111,7 @@ process_presence(From, Nick,
Status_el ->
fxml:get_tag_cdata(Status_el)
end,
remove_online_user(From, NewState, IsSubscriber, Reason);
remove_online_user(From, NewState, Reason);
<<"error">> ->
ErrorText = <<"It is not allowed to send error messages to the"
" room. The participant (~s) has sent an error "
@ -1172,27 +1168,15 @@ process_presence(From, Nick,
From, Err),
StateData;
_ ->
case is_initial_presence(From, StateData) of
true ->
subscriber_becomes_available(
From, Nick, Packet, StateData);
false ->
change_nick(From, Nick, StateData)
end
change_nick(From, Nick, StateData)
end;
_NotNickChange ->
case is_initial_presence(From, StateData) of
true ->
subscriber_becomes_available(
From, Nick, Packet, StateData);
false ->
Stanza = maybe_strip_status_from_presence(
From, Packet, StateData),
NewState = add_user_presence(From, Stanza,
StateData),
send_new_presence(From, NewState, StateData),
NewState
end
Stanza = maybe_strip_status_from_presence(
From, Packet, StateData),
NewState = add_user_presence(From, Stanza,
StateData),
send_new_presence(From, NewState, StateData),
NewState
end
end
end,
@ -1210,22 +1194,10 @@ maybe_strip_status_from_presence(From, Packet, StateData) ->
_Allowed -> Packet
end.
subscriber_becomes_available(From, Nick, Packet, StateData) ->
Stanza = maybe_strip_status_from_presence(From, Packet, StateData),
State1 = add_user_presence(From, Stanza, StateData),
Aff = get_affiliation(From, State1),
Role = get_default_role(Aff, State1),
State2 = set_role(From, Role, State1),
State3 = set_nick(From, Nick, State2),
tab_add_online_user(From, StateData),
send_existing_presences(From, State3),
send_initial_presence(From, State3, StateData),
State3.
close_room_if_temporary_and_empty(StateData1) ->
case not (StateData1#state.config)#config.persistent
andalso (?DICT):to_list(StateData1#state.users) == []
of
andalso (?DICT):size(StateData1#state.users) == 0
andalso (?DICT):size(StateData1#state.subscribers) == 0 of
true ->
?INFO_MSG("Destroyed MUC room ~s because it's temporary "
"and empty",
@ -1235,18 +1207,39 @@ close_room_if_temporary_and_empty(StateData1) ->
_ -> {next_state, normal_state, StateData1}
end.
get_users_and_subscribers(StateData) ->
OnlineSubscribers = ?DICT:fold(
fun(LJID, _, Acc) ->
LBareJID = jid:remove_resource(LJID),
case is_subscriber(LBareJID, StateData) of
true ->
?SETS:add_element(LBareJID, Acc);
false ->
Acc
end
end, ?SETS:new(), StateData#state.users),
?DICT:fold(
fun(LBareJID, #subscriber{nick = Nick}, Acc) ->
case ?SETS:is_element(LBareJID, OnlineSubscribers) of
false ->
?DICT:store(LBareJID,
#user{jid = jid:make(LBareJID),
nick = Nick,
role = none,
last_presence = undefined},
Acc);
true ->
Acc
end
end, StateData#state.users, StateData#state.subscribers).
is_user_online(JID, StateData) ->
LJID = jid:tolower(JID),
(?DICT):is_key(LJID, StateData#state.users).
is_subscriber(JID, StateData) ->
LJID = jid:tolower(JID),
case (?DICT):find(LJID, StateData#state.users) of
{ok, #user{is_subscriber = IsSubscriber}} ->
IsSubscriber;
_ ->
false
end.
LJID = jid:tolower(jid:remove_resource(JID)),
(?DICT):is_key(LJID, StateData#state.subscribers).
%% Check if the user is occupant of the room, or at least is an admin or owner.
is_occupant_or_admin(JID, StateData) ->
@ -1423,7 +1416,6 @@ make_reason(Packet, From, StateData, Reason1) ->
iolist_to_binary(io_lib:format(Reason1, [FromNick, Condition])).
expulse_participant(Packet, From, StateData, Reason1) ->
IsSubscriber = is_subscriber(From, StateData),
Reason2 = make_reason(Packet, From, StateData, Reason1),
NewState = add_user_presence_un(From,
#xmlel{name = <<"presence">>,
@ -1438,7 +1430,7 @@ expulse_participant(Packet, From, StateData, Reason1) ->
Reason2}]}]},
StateData),
send_new_presence(From, NewState, StateData),
remove_online_user(From, NewState, IsSubscriber).
remove_online_user(From, NewState).
set_affiliation(JID, Affiliation, StateData) ->
set_affiliation(JID, Affiliation, StateData, <<"">>).
@ -1718,8 +1710,7 @@ prepare_room_queue(StateData) ->
{empty, _} -> StateData
end.
update_online_user(JID, #user{nick = Nick, subscriptions = Nodes,
is_subscriber = IsSubscriber} = User, StateData) ->
update_online_user(JID, #user{nick = Nick} = User, StateData) ->
LJID = jid:tolower(JID),
Nicks1 = case (?DICT):find(LJID, StateData#state.users) of
{ok, #user{nick = OldNick}} ->
@ -1738,9 +1729,7 @@ update_online_user(JID, #user{nick = Nick, subscriptions = Nodes,
[LJID], Nicks1),
Users = (?DICT):update(LJID,
fun(U) ->
U#user{nick = Nick,
subscriptions = Nodes,
is_subscriber = IsSubscriber}
U#user{nick = Nick}
end, User, StateData#state.users),
NewStateData = StateData#state{users = Users, nicks = Nicks},
case {?DICT:find(LJID, StateData#state.users),
@ -1752,32 +1741,26 @@ update_online_user(JID, #user{nick = Nick, subscriptions = Nodes,
end,
NewStateData.
add_online_user(JID, Nick, Role, IsSubscriber, Nodes, StateData) ->
User = #user{jid = JID, nick = Nick, role = Role,
is_subscriber = IsSubscriber, subscriptions = Nodes},
StateData1 = update_online_user(JID, User, StateData),
if IsSubscriber ->
store_room(StateData1);
true ->
ok
end,
StateData1.
set_subscriber(JID, Nick, Nodes, StateData) ->
BareJID = jid:remove_resource(JID),
Subscribers = ?DICT:store(jid:tolower(BareJID),
#subscriber{jid = BareJID,
nick = Nick,
nodes = Nodes},
StateData#state.subscribers),
NewStateData = StateData#state{subscribers = Subscribers},
store_room(NewStateData),
NewStateData.
remove_online_user(JID, StateData, IsSubscriber) ->
remove_online_user(JID, StateData, IsSubscriber, <<"">>).
add_online_user(JID, Nick, Role, StateData) ->
tab_add_online_user(JID, StateData),
User = #user{jid = JID, nick = Nick, role = Role},
update_online_user(JID, User, StateData).
remove_online_user(JID, StateData, _IsSubscriber = true, _Reason) ->
LJID = jid:tolower(JID),
Users = case (?DICT):find(LJID, StateData#state.users) of
{ok, U} ->
(?DICT):store(LJID, U#user{last_presence = undefined},
StateData#state.users);
error ->
StateData#state.users
end,
tab_remove_online_user(JID, StateData),
StateData#state{users = Users};
remove_online_user(JID, StateData, _IsSubscriber, Reason) ->
remove_online_user(JID, StateData) ->
remove_online_user(JID, StateData, <<"">>).
remove_online_user(JID, StateData, Reason) ->
LJID = jid:tolower(JID),
{ok, #user{nick = Nick}} = (?DICT):find(LJID,
StateData#state.users),
@ -2032,9 +2015,7 @@ add_new_user(From, Nick,
NewState = add_user_presence(
From, Packet,
add_online_user(From, Nick, Role,
IsSubscribeRequest,
Nodes, StateData)),
tab_add_online_user(From, NewState),
StateData)),
send_existing_presences(From, NewState),
send_initial_presence(From, NewState, StateData),
Shift = count_stanza_shift(Nick, Els, NewState),
@ -2044,9 +2025,7 @@ add_new_user(From, Nick,
end,
NewState;
true ->
add_online_user(From, Nick, none,
IsSubscribeRequest,
Nodes, StateData)
set_subscriber(From, Nick, Nodes, StateData)
end,
ResultState =
case NewStateData#state.just_created of
@ -2286,15 +2265,6 @@ presence_broadcast_allowed(JID, StateData) ->
Role = get_role(JID, StateData),
lists:member(Role, (StateData#state.config)#config.presence_broadcast).
is_initial_presence(From, StateData) ->
LJID = jid:tolower(From),
case (?DICT):find(LJID, StateData#state.users) of
{ok, #user{last_presence = Pres}} when Pres /= undefined ->
false;
_ ->
true
end.
send_initial_presence(NJID, StateData, OldStateData) ->
send_new_presence1(NJID, <<"">>, true, StateData, OldStateData).
@ -2388,7 +2358,7 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
true ->
[{LNJID, UserInfo}];
false ->
(?DICT):to_list(StateData#state.users)
(?DICT):to_list(get_users_and_subscribers(StateData))
end,
lists:foreach(
fun({LUJID, Info}) ->
@ -2444,7 +2414,7 @@ send_new_presence1(NJID, Reason, IsInitialPresence, StateData, OldStateData) ->
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
Info#user.jid, Packet, Node1, StateData),
Type = fxml:get_tag_attr_s(<<"type">>, Packet),
IsSubscriber = Info#user.is_subscriber,
IsSubscriber = is_subscriber(Info#user.jid, StateData),
IsOccupant = Info#user.last_presence /= undefined,
if (IsSubscriber and not IsOccupant) and
(IsInitialPresence or (Type == <<"unavailable">>)) ->
@ -2668,19 +2638,20 @@ send_nick_changing(JID, OldNick, StateData,
(_) ->
ok
end,
(?DICT):to_list(StateData#state.users)).
?DICT:to_list(get_users_and_subscribers(StateData))).
maybe_send_affiliation(JID, Affiliation, StateData) ->
LJID = jid:tolower(JID),
Users = get_users_and_subscribers(StateData),
IsOccupant = case LJID of
{LUser, LServer, <<"">>} ->
not (?DICT):is_empty(
(?DICT):filter(fun({U, S, _}, _) ->
U == LUser andalso
S == LServer
end, StateData#state.users));
end, Users));
{_LUser, _LServer, _LResource} ->
(?DICT):is_key(LJID, StateData#state.users)
(?DICT):is_key(LJID, Users)
end,
case IsOccupant of
true ->
@ -2701,19 +2672,19 @@ send_affiliation(LJID, Affiliation, StateData) ->
children =
[#xmlel{name = <<"item">>,
attrs = ItemAttrs}]}]},
Users = get_users_and_subscribers(StateData),
Recipients = case (StateData#state.config)#config.anonymous of
true ->
(?DICT):filter(fun(_, #user{role = moderator}) ->
true;
(_, _) ->
false
end, StateData#state.users);
end, Users);
false ->
StateData#state.users
Users
end,
send_multiple(StateData#state.jid,
StateData#state.server_host,
Recipients, Message).
send_wrapped_multiple(StateData#state.jid, Recipients, Message,
?NS_MUCSUB_NODES_AFFILIATIONS, StateData).
status_els(IsInitialPresence, JID, #user{jid = JID}, StateData) ->
Status = case IsInitialPresence of
@ -3420,7 +3391,7 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
StateData#state.jid, Nick),
send_wrapped(RoomJIDNick, Info#user.jid, Packet,
?NS_MUCSUB_NODES_AFFILIATIONS, StateData),
IsSubscriber = Info#user.is_subscriber,
IsSubscriber = is_subscriber(Info#user.jid, StateData),
IsOccupant = Info#user.last_presence /= undefined,
if (IsSubscriber and not IsOccupant) ->
send_wrapped(RoomJIDNick, Info#user.jid, Packet,
@ -3429,7 +3400,7 @@ send_kickban_presence1(MJID, UJID, Reason, Code, Affiliation,
ok
end
end,
(?DICT):to_list(StateData#state.users)).
(?DICT):to_list(get_users_and_subscribers(StateData))).
get_actor_nick(<<"">>, _StateData) ->
<<"">>;
@ -4259,7 +4230,7 @@ send_config_change_info(New, #state{config = Old} = StateData) ->
attrs = [{<<"xmlns">>, ?NS_MUC_USER}],
children = StatusEls}]},
send_wrapped_multiple(StateData#state.jid,
StateData#state.users,
get_users_and_subscribers(StateData),
Message,
?NS_MUCSUB_NODES_CONFIG,
StateData).
@ -4275,7 +4246,7 @@ remove_nonmembers(StateData) ->
_ -> SD
end
end,
StateData, (?DICT):to_list(StateData#state.users)).
StateData, (?DICT):to_list(get_users_and_subscribers(StateData))).
set_opts([], StateData) -> StateData;
set_opts([{Opt, Val} | Opts], StateData) ->
@ -4396,14 +4367,17 @@ set_opts([{Opt, Val} | Opts], StateData) ->
StateData#state{config =
(StateData#state.config)#config{allow_subscription = Val}};
subscribers ->
lists:foldl(
fun({JID, Nick, Nodes}, State) ->
User = #user{jid = JID, nick = Nick,
subscriptions = Nodes,
is_subscriber = true,
role = none},
update_online_user(JID, User, State)
end, StateData, Val);
Subscribers = lists:foldl(
fun({JID, Nick, Nodes}, Acc) ->
BareJID = jid:remove_resource(JID),
?DICT:store(
jid:tolower(BareJID),
#subscriber{jid = BareJID,
nick = Nick,
nodes = Nodes},
Acc)
end, ?DICT:new(), Val),
StateData#state{subscribers = Subscribers};
affiliations ->
StateData#state{affiliations = (?DICT):from_list(Val)};
subject -> StateData#state{subject = Val};
@ -4418,12 +4392,11 @@ set_opts([{Opt, Val} | Opts], StateData) ->
make_opts(StateData) ->
Config = StateData#state.config,
Subscribers = (?DICT):fold(
fun(_LJID, #user{is_subscriber = true} = User, Acc) ->
[{User#user.jid, User#user.nick,
User#user.subscriptions}|Acc];
(_, _, Acc) ->
Acc
end, [], StateData#state.users),
fun(_LJID, Sub, Acc) ->
[{Sub#subscriber.jid,
Sub#subscriber.nick,
Sub#subscriber.nodes}|Acc]
end, [], StateData#state.subscribers),
[?MAKE_CONFIG_OPT(title), ?MAKE_CONFIG_OPT(description),
?MAKE_CONFIG_OPT(allow_change_subj),
?MAKE_CONFIG_OPT(allow_query_users),
@ -4479,7 +4452,7 @@ destroy_room(DEl, StateData) ->
Info#user.jid, Packet,
?NS_MUCSUB_NODES_CONFIG, StateData)
end,
(?DICT):to_list(StateData#state.users)),
(?DICT):to_list(get_users_and_subscribers(StateData))),
case (StateData#state.config)#config.persistent of
true ->
mod_muc:forget_room(StateData#state.server_host,
@ -4639,9 +4612,9 @@ process_iq_mucsub(From, Packet,
Err = ?ERRT_BAD_REQUEST(Lang, <<"Missing 'nick' attribute">>),
{error, Err};
Nick when Config#config.allow_subscription ->
LJID = jid:tolower(From),
case (?DICT):find(LJID, StateData#state.users) of
{ok, #user{role = Role, nick = Nick1}} when Nick1 /= Nick ->
LBareJID = jid:tolower(jid:remove_resource(From)),
case (?DICT):find(LBareJID, StateData#state.subscribers) of
{ok, #subscriber{nick = Nick1}} when Nick1 /= Nick ->
Nodes = get_subscription_nodes(Packet),
case {nick_collision(From, Nick, StateData),
mod_muc:can_use_nick(StateData#state.server_host,
@ -4654,14 +4627,12 @@ process_iq_mucsub(From, Packet,
ErrText = <<"That nickname is registered by another person">>,
{error, ?ERRT_CONFLICT(Lang, ErrText)};
_ ->
NewStateData = add_online_user(
From, Nick, Role, true, Nodes, StateData),
NewStateData = set_subscriber(From, Nick, Nodes, StateData),
{result, subscription_nodes_to_events(Nodes), NewStateData}
end;
{ok, #user{role = Role}} ->
{ok, #subscriber{}} ->
Nodes = get_subscription_nodes(Packet),
NewStateData = add_online_user(
From, Nick, Role, true, Nodes, StateData),
NewStateData = set_subscriber(From, Nick, Nodes, StateData),
{result, subscription_nodes_to_events(Nodes), NewStateData};
error ->
add_new_user(From, Nick, Packet, StateData)
@ -4674,27 +4645,11 @@ process_iq_mucsub(From, _Packet,
#iq{type = set,
sub_el = #xmlel{name = <<"unsubscribe">>}},
StateData) ->
LJID = jid:tolower(From),
case ?DICT:find(LJID, StateData#state.users) of
{ok, #user{is_subscriber = true} = User} ->
NewStateData = remove_subscription(From, User, StateData),
store_room(NewStateData),
{result, [], NewStateData};
error when From#jid.lresource == <<"">> ->
{LUser, LServer, _} = LJID,
NewStateData =
dict:fold(
fun({U, S, _}, #user{jid = J, is_subscriber = true} = User,
AccState) when U == LUser, S == LServer ->
remove_subscription(J, User, AccState);
(_, _, AccState) ->
AccState
end, StateData, StateData#state.users),
store_room(NewStateData),
{result, [], NewStateData};
_ ->
{result, [], StateData}
end;
LBareJID = jid:tolower(jid:remove_resource(From)),
Subscribers = ?DICT:erase(LBareJID, StateData#state.subscribers),
NewStateData = StateData#state{subscribers = Subscribers},
store_room(NewStateData),
{result, [], NewStateData};
process_iq_mucsub(From, _Packet,
#iq{type = get, lang = Lang,
sub_el = #xmlel{name = <<"subscriptions">>}},
@ -4703,13 +4658,11 @@ process_iq_mucsub(From, _Packet,
FRole = get_role(From, StateData),
if FRole == moderator; FAffiliation == owner; FAffiliation == admin ->
Subs = dict:fold(
fun(_, #user{is_subscriber = true, jid = J}, Acc) ->
SJID = jid:to_string(jid:remove_resource(J)),
fun(_, #subscriber{jid = J}, Acc) ->
SJID = jid:to_string(J),
[#xmlel{name = <<"subscription">>,
attrs = [{<<"jid">>, SJID}]}|Acc];
(_, _, Acc) ->
Acc
end, [], StateData#state.users),
attrs = [{<<"jid">>, SJID}]}|Acc]
end, [], StateData#state.subscribers),
{result, Subs, StateData};
true ->
Txt = <<"Moderator privileges required">>,
@ -4719,25 +4672,9 @@ process_iq_mucsub(_From, _Packet, #iq{lang = Lang}, _StateData) ->
Txt = <<"Unrecognized subscription command">>,
{error, ?ERRT_BAD_REQUEST(Lang, Txt)}.
remove_subscription(JID, #user{is_subscriber = true} = User, StateData) ->
case User#user.last_presence of
undefined ->
remove_online_user(JID, StateData, false);
_ ->
LJID = jid:tolower(JID),
Users = ?DICT:store(LJID, User#user{is_subscriber = false},
StateData#state.users),
StateData#state{users = Users}
end;
remove_subscription(_JID, #user{}, StateData) ->
StateData.
remove_subscriptions(StateData) ->
if not (StateData#state.config)#config.allow_subscription ->
dict:fold(
fun(_LJID, User, State) ->
remove_subscription(User#user.jid, User, State)
end, StateData, StateData#state.users);
StateData#state{subscribers = ?DICT:new()};
true ->
StateData
end.
@ -5198,18 +5135,26 @@ store_room(StateData) ->
send_wrapped(From, To, Packet, Node, State) ->
LTo = jid:tolower(To),
case ?DICT:find(LTo, State#state.users) of
{ok, #user{is_subscriber = true,
subscriptions = Nodes,
last_presence = undefined}} ->
case lists:member(Node, Nodes) of
true ->
NewPacket = wrap(From, To, Packet, Node),
ejabberd_router:route(State#state.jid, To, NewPacket);
false ->
LBareTo = jid:tolower(jid:remove_resource(To)),
IsOffline = case ?DICT:find(LTo, State#state.users) of
{ok, #user{last_presence = undefined}} -> true;
error -> true;
_ -> false
end,
if IsOffline ->
case ?DICT:find(LBareTo, State#state.subscribers) of
{ok, #subscriber{nodes = Nodes, jid = JID}} ->
case lists:member(Node, Nodes) of
true ->
NewPacket = wrap(From, JID, Packet, Node),
ejabberd_router:route(State#state.jid, JID, NewPacket);
false ->
ok
end;
_ ->
ok
end;
_ ->
true ->
ejabberd_router:route(From, To, Packet)
end.
@ -5230,9 +5175,9 @@ wrap(From, To, Packet, Node) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Multicast
send_multiple(From, Server, Users, Packet) ->
JIDs = [ User#user.jid || {_, User} <- ?DICT:to_list(Users)],
ejabberd_router_multicast:route_multicast(From, Server, JIDs, Packet).
%% send_multiple(From, Server, Users, Packet) ->
%% JIDs = [ User#user.jid || {_, User} <- ?DICT:to_list(Users)],
%% ejabberd_router_multicast:route_multicast(From, Server, JIDs, Packet).
send_wrapped_multiple(From, Users, Packet, Node, State) ->
lists:foreach(