/*
// File: shutdownd.c
// Purpose: Does mudlibby things before calling the shutdown() efun.
// Credits:
// 92-09-26 Truilkan @ Basis wrote the original version.
// 93-01-04 Pallando @ TMI-2 added in the delay option and Apocalypse bits.
// 93-01-14 Pallando moved the emotes to a seperate file
// Comments: (makes it easier for other muds to create their own emote files)
// 93-04-02 Pallando added stop_shutdown()
// 93-05-22 Watcher @ TMI-2 Changed shout()s to message()s
// Comments: ensures the emotes are labeled and this_player() get them.
// 93-07-08 Pallando ensured delay to shutdown isn't messaged twice.
// 93-07-08 Grendel@tmi-2 stoped two shutdowns happening at once
// 93-10-30 Inspiral@TMI-2 added the DNS_MASTER call in save_daemons().
// 94-04-30 Robocoder added query_reason(), and PRUNE_LOGDIR to save_daemons()
// 94-07-26 Blue streamlined the get_emote() function, and made the
// function select a random file, instead of a #defined one.
// Also added some comments to the functions.
// 94-12-04 Blue fixed the count_down() function for the new driver,
// cause previous_object() wasn't defined any more.
*/
#include <config.h>
#include <uid.h>
#include <daemons.h>
#include <net/daemons.h>
#include <driver/origin.h>
#define log( x )
// #define EMOTE_FILE "/adm/daemons/sh_apocalypse.t"
#define EMOTE_DIR "/adm/daemons/"
// Note the trailing slash. Saves a bit of bother.
#define EMOTE_WILD "sh_*.t"
// The format of the filenames in EMOTE_DIR with the shutdown
// sequences in them.
string *emotes;
int num_emot; // the number of emotes
int s_sec; // The time() the shutdown is due at, in seconds.
string reason;
string query_reason() { return reason; }
int query_shutdown() { return s_sec; }
mixed query_emotes() { return copy(emotes); }
void
save_daemons()
{
// Someone commented this check below, and i enabled it again.
// It's there so that no sneaky wiz can send UDP shutdowns
// to all muds by calling this. Leto
if (previous_object()) {
if (getuid(previous_object()) != ROOT_UID) return; // Leto
}
PRUNE_LOGDIR_D->backup_debug_log();
EMOTE_D->save_data();
#ifdef INTERMUD
// Commentd out because wmhod is obsolete and the existing
// Server at Actlab is gone anyways.
// CMWHO_D->halt();
DNS_MASTER->send_shutdown();
#endif
users()->save_data();
}
void init_emotes() {
// Chooses a random emote file, if it can find any. If so,
// loads the contents into the *emotes array. If not, sets
// the *emotes array to be empty.
string *emotefiles;
emotefiles = get_dir( EMOTE_DIR + EMOTE_WILD );
if (!sizeof( emotefiles )) {
emotes = ({ });
num_emot = -1;
}
else {
emotes = explode( read_file(EMOTE_DIR + emotefiles[random(sizeof(emotefiles))]), "###\n");
num_emot = sizeof(emotes) - 1;
#ifdef DEBUG
write ("NE="+num_emot) ;
#endif
}
}
void
do_shutdown(int how) {
// Performs the actual shutting down, right at the end.
if ((previous_object() && geteuid( previous_object() ) != ROOT_UID) ||
(!previous_object() && origin()==ORIGIN_CALL_OTHER) ) return ;
save_daemons();
shutdown(how);
}
void count_down(int how);
varargs
int start_shutdown( int how, int delay, string reasoning ) {
// Called by the shutdown command to start the process off.
if( geteuid( previous_object() ) != ROOT_UID ) return s_sec;
if( delay < 0 ) return s_sec;
if( this_player() )
message("shutdown", (string)this_player()->query("cap_name") +
" cackles: The end of the world is nigh. Prepare to meet thy " +
"DOOM!\n", users());
reason = reasoning;
if( !delay )
{
do_shutdown( how );
return time();
}
// if there is another shutdown on the way then cancel it
if(s_sec)
remove_call_out("count_down");
s_sec = time() + ( delay * 60 );
init_emotes();
count_down( how );
return s_sec;
}
string get_emote( int delay )
{
// Returns the appropriate emote to the number of minutes left.
if( delay < num_emot ) return emotes[(num_emot-delay)];
return 0; // No message except the time until shutdown, done by count_down()
}
void count_down( int how )
{
// A rather foolishly written function (sorry :) that is
// called every minute once the shutdown has started.
// It calculates the remaining time to shutdown, and
// broadcasts the appropriate messages.
int delay;
string msg;
if ( (origin() != ORIGIN_LOCAL) && (origin() != ORIGIN_CALL_OUT) )
return;
delay = ( s_sec + 30 - time() ) / 60;
// If s_sec - time() is a multiple of 60, as it's supposed to be,
// this won't make any difference. However, it seems that the
// call_outs are getting delayed at some point by a couple of
// seconds, so this is needed to get the number of minutes right.
if( msg = get_emote( delay ) )
message( "shutdown", msg, users() );
if( delay ) message( "shutdown",
"The mud will shut down in " + delay + " minutes.\n", users() );
if( delay < 1 )
{
do_shutdown( how );
return;
}
call_out( "count_down", 60, how );
}
int stop_shutdown()
{
// Self-explanatory, I suppose. Stops everything.
if( geteuid( previous_object() ) != ROOT_UID ) return 0;
s_sec = 0;
reason = 0;
remove_call_out( "count_down" );
if( this_player() )
message("shutdown", "The Mighty " + this_player()->query("cap_name") +
" intervenes to save the world.\n", users());
// Blessed are the peacemakers, for they shall save your hard won kit.
return 1;
}