#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <winnt.h>
#endif
#include "svclib.h"

int emsg(const char * arg_list, ...);

static int not_service;
//#include "emsg.h"
int main_setexit(void);
#define SVC_NAME "notused"
#ifndef WIN32
void svc_delay_running(int state)
{
}
void svc_running(void)
{
}
void svc_exiting(void)
{
}
void svc_exit(void)
{
}
void svc_init(char *sname)
{
}

#else
void svc_exiting(void);
void svc_exit(void);
void svc_handler(DWORD msg);

static SERVICE_STATUS_HANDLE ssh;
void svc_report(int status)
{
	static int cp;
	/*static int stop_pending;*/
	static SERVICE_STATUS ss;
	
	ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	ss.dwCurrentState = status;	 
	ss.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;
	ss.dwWin32ExitCode = NO_ERROR;
	ss.dwServiceSpecificExitCode = 0;
	ss.dwWaitHint = 0;
	ss.dwCheckPoint = 0;
	
	if ((status==SERVICE_STOP_PENDING) || (status==SERVICE_START_PENDING)) {
		ss.dwWaitHint = 300;
		ss.dwCheckPoint = cp++;
	}
	if ((status==SERVICE_STOP_PENDING)) {
		ss.dwWaitHint = 100;
		ss.dwCheckPoint = cp++;
	}

	if (ssh!=0) SetServiceStatus(ssh,&ss);
}

VOID svc_handler(DWORD msg)
{
	/*static int cp;*/
	/*static int stop_pending;*/
	int mde = SERVICE_RUNNING;	

	switch (msg) {
		case SERVICE_CONTROL_PAUSE:
		case SERVICE_CONTROL_CONTINUE:
		case SERVICE_CONTROL_INTERROGATE:
			break;
		case SERVICE_CONTROL_SHUTDOWN:
		case SERVICE_CONTROL_STOP:
			mde = SERVICE_STOP_PENDING;
			break;
	}
	svc_report(mde);
	if (mde==SERVICE_STOP_PENDING) {
		main_setexit();
#ifdef WIN32
		WSACancelBlockingCall(); /* To kill any lookups that are holding it up */ 
#endif
	}
}

VOID svc_exiting(void)
{
	svc_report(SERVICE_STOP_PENDING);
}
VOID svc_exit(void)
{
	svc_report(SERVICE_STOPPED);
}
VOID ServiceMain(DWORD  argc, LPTSTR  *argv)
{
	svc_main(argc,argv);
}

static char xname[200];
int main(int argc, char *argv[])
{
	static SERVICE_TABLE_ENTRY stable[3];
	/*int isslave = FALSE;*/


	if (argc>0) strcpy(xname,argv[0]);
	stable[0].lpServiceName = SVC_NAME;
	stable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION) ServiceMain;
	stable[1].lpServiceName = NULL;
	stable[1].lpServiceProc = NULL;

	if (argc>1 || (strstr(xname,"install.exe")!=NULL)) {
		not_service = TRUE;
		svc_main(argc,argv);
		return 0;
        }
	if (!StartServiceCtrlDispatcher(stable)) {
//		printf("StartServiceCtrlDispatcher failed - use -test to run on command line %d\n",GetLastError());
		if (argc<2) FreeConsole();
		svc_main(argc,argv);
	} 
	svc_exit();
	return 0;
}
static int s_d_r = FALSE;
void svc_delay_running(int state)
{
	s_d_r = state;
}
void svc_init(char *sname)
{
	DWORD r;

	if (not_service) return;
	ssh = RegisterServiceCtrlHandler(sname,(LPHANDLER_FUNCTION)	svc_handler);
	if (ssh==0) {
		r = GetLastError();
		if (r==ERROR_INVALID_NAME) emsg("svc: Invalid name");
		else if (r==ERROR_SERVICE_DOES_NOT_EXIST) emsg("svc: Service doesn't exist");
		else emsg("svc: Not running as a service\n");
	}
	svc_report(SERVICE_START_PENDING);
	if (s_d_r == FALSE) svc_report(SERVICE_RUNNING);
}
void svc_running(void)
{
	svc_report(SERVICE_RUNNING);
}

char *svc_getargs(char *svcname)
{
	char key[400];
	static char val[400];
	int r;

	DWORD valtype;
	DWORD vallen=300;
	HKEY skey;
	DWORD reserved=0;
	REGSAM sam;

	sprintf(key,"System\\CurrentControlSet\\Services\\%s",svcname);
	/* r = RegOpenKey(HKEY_LOCAL_MACHINE,key,&skey);*/
	sam = KEY_READ;
	r = RegOpenKeyEx(HKEY_LOCAL_MACHINE,key,reserved,sam,&skey);
	if (r!=ERROR_SUCCESS) emsg("failure: RegOpenKey %d(0x%02x)\n", r,GetLastError());
	r = RegQueryValueEx(skey,"DisplayName",NULL,&valtype,(unsigned char *)val,&vallen);
	if (r!=ERROR_SUCCESS) emsg("failure: RegQueryKey %d(0x%02x)\n", r,GetLastError());
	val[vallen] = 0;
	return val;
}
#ifndef iseol
#	define iseol(x) (x == '\r' || x == '\n' || x == '\0')
#endif
char *svc_system_error(int ecode, char *bf, int bfsz) {
	if (bf) {
		int r;

		*bf = '\0';
#ifdef WIN32
		r = FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM,
			NULL,
			ecode,
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			(LPTSTR) bf,
			bfsz,
			NULL);
		for(; r != 0 && iseol(bf[r]); r--) bf[r] = '\0';
#else
		ncpy(bf,strerror(ecode),bfsz-1);
#endif
	}
	return bf;
}
char *svc_getpath(char *svcname)
{
	char key[400];
	static char val[400];
	int r;
	char tmp[1000];
	int e;

	DWORD valtype;
	DWORD vallen=300;
	HKEY skey;
	DWORD reserved=0;
	REGSAM sam;

	strcpy(val,""); 
	sprintf(key,"System\\CurrentControlSet\\Services\\%s",svcname);
	sam = KEY_READ;
	r = RegOpenKeyEx(HKEY_LOCAL_MACHINE,key,reserved,sam,&skey);
	if (r!=ERROR_SUCCESS) emsg("failure: RegOpenKey %d(0x%02x)\n", r,GetLastError());
	r = RegQueryValueEx(skey,"ImagePath",NULL,&valtype,(unsigned char *)val,&vallen);
	e = GetLastError();
	if (r!=ERROR_SUCCESS) emsg("failure: RegQueryKey %d(0x%02x) %s\n", r,e,svc_system_error(r,tmp,300));
	val[vallen] = 0;
	return val;
}

#endif
