aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd_admin.erl54
-rw-r--r--src/ejabberd_listener.erl9
-rw-r--r--src/mod_announce.erl22
-rw-r--r--src/mod_muc/mod_muc.erl2
4 files changed, 86 insertions, 1 deletions
diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl
index b02d83be3..f311790fb 100644
--- a/src/ejabberd_admin.erl
+++ b/src/ejabberd_admin.erl
@@ -30,6 +30,7 @@
-export([start/0, stop/0,
%% Server
status/0, reopen_log/0,
+ stop_kindly/2, send_service_message_all_mucs/2,
%% Accounts
register/3, unregister/2,
registered_users/1,
@@ -79,6 +80,11 @@ commands() ->
desc = "Reopen the log files",
module = ?MODULE, function = reopen_log,
args = [], result = {res, rescode}},
+ #ejabberd_commands{name = stop_kindly, tags = [server],
+ desc = "Inform users and rooms, wait, and stop the server",
+ module = ?MODULE, function = stop_kindly,
+ args = [{delay, integer}, {announcement, string}],
+ result = {res, rescode}},
#ejabberd_commands{name = get_loglevel, tags = [logs, server],
desc = "Get the current loglevel",
module = ejabberd_loglevel, function = get,
@@ -216,6 +222,54 @@ get_sasl_error_logger_type () ->
end.
%%%
+%%% Stop Kindly
+%%%
+
+stop_kindly(DelaySeconds, AnnouncementText) ->
+ Subject = io_lib:format("Server stop in ~p seconds!", [DelaySeconds]),
+ WaitingDesc = io_lib:format("Waiting ~p seconds", [DelaySeconds]),
+ Steps = [
+ {"Stopping ejabberd port listeners",
+ ejabberd_listener, stop_listeners, []},
+ {"Sending announcement to connected users",
+ mod_announce, send_announcement_to_all,
+ [?MYNAME, Subject, AnnouncementText]},
+ {"Sending service message to MUC rooms",
+ ejabberd_admin, send_service_message_all_mucs,
+ [Subject, AnnouncementText]},
+ {WaitingDesc, timer, sleep, [DelaySeconds * 1000]},
+ {"Stopping ejabberd", application, stop, [ejabberd]},
+ {"Stopping Mnesia", mnesia, stop, []},
+ {"Stopping Erlang node", init, stop, []}
+ ],
+ NumberLast = length(Steps),
+ TimestampStart = calendar:datetime_to_gregorian_seconds({date(), time()}),
+ lists:foldl(
+ fun({Desc, Mod, Func, Args}, NumberThis) ->
+ SecondsDiff =
+ calendar:datetime_to_gregorian_seconds({date(), time()})
+ - TimestampStart,
+ io:format("[~p/~p ~ps] ~s... ",
+ [NumberThis, NumberLast, SecondsDiff, Desc]),
+ Result = apply(Mod, Func, Args),
+ io:format("~p~n", [Result]),
+ NumberThis+1
+ end,
+ 1,
+ Steps),
+ ok.
+
+send_service_message_all_mucs(Subject, AnnouncementText) ->
+ Message = io_lib:format("~s~n~s", [Subject, AnnouncementText]),
+ lists:foreach(
+ fun(ServerHost) ->
+ MUCHost = gen_mod:get_module_opt_host(
+ ServerHost, mod_muc, "conference.@HOST@"),
+ mod_muc:broadcast_service_message(MUCHost, Message)
+ end,
+ ?MYHOSTS).
+
+%%%
%%% Account management
%%%
diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl
index 5d0a55c98..465b311c1 100644
--- a/src/ejabberd_listener.erl
+++ b/src/ejabberd_listener.erl
@@ -31,6 +31,7 @@
init/3,
start_listeners/0,
start_listener/3,
+ stop_listeners/0,
stop_listener/2,
parse_listener_portip/2,
add_listener/3,
@@ -304,6 +305,14 @@ start_listener_sup(Port, Module, Opts) ->
[?MODULE]},
supervisor:start_child(ejabberd_listeners, ChildSpec).
+stop_listeners() ->
+ Ports = ejabberd_config:get_local_option(listen),
+ lists:foreach(
+ fun({PortIpNetp, Module, _Opts}) ->
+ delete_listener(PortIpNetp, Module)
+ end,
+ Ports).
+
%% @spec (PortIP, Module) -> ok
%% where
%% PortIP = {Port, IPT | IPS}
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 0db43a232..f9460c198 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -40,6 +40,7 @@
disco_identity/5,
disco_features/5,
disco_items/5,
+ send_announcement_to_all/3,
announce_commands/4,
announce_items/4]).
@@ -846,6 +847,27 @@ get_stored_motd(LServer) ->
{"", ""}
end.
+%% This function is similar to others, but doesn't perform any ACL verification
+send_announcement_to_all(Host, SubjectS, BodyS) ->
+ SubjectEls = if SubjectS /= [] ->
+ [{xmlelement, "subject", [], [{xmlcdata, SubjectS}]}];
+ true ->
+ []
+ end,
+ BodyEls = if BodyS /= [] ->
+ [{xmlelement, "body", [], [{xmlcdata, BodyS}]}];
+ true ->
+ []
+ end,
+ Packet = {xmlelement, "message", [{"type", "normal"}], SubjectEls ++ BodyEls},
+ Sessions = ejabberd_sm:dirty_get_sessions_list(),
+ Local = jlib:make_jid("", Host, ""),
+ lists:foreach(
+ fun({U, S, R}) ->
+ Dest = jlib:make_jid(U, S, R),
+ ejabberd_router:route(Local, Dest, Packet)
+ end, Sessions).
+
%%-------------------------------------------------------------------------
update_tables() ->
diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl
index c731da13d..d8a73850b 100644
--- a/src/mod_muc/mod_muc.erl
+++ b/src/mod_muc/mod_muc.erl
@@ -40,6 +40,7 @@
forget_room/2,
create_room/5,
process_iq_disco_items/4,
+ broadcast_service_message/2,
can_use_nick/3]).
%% gen_server callbacks
@@ -849,7 +850,6 @@ clean_table_from_bad_node(Node, Host) ->
end,
mnesia:transaction(F).
-
update_tables(Host) ->
update_muc_room_table(Host),
update_muc_registered_table(Host).