From 8d218dd2b9ad582713c8347444513ccc416a6e8e Mon Sep 17 00:00:00 2001 From: Badlop Date: Sun, 3 Jan 2010 00:38:00 +0000 Subject: [PATCH] Command to stop ejabberd informing users, with grace period, and kindly (EJAB-1112) SVN Revision: 2853 --- src/ejabberd_admin.erl | 54 +++++++++++++++++++++++++++++++++++++++ src/ejabberd_listener.erl | 9 +++++++ src/mod_announce.erl | 22 ++++++++++++++++ src/mod_muc/mod_muc.erl | 2 +- 4 files changed, 86 insertions(+), 1 deletion(-) 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, @@ -215,6 +221,54 @@ get_sasl_error_logger_type () -> _ -> all 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).