#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../conf/portability.h"
#include "../compat/lib/log.h"


// ---------------------------------------------------------------------------------------
SC_HANDLE schService;
SC_HANDLE bindService;

#define              SZ_NAME_BUF 30
    char    inbuf[40];
    char    outbuf[120];
    char    commonbuf[100];
    DWORD   bytesRead, bytesWritten;
    BOOL    ret, ret2, ret3;
    #define               SZ_SLOT_NAME_BUF 50
    UCHAR   ucSlotNameBuf[SZ_SLOT_NAME_BUF] = "";
    LPTSTR  lpszSlotName = (LPTSTR)&ucSlotNameBuf;
    UCHAR   ucOperation = '\0';
    HANDLE outslot;
    HANDLE inslot;
    char tickbuf[20];
    char commonbuf[100];
    BOOL handles_open = FALSE;



// ---------------------------------------------------------------------------------------

LONG APIENTRY CreateBINDService(HWND hwnd, LPLONG lpIValue, LPSTR serviceexe)
{
  LPCTSTR serviceName = "DomainNameService";
  LPCTSTR lpszBinaryPathName = serviceexe;
  LPTSTR  lpszRootPathName="?:\\";
  HANDLE hSCManager = NULL;

  if ( (':' != *(lpszBinaryPathName+1)) || ('\\' != *(lpszBinaryPathName+2)) )
  {
    return 101;
  }

  #define DRIVE_TYPE_INDETERMINATE 0
  #define ROOT_DIR_DOESNT_EXIST    1

  *lpszRootPathName = *(lpszBinaryPathName+0) ;

  switch (  GetDriveType(lpszRootPathName)  )
  {
    case DRIVE_FIXED :
    { // OK
      break;
    }
    case  ROOT_DIR_DOESNT_EXIST :
    {
      return 101;
    }
    case  DRIVE_TYPE_INDETERMINATE :
    case  DRIVE_REMOVABLE          :
    case  DRIVE_REMOTE             :
    case  DRIVE_CDROM              :
    case  DRIVE_RAMDISK            :
    {
      return 101;
    }
    default :
    {
      return 101;
    }
  }

  if (INVALID_HANDLE_VALUE == CreateFile(lpszBinaryPathName,
                                         GENERIC_READ,
                                         FILE_SHARE_READ,
                                         NULL,
                                         OPEN_EXISTING,
                                         FILE_ATTRIBUTE_NORMAL,
                                         NULL))
  { 
    return 101;
  }
   
	if((hSCManager = OpenSCManager(
			NULL, 
     		NULL,
     		SC_MANAGER_ALL_ACCESS)) == NULL) {
		return 11;
	}

  schService = CreateService(
        hSCManager,                 // SCManager database
        serviceName,                // name of service
        serviceName,                // name to display (new parameter after october beta)
        SERVICE_ALL_ACCESS,         // desired access
        SERVICE_WIN32_OWN_PROCESS,  // service type
        SERVICE_AUTO_START,         // start type
        SERVICE_ERROR_NORMAL,       // error control type
        lpszBinaryPathName,         // service's binary
        NULL,                       // no load ordering group
        NULL,                       // no tag identifier
        NULL,                       // no dependencies
        NULL,                       // Local System account
        NULL);                      // null password

  if (NULL == schService)
  { switch (GetLastError())
    {
      case ERROR_ACCESS_DENIED :
      { 
        CloseServiceHandle(hSCManager);
        return 102;
        break;
      }
      case ERROR_SERVICE_EXISTS :
      {
        CloseServiceHandle(hSCManager);
        return 103;
        break;
      }
      default :
      {
      }
    }
    CloseServiceHandle(hSCManager);
    return 104;
  }
  else

  CloseServiceHandle(schService);
  CloseServiceHandle(hSCManager);

  return 0;
}

// ---------------------------------------------------------------------------------------


LONG APIENTRY RemoveBINDService(HWND hwnd, LPLONG lpIValue, LPSTR serviceName)
  {
    HANDLE hSCManager = NULL;

	if((hSCManager = OpenSCManager(
			NULL, 
     		NULL,
     		SC_MANAGER_ALL_ACCESS)) == NULL) {
		return 11;
	}

    
  bindService = OpenService(hSCManager,serviceName,SERVICE_ALL_ACCESS);
  if (NULL == bindService)
  { switch (GetLastError())
    {
      case ERROR_ACCESS_DENIED :
      { 
             
         CloseServiceHandle(hSCManager);
         return 102;
        break;
      }
      case ERROR_SERVICE_DOES_NOT_EXIST :
      { 
         CloseServiceHandle(hSCManager);
         return 106;
        break;
      }
      default :
       {
           CloseServiceHandle(hSCManager);
           return 105;
      }
    }
  
           CloseServiceHandle(hSCManager);
           return 105;
  }

  if (DeleteService(bindService))
  {
   CloseServiceHandle(bindService);
   CloseServiceHandle(hSCManager);
   return 0;
  }
  else
  { switch (GetLastError())
    {
      case ERROR_ACCESS_DENIED :
      { 
        CloseServiceHandle(bindService);
        CloseServiceHandle(hSCManager);
        return 102;
        break;
      }
      default :
      { 
         CloseServiceHandle(bindService);
         CloseServiceHandle(hSCManager);
         return 105;
      }
    }
   return 105;
  }
  CloseServiceHandle(bindService);
  CloseServiceHandle(hSCManager);
 }


LONG APIENTRY addKeysToRegistry(HWND hwnd, LPLONG lpIValue, LPSTR bs)

{
  HKEY hk;                      /* registry key handle */
  BOOL bSuccess;
  UCHAR   myarray[200];
  char *lpmyarray = myarray;
  int arsize = 0;

 /* now add the depends on service key */
 
  /* Create a new key for our application */
  bSuccess = RegCreateKey(HKEY_LOCAL_MACHINE,
      "SYSTEM\\CurrentControlSet\\Services\\DomainNameService", &hk);
  if(bSuccess != ERROR_SUCCESS)
    {
      return 1;
    }

  strcpy(lpmyarray,"TcpIp");
  lpmyarray = lpmyarray + 6;
  arsize = arsize + 6;
  strcpy(lpmyarray,"Afd");
  lpmyarray = lpmyarray + 4;
  arsize = arsize + 4;
  strcpy(lpmyarray,"LanManWorkstation");
  lpmyarray = lpmyarray + 18;
  arsize = arsize + 19;
  strcpy(lpmyarray,"\0\0");
  
  bSuccess = RegSetValueEx(hk,  /* subkey handle         */
      "DependOnService",                 /* value name            */
      0,                        /* must be zero          */
      REG_MULTI_SZ,                   /* value type            */
      (LPBYTE) &myarray,        /* address of value data */
      arsize);   /* length of value data  */
   if(bSuccess != ERROR_SUCCESS)
    {
      return 1;
    }

  RegCloseKey(hk);
  return 0;
}

LONG APIENTRY StartBINDService(HWND hwnd, LPLONG lpIValue, LPSTR bs)
  {

HANDLE hSCManager = NULL, hDomainNameService = NULL;

	if((hSCManager = OpenSCManager(
			NULL, 
     		NULL,
     		SC_MANAGER_ALL_ACCESS)) == NULL) {
		return 11;
	}

  	if((hDomainNameService = OpenService(
       		hSCManager,                              
       		TEXT("DomainNameService"),               
       		SERVICE_ALL_ACCESS)) == NULL) {
                CloseServiceHandle(hSCManager);
		return 12;
	}

	if(!StartService(hDomainNameService, 0, NULL))
                 {
		 if(GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
          { 
          }
		   else
          {
                   CloseServiceHandle(hDomainNameService);
                   CloseServiceHandle(hSCManager);
		    return 50;
		  }
		 }
		 
       CloseServiceHandle(hDomainNameService);
       CloseServiceHandle(hSCManager);
        return 0;

}

LONG APIENTRY StopBINDService(HWND hwnd, LPLONG lpIValue, LPSTR bs)
  {


DWORD ControlCode = SERVICE_CONTROL_STOP;
HANDLE hSCManager = NULL, hDomainNameService = NULL;
SERVICE_STATUS ServiceStatus;

	if((hSCManager = OpenSCManager(
			NULL,
     		NULL,
     		SC_MANAGER_ALL_ACCESS)) == NULL) {
		return 11;
	}

  	if((hDomainNameService = OpenService(
       		hSCManager,                              
       		TEXT("DomainNameService"),               
       		SERVICE_ALL_ACCESS)) == NULL) {
                CloseServiceHandle(hSCManager);
		return 12;
	}

	if (!ControlService(hDomainNameService, ControlCode, &ServiceStatus))
         {
                CloseServiceHandle(hDomainNameService);
                CloseServiceHandle(hSCManager);
                //dont return an erro here assume it is already stopped.
		return 0;
  	 }
	
  CloseServiceHandle(hDomainNameService);
  CloseServiceHandle(hSCManager);
  return 0;

}


void CloseHandles()
{
     CloseHandle(outslot);
     CloseHandle(inslot);
     handles_open = FALSE;
}

/* ----------------------------------------- */

BOOL open_handles()

{

  if (handles_open)
     return TRUE;

  outbuf[0] = ucOperation;
  outbuf[1] = '\0';

  inslot = CreateMailslot("\\\\.\\mailslot\\sd_ndcin",0,7000,NULL);

  if (inslot == INVALID_HANDLE_VALUE)
      {
	   return FALSE;
      }

  outslot = CreateFile(lpszSlotName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL,NULL);
  if (outslot == INVALID_HANDLE_VALUE)
     {
       CloseHandle(inslot);
       handles_open = FALSE;
       return FALSE;
     }

handles_open = TRUE;     
return TRUE;

}

/*-------------------------------------------------------- */
/* is running or not */
BOOL is_running()

{

  ret = FALSE;
  if (!handles_open)
  { 
    ret = open_handles();
  }

  if (!ret)
   return FALSE;
   
   strcpy(outbuf,commonbuf);
   strcat(outbuf,"status ");
   sprintf(tickbuf,"%d",GetTickCount());
   strcat(outbuf,tickbuf);

  ret = FALSE;
  ret = WriteFile(
                  outslot,       // file to write to
                  outbuf,         // address of output buffer
                  strlen(outbuf) + 1, // number of bytes to write
                  &bytesWritten,  // number of bytes written
                  NULL);          // overlapped stuff, not needed

  if (!ret)
   {
     CloseHandles();
     return FALSE;
   }

   ret2 = FALSE;
   ret2 = ReadFile(
                    inslot,     // file to read from
                    inbuf,          // address of input buffer
                    sizeof(inbuf),  // number of bytes to read
                    &bytesRead,     // number of bytes read
                    NULL);          // overlapped stuff, not needed

   if (!ret2)
     { 
      CloseHandles();
      return FALSE;
     }

  CloseHandles();
  return TRUE;

 } // end of running

//--------------------------------------------------------------------------------------------------
/* lgk code to start up bind hidden under win95 since there are no services */

void start_up_bind()
{

   STARTUPINFO StartInfo;
   BOOLEAN rvalue;
   PROCESS_INFORMATION phandle;
   static char cline[100] = "named95.exe";
  
    /* Set up members of STARTUPINFO structure. */

    StartInfo.cb = sizeof(STARTUPINFO);
    StartInfo.lpReserved = NULL;
    StartInfo.lpReserved2 = NULL;
    StartInfo.cbReserved2 = 0;
    StartInfo.lpDesktop = NULL;

    // set noshow in case it is a win app
    StartInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USEPOSITION;

    StartInfo.lpTitle = NULL;
    StartInfo.dwX = 1000;
    StartInfo.dwY = 1000;
    StartInfo.dwXSize = 0;
    StartInfo.dwYSize = 0;
    StartInfo.dwXCountChars= 0;
    StartInfo.dwYCountChars = 0;
    StartInfo.dwFillAttribute = 0;
    StartInfo.hStdInput = NULL;
    StartInfo.hStdOutput = NULL;
    StartInfo.hStdError = NULL;
    StartInfo.wShowWindow = SW_HIDE;

     rvalue = CreateProcess(NULL,(LPSTR)&cline,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartInfo,&phandle);
 
	if (rvalue == FALSE)
	  {
 	   
           int ecode = GetLastError();
	   if (ecode == 2)
	     {
	       printf("Startup of named95.exe failed errorcode = 2 (FILE_NOT_FOUND)\n");
	     }
	   else
	     {
	      printf("Startup of named95.exe failed errorcode = %d \n",ecode);
	   	 }

	   fflush(stdout);
	   Sleep(10000);
	   }
	   
	     {
	      DWORD waitval = WaitForInputIdle(phandle.hProcess,5000);
	     }

  	   CloseHandle(phandle.hThread);
	   CloseHandle(phandle.hProcess);

	   }
// -------------------------------------------------------------------------
LONG APIENTRY StartBIND95(HWND hwnd, LPLONG lpIValue, LPSTR bs)
  {

           BOOL running = FALSE;
           int i;

           
           strcpy(lpszSlotName,"\\\\.\\mailslot\\sd_bind");
           strcpy(commonbuf,". sd_ndcin ");
           // lgk first try status command to see if already running
           // so we don't start it again.
           if (!is_running())
             {
              // set to start
              start_up_bind();
              for (i=1; i<=4; i++)
               {
                Sleep(i*2000);
                running = is_running();
                if (running)
                  break;
               }
               
              if (!running)
		 return 107;
               else
                { // started ok
	             return 0;
	         }
	     } // not running
                
           else // already running
             {
               return 0;
             }
 return(FALSE);
  }

  
// -------------------------------------------------------------------------
LONG APIENTRY StopBIND95(HWND hwnd, LPLONG lpIValue, LPSTR bs)
  {

                strcpy(lpszSlotName,"\\\\.\\mailslot\\sd_bind");
                strcpy(commonbuf,". sd_ndcin ");
                if (!handles_open)
                  open_handles();

                 ret3 = FALSE;
                 strcpy(outbuf,commonbuf);
                 strcat(outbuf,"stop ");
                 sprintf(tickbuf,"%d",GetTickCount());
                 strcat(outbuf,tickbuf);

                 ret3 = WriteFile(
                        outslot,       // file to write to
                        outbuf,         // address of output buffer
                        strlen(outbuf) + 1, // number of bytes to write
                        &bytesWritten,  // number of bytes written
                        NULL);          // overlapped stuff, not needed

                  if (!ret3)
                    {
                     CloseHandles();
                     // don't return error here assume it is already stopped...
		     return 0;
                    }  

        CloseHandles();
        return 0;
}


LONG APIENTRY LaunchApp(HWND hwnd, LPLONG lpIValue, LPSTR cmd)
{
   BOOLEAN dowait = (BOOLEAN)lpIValue;
   //char arglist[1000];
   STARTUPINFO StartInfo;
   BOOLEAN rvalue;
   PROCESS_INFORMATION phandle;
   DWORD waitval;

    /* Set up members of STARTUPINFO structure. */

    StartInfo.cb = sizeof(STARTUPINFO);
    StartInfo.lpReserved = NULL;
    StartInfo.lpReserved2 = NULL;
    StartInfo.cbReserved2 = 0;
    StartInfo.lpDesktop = NULL;

    // set noshow in case it is a win app
      StartInfo.dwFlags = 0;

	StartInfo.lpTitle = NULL;
    StartInfo.dwX = 1000;
    StartInfo.dwY = 1000;
    StartInfo.dwXSize = 500;
    StartInfo.dwYSize = 500;
    StartInfo.dwXCountChars= 0;
    StartInfo.dwYCountChars = 0;
    StartInfo.dwFillAttribute = 0;
    StartInfo.hStdInput = NULL;
    StartInfo.hStdOutput = NULL;
    StartInfo.hStdError = NULL;

     rvalue = CreateProcess(NULL,cmd,NULL,NULL,FALSE,CREATE_SEPARATE_WOW_VDM,NULL,NULL,&StartInfo,&phandle);
	 if (rvalue == FALSE)
	   {
        return 1;
       }	   
       
 	 if (dowait)
 	   waitval = WaitForSingleObject(phandle.hProcess,INFINITE);
  	 
  	 CloseHandle(phandle.hThread);
	 CloseHandle(phandle.hProcess);
     return 0;
}

