aboutsummaryrefslogtreecommitdiff
path: root/src/mod_announce.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_announce.erl')
-rw-r--r--src/mod_announce.erl961
1 files changed, 473 insertions, 488 deletions
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index d74c46bf9..013594af8 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -5,7 +5,7 @@
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
-%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
+%%% ejabberd, Copyright (C) 2002-2019 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -29,39 +29,84 @@
-module(mod_announce).
-author('alexey@process-one.net').
+-behaviour(gen_server).
-behaviour(gen_mod).
--export([start/2, init/0, stop/1, export/1, import/1,
- import/3, announce/3, send_motd/1, disco_identity/5,
+-export([start/2, stop/1, reload/3, export/1, import_info/0,
+ import_start/2, import/5, announce/1, send_motd/1, disco_identity/5,
disco_features/5, disco_items/5, depends/2,
send_announcement_to_all/3, announce_commands/4,
- announce_items/4, mod_opt_type/1]).
+ announce_items/4, mod_opt_type/1, mod_options/1, clean_cache/1]).
+-export([init/1, handle_call/3, handle_cast/2,
+ handle_info/2, terminate/2, code_change/3]).
+-export([announce_all/1,
+ announce_all_hosts_all/1,
+ announce_online/1,
+ announce_all_hosts_online/1,
+ announce_motd/1,
+ announce_all_hosts_motd/1,
+ announce_motd_update/1,
+ announce_all_hosts_motd_update/1,
+ announce_motd_delete/1,
+ announce_all_hosts_motd_delete/1]).
--include("ejabberd.hrl").
-include("logger.hrl").
--include("jlib.hrl").
--include("adhoc.hrl").
+-include("xmpp.hrl").
-include("mod_announce.hrl").
+-include("translate.hrl").
-callback init(binary(), gen_mod:opts()) -> any().
--callback import(binary(), #motd{} | #motd_users{}) -> ok | pass.
--callback set_motd_users(binary(), [{binary(), binary(), binary()}]) -> {atomic, any()}.
--callback set_motd(binary(), xmlel()) -> {atomic, any()}.
--callback delete_motd(binary()) -> {atomic, any()}.
--callback get_motd(binary()) -> {ok, xmlel()} | error.
--callback is_motd_user(binary(), binary()) -> boolean().
--callback set_motd_user(binary(), binary()) -> {atomic, any()}.
+-callback import(binary(), binary(), [binary()]) -> ok.
+-callback set_motd_users(binary(), [{binary(), binary(), binary()}]) -> ok | {error, any()}.
+-callback set_motd(binary(), xmlel()) -> ok | {error, any()}.
+-callback delete_motd(binary()) -> ok | {error, any()}.
+-callback get_motd(binary()) -> {ok, xmlel()} | error | {error, any()}.
+-callback is_motd_user(binary(), binary()) -> {ok, boolean()} | {error, any()}.
+-callback set_motd_user(binary(), binary()) -> ok | {error, any()}.
+-callback use_cache(binary()) -> boolean().
+-callback cache_nodes(binary()) -> [node()].
--define(PROCNAME, ejabberd_announce).
+-optional_callbacks([use_cache/1, cache_nodes/1]).
+
+-record(state, {host :: binary()}).
-define(NS_ADMINL(Sub), [<<"http:">>, <<"jabber.org">>, <<"protocol">>,
<<"admin">>, <<Sub>>]).
+-define(MOTD_CACHE, motd_cache).
tokenize(Node) -> str:tokens(Node, <<"/#">>).
+%%====================================================================
+%% gen_mod callbacks
+%%====================================================================
start(Host, Opts) ->
- Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
+ gen_mod:start_child(?MODULE, Host, Opts).
+
+stop(Host) ->
+ gen_mod:stop_child(?MODULE, Host).
+
+reload(Host, NewOpts, OldOpts) ->
+ NewMod = gen_mod:db_mod(NewOpts, ?MODULE),
+ OldMod = gen_mod:db_mod(OldOpts, ?MODULE),
+ if NewMod /= OldMod ->
+ NewMod:init(Host, NewOpts);
+ true ->
+ ok
+ end,
+ init_cache(NewMod, Host, NewOpts).
+
+depends(_Host, _Opts) ->
+ [{mod_adhoc, hard}].
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+init([Host|_]) ->
+ process_flag(trap_exit, true),
+ Opts = gen_mod:get_module_opts(Host, ?MODULE),
+ Mod = gen_mod:db_mod(Opts, ?MODULE),
Mod:init(Host, Opts),
+ init_cache(Mod, Host, Opts),
ejabberd_hooks:add(local_send_to_resource_hook, Host,
?MODULE, announce, 50),
ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, disco_identity, 50),
@@ -69,114 +114,98 @@ start(Host, Opts) ->
ejabberd_hooks:add(disco_local_items, Host, ?MODULE, disco_items, 50),
ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, announce_items, 50),
ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, announce_commands, 50),
- ejabberd_hooks:add(user_available_hook, Host,
+ ejabberd_hooks:add(c2s_self_presence, Host,
?MODULE, send_motd, 50),
- register(gen_mod:get_module_proc(Host, ?PROCNAME),
- proc_lib:spawn(?MODULE, init, [])).
+ {ok, #state{host = Host}}.
+
+handle_call(Request, From, State) ->
+ ?WARNING_MSG("Unexpected call from ~p: ~p", [From, Request]),
+ {noreply, State}.
+
+handle_cast({F, #message{from = From, to = To} = Pkt}, State) when is_atom(F) ->
+ LServer = To#jid.lserver,
+ Host = case F of
+ announce_all -> LServer;
+ announce_all_hosts_all -> global;
+ announce_online -> LServer;
+ announce_all_hosts_online -> global;
+ announce_motd -> LServer;
+ announce_all_hosts_motd -> global;
+ announce_motd_update -> LServer;
+ announce_all_hosts_motd_update -> global;
+ announce_motd_delete -> LServer;
+ announce_all_hosts_motd_delete -> global
+ end,
+ Access = get_access(Host),
+ case acl:match_rule(Host, Access, From) of
+ deny ->
+ route_forbidden_error(Pkt);
+ allow ->
+ ?MODULE:F(Pkt)
+ end,
+ {noreply, State};
+handle_cast(Msg, State) ->
+ ?WARNING_MSG("Unexpected cast: ~p", [Msg]),
+ {noreply, State}.
-depends(_Host, _Opts) ->
- [{mod_adhoc, hard}].
-init() ->
- loop().
-
-loop() ->
- receive
- {announce_all, From, To, Packet} ->
- announce_all(From, To, Packet),
- loop();
- {announce_all_hosts_all, From, To, Packet} ->
- announce_all_hosts_all(From, To, Packet),
- loop();
- {announce_online, From, To, Packet} ->
- announce_online(From, To, Packet),
- loop();
- {announce_all_hosts_online, From, To, Packet} ->
- announce_all_hosts_online(From, To, Packet),
- loop();
- {announce_motd, From, To, Packet} ->
- announce_motd(From, To, Packet),
- loop();
- {announce_all_hosts_motd, From, To, Packet} ->
- announce_all_hosts_motd(From, To, Packet),
- loop();
- {announce_motd_update, From, To, Packet} ->
- announce_motd_update(From, To, Packet),
- loop();
- {announce_all_hosts_motd_update, From, To, Packet} ->
- announce_all_hosts_motd_update(From, To, Packet),
- loop();
- {announce_motd_delete, From, To, Packet} ->
- announce_motd_delete(From, To, Packet),
- loop();
- {announce_all_hosts_motd_delete, From, To, Packet} ->
- announce_all_hosts_motd_delete(From, To, Packet),
- loop();
- _ ->
- loop()
- end.
+handle_info(Info, State) ->
+ ?WARNING_MSG("Unexpected info: ~p", [Info]),
+ {noreply, State}.
-stop(Host) ->
+terminate(_Reason, #state{host = Host}) ->
ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, announce_commands, 50),
ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, announce_items, 50),
ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, disco_identity, 50),
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50),
ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, disco_items, 50),
- ejabberd_hooks:delete(local_send_to_resource_hook, Host,
- ?MODULE, announce, 50),
- ejabberd_hooks:delete(user_available_hook, Host,
- ?MODULE, send_motd, 50),
- Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- exit(whereis(Proc), stop),
- {wait, Proc}.
+ ejabberd_hooks:delete(local_send_to_resource_hook, Host, ?MODULE, announce, 50),
+ ejabberd_hooks:delete(c2s_self_presence, Host, ?MODULE, send_motd, 50).
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
%% Announcing via messages to a custom resource
-announce(From, #jid{luser = <<>>} = To, #xmlel{name = <<"message">>} = Packet) ->
- Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME),
- case To#jid.lresource of
- <<"announce/all">> ->
- Proc ! {announce_all, From, To, Packet},
- stop;
- <<"announce/all-hosts/all">> ->
- Proc ! {announce_all_hosts_all, From, To, Packet},
- stop;
- <<"announce/online">> ->
- Proc ! {announce_online, From, To, Packet},
- stop;
- <<"announce/all-hosts/online">> ->
- Proc ! {announce_all_hosts_online, From, To, Packet},
- stop;
- <<"announce/motd">> ->
- Proc ! {announce_motd, From, To, Packet},
- stop;
- <<"announce/all-hosts/motd">> ->
- Proc ! {announce_all_hosts_motd, From, To, Packet},
- stop;
- <<"announce/motd/update">> ->
- Proc ! {announce_motd_update, From, To, Packet},
- stop;
- <<"announce/all-hosts/motd/update">> ->
- Proc ! {announce_all_hosts_motd_update, From, To, Packet},
- stop;
- <<"announce/motd/delete">> ->
- Proc ! {announce_motd_delete, From, To, Packet},
- stop;
- <<"announce/all-hosts/motd/delete">> ->
- Proc ! {announce_all_hosts_motd_delete, From, To, Packet},
- stop;
- _ ->
- ok
+-spec announce(stanza()) -> ok | stop.
+announce(#message{to = #jid{luser = <<>>} = To} = Packet) ->
+ Proc = gen_mod:get_module_proc(To#jid.lserver, ?MODULE),
+ Res = case To#jid.lresource of
+ <<"announce/all">> ->
+ gen_server:cast(Proc, {announce_all, Packet});
+ <<"announce/all-hosts/all">> ->
+ gen_server:cast(Proc, {announce_all_hosts_all, Packet});
+ <<"announce/online">> ->
+ gen_server:cast(Proc, {announce_online, Packet});
+ <<"announce/all-hosts/online">> ->
+ gen_server:cast(Proc, {announce_all_hosts_online, Packet});
+ <<"announce/motd">> ->
+ gen_server:cast(Proc, {announce_motd, Packet});
+ <<"announce/all-hosts/motd">> ->
+ gen_server:cast(Proc, {announce_all_hosts_motd, Packet});
+ <<"announce/motd/update">> ->
+ gen_server:cast(Proc, {announce_motd_update, Packet});
+ <<"announce/all-hosts/motd/update">> ->
+ gen_server:cast(Proc, {announce_all_hosts_motd_update, Packet});
+ <<"announce/motd/delete">> ->
+ gen_server:cast(Proc, {announce_motd_delete, Packet});
+ <<"announce/all-hosts/motd/delete">> ->
+ gen_server:cast(Proc, {announce_all_hosts_motd_delete, Packet});
+ _ ->
+ undefined
+ end,
+ case Res of
+ ok -> stop;
+ _ -> ok
end;
-announce(_From, _To, _Packet) ->
+announce(_Packet) ->
ok.
%%-------------------------------------------------------------------------
%% Announcing via ad-hoc commands
-define(INFO_COMMAND(Lang, Node),
- [#xmlel{name = <<"identity">>,
- attrs = [{<<"category">>, <<"automation">>},
- {<<"type">>, <<"command-node">>},
- {<<"name">>, get_title(Lang, Node)}]}]).
+ [#identity{category = <<"automation">>,
+ type = <<"command-node">>,
+ name = get_title(Lang, Node)}]).
disco_identity(Acc, _From, _To, Node, Lang) ->
LNode = tokenize(Node),
@@ -210,7 +239,7 @@ disco_identity(Acc, _From, _To, Node, Lang) ->
-define(INFO_RESULT(Allow, Feats, Lang),
case Allow of
deny ->
- {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
+ {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)};
allow ->
{result, Feats}
end).
@@ -225,8 +254,8 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, <<"announce">>, Lang) -
case {acl:match_rule(LServer, Access1, From),
acl:match_rule(global, Access2, From)} of
{deny, deny} ->
- Txt = <<"Denied by ACL">>,
- {error, ?ERRT_FORBIDDEN(Lang, Txt)};
+ Txt = ?T("Access denied by service policy"),
+ {error, xmpp:err_forbidden(Txt, Lang)};
_ ->
{result, []}
end
@@ -269,26 +298,19 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) ->
%%-------------------------------------------------------------------------
-define(NODE_TO_ITEM(Lang, Server, Node),
-(
- #xmlel{
- name = <<"item">>,
- attrs = [
- {<<"jid">>, Server},
- {<<"node">>, Node},
- {<<"name">>, get_title(Lang, Node)}
- ]
- }
-)).
+ #disco_item{jid = jid:make(Server),
+ node = Node,
+ name = get_title(Lang, Node)}).
-define(ITEMS_RESULT(Allow, Items, Lang),
case Allow of
deny ->
- {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
+ {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)};
allow ->
{result, Items}
end).
-disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, <<>>, Lang) ->
+disco_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, <<"">>, Lang) ->
case gen_mod:is_loaded(LServer, mod_adhoc) of
false ->
Acc;
@@ -353,7 +375,10 @@ disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, Lang) ->
end.
%%-------------------------------------------------------------------------
-
+-spec announce_items(empty | {error, stanza_error()} | {result, [disco_item()]},
+ jid(), jid(), binary()) -> {error, stanza_error()} |
+ {result, [disco_item()]} |
+ empty.
announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) ->
Access1 = get_access(LServer),
Nodes1 = case acl:match_rule(LServer, Access1, From) of
@@ -393,15 +418,16 @@ announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang)
commands_result(Allow, From, To, Request) ->
case Allow of
deny ->
- Lang = Request#adhoc_request.lang,
- {error, ?ERRT_FORBIDDEN(Lang, <<"Denied by ACL">>)};
+ Lang = Request#adhoc_command.lang,
+ {error, xmpp:err_forbidden(?T("Access denied by service policy"), Lang)};
allow ->
announce_commands(From, To, Request)
end.
-
+-spec announce_commands(empty | adhoc_command(), jid(), jid(), adhoc_command()) ->
+ adhoc_command() | {error, stanza_error()}.
announce_commands(Acc, From, #jid{lserver = LServer} = To,
- #adhoc_request{ node = Node} = Request) ->
+ #adhoc_command{node = Node} = Request) ->
LNode = tokenize(Node),
F = fun() ->
Access = get_access(global),
@@ -440,112 +466,72 @@ announce_commands(Acc, From, #jid{lserver = LServer} = To,
%%-------------------------------------------------------------------------
announce_commands(From, To,
- #adhoc_request{lang = Lang,
+ #adhoc_command{lang = Lang,
node = Node,
- action = Action,
- xdata = XData} = Request) ->
- %% If the "action" attribute is not present, it is
- %% understood as "execute". If there was no <actions/>
- %% element in the first response (which there isn't in our
- %% case), "execute" and "complete" are equivalent.
- ActionIsExecute = lists:member(Action, [<<>>, <<"execute">>, <<"complete">>]),
- if Action == <<"cancel">> ->
+ sid = SID,
+ xdata = XData,
+ action = Action} = Request) ->
+ if Action == cancel ->
%% User cancels request
- adhoc:produce_response(Request, #adhoc_response{status = canceled});
- XData == false, ActionIsExecute ->
+ #adhoc_command{status = canceled, lang = Lang, node = Node,
+ sid = SID};
+ XData == undefined andalso Action == execute ->
%% User requests form
- Elements = generate_adhoc_form(Lang, Node, To#jid.lserver),
- adhoc:produce_response(Request,
- #adhoc_response{status = executing,elements = [Elements]});
- XData /= false, ActionIsExecute ->
- %% User returns form.
- case jlib:parse_xdata_submit(XData) of
- invalid ->
- {error, ?ERRT_BAD_REQUEST(Lang, <<"Incorrect data form">>)};
- Fields ->
- handle_adhoc_form(From, To, Request, Fields)
+ Form = generate_adhoc_form(Lang, Node, To#jid.lserver),
+ xmpp_util:make_adhoc_response(
+ #adhoc_command{status = executing, lang = Lang, node = Node,
+ sid = SID, xdata = Form});
+ XData /= undefined andalso (Action == execute orelse Action == complete) ->
+ case handle_adhoc_form(From, To, Request) of
+ ok ->
+ #adhoc_command{lang = Lang, node = Node, sid = SID,
+ status = completed};
+ {error, _} = Err ->
+ Err
end;
true ->
- Txt = <<"Incorrect action or data form">>,
- {error, ?ERRT_BAD_REQUEST(Lang, Txt)}
+ Txt = ?T("Unexpected action"),
+ {error, xmpp:err_bad_request(Txt, Lang)}
end.
--define(VVALUE(Val),
-(
- #xmlel{
- name = <<"value">>,
- children = [{xmlcdata, Val}]
- }
-)).
-
-define(TVFIELD(Type, Var, Val),
-(
- #xmlel{
- name = <<"field">>,
- attrs = [{<<"type">>, Type}, {<<"var">>, Var}],
- children = vvaluel(Val)
- }
-)).
-
--define(HFIELD(), ?TVFIELD(<<"hidden">>, <<"FORM_TYPE">>, ?NS_ADMIN)).
+ #xdata_field{type = Type, var = Var, values = vvaluel(Val)}).
vvaluel(Val) ->
case Val of
<<>> -> [];
- _ -> [?VVALUE(Val)]
+ _ -> [Val]
end.
generate_adhoc_form(Lang, Node, ServerHost) ->
LNode = tokenize(Node),
- {OldSubject, OldBody} = if (LNode == ?NS_ADMINL("edit-motd"))
+ {OldSubject, OldBody} = if (LNode == ?NS_ADMINL("edit-motd"))
or (LNode == ?NS_ADMINL("edit-motd-allhosts")) ->
get_stored_motd(ServerHost);
- true ->
+ true ->
{<<>>, <<>>}
end,
- #xmlel{
- name = <<"x">>,
- attrs = [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}],
- children = [
- ?HFIELD(),
- #xmlel{name = <<"title">>, children = [{xmlcdata, get_title(Lang, Node)}]}
- ]
- ++
- if (LNode == ?NS_ADMINL("delete-motd"))
- or (LNode == ?NS_ADMINL("delete-motd-allhosts")) ->
- [#xmlel{
- name = <<"field">>,
- attrs = [
- {<<"var">>, <<"confirm">>},
- {<<"type">>, <<"boolean">>},
- {<<"label">>,
- translate:translate(Lang, <<"Really delete message of the day?">>)}
- ],
- children = [
- #xmlel{name = <<"value">>, children = [{xmlcdata, <<"true">>}]}
- ]
- }
- ];
- true ->
- [#xmlel{
- name = <<"field">>,
- attrs = [
- {<<"var">>, <<"subject">>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>, translate:translate(Lang, <<"Subject">>)}],
- children = vvaluel(OldSubject)
- },
- #xmlel{
- name = <<"field">>,
- attrs = [
- {<<"var">>, <<"body">>},
- {<<"type">>, <<"text-multi">>},
- {<<"label">>, translate:translate(Lang, <<"Message body">>)}],
- children = vvaluel(OldBody)
- }
- ]
-
- end}.
+ Fs = if (LNode == ?NS_ADMINL("delete-motd"))
+ or (LNode == ?NS_ADMINL("delete-motd-allhosts")) ->
+ [#xdata_field{type = boolean,
+ var = <<"confirm">>,
+ label = translate:translate(
+ Lang, ?T("Really delete message of the day?")),
+ values = [<<"true">>]}];
+ true ->
+ [#xdata_field{type = 'text-single',
+ var = <<"subject">>,
+ label = translate:translate(Lang, ?T("Subject")),
+ values = vvaluel(OldSubject)},
+ #xdata_field{type = 'text-multi',
+ var = <<"body">>,
+ label = translate:translate(Lang, ?T("Message body")),
+ values = vvaluel(OldBody)}]
+ end,
+ #xdata{type = form,
+ title = get_title(Lang, Node),
+ fields = [#xdata_field{type = hidden, var = <<"FORM_TYPE">>,
+ values = [?NS_ADMIN]}|Fs]}.
join_lines([]) ->
<<>>;
@@ -558,227 +544,130 @@ join_lines([], Acc) ->
iolist_to_binary(lists:reverse(tl(Acc))).
handle_adhoc_form(From, #jid{lserver = LServer} = To,
- #adhoc_request{lang = Lang,
- node = Node,
- sessionid = SessionID},
- Fields) ->
- Confirm = case lists:keysearch(<<"confirm">>, 1, Fields) of
- {value, {<<"confirm">>, [<<"true">>]}} ->
- true;
- {value, {<<"confirm">>, [<<"1">>]}} ->
- true;
- _ ->
- false
+ #adhoc_command{lang = Lang, node = Node,
+ xdata = XData}) ->
+ Confirm = case xmpp_util:get_xdata_values(<<"confirm">>, XData) of
+ [<<"true">>] -> true;
+ [<<"1">>] -> true;
+ _ -> false
end,
- Subject = case lists:keysearch(<<"subject">>, 1, Fields) of
- {value, {<<"subject">>, SubjectLines}} ->
- %% There really shouldn't be more than one
- %% subject line, but can we stop them?
- join_lines(SubjectLines);
- _ ->
- <<>>
- end,
- Body = case lists:keysearch(<<"body">>, 1, Fields) of
- {value, {<<"body">>, BodyLines}} ->
- join_lines(BodyLines);
- _ ->
- <<>>
- end,
- Response = #adhoc_response{lang = Lang,
- node = Node,
- sessionid = SessionID,
- status = completed},
- Packet = #xmlel{
- name = <<"message">>,
- attrs = [{<<"type">>, <<"headline">>}],
- children = if Subject /= <<>> ->
- [#xmlel{name = <<"subject">>, children = [{xmlcdata, Subject}]}];
- true ->
- []
- end
- ++
- if Body /= <<>> ->
- [#xmlel{name = <<"body">>, children = [{xmlcdata, Body}]}];
- true ->
- []
- end
- },
- Proc = gen_mod:get_module_proc(LServer, ?PROCNAME),
+ Subject = join_lines(xmpp_util:get_xdata_values(<<"subject">>, XData)),
+ Body = join_lines(xmpp_util:get_xdata_values(<<"body">>, XData)),
+ Packet = #message{from = From,
+ to = To,
+ type = headline,
+ body = xmpp:mk_text(Body),
+ subject = xmpp:mk_text(Subject)},
+ Proc = gen_mod:get_module_proc(LServer, ?MODULE),
case {Node, Body} of
{?NS_ADMIN_DELETE_MOTD, _} ->
if Confirm ->
- Proc ! {announce_motd_delete, From, To, Packet},
- adhoc:produce_response(Response);
+ gen_server:cast(Proc, {announce_motd_delete, Packet});
true ->
- adhoc:produce_response(Response)
+ ok
end;
{?NS_ADMIN_DELETE_MOTD_ALLHOSTS, _} ->
if Confirm ->
- Proc ! {announce_all_hosts_motd_delete, From, To, Packet},
- adhoc:produce_response(Response);
+ gen_server:cast(Proc, {announce_all_hosts_motd_delete, Packet});
true ->
- adhoc:produce_response(Response)
+ ok
end;
{_, <<>>} ->
%% An announce message with no body is definitely an operator error.
%% Throw an error and give him/her a chance to send message again.
- {error, ?ERRT_NOT_ACCEPTABLE(Lang,
- <<"No body provided for announce message">>)};
- %% Now send the packet to ?PROCNAME.
+ {error, xmpp:err_not_acceptable(
+ ?T("No body provided for announce message"), Lang)};
+ %% Now send the packet to ?MODULE.
%% We don't use direct announce_* functions because it
%% leads to large delay in response and <iq/> queries processing
{?NS_ADMIN_ANNOUNCE, _} ->
- Proc ! {announce_online, From, To, Packet},
- adhoc:produce_response(Response);
- {?NS_ADMIN_ANNOUNCE_ALLHOSTS, _} ->
- Proc ! {announce_all_hosts_online, From, To, Packet},
- adhoc:produce_response(Response);
+ gen_server:cast(Proc, {announce_online, Packet});
+ {?NS_ADMIN_ANNOUNCE_ALLHOSTS, _} ->
+ gen_server:cast(Proc, {announce_all_hosts_online, Packet});
{?NS_ADMIN_ANNOUNCE_ALL, _} ->
- Proc ! {announce_all, From, To, Packet},
- adhoc:produce_response(Response);
- {?NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS, _} ->
- Proc ! {announce_all_hosts_all, From, To, Packet},
- adhoc:produce_response(Response);
+ gen_server:cast(Proc, {announce_all, Packet});
+ {?NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS, _} ->
+ gen_server:cast(Proc, {announce_all_hosts_all, Packet});
{?NS_ADMIN_SET_MOTD, _} ->
- Proc ! {announce_motd, From, To, Packet},
- adhoc:produce_response(Response);
- {?NS_ADMIN_SET_MOTD_ALLHOSTS, _} ->
- Proc ! {announce_all_hosts_motd, From, To, Packet},
- adhoc:produce_response(Response);
+ gen_server:cast(Proc, {announce_motd, Packet});
+ {?NS_ADMIN_SET_MOTD_ALLHOSTS, _} ->
+ gen_server:cast(Proc, {announce_all_hosts_motd, Packet});
{?NS_ADMIN_EDIT_MOTD, _} ->
- Proc ! {announce_motd_update, From, To, Packet},
- adhoc:produce_response(Response);
- {?NS_ADMIN_EDIT_MOTD_ALLHOSTS, _} ->
- Proc ! {announce_all_hosts_motd_update, From, To, Packet},
- adhoc:produce_response(Response);
- _ ->
+ gen_server:cast(Proc, {announce_motd_update, Packet});
+ {?NS_ADMIN_EDIT_MOTD_ALLHOSTS, _} ->
+ gen_server:cast(Proc, {announce_all_hosts_motd_update, Packet});
+ Junk ->
%% This can't happen, as we haven't registered any other
%% command nodes.
- {error, ?ERR_INTERNAL_SERVER_ERROR}
+ ?ERROR_MSG("Unexpected node/body = ~p", [Junk]),
+ {error, xmpp:err_internal_server_error()}
end.
get_title(Lang, <<"announce">>) ->
- translate:translate(Lang, <<"Announcements">>);
+ translate:translate(Lang, ?T("Announcements"));
get_title(Lang, ?NS_ADMIN_ANNOUNCE_ALL) ->
- translate:translate(Lang, <<"Send announcement to all users">>);
+ translate:translate(Lang, ?T("Send announcement to all users"));
get_title(Lang, ?NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS) ->
- translate:translate(Lang, <<"Send announcement to all users on all hosts">>);
+ translate:translate(Lang, ?T("Send announcement to all users on all hosts"));
get_title(Lang, ?NS_ADMIN_ANNOUNCE) ->
- translate:translate(Lang, <<"Send announcement to all online users">>);
+ translate:translate(Lang, ?T("Send announcement to all online users"));
get_title(Lang, ?NS_ADMIN_ANNOUNCE_ALLHOSTS) ->
- translate:translate(Lang, <<"Send announcement to all online users on all hosts">>);
+ translate:translate(Lang, ?T("Send announcement to all online users on all hosts"));
get_title(Lang, ?NS_ADMIN_SET_MOTD) ->
- translate:translate(Lang, <<"Set message of the day and send to online users">>);
+ translate:translate(Lang, ?T("Set message of the day and send to online users"));
get_title(Lang, ?NS_ADMIN_SET_MOTD_ALLHOSTS) ->
- translate:translate(Lang, <<"Set message of the day on all hosts and send to online users">>);
+ translate:translate(Lang, ?T("Set message of the day on all hosts and send to online users"));
get_title(Lang, ?NS_ADMIN_EDIT_MOTD) ->
- translate:translate(Lang, <<"Update message of the day (don't send)">>);
+ translate:translate(Lang, ?T("Update message of the day (don't send)"));
get_title(Lang, ?NS_ADMIN_EDIT_MOTD_ALLHOSTS) ->
- translate:translate(Lang, <<"Update message of the day on all hosts (don't send)">>);
+ translate:translate(Lang, ?T("Update message of the day on all hosts (don't send)"));
get_title(Lang, ?NS_ADMIN_DELETE_MOTD) ->
- translate:translate(Lang, <<"Delete message of the day">>);
+ translate:translate(Lang, ?T("Delete message of the day"));
get_title(Lang, ?NS_ADMIN_DELETE_MOTD_ALLHOSTS) ->
- translate:translate(Lang, <<"Delete message of the day on all hosts">>).
+ translate:translate(Lang, ?T("Delete message of the day on all hosts")).
%%-------------------------------------------------------------------------
-announce_all(From, To, Packet) ->
- Host = To#jid.lserver,
- Access = get_access(Host),
- case acl:match_rule(Host, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- Local = jid:make(<<>>, To#jid.server, <<>>),
- lists:foreach(
- fun({User, Server}) ->
- Dest = jid:make(User, Server, <<>>),
- ejabberd_router:route(Local, Dest, add_store_hint(Packet))
- end, ejabberd_auth:get_vh_registered_users(Host))
- end.
-
-announce_all_hosts_all(From, To, Packet) ->
- Access = get_access(global),
- case acl:match_rule(global, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- Local = jid:make(<<>>, To#jid.server, <<>>),
- lists:foreach(
- fun({User, Server}) ->
- Dest = jid:make(User, Server, <<>>),
- ejabberd_router:route(Local, Dest, add_store_hint(Packet))
- end, ejabberd_auth:dirty_get_registered_users())
- end.
+announce_all(#message{to = To} = Packet) ->
+ Local = jid:make(To#jid.server),
+ lists:foreach(
+ fun({User, Server}) ->
+ Dest = jid:make(User, Server),
+ ejabberd_router:route(
+ xmpp:set_from_to(add_store_hint(Packet), Local, Dest))
+ end, ejabberd_auth:get_users(To#jid.lserver)).
+
+announce_all_hosts_all(#message{to = To} = Packet) ->
+ Local = jid:make(To#jid.server),
+ lists:foreach(
+ fun({User, Server}) ->
+ Dest = jid:make(User, Server),
+ ejabberd_router:route(
+ xmpp:set_from_to(add_store_hint(Packet), Local, Dest))
+ end, ejabberd_auth:get_users()).
-announce_online(From, To, Packet) ->
- Host = To#jid.lserver,
- Access = get_access(Host),
- case acl:match_rule(Host, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- announce_online1(ejabberd_sm:get_vh_session_list(Host),
- To#jid.server,
- Packet)
- end.
+announce_online(#message{to = To} = Packet) ->
+ announce_online1(ejabberd_sm:get_vh_session_list(To#jid.lserver),
+ To#jid.server, Packet).
-announce_all_hosts_online(From, To, Packet) ->
- Access = get_access(global),
- case acl:match_rule(global, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- announce_online1(ejabberd_sm:dirty_get_sessions_list(),
- To#jid.server,
- Packet)
- end.
+announce_all_hosts_online(#message{to = To} = Packet) ->
+ announce_online1(ejabberd_sm:dirty_get_sessions_list(),
+ To#jid.server, Packet).
announce_online1(Sessions, Server, Packet) ->
- Local = jid:make(<<>>, Server, <<>>),
+ Local = jid:make(Server),
lists:foreach(
fun({U, S, R}) ->
Dest = jid:make(U, S, R),
- ejabberd_router:route(Local, Dest, Packet)
+ ejabberd_router:route(xmpp:set_from_to(Packet, Local, Dest))
end, Sessions).
-announce_motd(From, To, Packet) ->
- Host = To#jid.lserver,
- Access = get_access(Host),
- case acl:match_rule(Host, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- announce_motd(Host, Packet)
- end.
+announce_motd(#message{to = To} = Packet) ->
+ announce_motd(To#jid.lserver, Packet).
-announce_all_hosts_motd(From, To, Packet) ->
- Access = get_access(global),
- case acl:match_rule(global, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- Hosts = ?MYHOSTS,
- [announce_motd(Host, Packet) || Host <- Hosts]
- end.
+announce_all_hosts_motd(Packet) ->
+ Hosts = ejabberd_option:hosts(),
+ [announce_motd(Host, Packet) || Host <- Hosts].
announce_motd(Host, Packet) ->
LServer = jid:nameprep(Host),
@@ -788,147 +677,243 @@ announce_motd(Host, Packet) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:set_motd_users(LServer, Sessions).
-announce_motd_update(From, To, Packet) ->
- Host = To#jid.lserver,
- Access = get_access(Host),
- case acl:match_rule(Host, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- announce_motd_update(Host, Packet)
- end.
+announce_motd_update(#message{to = To} = Packet) ->
+ announce_motd_update(To#jid.lserver, Packet).
-announce_all_hosts_motd_update(From, To, Packet) ->
- Access = get_access(global),
- case acl:match_rule(global, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- Hosts = ?MYHOSTS,
- [announce_motd_update(Host, Packet) || Host <- Hosts]
- end.
+announce_all_hosts_motd_update(Packet) ->
+ Hosts = ejabberd_option:hosts(),
+ [announce_motd_update(Host, Packet) || Host <- Hosts].
announce_motd_update(LServer, Packet) ->
- announce_motd_delete(LServer),
Mod = gen_mod:db_mod(LServer, ?MODULE),
- Mod:set_motd(LServer, Packet).
+ delete_motd(Mod, LServer),
+ set_motd(Mod, LServer, xmpp:encode(Packet)).
-announce_motd_delete(From, To, Packet) ->
- Host = To#jid.lserver,
- Access = get_access(Host),
- case acl:match_rule(Host, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- announce_motd_delete(Host)
+announce_motd_delete(#message{to = To}) ->
+ LServer = To#jid.lserver,
+ Mod = gen_mod:db_mod(LServer, ?MODULE),
+ delete_motd(Mod, LServer).
+
+announce_all_hosts_motd_delete(_Packet) ->
+ lists:foreach(
+ fun(Host) ->
+ Mod = gen_mod:db_mod(Host, ?MODULE),
+ delete_motd(Mod, Host)
+ end, ejabberd_option:hosts()).
+
+-spec send_motd({presence(), ejabberd_c2s:state()}) -> {presence(), ejabberd_c2s:state()}.
+send_motd({_, #{pres_last := _}} = Acc) ->
+ %% This is just a presence update, nothing to do
+ Acc;
+send_motd({#presence{type = available},
+ #{jid := #jid{luser = LUser, lserver = LServer} = JID}} = Acc)
+ when LUser /= <<>> ->
+ Mod = gen_mod:db_mod(LServer, ?MODULE),
+ case get_motd(Mod, LServer) of
+ {ok, Packet} ->
+ CodecOpts = ejabberd_config:codec_options(),
+ try xmpp:decode(Packet, ?NS_CLIENT, CodecOpts) of
+ Msg ->
+ case is_motd_user(Mod, LUser, LServer) of
+ false ->
+ Local = jid:make(LServer),
+ ejabberd_router:route(
+ xmpp:set_from_to(Msg, Local, JID)),
+ set_motd_user(Mod, LUser, LServer);
+ true ->
+ ok
+ end
+ catch _:{xmpp_codec, Why} ->
+ ?ERROR_MSG("Failed to decode motd packet ~p: ~ts",
+ [Packet, xmpp:format_error(Why)])
+ end;
+ _ ->
+ ok
+ end,
+ Acc;
+send_motd(Acc) ->
+ Acc.
+
+-spec get_motd(module(), binary()) -> {ok, xmlel()} | error | {error, any()}.
+get_motd(Mod, LServer) ->
+ case use_cache(Mod, LServer) of
+ true ->
+ ets_cache:lookup(
+ ?MOTD_CACHE, {<<"">>, LServer},
+ fun() -> Mod:get_motd(LServer) end);
+ false ->
+ Mod:get_motd(LServer)
end.
-announce_all_hosts_motd_delete(From, To, Packet) ->
- Access = get_access(global),
- case acl:match_rule(global, Access, From) of
- deny ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- Txt = <<"Denied by ACL">>,
- Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
- allow ->
- Hosts = ?MYHOSTS,
- [announce_motd_delete(Host) || Host <- Hosts]
+-spec set_motd(module(), binary(), xmlel()) -> any().
+set_motd(Mod, LServer, XML) ->
+ case use_cache(Mod, LServer) of
+ true ->
+ ets_cache:update(
+ ?MOTD_CACHE, {<<"">>, LServer}, {ok, XML},
+ fun() -> Mod:set_motd(LServer, XML) end,
+ cache_nodes(Mod, LServer));
+ false ->
+ Mod:set_motd(LServer, XML)
end.
-announce_motd_delete(LServer) ->
- Mod = gen_mod:db_mod(LServer, ?MODULE),
- Mod:delete_motd(LServer).
+-spec is_motd_user(module(), binary(), binary()) -> boolean().
+is_motd_user(Mod, LUser, LServer) ->
+ Res = case use_cache(Mod, LServer) of
+ true ->
+ ets_cache:lookup(
+ ?MOTD_CACHE, {LUser, LServer},
+ fun() -> Mod:is_motd_user(LUser, LServer) end);
+ false ->
+ Mod:is_motd_user(LUser, LServer)
+ end,
+ case Res of
+ {ok, Bool} -> Bool;
+ _ -> false
+ end.
-send_motd(#jid{luser = LUser, lserver = LServer} = JID) when LUser /= <<>> ->
- Mod = gen_mod:db_mod(LServer, ?MODULE),
- case Mod:get_motd(LServer) of
- {ok, Packet} ->
- case Mod:is_motd_user(LUser, LServer) of
- false ->
- Local = jid:make(<<>>, LServer, <<>>),
- ejabberd_router:route(Local, JID, Packet),
- Mod:set_motd_user(LUser, LServer);
+-spec set_motd_user(module(), binary(), binary()) -> any().
+set_motd_user(Mod, LUser, LServer) ->
+ case use_cache(Mod, LServer) of
+ true ->
+ ets_cache:update(
+ ?MOTD_CACHE, {LUser, LServer}, {ok, true},
+ fun() -> Mod:set_motd_user(LUser, LServer) end,
+ cache_nodes(Mod, LServer));
+ false ->
+ Mod:set_motd_user(LUser, LServer)
+ end.
+
+-spec delete_motd(module(), binary()) -> ok | {error, any()}.
+delete_motd(Mod, LServer) ->
+ case Mod:delete_motd(LServer) of
+ ok ->
+ case use_cache(Mod, LServer) of
true ->
+ ejabberd_cluster:eval_everywhere(
+ ?MODULE, clean_cache, [LServer]);
+ false ->
ok
end;
- error ->
- ok
- end;
-send_motd(_) ->
- ok.
+ Err ->
+ Err
+ end.
get_stored_motd(LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
- case Mod:get_motd(LServer) of
+ case get_motd(Mod, LServer) of
{ok, Packet} ->
- {fxml:get_subtag_cdata(Packet, <<"subject">>),
- fxml:get_subtag_cdata(Packet, <<"body">>)};
- error ->
+ CodecOpts = ejabberd_config:codec_options(),
+ try xmpp:decode(Packet, ?NS_CLIENT, CodecOpts) of
+ #message{body = Body, subject = Subject} ->
+ {xmpp:get_text(Subject), xmpp:get_text(Body)}
+ catch _:{xmpp_codec, Why} ->
+ ?ERROR_MSG("Failed to decode motd packet ~p: ~ts",
+ [Packet, xmpp:format_error(Why)])
+ end;
+ _ ->
{<<>>, <<>>}
end.
%% This function is similar to others, but doesn't perform any ACL verification
send_announcement_to_all(Host, SubjectS, BodyS) ->
- SubjectEls = if SubjectS /= <<>> ->
- [#xmlel{name = <<"subject">>, children = [{xmlcdata, SubjectS}]}];
- true ->
- []
- end,
- BodyEls = if BodyS /= <<>> ->
- [#xmlel{name = <<"body">>, children = [{xmlcdata, BodyS}]}];
- true ->
- []
- end,
- Packet = #xmlel{
- name = <<"message">>,
- attrs = [{<<"type">>, <<"headline">>}],
- children = SubjectEls ++ BodyEls
- },
+ Packet = #message{type = headline,
+ body = xmpp:mk_text(BodyS),
+ subject = xmpp:mk_text(SubjectS)},
Sessions = ejabberd_sm:dirty_get_sessions_list(),
- Local = jid:make(<<>>, Host, <<>>),
+ Local = jid:make(Host),
lists:foreach(
fun({U, S, R}) ->
Dest = jid:make(U, S, R),
- ejabberd_router:route(Local, Dest, add_store_hint(Packet))
+ ejabberd_router:route(
+ xmpp:set_from_to(add_store_hint(Packet), Local, Dest))
end, Sessions).
-spec get_access(global | binary()) -> atom().
get_access(Host) ->
- gen_mod:get_module_opt(Host, ?MODULE, access,
- fun(A) -> A end,
- none).
-
--spec add_store_hint(xmlel()) -> xmlel().
+ mod_announce_opt:access(Host).
+-spec add_store_hint(stanza()) -> stanza().
add_store_hint(El) ->
- Hint = #xmlel{name = <<"store">>, attrs = [{<<"xmlns">>, ?NS_HINTS}]},
- fxml:append_subtags(El, [Hint]).
+ xmpp:set_subtag(El, #hint{type = store}).
+
+-spec route_forbidden_error(stanza()) -> ok.
+route_forbidden_error(Packet) ->
+ Lang = xmpp:get_lang(Packet),
+ Err = xmpp:err_forbidden(?T("Access denied by service policy"), Lang),
+ ejabberd_router:route_error(Packet, Err).
+
+-spec init_cache(module(), binary(), gen_mod:opts()) -> ok.
+init_cache(Mod, Host, Opts) ->
+ case use_cache(Mod, Host) of
+ true ->
+ CacheOpts = cache_opts(Opts),
+ ets_cache:new(?MOTD_CACHE, CacheOpts);
+ false ->
+ ets_cache:delete(?MOTD_CACHE)
+ end.
+
+-spec cache_opts(gen_mod:opts()) -> [proplists:property()].
+cache_opts(Opts) ->
+ MaxSize = mod_announce_opt:cache_size(Opts),
+ CacheMissed = mod_announce_opt:cache_missed(Opts),
+ LifeTime = mod_announce_opt:cache_life_time(Opts),
+ [{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
+
+-spec use_cache(module(), binary()) -> boolean().
+use_cache(Mod, Host) ->
+ case erlang:function_exported(Mod, use_cache, 1) of
+ true -> Mod:use_cache(Host);
+ false -> mod_announce_opt:use_cache(Host)
+ end.
+
+-spec cache_nodes(module(), binary()) -> [node()].
+cache_nodes(Mod, Host) ->
+ case erlang:function_exported(Mod, cache_nodes, 1) of
+ true -> Mod:cache_nodes(Host);
+ false -> ejabberd_cluster:get_nodes()
+ end.
+
+-spec clean_cache(binary()) -> non_neg_integer().
+clean_cache(LServer) ->
+ ets_cache:filter(
+ ?MOTD_CACHE,
+ fun({_, S}, _) -> S /= LServer end).
%%-------------------------------------------------------------------------
export(LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:export(LServer).
-import(LServer) ->
- Mod = gen_mod:db_mod(LServer, ?MODULE),
- Mod:import(LServer).
+import_info() ->
+ [{<<"motd">>, 3}].
+
+import_start(LServer, DBType) ->
+ Mod = gen_mod:db_mod(DBType, ?MODULE),
+ Mod:init(LServer, []).
-import(LServer, DBType, LA) ->
+import(LServer, {sql, _}, DBType, Tab, List) ->
Mod = gen_mod:db_mod(DBType, ?MODULE),
- Mod:import(LServer, LA).
+ Mod:import(LServer, Tab, List).
mod_opt_type(access) ->
- fun acl:access_rules_validator/1;
-mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
-mod_opt_type(_) -> [access, db_type].
+ econf:acl();
+mod_opt_type(db_type) ->
+ econf:db_type(?MODULE);
+mod_opt_type(use_cache) ->
+ econf:bool();
+mod_opt_type(cache_size) ->
+ econf:pos_int(infinity);
+mod_opt_type(cache_missed) ->
+ econf:bool();
+mod_opt_type(cache_life_time) ->
+ econf:timeout(second, infinity).
+
+mod_options(Host) ->
+ [{access, none},
+ {db_type, ejabberd_config:default_db(Host, ?MODULE)},
+ {use_cache, ejabberd_option:use_cache(Host)},
+ {cache_size, ejabberd_option:cache_size(Host)},
+ {cache_missed, ejabberd_option:cache_missed(Host)},
+ {cache_life_time, ejabberd_option:cache_life_time(Host)}].