/**********************************************************************
 * Copyright (c) 2005, 2006 IBM Corporation and Intel Corporation.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: InstService.c,v 1.4 2006/05/12 00:46:46 akaylor Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 * Vishnu K Naikawadi, Intel - Brought over the code from old RAC
 **********************************************************************/

#ifdef _WIN32     // Windows-specific

#include <windows.h>
#include <windowsx.h>
#include <stdio.h>

#define BUFFER_SIZE 1024

void trimQuotesAndSpaces(char* str);

int createRegistryKey(PHKEY key) {
    long result;
    DWORD disp;

    /* Create the key if nessessary */
	result=RegCreateKeyEx(HKEY_LOCAL_MACHINE,                       /* Parent key */
                          "SOFTWARE\\Eclipse\\TPTP\\ACService",		/* Subkey to create */ 
                          0,                                        /* Reserved */
                          NULL,                                     /* Class (ignored locally) */
                          REG_OPTION_NON_VOLATILE,
                          KEY_ALL_ACCESS,                           /* Open for any type of maniplation */
                          NULL,
                          key,
                          &disp);

	if(result != ERROR_SUCCESS) {
		return -1;
	}

    return 0;
}


int deleteRegistryKey() {
    LONG result=RegDeleteKey(HKEY_LOCAL_MACHINE,
                             "SOFTWARE\\Eclipse\\TPTP\\ACService");		/* Subkey to delete */ 

    if(result!=ERROR_SUCCESS) {
        return -1;
    }
    return 0;
}

int createSubKey(PHKEY key, LPSTR name, LPSTR value) {
    LONG result;
    result=RegSetValueEx(*key,
                         name,
                         0,
                         REG_SZ,
                         value,
                         strlen(value)+1);

    if(result!=ERROR_SUCCESS) {

    }
    return 0;
}


int deleteSubKey(PHKEY key, LPSTR name) {
    LONG result;

    result=RegDeleteValue(*key,
                          name);

    if(result!=ERROR_SUCCESS) {

    }
    return 0;
}

int findSubkey(PHKEY key, LPSTR name) {
    LONG result;
    char nameBuffer[BUFFER_SIZE];

    int i=0;
    while(TRUE) {
        DWORD size=BUFFER_SIZE;
        FILETIME lastWrite;
        result=RegEnumKeyEx(*key,
                            i,
                            nameBuffer,
                            &size,
                            NULL,
                            NULL,
                            NULL,
                            &lastWrite);

        if(result!=ERROR_SUCCESS) {
            return -1;
        }

        if(!strcmp(name, nameBuffer)) {
            return i;
        }
        i++;
    }
    return -1;
}

int countSubkeys(PHKEY key) {
    LONG result;
    char nameBuffer[BUFFER_SIZE];

    int i=0;
    while(TRUE) {
        DWORD size=BUFFER_SIZE;
        result=RegEnumValue(*key,
                            i,
                            nameBuffer,
                            &size,
                            NULL,
                            NULL,
                            NULL,
                            NULL);

        if(result==ERROR_NO_MORE_ITEMS) {
            return i;
        }
        else if(result!=ERROR_SUCCESS) {
            return -1;
        }
        i++;
    }
    return -1;
}


/**
  * ADD_SERVICE  ***************************************************************
  * Adds the service.  This is done as two steps, first the service is added to
  * the CurrentControlSet.  Second, we place an entry in our registry key to 
  * indicate what the service name is corresponding to specified path.
  */
LONG APIENTRY addService(LPSTR lpszPath, LPSTR lpszName) {
	SC_HANDLE hServiceManager, hNewService;
	DWORD error;
	char error_buffer[128];
    HKEY registryKey;
    char finalPath[256];


	/* Calculate the final path of the executable */
	strcpy(finalPath, lpszPath);
	strcat(finalPath, "\\bin\\ACWinService.exe");

	/* Get a handle to the Service Control Manager */
	hServiceManager=OpenSCManager(
					NULL,		// The service control manager on the local machine
					SERVICES_ACTIVE_DATABASE,
					SC_MANAGER_CREATE_SERVICE);

	/* Install the service */
	hNewService=CreateService(hServiceManager,
				  lpszName,
				  lpszName,
				  SERVICE_ALL_ACCESS ,
				  SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS ,
				  SERVICE_AUTO_START,	// Auto start at login time
				  //SERVICE_DEMAND_START,
				  SERVICE_ERROR_NORMAL,	// error level logged if the service does not start
				  finalPath,
				  NULL,					// No load order group
				  NULL,					// No dependancies
				  NULL,
				  NULL,					// use the system account
				  NULL);				// the password

	/* Was the install successful? */
	if(hNewService==0) {
		error=GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
					  NULL,
					  error,
					  0,
					  error_buffer,
					  128,
					  NULL);
		CloseServiceHandle(hServiceManager);
		return FALSE;
		
	}

	/* Clean up resources */
	CloseServiceHandle(hServiceManager);
	CloseServiceHandle(hNewService);

    /* Ensure the regoistry contains our key */
    createRegistryKey(&registryKey);

    /* Create/Update our subkey */
    createSubKey(&registryKey, lpszName, lpszPath);

    /* Close the registry key */
    RegCloseKey(registryKey);

	return TRUE;

}


/**
  * REMOVE SERVICE  ************************************************************
  * Removes the specified service from the registry.  This is done as two parts.
  * First, the service is removed from the CurrentControlSet.  Second, we remove
  * the database information from our well know registry key, even removing the
  * key itself if this is the last entry.
  */
LONG APIENTRY removeService(LPSTR lpszName) {
	SC_HANDLE hServiceManager, hService;
	DWORD error;
	char error_buffer[128];
    HKEY registryKey;
    SERVICE_STATUS status;

	/* Get a handle to the Service Control Manager */
	hServiceManager=OpenSCManager(
					NULL,		// The service controll manager on the local machine
					SERVICES_ACTIVE_DATABASE,
					SC_MANAGER_ALL_ACCESS);

	/* Find the service */
	hService=OpenService(hServiceManager, lpszName, DELETE | SERVICE_STOP); /* 9774 */

	/* Was the service opened successfully? */
	if(hService==0) {
		error=GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
					  NULL,
					  error,
					  0,
					  error_buffer,
					  128,
					  NULL);
		CloseServiceHandle(hServiceManager);
		return FALSE;
		
	}

    /* Ensure the service is stopped */
    ControlService(hService, SERVICE_CONTROL_STOP, &status);


	/* Uninstall the service */
	if(!DeleteService(hService)) {
		CloseServiceHandle(hServiceManager);
		return FALSE;
	}


	/* Clean up resources */
	CloseServiceHandle(hServiceManager);
	CloseServiceHandle(hService);

    /* Ensure the regoistry contains our key */
    createRegistryKey(&registryKey);

    /* Delete our subkey */
    deleteSubKey(&registryKey, lpszName);

    /* If the key is empty, remove the entire key */
    if(countSubkeys(&registryKey)==0) {
        deleteRegistryKey();
    }

    /* Close the registry key */
    RegCloseKey(registryKey);

	return TRUE;

}

/**
  * PRINT_USAGE  ***************************************************************
  * Prints the proper invocation usage of the application.
  */
void printUsage() {
		printf("Usage:\n");
		printf("\t\tTo add the service:  manageservice  add <service name> <install path>\n");
		printf("\t\tTo remove the service:  manageservice  remove <service name>\n");
}


/**
 * TRIM TRAILING SPACES AND SLASHES
 *
*/
void trimQuotesAndSpaces(char* str) {
	int i;

	for(i = strlen(str) - 1; i > 0; i--) {
		/* 70353 - remove trailing quotes */
		if((str[i] == '\\') || (str[i] == ' ') || (str[i] == '\"') || (str[i] == '\'')) { /* remove any trailing spaces and slashes */
			str[i] = '\0'; /* null it */
		}
		else {
			break;
		}
	}
}


/**
  * MAIN  **********************************************************************
  * This is the entry point for this executable.  We will check the command line
  * to determine we are being invoked correctly.  We will then proceed to either 
  * add a service or remove an existing one depending upon the command line 
  * arguments.
  */
int main(int argc, char **argv) {

	if(argc<3) {
		printUsage();
		return -1;
	}

	if(!strcmp(argv[1], "add")) {
		if(argc!=4) {
			printUsage();
			return -1;
		}
		else {
			trimQuotesAndSpaces(argv[2]);
			trimQuotesAndSpaces(argv[3]);
			addService(argv[3], argv[2]);
		}
	}
	else if(!strcmp(argv[1], "remove")) {
		if(argc!=3) {
			printUsage();
			return -1;
		}
		trimQuotesAndSpaces(argv[2]);
		removeService(argv[2]);
	}

	return -1;
}


#endif // Windows Specific