mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-20 16:15:59 +01:00
Support "IQ permission" from XEP-0356 0.4.1 (#3889)
This commit is contained in:
parent
74b0f64645
commit
81906b74ed
@ -380,8 +380,9 @@ code_change(_OldVsn, State, _Extra) ->
|
|||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
-spec do_route(stanza()) -> ok.
|
-spec do_route(stanza()) -> ok.
|
||||||
do_route(OrigPacket) ->
|
do_route(OrigPacket1) ->
|
||||||
?DEBUG("Route:~n~ts", [xmpp:pp(OrigPacket)]),
|
?DEBUG("Route:~n~ts", [xmpp:pp(OrigPacket1)]),
|
||||||
|
OrigPacket = process_privilege_iq(OrigPacket1),
|
||||||
case ejabberd_hooks:run_fold(filter_packet, OrigPacket, []) of
|
case ejabberd_hooks:run_fold(filter_packet, OrigPacket, []) of
|
||||||
drop ->
|
drop ->
|
||||||
ok;
|
ok;
|
||||||
@ -405,6 +406,22 @@ do_route(OrigPacket) ->
|
|||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% @format-begin
|
||||||
|
process_privilege_iq(Packet) ->
|
||||||
|
To = xmpp:get_to(Packet),
|
||||||
|
case xmpp:get_meta(Packet, privilege_iq, none) of
|
||||||
|
{OriginalId, OriginalHost, ReplacedJid} when ReplacedJid == To ->
|
||||||
|
Privilege = #privilege{forwarded = #forwarded{sub_els = [Packet]}},
|
||||||
|
#iq{type = xmpp:get_type(Packet),
|
||||||
|
id = OriginalId,
|
||||||
|
to = jid:make(OriginalHost),
|
||||||
|
from = ReplacedJid,
|
||||||
|
sub_els = [Privilege]};
|
||||||
|
_ ->
|
||||||
|
Packet
|
||||||
|
end.
|
||||||
|
%% @format-end
|
||||||
|
|
||||||
-spec do_route(stanza(), #route{}) -> any().
|
-spec do_route(stanza(), #route{}) -> any().
|
||||||
do_route(Pkt, #route{local_hint = LocalHint,
|
do_route(Pkt, #route{local_hint = LocalHint,
|
||||||
pid = Pid}) when is_pid(Pid) ->
|
pid = Pid}) when is_pid(Pid) ->
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
-author('amuhar3@gmail.com').
|
-author('amuhar3@gmail.com').
|
||||||
|
|
||||||
-protocol({xep, 356, '0.2.1', '16.09', "", ""}).
|
-protocol({xep, 356, '0.4.1', '24.xx', "", ""}).
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
@ -37,6 +37,7 @@
|
|||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
terminate/2, code_change/3]).
|
terminate/2, code_change/3]).
|
||||||
-export([component_connected/1, component_disconnected/2,
|
-export([component_connected/1, component_disconnected/2,
|
||||||
|
component_send_packet/1,
|
||||||
roster_access/2, process_message/1,
|
roster_access/2, process_message/1,
|
||||||
process_presence_out/1, process_presence_in/1]).
|
process_presence_out/1, process_presence_in/1]).
|
||||||
|
|
||||||
@ -45,14 +46,17 @@
|
|||||||
-include("translate.hrl").
|
-include("translate.hrl").
|
||||||
|
|
||||||
-type roster_permission() :: both | get | set.
|
-type roster_permission() :: both | get | set.
|
||||||
|
-type iq_permission() :: both | get | set.
|
||||||
-type presence_permission() :: managed_entity | roster.
|
-type presence_permission() :: managed_entity | roster.
|
||||||
-type message_permission() :: outgoing.
|
-type message_permission() :: outgoing.
|
||||||
-type roster_permissions() :: [{roster_permission(), acl:acl()}].
|
-type roster_permissions() :: [{roster_permission(), acl:acl()}].
|
||||||
|
-type iq_permissions() :: [{iq_permission(), acl:acl()}].
|
||||||
-type presence_permissions() :: [{presence_permission(), acl:acl()}].
|
-type presence_permissions() :: [{presence_permission(), acl:acl()}].
|
||||||
-type message_permissions() :: [{message_permission(), acl:acl()}].
|
-type message_permissions() :: [{message_permission(), acl:acl()}].
|
||||||
-type access() :: [{roster, roster_permissions()} |
|
-type access() :: [{roster, roster_permission()} |
|
||||||
{presence, presence_permissions()} |
|
{iq, [privilege_namespace()]} |
|
||||||
{message, message_permissions()}].
|
{presence, presence_permission()} |
|
||||||
|
{message, message_permission()}].
|
||||||
-type permissions() :: #{binary() => access()}.
|
-type permissions() :: #{binary() => access()}.
|
||||||
-record(state, {server_host = <<"">> :: binary()}).
|
-record(state, {server_host = <<"">> :: binary()}).
|
||||||
|
|
||||||
@ -71,6 +75,10 @@ reload(_Host, _NewOpts, _OldOpts) ->
|
|||||||
mod_opt_type(roster) ->
|
mod_opt_type(roster) ->
|
||||||
econf:options(
|
econf:options(
|
||||||
#{both => econf:acl(), get => econf:acl(), set => econf:acl()});
|
#{both => econf:acl(), get => econf:acl(), set => econf:acl()});
|
||||||
|
mod_opt_type(iq) ->
|
||||||
|
econf:map(
|
||||||
|
econf:binary(),
|
||||||
|
econf:options(#{both => econf:acl(), get => econf:acl(), set => econf:acl()}));
|
||||||
mod_opt_type(message) ->
|
mod_opt_type(message) ->
|
||||||
econf:options(
|
econf:options(
|
||||||
#{outgoing => econf:acl()});
|
#{outgoing => econf:acl()});
|
||||||
@ -80,6 +88,7 @@ mod_opt_type(presence) ->
|
|||||||
|
|
||||||
mod_options(_) ->
|
mod_options(_) ->
|
||||||
[{roster, [{both, none}, {get, none}, {set, none}]},
|
[{roster, [{both, none}, {get, none}, {set, none}]},
|
||||||
|
{iq, []},
|
||||||
{presence, [{managed_entity, none}, {roster, none}]},
|
{presence, [{managed_entity, none}, {roster, none}]},
|
||||||
{message, [{outgoing,none}]}].
|
{message, [{outgoing,none}]}].
|
||||||
|
|
||||||
@ -130,6 +139,27 @@ mod_doc() ->
|
|||||||
desc =>
|
desc =>
|
||||||
?T("Sets write access to a user's roster. "
|
?T("Sets write access to a user's roster. "
|
||||||
"The default value is 'none'.")}}]},
|
"The default value is 'none'.")}}]},
|
||||||
|
{iq,
|
||||||
|
#{value => "{Namespace: Options}",
|
||||||
|
desc =>
|
||||||
|
?T("This option defines namespaces and their IQ permissions. "
|
||||||
|
"By default no permissions are given. "
|
||||||
|
"The 'Options' are:")},
|
||||||
|
[{both,
|
||||||
|
#{value => ?T("AccessName"),
|
||||||
|
desc =>
|
||||||
|
?T("Allows sending IQ stanzas of type 'get' and 'set'. "
|
||||||
|
"The default value is 'none'.")}},
|
||||||
|
{get,
|
||||||
|
#{value => ?T("AccessName"),
|
||||||
|
desc =>
|
||||||
|
?T("Allows sending IQ stanzas of type 'get'. "
|
||||||
|
"The default value is 'none'.")}},
|
||||||
|
{set,
|
||||||
|
#{value => ?T("AccessName"),
|
||||||
|
desc =>
|
||||||
|
?T("Allows sending IQ stanzas of type 'set'. "
|
||||||
|
"The default value is 'none'.")}}]},
|
||||||
{message,
|
{message,
|
||||||
#{value => ?T("Options"),
|
#{value => ?T("Options"),
|
||||||
desc =>
|
desc =>
|
||||||
@ -164,6 +194,9 @@ mod_doc() ->
|
|||||||
example =>
|
example =>
|
||||||
["modules:",
|
["modules:",
|
||||||
" mod_privilege:",
|
" mod_privilege:",
|
||||||
|
" iq:",
|
||||||
|
" http://jabber.org/protocol/pubsub:",
|
||||||
|
" get: all",
|
||||||
" roster:",
|
" roster:",
|
||||||
" get: all",
|
" get: all",
|
||||||
" presence:",
|
" presence:",
|
||||||
@ -190,6 +223,10 @@ component_disconnected(Host, _Reason) ->
|
|||||||
gen_server:cast(Proc, {component_disconnected, Host})
|
gen_server:cast(Proc, {component_disconnected, Host})
|
||||||
end, ejabberd_option:hosts()).
|
end, ejabberd_option:hosts()).
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Message processing
|
||||||
|
%%
|
||||||
|
|
||||||
-spec process_message(stanza()) -> stop | ok.
|
-spec process_message(stanza()) -> stop | ok.
|
||||||
process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From,
|
process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From,
|
||||||
to = #jid{lresource = <<"">>} = To,
|
to = #jid{lresource = <<"">>} = To,
|
||||||
@ -212,9 +249,73 @@ process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From,
|
|||||||
%% Component is disconnected
|
%% Component is disconnected
|
||||||
ok
|
ok
|
||||||
end;
|
end;
|
||||||
|
|
||||||
process_message(_Stanza) ->
|
process_message(_Stanza) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% IQ processing
|
||||||
|
%%
|
||||||
|
|
||||||
|
%% @format-begin
|
||||||
|
|
||||||
|
component_send_packet({#iq{from = From,
|
||||||
|
to = #jid{lresource = <<"">>} = To,
|
||||||
|
id = Id,
|
||||||
|
type = Type} =
|
||||||
|
IQ,
|
||||||
|
State})
|
||||||
|
when Type /= error ->
|
||||||
|
Host = From#jid.lserver,
|
||||||
|
ServerHost = To#jid.lserver,
|
||||||
|
Permissions = get_permissions(ServerHost),
|
||||||
|
Result =
|
||||||
|
case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of
|
||||||
|
{{ok, Access}, {ok, EncapType, EncapNs, EncapFrom, EncIq}}
|
||||||
|
when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) ->
|
||||||
|
NsPermissions = proplists:get_value(iq, Access, none),
|
||||||
|
Permission =
|
||||||
|
case lists:keyfind(EncapNs, 2, NsPermissions) of
|
||||||
|
#privilege_namespace{type = AllowedType} ->
|
||||||
|
AllowedType;
|
||||||
|
_ ->
|
||||||
|
none
|
||||||
|
end,
|
||||||
|
case Permission == both
|
||||||
|
orelse Permission == get andalso Type == get
|
||||||
|
orelse Permission == set andalso Type == set
|
||||||
|
of
|
||||||
|
true ->
|
||||||
|
forward_iq(Host, To, Id, EncIq);
|
||||||
|
false ->
|
||||||
|
?INFO_MSG("IQ not forwarded: Permission not granted to ns=~s with type=~p",
|
||||||
|
[EncapNs, Type]),
|
||||||
|
drop
|
||||||
|
end;
|
||||||
|
{error, _} ->
|
||||||
|
%% Component is disconnected
|
||||||
|
?INFO_MSG("IQ not forwarded: Component seems disconnected", []),
|
||||||
|
drop;
|
||||||
|
{_, {ok, E, _, _, _}} when E /= Type ->
|
||||||
|
?INFO_MSG("IQ not forwarded: The encapsulated IQ stanza type=~p "
|
||||||
|
"does not match the top-level IQ stanza type=~p",
|
||||||
|
[E, Type]),
|
||||||
|
drop;
|
||||||
|
{_, {ok, _, _, EF, _}} when (EF /= undefined) and (EF /= To) ->
|
||||||
|
?INFO_MSG("IQ not forwarded: The FROM attribute in the encapsulated "
|
||||||
|
"IQ stanza and the TO in top-level IQ stanza do not match",
|
||||||
|
[]),
|
||||||
|
drop
|
||||||
|
end,
|
||||||
|
{Result, State};
|
||||||
|
component_send_packet(Acc) ->
|
||||||
|
Acc.
|
||||||
|
%% @format-end
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Roster processing
|
||||||
|
%%
|
||||||
|
|
||||||
-spec roster_access({true, iq()} | false, iq()) -> {true, iq()} | false.
|
-spec roster_access({true, iq()} | false, iq()) -> {true, iq()} | false.
|
||||||
roster_access({true, _IQ} = Acc, _) ->
|
roster_access({true, _IQ} = Acc, _) ->
|
||||||
Acc;
|
Acc;
|
||||||
@ -309,6 +410,8 @@ init([Host|_]) ->
|
|||||||
process_presence_out, 50),
|
process_presence_out, 50),
|
||||||
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE,
|
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE,
|
||||||
process_presence_in, 50),
|
process_presence_in, 50),
|
||||||
|
ejabberd_hooks:add(component_send_packet, ?MODULE,
|
||||||
|
component_send_packet, 50),
|
||||||
{ok, #state{server_host = Host}}.
|
{ok, #state{server_host = Host}}.
|
||||||
|
|
||||||
handle_call(Request, From, State) ->
|
handle_call(Request, From, State) ->
|
||||||
@ -320,22 +423,26 @@ handle_cast({component_connected, Host}, State) ->
|
|||||||
From = jid:make(ServerHost),
|
From = jid:make(ServerHost),
|
||||||
To = jid:make(Host),
|
To = jid:make(Host),
|
||||||
RosterPerm = get_roster_permission(ServerHost, Host),
|
RosterPerm = get_roster_permission(ServerHost, Host),
|
||||||
|
IqNamespaces = get_iq_namespaces(ServerHost, Host),
|
||||||
PresencePerm = get_presence_permission(ServerHost, Host),
|
PresencePerm = get_presence_permission(ServerHost, Host),
|
||||||
MessagePerm = get_message_permission(ServerHost, Host),
|
MessagePerm = get_message_permission(ServerHost, Host),
|
||||||
if RosterPerm /= none; PresencePerm /= none; MessagePerm /= none ->
|
if RosterPerm /= none; IqNamespaces /= []; PresencePerm /= none; MessagePerm /= none ->
|
||||||
Priv = #privilege{perms = [#privilege_perm{access = message,
|
Priv = #privilege{perms = [#privilege_perm{access = message,
|
||||||
type = MessagePerm},
|
type = MessagePerm},
|
||||||
#privilege_perm{access = roster,
|
#privilege_perm{access = roster,
|
||||||
type = RosterPerm},
|
type = RosterPerm},
|
||||||
|
#privilege_perm{access = iq,
|
||||||
|
namespaces = IqNamespaces},
|
||||||
#privilege_perm{access = presence,
|
#privilege_perm{access = presence,
|
||||||
type = PresencePerm}]},
|
type = PresencePerm}]},
|
||||||
?INFO_MSG("Granting permissions to external "
|
?INFO_MSG("Granting permissions to external "
|
||||||
"component '~ts': roster = ~ts, presence = ~ts, "
|
"component '~ts': roster = ~ts, presence = ~ts, "
|
||||||
"message = ~ts",
|
"message = ~ts,~n iq = ~p",
|
||||||
[Host, RosterPerm, PresencePerm, MessagePerm]),
|
[Host, RosterPerm, PresencePerm, MessagePerm, IqNamespaces]),
|
||||||
Msg = #message{from = From, to = To, sub_els = [Priv]},
|
Msg = #message{from = From, to = To, sub_els = [Priv]},
|
||||||
ejabberd_router:route(Msg),
|
ejabberd_router:route(Msg),
|
||||||
Permissions = maps:put(Host, [{roster, RosterPerm},
|
Permissions = maps:put(Host, [{roster, RosterPerm},
|
||||||
|
{iq, IqNamespaces},
|
||||||
{presence, PresencePerm},
|
{presence, PresencePerm},
|
||||||
{message, MessagePerm}],
|
{message, MessagePerm}],
|
||||||
get_permissions(ServerHost)),
|
get_permissions(ServerHost)),
|
||||||
@ -366,6 +473,8 @@ terminate(_Reason, State) ->
|
|||||||
Host = State#state.server_host,
|
Host = State#state.server_host,
|
||||||
case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of
|
case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of
|
||||||
false ->
|
false ->
|
||||||
|
ejabberd_hooks:delete(component_send_packet, ?MODULE,
|
||||||
|
component_send_packet, 50),
|
||||||
ejabberd_hooks:delete(component_connected, ?MODULE,
|
ejabberd_hooks:delete(component_connected, ?MODULE,
|
||||||
component_connected, 50),
|
component_connected, 50),
|
||||||
ejabberd_hooks:delete(component_disconnected, ?MODULE,
|
ejabberd_hooks:delete(component_disconnected, ?MODULE,
|
||||||
@ -396,6 +505,10 @@ get_permissions(ServerHost) ->
|
|||||||
[{_, Permissions}] -> Permissions
|
[{_, Permissions}] -> Permissions
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Message
|
||||||
|
%%
|
||||||
|
|
||||||
-spec forward_message(message()) -> ok.
|
-spec forward_message(message()) -> ok.
|
||||||
forward_message(#message{to = To} = Msg) ->
|
forward_message(#message{to = To} = Msg) ->
|
||||||
ServerHost = To#jid.lserver,
|
ServerHost = To#jid.lserver,
|
||||||
@ -436,6 +549,45 @@ forward_message(#message{to = To} = Msg) ->
|
|||||||
ejabberd_router:route_error(Msg, Err)
|
ejabberd_router:route_error(Msg, Err)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% IQ
|
||||||
|
%%
|
||||||
|
|
||||||
|
%% @format-begin
|
||||||
|
|
||||||
|
-spec get_iq_encapsulated_details(iq()) ->
|
||||||
|
{ok, set | get, binary(), jid(), iq()} |
|
||||||
|
{error, Why :: atom(), any(), iq()}.
|
||||||
|
get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) ->
|
||||||
|
Lang = xmpp:get_lang(Msg),
|
||||||
|
try xmpp:try_subtag(Msg, #privileged_iq{}) of
|
||||||
|
#privileged_iq{iq = #iq{type = EncapsulatedType, from = From} = EncIq} ->
|
||||||
|
[IqSubSub] = xmpp:get_els(IqSub),
|
||||||
|
[Element] = xmpp:get_els(IqSubSub),
|
||||||
|
Ns = xmpp:get_ns(Element),
|
||||||
|
{ok, EncapsulatedType, Ns, From, EncIq};
|
||||||
|
_ ->
|
||||||
|
Txt = ?T("No <privileged_iq/> element found"),
|
||||||
|
Err = xmpp:err_bad_request(Txt, Lang),
|
||||||
|
{error, no_privileged_iq, Err}
|
||||||
|
catch
|
||||||
|
_:{xmpp_codec, Why} ->
|
||||||
|
Txt = xmpp:io_format_error(Why),
|
||||||
|
Err = xmpp:err_bad_request(Txt, Lang),
|
||||||
|
{error, codec_error, Err}
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec forward_iq(binary(), jid(), binary(), iq()) -> iq().
|
||||||
|
forward_iq(Host, ToplevelTo, Id, Iq) ->
|
||||||
|
FromJID = ToplevelTo,
|
||||||
|
NewIq0 = Iq#iq{from = FromJID},
|
||||||
|
xmpp:put_meta(NewIq0, privilege_iq, {Id, Host, FromJID}).
|
||||||
|
%% @format-end
|
||||||
|
|
||||||
|
%%
|
||||||
|
%% Permissions
|
||||||
|
%%
|
||||||
|
|
||||||
-spec get_roster_permission(binary(), binary()) -> roster_permission() | none.
|
-spec get_roster_permission(binary(), binary()) -> roster_permission() | none.
|
||||||
get_roster_permission(ServerHost, Host) ->
|
get_roster_permission(ServerHost, Host) ->
|
||||||
Perms = mod_privilege_opt:roster(ServerHost),
|
Perms = mod_privilege_opt:roster(ServerHost),
|
||||||
@ -452,6 +604,26 @@ get_roster_permission(ServerHost, Host) ->
|
|||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec get_iq_namespaces(binary(), binary()) -> [privilege_namespace()].
|
||||||
|
get_iq_namespaces(ServerHost, Host) ->
|
||||||
|
NsPerms = mod_privilege_opt:iq(ServerHost),
|
||||||
|
[#privilege_namespace{ns = Ns, type = get_iq_permission(ServerHost, Host, Perms)} || {Ns, Perms} <- NsPerms].
|
||||||
|
|
||||||
|
-spec get_iq_permission(binary(), binary(), [iq_permission()]) -> iq_permission() | none.
|
||||||
|
get_iq_permission(ServerHost, Host, Perms) ->
|
||||||
|
case match_rule(ServerHost, Host, Perms, both) of
|
||||||
|
allow ->
|
||||||
|
both;
|
||||||
|
deny ->
|
||||||
|
Get = match_rule(ServerHost, Host, Perms, get),
|
||||||
|
Set = match_rule(ServerHost, Host, Perms, set),
|
||||||
|
if Get == allow, Set == allow -> both;
|
||||||
|
Get == allow -> get;
|
||||||
|
Set == allow -> set;
|
||||||
|
true -> none
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
-spec get_message_permission(binary(), binary()) -> message_permission() | none.
|
-spec get_message_permission(binary(), binary()) -> message_permission() | none.
|
||||||
get_message_permission(ServerHost, Host) ->
|
get_message_permission(ServerHost, Host) ->
|
||||||
Perms = mod_privilege_opt:message(ServerHost),
|
Perms = mod_privilege_opt:message(ServerHost),
|
||||||
@ -473,7 +645,12 @@ get_presence_permission(ServerHost, Host) ->
|
|||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-ifdef(OTP_BELOW_26).
|
||||||
|
-dialyzer({no_contracts, match_rule/4}).
|
||||||
|
-endif.
|
||||||
|
|
||||||
-spec match_rule(binary(), binary(), roster_permissions(), roster_permission()) -> allow | deny;
|
-spec match_rule(binary(), binary(), roster_permissions(), roster_permission()) -> allow | deny;
|
||||||
|
(binary(), binary(), iq_permissions(), iq_permission()) -> allow | deny;
|
||||||
(binary(), binary(), presence_permissions(), presence_permission()) -> allow | deny;
|
(binary(), binary(), presence_permissions(), presence_permission()) -> allow | deny;
|
||||||
(binary(), binary(), message_permissions(), message_permission()) -> allow | deny.
|
(binary(), binary(), message_permissions(), message_permission()) -> allow | deny.
|
||||||
match_rule(ServerHost, Host, Perms, Type) ->
|
match_rule(ServerHost, Host, Perms, Type) ->
|
||||||
|
@ -3,10 +3,17 @@
|
|||||||
|
|
||||||
-module(mod_privilege_opt).
|
-module(mod_privilege_opt).
|
||||||
|
|
||||||
|
-export([iq/1]).
|
||||||
-export([message/1]).
|
-export([message/1]).
|
||||||
-export([presence/1]).
|
-export([presence/1]).
|
||||||
-export([roster/1]).
|
-export([roster/1]).
|
||||||
|
|
||||||
|
-spec iq(gen_mod:opts() | global | binary()) -> [{binary(),[{'both',acl:acl()} | {'get',acl:acl()} | {'set',acl:acl()}]}].
|
||||||
|
iq(Opts) when is_map(Opts) ->
|
||||||
|
gen_mod:get_opt(iq, Opts);
|
||||||
|
iq(Host) ->
|
||||||
|
gen_mod:get_module_opt(Host, mod_privilege, iq).
|
||||||
|
|
||||||
-spec message(gen_mod:opts() | global | binary()) -> [{'outgoing','none' | acl:acl()}].
|
-spec message(gen_mod:opts() | global | binary()) -> [{'outgoing','none' | acl:acl()}].
|
||||||
message(Opts) when is_map(Opts) ->
|
message(Opts) when is_map(Opts) ->
|
||||||
gen_mod:get_opt(message, Opts);
|
gen_mod:get_opt(message, Opts);
|
||||||
|
Loading…
Reference in New Issue
Block a user