]> granicus.if.org Git - ejabberd/commitdiff
Command to stop ejabberd informing users, with grace period, and kindly (EJAB-1112)
authorBadlop <badlop@process-one.net>
Sun, 3 Jan 2010 00:38:00 +0000 (00:38 +0000)
committerBadlop <badlop@process-one.net>
Sun, 3 Jan 2010 00:38:00 +0000 (00:38 +0000)
SVN Revision: 2853

src/ejabberd_admin.erl
src/ejabberd_listener.erl
src/mod_announce.erl
src/mod_muc/mod_muc.erl

index b02d83be373ae638b425eaaaebe058a98e5c5ae2..f311790fb33711cc2a784c59928ef510699b4366 100644 (file)
@@ -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
 %%%
index 5d0a55c98dfda46e10cda9099bf981ad4f02063e..465b311c1cfbdec9806ec4c9f87a433eba2962d9 100644 (file)
@@ -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}
index 0db43a23277a8e561956f282abc97a5a03dee0a5..f9460c198e1a8a92d7c9531d792d8056c844b005 100644 (file)
@@ -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() ->
index c731da13dd3c59ce02ae7c0584b52f1f2a038993..d8a73850b9d327c079a0fc99245e87c7b44da82b 100644 (file)
@@ -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).