/*---------------------------------------------------------------------------*\
 *  Fileg Name:  SETUP.RUL
 *
 *  Description:  BIND - NT Install, larry kahn... using ideas from software.com's
 *   version
 *
\* ----------------------------------------------------------------------------*/
declare
	// Constant declarations.
	#define SPACE_REQUIRED          400000          // Disk space in bytes.
	#define APP_NAME                "DomainNameService"
	#define APP_NAME2               "Bind 4.9.3. P1 DNS Freeware"
	#define APPBASE_PATH            "\\var\\named\\"
	#define PRODUCT_VERSION         "4.9.3RelP1"
	#define DEINSTALL_KEY           "BIND4.9.3"
	#define UNINSTALL_NAME          "BIND"
	#define PRODUCT_KEY             "named.exe"
	#define DNS_PORT                53
	#define PRIMARY         1
	#define SECONDARY       2
	#define CACHEONLY       3
	
	// Global variable declarations
	STRING  svDir, szMsg, szFileSet,szTitle,  szMessage, svUninstLogFile;
	STRING  szProgram, szParam, szTemp, szTemp2, szAppPath;
	STRING  svFileName;
	STRING  svTempStr;
        STRING  svModuleDir;
        STRING  svAnswer;
        STRING  dummy;
	
	BOOL    bRemoveBIND, bUpdateModules;
	

	STRING  svDomainName;                   // the domain we're installing in
	STRING  svHostName;                     // the name of this host
	STRING  svNetId;                        // limit, if any, on XFRNETS
	STRING  svDnsAddress;                   // the IP address of "primary" DNS
	STRING  szDllBindInst;
	NUMBER  nReturnValue;
        INT     nReturnValue2;
        INT     nValue;
	
	//--------Custom Dialog in Ishield-------------------------
	BOOL bDone;
	LIST lNames, lAddrs;

	//------- BindInst.DLL defines------------------------
	#define k_PrivilegeErr                  1
	#define k_CreateKeyErr                  2
	#define k_RestoreKeyErr                 3
	#define k_ErrUnableToOpenWriteOwner     4
	#define k_ErrUnableToSetOwner           5
	#define k_ErrUnableToOpenDAC            6
	#define k_ErrUnableToWriteDACL          7
	#define k_OpenKeyError                  8
	#define k_ModifySetAccountFail          10
	#define k_SCMErr                        11
	#define k_SCMpoErr                      12
	#define k_DeleteServiceFail             13
	#define k_DeleteKeyFail                 14
	#define k_DeleteValueFail               15
	#define k_DirSecurityErr                16
	#define k_DirSetDACLErr                 17
	#define k_DirSetSecurityErr             18
	#define k_SCMpoStopErr                  19
	#define k_SaveKeyErr                    20
	#define k_ServiceUnknownErr             50
	#define k_ServiceDependency             51
	#define k_ServiceDependencyFail         52
	#define k_ServiceLogonFail              53

        #define k_BadPath                       101
	#define k_AccessDenied                  102
	#define k_ServiceExists                 103
        #define k_createservicefailed           104
        #define k_removeservicefailed           105
	#define k_ServicenoExists               106
	
	//--------Function declarations----------------------------
	prototype SetupScreen                   ();
	prototype CheckRequirements             ();
	prototype RemoveBIND                    ();
	prototype UpdateModules                 ();
	
	prototype ReportError                   (INT, BYREF STRING);
	prototype DoConfigType                  ();
	prototype CreateConfigFiles             (INT);
	prototype InstallBindFiles              (STRING, INT);
	prototype RegisterEventlogMessages	(STRING);
        prototype CheckForService               ();
        prototype GetImagePath                  (BYREF STRING);
        prototype LaunchAppAndWait              (STRING,STRING, INT);
        prototype GetReverseAddress             (BYREF STRING, STRING);
        prototype ReverseOctet                  (BYREF STRING, STRING);
        prototype FixDirectory                  (BYREF STRING, STRING);
        prototype GetThisIp                     (BYREF STRING, STRING);

//--------------------------------------------------------------------------
program

StartHere:
    Disable( BACKGROUND );

    dummy = "   ";
    // Set default registry tree
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);

    // Set up the installation screen.
    SetupScreen();
    Enable( DIALOGCACHE );

	TARGETDIR = SUPPORTDIR;
	szDllBindInst = SUPPORTDIR ^ "BINDDLL.DLL";  // BIND-specific helper library

    svDir = WINSYSDISK + "\\";
    
OfferReadmeFile:

if (AskYesNo("Would you like to see the readme file before proceeding? \n",NO ) = YES) then
	LaunchAppAndWait("NOTEPAD",SUPPORTDIR ^ "README.NT",1);
endif;
	
CheckForService1:
    // Look for service
    if (CheckForService() != 0) then                    // Not clean install
	Disable(BACKBUTTON);
		bUpdateModules = TRUE;
	szMessage = "Setup has determined that the BIND - NT service is\n" +
		    "already present.  Do you want to:\n";
	AskOptions(EXCLUSIVE, szMessage,
                
		   "&Remove BIND service", bRemoveBIND,
		   "&Update BIND to this version", bUpdateModules);
				   
	Enable(BACKBUTTON);
	if (bRemoveBIND) then
		    if (AskYesNo("Are you certain you wish to remove the BIND service\n" +
				 "and registry entries? \n",NO ) = YES) then
		RemoveBIND();
		    endif;
	endif;
	if (bUpdateModules) then
			UpdateModules();
	endif;
	exit;
    endif;           
// install drops through

DoCleanInstall:

    // Defaults

    // Create a Welcome dialog.
WelcomeDlg:
    Disable( BACKBUTTON );
    Welcome( "", 0 );
    Enable( BACKBUTTON );
 
    // Test target system for proper configuration.
    CheckRequirements();


HostName:
    svHostName = "";
    // Ask Internet Domain name
    szMessage = "Please this machines Host name (not the fully qualifed host.domain)\n" +
                 "but just the host name (e.g. dns1).\n" + 
                 "NOTE: this does not have to be the same as your Windows NT machine name.";
		
    if (AskText(szMessage, svHostName, svHostName) = BACK)
    then
	goto WelcomeDlg;
    endif;


DomainName:
    svDomainName = "";
    // Ask Internet Domain name
    szMessage = "Please enter your Internet domain name (e.g. plugh.com, or\n" +
		"if you are part of a subdomain - engineering.plugh.com).\n\n" +
		"Note: Please do not include your host name, only the domain name.";
		
    if (AskText(szMessage, svDomainName, svDomainName) = BACK)
    then
	goto HostName;
    endif;

Netid:
    svNetId = "";
    // Ask Network XFRNETS parameter (security:  only forward to this Subnet)
    szMessage = "Please enter the subnet for this network in the form of: x.y.z.0\n" +
                 "for a class C.  This information is used for the XFRNETS entry in\n" +
                 "your named.boot and to contruct the name for your reverse zone info files.";
		
    if (AskText(szMessage, svNetId, svNetId) = BACK)
    then
	goto DomainName;
    endif;
	
ModuleDir:
    svModuleDir = "";
    // Module locations, BIND - NT location
    svModuleDir = "c:\\var\\named";
    
    if (AskDestPath("Domain Name Server program and setup file location",
		    "Choose the directory for storage of the DNS information",
		    svModuleDir,0) = BACK) then
	goto Netid;
    endif;
	
ThatsItDoIt:    
    
	InstallBindFiles(svModuleDir,0);  // uncompress & place files in directories
	
GetConfigurationType:
    Disable(BACKBUTTON);
	TARGETDIR = svModuleDir;                // point back to bind directory

	SetStatusWindow( 85, "Creating Database Files..." );
	DoConfigType();                                 // do the configuration for user-spec'd type
    Enable(BACKBUTTON);

RegistryInit:

	SetStatusWindow( 90, "Creating Bind Service..." );
    
CreateService:
        nReturnValue2 = CallDLLFx(szDllBindInst,"CreateBINDService",nValue,svModuleDir^"\\named.exe");
	if (nReturnValue2 != 0) then
		ReportError(nReturnValue2,szMessage);
		szMessage = "Unable to install BIND - NT Service entry in Service Control Manager.\n" + szMessage;
		MessageBox(szMessage,SEVERE);
		exit;
	endif;


	SetStatusWindow( 95, "Adding Additional Registry Keys..." );

        nReturnValue2 = CallDLLFx(szDllBindInst,"addKeysToRegistry",nValue,dummy);
	if (nReturnValue2 != 0) then
		szMessage = "Unable to add the Depend on service key in the NT registry\n";
		MessageBox(szMessage,SEVERE);
		exit;
	endif;


	SetStatusWindow( 98, "Starting the Service..." );

StartService:
    nReturnValue2 = CallDLLFx(szDllBindInst,"StartBINDService",nValue,dummy);
    if (nReturnValue2 != 0) then
		ReportError(nReturnValue2,szMessage);
		szMessage = "Unable to start the BIND - NT Service.\n" + szMessage;
		MessageBox(szMessage,SEVERE);
		exit;
    endif;

   	// Announce setup complete and offer to read README file.e
   	FinalInstallProcess:
   	SetStatusWindow( 100, "Installation complete." );
   	Delay( 2 );

   	if (AskYesNo("Setup is complete.  The BIND service is running.\n"+
				"Do you want to look at the documentation for BIND?\n",
				 YES) = YES) then
	    LaunchAppAndWait("WRITE.EXE",TARGETDIR ^ "bog.wri",1);
   	endif;
exit;

/*---------------------------------------------------------------------------*\
 *
 * Function:  InstallBindFiles()
 *
 *  Purpose:  Uncompress the IShield package, and put files in the directory
 *            passed as an argument.
 *
 *              This function used both for new installations, and for the 
 *              "update modules" function.
 *
\*---------------------------------------------------------------------------*/
function InstallBindFiles(svInstDir,updateonly)
	NUMBER  nResult;
	STRING szBitmapPath;
begin
	szBitmapPath = SUPPORTDIR^"ishield.bmp";
//	PlaceBitmap(szBitmapPath,1,10,10,UPPER_RIGHT);

	// Insure that directories have sufficient permissions
//		ReleaseModuleDirSecurity(svInstDir);
    
	szFileSet = "DomainServer";
	FileSetBeginDefine(szFileSet);

	TARGETDIR = svInstDir;
	SetStatusWindow( -1, "Copying modules..." );
//	MessageBox("decompressing data.z: sourcedir = " + SRCDIR + " target dir = " +
//                  TARGETDIR,INFORMATION);
// change this to comp update date eventually

if (updateonly != 0)
  then
 	  nResult = CompressGet("data.z","*.cpl",COMP_UPDATE_DATE);
          if (nResult < 0) then
                NumToStr( szTemp, nResult );
		MessageBox("File Decompression1 failed! ecode = " + szTemp, SEVERE);
		exit;
	endif;
 	  nResult = CompressGet("data.z","*.exe",COMP_UPDATE_DATE);
          if (nResult < 0) then
                NumToStr( szTemp, nResult );
		MessageBox("File Decompression2 failed! ecode = " + szTemp, SEVERE);
		exit;
	endif;

 	  nResult = CompressGet("data.z","*.help",COMP_UPDATE_DATE);
          if (nResult < 0) then
                NumToStr( szTemp, nResult );
		MessageBox("File Decompression3 failed! ecode = " + szTemp, SEVERE);
		exit;
	endif;

else // not update install all


 	  nResult = CompressGet("data.z","*.*",COMP_UPDATE_DATE);
          if (nResult < 0) then
                NumToStr( szTemp, nResult );
		MessageBox("File Decompression4 failed! ecode = " + szTemp, SEVERE);
		exit;
           endif;
endif;
	FileSetEndDefine(szFileSet);
	
    // Set up progress indicator and information gauge.
    Disable( DIALOGCACHE );
    Enable( STATUSDLG );

    StatusUpdate( ON, 80 );

    // Perform the file set.
    SetStatusWindow( 0, "Copying program files..." );
    nResult = FileSetPerformEz( szFileSet, 0 );

    switch (nResult)
	    case FS_DONE: // Successful completion.
	    case FS_CREATEDIR: // Create directory error.
		MessageBox( "Unable to create a directory under " + TARGETDIR + "."+
			"Please check write access to this directory.", SEVERE );
		exit;
	default: // Group all other errors under default label.
		NumToStr( szTemp, nResult );
		MessageBox( "General file transfer error."+
			"Please check your target location and try again."+
			"\n\n Error Number:"+ szTemp +
			"\n Related File: "+ ERRORFILENAME,SEVERE);
		exit;
    endswitch;
	
	// rename the files that stupid MIPS-Ishield made us do 8 chars
        // this stuff not necessary on an update as we only update the exes
if (updateonly = 0)
  then
	SRCDIR = TARGETDIR;
	CopyFile("db.cac","db.cache");    // use copy in case already exists


	TARGETDIR = WINSYSDIR;  // copy to the system32 subdirectory (on path)
	CopyFile("ndc.exe",      "ndc.exe");		// command line applet
	CopyFile("ndc.cpl",      "ndc.cpl");		// control-panel applet
	CopyFile("nslookup.exe", "nslookup.exe");	// nslookup
	CopyFile("nslookup.help","nslookup.help");
	CopyFile("xfer.exe",     "xfer.exe");		// zone-transfer function
	CopyFile("dig.exe",      "dig.exe");		// dig
	CopyFile("ipaddr.exe",   "ipaddr.exe");
	CopyFile("named.exe",    "named.exe");		// the server
endif;
	RegisterEventlogMessages(svInstDir);	// put EventLog reg entries in
end;


/*---------------------------------------------------------------------------*\
 *
 * Function:  RegisterEventlogMessages
 *
 *  Purpose:  Put an entry under the Eventlog registry information, so that
 *            it understands where to find messages that come from post.office.
 *
 *  History:  PIW	Created		12/14/95
 *
\*---------------------------------------------------------------------------*/
#define	EVENTLOG_ENTRY "\\SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\DNS"
#define	SERVICE_ENTRY "\\SYSTEM\\CurrentControlSet\\Services\\DomainNameService"

function RegisterEventlogMessages(svTemp)
	NUMBER nvSize;
begin
	RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
	RegDBSetKeyValueEx(EVENTLOG_ENTRY,"EventMessageFile",
				REGDB_STRING,svTemp^"named.exe",nvSize);
	RegDBSetKeyValueEx(EVENTLOG_ENTRY,"TypeSupported",REGDB_NUMBER,"7",nvSize);
end;

/*---------------------------------------------------------------------------*\
 *
 * Function:  DoConfigType
 *
 *  Purpose:  Find out what type of installation the user is planning,
 *                        and then create and/or show the configuration files to them.
 *
\*---------------------------------------------------------------------------*/
function DoConfigType()
	BOOL bPrimaryDns,bSecondaryDns,bCacheOnly;
begin
	bPrimaryDns = FALSE;
	bSecondaryDns = TRUE;
	bCacheOnly = FALSE;
    szMessage = "For creation of configuration files, please select the setup\n" +
		"you want for BIND.  Do you want to set up a:\n";
    AskOptions(EXCLUSIVE, szMessage,
	       "&Primary DNS", bPrimaryDns,
	       "&Secondary DNS", bSecondaryDns,
	       "&Caching-only DNS", bCacheOnly);
			   
    Enable(BACKBUTTON);
    if (bPrimaryDns) then
	    szMessage = "Please enter the IP address of this machine.\n";
	    AskText(szMessage, svDnsAddress, svDnsAddress);
		CreateConfigFiles(PRIMARY);   // create named.boot and db.127.0.0 files
    endif;
	
    if (bSecondaryDns) then
	    szMessage = "Please enter the IP address of the DNS from which you\n" +
			"will RECEIVE zone transfers (your primary)\n";
	    AskText(szMessage, svDnsAddress, svDnsAddress);
		CreateConfigFiles(SECONDARY);   // create named.boot and db.127.0.0 files
    endif;
	
	if (bCacheOnly) then
		CreateConfigFiles(CACHEONLY);   // create named.boot and db.127.0.0 files
	endif;          
	
    if (AskYesNo("Do you want to see the configuration files which have\n" + 
		     "been created for this DNS host?\n", YES) = YES) then
		// Let them see/edit the files, if they want to:
		LaunchAppAndWait("NOTEPAD.EXE", WINDIR ^ "named.boot",1);
		LaunchAppAndWait("NOTEPAD.EXE", TARGETDIR ^ "db.127.0.0",1);
		if (bPrimaryDns) then
                        szTemp = TARGETDIR ^ "db."+svNetId;
			LaunchAppAndWait("NOTEPAD.EXE", TARGETDIR ^ "db.zoneinfo",1);
			LaunchAppAndWait("NOTEPAD.EXE", szTemp,1);
		endif;
	endif;
end;

/*---------------------------------------------------------------------------*\
 *
 * Function:  CreateConfigFiles
 *
 *  Purpose:  Now that we know the domain name, host name, and IP Address,
 *                        create the configuration files for this DNS to be of type 
 *            specified by parameter:
 *                                      PRIMARY         user will have to populate db.zoneinfo file
 *                                      SECONDARY
 *                                      CACHEONLY
 *                        for the zone to some other, primar DNS specified.
 *
 *    Need to have filled in:  
 *                              svDomainName
 *                              svDnsAddress
 *                              svHostName
 *
\*---------------------------------------------------------------------------*/
function CreateConfigFiles(nType)
	NUMBER nvFileHandle;
	STRING svInAddrArpa;
        STRING saveddir;
        STRING svIP;
begin

    CreateFile(nvFileHandle,WINDIR,"NAMED.BOOT");
    WriteLine(nvFileHandle,";");
    WriteLine(nvFileHandle,";    File:       named.boot");
    WriteLine(nvFileHandle,";    Purpose:    give the DNS its startup parameters and");
    WriteLine(nvFileHandle,";                list of startup files.");
    WriteLine(nvFileHandle," ");
    // lgk we must put double slashes in  the directory here so it works...
    FixDirectory(saveddir,svModuleDir);
    WriteLine(nvFileHandle,"Directory " +saveddir);
    WriteLine(nvFileHandle," ");
 
    WriteLine(nvFileHandle,";");
    WriteLine(nvFileHandle,";");
    WriteLine(nvFileHandle,";");

    WriteLine(nvFileHandle,";    establish a loopback entry for this machine, and tell");
    WriteLine(nvFileHandle,";    it to load its identity from db.127.0.0");
    WriteLine(nvFileHandle," ");
    WriteLine(nvFileHandle,"primary 0.0.127.IN-ADDR.ARPA db.127.0.0");
    WriteLine(nvFileHandle," ");


	if (nType != CACHEONLY) then 
	    WriteLine(nvFileHandle,";    XFRNETS parameter limits the transfer of zone information");
	    WriteLine(nvFileHandle,";    to machines matching the subnet wildcard/mask entries listed");
            WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,"XFRNETS 127.0.0.0 "+svNetId);
            WriteLine(nvFileHandle," ");
	endif;  
	
	
	if (nType = SECONDARY) then 
	    WriteLine(nvFileHandle,";    set ourselves up as secondary for our domain with data");
	    WriteLine(nvFileHandle,";    for the domain coming from the file 'db.zoneinfo'");
	    WriteLine(nvFileHandle,";    which is empty by default, but is filled in with site-");
	    WriteLine(nvFileHandle,";    specific information as appropriate.");
            WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,"secondary "+svDomainName+" "+svDnsAddress+" db.zoneinfo");
	    GetReverseAddress(svInAddrArpa,svNetId);
	    WriteLine(nvFileHandle,"secondary " +svInAddrArpa+"in-addr.arpa " +svDnsAddress+" db.inaddr");
	    WriteLine(nvFileHandle,";");
	endif;

	if (nType = PRIMARY) then
	    WriteLine(nvFileHandle,";    set ourselves as primary server for the zone");
            WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,"primary "+svDomainName+" db.zoneinfo");
            WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";    provide reverse address-to-host mapping");
            WriteLine(nvFileHandle," ");
  	    GetReverseAddress(svInAddrArpa,svDnsAddress);
  	    WriteLine(nvFileHandle,"primary " +svInAddrArpa+".in-addr.arpa db."+svNetId);
	    WriteLine(nvFileHandle,";");
	endif;

    WriteLine(nvFileHandle,"; prime the DNS with root server 'hint' information");
    WriteLine(nvFileHandle," ");
    WriteLine(nvFileHandle," ");
    WriteLine(nvFileHandle,"cache . db.cache");
    WriteLine(nvFileHandle," ");
    CloseFile(nvFileHandle);
    
    CreateFile(nvFileHandle,TARGETDIR,"db.127.0.0");
    WriteLine(nvFileHandle,";");
    WriteLine(nvFileHandle,";    File:      db.127.0.0 file");
    WriteLine(nvFileHandle,";    Purpose:   This file establishes the identity of this DNS.");
    WriteLine(nvFileHandle,";               SOA stands for 'start of authority' and sets the");
    WriteLine(nvFileHandle,";               default parameters for information this DNS is ");
    WriteLine(nvFileHandle,";               authoritative for:");
    WriteLine(nvFileHandle,";");
    WriteLine(nvFileHandle,"@        IN SOA    "+svHostName+"."+svDomainName+". postmaster."+svDomainName+". (");
    WriteLine(nvFileHandle,"        1996050101   ; serial  [yyyyMMddNN]");
    WriteLine(nvFileHandle,"             21600   ; refresh [6h]");
    WriteLine(nvFileHandle,"              3600   ; retry   [1h]");
    WriteLine(nvFileHandle,"            691200   ; expire  [8d]");
    WriteLine(nvFileHandle,"             86400)  ; minimum [1d]");
    WriteLine(nvFileHandle,";");
    WriteLine(nvFileHandle,"         IN NS    "+svHostName+"."+svDomainName+". ");
    WriteLine(nvFileHandle,"1        IN PTR    localhost."+svDomainName+".");
    WriteLine(nvFileHandle,";");
    CloseFile(nvFileHandle);

	// for Primary ONLY, make the zone information files.  Secondary will load from
	// primary when it boots.
	if (nType = PRIMARY) then 
	    CreateFile(nvFileHandle,TARGETDIR,"db."+svNetId);
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";    File:      db.inaddr");
	    WriteLine(nvFileHandle,";    Purpose:   This file establishes the address-to-name lookup");
	    WriteLine(nvFileHandle,";               information for this zone.  You will have to");
	    WriteLine(nvFileHandle,";               fill out the actual address information for your");
	    WriteLine(nvFileHandle,";               specific zone in the format shown in the comments");
	    WriteLine(nvFileHandle,";");
            WriteLine(nvFileHandle,"@        IN SOA "+svHostName+"."+svDomainName+". postmaster."+svDomainName+". (");
            WriteLine(nvFileHandle,"        1996050101   ; serial  [yyyyMMddNN]");
            WriteLine(nvFileHandle,"             21600   ; refresh [6h]");
            WriteLine(nvFileHandle,"              3600   ; retry   [1h]");
            WriteLine(nvFileHandle,"            691200   ; expire  [8d]");
            WriteLine(nvFileHandle,"             86400)  ; minimum [1d]");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,"         IN NS    "+svHostName+"."+svDomainName+". ");
	    WriteLine(nvFileHandle,"1        IN PTR    localhost."+svDomainName+".");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
            GetThisIp(svIP,svDnsAddress);
	    WriteLine(nvFileHandle,svIP+"       IN PTR    "+svHostName+"."+svDomainName+".");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";  Other Name Servers for this domain?   (EXAMPLES ONLY)");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";	IN NS	examplens1.plugh.com.");
	    WriteLine(nvFileHandle,";	IN NS	examplens2.plugh.com.");
	    WriteLine(nvFileHandle,";	IN NS	examplens3.cerf.net.");
	    WriteLine(nvFileHandle,";	IN NS	examplens4.webpa.com.");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";  	Addresses point to canonical name    (EXAMPLES ONLY)");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";	33	IN PTR	example_host1.plugh.com.");
	    WriteLine(nvFileHandle,";	34	IN PTR	example_host2.plugh.com.");
	    WriteLine(nvFileHandle," ");
	    CloseFile(nvFileHandle);
	
	    CreateFile(nvFileHandle,TARGETDIR,"db.ZONEINFO");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";    File:      db.zoneinfo");
	    WriteLine(nvFileHandle,";    Purpose:   This file establishes the name/address information");
	    WriteLine(nvFileHandle,";               for this zone.  You will have to fill out the actual");
	    WriteLine(nvFileHandle,";               information for your specific zone in the format shown");
	    WriteLine(nvFileHandle,";               in the comments.");
	    WriteLine(nvFileHandle,";");
            WriteLine(nvFileHandle,"@        IN SOA    "+svHostName+"."+svDomainName+". postmaster."+svDomainName+". (");
            WriteLine(nvFileHandle,"        1996050101   ; serial  [yyyyMMddNN]");
            WriteLine(nvFileHandle,"             21600   ; refresh [6h]");
            WriteLine(nvFileHandle,"              3600   ; retry   [1h]");
            WriteLine(nvFileHandle,"            691200   ; expire  [8d]");
            WriteLine(nvFileHandle,"             86400)  ; minimum [1d]");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,"         IN NS    "+svHostName+"."+svDomainName+". ");
	    WriteLine(nvFileHandle,"localhost	IN     A   127.0.0.1");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";  Other Name Servers for this domain?   (EXAMPLES ONLY)");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";	IN NS	examplens1.plugh.com.");
	    WriteLine(nvFileHandle,";	IN NS	examplens2.plugh.com.");
	    WriteLine(nvFileHandle,";	IN NS	examplens3.cerf.net.");
	    WriteLine(nvFileHandle,";	IN NS	examplens4.webpa.com.");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";	Mail Exchange Records	(EXAMPLES ONLY)");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";	plugh.com.	IN MX	10 mailserver.plugh.com.");
	    WriteLine(nvFileHandle,";			IN MX	30 backupserver.cerf.net.");
	    WriteLine(nvFileHandle,";	plugh.com.	IN A	255.255.255.255	; For DUMB Mailers");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";	Define local hosts    ");
	    WriteLine(nvFileHandle," ");
            WriteLine(nvFileHandle,svHostName+"     IN     A   "+svDnsAddress);
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,";	Define local hosts      (EXAMPLES ONLY)");
            WriteLine(nvFileHandle,";mach1	IN A	255.255.255.0");
	    WriteLine(nvFileHandle,";		IN MX	10 mailserver.plugh.com.");
	    WriteLine(nvFileHandle,";		IN MX	30 backupserver.cerf.net.");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";   Example machine that receives its own mail, first:");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";mach2	IN A	255.255.255.0");
	    WriteLine(nvFileHandle,";		IN MX	10 mach2.plugh.com.");
	    WriteLine(nvFileHandle,";		IN MX	20 mailserver.plugh.com.");
	    WriteLine(nvFileHandle,";		IN MX	30 backupserver.cerf.net.");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle," ");
	    WriteLine(nvFileHandle,"; CNames			 (EXAMPLES ONLY)");
	    WriteLine(nvFileHandle,";");
	    WriteLine(nvFileHandle,";news		IN CNAME	mach1.plugh.com.");
	    WriteLine(nvFileHandle,";www		IN CNAME	mach2.plugh.com.");
	    WriteLine(nvFileHandle,";ftp		IN CNAME	mach1.plugh.com.");
	    WriteLine(nvFileHandle,";hub		IN CNAME	mach2.plugh.com.");
	    WriteLine(nvFileHandle," ");
	    CloseFile(nvFileHandle);
	endif;
	
end;    
	
/*---------------------------------------------------------------------------*\
 *
 * Function:  SetupScreen
 *
 *  Purpose:  This function will set up the screen look.  This includes
 *            colors, fonts, text to be displayed, etc.
 *
\*---------------------------------------------------------------------------*/
function SetupScreen()
	INT nDx, nDy;
begin
	Enable( DEFWINDOWMODE );
    Enable( INDVFILESTATUS );

	//----------------------------------------------------------
	//      If you want to downsize the Blue-fade background:
	//
	//      GetExtents(nDx,nDy);
	//
	//      
	//      PlaceWindow(BACKGROUND,nDx/2,0,UPPER_LEFT);
	//      SizeWindow(BACKGROUND,nDx/2,nDy/2);
	//
	//  However will also have to move all the dialogs/bitmaps
	//  around to make this work correctly...
	//----------------------------------------------------------
	
    SetTitle( APP_NAME2 + " Setup", 24, WHITE );

//    SetColor( BACKGROUND, BK_BLUE ); // Dark blue.
//    SetColor( STATUSBAR, BLUE );     // Bright blue.
    SetTitle( "Setup", 0, BACKGROUNDCAPTION ); // Caption bar text.

    Enable( BACKGROUND );
    Delay( 1 );

    // Show the bitmap.
   // PlaceBitmap( SUPPORTDIR ^ "BINDNT.BMP",1,10,10,UPPER_RIGHT);
end;


/*---------------------------------------------------------------------------*\
 * Function:  CheckRequirements
 *  Purpose:  This function will make sure we are on NT, not Win95.
\*---------------------------------------------------------------------------*/
function CheckRequirements()
	number nvVersion;
	STRING szResult, svVersion;
begin
    // Determine the target system's operating system.
    GetSystemInfo( WINMAJOR, nvVersion, svVersion );
    if (nvVersion =  4) then
	    MessageBox("This product can only run on Windows NT",SEVERE);
		exit;
    endif;
end;

//+---------------------------------------------------------------------------
//  Member:             ReportError()
//----------------------------------------------------------------------------
function ReportError(n_Err, sz_Message)

begin
  switch(n_Err)
	case k_PrivilegeErr:              sz_Message = "Privilege Error";
	case k_CreateKeyErr:              sz_Message = "Create Key Failed";
	case k_RestoreKeyErr:             sz_Message = "Restore Default Key Failed";
	case k_ErrUnableToOpenWriteOwner: sz_Message = "Unable to Open and Write Owner Information";
	case k_ErrUnableToSetOwner:       sz_Message = "Unable to Set Owner Information";
	case k_ErrUnableToOpenDAC:        sz_Message = "Unable to Open Access Control List";
	case k_ErrUnableToWriteDACL:      sz_Message = "Unable to Write Access Control List";
	case k_OpenKeyError:              sz_Message = "Unable to Open Registry Key Entry";
	case k_ModifySetAccountFail:      sz_Message = "Unable to Setup Account Parameters";
	case k_SCMErr:                    sz_Message = "Unable to Open Service Control Manager Database";
	case k_SCMpoErr:                  sz_Message = "Unable to Open BIND - NT service entries in the Service Control Manager";
	case k_DeleteServiceFail:         sz_Message = "Unable to delete BIND - NT service";
	case k_DeleteKeyFail:             sz_Message = "Unable to delete registry key information";
	case k_DeleteValueFail:           sz_Message = "Unable to delete registry value information";
	case k_DirSecurityErr:            sz_Message = "Unable to retreive Security information on directory";
	case k_DirSetDACLErr:             sz_Message = "Unable to add security information on directory";
	case k_DirSetSecurityErr:         sz_Message = "Unable to set directory security information";
	case k_SCMpoStopErr:              sz_Message = "Unable to stop the BIND - NT service";
	case k_SaveKeyErr:                sz_Message = "Unable to save registry key.";
	case k_ServiceUnknownErr:         sz_Message = "The service control manager could not start the BIND - NT service - please check the event log";
	case k_ServiceDependency:         sz_Message = "The BIND - NT sevice depends on several other services which are not installed.";
	case k_ServiceDependencyFail:     sz_Message = "The BIND - NT service depends on other services which failed to start.";
	case k_ServiceLogonFail:          sz_Message = "The service manager was unable to login the BIND - NT service - Please check the password and logon as service privilege";

       // lgk new for freeware
        case k_BadPath:                   sz_Message = "Bad Path Specified."; 
	case k_AccessDenied:              sz_Message = "Access Denied.";
	case k_ServiceExists:             sz_Message = "Bind - NT service already exists so cannot be re-installed";
        case k_createservicefailed:       sz_Message = "Creation of the Bind - NT service failed.";
        case k_removeservicefailed:       sz_Message = "Unable to remove the Bind - NT service.";
	case k_ServicenoExists:           sz_Message = "Bind - NT service is not installed so cannot be removed.";
	default:                          sz_Message = "Unknown Error";
  endswitch;
end;

//+---------------------------------------------------------------------------
//
//  Member:             RemoveBIND()
//
//  Synopsis:   Remove the BIND service entry and registry entries
//
//----------------------------------------------------------------------------
function RemoveBIND()
	NUMBER n_Result;
begin
	
    dummy = APP_NAME;
    SetStatusWindow( 0, "Stopping and removing BIND service..." );
	// Remove the BIND service entry & Registry but first stop the service
 
        nReturnValue2 = CallDLLFx(szDllBindInst,"StopBINDService",nValue,dummy);

	if (nReturnValue2 != 0) then
		ReportError(nReturnValue2,szMessage);
		NumToStr( szTemp, nReturnValue2 );
		szMessage = "Unable to Stop the BIND - NT Service. \n" + szTemp + "\nAre you sure it is installed?\n" + szMessage;
		MessageBox(szMessage,SEVERE);
		exit;
	endif;
   	Delay( 3 ); // delay for named.exe file to free up so copy works


  	// have to get the currently install directory from the dll by pulling it off of the imagepath param
        if (GetImagePath(svModuleDir) != 0) then
	    szMessage = "Unable to retrieve the path to Remove BIND Files \n" + svModuleDir + 
                        "\nAre you sure it is installed?\n";
	    MessageBox(szMessage,SEVERE);
	    exit;
	 endif;

	n_Result = CallDLLFx(szDllBindInst,"RemoveBINDService",nValue,dummy);

	if (n_Result != 0) then            
		MessageBox("Unable to remove BIND - NT service from the registry.",SEVERE);
                exit;
	else
	    if (AskYesNo("Service Removed\n Do you want to delete all the BIND Executables and config/databasefiles also?\n",
				 NO) = YES) then

			TARGETDIR = WINSYSDIR;                  // pick off the files we put in the 
			DeleteFile("nslookup.exe");             // WinNT system directory
			DeleteFile("nslookup.help");             // WinNT system directory
			DeleteFile("xfer.exe");
			DeleteFile("ndc.cpl");
			DeleteFile("ndc.exe");
			DeleteFile("dig.exe");
			DeleteFile("ipaddr.exe");
			DeleteFile("named.exe");
			DeleteFile("instsrv.exe");

			TARGETDIR = svModuleDir;                 
			DeleteFile("nslookup.exe");             
			DeleteFile("nslookup.help");            
			DeleteFile("xfer.exe");
			DeleteFile("ndc.cpl");
			DeleteFile("ndc.exe");
			DeleteFile("dig.exe");
			DeleteFile("ipaddr.exe");
			DeleteFile("named.exe");
			DeleteFile("db.cache");
			DeleteFile("db.cac");
			DeleteFile("db.127.0.0.");
			DeleteFile("db.zoneinfo");
			DeleteFile("db.inaddr");
			DeleteFile("bog.wri");
			DeleteFile("readme.nt");
			DeleteFile("winntport.");
			DeleteFile("winntport.txt");
			DeleteFile("changes.");
			DeleteFile("h2n.bat");
			DeleteFile("h2n.dat");
			DeleteFile("h2n.txt");
			DeleteFile("install.bat");
			DeleteFile("instsrv.exe");
			DeleteFile("mkdist.bat");
			DeleteFile("named.boot");
			DeleteFile("options.");
			DeleteFile("todo.");


                        TARGETDIR = WINDIR;
                        DeleteFile("named.boot");

			MessageBox("BIND - NT service and registry entries are removed.\n" +
					   "All DomainNameServer Executable/Config files are also deleted.",INFORMATION);
		else
			MessageBox("BIND - NT service and registry entries are removed.\n" +
					   "All Executable/Config files are retained.",INFORMATION);
		endif;  
	endif;
end;

 
//+---------------------------------------------------------------------------
//
//  Member:             UpdateModules()
//
//----------------------------------------------------------------------------
function UpdateModules()
	STRING szFileSet;
	STRING szMessage;
	NUMBER nvSize, nvType;
begin
    SetStatusWindow( 0, "Updating BIND installation..." );

        nReturnValue2 = CallDLLFx(szDllBindInst,"StopBINDService",nValue,dummy);

	if (nReturnValue2 != 0) then
		ReportError(nReturnValue2,szMessage);
		NumToStr( szTemp, nReturnValue2 );
		szMessage = "Unable to Stop the BIND - NT Service. \n" + szTemp + "\nAre you sure it is running?\n" + szMessage;
		MessageBox(szMessage,SEVERE);
		exit;
	endif;
   	Delay( 3 ); // delay for named.exe file to free up so copy works

	// have to get the currently install directory from the dll by pulling it off of the imagepath param
        if (GetImagePath(svModuleDir) != 0) then
		szMessage = "Unable to retrieve the path to Update BIND Files \n" + svModuleDir + 
                  "\nAre you sure it is installed?\n";
		MessageBox(szMessage,SEVERE);
		exit;
	endif;

	InstallBindFiles(svModuleDir,1);
	
    nReturnValue2 = CallDLLFx(szDllBindInst,"StartBINDService",nValue,dummy);

    if (nReturnValue2 != 0) then
		ReportError(nReturnValue2,szMessage);
		szMessage = "Unable to start the BIND - NT Service.\n" + szMessage;
		MessageBox(szMessage,SEVERE);
		exit;
    endif;

	SetStatusWindow( 100, "Update completed." );
	Delay( 2 );
   
	MessageBox("Your Domain Name Server modules have been updated and\n" +
			   "the service is restarted.  You should check the event log\n" +
			   "to make sure everything came back up properly.",INFORMATION);
end;


/*---------------------------------------------------------------------------*\
 *
 * Function:  GetImagePAth
 *
 *  Purpose:  Get the given value, under the given key, from the registry.
 *   l. kahn
\*---------------------------------------------------------------------------*/
function GetImagePath(svValue)
	NUMBER nvSize;
	NUMBER nvType;
begin

        RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
        if (RegDBGetKeyValueEx(SERVICE_ENTRY,
              "ImagePath",nvType,svValue,nvSize) < 0) then
		return -1;
	endif;
			
	StrSub(svValue,svValue,0,nvSize - 10);                       // trim to REAL length   
        return 0;
end;

function CheckForService()
        STRING temp;
	NUMBER nvSize;
	NUMBER nvType;
begin


	RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
        if (RegDBGetKeyValueEx(SERVICE_ENTRY,
			"ImagePath",nvType,temp,nvSize) < 0) then
		return 0;
	endif;
 return -1;
end;

/*---------------------------------------------------------------------------*\
 *
 * Function:  LaunchAppAndWait
 *
 *  Purpose:  replace predefine fx in more expensive install sheild with c fx
 * l. kahn
\*---------------------------------------------------------------------------*/
function LaunchAppAndWait(svApp, svData, waitval)
  STRING tstring;
begin
        nValue = waitval;
        tstring = svApp+" "+svData;
        nReturnValue2 = CallDLLFx(szDllBindInst,"LaunchApp",nValue,tstring);
        return 0;
end;


/*---------------------------------------------------------------------------*\
 *
 * Function:  GetReverseAddrss
 *
 *  Purpose:  reverse and ip address for inaddr notation... l. kahn
 *
\*---------------------------------------------------------------------------*/
function GetReverseAddress(svOut,svIn)

INT location, len;
STRING newString, temp;
STRING outstring;
STRING part1, part2, part3;
INT parts;
NUMBER cnum;

begin
 
 len = StrLength(svIn) - 1;
 temp = svIn;
 parts = 0;

 location = StrFind(temp,".");
 while (location != -1)

   StrSub(newString,temp,0,location);
   StrToNum(cnum,newString);

   if (cnum != 0)
   then
 
     parts = parts + 1;
     switch (parts)

       case 1:
        part3 = newString;
       case 2:
        part2 = newString;
       case 3:
        part1 = newString;
       default:
     endswitch;


   endif; // not 0 octet

  StrSub(temp,temp,location+1,len);
  location = StrFind(temp,".");

 endwhile; 

     // now put it on outstring
     switch (parts)

       case 1:
        outstring = part3;
       case 2:
        outstring = part2 + "." + part3;
       case 3:
        outstring = part1 + "." + part2 + "." + part3;
       default:
     endswitch;

 svOut = outstring;

end;

/*---------------------------------------------------------------------------*\
 *
 * Function:  FixDirectory
 *
 *  Purpose:  put the double slashes in the directory
 *  l. kahn
\*---------------------------------------------------------------------------*/
function FixDirectory(svOut,svIn)

INT len;
INT ctr;
NUMBER letter;
INT i;

begin
 len = StrLength(svIn) - 1;
 ctr = 0;

 for i = 0 to len
    GetByte(letter,svIn,i);
    if (letter = 92)
      then
       SetByte(svOut,ctr,letter);
       ctr = ctr + 1;
    endif;

    SetByte(svOut,ctr,letter);
    ctr = ctr + 1;
 endfor;
end;

/*---------------------------------------------------------------------------*\
 *
 * Function:  GetThisIp
 *
 *  Purpose:  pull off the last octet of the ip address for the inaddr ptr record
 *  for this machine
 *  l. kahn
\*---------------------------------------------------------------------------*/
function GetThisIp(svOut,svIn)

INT len;
NUMBER letter;
STRING byte1, byte2, byte3, temp;
INT bytes;

begin

 bytes = 0;
 svOut = "";
 len = StrLength(svIn) - 1;
    
  GetByte(letter,svIn,len);
  while (letter != 46) && (len != 0)
    if (letter != 46)
      then
       
       bytes = bytes + 1;
       SetByte(temp,0,letter);
       switch (bytes)
         case 1:
            byte3 = temp;
         case 2:
            byte2 = temp;
         case 3:
            byte1 = temp;
         default:
       endswitch;
    endif;
  
    len = len - 1;
    GetByte(letter,svIn,len);

   endwhile;

       switch (bytes)
           case 1:
             svOut = byte3;
         case 2:
            svOut = byte2 + byte3;
         case 3:
            svOut = byte1 + byte2 + byte3;
         default:
       endswitch;

   return 0;

end;
