/*--------------------------------------------------------------
	File:		ndc.c
	Function:	control-panel applet for BIND
	By:			Paul Wren, Software.com
	Created:	12/14/95

	Copyright (c) Software.com, Inc 1995
	Modified 1/12 96 by L. Kahn for freeware version
--------------------------------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include <cpl.h>
#include "ndc.h"
#include "resource.h"
#include "../conf/portability.h"
#include "../compat/lib/log.h"

typedef struct tagApplet
{
    int icon;           // icon resource identifier
    int namestring;     // name-string resource identifier
    int descstring;     // description-string resource identifier
    int dlgtemplate;    // dialog box template resource identifier
    DLGPROC dlgfn;      // dialog box procedure
} APPLET;

APPLET BindApplet =
{
    BIND_ICON, 
    BIND_NAME, 
    BIND_DESC,
    BIND_DLG,
    BindDlgProc,
};

HWND 			g_hwndDlg;
HANDLE 			hModule = NULL;
DWORD 			ControlCode;
SERVICE_STATUS 	ServiceStatus;
HANDLE 			hSCManager = NULL;
HANDLE			hDomainNameService = NULL;

char szMsg[255];
char szCtlPanel[30];
char editor[100];
char image_path[300];
char commandline[1000];
BOOLEAN server_up = FALSE;


static int  ndcStartService();
static int  ndcStopService();
static void ndcQueryToggle();
static void ndcTraceOff();
static void ndcTraceOn();
static void ndcReloadDatabase();
static void ndcDumpDatabase();
static void ndcStatusService();
static void ndcWriteStats();
static void ndcRestartService();

/*--------------------------------------------------------------
	Function:	DllMain
--------------------------------------------------------------*/
BOOL WINAPI DllMain(IN PVOID hmod,IN ULONG ulReason,
					IN PCONTEXT pctx OPTIONAL)
{
    if (ulReason != DLL_PROCESS_ATTACH)
        return TRUE;
    else
        hModule = hmod;

    return TRUE;
    UNREFERENCED_PARAMETER(pctx);
}


/*--------------------------------------------------------------
	Function:	InitBindApplet
	Synopsis:	load the caption string for Control Panel
--------------------------------------------------------------*/
BOOL InitBindApplet (HWND hwndParent)
{
	BOOL bResult;
    LoadString (hModule,CPCAPTION,szCtlPanel,sizeof(szCtlPanel));

	if ((hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS)) == NULL)
	{
 		sprintf(szMsg, "Unable to open Service Control Manager: %u", GetLastError());
		bResult = FALSE;
	}

  	if ((hDomainNameService = OpenService(hSCManager,TEXT("DomainNameService"),
  										 SERVICE_ALL_ACCESS)) == NULL)
    {
		sprintf(szMsg,"Unable to open a handle to Domain Name Service: %u",
					   GetLastError());
		bResult = FALSE;
	}

    return bResult;
    UNREFERENCED_PARAMETER(hwndParent);
}

/*--------------------------------------------------------------
	Function:	TermBindApplet
	Synopsis:	terminate the applet:  do nothing
--------------------------------------------------------------*/
void TermBindApplet()
{
}


/*--------------------------------------------------------------
	Function:	CPIApplet
	Synopsis:	process messages for applet
--------------------------------------------------------------*/
LONG CALLBACK CPlApplet(HWND hwndCPL, UINT uMsg,
						LONG lParam1, LONG lParam2)
{
    int iApplet;
    LPNEWCPLINFO lpNewCPlInfo;
    static iInitCount = 0;
            
    switch (uMsg) {
        case CPL_INIT:              // first message, sent once
            if (!iInitCount)
                if (!InitBindApplet(hwndCPL))
                    return FALSE;
            iInitCount++;
            return TRUE;

        case CPL_GETCOUNT:          // second message, sent once
            return 1L;
            break;

        case CPL_NEWINQUIRE:        // third message, sent once per app
            lpNewCPlInfo = (LPNEWCPLINFO) lParam2;

            iApplet = (int)(LONG)lParam1;
            lpNewCPlInfo->dwSize = (DWORD) sizeof(NEWCPLINFO);
            lpNewCPlInfo->dwFlags = 0;
            lpNewCPlInfo->dwHelpContext = 0;
            lpNewCPlInfo->lData = 0;
            lpNewCPlInfo->hIcon = LoadIcon (hModule,
                (LPCTSTR) MAKEINTRESOURCE(BindApplet.icon));
            lpNewCPlInfo->szHelpFile[0] = '\0';

            LoadString (hModule, BindApplet.namestring,
                        lpNewCPlInfo->szName, 32);

            LoadString (hModule, BindApplet.descstring,
                        lpNewCPlInfo->szInfo, 64);
            break;

        case CPL_SELECT:            // application icon selected
            break;

        case CPL_DBLCLK:            // application icon double-clicked
            iApplet = (int)(LONG)lParam1;
            DialogBox (hModule,
                       MAKEINTRESOURCE(BindApplet.dlgtemplate),
                       hwndCPL,
                       BindApplet.dlgfn);
            break;

         case CPL_STOP:              // sent once per app. before CPL_EXIT
            break;

         case CPL_EXIT:              // sent once before FreeLibrary called
            iInitCount--;
            if (!iInitCount)
                TermBindApplet();
            break;

         default:
            break;
    }
    return 0;
}

/*--------------------------------------------------------------
	Function:	AddToListBox
	Synopsis:	put the char string passed, in the list box
--------------------------------------------------------------*/
static void AddToListBox (LPCTSTR szBuffer)
{
   HWND hwndDataBox = GetDlgItem(g_hwndDlg, IDC_DATABOX);

   int x = ListBox_AddString(hwndDataBox, szBuffer);
   ListBox_SetCurSel(hwndDataBox, x);

   if (ListBox_GetCount(hwndDataBox) > 100)
      ListBox_DeleteString(hwndDataBox, 0);
}
 

/* edit the file */
int edit_it (char *filename)
{
	STARTUPINFO sui;
	PROCESS_INFORMATION proc_info;
    strcpy(commandline,editor);
    strcat(commandline," ");
    strcat(commandline,image_path);
    strcat(commandline,filename);

	memset((char *)&sui, 0,sizeof(STARTUPINFO));
	sui.cb = sizeof(STARTUPINFO);
    /* give the app about a second to make sure the file was generated */
    Sleep(1000);
	if (!CreateProcess(NULL, commandline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL,
					   NULL, &sui, (LPPROCESS_INFORMATION)&proc_info))
      {

        sprintf(szMsg,"Execution of Command Failed: %s",commandline);
        AddToListBox(szMsg);
	    return -1;
	  }
  return 1;
}

/*--------------------------------------------------------------
	Function:	Getvalues
	Synopsis:	Look in the registry for the editor string.
--------------------------------------------------------------*/
static int GetEditor(char *editor)

{

  HKEY hk;                      /* registry key handle */
  BOOL bSuccess;
  DWORD  sizeofeditor    = 100;


  /* Create/open a new key for our application */
  bSuccess = RegCreateKey(HKEY_LOCAL_MACHINE,
      "SYSTEM\\CurrentControlSet\\Services\\DomainNameService\\Parameters", &hk);
  if(bSuccess != ERROR_SUCCESS)
    {
      strcpy(editor,"notepad.exe");
      return -1;
    }

  /* get the entry */
  bSuccess = RegQueryValueEx(hk,  /* subkey handle         */
     "Editor",       /* value name            */
      NULL,                        /* must be zero          */
      NULL,                   /* value type          not required  */
      (LPBYTE)editor,        /* address of value data */
      &sizeofeditor);   /* length of value data  */
  if(bSuccess != ERROR_SUCCESS)
    {
      RegCloseKey(hk);
      strcpy(editor,"notepad.exe");
      return 1;
    }

  RegCloseKey(hk);
  return 0;
}

/* ------------------------------------------------------------------------------------- */
/* get image path.. get the executable path.. lgk */

static int GetImagePath(char *imagepath)

{

  HKEY hk;                      /* registry key handle */
  BOOL bSuccess;
  DWORD  sizeofimagepath   = 300;
  
  
  /* Open a new key for our application */
  bSuccess = RegOpenKey(HKEY_LOCAL_MACHINE,
      "SYSTEM\\CurrentControlSet\\Services\\DomainNameService", &hk);
  if(bSuccess != ERROR_SUCCESS)
    {
      strcpy(imagepath,"");
      return -1;
    }

      /* get the entry */
  bSuccess = RegQueryValueEx(hk,  /* subkey handle         */
     "ImagePath",       /* value name            */
      NULL,                        /* must be zero          */
      NULL,                   /* value type          not required  */
      (LPBYTE)imagepath,        /* address of value data */
      &sizeofimagepath);   /* length of value data  */
  if(bSuccess != ERROR_SUCCESS)
    {
      RegCloseKey(hk);
      strcpy(imagepath,"");
      return 1;
    }

  /* now strip off the stuff at the end .. it should be just strip off named.exe or 9 characters.  */
  imagepath[strlen(imagepath)-9] = '\0';
  return 0;
}



/*-----------------------------------------------------------------
	Function:	SetEditor
	Synopsis:	Set a value for the editor in the registry
------------------------------------------------------------------*/
static int SetEditor(const char *Editor)
{
    HKEY hk;
    BOOL bSuccess;
	
  /* Create/open a new key for our application */
  bSuccess = RegCreateKey(HKEY_LOCAL_MACHINE,
      "SYSTEM\\CurrentControlSet\\Services\\DomainNameService\\Parameters", &hk);
  if(bSuccess != ERROR_SUCCESS)
    {
      return -1;
    }

  /* Add the phone entry */
  bSuccess = RegSetValueEx(hk,  /* subkey handle         */
      "Editor",       /* value name            */
      0,                        /* must be zero          */
      REG_SZ,                   /* value type            */
      (LPBYTE) Editor,        /* address of value data */
      strlen(Editor) + 1);   /* length of value data  */
   if(bSuccess != ERROR_SUCCESS)
    {
      RegCloseKey(hk);
      return -1;
    }

 RegCloseKey(hk);
 return 0;
}

void setbuttons_stopped()
{
           CheckDlgButton(g_hwndDlg,IDC_RUNNING,0);
           CheckDlgButton(g_hwndDlg,IDC_STOPPED,1);
           server_up = FALSE;
}

void setbuttons_running()
{
           CheckDlgButton(g_hwndDlg,IDC_STOPPED,0);
           CheckDlgButton(g_hwndDlg,IDC_RUNNING,1);
           server_up = TRUE;
}


/*--------------------------------------------------------------
	Function:	Dlg_OnInitDialog
	Synopsis:	initialize dialog:  save handle in global,
				display "ready" message
--------------------------------------------------------------*/
BOOL Dlg_OnInitDialog (HWND hwnd, HWND hwndFocus, LPARAM lParam)
{
   	g_hwndDlg = hwnd;
	AddToListBox("Ready for Request");

	GetEditor(editor);
	GetImagePath(image_path);
	SetDlgItemText(g_hwndDlg,IDC_Editor,editor);
    if (strncmp(editor,"  ",2) == 0)
      { 
        strcpy(editor,"notepad.exe");
        SetEditor(editor);
        SetDlgItemText(g_hwndDlg,IDC_Editor,editor);
      }
        /* now check the status of the server and activate the correct radionbutton */
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_INTERROGATE,&ServiceStatus))
	  {
           setbuttons_stopped();
          }      /* not running */
	else
  	{
          setbuttons_running();
	}
	return(TRUE);
}


/*--------------------------------------------------------------
	Function:	Dlg_OnDestroy
	Synopsis:	dummy function for end of dialog
--------------------------------------------------------------*/
void Dlg_OnDestroy (HWND hwnd)
{
}


/*--------------------------------------------------------------
	Function:	Dlg_OnCommand
	Synopsis:	message handler for dialog
--------------------------------------------------------------*/
void Dlg_OnCommand (HWND hwnd,int id,HWND hwndCtl,UINT codeNotify)
{
   	switch (id)
   	{
      	case IDC_RESTART:   ndcRestartService();	break;
      	case IDC_STARTUP:   ndcStartService();		break;
      	case IDC_SHUTDOWN:  ndcStopService();		break;
      	case IDC_STATUS:    ndcStatusService();    	break;
      	case IDC_STATS:     ndcWriteStats();    	break;
   	    case IDC_DUMPDB:    ndcDumpDatabase();		break;
	    case IDC_TRACE:	    ndcTraceOn();		    break;
	    case IDC_NOTRACE:   ndcTraceOff();		    break;
	    case IDC_RELOAD:    ndcReloadDatabase();	break;
	    case IDC_QUERY:	    ndcQueryToggle();		break;
	    case IDCANCEL:      EndDialog(hwnd, id);    break;
      	case IDOK:	        EndDialog(hwnd,id);		break;
	    default:	                                
	      /* kludge cannot determine how to make the radion buttons read only easily
	         so set it always */
          if (server_up)
             setbuttons_running();
           else setbuttons_stopped();
   	}
}


/*--------------------------------------------------------------
	Function:	BindDlgProc
	Synopsis:	processes messages sent to applet
	Comments:	Dialog presents buttons for the signals
				that named.exe understands.
--------------------------------------------------------------*/
BOOL APIENTRY BindDlgProc (	HWND hDlg, UINT message,
				UINT wParam, LONG lParam)
{
	BOOL fProcessed = TRUE;

    switch (message)
     {

      case WM_COMMAND:
       {
        switch(LOWORD(wParam))
           {
           case IDC_SET_EDITOR:
              {
                GetDlgItemText(g_hwndDlg,IDC_Editor,editor,100);
                SetEditor(editor);
               }
               break;

            }
         }
       }

    switch (message)
    {
	    HANDLE_MSG(hDlg, WM_INITDIALOG, Dlg_OnInitDialog);      
	    HANDLE_MSG(hDlg, WM_COMMAND, 	Dlg_OnCommand);      
		HANDLE_MSG(hDlg, WM_DESTROY, 	Dlg_OnDestroy);
		default:	
			fProcessed = FALSE;
			break;
    }
    return (fProcessed);
}

/*--------------------------------------------------------------
	Function:	ndcStartService
	Synopsis:	send a START signal to DNS service
--------------------------------------------------------------*/
static int ndcStartService(void)
{
	if (!StartService(hDomainNameService,0,NULL))
	{
		if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
		  {
		 	sprintf(szMsg,"Domain Name Service already running!");
			AddToListBox(szMsg);
           }
		else
          {
			sprintf(szMsg,"Unable to start the Domain Name Service: %u", GetLastError());
		    AddToListBox(szMsg);
		    return(FALSE);
          }
	}
    setbuttons_running();
	sprintf(szMsg, "Name Server Started.");
	AddToListBox(szMsg);
	return(TRUE);
}

/*--------------------------------------------------------------
	Function:	ndcStopService
	Synopsis:	send a STOP signal to DNS service
--------------------------------------------------------------*/
static int ndcStopService()
{
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_STOP,&ServiceStatus))
	{
		sprintf(szMsg,"Stop request failed:  %u",GetLastError());
		AddToListBox(szMsg);
		return(FALSE);
	}
    setbuttons_stopped();
	sprintf(szMsg,"Name Server stopped.");
	AddToListBox(szMsg);
	return(TRUE);
}


/*--------------------------------------------------------------
	Function:	ndcrestart
	Synopsis:	restart the dns server...
	                you can use start and stop here.. but
	                to be consistend with the unix ndc I
	                have also implement restart.
--------------------------------------------------------------*/

static void ndcRestartService(void)
{

	if (!ControlService(hDomainNameService,SERVICE_CONTROL_STOP,&ServiceStatus))
 	 {
		sprintf(szMsg,"Unable to restart... Domain Name Service is not Running!");
	    AddToListBox(szMsg);
        setbuttons_stopped();
        return;
	 }

        setbuttons_stopped();
	/* now restart it */
	if (!StartService(hDomainNameService,0,NULL))
	{
		if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
		   {	
		     sprintf(szMsg,"Domain Name Service already running");  
			 AddToListBox(szMsg);
             return;
           }
		else
        {
			sprintf(szMsg,"Unable to restart the Domain Name Service: %u", GetLastError());
            AddToListBox(szMsg);
            setbuttons_stopped();
            return;
        }
	}
    setbuttons_running();
	sprintf(szMsg, "Name Server Restarted.");
	AddToListBox(szMsg);
}


#define LB_MSG(a,b)   sprintf(szMsg,a,b);   AddToListBox(szMsg);

/*--------------------------------------------------------------
	Function:	ndcWriteStats
	Synopsis:	send a WRITE_STATS signal to DNS service
--------------------------------------------------------------*/

static void ndcWriteStats()
{
    
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_STATS,&ServiceStatus))
	  {
		sprintf(szMsg,"Stats request failed:  %u",GetLastError());
        AddToListBox(szMsg);
      }
	else
       {
  		AddToListBox("Current Stats. written to file 'named.sts'.");
        if (!edit_it("named.sts"))
          AddToListBox("Edit of Stats. file failed.");
       }
}
                                              

/*--------------------------------------------------------------
	Function:	ndcStatusService
	Synopsis:	print the service status
--------------------------------------------------------------*/
static void ndcStatusService()
{
	/* refresh the running buttons based on the status */
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_INTERROGATE,&ServiceStatus))
          {
		sprintf(szMsg,"Status request failed:  %u",GetLastError());
		setbuttons_stopped();
	  }
	else
  	{
		setbuttons_running();
  		AddToListBox("Status of Domain Name Service:");
  		LB_MSG("  Service Type: 0x%x",ServiceStatus.dwServiceType);
  		LB_MSG("  Current State: 0x%x",ServiceStatus.dwCurrentState);
  		LB_MSG("  Controls Accepted: 0x%x",ServiceStatus.dwControlsAccepted);
  		LB_MSG("  Exit Code: %d", ServiceStatus.dwWin32ExitCode);
  		LB_MSG("  Service Specific Exit Code: %d",
  				  ServiceStatus.dwServiceSpecificExitCode);
  		LB_MSG("  Check Point: %d", ServiceStatus.dwCheckPoint);
  		LB_MSG("  Wait Hint: %d", ServiceStatus.dwWaitHint);
	}
}

/*--------------------------------------------------------------
	Function:	ndcDumpDatabase
	Synopsis:	send a DUMP signal to DNS service
--------------------------------------------------------------*/
static void ndcDumpDatabase()
{
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_DUMPDB,&ServiceStatus))
	  {	
	   sprintf(szMsg,"Dump request failed:  %u",GetLastError());
       AddToListBox(szMsg);
      } 
	else
  	  {
  	   sprintf(szMsg,"Database dumped to file 'namdump.db'.");
	   AddToListBox(szMsg);
	   /* now pull this up in the editor */
       if (!edit_it("namdump.db"))
         AddToListBox("Edit of database dump failed.");
      }
}      

/*--------------------------------------------------------------
	Function:	ndcReloadDatabase
	Synopsis:	send a RELOAD signal to DNS service
--------------------------------------------------------------*/
static void ndcReloadDatabase()
{
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_RELOAD,&ServiceStatus))
		sprintf(szMsg,"Reload request failed:  %u",GetLastError());
	else
  		sprintf(szMsg,"Database reloaded.");
	AddToListBox(szMsg);
}

/*--------------------------------------------------------------
	Function:	ndcTraceOn
	Synopsis:	send a TRACE ON signal to DNS service
--------------------------------------------------------------*/
static void ndcTraceOn()
{
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_TRACE,&ServiceStatus))
		sprintf(szMsg,"Trace request failed:  %u",GetLastError());
	else
  		sprintf(szMsg,"Tracing Level Incremented.");
	AddToListBox(szMsg);
}

/*--------------------------------------------------------------
	Function:	ndcTraceOff
	Synopsis:	send a TRACE OFF signal to DNS service
--------------------------------------------------------------*/
static void ndcTraceOff()
{
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_NOTRACE,&ServiceStatus))
		sprintf(szMsg,"No-Trace request failed:  %u",GetLastError());
	else
  		sprintf(szMsg,"Tracing turned off.");
	AddToListBox(szMsg);
}

/*--------------------------------------------------------------
	Function:	ndcQueryToggle
	Synopsis:	send a QRYLOG signal to DNS service
--------------------------------------------------------------*/
static void ndcQueryToggle()
{
	if (!ControlService(hDomainNameService,SERVICE_CONTROL_QRYLOG,&ServiceStatus))
		sprintf(szMsg,"Toggle Query Logging request failed:  %u",GetLastError());
	else
  		sprintf(szMsg,"Query Logging toggled.");
	AddToListBox(szMsg);
}
