summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--src/gen_mod.erl39
-rw-r--r--src/mod_announce.erl2
-rw-r--r--src/mod_echo.erl9
-rw-r--r--src/mod_irc/mod_irc.erl11
-rw-r--r--src/mod_muc/mod_muc.erl9
-rw-r--r--src/mod_offline.erl2
-rw-r--r--src/mod_pubsub/mod_pubsub.erl7
-rw-r--r--src/web/ejabberd_web_admin.erl112
9 files changed, 176 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index 630ed154..9633b9f1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2005-05-23 Alexey Shchepin <alexey@sevcom.net>
+ * src/web/ejabberd_web_admin.erl: Updated CSS, added modules
+ management (thanks to Sergei Golovan)
+
+ * src/gen_mod.erl: Added function loaded_modules_with_opts/0, new
+ API for module stopping (thanks to Sergei Golovan)
+ * src/mod_muc/mod_muc.erl: Moved a process name to a macros,
+ updated module stopping (thanks to Sergei Golovan)
+ * src/mod_irc/mod_irc.erl: Likewise
+ * src/mod_pubsub/mod_pubsub.erl: Likewise
+ * src/mod_announce.erl: Updated module stopping (thanks to Sergei
+ Golovan)
+ * src/mod_echo.erl: Likewise
+ * src/mod_offline.erl: Likewise
+
* src/web/ejabberd_http.erl: "Connection:" header value now
matched case-insensitive, and returned to client, replaced
duplicate is_space($\r) with is_space($\t) (thanks to Maxim
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index 205c843c..768869d5 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -17,6 +17,7 @@
get_opt/3,
get_module_opt/3,
loaded_modules/0,
+ loaded_modules_with_opts/0,
get_hosts/2]).
-export([behaviour_info/1]).
@@ -52,11 +53,39 @@ stop_module(Module) ->
case catch Module:stop() of
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]);
+ {wait, ProcList} when is_list(ProcList) ->
+ lists:foreach(fun wait_for_process/1, ProcList),
+ ets:delete(ejabberd_modules, Module),
+ ok;
+ {wait, Process} ->
+ wait_for_process(Process),
+ ets:delete(ejabberd_modules, Module),
+ ok;
_ ->
ets:delete(ejabberd_modules, Module),
ok
end.
+wait_for_process(Process) ->
+ MonitorReference = erlang:monitor(process, Process),
+ wait_for_stop(Process, MonitorReference).
+
+wait_for_stop(Process, MonitorReference) ->
+ receive
+ {'DOWN', MonitorReference, _Type, _Object, _Info} ->
+ ok
+ after 5000 ->
+ catch exit(whereis(Process), kill),
+ wait_for_stop1(MonitorReference)
+ end.
+
+wait_for_stop1(MonitorReference) ->
+ receive
+ {'DOWN', MonitorReference, _Type, _Object, _Info} ->
+ ok
+ after 5000 ->
+ ok
+ end.
get_opt(Opt, Opts) ->
case lists:keysearch(Opt, 1, Opts) of
@@ -86,7 +115,15 @@ get_module_opt(Module, Opt, Default) ->
loaded_modules() ->
ets:select(ejabberd_modules,
- [{#ejabberd_module{_ = '_', module = '$1'}, [],['$1']}]).
+ [{#ejabberd_module{_ = '_', module = '$1'},
+ [],
+ ['$1']}]).
+
+loaded_modules_with_opts() ->
+ ets:select(ejabberd_modules,
+ [{#ejabberd_module{_ = '_', module = '$1', opts = '$2'},
+ [],
+ [{{'$1', '$2'}}]}]).
get_hosts(Opts, Prefix) ->
case catch gen_mod:get_opt(hosts, Opts) of
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 495eac26..b8581a37 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -70,7 +70,7 @@ stop() ->
ejabberd_hooks:delete(sm_register_connection_hook,
?MODULE, send_motd, 50),
exit(whereis(?PROCNAME), stop),
- ok.
+ {wait, ?PROCNAME}.
announce(From, To, Packet) ->
case To of
diff --git a/src/mod_echo.erl b/src/mod_echo.erl
index f7a268f6..b93bba91 100644
--- a/src/mod_echo.erl
+++ b/src/mod_echo.erl
@@ -17,12 +17,12 @@
-include("ejabberd.hrl").
-include("jlib.hrl").
-
+-define(PROCNAME, ejabberd_mod_echo).
start(Opts) ->
%Host = gen_mod:get_opt(host, Opts),
Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME),
- register(ejabberd_mod_echo, spawn(?MODULE, init, [Host])).
+ register(?PROCNAME, spawn(?MODULE, init, [Host])).
init(Host) ->
ejabberd_router:register_route(Host),
@@ -41,5 +41,6 @@ loop(Host) ->
end.
stop() ->
- ejabberd_mod_echo ! stop,
- ok.
+ ?PROCNAME ! stop,
+ {wait, ?PROCNAME}.
+
diff --git a/src/mod_irc/mod_irc.erl b/src/mod_irc/mod_irc.erl
index 337d9761..9b05876f 100644
--- a/src/mod_irc/mod_irc.erl
+++ b/src/mod_irc/mod_irc.erl
@@ -24,6 +24,8 @@
-record(irc_connection, {jid_server_host, pid}).
-record(irc_custom, {us_host, data}).
+-define(PROCNAME, ejabberd_mod_irc).
+
start(Opts) ->
iconv:start(),
mnesia:create_table(irc_custom,
@@ -33,7 +35,7 @@ start(Opts) ->
Host = hd(Hosts),
update_table(Host),
Access = gen_mod:get_opt(access, Opts, all),
- register(ejabberd_mod_irc, spawn(?MODULE, init, [Hosts, Access])).
+ register(?PROCNAME, spawn(?MODULE, init, [Hosts, Access])).
init(Hosts, Access) ->
catch ets:new(irc_connection, [named_table,
@@ -172,11 +174,10 @@ do_route1(Host, From, To, Packet) ->
end.
-
-
stop() ->
- ejabberd_mod_irc ! stop,
- ok.
+ ?PROCNAME ! stop,
+ {wait, ?PROCNAME}.
+
closed_connection(Host, From, Server) ->
ets:delete(irc_connection, {From, Server, Host}).
diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl
index e7ffe42d..f3c61e59 100644
--- a/src/mod_muc/mod_muc.erl
+++ b/src/mod_muc/mod_muc.erl
@@ -30,6 +30,7 @@
-record(muc_online_room, {name_host, pid}).
-record(muc_registered, {us_host, nick}).
+-define(PROCNAME, ejabberd_mod_muc).
start(Opts) ->
mnesia:create_table(muc_room,
@@ -45,7 +46,7 @@ start(Opts) ->
Access = gen_mod:get_opt(access, Opts, all),
AccessCreate = gen_mod:get_opt(access_create, Opts, all),
AccessAdmin = gen_mod:get_opt(access_admin, Opts, none),
- register(ejabberd_mod_muc,
+ register(?PROCNAME,
spawn(?MODULE, init,
[Hosts, {Access, AccessCreate, AccessAdmin}])).
@@ -252,12 +253,12 @@ do_route1(Host, Access, From, To, Packet) ->
room_destroyed(Host, Room) ->
- ejabberd_mod_muc ! {room_destroyed, {Room, Host}},
+ ?PROCNAME ! {room_destroyed, {Room, Host}},
ok.
stop() ->
- ejabberd_mod_muc ! stop,
- ok.
+ ?PROCNAME ! stop,
+ {wait, ?PROCNAME}.
store_room(Host, Name, Opts) ->
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 3d7bd0e0..1c79d6a5 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -89,7 +89,7 @@ stop() ->
ejabberd_hooks:delete(remove_user,
?MODULE, remove_user, 50),
exit(whereis(?PROCNAME), stop),
- ok.
+ {wait, ?PROCNAME}.
store_packet(From, To, Packet) ->
Type = xml:get_tag_attr_s("type", Packet),
diff --git a/src/mod_pubsub/mod_pubsub.erl b/src/mod_pubsub/mod_pubsub.erl
index 1823be44..40cdabc4 100644
--- a/src/mod_pubsub/mod_pubsub.erl
+++ b/src/mod_pubsub/mod_pubsub.erl
@@ -35,6 +35,7 @@
subscription = none}).
-record(item, {id, publisher, payload}).
+-define(PROCNAME, ejabberd_mod_pubsub).
start(Opts) ->
mnesia:create_table(pubsub_node,
@@ -45,7 +46,7 @@ start(Opts) ->
update_table(Host),
mnesia:add_table_index(pubsub_node, host_parent),
ServedHosts = gen_mod:get_opt(served_hosts, Opts, []),
- register(ejabberd_mod_pubsub,
+ register(?PROCNAME,
proc_lib:spawn_link(?MODULE, init, [Hosts, ServedHosts, self()])).
@@ -202,8 +203,8 @@ do_route(Host, From, To, Packet) ->
stop() ->
- ejabberd_mod_pubsub ! stop,
- ok.
+ ?PROCNAME ! stop,
+ {wait, ?PROCNAME}.
diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl
index 754e89c3..dacbf781 100644
--- a/src/web/ejabberd_web_admin.erl
+++ b/src/web/ejabberd_web_admin.erl
@@ -185,12 +185,12 @@ html>body #container {
#navigation ul {
position: absolute;
- top: 55px;
+ top: 54px;
left: 0;
- padding: 0 1px 1px;
+ padding: 0 1px 1px 1px;
margin: 0;
font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 7.5pt;
+ font-size: 8pt;
font-weight: bold;
background: #d47911;
width: 13em;
@@ -206,9 +206,9 @@ html>body #container {
#navigation ul li a {
margin: 0;
display: block;
- padding: 0.25em 0.5em 0.25em 0.75em;
+ padding: 3px 6px 3px 9px;
border-left: 1em solid #ffc78c;
- border-top: 1px solid gray;
+ border-top: 1px solid #d47911;
background: #ffe3c9;
text-decoration: none;
}
@@ -257,7 +257,7 @@ input {
input[type=submit] {
font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 7pt;
+ font-size: 8pt;
font-weight: bold;
color: #ffffff;
background-color: #fe8a00;
@@ -1683,6 +1683,7 @@ get_node(Node, [], Query, Lang) ->
[?LI([?ACT("db/", "DB Management")]),
?LI([?ACT("backup/", "Backup Management")]),
?LI([?ACT("ports/", "Listened Ports Management")]),
+ ?LI([?ACT("modules/", "Modules Management")]),
?LI([?ACT("stats/", "Statistics")])
]),
?XAE("form", [{"method", "post"}],
@@ -1825,6 +1826,28 @@ get_node(Node, ["ports"], Query, Lang) ->
[node_ports_to_xhtml(NewPorts, Lang)])
];
+get_node(Node, ["modules"], Query, Lang) ->
+ Modules = rpc:call(Node, gen_mod, loaded_modules_with_opts, []),
+ Res = case catch node_modules_parse_query(Node, Modules, Query) of
+ submitted ->
+ ok;
+ {'EXIT', Reason} ->
+ ?INFO_MSG("~p~n", [Reason]),
+ error;
+ _ ->
+ nothing
+ end,
+ NewModules = lists:sort(rpc:call(Node, gen_mod, loaded_modules_with_opts, [])),
+ [?XC("h1", ?T("Modules at ") ++ atom_to_list(Node))] ++
+ case Res of
+ ok -> [?CT("submitted"), ?P];
+ error -> [?CT("bad format"), ?P];
+ nothing -> []
+ end ++
+ [?XAE("form", [{"method", "post"}],
+ [node_modules_to_xhtml(NewModules, Lang)])
+ ];
+
get_node(Node, ["stats"], Query, Lang) ->
UpTime = rpc:call(Node, erlang, statistics, [wall_clock]),
UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]),
@@ -2041,13 +2064,13 @@ node_ports_parse_query(Node, Ports, Query) ->
Module = list_to_atom(SModule),
{ok, Tokens, _} = erl_scan:string(SOpts ++ "."),
{ok, Opts} = erl_parse:parse_term(Tokens),
- ejabberd_listener:delete_listener(Port),
- ejabberd_listener:add_listener(Port, Module, Opts),
+ rpc:call(Node, ejabberd_listener, delete_listener, [Port]),
+ rpc:call(Node, ejabberd_listener, add_listener, [Port, Module, Opts]),
throw(submitted);
_ ->
case lists:keysearch("delete" ++ SPort, 1, Query) of
{value, _} ->
- ejabberd_listener:delete_listener(Port),
+ rpc:call(Node, ejabberd_listener, delete_listener, [Port]),
throw(submitted);
_ ->
ok
@@ -2066,12 +2089,81 @@ node_ports_parse_query(Node, Ports, Query) ->
Module = list_to_atom(SModule),
{ok, Tokens, _} = erl_scan:string(SOpts ++ "."),
{ok, Opts} = erl_parse:parse_term(Tokens),
- ejabberd_listener:add_listener(Port, Module, Opts),
+ rpc:call(Node, ejabberd_listener, add_listener, [Port, Module, Opts]),
throw(submitted);
_ ->
ok
end.
+node_modules_to_xhtml(Modules, Lang) ->
+ ?XAE("table", [],
+ [?XE("thead",
+ [?XE("tr",
+ [?XCT("td", "Module"),
+ ?XCT("td", "Options")
+ ])]),
+ ?XE("tbody",
+ lists:map(
+ fun({Module, Opts} = E) ->
+ SModule = atom_to_list(Module),
+ ID = term_to_id(E),
+ ?XE("tr",
+ [?XC("td", SModule),
+ ?XE("td", [?INPUTS("text", "opts" ++ SModule,
+ term_to_string(Opts), "40")]),
+ ?XE("td", [?INPUTT("submit", "restart" ++ SModule,
+ "Restart")]),
+ ?XE("td", [?INPUTT("submit", "stop" ++ SModule,
+ "Stop")])
+ ]
+ )
+ end, Modules) ++
+ [?XE("tr",
+ [?XE("td", [?INPUT("text", "modulenew", "")]),
+ ?XE("td", [?INPUTS("text", "optsnew", "", "40")]),
+ ?XAE("td", [{"colspan", "2"}],
+ [?INPUTT("submit", "start", "Start")])
+ ]
+ )]
+ )]).
+
+node_modules_parse_query(Node, Modules, Query) ->
+ lists:foreach(
+ fun({Module, _Opts1}) ->
+ SModule = atom_to_list(Module),
+ case lists:keysearch("restart" ++ SModule, 1, Query) of
+ {value, _} ->
+ {value, {_, SOpts}} =
+ lists:keysearch("opts" ++ SModule, 1, Query),
+ {ok, Tokens, _} = erl_scan:string(SOpts ++ "."),
+ {ok, Opts} = erl_parse:parse_term(Tokens),
+ rpc:call(Node, gen_mod, stop_module, [Module]),
+ rpc:call(Node, gen_mod, start_module, [Module, Opts]),
+ throw(submitted);
+ _ ->
+ case lists:keysearch("stop" ++ SModule, 1, Query) of
+ {value, _} ->
+ rpc:call(Node, gen_mod, stop_module, [Module]),
+ throw(submitted);
+ _ ->
+ ok
+ end
+ end
+ end, Modules),
+ case lists:keysearch("start", 1, Query) of
+ {value, _} ->
+ {{value, {_, SModule}},
+ {value, {_, SOpts}}} =
+ {lists:keysearch("modulenew", 1, Query),
+ lists:keysearch("optsnew", 1, Query)},
+ Module = list_to_atom(SModule),
+ {ok, Tokens, _} = erl_scan:string(SOpts ++ "."),
+ {ok, Opts} = erl_parse:parse_term(Tokens),
+ rpc:call(Node, gen_mod, start_module, [Module, Opts]),
+ throw(submitted);
+ _ ->
+ ok
+ end.
pretty_print(El) ->