/*ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ*/
/*Ý                                                                          Þ*/
/*Ý      DOWNSERV NLM                                                        Þ*/
/*Ý                                                                          Þ*/
/*Ý      NetWare Loadable Module to schedule shutdown of a NetWare 386       Þ*/
/*Ý      file server at a later time.                                        Þ*/      
/*Ý                                                                          Þ*/
/*Ý      written by:    Morgan Adair                                         Þ*/
/*Ý      date:          15 July 1991                                         Þ*/
/*Ý                                                                          Þ*/
/*ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß*/

#include <advanced.h>
#include <process.h>
#include <time.h>
#include <nwbindry.h>
#include <errno.h>

#define DELAY_AMOUNT 9
#define TIME_FOR_FIRST_WARNING 10
#define TIME_FOR_SECOND_WARNING 5

LONG		AESEventTag;
struct	AESProcessStructure 	ClockEvent, WarningEvent1,
										WarningEvent2, ShutdownEvent;
LONG		MyNLMHandle;
int		myThreadID;
int		timeRemaining = -1;
int		shutdownTime = FALSE;
int		firstTry = TRUE;

void Usage(void);
LONG TimeToTicks(char *timeIn);
void WakeUp(void);
void SetTimeRemaining(void);
void SetShutdownFlag(void);
void ExitProcedure(void);
void ShutdownServer(void);
void WarnUsers(void);

void main(int argc, char *argv[])
{
	time_t	currentTime;
	char		timeBuf[30];
	LONG		nTicks;
	LONG		warningTimeInTicks;
	int		ccode;

	if (argc != 2) {
		printf("Incorrect number of command line parameters\n");
		Usage();
		exit(-1);
	}

	SecondsToTicks((TIME_FOR_FIRST_WARNING * 60L), 0L, &warningTimeInTicks);

	nTicks = TimeToTicks(argv[1]);
	if (nTicks == -1L) {
		printf("Invalid time entered");
		exit(-1);
	} else if (nTicks < warningTimeInTicks) {
		printf("Shutdown time must be more than %d minutes away", TIME_FOR_FIRST_WARNING);
		exit(-1);
	}

	myThreadID = GetThreadID();
	MyNLMHandle = GetNLMHandle();

	/* AES Event Resource Tag */
	AESEventTag = AllocateResourceTag(MyNLMHandle, (BYTE *)"AES Events",
													AESProcessSignature);
	if (AESEventTag == NULL) {
		printf("Unable to get AES Event resource tag\n");
		exit(-1);
	}

	/* Register exit procedure to return AES Event Resource Tag */
	if (atexit(ExitProcedure) == EFAILURE) {
		printf("Unable to register exit procedure:\n");
		printf("     AES Events resources will not be released when NLM is unloaded\n");
	}

	/* Initialize AESProcessStructure for screen clock */
	ClockEvent.AWakeUpDelayAmount = DELAY_AMOUNT;
	ClockEvent.AProcessToCall = WakeUp;
	ClockEvent.ARTag = AESEventTag;

	/* Initialize AESProcessStructure for first warning */
	WarningEvent1.AWakeUpDelayAmount = nTicks - warningTimeInTicks;
	WarningEvent1.AProcessToCall = SetTimeRemaining;
	WarningEvent1.ARTag = AESEventTag;

	/* Schedule first warning */
	ScheduleSleepAESProcessEvent(&WarningEvent1);

	SecondsToTicks((TIME_FOR_SECOND_WARNING * 60L), 0L, &warningTimeInTicks);

	/* Initialize AESProcessStructure for second warning */
	WarningEvent2.AWakeUpDelayAmount = nTicks - warningTimeInTicks;
	WarningEvent2.AProcessToCall = SetTimeRemaining;
	WarningEvent2.ARTag = AESEventTag;

	/* Schedule second warning */
	ScheduleSleepAESProcessEvent(&WarningEvent2);

	/* Initialize AESProcessStructure for shutdown procedure */
	ShutdownEvent.AWakeUpDelayAmount = nTicks;
	ShutdownEvent.AProcessToCall = SetShutdownFlag;
	ShutdownEvent.ARTag = AESEventTag;

	/* Schedule shutdown */
	ScheduleSleepAESProcessEvent(&ShutdownEvent);

	HideInputCursor();

	gotoxy(10, 10);
	printf("Server shutdown scheduled for:  %s:00", argv[1]);

	do {
		/* Get the time */
		currentTime = time(NULL);
		if (!currentTime)
			printf("Unable to get current time\n");

		else {
			/* Display time */
			strftime(timeBuf, 28, "%H:%M:%S     (%I:%M:%S %p)", localtime(&currentTime));
			gotoxy(27, 12);
			printf(           "Current time:  %s", timeBuf);
		}

		/* Check flags and take appropriate actions */
		if ((timeRemaining == TIME_FOR_FIRST_WARNING) || 
			 (timeRemaining == TIME_FOR_SECOND_WARNING) ||
			 (timeRemaining == 0))
			WarnUsers();

		if (shutdownTime == TRUE)
			ShutdownServer();

		/* Schedule a wakeup call */
		ScheduleSleepAESProcessEvent(&ClockEvent);

		/* Go to sleep */
		ccode = SuspendThread(myThreadID);
		if (ccode != ESUCCESS)
			printf("Suspend thread failed, ccode = %d\r\n", ccode);

	} while (1);
}

void Usage (void)
{
	ConsolePrintf("DOWNSERV:  Schedule server shutdown\n");
	ConsolePrintf("Usage: load downserv <hh:mm>\n");
	ConsolePrintf("Uses 24-hour clock (22:30 = 10:30 pm)\n");
}

LONG TimeToTicks(char *timeIn)
{
	char	hourStr[3];
	char	minStr[3];
	int	hour, min;
	LONG	nSec;
	LONG	nTicks;
	time_t		timeInSec;
	struct tm	*currentTime;

	if ((strlen(timeIn) < 4) || (strlen(timeIn) > 5)) {
		printf("Invalid time specification\n");
		Usage();
		exit(-1);
	}

	if (strlen(timeIn) == 4) {
		if (timeIn[1] != ':') {
			printf("Missing ':' in time specification\n");
			return((LONG)-1L);
		}
		hourStr[0] = timeIn[0];
		hourStr[1] = '\0';
		minStr[0] = timeIn[2];
		minStr[1] = timeIn[3];
		minStr[2] = '\0';

	} else {
		if (timeIn[2] != ':') {
			printf("Missing ':' in time specification\n");
			return((LONG)-1L);
		}
		hourStr[0] = timeIn[0];
		hourStr[1] = timeIn[1];
		hourStr[2] = '\0';
		minStr[0] = timeIn[3];
		minStr[1] = timeIn[4];
		minStr[2] = '\0';
	}

	hour = atoi(hourStr);
	min = atoi(minStr);

	if ((hour > 23) || (min > 59)) {
		printf("Hour must be 0-23 and minutes must be 0-59\n");
		return((LONG)-1L);
	}
	timeInSec = time(NULL);
	currentTime = localtime(&timeInSec);

	if ((*currentTime).tm_hour > hour)
		hour = 24 - (*currentTime).tm_hour + hour;
	else
		hour = hour - (*currentTime).tm_hour;

	nSec = 3600 * hour;

	nSec = nSec + (60 * min);
	nSec = nSec - (60 * (*currentTime).tm_min);

	SecondsToTicks(nSec, 0L, &nTicks);
	return(nTicks);
}

void WakeUp(void)
{
	int	ccode;

	ccode = ResumeThread(myThreadID);
	if (ccode != ESUCCESS)
		ConsolePrintf("DOWNSERV: ResumeThread failed, ccode = %d\r\n", ccode);
}

void ExitProcedure(void)
{
	CancelSleepAESProcessEvent(&ClockEvent);
	CancelSleepAESProcessEvent(&WarningEvent1);
	CancelSleepAESProcessEvent(&WarningEvent2);
	CancelSleepAESProcessEvent(&ShutdownEvent);
}

void SetTimeRemaining(void)
{
	if (timeRemaining == -1)
		timeRemaining = TIME_FOR_FIRST_WARNING;
	else if (timeRemaining == TIME_FOR_FIRST_WARNING - 1)
		timeRemaining = TIME_FOR_SECOND_WARNING;
	else
		timeRemaining = 0;
}

void SetShutdownFlag(void)
{
	shutdownTime = TRUE;
}

void WarnUsers(void)
{
	int	ccode;
	char	serverName[49];
	char	buffer[80];

	GetFileServerName(0, serverName);
	sprintf(buffer, "%s shutting down in %d min",
							serverName, timeRemaining);
 	ConsolePrintf("DOWNSERV NLM: Server shutdown in %d minutes\n", timeRemaining);

	gotoxy(20,15);
	if (timeRemaining == TIME_FOR_FIRST_WARNING)
		printf("STATUS:  Broadcasting first server shutdown warning");
	else if (timeRemaining == TIME_FOR_SECOND_WARNING)
		printf("STATUS:  Broadcasting second server shutdown warning");

	/* Send warning to all connected stations */
	ccode = SendConsoleBroadcast(buffer, 0, (WORD *)NULL);
	if (ccode != ESUCCESS) {
		gotoxy(20,15);
		printf("STATUS:  Unable to notify connections of server shutdown. ccode = %x\n", ccode);
	}

	timeRemaining--;
}

void ShutdownServer(void)
{
	char	serverName[49];
	char	buffer[80];
	int	ccode;
	LONG	oneMinInTicks;

	/* Clear old status messages, if any */
	gotoxy(20,15);
	printf("\n\n");

	/* Do not force server to shut down if files are open */
	if (firstTry) {
		ccode = DownFileServer(0);
		firstTry = FALSE;

		if (ccode == ESUCCESS)
			exit(0);
		else {
			shutdownTime = FALSE;

			gotoxy(20,15);
			printf("STATUS:  Files open--can't shut down.  ccode = %x.  Force shutdown in 1 minute.\n", ccode);

			SecondsToTicks(60L, 0L, &oneMinInTicks);

			/* Reset time in AESProcessStructure for shutdown procedure */
			ShutdownEvent.AWakeUpDelayAmount = oneMinInTicks;

			/* Reschedule shutdown */
			ScheduleSleepAESProcessEvent(&ShutdownEvent);

			/* Send warning to all connected stations */
			sprintf(buffer, "%s shutting down. Logout now.", serverName);
			ccode = SendConsoleBroadcast(buffer, 0, (WORD *)NULL);
			if (ccode != ESUCCESS)
				printf("Unable to notify connections of server shutdown. ccode = %x\n", ccode);
		}

	} else {
		ccode = DownFileServer(1);
		if (ccode == ESUCCESS)
			exit(0);
		else {
			gotoxy(20,15);
			printf("STATUS:  Unable to shut down.  ccode = %xh.\n", ccode);
		}
	}
}

