#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#ifdef WIN32
#include <windows.h>
#endif
#define DMID 16
#include "debug.h"
int emsg(const char * arg_list, ...);

//#include "emsg.h"
//---------------------------------------------------------------------------
#ifndef WIN32
void svc_add(char *name, char *fname, char *desc)
{
}

int svc_start(char *name, char *reason)
{
	return 1;
}

int svc_stop(char *name)
{
	return 1;
}

int svc_del(char *name)
{
	return 1;
}

int svc_disable_autostart(char *name) {
	return 1;
}
int svc_enable_autostart(char *name) {
	return 1;
}
#else
char *winmsg(int i);
int  svc_add(char *name, char *fname, char *desc, char *reason)
{
	static	SC_HANDLE sc,sc2;

	int r;
	char sysdir[MAX_PATH];
	char binpath[MAX_PATH];

	sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (sc==NULL) { sprintf(reason,"Open scmanager failed\n"); return FALSE;}
	GetSystemDirectory((LPSTR) sysdir,MAX_PATH);
	if (strchr(fname,'\\')!=NULL) strncpy(binpath,fname,MAX_PATH-1);
	else sprintf(binpath,"%s\\%s",sysdir,fname);
	binpath[MAX_PATH - 1] = 0;

	sc2 = CreateService(
    	sc, // handle of service control manager database
    	(LPCSTR) name,	// address of name of service to start
    	(LPCSTR) desc,	// address of display name
		SERVICE_ALL_ACCESS,	// type of access to service
		SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,	// type of service
		SERVICE_AUTO_START,			// when to start service
    	SERVICE_ERROR_NORMAL, 		// severity if service fails to start
		(LPCSTR) binpath,	// address of name of binary file
		"",		// address of name of load ordering group
		NULL,		// address of variable to get tag identifier
    	NULL,// address of array of dependency names
    	NULL,// address of account name of service
    	NULL 	// address of password for service account
   );




#define err(x,y) if (r==x) strcat(reason,y)
   if (sc2==NULL) {
   		sprintf(reason,"Creation of service failed \n");
	 	r = GetLastError();
		err(ERROR_ACCESS_DENIED,"Access Denied\n");
		err(ERROR_CIRCULAR_DEPENDENCY,"Cicular dependency\n");
		err(ERROR_DUP_NAME,"Dup Name\n");
		err(ERROR_INVALID_HANDLE,"Invalid handle \n");
		err(ERROR_INVALID_NAME,"Invalid name\n");
		err(ERROR_INVALID_PARAMETER,"Invalid Parameter\n");
		err(ERROR_INVALID_SERVICE_ACCOUNT,"Invalid service\n");
		err(ERROR_SERVICE_EXISTS,"Service exists\n");
	} else {
    		CloseServiceHandle(sc2);
	}
	CloseServiceHandle(sc);
	return  TRUE;
}
// Non interactive service
int  svc_add2(char *name, char *fname, char *desc, char *reason)
{
	static	SC_HANDLE sc,sc2;

	int r;
	char sysdir[MAX_PATH];
	char binpath[MAX_PATH];

	sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (sc==NULL) { sprintf(reason,"Open scmanager failed\n"); return FALSE;}
	GetSystemDirectory((LPSTR) sysdir,MAX_PATH);
	if (strchr(fname,'\\')!=NULL) strncpy(binpath,fname,MAX_PATH-1);
	else sprintf(binpath,"%s\\%s",sysdir,fname);
	binpath[MAX_PATH - 1] = 0;

	sc2 = CreateService(
    	sc, // handle of service control manager database
    	(LPCSTR) name,	// address of name of service to start
    	(LPCSTR) desc,	// address of display name
		SERVICE_ALL_ACCESS,	// type of access to service
		SERVICE_WIN32_OWN_PROCESS,	// type of service
		SERVICE_AUTO_START,			// when to start service
    	SERVICE_ERROR_NORMAL, 		// severity if service fails to start
		(LPCSTR) binpath,	// address of name of binary file
		"",		// address of name of load ordering group
		NULL,		// address of variable to get tag identifier
    	NULL,// address of array of dependency names
    	NULL,// address of account name of service
    	NULL 	// address of password for service account
   );

#define err(x,y) if (r==x) strcat(reason,y)
   if (sc2==NULL) {
   		sprintf(reason,"Creation of service failed \n");
	 	r = GetLastError();
		err(ERROR_ACCESS_DENIED,"Access Denied\n");
		err(ERROR_CIRCULAR_DEPENDENCY,"Cicular dependency\n");
		err(ERROR_DUP_NAME,"Dup Name\n");
		err(ERROR_INVALID_HANDLE,"Invalid handle \n");
		err(ERROR_INVALID_NAME,"Invalid name\n");
		err(ERROR_INVALID_PARAMETER,"Invalid Parameter\n");
		err(ERROR_INVALID_SERVICE_ACCOUNT,"Invalid service\n");
		err(ERROR_SERVICE_EXISTS,"Service exists\n");
	} else {
    		CloseServiceHandle(sc2);
	}
	CloseServiceHandle(sc);
	return  TRUE;
}
int svc_start(char *name, char *reason)
{
 int ret;
 int e;
 static  SC_HANDLE sc,sc2;

 sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
 if (sc==NULL) { sprintf(reason,"Open scmanager failed, probably not running NT\n"); 	return FALSE; }
 sc2 = OpenService(sc, name, SERVICE_ALL_ACCESS);
 if (sc2 == NULL) {
    e = GetLastError();
    if (e==ERROR_ACCESS_DENIED) sprintf(reason,"Could not start %s service, access denied\n",name);
    else if (e==ERROR_SERVICE_DOES_NOT_EXIST) sprintf(reason,"The %s service does not exist locally, cannot start it\n",name);
    else sprintf(reason,"OpenService %s (%s) %s\n",name, winmsg(GetLastError()),winmsg(e));
	return FALSE;
 }
 ret = StartService(sc2,0,NULL);
 CloseServiceHandle(sc2);
 CloseServiceHandle(sc);
 if (ret){
    		return TRUE;
 } else {
        if (GetLastError()==ERROR_SERVICE_ALREADY_RUNNING) sprintf(reason,"The %s service is running already\n",name);
        else sprintf(reason,"StartService %s %s\n", name, winmsg(GetLastError()));
 }
 return ret;
}
int svc_stop(char *name)
{
	int ret;
	int e;
	static  SC_HANDLE sc,sc2;
	SERVICE_STATUS svcstat;
	time_t timeout_start;

	sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (sc==NULL) { emsg("Open scmanager failed, probably not running NT\n"); 	return FALSE; }
	sc2 = OpenService(sc, name, SERVICE_ALL_ACCESS);
	if (sc2 == NULL) {
		e = GetLastError();
		if (e==ERROR_ACCESS_DENIED) emsg("Could not start %s service, access denied\n",name);
		else if (e==ERROR_SERVICE_DOES_NOT_EXIST) emsg("The %s service does not exist locally, cannot stop it\n",name);
		else emsg("failure: OpenService %s (%d)\n",name, GetLastError());
		return FALSE;
	}

	ret = ControlService(sc2,SERVICE_CONTROL_STOP,&svcstat);
	if (ret) {
		if (svcstat.dwCurrentState==SERVICE_STOP_PENDING) ;
		timeout_start = time(NULL);
		while (TRUE)
		{
			if ((time(NULL) - timeout_start)>=60) {/*timeout after a minute */ emsg("svc: service stop error : stop timed out\n"); ret = FALSE; break; }
			if (!ControlService(sc2,SERVICE_CONTROL_STOP,&svcstat))
			{
				if (GetLastError()==ERROR_SERVICE_NOT_ACTIVE) { 
					/* service is no longer running */ ret = TRUE; 
					break; 
				}
				if (GetLastError()!=ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
				{
					emsg("svc: service stop error : (%d)%s\n",GetLastError(),winmsg(GetLastError())); ret = FALSE; break;
				}
			}
			else
				emsg("svc: service stop error : controlservice call didn't fail\n");
			/* service still stopping so wait a bit longer */
			Sleep(500);
		}
	}
	else {
		if (GetLastError()!=ERROR_SERVICE_NOT_ACTIVE)
		{
			emsg("svc: service stop error : (%d)%s\n",GetLastError(),winmsg(GetLastError()));
			ret = FALSE;
		}
	}
	CloseServiceHandle(sc2);
	CloseServiceHandle(sc);
	if (ret){
		return TRUE;
	} else {
		emsg("failure: StopService %s failed (%d)%s\n", name, GetLastError(),winmsg(GetLastError()));
	}
	return ret;
}

char *winmsg(int i)
{
	static char bf[1000];
	LPVOID lpMsgBuf;
	char *s;
	FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
		, NULL
		,i
		, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
		, (LPTSTR) &lpMsgBuf, 0, NULL);

	strncpy(bf,(char *)lpMsgBuf,100); bf[100] = 0;
	LocalFree(lpMsgBuf);
	s = strchr(bf,'\n'); 	if (s!=NULL) *s = 0;
	s = strchr(bf,'\r'); 	if (s!=NULL) *s = 0;
	return bf;
}


int svc_del(char *name)
{
	int ret;
	static  SC_HANDLE sc,sc2;
	
#define mmsg printf

	sc = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (sc==NULL) { mmsg("Open scmanager failed, probably not running NT\n"); 	return FALSE; }
    sc2 = OpenService(sc, name, SERVICE_ALL_ACCESS);
    if (sc2 == NULL) {
        mmsg("failure: OpenService (%s) (%d)\n", name,GetLastError());
        return FALSE;
    }
    ret = DeleteService(sc2);
	CloseServiceHandle(sc2);

    if (ret)
        ;
    else
        mmsg("failure: DeleteService (%d)\n", GetLastError());
 CloseServiceHandle(sc);
 if (ret){
	 mmsg("Deleted it ok (%s)\n",name);
       		return TRUE;
 } else {
        mmsg("failure : svc_del (%d)%s\n",GetLastError(),winmsg(GetLastError()));
 }
 return ret;
}

int svc_disable_autostart(char *name) {
	static SC_HANDLE SCMan,Service;
	int r;

	SCMan = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (SCMan==NULL) {
		emsg("Open scmanager failed, probably not running NT\n");
		return FALSE;
	}
	Service = OpenService(SCMan,name,SERVICE_ALL_ACCESS);
    if (Service == NULL) {
        emsg("failure: OpenService (%d)\n", GetLastError());
        return FALSE;
    }
	r = ChangeServiceConfig(
		Service,
		SERVICE_NO_CHANGE,
		SERVICE_DEMAND_START,
		SERVICE_NO_CHANGE,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		name
	);
	CloseServiceHandle(Service);
	CloseServiceHandle(SCMan);
	if (r == 0) {
		emsg("failure: ChangeServiceConfig (%d)\n", GetLastError());
		return FALSE;
	}
	return TRUE;
}

int svc_enable_autostart(char *name) {
	static SC_HANDLE SCMan,Service;
	int r;

	SCMan = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
	if (SCMan==NULL) {
		emsg("Open scmanager failed, probably not running NT\n");
		return FALSE;
	}
	Service = OpenService(SCMan,name,SERVICE_ALL_ACCESS);
    if (Service == NULL) {
        emsg("failure: OpenService (%d)\n", GetLastError());
        return FALSE;
    }
	r = ChangeServiceConfig(
		Service,
		SERVICE_NO_CHANGE,
		SERVICE_AUTO_START,
		SERVICE_NO_CHANGE,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		NULL,
		name
	);
	CloseServiceHandle(Service);
	CloseServiceHandle(SCMan);
	if (r == 0) {
		emsg("failure: ChangeServiceConfig (%d)\n", GetLastError());
		return FALSE;
	}
	return TRUE;
}
#endif

