/
bin/95/
docs/DM/
docs/creatures/
docs/objects/
docs/rooms/
docs/utils/
help/
log/
objmon/ddesc/
player/
post/
rooms/
util/
util/fing/
util/italk/
util/lev-reset/
util/lib/
util/list/
util/msg/
util/tdel/
util/vote/
util/wtfix/
/*
 * MAIN.C:
 *
 *	This files contains the main() function which initiates the
 *	game.
 *
 *	Copyright (C) 1991, 1992, 1993, 1997 Brooke Paul & Brett Vickers
 *
 */
#ifdef WINNT_SERVICE
  #include <windows.h>
  #include <stdio.h>
#endif

#include "mstruct.h"
#include "mextern.h"
#include "version.h"
#include <time.h>
#include <signal.h>
#ifdef DMALLOC
  #include "/usr/local/include/dmalloc.h"
#endif

#ifdef WINNT_SERVICE
  SERVICE_STATUS_HANDLE serviceStatusHandle;

  extern HandleError(char *, int); 
  void ServiceMain(double argc, LPSTR argv);
  void ServiceCtrlHandler (double controlCode);
  int UpdateSCMStatus (double dwCurrentState, double dwWin32ExitCode,
		       double dwServiceSpecificExitCode, double dwCheckPoint,
		       double dwWaitHint);
  void KillService(void);
  void terminateService(int); 

  HANDLE killServiceEvent;
  double serviceCurrentStatus;
  double serviceRunning;
  HANDLE threadHandle;
  double servicePaused;

#endif

#define SCHEDPORT  4040

int Port; 
char report =0;
long last_dust_output;

#ifdef WINNT_SERVICE
	void MORDORMain(void)
#else
	main(argc,argv)
	int	argc;
	char	*argv[];
#endif
{
	int i;
	static void mvc_log();
	static int schedule_g();

	i=readini();
	Port = PORTNUM;

	if(CRASHTRAP){
		signal(SIGABRT, crash);	/* abnormal termination triggered by abort call */
		signal(SIGFPE, crash);	/* floating point exception */
		signal(SIGILL, crash);	/* illegal instruction - invalid function image */
		signal(SIGSEGV, crash);	/* segment violation */
	}

	for(i=0; i<PMAX; i++) Spy[i] = -1;

	if(SCHED)
#ifndef WINNT_SERVICE
		if(argc == 1)
#endif
			Port = schedule_g();
	
#ifndef DEBUG
#ifndef WIN32
	if(fork()) exit(0);		/* go into background */
#endif
	close(0); close(1); close(2);	/* close stdio */
#endif

#ifndef WINNT_SERVICE
/* Doneval: BUG isnumber gave me problems with my FreeBSD, only subtitute */
/* the name, is_num */
	if (argc == 2)
#ifdef FREEBSD
		if(is_num(argv[1]))
#else
		if(isnumber(argv[1]))
#endif
			Port = atoi(argv[1]);
	    else if (!strcmp(argv[1],"-r"))
				report = 1;

	if (argc == 3){
#ifdef FREEBSD
		if(is_num(argv[1]))
#else
		if(isnumber(argv[1]))
#endif
			Port = atoi(argv[1]);
	    else if (!strcmp(argv[1],"-r"))
                report = 1;
#ifdef FREEBSD
		if(is_num(argv[2]))
#else
		if(isnumber(argv[2]))
#endif
			Port = atoi(argv[2]);
	    else if (!strcmp(argv[2],"-r"))
                report = 1;
	}
#endif /* not WINNT_SERVICE */

if(AUTOSHUTDOWN)
	if (!Shutdown.interval){
	    Shutdown.ltime = time(0);
	    Shutdown.interval = 43200L;
	}


	umask(000);
	srand(getpid() + time(0));
	load_lockouts();

#ifndef DEBUG
 	sock_init(Port,0);
#else
 	sock_init(Port,1);
#endif

	if(RECORD_ALL) mvc_log();
	
	{
	 long c;
	 c = time(0);
	StartTime = time(0);
	loge("--- Game Up: %d --- (%.24s) [%s]\n", Port, ctime(&c), VERSION);
	}

	sock_loop();
	return(0);
}

#ifdef WINNT_SERVICE

char *pcServiceName = "MudServices";

void main(void)
{
  SERVICE_TABLE_ENTRY serviceTable[] =
  {
    {pcServiceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
    {NULL, NULL}
  };
  int bSuccess;

  bSuccess = StartServiceCtrlDispatcher(serviceTable);
  if (!bSuccess)
    HandleError("StartServiceCtrlDispatcher failed!", GetLastError());
}  

void ServiceMain(double argc, LPSTR argv)
{
  int bSuccess;

  serviceStatusHandle = RegisterServiceCtrlHandler(pcServiceName,
    (LPHANDLER_FUNCTION) ServiceCtrlHandler);

  if (!serviceStatusHandle)
  {
    terminateService(GetLastError()); 
    return;
  }
  bSuccess = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 1, 5000);

  if (!bSuccess)
  {
    terminateService(GetLastError());
    return;
  }
  killServiceEvent = CreateEvent(0, 1, 0, 0);
  if (!killServiceEvent)
  {
    terminateService(GetLastError());
    return;
  }
  bSuccess = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000);
  if (!bSuccess)
  {
    terminateService(GetLastError());
    return;
  }
  
  if (argc == 2)
    if(isnumber(argv[1]))
      Port = atoi(argv[1]);
    else
      if (!strcmp(argv[1],"-r"))
	report = 1;
  if (argc == 3)
  {
    if(isnumber(argv[1]))
      Port = atoi(argv[1]);
    else 
      if (!strcmp(argv[1],"-r"))
	report = 1;
    if(isnumber(argv[2]))
      Port = atoi(argv[2]);
    else if (!strcmp(argv[2],"-r"))
      report = 1;
  }
  bSuccess = UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0, 3, 5000);
  if (!bSuccess)
  {
    terminateService(GetLastError());
    return;
  }
  bSuccess = StartServiceThread();
  if (!bSuccess)
  {
    terminateService(GetLastError());
    return;
  }
  serviceCurrentStatus = SERVICE_RUNNING;
  bSuccess = UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
  if (!bSuccess)
  {
    terminateService(GetLastError());
    return;
  }
  WaitForSingleObject(killServiceEvent, INFINITE);
  terminateService(0);
}

DWORD ServiceExecutionThread(LPDWORD param)
{
  while (serviceRunning)
  {
    MORDORMain();
  }
  return 0;
}

BOOL StartServiceThread()
{
  DWORD id;
 
  threadHandle = CreateThread(0, 0,
		   (LPTHREAD_START_ROUTINE) ServiceExecutionThread,
		   0, 0, &id);
  if (threadHandle == 0)
    return 0;
  else
  {
    serviceRunning = 1;
    return 1;
  }
}

int UpdateSCMStatus (double dwCurrentState, double dwWin32ExitCode,
		     double dwServiceSpecificExitCode, double dwCheckPoint,
		     double dwWaitHint)
{
  int bSuccess;
  SERVICE_STATUS serviceStatus;

  serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  serviceStatus.dwCurrentState = dwCurrentState;
  if (dwCurrentState == SERVICE_START_PENDING)
    serviceStatus.dwControlsAccepted = 0;
  else
    serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
				       SERVICE_ACCEPT_PAUSE_CONTINUE |
				       SERVICE_ACCEPT_SHUTDOWN;
  if (dwServiceSpecificExitCode == 0)
    serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
  else
    serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
  serviceStatus.dwCheckPoint = dwCheckPoint;
  serviceStatus.dwWaitHint = dwWaitHint;
  bSuccess = SetServiceStatus(serviceStatusHandle, &serviceStatus);
  if (!bSuccess)
    KillService();
  return bSuccess;
}

void ServiceCtrlHandler (DWORD controlCode)
{
  int bSuccess;
  
  switch (controlCode)
  {
    case SERVICE_CONTROL_PAUSE:
      if (serviceRunning && !servicePaused)
      {
	bSuccess = UpdateSCMStatus(SERVICE_PAUSE_PENDING, NO_ERROR, 0, 1, 1000);
	servicePaused = 1;
	SuspendThread(threadHandle);
	serviceCurrentStatus = SERVICE_PAUSED;
      }
      break;
    case SERVICE_CONTROL_CONTINUE:
      if (serviceRunning && servicePaused)
      {
	bSuccess = UpdateSCMStatus(SERVICE_CONTINUE_PENDING, NO_ERROR, 0, 1, 1000);
	servicePaused = 0;
	ResumeThread(threadHandle);
	serviceCurrentStatus = SERVICE_RUNNING;
      }
      break;
    case SERVICE_CONTROL_INTERROGATE:
      break;
    case SERVICE_CONTROL_SHUTDOWN:
    case SERVICE_CONTROL_STOP:
      Shutdown.ltime = time(0);
      Shutdown.interval = 1;
      serviceCurrentStatus = SERVICE_STOP_PENDING;
      bSuccess = UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
      KillService();
      return;
    default:
      break;   
  }
  UpdateSCMStatus(serviceCurrentStatus, NO_ERROR, 0, 0, 0);
}

void KillService(void)
{
  serviceRunning = 0;
  SetEvent(killServiceEvent);
}

void terminateService(int iErr)
{
  printf("Killing service: Err(%d)\n", iErr);
  KillService();
}
#endif

/*================================================================*/

#define DAYSEC 86400L
#define MORNT 27900L
#define MIDSEC(x) (((x->tm_hour)*3600)+((x->tm_min)*60)+(x->tm_sec))

/*================================================================*/
int schedule_g()
/* The schedule_g function keeps the game on a time  schedule */
{
    struct tm   *time_m;
    long	t = 0;
    int		mport = SCHEDPORT, port = PORTNUM; 
    enum {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

    t = time(0);
    time_m = localtime(&t);
    t = 0;

    switch(time_m->tm_wday){
	case Sun:
 		t = DAYSEC - MIDSEC(time_m) + MORNT;
		break;
	case Mon: 
	case Tue: 
	case Wed: 
	case Thu:
		if (time_m->tm_hour >= 18)
			t = MORNT + DAYSEC - MIDSEC(time_m);
		else if (MIDSEC(time_m) < MORNT)
			t =  MORNT - MIDSEC(time_m);
		else{
			t = (18L*3600L) - MIDSEC(time_m);
			port =  SCHEDPORT;
			mport  = PORTNUM;
		}
		break;
	case Fri: 
		if (time_m->tm_hour >= 18)
			t = DAYSEC*3 - MIDSEC(time_m) + MORNT;
		else if (MIDSEC(time_m) < MORNT) 
			t =  MORNT - MIDSEC(time_m);
		else{
			t = (18L*3600L) - MIDSEC(time_m);
			port =  SCHEDPORT;
			mport = PORTNUM;
		}
		break;
	case Sat:
		t = DAYSEC*2 - MIDSEC(time_m) + MORNT;
		break;
		}

	if (!port)
		exit(0);


	if(AUTOSHUTDOWN)
		t = MIN(21600L,t);
	Shutdown.ltime = time(0);
	Shutdown.interval =  t;
	Port = mport;
	return (port);
}

/*================================================================*/
void mvc_log(){
/*  This function renames the list of all command file to include  *
 *  the date.  This is done to preserve the list commands that     *
 *  occured before a crash. */

	long t;
	char *date, mfile[128], rfile[128];
	int i;

	t = time(0);
	date = ctime(&t);

   for(i=0;i<24;i++)
	if(date[i] == ' ')
		date[i] = '_';
   date[24] = 0;
   sprintf(rfile,"%s/%s",LOGPATH,"all_cmd");
   sprintf(mfile,"%s/%s_%s",LOGPATH,"all_cmd",date);
#ifndef WIN32
	link(rfile,mfile);
	unlink(rfile);
#else
	rename( rfile, mfile);
#endif

}