1
0
Fork 0
mirror of https://github.com/processone/ejabberd synced 2025-10-06 03:50:15 +02:00

Adopt remaining code to support new hooks

This commit is contained in:
Evgeniy Khramtsov 2017-01-09 17:02:17 +03:00
parent 3dd2a614ac
commit 1e55e018e5
42 changed files with 2109 additions and 1565 deletions

View file

@ -29,8 +29,8 @@
-protocol({xep, 191, '1.2'}).
-export([start/2, stop/1, process_iq/1, c2s_handle_info/2,
process_iq_set/3, process_iq_get/3, mod_opt_type/1, depends/2]).
-export([start/2, stop/1, process_iq/1, mod_opt_type/1, depends/2,
disco_features/5]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -48,77 +48,73 @@
start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
one_queue),
ejabberd_hooks:add(privacy_iq_get, Host, ?MODULE,
process_iq_get, 40),
ejabberd_hooks:add(privacy_iq_set, Host, ?MODULE,
process_iq_set, 40),
ejabberd_hooks:add(c2s_handle_info, Host, ?MODULE,
c2s_handle_info, 40),
mod_disco:register_feature(Host, ?NS_BLOCKING),
ejabberd_hooks:add(disco_local_features, Host, ?MODULE, disco_features, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
?NS_BLOCKING, ?MODULE, process_iq, IQDisc).
stop(Host) ->
ejabberd_hooks:delete(privacy_iq_get, Host, ?MODULE,
process_iq_get, 40),
ejabberd_hooks:delete(privacy_iq_set, Host, ?MODULE,
process_iq_set, 40),
ejabberd_hooks:delete(c2s_handle_info, Host, ?MODULE,
c2s_handle_info, 40),
mod_disco:unregister_feature(Host, ?NS_BLOCKING),
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host,
?NS_BLOCKING).
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_BLOCKING).
depends(_Host, _Opts) ->
[{mod_privacy, hard}].
-spec disco_features({error, stanza_error()} | {result, [binary()]} | empty,
jid(), jid(), binary(), binary()) ->
{error, stanza_error()} | {result, [binary()]}.
disco_features({error, Err}, _From, _To, _Node, _Lang) ->
{error, Err};
disco_features(empty, _From, _To, <<"">>, _Lang) ->
{result, [?NS_BLOCKING]};
disco_features({result, Feats}, _From, _To, <<"">>, _Lang) ->
{result, [?NS_BLOCKING|Feats]};
disco_features(Acc, _From, _To, _Node, _Lang) ->
Acc.
-spec process_iq(iq()) -> iq().
process_iq(IQ) ->
xmpp:make_error(IQ, xmpp:err_not_allowed()).
process_iq(#iq{type = Type,
from = #jid{luser = U, lserver = S},
to = #jid{luser = U, lserver = S}} = IQ) ->
case Type of
get -> process_iq_get(IQ);
set -> process_iq_set(IQ)
end;
process_iq(#iq{lang = Lang} = IQ) ->
Txt = <<"Query to another users is forbidden">>,
xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)).
-spec process_iq_get({error, stanza_error()} | {result, xmpp_element() | undefined},
iq(), userlist()) ->
{error, stanza_error()} |
{result, xmpp_element() | undefined}.
process_iq_get(_, #iq{lang = Lang, from = From,
sub_els = [#block_list{}]}, _) ->
#jid{luser = LUser, lserver = LServer} = From,
process_blocklist_get(LUser, LServer, Lang);
process_iq_get(Acc, _, _) -> Acc.
-spec process_iq_get(iq()) -> iq().
process_iq_get(#iq{sub_els = [#block_list{}]} = IQ) ->
process_get(IQ);
process_iq_get(#iq{lang = Lang} = IQ) ->
Txt = <<"No module is handling this query">>,
xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)).
-spec process_iq_set({error, stanza_error()} |
{result, xmpp_element() | undefined} |
{result, xmpp_element() | undefined, userlist()},
iq(), userlist()) ->
{error, stanza_error()} |
{result, xmpp_element() | undefined} |
{result, xmpp_element() | undefined, userlist()}.
process_iq_set(Acc, #iq{from = From, lang = Lang, sub_els = [SubEl]}, _) ->
#jid{luser = LUser, lserver = LServer} = From,
-spec process_iq_set(iq()) -> iq().
process_iq_set(#iq{lang = Lang, sub_els = [SubEl]} = IQ) ->
case SubEl of
#block{items = []} ->
Txt = <<"No items found in this query">>,
{error, xmpp:err_bad_request(Txt, Lang)};
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
#block{items = Items} ->
JIDs = [jid:tolower(Item) || Item <- Items],
process_blocklist_block(LUser, LServer, JIDs, Lang);
process_block(IQ, JIDs);
#unblock{items = []} ->
process_blocklist_unblock_all(LUser, LServer, Lang);
process_unblock_all(IQ);
#unblock{items = Items} ->
JIDs = [jid:tolower(Item) || Item <- Items],
process_blocklist_unblock(LUser, LServer, JIDs, Lang);
process_unblock(IQ, JIDs);
_ ->
Acc
end;
process_iq_set(Acc, _, _) -> Acc.
Txt = <<"No module is handling this query">>,
xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang))
end.
-spec list_to_blocklist_jids([listitem()], [ljid()]) -> [ljid()].
list_to_blocklist_jids([], JIDs) -> JIDs;
list_to_blocklist_jids([#listitem{type = jid,
action = deny, value = JID} =
Item
| Items],
JIDs) ->
-spec listitems_to_jids([listitem()], [ljid()]) -> [ljid()].
listitems_to_jids([], JIDs) ->
JIDs;
listitems_to_jids([#listitem{type = jid,
action = deny, value = JID} = Item | Items],
JIDs) ->
Match = case Item of
#listitem{match_all = true} ->
true;
@ -130,20 +126,18 @@ list_to_blocklist_jids([#listitem{type = jid,
_ ->
false
end,
if Match -> list_to_blocklist_jids(Items, [JID | JIDs]);
true -> list_to_blocklist_jids(Items, JIDs)
if Match -> listitems_to_jids(Items, [JID | JIDs]);
true -> listitems_to_jids(Items, JIDs)
end;
% Skip Privacy List items than cannot be mapped to Blocking items
list_to_blocklist_jids([_ | Items], JIDs) ->
list_to_blocklist_jids(Items, JIDs).
listitems_to_jids([_ | Items], JIDs) ->
listitems_to_jids(Items, JIDs).
-spec process_blocklist_block(binary(), binary(), [ljid()],
binary()) ->
{error, stanza_error()} |
{result, undefined, userlist()}.
process_blocklist_block(LUser, LServer, JIDs, Lang) ->
-spec process_block(iq(), [ljid()]) -> iq().
process_block(#iq{from = #jid{luser = LUser, lserver = LServer},
lang = Lang} = IQ, JIDs) ->
Filter = fun (List) ->
AlreadyBlocked = list_to_blocklist_jids(List, []),
AlreadyBlocked = listitems_to_jids(List, []),
lists:foldr(fun (JID, List1) ->
case lists:member(JID, AlreadyBlocked)
of
@ -161,23 +155,21 @@ process_blocklist_block(LUser, LServer, JIDs, Lang) ->
end,
Mod = db_mod(LServer),
case Mod:process_blocklist_block(LUser, LServer, Filter) of
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer,
{block, [jid:make(J) || J <- JIDs]}),
{result, undefined, UserList};
_Err ->
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, UserList, Default),
broadcast_event(LUser, LServer,
#block{items = [jid:make(J) || J <- JIDs]}),
xmpp:make_iq_result(IQ);
_Err ->
?ERROR_MSG("Error processing ~p: ~p", [{LUser, LServer, JIDs}, _Err]),
{error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)}
Err = xmpp:err_internal_server_error(<<"Database failure">>, Lang),
xmpp:make_error(IQ, Err)
end.
-spec process_blocklist_unblock_all(binary(), binary(), binary()) ->
{error, stanza_error()} |
{result, undefined} |
{result, undefined, userlist()}.
process_blocklist_unblock_all(LUser, LServer, Lang) ->
-spec process_unblock_all(iq()) -> iq().
process_unblock_all(#iq{from = #jid{luser = LUser, lserver = LServer},
lang = Lang} = IQ) ->
Filter = fun (List) ->
lists:filter(fun (#listitem{action = A}) -> A =/= deny
end,
@ -185,23 +177,22 @@ process_blocklist_unblock_all(LUser, LServer, Lang) ->
end,
Mod = db_mod(LServer),
case Mod:unblock_by_filter(LUser, LServer, Filter) of
{atomic, ok} -> {result, undefined};
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer, unblock_all),
{result, undefined, UserList};
_Err ->
{atomic, ok} ->
xmpp:make_iq_result(IQ);
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, UserList, Default),
broadcast_event(LUser, LServer, #unblock{}),
xmpp:make_iq_result(IQ);
_Err ->
?ERROR_MSG("Error processing ~p: ~p", [{LUser, LServer}, _Err]),
{error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)}
Err = xmpp:err_internal_server_error(<<"Database failure">>, Lang),
xmpp:make_error(IQ, Err)
end.
-spec process_blocklist_unblock(binary(), binary(), [ljid()], binary()) ->
{error, stanza_error()} |
{result, undefined} |
{result, undefined, userlist()}.
process_blocklist_unblock(LUser, LServer, JIDs, Lang) ->
-spec process_unblock(iq(), [ljid()]) -> iq().
process_unblock(#iq{from = #jid{luser = LUser, lserver = LServer},
lang = Lang} = IQ, JIDs) ->
Filter = fun (List) ->
lists:filter(fun (#listitem{action = deny, type = jid,
value = JID}) ->
@ -212,17 +203,18 @@ process_blocklist_unblock(LUser, LServer, JIDs, Lang) ->
end,
Mod = db_mod(LServer),
case Mod:unblock_by_filter(LUser, LServer, Filter) of
{atomic, ok} -> {result, undefined};
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, Default,
UserList),
broadcast_blocklist_event(LUser, LServer,
{unblock, [jid:make(J) || J <- JIDs]}),
{result, undefined, UserList};
_Err ->
{atomic, ok} ->
xmpp:make_iq_result(IQ);
{atomic, {ok, Default, List}} ->
UserList = make_userlist(Default, List),
broadcast_list_update(LUser, LServer, UserList, Default),
broadcast_event(LUser, LServer,
#unblock{items = [jid:make(J) || J <- JIDs]}),
xmpp:make_iq_result(IQ);
_Err ->
?ERROR_MSG("Error processing ~p: ~p", [{LUser, LServer, JIDs}, _Err]),
{error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)}
Err = xmpp:err_internal_server_error(<<"Database failure">>, Lang),
xmpp:make_error(IQ, Err)
end.
-spec make_userlist(binary(), [listitem()]) -> userlist().
@ -230,52 +222,36 @@ make_userlist(Name, List) ->
NeedDb = mod_privacy:is_list_needdb(List),
#userlist{name = Name, list = List, needdb = NeedDb}.
-spec broadcast_list_update(binary(), binary(), binary(), userlist()) -> ok.
broadcast_list_update(LUser, LServer, Name, UserList) ->
ejabberd_sm:route(jid:make(LUser, LServer, <<"">>),
{privacy_list, UserList, Name}).
-spec broadcast_list_update(binary(), binary(), userlist(), binary()) -> ok.
broadcast_list_update(LUser, LServer, UserList, Name) ->
mod_privacy:push_list_update(jid:make(LUser, LServer), UserList, Name).
-spec broadcast_blocklist_event(binary(), binary(), block_event()) -> ok.
broadcast_blocklist_event(LUser, LServer, Event) ->
JID = jid:make(LUser, LServer, <<"">>),
ejabberd_sm:route(JID, {blocking, Event}).
-spec broadcast_event(binary(), binary(), block_event()) -> ok.
broadcast_event(LUser, LServer, Event) ->
From = jid:make(LUser, LServer),
lists:foreach(
fun(R) ->
To = jid:replace_resource(From, R),
IQ = #iq{type = set, from = From, to = To,
id = <<"push", (randoms:get_string())/binary>>,
sub_els = [Event]},
ejabberd_router:route(From, To, IQ)
end, ejabberd_sm:get_user_resources(LUser, LServer)).
-spec process_blocklist_get(binary(), binary(), binary()) ->
{error, stanza_error()} | {result, block_list()}.
process_blocklist_get(LUser, LServer, Lang) ->
-spec process_get(iq()) -> iq().
process_get(#iq{from = #jid{luser = LUser, lserver = LServer},
lang = Lang} = IQ) ->
Mod = db_mod(LServer),
case Mod:process_blocklist_get(LUser, LServer) of
error ->
{error, xmpp:err_internal_server_error(<<"Database failure">>, Lang)};
List ->
LJIDs = list_to_blocklist_jids(List, []),
Items = [jid:make(J) || J <- LJIDs],
{result, #block_list{items = Items}}
error ->
Err = xmpp:err_internal_server_error(<<"Database failure">>, Lang),
xmpp:make_error(IQ, Err);
List ->
LJIDs = listitems_to_jids(List, []),
Items = [jid:make(J) || J <- LJIDs],
xmpp:make_iq_result(IQ, #block_list{items = Items})
end.
-spec c2s_handle_info(ejabberd_c2s:state(), term()) -> ejabberd_c2s:state().
c2s_handle_info(#{user := U, server := S, resource := R} = State,
{blocking, Action}) ->
SubEl = case Action of
{block, JIDs} ->
#block{items = JIDs};
{unblock, JIDs} ->
#unblock{items = JIDs};
unblock_all ->
#unblock{}
end,
PushIQ = #iq{type = set,
from = jid:make(U, S),
to = jid:make(U, S, R),
id = <<"push", (randoms:get_string())/binary>>,
sub_els = [SubEl]},
%% No need to replace active privacy list here,
%% blocking pushes are always accompanied by
%% Privacy List pushes
{stop, ejabberd_c2s:send(State, PushIQ)};
c2s_handle_info(State, _) ->
State.
-spec db_mod(binary()) -> module().
db_mod(LServer) ->
DBType = gen_mod:db_type(LServer, mod_privacy),