mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Add option user_mucsub_from_muc_archive to mod_muc
This option disable storing separate mucsub message for each individual subscriber but instead when user fetches archive virtual mucsub messages are generated from muc archives.
This commit is contained in:
parent
063869603a
commit
8e05fd1d24
133
src/mod_mam.erl
133
src/mod_mam.erl
@ -76,8 +76,12 @@
|
|||||||
-callback remove_from_archive(binary(), binary(), jid() | none) -> ok | {error, any()}.
|
-callback remove_from_archive(binary(), binary(), jid() | none) -> ok | {error, any()}.
|
||||||
-callback is_empty_for_user(binary(), binary()) -> boolean().
|
-callback is_empty_for_user(binary(), binary()) -> boolean().
|
||||||
-callback is_empty_for_room(binary(), binary(), binary()) -> boolean().
|
-callback is_empty_for_room(binary(), binary(), binary()) -> boolean().
|
||||||
|
-callback select_with_mucsub(binary(), jid(), jid(), mam_query:result(),
|
||||||
|
#rsm_set{} | undefined) ->
|
||||||
|
{[{binary(), non_neg_integer(), xmlel()}], boolean(), count()} |
|
||||||
|
{error, db_failure}.
|
||||||
|
|
||||||
-optional_callbacks([use_cache/1, cache_nodes/1]).
|
-optional_callbacks([use_cache/1, cache_nodes/1, select_with_mucsub/5]).
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
@ -886,16 +890,20 @@ may_enter_room(From, MUCState) ->
|
|||||||
store_msg(Pkt, LUser, LServer, Peer, Dir) ->
|
store_msg(Pkt, LUser, LServer, Peer, Dir) ->
|
||||||
case get_prefs(LUser, LServer) of
|
case get_prefs(LUser, LServer) of
|
||||||
{ok, Prefs} ->
|
{ok, Prefs} ->
|
||||||
case {should_archive_peer(LUser, LServer, Prefs, Peer), Pkt} of
|
UseMucArchive = gen_mod:get_module_opt(LServer, ?MODULE, user_mucsub_from_muc_archive),
|
||||||
{true, #message{meta = #{sm_copy := true}}} ->
|
StoredInMucMam = UseMucArchive andalso xmpp:get_meta(Pkt, in_muc_mam, false),
|
||||||
|
case {should_archive_peer(LUser, LServer, Prefs, Peer), Pkt, StoredInMucMam} of
|
||||||
|
{true, #message{meta = #{sm_copy := true}}, _} ->
|
||||||
ok; % Already stored.
|
ok; % Already stored.
|
||||||
{true, _} ->
|
{true, _, true} ->
|
||||||
|
ok; % Stored in muc archive.
|
||||||
|
{true, _, _} ->
|
||||||
case ejabberd_hooks:run_fold(store_mam_message, LServer, Pkt,
|
case ejabberd_hooks:run_fold(store_mam_message, LServer, Pkt,
|
||||||
[LUser, LServer, Peer, <<"">>, chat, Dir]) of
|
[LUser, LServer, Peer, <<"">>, chat, Dir]) of
|
||||||
#message{} -> ok;
|
#message{} -> ok;
|
||||||
_ -> pass
|
_ -> pass
|
||||||
end;
|
end;
|
||||||
{false, _} ->
|
{false, _, _} ->
|
||||||
pass
|
pass
|
||||||
end;
|
end;
|
||||||
{error, _} ->
|
{error, _} ->
|
||||||
@ -1073,10 +1081,118 @@ select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType) ->
|
|||||||
true ->
|
true ->
|
||||||
{[], true, 0};
|
{[], true, 0};
|
||||||
false ->
|
false ->
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
case {MsgType, gen_mod:get_module_opt(LServer, ?MODULE, user_mucsub_from_muc_archive)} of
|
||||||
Mod:select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType)
|
{chat, true} ->
|
||||||
|
select_with_mucsub(LServer, JidRequestor, JidArchive, Query, RSM);
|
||||||
|
_ ->
|
||||||
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
|
Mod:select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType)
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
select_with_mucsub(LServer, JidRequestor, JidArchive, Query, RSM) ->
|
||||||
|
MucHosts = mod_muc_admin:find_hosts(LServer),
|
||||||
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
|
case proplists:get_value(with, Query) of
|
||||||
|
#jid{lserver = WithLServer} = MucJid ->
|
||||||
|
case lists:member(WithLServer, MucHosts) of
|
||||||
|
true ->
|
||||||
|
select(LServer, JidRequestor, MucJid, Query, RSM,
|
||||||
|
{groupchat, member, #state{config = #config{mam = true}}});
|
||||||
|
_ ->
|
||||||
|
Mod:select(LServer, JidRequestor, JidArchive, Query, RSM, chat)
|
||||||
|
end;
|
||||||
|
_ ->
|
||||||
|
case erlang:function_exported(Mod, select_with_mucsub, 5) of
|
||||||
|
true ->
|
||||||
|
Mod:select_with_mucsub(LServer, JidRequestor, JidArchive, Query, RSM);
|
||||||
|
false ->
|
||||||
|
case Mod:select(LServer, JidRequestor, JidArchive, Query, RSM, chat) of
|
||||||
|
{error, _} = Err ->
|
||||||
|
Err;
|
||||||
|
{Entries, All, Count} ->
|
||||||
|
{Dir, Max} = case RSM of
|
||||||
|
#rsm_set{max = M, before = V} when is_binary(V) ->
|
||||||
|
{desc, M};
|
||||||
|
#rsm_set{max = M} ->
|
||||||
|
{asc, M};
|
||||||
|
_ ->
|
||||||
|
{asc, undefined}
|
||||||
|
end,
|
||||||
|
SubRooms = case mod_muc_admin:find_hosts(LServer) of
|
||||||
|
[First|_] ->
|
||||||
|
mod_muc:get_subscribed_rooms(First, JidRequestor);
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end,
|
||||||
|
SubRoomJids = [Jid || #muc_subscription{jid = Jid} <- SubRooms],
|
||||||
|
{E2, A2, C2} = lists:foldl(
|
||||||
|
fun(MucJid, {E0, A0, C0}) ->
|
||||||
|
case select(LServer, JidRequestor, MucJid, Query, RSM,
|
||||||
|
{groupchat, member, #state{config = #config{mam = true}}}) of
|
||||||
|
{error, _} ->
|
||||||
|
{E0, A0, C0};
|
||||||
|
{E, A, C} ->
|
||||||
|
{lists:keymerge(2, E0, wrap_as_mucsub(E, JidRequestor)),
|
||||||
|
A0 andalso A, C0 + C}
|
||||||
|
end
|
||||||
|
end, {Entries, All, Count}, SubRoomJids),
|
||||||
|
case {Dir, Max} of
|
||||||
|
{_, undefined} ->
|
||||||
|
{E2, A2, C2};
|
||||||
|
{desc, _} ->
|
||||||
|
Start = case length(E2) of
|
||||||
|
Len when Len < Max -> 1;
|
||||||
|
Len -> Len - Max + 1
|
||||||
|
end,
|
||||||
|
Sub = lists:sublist(E2, Start, Max),
|
||||||
|
{Sub, if Sub == E2 -> A2; true -> false end, C2};
|
||||||
|
_ ->
|
||||||
|
Sub = lists:sublist(E2, 1, Max),
|
||||||
|
{Sub, if Sub == E2 -> A2; true -> false end, C2}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
wrap_as_mucsub(Messages, #jid{lserver = LServer} = Requester) ->
|
||||||
|
ReqBare = jid:remove_resource(Requester),
|
||||||
|
ReqServer = jid:make(<<>>, LServer, <<>>),
|
||||||
|
[{T1, T2, wrap_as_mucsub(M, ReqBare, ReqServer)} || {T1, T2, M} <- Messages].
|
||||||
|
|
||||||
|
wrap_as_mucsub(Message, Requester, ReqServer) ->
|
||||||
|
case Message of
|
||||||
|
#forwarded{delay = #delay{stamp = Stamp, desc = Desc},
|
||||||
|
sub_els = [#message{from = From, sub_els = SubEls} = Msg]} ->
|
||||||
|
{L1, SubEls2} = case lists:keytake(mam_archived, 1, xmpp:decode(SubEls)) of
|
||||||
|
{value, Arch, Rest} ->
|
||||||
|
{[Arch#mam_archived{by = Requester}], Rest};
|
||||||
|
_ ->
|
||||||
|
{[], SubEls}
|
||||||
|
end,
|
||||||
|
{Sid, L2, SubEls3} = case lists:keytake(stanza_id, 1, SubEls2) of
|
||||||
|
{value, #stanza_id{id = Sid0} = SID, Rest2} ->
|
||||||
|
{Sid0, [SID#stanza_id{by = Requester} | L1], Rest2};
|
||||||
|
_ ->
|
||||||
|
{p1_rand:get_string(), L1, SubEls2}
|
||||||
|
end,
|
||||||
|
Msg2 = Msg#message{to = Requester, sub_els = SubEls3},
|
||||||
|
#forwarded{delay = #delay{stamp = Stamp, desc = Desc, from = ReqServer},
|
||||||
|
sub_els = [
|
||||||
|
#message{from = jid:remove_resource(From), to = Requester,
|
||||||
|
id = Sid,
|
||||||
|
sub_els = [#ps_event{
|
||||||
|
items = #ps_items{
|
||||||
|
node = ?NS_MUCSUB_NODES_MESSAGES,
|
||||||
|
items = [#ps_item{
|
||||||
|
id = Sid,
|
||||||
|
sub_els = [Msg2]
|
||||||
|
}]}} | L2]}]};
|
||||||
|
_ ->
|
||||||
|
Message
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
msg_to_el(#archive_msg{timestamp = TS, packet = El, nick = Nick,
|
msg_to_el(#archive_msg{timestamp = TS, packet = El, nick = Nick,
|
||||||
peer = Peer, id = ID},
|
peer = Peer, id = ID},
|
||||||
MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) ->
|
MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) ->
|
||||||
@ -1265,6 +1381,8 @@ mod_opt_type(request_activates_archiving) ->
|
|||||||
fun (B) when is_boolean(B) -> B end;
|
fun (B) when is_boolean(B) -> B end;
|
||||||
mod_opt_type(clear_archive_on_room_destroy) ->
|
mod_opt_type(clear_archive_on_room_destroy) ->
|
||||||
fun (B) when is_boolean(B) -> B end;
|
fun (B) when is_boolean(B) -> B end;
|
||||||
|
mod_opt_type(user_mucsub_from_muc_archive) ->
|
||||||
|
fun (B) when is_boolean(B) -> B end;
|
||||||
mod_opt_type(access_preferences) ->
|
mod_opt_type(access_preferences) ->
|
||||||
fun acl:access_rules_validator/1.
|
fun acl:access_rules_validator/1.
|
||||||
|
|
||||||
@ -1275,6 +1393,7 @@ mod_options(Host) ->
|
|||||||
{compress_xml, false},
|
{compress_xml, false},
|
||||||
{clear_archive_on_room_destroy, true},
|
{clear_archive_on_room_destroy, true},
|
||||||
{access_preferences, all},
|
{access_preferences, all},
|
||||||
|
{user_mucsub_from_muc_archive, false},
|
||||||
{db_type, ejabberd_config:default_db(Host, ?MODULE)},
|
{db_type, ejabberd_config:default_db(Host, ?MODULE)},
|
||||||
{use_cache, ejabberd_config:use_cache(Host)},
|
{use_cache, ejabberd_config:use_cache(Host)},
|
||||||
{cache_size, ejabberd_config:cache_size(Host)},
|
{cache_size, ejabberd_config:cache_size(Host)},
|
||||||
|
@ -65,7 +65,8 @@
|
|||||||
iq_set_register_info/5,
|
iq_set_register_info/5,
|
||||||
count_online_rooms_by_user/3,
|
count_online_rooms_by_user/3,
|
||||||
get_online_rooms_by_user/3,
|
get_online_rooms_by_user/3,
|
||||||
can_use_nick/4]).
|
can_use_nick/4,
|
||||||
|
get_subscribed_rooms/2]).
|
||||||
|
|
||||||
-export([init/1, handle_call/3, handle_cast/2,
|
-export([init/1, handle_call/3, handle_cast/2,
|
||||||
handle_info/2, terminate/2, code_change/3,
|
handle_info/2, terminate/2, code_change/3,
|
||||||
@ -727,6 +728,11 @@ get_room_disco_item({Name, Host, Pid}, Query) ->
|
|||||||
{error, notfound}
|
{error, notfound}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec get_subscribed_rooms(binary(), jid()) -> [#muc_subscription{}].
|
||||||
|
get_subscribed_rooms(Host, User) ->
|
||||||
|
ServerHost = ejabberd_router:host_of_route(Host),
|
||||||
|
get_subscribed_rooms(ServerHost, Host, User).
|
||||||
|
|
||||||
get_subscribed_rooms(ServerHost, Host, From) ->
|
get_subscribed_rooms(ServerHost, Host, From) ->
|
||||||
LServer = jid:nameprep(ServerHost),
|
LServer = jid:nameprep(ServerHost),
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
set_room_affiliation/4, get_room_affiliations/2, get_room_affiliation/3,
|
set_room_affiliation/4, get_room_affiliations/2, get_room_affiliation/3,
|
||||||
web_menu_main/2, web_page_main/2, web_menu_host/3,
|
web_menu_main/2, web_page_main/2, web_menu_host/3,
|
||||||
subscribe_room/4, unsubscribe_room/2, get_subscribers/2,
|
subscribe_room/4, unsubscribe_room/2, get_subscribers/2,
|
||||||
web_page_host/3, mod_options/1, get_commands_spec/0]).
|
web_page_host/3, mod_options/1, get_commands_spec/0, find_hosts/1]).
|
||||||
|
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("xmpp.hrl").
|
-include("xmpp.hrl").
|
||||||
|
@ -4397,9 +4397,17 @@ send_wrapped(From, To, Packet, Node, State) ->
|
|||||||
#subscriber{nodes = Nodes, jid = JID} ->
|
#subscriber{nodes = Nodes, jid = JID} ->
|
||||||
case lists:member(Node, Nodes) of
|
case lists:member(Node, Nodes) of
|
||||||
true ->
|
true ->
|
||||||
NewPacket = wrap(From, JID, Packet, Node),
|
MamEnabled = (State#state.config)#config.mam,
|
||||||
|
Id = case xmpp:get_subtag(Packet, #stanza_id{}) of
|
||||||
|
#stanza_id{id = Id2} ->
|
||||||
|
Id2;
|
||||||
|
_ ->
|
||||||
|
p1_rand:get_string()
|
||||||
|
end,
|
||||||
|
NewPacket = wrap(From, JID, Packet, Node, Id),
|
||||||
|
NewPacket2 = xmpp:put_meta(NewPacket, in_muc_mam, MamEnabled),
|
||||||
ejabberd_router:route(
|
ejabberd_router:route(
|
||||||
xmpp:set_from_to(NewPacket, State#state.jid, JID));
|
xmpp:set_from_to(NewPacket2, State#state.jid, JID));
|
||||||
false ->
|
false ->
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
@ -4432,10 +4440,9 @@ send_wrapped(From, To, Packet, Node, State) ->
|
|||||||
ejabberd_router:route(xmpp:set_from_to(Packet, From, To))
|
ejabberd_router:route(xmpp:set_from_to(Packet, From, To))
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec wrap(jid(), jid(), stanza(), binary()) -> message().
|
-spec wrap(jid(), jid(), stanza(), binary(), binary()) -> message().
|
||||||
wrap(From, To, Packet, Node) ->
|
wrap(From, To, Packet, Node, Id) ->
|
||||||
El = xmpp:set_from_to(Packet, From, To),
|
El = xmpp:set_from_to(Packet, From, To),
|
||||||
Id = p1_rand:get_string(),
|
|
||||||
#message{
|
#message{
|
||||||
id = Id,
|
id = Id,
|
||||||
sub_els = [#ps_event{
|
sub_els = [#ps_event{
|
||||||
|
Loading…
Reference in New Issue
Block a user