Update some modules to work with ejabberd 19.08 (#277)

This commit is contained in:
Badlop 2019-08-19 20:42:03 +02:00
parent 4753268b5f
commit 857d350a71
21 changed files with 258 additions and 214 deletions

View File

@ -1,6 +1,7 @@
mod_cron - Execute scheduled commands mod_cron - Execute scheduled commands
Requires: ejabberd 19.08 or higher
http://www.ejabberd.im/mod_cron http://www.ejabberd.im/mod_cron
Author: Badlop Author: Badlop

View File

@ -11,19 +11,18 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([ -export([start/2, stop/1, depends/2, mod_options/1, mod_opt_type/1]).
cron_list/1, cron_del/1, -export([cron_list/1, cron_del/1,
run_task/3, run_task/3,
web_menu_host/3, web_page_host/3, web_menu_host/3, web_page_host/3,
start/2,
apply_interval/3, apply_interval/3,
apply_interval1/3, apply_interval1/3]).
stop/1]).
-include("ejabberd_commands.hrl"). -include("ejabberd_commands.hrl").
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl"). -include("ejabberd_web_admin.hrl").
-include("logger.hrl"). -include("logger.hrl").
-include("translate.hrl").
-include("xmpp.hrl"). -include("xmpp.hrl").
-record(task, {taskid, timerref, host, task}). -record(task, {taskid, timerref, host, task}).
@ -36,7 +35,7 @@ start(Host, Opts) ->
ejabberd_commands:register_commands(commands()), ejabberd_commands:register_commands(commands()),
ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50), ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50),
ejabberd_hooks:add(webadmin_page_host, Host, ?MODULE, web_page_host, 50), ejabberd_hooks:add(webadmin_page_host, Host, ?MODULE, web_page_host, 50),
Tasks = gen_mod:get_opt(tasks, Opts, []), Tasks = gen_mod:get_opt(tasks, Opts),
catch ets:new(cron_tasks, [ordered_set, named_table, public, {keypos, 2}]), catch ets:new(cron_tasks, [ordered_set, named_table, public, {keypos, 2}]),
[add_task(Host, Task) || Task <- Tasks], [add_task(Host, Task) || Task <- Tasks],
ok. ok.
@ -49,6 +48,14 @@ stop(Host) ->
[delete_task(Task) || Task <- get_tasks(Host)], [delete_task(Task) || Task <- get_tasks(Host)],
ok. ok.
depends(_Host, _Opts) ->
[].
mod_opt_type(tasks) ->
econf:list(econf:any()).
mod_options(_Host) ->
[{tasks, []}].
%% --------------------- %% ---------------------
%% Task management %% Task management
@ -231,7 +238,7 @@ cron_del(TaskId) ->
%% --------------------- %% ---------------------
web_menu_host(Acc, _Host, Lang) -> web_menu_host(Acc, _Host, Lang) ->
[{<<"cron">>, ?T(<<"Cron Tasks">>)} | Acc]. [{<<"cron">>, translate:translate(Lang, ?T("Cron Tasks"))} | Acc].
web_page_host(_, Host, web_page_host(_, Host,
#request{path = [<<"cron">>], #request{path = [<<"cron">>],
@ -245,9 +252,13 @@ web_page_host(Acc, _, _) -> Acc.
make_tasks_table(Tasks, Lang) -> make_tasks_table(Tasks, Lang) ->
TList = lists:map( TList = lists:map(
fun(T) -> fun(T) ->
{Time_num, Time_unit, Mod, Fun, Args} = T#task.task, [TimeNum, TimeUnit, Mod, Fun, Args, InTimerType] =
[proplists:get_value(Key, T#task.task)
|| Key <- [time, units, module, function, arguments, timer_type]],
?XE(<<"tr">>, ?XE(<<"tr">>,
[?XC(<<"td">>, list_to_binary(integer_to_list(Time_num) ++" " ++ atom_to_list(Time_unit))), [?XC(<<"td">>, list_to_binary(integer_to_list(TimeNum)++" "
++atom_to_list(TimeUnit)++" "
++atom_to_list(InTimerType))),
?XC(<<"td">>, list_to_binary(atom_to_list(Mod))), ?XC(<<"td">>, list_to_binary(atom_to_list(Mod))),
?XC(<<"td">>, list_to_binary(atom_to_list(Fun))), ?XC(<<"td">>, list_to_binary(atom_to_list(Fun))),
?XC(<<"td">>, list_to_binary(io_lib:format("~p", [Args])))]) ?XC(<<"td">>, list_to_binary(io_lib:format("~p", [Args])))])

View File

@ -10,13 +10,10 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/2, -export([start/2, stop/1, depends/2, mod_opt_type/1, mod_options/1]).
init/1, -export([init/1,
stop/1,
depends/2,
log_packet_send/1, log_packet_send/1,
log_packet_receive/1, log_packet_receive/1]).
mod_opt_type/1]).
-ifndef(LAGER). -ifndef(LAGER).
-define(LAGER, 1). -define(LAGER, 1).
@ -33,7 +30,7 @@
start(Host, Opts) -> start(Host, Opts) ->
?DEBUG(" ~p ~p~n", [Host, Opts]), ?DEBUG(" ~p ~p~n", [Host, Opts]),
case gen_mod:get_opt(host_config, Opts, []) of case gen_mod:get_opt(host_config, Opts) of
[] -> [] ->
start_vh(Host, Opts); start_vh(Host, Opts);
HostConfig -> HostConfig ->
@ -51,8 +48,8 @@ start_vhs(Host, [{_VHost, _Opts}| Tail]) ->
?DEBUG("start_vhs ~p ~p~n", [Host, [{_VHost, _Opts}| Tail]]), ?DEBUG("start_vhs ~p ~p~n", [Host, [{_VHost, _Opts}| Tail]]),
start_vhs(Host, Tail). start_vhs(Host, Tail).
start_vh(Host, Opts) -> start_vh(Host, Opts) ->
Path = gen_mod:get_opt(path, Opts, ?DEFAULT_PATH), Path = gen_mod:get_opt(path, Opts),
Format = gen_mod:get_opt(format, Opts, ?DEFAULT_FORMAT), Format = gen_mod:get_opt(format, Opts),
ejabberd_hooks:add(user_send_packet, Host, ?MODULE, log_packet_send, 55), ejabberd_hooks:add(user_send_packet, Host, ?MODULE, log_packet_send, 55),
ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, log_packet_receive, 55), ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, log_packet_receive, 55),
register(gen_mod:get_module_proc(Host, ?PROCNAME), register(gen_mod:get_module_proc(Host, ?PROCNAME),
@ -79,10 +76,6 @@ stop(Host) ->
gen_mod:get_module_proc(Host, ?PROCNAME) ! stop, gen_mod:get_module_proc(Host, ?PROCNAME) ! stop,
ok. ok.
-spec depends(binary(), gen_mod:opts()) -> [{module(), hard | soft}].
depends(_Host, _Opts) ->
[].
log_packet_send({Packet, C2SState}) -> log_packet_send({Packet, C2SState}) ->
From = xmpp:get_from(Packet), From = xmpp:get_from(Packet),
To = xmpp:get_to(Packet), To = xmpp:get_to(Packet),
@ -103,10 +96,10 @@ log_packet_receive({Packet, C2SState}) ->
log_packet(From, To, #message{type = Type} = Packet, Host) -> log_packet(From, To, #message{type = Type} = Packet, Host) ->
case Type of case Type of
<<"groupchat">> -> %% mod_muc_log already does it groupchat -> %% mod_muc_log already does it
?DEBUG("dropping groupchat: ~s", [fxml:element_to_binary(Packet)]), ?DEBUG("dropping groupchat: ~s", [fxml:element_to_binary(Packet)]),
ok; ok;
<<"error">> -> %% we don't log errors error -> %% we don't log errors
?DEBUG("dropping error: ~s", [fxml:element_to_binary(Packet)]), ?DEBUG("dropping error: ~s", [fxml:element_to_binary(Packet)]),
ok; ok;
_ -> _ ->
@ -286,8 +279,15 @@ css() ->
".messagetext {color: black; margin: 0.2em; clear: both; display: block;}~n"++ ".messagetext {color: black; margin: 0.2em; clear: both; display: block;}~n"++
"//-->~n</style>~n". "//-->~n</style>~n".
depends(_Host, _Opts) ->
[].
mod_opt_type(host_config) -> econf:list(econf:any());
mod_opt_type(path) -> fun iolist_to_binary/1; mod_opt_type(path) -> fun iolist_to_binary/1;
mod_opt_type(format) -> mod_opt_type(format) ->
fun (A) when is_atom(A) -> A end; fun (A) when is_atom(A) -> A end.
mod_opt_type(_) ->
[path, format]. mod_options(_Host) ->
[{host_config, []},
{path, ?DEFAULT_PATH},
{format, ?DEFAULT_FORMAT}].

View File

@ -1,9 +1,9 @@
mod_logsession - Log session connections to file mod_logsession - Log session connections to file
Requirements: ejabberd 19.08 or higher
Homepage: http://www.ejabberd.im/mod_logsession Homepage: http://www.ejabberd.im/mod_logsession
Author: Badlop Author: Badlop
Requirements: ejabberd 17.01 or newer
DESCRIPTION DESCRIPTION

View File

@ -29,14 +29,11 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([ -export([start/2, stop/1, depends/2, mod_options/1, mod_opt_type/1]).
start/2, -export([loop/3,
stop/1,
loop/3,
reopen_log/1, reopen_log/1,
failed_auth/3, failed_auth/3,
forbidden/1 forbidden/1]).
]).
-include("xmpp.hrl"). -include("xmpp.hrl").
-include("ejabberd_commands.hrl"). -include("ejabberd_commands.hrl").
@ -54,9 +51,7 @@ start(Host, Opts) ->
ejabberd_commands:register_commands(commands()), ejabberd_commands:register_commands(commands()),
Filename1 = gen_mod:get_opt( Filename1 = gen_mod:get_opt(
sessionlog, sessionlog,
Opts, Opts),
fun(S) -> S end,
"/tmp/ejabberd_logsession_@HOST@.log"),
Filename = replace_host(Host, Filename1), Filename = replace_host(Host, Filename1),
File = open_file(Filename), File = open_file(Filename),
register(get_process_name(Host), spawn(?MODULE, loop, [Filename, File, Host])), register(get_process_name(Host), spawn(?MODULE, loop, [Filename, File, Host])),
@ -70,6 +65,15 @@ stop(Host) ->
exit(whereis(Proc), stop), exit(whereis(Proc), stop),
{wait, Proc}. {wait, Proc}.
depends(_Host, _Opts) ->
[].
mod_opt_type(sessionlog) ->
econf:string().
mod_options(_Host) ->
[{sessionlog, "/tmp/ejabberd_logsession_@HOST@.log"}].
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% REQUEST HANDLERS %%% REQUEST HANDLERS
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
@ -83,8 +87,8 @@ forbidden(JID) ->
failed_auth(State, true, _) -> failed_auth(State, true, _) ->
State; State;
failed_auth(#{lserver := Host, ip := IPPT} = State, false, U) -> failed_auth(#{lserver := Host, ip := IPPT} = State, {false, Reason}, U) ->
get_process_name(Host) ! {log, {failed_auth, U, IPPT}}, get_process_name(Host) ! {log, {failed_auth, U, IPPT, Reason}},
State. State.
commands() -> commands() ->
@ -144,10 +148,10 @@ make_date(Date) ->
io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
[Y, Mo, D, H, Mi, S]). [Y, Mo, D, H, Mi, S]).
make_message(Host, {failed_auth, Username, {IPTuple, IPPort}}) -> make_message(Host, {failed_auth, Username, {IPTuple, IPPort}, Reason}) ->
IPString = inet_parse:ntoa(IPTuple), IPString = inet_parse:ntoa(IPTuple),
io_lib:format("Failed authentication for ~s@~s from ~s port ~p", io_lib:format("Failed authentication for ~s@~s from ~s port ~p: ~s",
[Username, Host, IPString, IPPort]); [Username, Host, IPString, IPPort, Reason]);
make_message(_Host, {forbidden, JID}) -> make_message(_Host, {forbidden, JID}) ->
io_lib:format("Forbidden session for ~s", io_lib:format("Forbidden session for ~s",
[jlib:jid_to_string(JID)]). [jlib:jid_to_string(JID)]).

View File

@ -3,7 +3,7 @@
Homepage: http://www.ejabberd.im/mod_logxml Homepage: http://www.ejabberd.im/mod_logxml
Author: Badlop Author: Badlop
Module for ejabberd git master Requires: ejabberd 19.08 or higher
DESCRIPTION DESCRIPTION
@ -38,15 +38,15 @@ show_ip:
Default value: false Default value: false
rotate_days: rotate_days:
Rotate logs every X days Rotate logs every X days
Put 'no' to disable this limit. Put 0 to disable this limit.
Default value: 1 Default value: 1
rotate_megs: rotate_megs:
Rotate when the logfile size is higher than this, in megabytes. Rotate when the logfile size is higher than this, in megabytes.
Put 'no' to disable this limit. Put 0 to disable this limit.
Default value: 10 Default value: 10
rotate_kpackets: rotate_kpackets:
Rotate every *1000 XMPP packets logged Rotate every *1000 XMPP packets logged
Put 'no' to disable this limit. Put 0 to disable this limit.
Default value: 10 Default value: 10
check_rotate_kpackets: check_rotate_kpackets:
Check rotation every *1000 packets Check rotation every *1000 packets
@ -72,7 +72,7 @@ modules:
show_ip: false show_ip: false
rotate_days: 1 rotate_days: 1
rotate_megs: 100 rotate_megs: 100
rotate_kpackets: no rotate_kpackets: 0
check_rotate_kpackets: 1 check_rotate_kpackets: 1

View File

@ -12,5 +12,5 @@ modules:
show_ip: false show_ip: false
rotate_days: 1 rotate_days: 1
rotate_megs: 100 rotate_megs: 100
rotate_kpackets: no rotate_kpackets: 0
check_rotate_kpackets: 1 check_rotate_kpackets: 1

View File

@ -26,13 +26,16 @@
start(Host, Opts) -> start(Host, Opts) ->
Logdir = gen_mod:get_opt(logdir, Opts), Logdir = gen_mod:get_opt(logdir, Opts),
Rd = gen_mod:get_opt(rotate_days, Opts), Rd = case gen_mod:get_opt(rotate_days, Opts) of
0 -> no;
Rd1 -> Rd1
end,
Rf = case gen_mod:get_opt(rotate_megs, Opts) of Rf = case gen_mod:get_opt(rotate_megs, Opts) of
no -> no; 0 -> no;
Rf1 -> Rf1*1024*1024 Rf1 -> Rf1*1024*1024
end, end,
Rp = case gen_mod:get_opt(rotate_kpackets, Opts) of Rp = case gen_mod:get_opt(rotate_kpackets, Opts) of
no -> no; 0 -> no;
Rp1 -> Rp1*1000 Rp1 -> Rp1*1000
end, end,
RotateO = {Rd, Rf, Rp}, RotateO = {Rd, Rf, Rp},
@ -111,7 +114,7 @@ filter(FilterO, E) ->
FilterO, FilterO,
{Orientation, From, To, Packet} = E, {Orientation, From, To, Packet} = E,
Stanza = element(1, Packet), Stanza = element(1, Packet),
Hosts_all = ejabberd_config:get_global_option(hosts, fun(A) -> A end), Hosts_all = ejabberd_config:get_option(hosts),
{Host_local, Host_remote} = case Orientation of {Host_local, Host_remote} = case Orientation of
send -> {From#jid.lserver, To#jid.lserver}; send -> {From#jid.lserver, To#jid.lserver};
recv -> {To#jid.lserver, From#jid.lserver} recv -> {To#jid.lserver, From#jid.lserver}
@ -267,29 +270,23 @@ calc_div(_A, _B) ->
0.5. %% This ensures that no rotation is performed 0.5. %% This ensures that no rotation is performed
mod_opt_type(stanza) -> mod_opt_type(stanza) ->
fun (L) when is_list(L) -> [] = L -- [iq, message, presence, other], L end; econf:list(econf:enum([iq, message, presence, other]));
mod_opt_type(direction) -> mod_opt_type(direction) ->
fun (L) when is_list(L) -> [] = L -- [internal, vhosts, external], L end; econf:list(econf:enum([internal, vhosts, external]));
mod_opt_type(orientation) -> mod_opt_type(orientation) ->
fun (L) when is_list(L) -> [] = L -- [send, recv], L end; econf:list(econf:enum([send, recv]));
mod_opt_type(logdir) -> mod_opt_type(logdir) ->
fun iolist_to_binary/1; econf:directory();
mod_opt_type(show_ip) -> mod_opt_type(show_ip) ->
fun (A) when is_boolean(A) -> A end; econf:bool();
mod_opt_type(rotate_days) -> mod_opt_type(rotate_days) ->
fun (I) when is_integer(I), I > 0 -> I; econf:non_neg_int();
(no) -> no
end;
mod_opt_type(rotate_megs) -> mod_opt_type(rotate_megs) ->
fun (I) when is_integer(I), I > 0 -> I; econf:non_neg_int();
(no) -> no
end;
mod_opt_type(rotate_kpackets) -> mod_opt_type(rotate_kpackets) ->
fun (I) when is_integer(I), I > 0 -> I; econf:non_neg_int();
(no) -> no
end;
mod_opt_type(check_rotate_kpackets) -> mod_opt_type(check_rotate_kpackets) ->
fun (I) when is_integer(I), I > 0 -> I end. econf:non_neg_int().
mod_options(_Host) -> mod_options(_Host) ->
[{stanza, [iq, message, presence, other]}, [{stanza, [iq, message, presence, other]},

View File

@ -2,6 +2,7 @@
mod_muc_log_http - Serve MUC logs on the web mod_muc_log_http - Serve MUC logs on the web
Requires: ejabberd 19.08 or higher
Homepage: http://ejabberd.im/mod_muc_log_http Homepage: http://ejabberd.im/mod_muc_log_http
Author: Badlop Author: Badlop

View File

@ -10,11 +10,9 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([ -export([start/2, stop/1, depends/2, mod_options/1]).
start/2,
stop/1, -export([process/2]).
process/2
]).
-include("xmpp.hrl"). -include("xmpp.hrl").
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
@ -38,7 +36,7 @@ process(LocalPath, Request) ->
serve(LocalPath, Request). serve(LocalPath, Request).
serve(LocalPathBin, #request{host = Host} = Request) -> serve(LocalPathBin, #request{host = Host} = Request) ->
DocRoot = binary_to_list(gen_mod:get_module_opt(Host, mod_muc_log, outdir, <<"www/muc">>)), DocRoot = binary_to_list(gen_mod:get_module_opt(Host, mod_muc_log, outdir)),
LocalPath = [binary_to_list(LPB) || LPB <- LocalPathBin], LocalPath = [binary_to_list(LPB) || LPB <- LocalPathBin],
FileName = filename:join(filename:split(DocRoot) ++ LocalPath), FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
case file:read_file(FileName) of case file:read_file(FileName) of
@ -230,3 +228,9 @@ start(_Host, _Opts) ->
stop(_Host) -> stop(_Host) ->
ok. ok.
depends(_Host, _Opts) ->
[{mod_muc_log, hard}].
mod_options(_Host) ->
[].

View File

@ -60,9 +60,9 @@ filterMessageText2(Lang, MessageText) ->
string:join(filterWords(MessageTerms), " "). string:join(filterWords(MessageTerms), " ").
start(_Host, Opts) -> start(_Host, Opts) ->
Blacklists = gen_mod:get_opt(blacklists, Opts, fun(A) -> A end, []), Blacklists = gen_mod:get_opt(blacklists, Opts),
lists:map(fun bloom_gen_server:start/1, Blacklists), lists:map(fun bloom_gen_server:start/1, Blacklists),
CharMaps = gen_mod:get_opt(charmaps, Opts, fun(A) -> A end, []), CharMaps = gen_mod:get_opt(charmaps, Opts),
lists:map(fun normalize_leet_gen_server:start/1, CharMaps), lists:map(fun normalize_leet_gen_server:start/1, CharMaps),
ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0), ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0),
ok. ok.

View File

@ -1,6 +1,7 @@
mod_rest - HTTP interface to POST stanzas into ejabberd mod_rest - HTTP interface to POST stanzas into ejabberd
Requires: ejabberd 19.08 or higher
Author: Nolan Eakins <sneakin@semanticgap.com> Author: Nolan Eakins <sneakin@semanticgap.com>
Copyright (C) 2008 Nolan Eakins Copyright (C) 2008 Nolan Eakins
@ -40,8 +41,6 @@ With that configuration, you can send HTTP POST requests to the URL:
Configurable options: Configurable options:
allowed_ips: IP addresses that can use the rest service. allowed_ips: IP addresses that can use the rest service.
Allowed values: 'all' or a list of Erlang strings.
Default value: all
Notice that the IP address is checked after the connection is established. Notice that the IP address is checked after the connection is established.
If you want to restrict the IP address that listens connections, and If you want to restrict the IP address that listens connections, and
only allow a certain IP to be able to connect to the port, then the only allow a certain IP to be able to connect to the port, then the
@ -49,18 +48,13 @@ Configurable options:
listening IP address in the ejabberd listeners (see the ejabberd Guide). listening IP address in the ejabberd listeners (see the ejabberd Guide).
allowed_destinations: Allowed destination Jabber ID addresses in the stanza. allowed_destinations: Allowed destination Jabber ID addresses in the stanza.
Allowed values: 'all' or a list of strings.
Default value: all
allowed_stanza_types: Allowed stanza types of the posted stanza. allowed_stanza_types: Allowed stanza types of the posted stanza.
Allowed values: 'all' or a list of strings.
Default value: all
access_commands: Access restrictions to execute ejabberd commands. access_commands: Access restrictions to execute ejabberd commands.
This option is similar to the option ejabberdctl_access_commands that This option is similar to the option ejabberdctl_access_commands that
is documented in the ejabberd Guide. is documented in the ejabberd Guide.
There is more information about AccessCommands in the ejabberd Guide. There is more information about AccessCommands in the ejabberd Guide.
Default value: []
Complex example configuration: Complex example configuration:
@ -88,7 +82,7 @@ modules:
- "presence" - "presence"
- "iq" - "iq"
access_commands: access_commands:
restaccess: - restaccess:
- registered_users - registered_users
- connected_users - connected_users

View File

@ -70,19 +70,19 @@ maybe_post_request(<<$<,_/binary>> = Data, Host, ClientIp) ->
Stanza = {xmlel, _, _, _} = fxml_stream:parse_element(Data), Stanza = {xmlel, _, _, _} = fxml_stream:parse_element(Data),
Pkt = xmpp:decode(Stanza), Pkt = xmpp:decode(Stanza),
allowed = check_stanza(Pkt, Host), allowed = check_stanza(Pkt, Host),
?INFO_MSG("Got valid request with IP ~p:~n~p", ?DEBUG("Got valid request with IP ~p:~n~p",
[ClientIp, [ClientIp,
Pkt]), Pkt]),
post_request(Pkt) post_request(Pkt)
catch catch
error:{badmatch, _} = Error -> error:{badmatch, _} = Error ->
?DEBUG("Error when processing REST request: ~nData: ~p~nError: ~p", [Data, Error]), ?INFO_MSG("Error when processing REST request: ~nData: ~p~nError: ~p", [Data, Error]),
{406, [], "Error: REST request is rejected by service."}; {406, [], "Error: REST request is rejected by service."};
error:{Reason, _} = Error -> error:{Reason, _} = Error ->
?DEBUG("Error when processing REST request: ~nData: ~p~nError: ~p", [Data, Error]), ?INFO_MSG("Error when processing REST request: ~nData: ~p~nError: ~p", [Data, Error]),
{500, [], "Error: " ++ atom_to_list(Reason)}; {500, [], "Error: " ++ atom_to_list(Reason)};
Error -> Error ->
?DEBUG("Error when processing REST request: ~nData: ~p~nError: ~p", [Data, Error]), ?INFO_MSG("Error when processing REST request: ~nData: ~p~nError: ~p", [Data, Error]),
{500, [], "Error"} {500, [], "Error"}
end; end;
maybe_post_request(Data, Host, _ClientIp) -> maybe_post_request(Data, Host, _ClientIp) ->
@ -107,39 +107,38 @@ ensure_auth_is_provided(Args) ->
["--auth", "", "", "" | Args]. ["--auth", "", "", "" | Args].
%% This function throws an error if the module is not started in that VHost. %% This function throws an error if the module is not started in that VHost.
try_get_option(Host, OptionName, DefaultValue) -> try_get_option(Host, OptionName) ->
case gen_mod:is_loaded(Host, ?MODULE) of case gen_mod:is_loaded(Host, ?MODULE) of
true -> ok; true -> ok;
_ -> throw({module_must_be_started_in_vhost, ?MODULE, Host}) _ -> throw({module_must_be_started_in_vhost, ?MODULE, Host})
end, end,
gen_mod:get_module_opt(Host, ?MODULE, OptionName, fun(I) -> I end, DefaultValue). gen_mod:get_module_opt(Host, ?MODULE, OptionName).
get_option_access(Host) -> get_option_access(Host) ->
try_get_option(Host, access_commands, []). try_get_option(Host, access_commands).
%% This function crashes if the stanza does not satisfy configured restrictions %% This function crashes if the stanza does not satisfy configured restrictions
check_stanza(Pkt, Host) -> check_stanza(Pkt, Host) ->
To = xmpp:get_to(Pkt), To = xmpp:get_to(Pkt),
check_member_option(Host, jid:encode(To), allowed_destinations), check_member_option(Host, To, allowed_destinations),
%%+++ {xmlel, StanzaType, _Attrs, _Kids} = Stanza, Name = xmpp:get_name(Pkt),
%%+++ check_member_option(Host, StanzaType, allowed_stanza_types), check_member_option(Host, Name, allowed_stanza_types),
allowed. allowed.
check_member_option(Host, ClientIp, allowed_ips) -> check_member_option(Host, ClientIp, allowed_ips) ->
true = case try_get_option(Host, allowed_ips, all) of true = case try_get_option(Host, allowed_ips) of
all -> true; [] -> true;
AllowedValues -> ip_matches(ClientIp, AllowedValues) AllowedValues -> ip_matches(ClientIp, AllowedValues)
end; end;
check_member_option(Host, Element, Option) -> check_member_option(Host, Element, Option) ->
true = case try_get_option(Host, Option, all) of true = case try_get_option(Host, Option) of
all -> true; [] -> true;
AllowedValues -> lists:member(Element, AllowedValues) AllowedValues -> lists:member(Element, AllowedValues)
end. end.
ip_matches(ClientIp, AllowedValues) -> ip_matches(ClientIp, AllowedValues) ->
lists:any(fun(El) -> lists:any(fun({Net, Mask}) ->
{ok, Net, Mask} = acl:parse_ip_netmask(El), acl:match_acl(useless_host, {ip,{Net,Mask}}, #{ip => {ClientIp,useless_port}})
acl:acl_rule_matches({ip,{Net,Mask}}, #{ip => {ClientIp,port}}, host)
end, end,
AllowedValues). AllowedValues).
@ -178,16 +177,16 @@ splitend([92, 34, 32 | Line], Res) -> {Line, Res};
splitend([Char | Line], Res) -> splitend(Line, [Char | Res]). splitend([Char | Line], Res) -> splitend(Line, [Char | Res]).
mod_opt_type(allowed_ips) -> mod_opt_type(allowed_ips) ->
fun (all) -> all; (A) when is_list(A) -> A end; econf:list(econf:ip_mask());
mod_opt_type(allowed_destinations) -> mod_opt_type(allowed_destinations) ->
fun (all) -> all; (A) when is_list(A) -> A end; econf:list(econf:jid());
mod_opt_type(allowed_stanza_types) -> mod_opt_type(allowed_stanza_types) ->
fun (all) -> all; (A) when is_list(A) -> A end; econf:list(econf:enum([<<"iq">>, <<"message">>, <<"presence">>]));
mod_opt_type(access_commands) -> mod_opt_type(access_commands) ->
fun (A) when is_list(A) -> A end. fun (A) when is_list(A) -> A end.
mod_options(_Host) -> mod_options(_Host) ->
[{allowed_ips, all}, [{allowed_ips, []},
{allowed_destinations, all}, {allowed_destinations, []},
{allowed_stanza_types, all}, {allowed_stanza_types, []},
{access_commands, []}]. {access_commands, []}].

View File

@ -51,7 +51,7 @@
start(Host, Opts) -> start(Host, Opts) ->
case whereis(?PROCNAME) of case whereis(?PROCNAME) of
undefined -> undefined ->
Filename = gen_mod:get_opt(filename, Opts, ?DEFAULT_FILENAME), Filename = gen_mod:get_opt(filename, Opts),
case filelib:ensure_dir(Filename) of case filelib:ensure_dir(Filename) of
ok -> ok ->
register(?PROCNAME, register(?PROCNAME,

View File

@ -1,6 +1,7 @@
mod_shcommands - Execute shell commands mod_shcommands - Execute shell commands
Requires: ejabberd 19.08 or higher
Author: Badlop Author: Badlop
http://ejabberd.im/mod_shcommands http://ejabberd.im/mod_shcommands

View File

@ -11,12 +11,13 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([web_menu_node/3, web_page_node/5, -export([start/2, stop/1, depends/2, mod_options/1]).
start/2, stop/1]). -export([web_menu_node/3, web_page_node/5]).
-include("xmpp.hrl"). -include("xmpp.hrl").
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl"). -include("ejabberd_web_admin.hrl").
-include("translate.hrl").
%%------------------- %%-------------------
%% gen_mod functions %% gen_mod functions
@ -32,19 +33,25 @@ stop(_Host) ->
ejabberd_hooks:delete(webadmin_page_node, ?MODULE, web_page_node, 50), ejabberd_hooks:delete(webadmin_page_node, ?MODULE, web_page_node, 50),
ok. ok.
depends(_Host, _Opts) ->
[].
mod_options(_Host) ->
[].
%%------------------- %%-------------------
%% Web Admin Menu %% Web Admin Menu
%%------------------- %%-------------------
web_menu_node(Acc, _Node, Lang) -> web_menu_node(Acc, _Node, Lang) ->
Acc ++ [{<<"shcommands">>, ?T(<<"Shell Commands">>)}]. Acc ++ [{<<"shcommands">>, translate:translate(Lang, ?T("Shell Commands"))}].
%%------------------- %%-------------------
%% Web Admin Page %% Web Admin Page
%%------------------- %%-------------------
web_page_node(_, Node, [<<"shcommands">>], Query, Lang) -> web_page_node(_, Node, [<<"shcommands">>], Query, Lang) ->
Res = [?XC(<<"h1">>, <<"Shell Commands">>) | get_content(Node, Query, Lang)], Res = [?XC(<<"h1">>, translate:translate(Lang, ?T("Shell Commands"))) | get_content(Node, Query, Lang)],
{stop, Res}; {stop, Res};
web_page_node(Acc, _, _, _, _) -> Acc. web_page_node(Acc, _, _, _, _) -> Acc.
@ -53,14 +60,15 @@ web_page_node(Acc, _, _, _, _) -> Acc.
%%------------------- %%-------------------
get_content(Node, Query, Lang) -> get_content(Node, Query, Lang) ->
Instruct = ?T("Type a command in a textbox and click Execute."), Instruct = translate:translate(Lang, ?T("Type a command in a textbox and click Execute.")),
{{CommandCtl, CommandErl, CommandShell}, Res} = case catch parse_and_execute(Query, Node) of {{CommandCtl, CommandErl, CommandShell}, Res} = case catch parse_and_execute(Query, Node) of
{'EXIT', _} -> {{"", "", ""}, Instruct}; {'EXIT', _} -> {{"", "", ""}, Instruct};
Result_tuple -> Result_tuple Result_tuple -> Result_tuple
end, end,
TitleHTML = [ TitleHTML = [
?XC(<<"p">>, ?T(<<"Type a command in a textbox and click Execute. Use only commands which immediately return a result.">>)), ?XC(<<"p">>, translate:translate(Lang, ?T("Type a command in a textbox and click Execute."))),
?XC(<<"p">>, ?T(<<"WARNING: Use this only if you know what you are doing.">>)) ?XC(<<"p">>, translate:translate(Lang, ?T("Use only commands which immediately return a result."))),
?XC(<<"p">>, translate:translate(Lang, ?T("WARNING: Use this only if you know what you are doing.")))
], ],
CommandHTML = CommandHTML =
[?XAE(<<"form">>, [{<<"method">>, <<"post">>}], [?XAE(<<"form">>, [{<<"method">>, <<"post">>}],
@ -70,21 +78,21 @@ get_content(Node, Query, Lang) ->
[?X(<<"td">>), [?X(<<"td">>),
?XCT(<<"td">>, <<"ejabberd_ctl">>), ?XCT(<<"td">>, <<"ejabberd_ctl">>),
?XE(<<"td">>, [?INPUTS(<<"text">>, <<"commandctl">>, list_to_binary(CommandCtl), <<"70">>), ?XE(<<"td">>, [?INPUTS(<<"text">>, <<"commandctl">>, list_to_binary(CommandCtl), <<"70">>),
?INPUTT(<<"submit">>, <<"executectl">>, <<"Execute">>)]) ?INPUTT(<<"submit">>, <<"executectl">>, translate:translate(Lang, ?T("Execute")))])
] ]
), ),
?XE(<<"tr">>, ?XE(<<"tr">>,
[?X(<<"td">>), [?X(<<"td">>),
?XCT(<<"td">>, <<"erlang shell">>), ?XCT(<<"td">>, <<"erlang shell">>),
?XE(<<"td">>, [?INPUTS(<<"text">>, <<"commanderl">>, list_to_binary(CommandErl), <<"70">>), ?XE(<<"td">>, [?INPUTS(<<"text">>, <<"commanderl">>, list_to_binary(CommandErl), <<"70">>),
?INPUTT(<<"submit">>, <<"executeerl">>, <<"Execute">>)]) ?INPUTT(<<"submit">>, <<"executeerl">>, translate:translate(Lang, ?T("Execute")))])
] ]
), ),
?XE(<<"tr">>, ?XE(<<"tr">>,
[?X(<<"td">>), [?X(<<"td">>),
?XCT(<<"td">>, <<"system shell">>), ?XCT(<<"td">>, <<"system shell">>),
?XE(<<"td">>, [?INPUTS(<<"text">>, <<"commandshe">>, list_to_binary(CommandShell), <<"70">>), ?XE(<<"td">>, [?INPUTS(<<"text">>, <<"commandshe">>, list_to_binary(CommandShell), <<"70">>),
?INPUTT(<<"submit">>, <<"executeshe">>, <<"Execute">>)]) ?INPUTT(<<"submit">>, <<"executeshe">>, translate:translate(Lang, ?T("Execute")))])
] ]
) )
] ]
@ -93,7 +101,7 @@ get_content(Node, Query, Lang) ->
ResHTML = ResHTML =
[?XAC(<<"textarea">>, [{<<"wrap">>, <<"off">>}, {<<"style">>, <<"font-family:monospace;">>}, [?XAC(<<"textarea">>, [{<<"wrap">>, <<"off">>}, {<<"style">>, <<"font-family:monospace;">>},
{<<"name">>, <<"result">>}, {<<"rows">>, <<"30">>}, {<<"cols">>, <<"80">>}], {<<"name">>, <<"result">>}, {<<"rows">>, <<"30">>}, {<<"cols">>, <<"80">>}],
list_to_binary(Res)) Res)
], ],
TitleHTML ++ CommandHTML ++ ResHTML. TitleHTML ++ CommandHTML ++ ResHTML.

View File

@ -1,6 +1,7 @@
mod_statsdx - Calculates and gathers statistics actively mod_statsdx - Calculates and gathers statistics actively
Requires: ejabberd 19.08 or higher
Homepage: http://www.ejabberd.im/mod_statsdx Homepage: http://www.ejabberd.im/mod_statsdx
Author: Badlop Author: Badlop

View File

@ -11,7 +11,9 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/2, loop/5, stop/1]).
-export([start/2, stop/1, depends/2, mod_opt_type/1, mod_options/1]).
-export([loop/5]).
-include("xmpp.hrl"). -include("xmpp.hrl").
-include("mod_roster.hrl"). -include("mod_roster.hrl").
@ -26,19 +28,17 @@
start(_Host, Opts) -> start(_Host, Opts) ->
case whereis(?PROCNAME) of case whereis(?PROCNAME) of
undefined -> undefined ->
Interval = gen_mod:get_opt(interval, Opts, fun(O) -> O end, 5), Interval = gen_mod:get_opt(interval, Opts),
I = Interval*60*1000, I = Interval*60*1000,
%I = 9000, %+++ %I = 9000, %+++
Type = gen_mod:get_opt(type, Opts, fun(O) -> O end, html), Type = gen_mod:get_opt(type, Opts),
Split = gen_mod:get_opt(split, Opts, fun(O) -> O end, false), Split = gen_mod:get_opt(split, Opts),
BaseFilename = binary_to_list(gen_mod:get_opt(basefilename, Opts, fun(O) -> O end, "/tmp/ejasta")), BaseFilename = gen_mod:get_opt(basefilename, Opts),
Hosts_all = ejabberd_config:get_global_option(hosts, fun(O) -> O end), Hosts = gen_mod:get_opt(hosts, Opts),
Hosts1 = gen_mod:get_opt(hosts, Opts, fun(O) -> O end, Hosts_all),
Hosts = [binary_to_list(H) || H <- Hosts1],
register(?PROCNAME, spawn(?MODULE, loop, [I, Hosts, BaseFilename, Type, Split])); register(?PROCNAME, spawn(?MODULE, loop, [I, Hosts, BaseFilename, Type, Split]));
_ -> _ ->
@ -61,6 +61,26 @@ stop(_Host) ->
?PROCNAME ! stop ?PROCNAME ! stop
end. end.
depends(_Host, _Opts) ->
[{mod_statsdx, hard}].
mod_opt_type(interval) ->
econf:pos_int();
mod_opt_type(type) ->
econf:enum([html, txt, dat]);
mod_opt_type(split) ->
econf:bool();
mod_opt_type(basefilename) ->
econf:string();
mod_opt_type(hosts) ->
econf:list(econf:domain()).
mod_options(_Host) ->
[{interval, 5},
{type, html},
{split, false},
{basefilename, "/tmp/ejasta"},
{hosts, ejabberd_config:get_option(hosts)}].
%% ------------------- %% -------------------
%% write_stat* %% write_stat*
@ -96,13 +116,18 @@ write_statsfiles(true, I, Hs, O, T) ->
Hs). Hs).
write_statsfile(I, Class, Name, O, T) -> write_statsfile(I, Class, Name, O, T) ->
Fn = filename:flatten([O, "-", Class, "-", Name, ".", T]), Fn = filename:flatten([O, "-", Class, "-", to_string(Name), ".", T]),
{ok, F} = file:open(Fn, [write]), {ok, F} = file:open(Fn, [write]),
fwini(F, T), fwini(F, T),
write_stats(I, Class, Name, F, T), write_stats(I, Class, Name, F, T),
fwend(F, T), fwend(F, T),
file:close(F). file:close(F).
to_string(B) when is_binary(B) ->
binary_to_list(B);
to_string(S) ->
S.
write_stats(I, server, _Name, F, T) -> write_stats(I, server, _Name, F, T) ->
fwh(F, "Server statistics", 1, T), fwh(F, "Server statistics", 1, T),
fwbl1(F, T), fwbl1(F, T),

View File

@ -13,7 +13,8 @@
-behaviour(gen_mod). -behaviour(gen_mod).
-export([start/2, loop/1, stop/1, mod_opt_type/1, get_statistic/2, -export([start/2, stop/1, depends/2, mod_opt_type/1, mod_options/1]).
-export([loop/1, get_statistic/2,
received_response/3, received_response/3,
%% Commands %% Commands
getstatsdx/1, getstatsdx/2, getstatsdx/1, getstatsdx/2,
@ -34,22 +35,21 @@
-include("mod_roster.hrl"). -include("mod_roster.hrl").
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl"). -include("ejabberd_web_admin.hrl").
-include("translate.hrl").
-define(XCTB(Name, Text), ?XCT(list_to_binary(Name), list_to_binary(Text))). -define(XCTB(Name, Text), ?XCT(list_to_binary(Name), list_to_binary(Text))).
-define(PROCNAME, ejabberd_mod_statsdx). -define(PROCNAME, ejabberd_mod_statsdx).
%% Copied from ejabberd_s2s.erl Used in function get_s2sconnections/1 %% Copied from ejabberd_s2s.erl Used in function get_s2sconnections/1
-record(s2s, {fromto, pid, key}). -record(s2s, {fromto :: {binary(), binary()},
pid :: pid()}).
%%%================================== %%%==================================
%%%% Module control %%%% Module control
start(Host, Opts) -> start(Host, Opts) ->
Hooks = gen_mod:get_opt(hooks, Opts, Hooks = gen_mod:get_opt(hooks, Opts),
fun(O) when is_boolean(O) -> O;
(traffic) -> traffic
end, false),
%% Default value for the counters %% Default value for the counters
CD = case Hooks of CD = case Hooks of
true -> 0; true -> 0;
@ -79,8 +79,17 @@ stop(Host) ->
_ -> ?PROCNAME ! {stop, Host} _ -> ?PROCNAME ! {stop, Host}
end. end.
mod_opt_type(hooks) -> fun (B) when is_boolean(B) or (B==traffic) -> B end; depends(_Host, _Opts) ->
mod_opt_type(_) -> [hooks]. [].
mod_opt_type(hooks) ->
econf:enum([false, true, traffic]);
mod_opt_type(sessionlog) ->
econf:string().
mod_options(_Host) ->
[{hooks, false},
{sessionlog, "/tmp/ejabberd_logsession_@HOST@.log"}].
%%%================================== %%%==================================
%%%% Stats Server %%%% Stats Server
@ -764,7 +773,7 @@ user_logout(User, Host, Resource, _Status) ->
ets:update_counter(TableServer, {user_logout, server}, 1), ets:update_counter(TableServer, {user_logout, server}, 1),
ets:update_counter(TableHost, {user_logout, Host}, 1), ets:update_counter(TableHost, {user_logout, Host}, 1),
JID = jlib:make_jid(User, Host, Resource), JID = jid:make(User, Host, Resource),
case ets:lookup(TableHost, {session, JID}) of case ets:lookup(TableHost, {session, JID}) of
[{_, Client_id, OS_id, Lang, ConnType, _Client, _Version, _OS}] -> [{_, Client_id, OS_id, Lang, ConnType, _Client, _Version, _OS}] ->
ets:delete(TableHost, {session, JID}), ets:delete(TableHost, {session, JID}),
@ -791,7 +800,7 @@ request_iqversion(User, Host, Resource) ->
IQ = #iq{type = get, IQ = #iq{type = get,
from = From, from = From,
to = To, to = To,
id = randoms:get_string(), id = p1_rand:get_string(),
sub_els = [Query]}, sub_els = [Query]},
HandleResponse = fun(#iq{type = result} = IQr) -> HandleResponse = fun(#iq{type = result} = IQr) ->
spawn(?MODULE, received_response, spawn(?MODULE, received_response,
@ -848,7 +857,7 @@ received_response(From, #iq{type = Type, lang = Lang1, sub_els = Elc}) ->
update_counter_create(TableHost, {client_conntype, Host, Client_id, ConnType}, 1), update_counter_create(TableHost, {client_conntype, Host, Client_id, ConnType}, 1),
update_counter_create(TableServer, {client_conntype, server, Client_id, ConnType}, 1), update_counter_create(TableServer, {client_conntype, server, Client_id, ConnType}, 1),
JID = jlib:make_jid(User, Host, Resource), JID = jid:make(User, Host, Resource),
ets:insert(TableHost, {{session, JID}, Client_id, OS_id, Lang, ConnType, Client, Version, OS}). ets:insert(TableHost, {{session, JID}, Client_id, OS_id, Lang, ConnType, Client, Version, OS}).
get_connection_type(User, Host, Resource) -> get_connection_type(User, Host, Resource) ->
@ -1004,19 +1013,19 @@ localtime_to_string({{Y, Mo, D},{H, Mi, S}}) ->
%%%% Web Admin Menu %%%% Web Admin Menu
web_menu_main(Acc, Lang) -> web_menu_main(Acc, Lang) ->
Acc ++ [{<<"statsdx">>, <<(?T(<<"Statistics">>))/binary, " Dx">>}]. Acc ++ [{<<"statsdx">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>}].
web_menu_node(Acc, _Node, Lang) -> web_menu_node(Acc, _Node, Lang) ->
Acc ++ [{<<"statsdx">>, <<(?T(<<"Statistics">>))/binary, " Dx">>}]. Acc ++ [{<<"statsdx">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>}].
web_menu_host(Acc, _Host, Lang) -> web_menu_host(Acc, _Host, Lang) ->
Acc ++ [{<<"statsdx">>, <<(?T(<<"Statistics">>))/binary, " Dx">>}]. Acc ++ [{<<"statsdx">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>}].
%%%================================== %%%==================================
%%%% Web Admin Page %%%% Web Admin Page
web_page_main(_, #request{path=[<<"statsdx">>], lang = Lang} = _Request) -> web_page_main(_, #request{path=[<<"statsdx">>], lang = Lang} = _Request) ->
Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), Res = [?XC(<<"h1">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>),
?XC(<<"h3">>, <<"Accounts">>), ?XC(<<"h3">>, <<"Accounts">>),
?XAE(<<"table">>, [], ?XAE(<<"table">>, [],
[?XE(<<"tbody">>, [ [?XE(<<"tbody">>, [
@ -1124,7 +1133,7 @@ web_page_main(_, #request{path=[<<"statsdx">>], lang = Lang} = _Request) ->
], ],
{stop, Res}; {stop, Res};
web_page_main(_, #request{path=[<<"statsdx">>, <<"top">>, Topic, Topnumber], q = _Q, lang = Lang} = _Request) -> web_page_main(_, #request{path=[<<"statsdx">>, <<"top">>, Topic, Topnumber], q = _Q, lang = Lang} = _Request) ->
Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), Res = [?XC(<<"h1">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>),
case Topic of case Topic of
<<"offlinemsg">> -> ?XCT(<<"h2">>, <<"Top offline message queues">>); <<"offlinemsg">> -> ?XCT(<<"h2">>, <<"Top offline message queues">>);
<<"vcard">> -> ?XCT(<<"h2">>, <<"Top vCard sizes">>); <<"vcard">> -> ?XCT(<<"h2">>, <<"Top vCard sizes">>);
@ -1144,7 +1153,7 @@ web_page_main(_, #request{path=[<<"statsdx">> | FilterURL], q = Q, lang = Lang}
Filter = parse_url_filter(FilterURL), Filter = parse_url_filter(FilterURL),
Sort_query = get_sort_query(Q), Sort_query = get_sort_query(Q),
FilterS = io_lib:format("~p", [Filter]), FilterS = io_lib:format("~p", [Filter]),
Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), Res = [?XC(<<"h1">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>),
?XC(<<"h2">>, list_to_binary("Sessions with: " ++ FilterS)), ?XC(<<"h2">>, list_to_binary("Sessions with: " ++ FilterS)),
?XE(<<"table">>, ?XE(<<"table">>,
[ [
@ -1156,7 +1165,7 @@ web_page_main(_, #request{path=[<<"statsdx">> | FilterURL], q = Q, lang = Lang}
web_page_main(Acc, _) -> Acc. web_page_main(Acc, _) -> Acc.
do_top_table(_Node, Lang, Topic, TopnumberBin, Host) -> do_top_table(_Node, Lang, Topic, TopnumberBin, Host) ->
List = get_top_users(Host, jlib:binary_to_integer(TopnumberBin), Topic), List = get_top_users(Host, binary_to_integer(TopnumberBin), Topic),
%% get_top_users(Topnumber, "roster") %% get_top_users(Topnumber, "roster")
{List2, _} = lists:mapfoldl( {List2, _} = lists:mapfoldl(
fun({Value, UserB, ServerB}, Counter) -> fun({Value, UserB, ServerB}, Counter) ->
@ -1238,7 +1247,7 @@ web_page_node(_, Node, [<<"statsdx">>], _Query, Lang) ->
rpc:call(Node, mnesia, system_info, [transaction_log_writes]), rpc:call(Node, mnesia, system_info, [transaction_log_writes]),
Res = Res =
[?XC(<<"h1">>, list_to_binary(io_lib:format(?T("~p statistics"), [Node]))), [?XC(<<"h1">>, list_to_binary(io_lib:format(translate:translate(Lang, ?T("~p statistics")), [Node]))),
?XC(<<"h3">>, <<"Connections">>), ?XC(<<"h3">>, <<"Connections">>),
?XAE(<<"table">>, [], ?XAE(<<"table">>, [],
[?XE(<<"tbody">>, [ [?XE(<<"tbody">>, [
@ -1335,7 +1344,7 @@ web_page_node(Acc, _, _, _, _) -> Acc.
web_page_host(_, Host, web_page_host(_, Host,
#request{path = [<<"statsdx">>], #request{path = [<<"statsdx">>],
lang = Lang} = _Request) -> lang = Lang} = _Request) ->
Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), Res = [?XC(<<"h1">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>),
?XC(<<"h2">>, Host), ?XC(<<"h2">>, Host),
?XC(<<"h3">>, <<"Accounts">>), ?XC(<<"h3">>, <<"Accounts">>),
?XAE(<<"table">>, [], ?XAE(<<"table">>, [],
@ -1466,7 +1475,7 @@ web_page_host(_, Host,
], ],
{stop, Res}; {stop, Res};
web_page_host(_, Host, #request{path=[<<"statsdx">>, <<"top">>, Topic, Topnumber], q = _Q, lang = Lang} = _Request) -> web_page_host(_, Host, #request{path=[<<"statsdx">>, <<"top">>, Topic, Topnumber], q = _Q, lang = Lang} = _Request) ->
Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), Res = [?XC(<<"h1">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>),
case Topic of case Topic of
<<"offlinemsg">> -> ?XCT(<<"h2">>, <<"Top offline message queues">>); <<"offlinemsg">> -> ?XCT(<<"h2">>, <<"Top offline message queues">>);
<<"vcard">> -> ?XCT(<<"h2">>, <<"Top vCard sizes">>); <<"vcard">> -> ?XCT(<<"h2">>, <<"Top vCard sizes">>);
@ -1486,7 +1495,7 @@ web_page_host(_, Host, #request{path=[<<"statsdx">> | FilterURL], q = Q,
lang = Lang} = _Request) -> lang = Lang} = _Request) ->
Filter = parse_url_filter(FilterURL), Filter = parse_url_filter(FilterURL),
Sort_query = get_sort_query(Q), Sort_query = get_sort_query(Q),
Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), Res = [?XC(<<"h1">>, <<(translate:translate(Lang, ?T("Statistics")))/binary, " Dx">>),
?XC(<<"h2">>, list_to_binary("Sessions with: "++io_lib:format("~p", [Filter]))), ?XC(<<"h2">>, list_to_binary("Sessions with: "++io_lib:format("~p", [Filter]))),
?XAE(<<"table">>, [], ?XAE(<<"table">>, [],
[?XE(<<"tbody">>, [?XE(<<"tbody">>,
@ -1550,7 +1559,7 @@ do_sessions_table(_Node, _Lang, Filter, {Sort_direction, Sort_column}, Host) ->
Server = binary_to_list(JID#jid.lserver), Server = binary_to_list(JID#jid.lserver),
UserURL = "/admin/server/" ++ Server ++ "/user/" ++ User ++ "/", UserURL = "/admin/server/" ++ Server ++ "/user/" ++ User ++ "/",
?XE(<<"tr">>, [ ?XE(<<"tr">>, [
?XE(<<"td">>, [?AC(list_to_binary(UserURL), jlib:jid_to_string(JID))]), ?XE(<<"td">>, [?AC(list_to_binary(UserURL), jid:encode(JID))]),
?XCTB("td", atom_to_list(Client_id)), ?XCTB("td", atom_to_list(Client_id)),
?XCTB("td", atom_to_list(OS_id)), ?XCTB("td", atom_to_list(OS_id)),
?XCTB("td", LangS), ?XCTB("td", LangS),
@ -1584,12 +1593,12 @@ get_sessions_filtered(Filter, server) ->
ejabberd_config:get_myhosts()); ejabberd_config:get_myhosts());
get_sessions_filtered(Filter, Host) -> get_sessions_filtered(Filter, Host) ->
Match = case Filter of Match = case Filter of
[{<<"client">>, Client}] -> {{session, '$1'}, jlib:binary_to_atom(Client), '$2', '$3', '$4', '$5', '$6', '$7'}; [{<<"client">>, Client}] -> {{session, '$1'}, misc:binary_to_atom(Client), '$2', '$3', '$4', '$5', '$6', '$7'};
[{<<"os">>, OS}] -> {{session, '$1'}, '$2', jlib:binary_to_atom(OS), '$3', '$4', '$5', '$6', '$7'}; [{<<"os">>, OS}] -> {{session, '$1'}, '$2', misc:binary_to_atom(OS), '$3', '$4', '$5', '$6', '$7'};
[{<<"conntype">>, ConnType}] -> {{session, '$1'}, '$2', '$3', '$4', jlib:binary_to_atom(ConnType), '$5', '$6', '$7'}; [{<<"conntype">>, ConnType}] -> {{session, '$1'}, '$2', '$3', '$4', misc:binary_to_atom(ConnType), '$5', '$6', '$7'};
[{<<"languages">>, Lang}] -> {{session, '$1'}, '$2', '$3', binary_to_list(Lang), '$4', '$5', '$6', '$7'}; [{<<"languages">>, Lang}] -> {{session, '$1'}, '$2', '$3', binary_to_list(Lang), '$4', '$5', '$6', '$7'};
[{<<"client">>, Client}, {<<"os">>, OS}] -> {{session, '$1'}, jlib:binary_to_atom(Client), jlib:binary_to_atom(OS), '$3', '$4', '$5', '$6', '$7'}; [{<<"client">>, Client}, {<<"os">>, OS}] -> {{session, '$1'}, misc:binary_to_atom(Client), misc:binary_to_atom(OS), '$3', '$4', '$5', '$6', '$7'};
[{<<"client">>, Client}, {<<"conntype">>, ConnType}] -> {{session, '$1'}, jlib:binary_to_atom(Client), '$2', '$3', jlib:binary_to_atom(ConnType), '$5', '$6', '$7'}; [{<<"client">>, Client}, {<<"conntype">>, ConnType}] -> {{session, '$1'}, misc:binary_to_atom(Client), '$2', '$3', misc:binary_to_atom(ConnType), '$5', '$6', '$7'};
_ -> {{session, '$1'}, '$2', '$3', '$4', '$5'} _ -> {{session, '$1'}, '$2', '$3', '$4', '$5'}
end, end,
ets:match_object(table_name(Host), Match). ets:match_object(table_name(Host), Match).

View File

@ -1,5 +1,6 @@
mod_webpresence - Presence on the Web mod_webpresence - Presence on the Web
Requires: ejabberd 19.08 or higher
Authors: Igor Goryachev, Badlop, runcom Authors: Igor Goryachev, Badlop, runcom
http://www.ejabberd.im/mod_webpresence http://www.ejabberd.im/mod_webpresence
@ -69,20 +70,12 @@ pixmaps_path:
Remember to put the correct path to the pixmaps directory, Remember to put the correct path to the pixmaps directory,
and make sure the user than runs ejabberd has read access to that directory. and make sure the user than runs ejabberd has read access to that directory.
Default value: "./pixmaps" Default value: "./pixmaps"
port:
This informational option is used only when sending a message to the user.
If you set a different port in the 'listen' section, set this option too.
Default value: 5280
path:
This informational option is used only when sending a message to the user.
If you set a different path in the 'listen' section, set this option too.
Default value: "presence"
baseurl: baseurl:
This informational option is used only when sending a message to the user This informational option is used only when sending a message to the user
and when building the JavaScript code. and when building the JavaScript code.
It is the base part of the URL of the webpresence HTTP content. It is the base part of the URL of the webpresence HTTP content.
You can use the keyword @HOST@. You can use the keyword @HOST@.
If the option is not specified, it takes as default value: http://host:port/path/ If the option is not specified, it takes as default value: http://host:52080/presence/
AUTOMATIC ENABLE AUTOMATIC ENABLE
@ -144,8 +137,6 @@ modules:
host: "webstatus.@HOST@" host: "webstatus.@HOST@"
access: local access: local
pixmaps_path: "/path/to/pixmaps" pixmaps_path: "/path/to/pixmaps"
port: 80
path: "status"
baseurl: "http://www.example.org/status/" baseurl: "http://www.example.org/status/"

View File

@ -33,6 +33,7 @@
-include("xmpp.hrl"). -include("xmpp.hrl").
-include("logger.hrl"). -include("logger.hrl").
-include("translate.hrl").
-include("ejabberd_web_admin.hrl"). -include("ejabberd_web_admin.hrl").
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
@ -53,11 +54,7 @@ start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
start(Host, Opts) -> start(Host, Opts) ->
Default_dir = case code:priv_dir(ejabberd) of Dir = gen_mod:get_opt(pixmaps_path, Opts),
{error, _} -> ?PIXMAPS_DIR;
Path -> filename:join([Path, ?PIXMAPS_DIR])
end,
Dir = gen_mod:get_opt(pixmaps_path, Opts, fun(D) -> D end, Default_dir),
catch ets:new(pixmaps_dirs, [named_table, public]), catch ets:new(pixmaps_dirs, [named_table, public]),
ets:insert(pixmaps_dirs, {directory, Dir}), ets:insert(pixmaps_dirs, {directory, Dir}),
case gen_mod:start_child(?MODULE, Host, Opts) of case gen_mod:start_child(?MODULE, Host, Opts) of
@ -75,19 +72,23 @@ stop(Host) ->
gen_mod:stop_child(?MODULE, Host), gen_mod:stop_child(?MODULE, Host),
ok. ok.
-spec mod_opt_type(atom()) -> fun((term()) -> term()). mod_opt_type(host) ->
mod_opt_type(host) -> fun iolist_to_binary/1; econf:host();
mod_opt_type(access) -> fun acl:access_rules_validator/1; mod_opt_type(access) ->
mod_opt_type(pixmaps_path) -> fun iolist_to_binary/1; econf:acl();
mod_opt_type(pixmaps_path) ->
econf:directory();
mod_opt_type(port) -> mod_opt_type(port) ->
fun(I) when is_integer(I), I>0, I<65536 -> I end; econf:pos_int();
mod_opt_type(path) -> fun iolist_to_binary/1; mod_opt_type(path) ->
mod_opt_type(baseurl) -> fun iolist_to_binary/1. econf:binary();
mod_opt_type(baseurl) ->
econf:binary().
-spec mod_options(binary()) -> [{atom(), any()}]. -spec mod_options(binary()) -> [{atom(), any()}].
mod_options(Host) -> mod_options(Host) ->
[{host, <<"webpresence.@HOST@">>}, [{host, <<"webpresence.", Host/binary>>},
{access, none}, {access, local},
{pixmaps_path, ?PIXMAPS_DIR}, {pixmaps_path, ?PIXMAPS_DIR},
{port, 5280}, {port, 5280},
{path, <<"presence">>}, {path, <<"presence">>},
@ -114,12 +115,9 @@ init([Host, Opts]) ->
{attributes, record_info(fields, webpresence)}]), {attributes, record_info(fields, webpresence)}]),
mnesia:add_table_index(webpresence, ridurl), mnesia:add_table_index(webpresence, ridurl),
update_table(), update_table(),
MyHost = gen_mod:get_opt_host(Host, Opts, <<"webpresence.@HOST@">>), MyHost = gen_mod:get_opt(host, Opts),
Access = gen_mod:get_opt(access, Opts, fun(O) -> O end, local), Access = gen_mod:get_opt(access, Opts),
Port = gen_mod:get_opt(port, Opts, fun(O) -> O end, 5280), BaseURL1 = gen_mod:get_opt(baseurl, Opts),
Path = gen_mod:get_opt(path, Opts, fun(O) -> O end, <<"presence">>),
BaseURL1 = gen_mod:get_opt(baseurl, Opts, fun(O) -> O end,
iolist_to_binary(io_lib:format(<<"http://~s:~p/~s/">>, [Host, Port, Path]))),
BaseURL2 = ejabberd_regexp:greplace(BaseURL1, <<"@HOST@">>, Host), BaseURL2 = ejabberd_regexp:greplace(BaseURL1, <<"@HOST@">>, Host),
register_iq_handlers(MyHost), register_iq_handlers(MyHost),
ejabberd_router:register_route(MyHost, Host), ejabberd_router:register_route(MyHost, Host),
@ -304,7 +302,7 @@ process_disco_items(#iq{lang = Lang} = IQ) ->
name = <<"field">>, name = <<"field">>,
attrs = [ attrs = [
{<<"type">>, Type}, {<<"type">>, Type},
{<<"label">>, ?T(Label)}, {<<"label">>, translate:translate(Lang, ?T(Label))},
{<<"var">>, Var} {<<"var">>, Var}
], ],
children = Vals children = Vals
@ -445,7 +443,7 @@ send_message_registered(WP, To, Host, BaseURL, Lang) ->
false -> <<"">>; false -> <<"">>;
true -> ?BC([ true -> ?BC([
<<" text\n" <<" text\n"
" text/res/<">>, ?T(<<"Resource">>), <<">\n">> " text/res/<">>, translate:translate(Lang, ?T("Resource")), <<">\n">>
]) ])
end, end,
Oimage = case WP#webpresence.icon of Oimage = case WP#webpresence.icon of
@ -455,9 +453,9 @@ send_message_registered(WP, To, Host, BaseURL, Lang) ->
<<" image\n" <<" image\n"
" image/example.php\n" " image/example.php\n"
" image/mypresence.png\n" " image/mypresence.png\n"
" image/res/<">>, ?T(<<"Resource">>), <<">\n" " image/res/<">>, translate:translate(Lang, ?T("Resource")), <<">\n"
" image/theme/<">>, ?T(<<"Icon Theme">>), <<">\n" " image/theme/<">>, translate:translate(Lang, ?T("Icon Theme")), <<">\n"
" image/theme/<">>, ?T(<<"Icon Theme">>), <<">/res/<">>, ?T(<<"Resource">>), <<">\n">> " image/theme/<">>, translate:translate(Lang, ?T("Icon Theme")), <<">/res/<">>, translate:translate(Lang, ?T("Resource")), <<">\n">>
]) ])
end, end,
Oxml = case WP#webpresence.xml of Oxml = case WP#webpresence.xml of
@ -484,24 +482,24 @@ send_message_registered(WP, To, Host, BaseURL, Lang) ->
RIDT = ?BC([<<"rid/">>, RID]), RIDT = ?BC([<<"rid/">>, RID]),
{?BC([<<" ">>, RIDT, <<"\n">>]), {?BC([<<" ">>, RIDT, <<"\n">>]),
?BC([<<" ">>, BaseURL, RIDT, <<"/">>, Allowed_type, <<"/\n">>]), ?BC([<<" ">>, BaseURL, RIDT, <<"/">>, Allowed_type, <<"/\n">>]),
?BC([?T(<<"If you forget your RandomID, register again to receive this message.">>), <<"\n">>, ?BC([translate:translate(Lang, ?T("If you forget your RandomID, register again to receive this message.")), <<"\n">>,
?T(<<"To get a new RandomID, disable the option and register again.">>), <<"\n">>]) translate:translate(Lang, ?T("To get a new RandomID, disable the option and register again.")), <<"\n">>])
} }
end, end,
Subject = ?BC([?T(<<"Web Presence">>), <<": ">>, ?T(<<"registered">>)]), Subject = ?BC([translate:translate(Lang, ?T("Web Presence")), <<": ">>, translate:translate(Lang, ?T("registered"))]),
Body = ?BC([?T(<<"You have registered:">>), <<" ">>, JIDS, <<"\n\n">>, Body = ?BC([translate:translate(Lang, ?T("You have registered:")), <<" ">>, JIDS, <<"\n\n">>,
?T(<<"Use URLs like:">>), <<"\n">>, translate:translate(Lang, ?T("Use URLs like:")), <<"\n">>,
<<" ">>, BaseURL, <<"USERID/OUTPUT/\n">>, <<" ">>, BaseURL, <<"USERID/OUTPUT/\n">>,
<<"\n">>, <<"\n">>,
<<"USERID:\n">>, USERID_jid, USERID_rid, <<"\n">>, <<"USERID:\n">>, USERID_jid, USERID_rid, <<"\n">>,
<<"OUTPUT:\n">>, Oimage, Oxml, Ojs, Otext, Oavatar, <<"\n">>, <<"OUTPUT:\n">>, Oimage, Oxml, Ojs, Otext, Oavatar, <<"\n">>,
?T(<<"Example:">>), <<"\n">>, Example_jid, Example_rid, <<"\n">>, translate:translate(Lang, ?T("Example:")), <<"\n">>, Example_jid, Example_rid, <<"\n">>,
Text_rid]), Text_rid]),
send_headline(Host, To, Subject, Body). send_headline(Host, To, Subject, Body).
send_message_unregistered(To, Host, Lang) -> send_message_unregistered(To, Host, Lang) ->
Subject = ?BC([?T(<<"Web Presence">>), <<": ">>, ?T(<<"unregistered">>)]), Subject = ?BC([translate:translate(Lang, ?T("Web Presence")), <<": ">>, translate:translate(Lang, ?T("unregistered"))]),
Body = ?BC([?T(<<"You have unregistered.">>), <<"\n\n">>]), Body = ?BC([translate:translate(Lang, ?T("You have unregistered.")), <<"\n\n">>]),
send_headline(Host, To, Subject, Body). send_headline(Host, To, Subject, Body).
send_headline(Host, To, Subject, Body) -> send_headline(Host, To, Subject, Body) ->
@ -704,12 +702,12 @@ make_js(WP, Prs, Show_us, Lang, Q) ->
end, end,
?BC([US_string, <<"var jabber_resources=[\n">>, R_string, <<"];">>, CB_string]). ?BC([US_string, <<"var jabber_resources=[\n">>, R_string, <<"];">>, CB_string]).
long_show(<<"available">>, Lang) -> ?T(<<"available">>); long_show(<<"available">>, Lang) -> translate:translate(Lang, ?T("available"));
long_show(<<"chat">>, Lang) -> ?T(<<"free for chat">>); long_show(<<"chat">>, Lang) -> translate:translate(Lang, ?T("free for chat"));
long_show(<<"away">>, Lang) -> ?T(<<"away">>); long_show(<<"away">>, Lang) -> translate:translate(Lang, ?T("away"));
long_show(<<"xa">>, Lang) -> ?T(<<"extended away">>); long_show(<<"xa">>, Lang) -> translate:translate(Lang, ?T("extended away"));
long_show(<<"dnd">>, Lang) -> ?T(<<"do not disturb">>); long_show(<<"dnd">>, Lang) -> translate:translate(Lang, ?T("do not disturb"));
long_show(_, Lang) -> ?T(<<"unavailable">>). long_show(_, Lang) -> translate:translate(Lang, ?T("unavailable")).
intund2string(undefined) -> intund2string(0); intund2string(undefined) -> intund2string(0);
intund2string(Int) when is_integer(Int) -> list_to_binary(integer_to_list(Int)). intund2string(Int) when is_integer(Int) -> list_to_binary(integer_to_list(Int)).
@ -887,20 +885,20 @@ process(LocalPath, Request) ->
process2([], #request{lang = Lang1}) -> process2([], #request{lang = Lang1}) ->
Lang = parse_lang(Lang1), Lang = parse_lang(Lang1),
Title = [?XC(<<"title">>, ?T(<<"Web Presence">>))], Title = [?XC(<<"title">>, translate:translate(Lang, ?T("Web Presence")))],
Desc = [?XC(<<"p">>, ?BC([ ?T(<<"To publish your presence using this system you need a Jabber account in this Jabber server.">>), <<" ">>, Desc = [?XC(<<"p">>, ?BC([ translate:translate(Lang, ?T("To publish your presence using this system you need a Jabber account in this Jabber server.")), <<" ">>,
?T(<<"Login with a Jabber client, open the Service Discovery and register in Web Presence.">>), translate:translate(Lang, ?T("Login with a Jabber client, open the Service Discovery and register in Web Presence.")),
?T(<<"You will receive a message with further instructions.">>)]))], translate:translate(Lang, ?T("You will receive a message with further instructions."))]))],
Link_themes = [?AC(<<"themes">>, ?T(<<"Icon Theme">>))], Link_themes = [?AC(<<"themes">>, translate:translate(Lang, ?T("Icon Theme")))],
Body = [?XC(<<"h1">>, ?T(<<"Web Presence">>))] ++ Desc ++ Link_themes, Body = [?XC(<<"h1">>, translate:translate(Lang, ?T("Web Presence")))] ++ Desc ++ Link_themes,
make_xhtml(Title, Body); make_xhtml(Title, Body);
process2([<<"themes">>], #request{lang = Lang1}) -> process2([<<"themes">>], #request{lang = Lang1}) ->
Lang = parse_lang(Lang1), Lang = parse_lang(Lang1),
Title = [?XC(<<"title">>, ?BC([?T(<<"Web Presence">>), <<" - ">>, ?T("Icon Theme")]))], Title = [?XC(<<"title">>, ?BC([translate:translate(Lang, ?T("Web Presence")), <<" - ">>, translate:translate(Lang, ?T("Icon Theme"))]))],
Themes = available_themes(list), Themes = available_themes(list),
Icon_themes = themes_to_xhtml(Themes), Icon_themes = themes_to_xhtml(Themes),
Body = [?XC(<<"h1">>, ?T(<<"Icon Theme">>))] ++ Icon_themes, Body = [?XC(<<"h1">>, translate:translate(Lang, ?T("Icon Theme")))] ++ Icon_themes,
make_xhtml(Title, Body); make_xhtml(Title, Body);
process2([<<"image">>, Theme, Show], #request{} = _Request) -> process2([<<"image">>, Theme, Show], #request{} = _Request) ->
@ -958,7 +956,7 @@ serve_web_presence(TypeURL, User, Server, Tail, #request{lang = Lang1, q = Q}) -
%%%% --------------------- %%%% ---------------------
web_menu_host(Acc, _Host, Lang) -> web_menu_host(Acc, _Host, Lang) ->
[{<<"webpresence">>, ?T(<<"Web Presence">>)} | Acc]. [{<<"webpresence">>, translate:translate(Lang, ?T("Web Presence"))} | Acc].
web_page_host(_, _Host, web_page_host(_, _Host,
#request{path = [<<"webpresence">>], #request{path = [<<"webpresence">>],