
//
//	Copyright 2000, International Business Machines Corporation and others.
//	All Rights Reserved.
//
//	This software has been released under the terms of the IBM Public
//	License.  For details, see the LICENSE file in the top-level source
//	directory or online at http://www.openafs.org/dl/license10.html
//


// Include header files

    #include "sdlang.h"
    #include "sddialog.h"


////////////////////// string defines ////////////////////////////

	// If the user places a file with this name in the same directory as
	// the setup files, only the client component will be available for
	// install.  The contents of this file are not used.
	#define ALLOW_ONLY_CLIENT_FLAG_FILENAME		"setup.co"

	// The release types
	#define RELEASE_TYPE_GA	        "GA"
	#define RELEASE_TYPE_BETA		"Beta"
	
	// Client logon dll names
	#define FULL_CLIENT_LOGON_DLL	"Client\\PROGRAM\\afslogon.dll"
	#define LIGHT_CLIENT_LOGON_DLL	"Client\\PROGRAM\\afslog95.dll"

	// Uninstall log file names for each component
    #define SERVER_UNINST_LOGFILE_NAME      	"Server_Uninst.isu"
    #define CLIENT_UNINST_LOGFILE_NAME      	"Client_Uninst.isu"
    #define LIGHT_CLIENT_UNINST_LOGFILE_NAME	"Light_Client_Uninst.isu"
    #define CC_UNINST_LOGFILE_NAME      		"CC_Uninst.isu"
    #define DOCS_UNINST_LOGFILE_NAME      		"Docs_Uninst.isu"

	// Uninstall dll names for each component
	#define SERVER_UNINST_DLL_NAME				"ServerUninst.dll"
	#define CLIENT_UNINST_DLL_NAME				"ClientUninst.dll"
	#define CC_UNINST_DLL_NAME					"CCUninst.dll"
	#define LIGHT_CLIENT_UNINST_DLL_NAME		"LightClientUninst.dll"
	#define DOCS_UNINST_DLL_NAME				"DocsUninst.dll"
	
	// These are the components the user sees
	#define CLIENT_COMP_NAME			"Client"
	#define LIGHT_CLIENT_COMP_NAME		"Light_Client"
	#define SERVER_COMP_NAME			"Server"
	#define CC_COMP_NAME				"Control_Center"

	// Light Client platform components
	#define LIGHT95_CLIENT_COMP_NAME		"Light_Client\\Win95"
	#define LIGHT98_CLIENT_COMP_NAME		"Light_Client\\Win98"

	// This is added to autoexec.bat on Win95 systems
	#define LIGHT95_CLIENT_PROTSEQ			"AFS_RPC_PROTSEQ=ncacn_ip_tcp"
		
    // Language components
	#define LANG_COMP_NAME					"Languages"
    #define LANG_ENGLISH_COMP_NAME          "Languages\\Lang_English"
    #define LANG_SIMP_CHINESE_COMP_NAME     "Languages\\Lang_Simp_Chinese"
    #define LANG_TRAD_CHINESE_COMP_NAME     "Languages\\Lang_Trad_Chinese"
    #define LANG_KOREAN_COMP_NAME           "Languages\\Lang_Korean"
    #define LANG_JAPANESE_COMP_NAME         "Languages\\Lang_Japanese"
    #define LANG_GERMAN_COMP_NAME           "Languages\\Lang_German"
    #define LANG_SPANISH_COMP_NAME          "Languages\\Lang_Spanish"
    #define LANG_PORTUGUESE_COMP_NAME       "Languages\\Lang_Portuguese"

	// Documentation components
	#define DOCS_COMP_NAME					"Documentation"
	#define DOCS_ENGLISH_COMP_NAME			"Documentation\\English"
	#define DOCS_JAPANESE_COMP_NAME			"Documentation\\Japanese"
	#define DOCS_KOREAN_COMP_NAME			"Documentation\\Korean"
	#define DOCS_SIMP_CHINESE_COMP_NAME		"Documentation\\Simp_Chinese"
	#define DOCS_TRAD_CHINESE_COMP_NAME		"Documentation\\Trad_Chinese"
	#define DOCS_GERMAN_COMP_NAME			"Documentation\\German"
	#define DOCS_SPANISH_COMP_NAME			"Documentation\\Spanish"
	#define DOCS_PORTUGUESE_COMP_NAME		"Documentation\\Portuguese"
	
	// Readme files components
	#define README_COMP_NAME				"Readme"
	#define README_ENGLISH_COMP_NAME		"Readme\\English"
	#define README_JAPANESE_COMP_NAME		"Readme\\Japanese"
	#define README_KOREAN_COMP_NAME			"Readme\\Korean"
	#define README_SIMP_CHINESE_COMP_NAME	"Readme\\Simp_Chinese"
	#define README_TRAD_CHINESE_COMP_NAME	"Readme\\Trad_Chinese"
	#define README_GERMAN_COMP_NAME		"Readme\\German"
	#define README_SPANISH_COMP_NAME		"Readme\\Spanish"
	#define README_PORTUGUESE_COMP_NAME		"Readme\\Portuguese"

	// License filenames
	#define LICENSE_ENGLISH_FILENAME		"License\\en_US.rtf"
	#define LICENSE_JAPANESE_FILENAME		"License\\ja_JP.rtf"
	#define LICENSE_KOREAN_FILENAME			"License\\ko_KR.rtf"
	#define LICENSE_SIMP_CHINESE_FILENAME	"License\\zh_CN.rtf"
	#define LICENSE_TRAD_CHINESE_FILENAME	"License\\zh_TW.rtf"
	#define LICENSE_GERMAN_FILENAME			"License\\de_DE.rtf"
	#define LICENSE_SPANISH_FILENAME		"License\\es_ES.rtf"
	#define LICENSE_PORTUGUESE_FILENAME		"License\\pt_BR.rtf"

	#define SETUP_UTILS_DLL_PATH	"InstallUtils.dll"

	// Some registry keys
	#define MSUNINSTALL_KEY         "\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
	#define COMPANY_REG_KEY			"Software\\TransarcCorporation\\"
	#define CONFIG_INFO_KEY			"Software\\AfsPreservedConfigInfo"
	
	#define CLIENT_SERVICE_NAME		"TransarcAFSDaemon"

	// Client help file names
	#define CLIENT_HELP_FILE_NAME		"Common\\afs-nt.hlp"
	#define LIGHT_CLIENT_HELP_FILE_NAME	"Common\\afs-light.hlp"
	
	#define MAX_STRING_LEN	512

	// Install actions
	#define ACTION_NONE			0
	#define	ACTION_INSTALL		1
	#define ACTION_REINSTALL	2
	#define ACTION_UPGRADE		3
	#define ACTION_DOWNGRADE	4

	// Documenation start menu info
	#define DOCUMENTATION_CMD_PATH			"Documentation\\Html\\index.htm"
	#define DOCUMENTATION_ARGS				""

	#define DOCUMENTATION_LICENSE_PATH		"Documentation\\Html\\license.rtf"

	// Application start menu info
	#define CFG_WIZARD_CMD_PATH				 "Server\\usr\\afs\\bin\\afssvrcfg.exe"
	#define CFG_WIZARD_ARGS					"/wizard"
	#define CREDS_TOOL_CMD_PATH				"Client\\Program\\afscreds.exe"
	#define CREDS_TOOL_ARGS					"/show"
	#define CLIENT_HELP_CMD_PATH			"Common\\afs-nt.hlp"
	#define CLIENT_HELP_ARGS				""
	#define LIGHT_CLIENT_HELP_CMD_PATH		"Common\\afs-light.hlp"
	#define LIGHT_CLIENT_HELP_ARGS			""
	#define SERVER_MANAGER_CMD_PATH			"Control Center\\TaAfsServerManager.exe"
	#define SERVER_MANAGER_ARGS				""
	#define ACCT_MANAGER_CMD_PATH			"Control Center\\TaAfsAccountManager.exe"
	#define ACCT_MANAGER_ARGS				""

	#define CELLSERVDB_FILENAME				"afsdcell.ini"

	#define SERVER  1
	#define CLIENT  2
	#define LCLIENT 4
	#define CC      8
	#define DOCS    16

		

//////////////////// installation declarations ///////////////////

typedef VERINFO
begin
	int nMajorVersion;
	int nMinorVersion;
	int nPatchLevel;
	int nBetaLevel;
	string szReleaseType[32];
	string szTitle[32];
end;


//	NOTE:	There is a problem with the IS registry set functionality in that if
//			you specify to write a value under an existing key, at uninstall time
//			not just the value will be removed, but the KEY AND ALL ITS SUBKEYS
//			will also be removed.  So the registry sets can only be used to
//			create entries in the registry that are for values under keys that
//			we create.
//
//			There are some values that we need to create that live under existing
//			NT keys, so when we create them we must turn off logging.  The
//			szNoLogRegistrySets tell us which to create without logging.

typedef APPINFO
begin
	string  szCompName[64];
	string  szCompanyName[64];
	string  szProductName[128];
	VERINFO Ver;						// Version of this product
	VERINFO iVer;						// Verison of this product that is already installed
	string  szProductKey[128];
	BOOL    bUseUninstDLL;
	string  szUninstDllName[64];
	string  szUninstLogfileName[64];
	string  szUninstKey[128];
	string  szAppPath[256];				// Below TARGETDIR
	string  szBinPath[256];				// Path to binaries and uninstall dll
	BOOL    bAddToPath;					// TRUE if bin path should be added to path env var
	string  szUninstDisplayName[128];
	string  szRegistrySets[256];		// Comma separated list of registry sets to install
	string  szNoLogRegistrySets[256];	// Comma separated list of registry sets to install without logging
	int     nInstallAction;
	BOOL    bInstallSucceeded;
end;



// ----- DLL function prototypes -----


// ----- DLL prototypes -----

     // your DLL prototypes
    prototype int InstallUtils.InstallServerService(string);
    prototype int InstallUtils.InstallClientService(string);
    prototype int InstallUtils.AddToPath(string);
	prototype int InstallUtils.AddToNetworkProviderOrder(string);
	prototype int InstallUtils.CheckIfAdmin();
	prototype int InstallUtils.SetSilentMode();
	prototype int InstallUtils.WriteToInstallErrorLog(string);
	prototype int InstallUtils.RestoreConfigInfo(int);
	prototype int InstallUtils.Eradicate34Client();
	prototype int InstallUtils.Upgrade34ClientConfigInfo();
    prototype int InstallUtils.IsWin98();
	prototype int InstallUtils.ShowLicense(string,string);


// ---- script function prototypes -----

    // generated by the Project Wizard
    prototype ShowDialogs();
    prototype MoveFileData();
    prototype HandleMoveDataError( NUMBER );
    prototype ProcessBeforeDataMove(APPINFO POINTER);
    prototype ProcessAfterDataMove();
    prototype SetupRegistry();
    prototype CleanUpInstall();
    prototype SetupInstall();
    prototype SetupScreen();
    prototype CheckRequirements();
    prototype DialogShowSdWelcome();
    prototype DialogShowSdAskDestPath();
    prototype DialogShowSdSetupType();
    prototype DialogShowSdSelectFolder();
    prototype DialogShowSdFinishReboot();

    // your script function prototypes
	prototype FixTargetPaths();
	prototype SetupAppInfo();
	prototype LocalizeComponents();
	prototype LocalizeComponentStatusText (STRING);
	prototype InstallApp(APPINFO POINTER);	
	prototype DialogShowSdAskComponentDialog();
	prototype ShowIsSelected(string);
	prototype ShowSelectedComponents();
	prototype ConfigClientService();
	prototype ConfigServerService();
	prototype AddPath(string);
	prototype AddBinPaths();
	prototype ConfigUninstallDLL(APPINFO POINTER);
	prototype CreateServerDirs();
	prototype SetUserVars();
	prototype SetNetworkProviderOrder();
	prototype CreateRegistrySets(string);
	prototype ConfigAfsCreds();
	prototype GetLicenseFilename(BYREF string);
	prototype GetNlsComps(BYREF string, BYREF string, BYREF string, BYREF string);
	prototype DetectInstalledComponents();
	prototype IsAppInstalled(APPINFO POINTER);
	prototype ProcessCompsOnCmdLn(string);
	prototype ParseCommandLine();
	prototype GetVersionNumber(string);
	prototype GetInstallAction(string, BOOL, string, string, string, string, APPINFO POINTER);
	prototype GetInstallActions();
	prototype ClientSelectedOrInstalled();
	prototype RenameUninstDll(APPINFO POINTER);	
	prototype RemoveInstalledBits(string);
	prototype PrepareForWSPPInstall();
	prototype CreateStartMenuEntries();
    prototype ShowError(string, int);
    prototype GetDateTimeString(BYREF string);
	prototype OnlyInstallingDocs();
	prototype CreateDirs();
	prototype AddShortCut(string, string, string, string);
	prototype CheckCopyCellServDB();
	prototype RestorePreviousConfigs();
	prototype RemoveCurrentVersion(APPINFO POINTER);
	prototype DoesConfigInfoExist(APPINFO POINTER);
	prototype UnselectComps();
    prototype AnyNonUpgradableSoftwareInstalled();
	prototype RemoveAllCurrentVersions();
	prototype AppVersionOk(BOOL, BOOL, APPINFO POINTER);
	prototype SetupVerInfo(APPINFO POINTER, string, string, string, string, string, string, BOOL);
	prototype NotUpgradable(APPINFO POINTER);
	prototype CompareVersions(APPINFO POINTER);

    // ----- global variables ------

    // generated by the Project Wizard
    BOOL        bWin95, bWin98, bWinNT, bIsShellExplorer, bInstallAborted, bIs32BitSetup;
    STRING      svDir;
    STRING      svName, svCompany, svSerial;
    STRING      svDefGroup;
    STRING      szAppPath;
    STRING      svSetupType;
	NUMBER		nResult;
	
    // your global variables
	APPINFO		appFullClient;
	APPINFO		appLightClient;
	APPINFO		appServer;
	APPINFO		appControlCenter;
    APPINFO     appDocs;
	APPINFO POINTER pApp;

	BOOL		bFullClientSel, bServerSel, bCcSel, bLightClientSel, bDocsSel;
	string		szCommonBinPath;
	string		szCodePage;
	BOOL		bClientInstalled, bServerInstalled, bCcInstalled, bLightClientInstalled, bDocsInstalled;
    string 		szLangComp, szReadmeComp, szDocsComp;

	// WSPP support vars
	BOOL 		bWSPPInstall;
	BOOL 		bPreinstallReplace;


////////////////////////////////////////////////////////////////////////////////
//
//   Function Name: Template
//
//     Description: This dialog will show a dialog template which can be
//                  used for creating any user-defined dialog with the
//                  Windows 95 look and feel.
//        Comments:
//
////////////////////////////////////////////////////////////////////////////////

number nvSection,nFileIsLocked;
STRING szTemp,szCellName;

#define IDC_HOMEPATH                    301
#define IDC_ROOTPATH                    302
#define IDC_HOMEDRIVELIST               1007
#define IDC_ROOTDRIVELIST               1008
#define IDC_ENABLEROOT                  1010
#define IDC_ENABLEHOME                  1011
#define IDC_INSTALL              		1011
#define IDC_WEB                         1016
#define IDC_CHECK_INSTALL               1018
#define IDC_CHECK_WEB                   1019
#define IDC_CHECK_BROWSEFILE            1020
#define IDC_CHECK_PREVIOUSFILE          1021
#define IDC_PREVIOUSFILE                1024
#define IDC_BROWSE                      1025
#define IDC_BROWSEFILE                  1026
#define DLG_TEMPLATE                    13029
#define DLG_DRIVEPATH                   13030
#define DLG_CELLSERVDB                  13031
#define IDC_PATH                        13032

prototype Logit(STRING);
function Logit(szMsg)
HWND handle;
begin
	return;
	OpenFileMode(FILE_MODE_APPEND);
 	if (OpenFile (handle, "y:\\dest", "silent.log") < 0) then
	    CreateFile(handle,"y:\\dest", "silent.log");
     endif;
 	WriteLine(handle,szMsg);
    CloseFile(handle);
end;

prototype Logitn(STRING,NUMBER);
function Logitn(szMsg,i)
HWND handle;
STRING sz;
begin
    Sprintf(sz,szMsg,i);
	Logit(sz);
end;
prototype INT GetWebDll.BrowseFile(NUMBER,BYREF STRING,BYREF STRING,NUMBER);
prototype INT GetWebDll.GetWebPage(BYREF STRING,BYREF STRING,BYREF STRING);
prototype INT GetWebDll.GetUserLogon(BYREF STRING);
prototype SetCellServDB(STRING,BYREF NUMBER,BYREF STRING,BYREF STRING,BYREF STRING,BYREF STRING);
prototype FormErrorMessage(NUMBER,BYREF STRING);
prototype SetHomeRoot( STRING,BYREF STRING,BYREF STRING,BYREF STRING,BYREF STRING );
prototype BOOL getWebCellSrvDB(STRING,STRING);

prototype BOOL GetDefaultDrive(BYREF NUMBER);
function GetDefaultDrive(listAv)
	NUMBER listAc;
	NUMBER I,nResult;
	STRING item,iitem;
begin
   listAc = ListCreate (STRINGLIST);
	Enable (STATUS);
	SetStatusWindow (50, "Scaning for available Drives...");
   	nResult=GetValidDrivesList (listAc, -1,-1);
	SetStatusWindow (100, "Completed.");
	Delay (2);
	if (nResult<0) then
	    SetStatusWindow(0, "");
		MessageBox ("Scan Drive Error" , SEVERE);
		abort;
	endif;
    SetStatusWindow(0, "");
   listAv = ListCreate (STRINGLIST);
   ListAddString(listAv,"None:",AFTER);
   ListGetFirstString(listAc, iitem);
	for I=67 to 90
		Sprintf(item,"%c",I);
		nResult=ListFindString(listAc,item);
		if nResult==END_OF_LIST then
			ListAddString(listAv,item+":",AFTER);
		endif;
		ListGetNextString(listAc,iitem);   	
   endfor;
    ListDestroy(listAc);
	return TRUE;
end;

function FormErrorMessage(nResult,szResult)
begin
	switch(nResult)
	case COPY_ERR_CREATEDIR:
		szResult=TARGETDIR+ "could not be created. Make sure that you have access rights to the target drive.";
	case COPY_ERR_MEMORY:
		szResult="The function was unable to allocate the memory required to complete the copy file process. Terminate as many running applications as possible to free memory.";
	case COPY_ERR_NODISKSPACE:
		szResult="The function could not find enough disk space on "+TARGETDIR+" to copy the files. Free disk space on the target drive.";
	case COPY_ERR_OPENINPUT:
		szResult="The function was unable to open the input file in "+SRCDIR+". Make sure the source file is a valid filename and that both the source file and target directory exist.";
	case COPY_ERR_OPENOUTPUT:
		szResult="The function was unable to copy the requested file.";
	case COPY_ERR_TARGETREADONLY:
		szResult="The file in "+TARGETDIR+" is read-only. Remove the read-only attribute from the target file and try again.";
	default:
		szResult="Unknown error";
	endswitch;
end;

function getWebCellSrvDB(szDefaultWeb,szDestFile)
	NUMBER nResult;
	STRING szFile,szErrMsg,szURL;
begin
	szErrMsg="                                                                 ";
	Enable (STATUS);
	SetStatusWindow (50, "Now Downloading CellServDB file...");
	CreateDir(TARGETDIR);
	nResult=GetWebPage(szErrMsg,szDestFile,szDefaultWeb);
	SetStatusWindow (100, "Downloading completed.");
	Delay (2);
	if (nResult!=0) then
	    SetStatusWindow(0, "");
		MessageBox (szErrMsg, INFORMATION);
		return FALSE;
	endif;
    // setup default status
    SetStatusWindow(0, "");
   return TRUE;
end;

// Transfer file to CELLSERVDB
prototype BOOL InstallCellServDB(NUMBER,STRING,STRING);
function InstallCellServDB(DefaultItem,szDefaultWeb,szDefaultBrowse)
STRING szFile,svErrorMessage;
begin
	switch (DefaultItem)
	case IDC_CHECK_WEB:
		nResult=getWebCellSrvDB(szDefaultWeb,TARGETDIR^@CELLSERVDB_CONFIGNAME);
	case IDC_CHECK_BROWSEFILE:
		// open file and copy to area
		ParsePath(szFile,szDefaultBrowse,PATH);
		SRCDIR=szFile;
		ParsePath(szFile,szDefaultBrowse,FILENAME);
		nResult=CopyFile ( szFile ,@CELLSERVDB_CONFIGNAME );
		if nResult < 0 then
		    if nResult = -1 then
		        MessageBox ( "CopyFile failed with error code -1!", WARNING );
		    else
		        FormErrorMessage(nResult,svErrorMessage);
		        SprintfBox ( WARNING, "",
		            "CopyFile failed!\n\nError code: %ld\nMessage text: %s",
		            nResult, svErrorMessage );
		    endif;
		    nResult=FALSE;
		 else
		 	nResult=TRUE;
		 endif;
	case IDC_CHECK_INSTALL:	//need to delete because install will never overwrite
		SRCDIR=SUPPORTDIR;
		nResult=CopyFile (@CELLSERVDB_CONFIGNAME,@CELLSERVDB_CONFIGNAME );
		if nResult < 0 then
		    if nResult = -1 then
		        MessageBox ( "CopyFile failed with error code -1!", WARNING );
		    else
		        FormErrorMessage(nResult,svErrorMessage);
		        SprintfBox ( WARNING, "",
		            "CopyFile failed!\n\nError code: %ld\nMessage text: %s",
			            nResult, svErrorMessage );
			    endif;
			nResult=FALSE;
		else
			nResult=TRUE;
		endif;
	case IDC_CHECK_PREVIOUSFILE:
		nResult=TRUE;// work is done, it will use previous file
	default:
		nResult=TRUE;
		;
	endswitch;
	return nResult;
end;

// Return TRUE if silent mode active
prototype BOOL SilentSetCellServDB(STRING,NUMBER,NUMBER,NUMBER,BYREF STRING,BYREF STRING);
function SilentSetCellServDB(szDlg,option,nResult,DefaultItem,szDefaultWeb,szDefaultBrowse)
STRING svSection,szTemp;
NUMBER nTemp;
begin
	switch (option)
	case 0:		//READ function
		if (MODE!=SILENTMODE) then
			return FALSE;
		endif;
		SdMakeName( svSection, szDlg, "", nvSection );
        SilentReadData( svSection, "Result", DATA_NUMBER,szTemp,nResult);
        if (nResult!=NEXT) then
        	return TRUE;
        endif;
   	    SilentReadData( svSection, "DefaultItem", DATA_NUMBER,szTemp,DefaultItem);
       	SilentReadData( svSection, "szDefaultWeb", DATA_STRING, szDefaultWeb,nTemp);
       	SilentReadData( svSection, "szDefaultBrowse", DATA_STRING,szDefaultBrowse,nTemp );
       	if (InstallCellServDB(DefaultItem,szDefaultWeb,szDefaultBrowse)==FALSE) then
	       	nResult=CANCEL;
		else
			nResult=NEXT;
       	endif;
		return TRUE;
	default:	//write
		SdMakeName( svSection, szDlg, "", nvSection );
        SilentWriteData( svSection, "Result", DATA_NUMBER,szTemp, nResult );
        SilentWriteData( svSection, "DefaultItem", DATA_NUMBER,szTemp, DefaultItem );
        SilentWriteData( svSection, "szDefaultWeb", DATA_STRING, szDefaultWeb,nTemp );
        SilentWriteData( svSection, "szDefaultBrowse", DATA_STRING, szDefaultBrowse,nTemp );
		return TRUE;		
    endswitch;
end;

function SetCellServDB( szTitle,DefaultItem,szPreviousInstall,szDefaultWeb,szDefaultBrowse,szDefaultInstall)
STRING  szDlg, szTemp,szResult[256],svErrorMessage,szFile,svSection;
NUMBER  bDone, nId, nMessage, nTemp,AvailableDrives,nResult;
INT     hwndDlg,hwndItem;

begin
        szDlg = "DLG_CELLSERVDB";
        // record data produced by this dialog
		if SilentSetCellServDB(szDlg,0,nResult,DefaultItem,szDefaultWeb,szDefaultBrowse) then
			return nResult;
		endif;

        // ensure general initialization is complete
        if (!bSdInit) then
           SdInit();
        endif;

        if (EzDefineDialog( szDlg, "", "",
                            DLG_CELLSERVDB ) = DLG_ERR) then
           return -1;
        endif;

        // Loop in dialog until the user selects a standard button
       	Disable(LOGGING);
		VarSave(SRCTARGETDIR);
		TARGETDIR=WINDIR;
		doagain:
        bDone = FALSE;

        while (!bDone)

           nId = WaitOnDialog( szDlg );
           hwndDlg = CmdGetHwndDlg( szDlg );

           switch(nId)

           case DLG_INIT:
                // Initialize List Control
                // set file
                CtrlSetState (szDlg, DefaultItem,BUTTON_CHECKED);
				if !Is(FILE_EXISTS,szPreviousInstall) then
					hwndItem = GetDlgItem( hwndDlg, IDC_CHECK_PREVIOUSFILE );
					EnableWindow( hwndItem, FALSE);
				endif;
				hwndItem = GetDlgItem( hwndDlg, IDC_PREVIOUSFILE );
				EnableWindow( hwndItem, DefaultItem==IDC_CHECK_PREVIOUSFILE);
				hwndItem = GetDlgItem( hwndDlg, IDC_BROWSEFILE );
				EnableWindow( hwndItem, DefaultItem==IDC_CHECK_BROWSEFILE);
				hwndItem = GetDlgItem( hwndDlg, IDC_BROWSE );
				EnableWindow( hwndItem, DefaultItem==IDC_CHECK_BROWSEFILE);
				hwndItem = GetDlgItem( hwndDlg, IDC_WEB );
				EnableWindow( hwndItem, DefaultItem==IDC_CHECK_WEB);
				hwndItem = GetDlgItem( hwndDlg, IDC_INSTALL );
				EnableWindow( hwndItem, DefaultItem==IDC_CHECK_INSTALL);
				CtrlSetText (szDlg, IDC_PREVIOUSFILE, szPreviousInstall);
				CtrlSetText (szDlg, IDC_BROWSEFILE, szDefaultBrowse);
				CtrlSetText (szDlg, IDC_WEB, szDefaultWeb);
				CtrlSetText (szDlg, IDC_INSTALL, szDefaultInstall);

                SdGeneralInit( szDlg, hwndDlg, STYLE_NORMAL, szSdProduct );
			
                //This function sets the caption for old style dialogs or
                //sets the text in the top banner area of win2k style dialogs
//                SdSetDlgTitle(szDlg, hwndDlg, szTitle); //Version 6.0 only

           case OK:
                nId    = NEXT;
                bDone  = TRUE;

           case BACK:
                nId    = BACK;
                bDone  = TRUE;

           case DLG_ERR:
                SdError( -1, "DLG_CELLSERVDB" );
                nId    = -1;
                bDone  = TRUE;

           case DLG_CLOSE:
                SdCloseDlg( hwndDlg, nId, bDone );

		   case IDC_BROWSE:
				szResult=szDefaultBrowse;
				szTitle="Select file to be used for CellServDB";
				nResult=BrowseFile(hwndDlg,szTitle,szResult,256);
				CtrlSetText (szDlg, IDC_BROWSEFILE, szResult);
				szDefaultBrowse=szResult;
			
		   case IDC_CHECK_BROWSEFILE:
				hwndItem = GetDlgItem( hwndDlg, IDC_BROWSEFILE );
				EnableWindow( hwndItem, TRUE);
				hwndItem = GetDlgItem( hwndDlg, IDC_BROWSE );
				EnableWindow( hwndItem, TRUE);
                CtrlSetState (szDlg, DefaultItem,BUTTON_UNCHECKED);
                CtrlSetState (szDlg, nId,BUTTON_CHECKED);
				switch (DefaultItem)
				case IDC_CHECK_WEB:
					hwndItem = GetDlgItem( hwndDlg, IDC_WEB );
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_PREVIOUSFILE:
					hwndItem = GetDlgItem( hwndDlg, IDC_PREVIOUSFILE );
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_INSTALL:
					hwndItem = GetDlgItem( hwndDlg, IDC_INSTALL);
					EnableWindow( hwndItem, FALSE);
				default:
					;
				endswitch;
				DefaultItem=nId;
		   case IDC_CHECK_INSTALL:
				hwndItem = GetDlgItem( hwndDlg, IDC_INSTALL );
				EnableWindow( hwndItem, TRUE);
                CtrlSetState (szDlg, DefaultItem,BUTTON_UNCHECKED);
                CtrlSetState (szDlg, nId,BUTTON_CHECKED);
				switch (DefaultItem)
				case IDC_CHECK_BROWSEFILE:
					hwndItem = GetDlgItem( hwndDlg, IDC_BROWSE );
					EnableWindow( hwndItem, FALSE);
					hwndItem = GetDlgItem( hwndDlg, IDC_BROWSEFILE );
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_WEB:
					hwndItem = GetDlgItem( hwndDlg, IDC_WEB );
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_PREVIOUSFILE:
					hwndItem = GetDlgItem( hwndDlg, IDC_PREVIOUSFILE );
					EnableWindow( hwndItem, FALSE);
				default:
					;
				endswitch;
				DefaultItem=nId;
		   case IDC_CHECK_WEB:
				hwndItem = GetDlgItem( hwndDlg, IDC_WEB );
				EnableWindow( hwndItem, TRUE);
                CtrlSetState (szDlg, DefaultItem,BUTTON_UNCHECKED);
                CtrlSetState (szDlg, nId,BUTTON_CHECKED);
				switch (DefaultItem)
				case IDC_CHECK_BROWSEFILE:
					hwndItem = GetDlgItem( hwndDlg, IDC_BROWSE );
					EnableWindow( hwndItem, FALSE);
					hwndItem = GetDlgItem( hwndDlg, IDC_BROWSEFILE );
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_INSTALL:
					hwndItem = GetDlgItem( hwndDlg, IDC_INSTALL);
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_PREVIOUSFILE:
					hwndItem = GetDlgItem( hwndDlg, IDC_PREVIOUSFILE );
					EnableWindow( hwndItem, FALSE);
				default:
					;
				endswitch;
				DefaultItem=nId;
		   case IDC_CHECK_PREVIOUSFILE:
				hwndItem = GetDlgItem( hwndDlg, IDC_PREVIOUSFILE );
				EnableWindow( hwndItem, TRUE);
                CtrlSetState (szDlg, DefaultItem,BUTTON_UNCHECKED);
                CtrlSetState (szDlg, nId,BUTTON_CHECKED);
				switch (DefaultItem)
				case IDC_CHECK_BROWSEFILE:
					hwndItem = GetDlgItem( hwndDlg, IDC_BROWSE );
					EnableWindow( hwndItem, FALSE);
					hwndItem = GetDlgItem( hwndDlg, IDC_BROWSEFILE );
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_INSTALL:
					hwndItem = GetDlgItem( hwndDlg, IDC_INSTALL);
					EnableWindow( hwndItem, FALSE);
				case IDC_CHECK_WEB:
					hwndItem = GetDlgItem( hwndDlg, IDC_WEB );
					EnableWindow( hwndItem, FALSE);
				default:
					;
				endswitch;
				DefaultItem=nId;
           default:
                // check standard handling
                 if (SdIsStdButton( nId ) && SdDoStdButton( nId )) then
                    bDone = TRUE;
                endif;
           endswitch;

        endwhile;

		CtrlGetText (szDlg, IDC_BROWSEFILE, szDefaultBrowse);
		CtrlGetText (szDlg, IDC_WEB, szDefaultWeb);
        if (nId != NEXT) then
			return nId;
		endif;
       	if InstallCellServDB(DefaultItem,szDefaultWeb,szDefaultBrowse)==FALSE then
       		goto doagain;
 		endif;
        EndDialog( szDlg );
        ReleaseDialog( szDlg );
		VarRestore(SRCTARGETDIR);
		Enable(LOGGING);
        SdUnInit( );
        // record data produced by this dialog
		SilentSetCellServDB(szDlg,1,nId,DefaultItem,szDefaultWeb,szDefaultBrowse);
        return nId;
end;

////////////////////////////////////////////////////////////////////////////////
//
//   Function Name: Template
//
//     Description: This dialog will show a dialog template which can be
//                  used for creating any user-defined dialog with the
//                  Windows 95 look and feel.
//        Comments:
//
////////////////////////////////////////////////////////////////////////////////

prototype BOOL GetUser(BYREF STRING);

function GetUser(sUser)
	NUMBER nResult;
begin
	sUser="                                                                 ";
	nResult=GetUserLogon(sUser);
	if (nResult!=1) then
		sUser="";
	endif;
	return (nResult==1);
end;


prototype BOOL SetDriveMaps(STRING,STRING,STRING,STRING,STRING);
function SetDriveMaps(szPath,szRootDrive,szRootPath,szHomeDrive,szHomePath)
HWND   handle;
begin
	VarSave(SRCTARGETDIR);
	DeleteFile("afsdsbmt.ini");
	VarRestore(SRCTARGETDIR);
    CreateFile(handle, szPath, "afsdsbmt.ini");
    WriteLine(handle, "[AFS Submounts]");
   	if (StrLength(szRootDrive)==2) then
   		WriteLine(handle, "all="+szRootPath);
   	endif;
    if (StrLength(szHomeDrive)==2) then
   		WriteLine(handle, "home=" + szHomePath);
   	endif;
   	WriteLine(handle, "[AFS Mappings]");
   	if (StrLength(szRootDrive)>0) then
   		WriteLine(handle, szRootDrive+"="+szRootPath);
    endif;
   	if (StrLength(szHomeDrive)>0) then
   		WriteLine(handle, szHomeDrive+"="+szHomePath);
    endif;
   	CloseFile(handle);
end;

// Return TRUE if silent mode active
prototype BOOL SilentSetHomeRoot(STRING,NUMBER,NUMBER,BYREF STRING,BYREF STRING,BYREF STRING,BYREF STRING);
function SilentSetHomeRoot(szDlg,option,nResult,szRootDrive,szRootPath,szHomeDrive,szHomePath)
STRING svSection,szTemp,szTPath,szTShare,szTDrive,szLogname;
NUMBER nTemp,nCount,I;
HWND   handle;
begin
	Logitn("SilentSetHomeRoot option=%i",option);
	switch (option)
	case 0:		//READ function
		if (MODE!=SILENTMODE) then
			return FALSE;
		endif;			// this section is a little more complicated, allowing installation of n mappings
		SdMakeName( svSection, szDlg, "", nvSection );
		Logit("SdMakeName="+svSection);
        SilentReadData( svSection, "Result", DATA_NUMBER,szTemp,nResult);
       	Logitn("nResult=%i",nResult);
        if (nResult!=NEXT) then
        	return TRUE;
        endif;
        Logit("Do count");
       	SilentReadData( svSection, "Count", DATA_NUMBER, szTemp,nCount);
       	Logitn("nCount=%i",nCount);
       	if nCount==0 then
       		return TRUE;
       	endif;
		VarSave(SRCTARGETDIR);
		TARGETDIR=WINDIR;
		DeleteFile("afsdsbmt.ini");
		VarRestore(SRCTARGETDIR);
	    CreateFile(handle, WINDIR, "afsdsbmt.ini");
    	WriteLine(handle, "[AFS Submounts]");
       	for I=0 to nCount-1
	       	Logitn("I=%i",I);       	
       		Sprintf(szTemp,"Path_%i",I);
       		Logit("Path="+szTemp);       		
	       	SilentReadData( svSection, szTemp, DATA_STRING, szTPath,nTemp);
       		Logit("TPath="+szTPath);       		
	       	if (szTPath % "%LOGINNAME%") then
	       		//Replace loginname with actual loging name
				nTemp=StrFind(szTPath,"%LOGINNAME%");
				StrSub(szTemp,szTPath,nTemp+11,StrLength(szTPath));
				StrSub(szTPath,szTPath,0,nTemp);
			    if (GetUser(szLogname)) then
					szTPath=szTPath+szLogname+szTemp;
				endif;
	       	endif;
       		Sprintf(szTemp,"Share_%i",I);
	       	SilentReadData( svSection, szTemp, DATA_STRING, szTShare,nTemp);
	   		WriteLine(handle, szTShare+"="+szTPath);
       	endfor;
	   	WriteLine(handle, "[AFS Mappings]");
       	for I=0 to nCount-1
       		Sprintf(szTemp,"Drive_%i",I);
	       	SilentReadData( svSection, szTemp, DATA_STRING, szTDrive,nTemp);
       		Sprintf(szTemp,"Path_%i",I);
	       	SilentReadData( svSection, szTemp, DATA_STRING, szTPath,nTemp);
	       	if (szTPath % "%LOGINNAME%") then
	       		//Replace loginname with actual loging name
				nTemp=StrFind(szTPath,"%LOGINNAME%");
				StrSub(szTemp,szTPath,nTemp+11,StrLength(szTPath));
				StrSub(szTPath,szTPath,0,nTemp);
			    if (GetUser(szLogname)) then
					szTPath=szTPath+szLogname+szTemp;
				endif;
	       	endif;
	   		WriteLine(handle, szTDrive+"="+szTPath);
       	endfor;
	    CloseFile(handle);
		nResult=NEXT;
		return TRUE;
	default:	//write
		SdMakeName( svSection, szDlg, "", nvSection );
		nCount=0;
        SilentWriteData( svSection, "Result", DATA_NUMBER,szTemp, nResult );
        if (StrLength(szRootDrive)==2) then
       		Sprintf(szTemp,"Drive_%i",nCount);
	        SilentWriteData( svSection,szTemp, DATA_STRING,szRootDrive, nTemp );//root drive
       		Sprintf(szTemp,"Path_%i",nCount);
	        SilentWriteData( svSection,szTemp, DATA_STRING,szRootPath, nTemp );//root drive
       		Sprintf(szTemp,"Share_%i",nCount);
	        SilentWriteData( svSection,szTemp, DATA_STRING,"all", nTemp );//root drive
	        nCount++;
	    endif;
        if (StrLength(szHomeDrive)==2) then
       		Sprintf(szTemp,"Drive_%i",nCount);
	        SilentWriteData( svSection,szTemp, DATA_STRING,szHomeDrive, nTemp );//root drive
       		Sprintf(szTemp,"Path_%i",nCount);
	        SilentWriteData( svSection,szTemp, DATA_STRING,szHomePath, nTemp );//root drive
       		Sprintf(szTemp,"Share_%i",nCount);
	        SilentWriteData( svSection,szTemp, DATA_STRING,"home", nTemp );//root drive
        	nCount++;
        endif;
        SilentWriteData( svSection, "Count", DATA_NUMBER,szTemp, nCount );	// only two can be defined through Dialog box
		SetDriveMaps(WINDIR,szRootDrive,szRootPath,szHomeDrive,szHomePath);
		return TRUE;		
    endswitch;
end;

function SetHomeRoot( szTitle,szRootDrive,szRootPath,szHomeDrive,szHomePath )

STRING  szDlg, szTemp,svSection;
NUMBER  bDone, nId, nMessage, nTemp,AvailableDrives,nResult;
INT     hwndDlg,hwndItem,hwndItem2;

begin
       szDlg = "DLG_DRIVEPATH";

        // record data produced by this dialog
		Logit("SetHomeRoot");
		if SilentSetHomeRoot(szDlg,0,nResult,szRootDrive,szRootPath,szHomeDrive,szHomePath ) then
			return nResult;
		endif;

		GetDefaultDrive(AvailableDrives);
         // ensure general initialization is complete
        if (!bSdInit) then
           SdInit();
        endif;

        if (EzDefineDialog( szDlg, "", "",
                            DLG_DRIVEPATH ) = DLG_ERR) then
           return -1;
        endif;

        // Loop in dialog until the user selects a standard button
        bDone = FALSE;

        while (!bDone)

           nId = WaitOnDialog( szDlg );

           switch(nId)

           case DLG_INIT:
                hwndDlg = CmdGetHwndDlg( szDlg );
                // Initialize List Control
        		nResult=CtrlSetList( szDlg, IDC_HOMEDRIVELIST, AvailableDrives );
	            if (nResult != 0) then
	               // Handle error from CtrlSetList.
	               MessageBox ("Unable to create folder name list.", SEVERE);
	               bDone = TRUE;
	            endif;
				if (CtrlSetCurSel(szDlg,IDC_HOMEDRIVELIST,szHomeDrive)!=0) then
					szHomeDrive="None:";
					CtrlSetCurSel(szDlg,IDC_HOMEDRIVELIST,szHomeDrive);
				endif;

        		nResult=CtrlSetList( szDlg, IDC_ROOTDRIVELIST, AvailableDrives );
	            if (nResult != 0) then
	               // Handle error from CtrlSetList.
	               MessageBox ("Unable to create folder name list.", SEVERE);
	               bDone = TRUE;
	            endif;
				if (CtrlSetCurSel(szDlg,IDC_ROOTDRIVELIST,szRootDrive)!=0) then
					szRootDrive="None:";
					CtrlSetCurSel(szDlg,IDC_ROOTDRIVELIST,szRootDrive);
				endif;

        		nResult=CtrlSetText( szDlg, IDC_ROOTPATH,szRootPath );
	            if (nResult != 0) then
	               MessageBox ("Unable to create szRootPath.", SEVERE);
	               bDone = TRUE;
	            endif;
        		nResult=CtrlSetText( szDlg, IDC_HOMEPATH,szHomePath );
	            if (nResult != 0) then
	               MessageBox ("Unable to create szHomePath.", SEVERE);
	               bDone = TRUE;
	            endif;

                CtrlSetState (szDlg, IDC_ENABLEHOME,BUTTON_CHECKED);
                CtrlSetState (szDlg, IDC_ENABLEROOT,BUTTON_CHECKED);
                SdGeneralInit( szDlg, hwndDlg, STYLE_NORMAL, szSdProduct );
			
                //This function sets the caption for old style dialogs or
                //sets the text in the top banner area of win2k style dialogs
           case OK:
           		if (szRootDrive!=szHomeDrive) then
	                nId    = NEXT;
	                bDone  = TRUE;
	            else
	            	MessageBox("Home and Root drives cannot be the same",WARNING);
                endif;

           case BACK:
                nId    = BACK;
                bDone  = TRUE;

           case DLG_ERR:
                SdError( -1, "DLG_DRIVEPATH" );
                nId    = -1;
                bDone  = TRUE;

           case DLG_CLOSE:
                SdCloseDlg( hwndDlg, nId, bDone );

		   case IDC_ENABLEROOT:
		   	
				hwndItem = GetDlgItem( hwndDlg, IDC_ROOTDRIVELIST );//get handle of control in custom dialog box
				hwndItem2 = GetDlgItem( hwndDlg, IDC_ROOTPATH );//get handle of control in custom dialog box
				if (CtrlGetState (szDlg, nId)==BUTTON_CHECKED) then
					EnableWindow( hwndItem2, TRUE);
					EnableWindow( hwndItem, TRUE);
				else
					EnableWindow( hwndItem2, FALSE);
					EnableWindow( hwndItem, FALSE);
				endif;
		   case IDC_ENABLEHOME:
				hwndItem = GetDlgItem( hwndDlg, IDC_HOMEDRIVELIST );//get handle of control in custom dialog box
				hwndItem2 = GetDlgItem( hwndDlg, IDC_HOMEPATH );//get handle of control in custom dialog box
				if (CtrlGetState (szDlg, nId)==BUTTON_CHECKED) then
					EnableWindow( hwndItem2, TRUE);
					EnableWindow( hwndItem, TRUE);
				else
					EnableWindow( hwndItem2, FALSE);
					EnableWindow( hwndItem, FALSE);
				endif;

           case IDC_HOMEDRIVELIST:
				;
           case IDC_ROOTDRIVELIST:
				;
           case IDC_HOMEPATH:
        		CtrlGetText (szDlg, nId,szHomePath);

           case IDC_ROOTPATH:
        		CtrlGetText (szDlg, nId,szRootPath);

           default:
                // check standard handling
                 if (SdIsStdButton( nId ) && SdDoStdButton( nId )) then
                    bDone = TRUE;
                endif;
           endswitch;

        endwhile;

		CtrlGetCurSel (szDlg, nId, szRootDrive);
		if (CtrlGetState (szDlg, IDC_ENABLEROOT)==BUTTON_UNCHECKED) then
	        szRootDrive="None:";
		endif;
		CtrlGetCurSel (szDlg, nId, szHomeDrive);
		if (CtrlGetState (szDlg, IDC_ENABLEHOME)==BUTTON_UNCHECKED) then
	        szHomeDrive="None:";
		endif;
        EndDialog( szDlg );
        ReleaseDialog( szDlg );

        SdUnInit( );

        // record data produced by this dialog
        if (nId==NEXT) then
			SilentSetHomeRoot(szDlg,1,nId,szRootDrive,szRootPath,szHomeDrive,szHomePath );
		endif;
        ListDestroy (AvailableDrives);
        return nId;

end;


// ---- script function prototypes -----


    // your script function prototypes



///////////////////////////////////////////////////////////////////////////////
//
//   MAIN PROGRAM
//
//      The setup begins here by hiding the visible setup
//      window.  This is done to allow all the titles, images, etc. to
//      be established before showing the main window.  The setup is
//      then performed in a series of calls to script defined functions,
//      with error checking at each step.
//
///////////////////////////////////////////////////////////////////////////////
program
	Logit("Begin");
	nvSection=0;
    Disable( BACKGROUND );
	if (UseDLL(SUPPORTDIR ^ SETUP_UTILS_DLL_PATH) < 0) then
        ShowError(@SETUPUTILS_NOT_FOUND, SEVERE);
        bInstallAborted = TRUE;
        goto end_install;
    endif;
	Logit("UseDLL1");
	ChangeDirectory (SUPPORTDIR);
	if (UseDLL("GetWebDLL.dll") != 0) then
		MessageBox ("DLL failed.\n\nCouldn't load"+SUPPORTDIR^"GetWebDLL.dll", INFORMATION);
		abort;
	endif;
	Logit("UseDLL2");
		
	SetupInstall();
	Logit("SetupInstall");
	
    CheckRequirements();
	Logit("CheckRequirements");
	
	ParseCommandLine();
	Logit("ParseCommandLine");
		
	SetupAppInfo();
	Logit("SetupAppInfo");
	
	LocalizeComponents();
	Logit("LocalizeComponents");
	
	DetectInstalledComponents();
	Logit("DetectInstalledComponents");
	
	// Can't upgrade, downgrade, or reinstall the light client, so if it is
	// already installed, we must abort.  This is because on Win9x, we can't
	// move in-use files, and so we can't silently uninstall the light client,
	// which upgrade, downgrade, and reinstall require.
	if (bLightClientInstalled && !bWinNT) then
		ShowError(@LIGHT_CLIENT_ALREADY_INSTALLED_MSG, SEVERE);
		bInstallAborted = TRUE;
		goto end_install;
	endif;

	if (AnyNonUpgradableSoftwareInstalled()) then
		ShowError(@NON_UPGRADABLE_SOFTWARE_INSTALLED_ERROR_MSG, SEVERE);
		bInstallAborted = TRUE;
		goto end_install;
	endif;

	GetInstallActions();

	if (bWSPPInstall) then
		SetSilentMode();	// Tells the InstallUtils dll to run silently
		PrepareForWSPPInstall();
	else
		// Ask user what to install
		SetupScreen();
    	if (ShowDialogs()<0) goto end_install;
    endif;

	// The AFS path must not contain spaces.  AFS code will break if it does.
	LongPathToShortPath(TARGETDIR);

	// Determine which comps to install to get the proper NLS files.
    GetNlsComps(szLangComp, szReadmeComp, szDocsComp, szCodePage);

	SetUserVars();

	CreateDirs();

	// Uninstall current versions before we install
	RemoveAllCurrentVersions();

	// Install the Client
	if (bFullClientSel) then
		RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
		Enable(LOGGING);
		if RegDBSetKeyValueEx ("SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters"	
			,"SmbDeviceEnabled", REGDB_NUMBER, "0", 8) < 0 then
			MessageBox ("RegDBCreateKeyEx failed.", SEVERE);
		    abort;
		endif;
		pApp = &appFullClient;
		if (InstallApp(pApp) < 0) goto end_install;
	endif;
        if RegDBSetKeyValueEx("SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters","Cell", REGDB_STRING, szCellName, -1) < 0 then
             MessageBox ("RegDBCreateKeyEx failed.", SEVERE);
             abort;
        endif;
	// Install the Light Client
	if (bLightClientSel) then
		pApp = &appLightClient;
		if (InstallApp(pApp) < 0) goto end_install;
		if (bWin95) then
			EzBatchAddString(LIGHT95_CLIENT_PROTSEQ, "", AFTER | REPLACE);
		endif;
	endif;

	// Install the Server
	if (bServerSel) then
		pApp = &appServer;
		if (InstallApp(pApp) < 0) goto end_install;
		CreateServerDirs();
	endif;

	// Install the Control Center
	if (bCcSel) then
		pApp = &appControlCenter;
		if (InstallApp(pApp) < 0) goto end_install;
	endif;

	// Install the Docs
	if (bDocsSel) then
		appDocs.szCompName = szDocsComp;
		pApp = &appDocs;
		if (InstallApp(pApp) < 0) goto end_install;
	endif;

	// If we installed the server, then configure the bos service
	if (bServerSel) then
		if (ConfigServerService() < 0) goto end_install;
	endif;

	// If we installed the full client, then configure the client service
	// and add the NetworkProviderOrder value.
	if (bFullClientSel) then
		if (ConfigClientService() < 0) goto end_install;
        // I'm commenting out the line below.  This will result in integrated
        // login being off after an install.  If you want it to be on after an
        // install, then uncomment the line.
		// if (SetNetworkProviderOrder() < 0) goto end_install;
	endif;

	if (bFullClientSel || bLightClientSel) then
		ConfigAfsCreds();
	endif;

	RestorePreviousConfigs();

	AddPath(szCommonBinPath);

    // If not only installing docs, then set BATCH_INSTALL to true,
    // which will cause setup to want to reboot the computer.
	if (OnlyInstallingDocs() == FALSE) then
		BATCH_INSTALL = TRUE;
	endif;

	CreateStartMenuEntries();

//	if (bFullClientSel || bLightClientSel || bCcSel) then
//		CheckCopyCellServDB();
//	endif;

	end_install:

	UnUseDLL(SUPPORTDIR^"GetWebDLL.dll");
	UnUseDLL(SUPPORTDIR ^ SETUP_UTILS_DLL_PATH);

    CleanUpInstall();

    // If an unrecoverable error occurred, clean up
    // the partial installation. Otherwise, exit normally.
    if (bInstallAborted) then
        abort;
    endif;

endprogram

///////////////////////////////////////////////////////////////////////////////
//
// Function:  ShowDialogs
//
//  Purpose:  This function manages the display and navigation of
//            the standard dialogs that exist in a setup.
//
///////////////////////////////////////////////////////////////////////////////
function ShowDialogs()
    NUMBER  nResult,handle;
    STRING	szTargetLicense;
    STRING	szSourceLicense;
	STRING sRootDrive,sHomeDrive,userID,rootPath,homePath;
	NUMBER 	DefaultItem;
	STRING  szDefaultWeb,szDefaultBrowse,szDefaultInstall,szPreviousInstall;
	STRING  szResult[256],svResult;
begin
    Dlg_Start:
    // beginning of dialogs label
    Dlg_SdWelcome:
    nResult = DialogShowSdWelcome();
    if (nResult = BACK) goto Dlg_Start;

    Dlg_License:
//    szTargetLicense = DOCUMENTATION_LICENSE_PATH;
//    GetLicenseFilename (szSourceLicense);
//	Logit("ShowLicense");
//	Disable( DIALOGCACHE );
//	if (MODE!=SILENTMODE) then
//	    nResult = ShowLicense(szTargetLicense,szSourceLicense);
//	    if (nResult = 0) then
//	    	abort;
//	    endif;
//	    Enable( DIALOGCACHE );
//	endif;
    if (nResult = BACK) goto Dlg_Start;
	Dlg_SdCompDlg:
	nResult = DialogShowSdAskComponentDialog();
	Logit("DialogShowSdAskComponentDialog");
	if (nResult = BACK) goto Dlg_License;

    Dlg_SdSelectFolder:
    nResult = DialogShowSdSelectFolder();
	Logit("DialogShowSdSelectFolder");
	if (nResult = BACK) goto Dlg_SdCompDlg;
	if (bFullClientSel || bLightClientSel) then
		szDefaultWeb=@CELLSERVDB_WEB;
		szDefaultBrowse=TARGETDIR^"*";
		szDefaultInstall=@CELLSERVDB_INSTALL;
		szPreviousInstall=WINDIR^@CELLSERVDB_CONFIGNAME;
	    if (Is(FILE_EXISTS,szPreviousInstall)) then
			DefaultItem=IDC_CHECK_PREVIOUSFILE;
		else
			DefaultItem=IDC_CHECK_INSTALL;
		endif;
		Dlg_SdSelectCellServDB:
			Logit("SetCellServDB-next");
			nResult =SetCellServDB("Select AFS Cell Data base (afsdcell.ini)"
			,DefaultItem
			,szPreviousInstall
			,szDefaultWeb
			,szDefaultBrowse
			,szDefaultInstall);
		Logit("SetCellServDB");
	    if (nResult=BACK) goto Dlg_SdSelectFolder;
            Dlg_SdSelectCellName:
            nResult=SdShowDlgEdit1 ("Select AFS Cell Name","A valid cell name should be entered here.\nIf you don't know your cell name, you may enter one after installation using the AFS Control Center.","Enter Cell Name:", szCellName);
            if (nResult = BACK) goto Dlg_SdSelectCellName;
		if (Is(FILE_EXISTS, WINDIR^"afsdsbmt.ini")) then
			Logit("AskYesNo next");
			if (AskYesNo("Previous Drive Mapping Configuration already exist.\n\nPress Yes to keep previous configuration\nPress No to change previous configuration.",YES)=YES) then
				return 0;
			endif;
		endif;
		userID="                   ";
	    GetUser(userID);
		sRootDrive="Z:";
		sHomeDrive="U:";
	   	rootPath="/";
	    homePath = "/afs/" + szCellName + "/u/" + userID;
	    nResult=SetHomeRoot( "Home and Root Drive Assignment\nThese drives will be mapped each time AFS is connected!",sRootDrive,rootPath,sHomeDrive,homePath );
		Logit("SetHomeRoot");
		if (nResult = BACK) goto Dlg_SdSelectCellServDB;
	endif;
	Logit("ShowDialogs-done");
	return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: NotUpgradable
//
//  Purpose: This function will return TRUE if the passed in version is not
//           upgradable.
//
///////////////////////////////////////////////////////////////////////////////
function NotUpgradable(pApp)
begin
	// The 3.5 beta is not upgradable
//	if ((pApp->iVer.nMajorVersion = 3) && (pApp->iVer.nMinorVersion = 5) && (pApp->iVer.nPatchLevel = 0) && (pApp->iVer.szReleaseType = RELEASE_TYPE_BETA)) then
//		return TRUE;
//	endif;
	
	return FALSE;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: AnyNonUpgradableSoftwareInstalled
//
//  Purpose: This function will return TRUE if any non-upgradable software is
//           installed.
//
///////////////////////////////////////////////////////////////////////////////
function AnyNonUpgradableSoftwareInstalled()
begin
	if (NotUpgradable(&appFullClient) ||
	    NotUpgradable(&appServer) ||
		NotUpgradable(&appControlCenter) ||
		NotUpgradable(&appLightClient) ||
		NotUpgradable(&appDocs))
	then
		return TRUE;
	endif;
	
	return FALSE;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: UnselectComps
//
//  Purpose: This function unselects all of the componenets so that we can
//           completely control what gets installed.  We will select each
//           component at the time when we want to install it.
//
///////////////////////////////////////////////////////////////////////////////
function UnselectComps()
begin
	ComponentSelectItem(MEDIA, SERVER_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, CLIENT_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LIGHT_CLIENT_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, CC_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_ENGLISH_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_SIMP_CHINESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_TRAD_CHINESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_KOREAN_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_JAPANESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_GERMAN_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_SPANISH_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, LANG_PORTUGUESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_ENGLISH_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_JAPANESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_KOREAN_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_SIMP_CHINESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_TRAD_CHINESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_GERMAN_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_SPANISH_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, README_PORTUGUESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_ENGLISH_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_JAPANESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_KOREAN_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_SIMP_CHINESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_TRAD_CHINESE_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_GERMAN_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_SPANISH_COMP_NAME, FALSE);
	ComponentSelectItem(MEDIA, DOCS_PORTUGUESE_COMP_NAME, FALSE);
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: DoesConfigInfoExist
//
//  Purpose: This function determines if config info exists for an app.
//
///////////////////////////////////////////////////////////////////////////////
function DoesConfigInfoExist(pApp)
begin
	RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);

	if (RegDBKeyExist(CONFIG_INFO_KEY ^ pApp->szProductName) = 1) then
		return TRUE;
	endif;
	
	return FALSE;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: RestorePreviousConfigs
//
//  Purpose: This function restores config info for the apps we just installed.
//
///////////////////////////////////////////////////////////////////////////////
function RestorePreviousConfigs()
begin
	if (appServer.bInstallSucceeded && DoesConfigInfoExist(&appServer)) then
		RestoreConfigInfo(SERVER);
	endif;

    if (appFullClient.bInstallSucceeded) then
        if (appFullClient.iVer.szTitle = "3.4a") then
            Upgrade34ClientConfigInfo();
        elseif (DoesConfigInfoExist(&appFullClient) = TRUE) then
		    RestoreConfigInfo(CLIENT);
		endif;
	endif;

	if (appLightClient.bInstallSucceeded && DoesConfigInfoExist(&appLightClient)) then
		RestoreConfigInfo(LCLIENT);
	endif;
	
	// Only restore control center info if client not installed
	if (appControlCenter.bInstallSucceeded && !bClientInstalled && !appFullClient.bInstallSucceeded
		&& DoesConfigInfoExist(&appControlCenter))
	then
		RestoreConfigInfo(CC);
	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: OnlyInstallingDocs
//
//  Purpose: This function determines if only the doc files are being installed.
//
///////////////////////////////////////////////////////////////////////////////
function OnlyInstallingDocs()
begin
	if (!bServerSel && !bFullClientSel && !bLightClientSel && !bCcSel && bDocsSel) then
		return TRUE;
	endif;
	
	return FALSE;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: CreateDirs
//
//  Purpose: This function creates directories that we don't want IS to make.
//
///////////////////////////////////////////////////////////////////////////////
function CreateDirs()
begin
	// Turn off logging.  It shouldn't be on when this func is called, but we
	// turn it off anyway just to make sure.  We turn it off so that IS won't
	// try to delete the dirs we are about to make during an uninstall.  If
	// we don't do this, then the first app installed that uses one of these
	// dirs will think that it owns that dir and won't know that other apps
	// are sharing it.
	Disable(LOGGING);

	// Create the target dir and the shared dirs
	CreateDir(TARGETDIR);
	CreateDir(TARGETDIR ^ "Documentation");
	CreateDir(TARGETDIR ^ "Documentation\\Html");
	CreateDir(TARGETDIR ^ "Documentation\\Html\\InstallGd");
	CreateDir(TARGETDIR ^ "Documentation\\Html\\ReleaseNotes");

	// We need to manually create the Server dir so that if we have to leave
	// it behind during an uninstall (so that config info is preserved), IS
	// won't complain that it can't be deleted.
	if (bServerSel) then
		CreateDir(TARGETDIR ^ "Server\\usr\\afs\\bin");
	endif;

    // Docs don't use the common dir
	if (OnlyInstallingDocs() = FALSE) then
		CreateDir(TARGETDIR ^ "Common");
	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: PrepareForWSPPInstall
//
//  Purpose: This function decides what to install when doing a WSPP install.
//
///////////////////////////////////////////////////////////////////////////////
function PrepareForWSPPInstall()
begin
	SHELL_OBJECT_FOLDER = @WSPP_FOLDER_NAME;

	// Never install the Docs during a WSPP install
	appDocs.nInstallAction = ACTION_NONE;

	// If we have been told to replace any preinstalled software, then set
	// our reinstall mechanism in motion.
	if (bPreinstallReplace) then
		if (bCcInstalled && bCcSel) then
			appControlCenter.nInstallAction = ACTION_REINSTALL;
		endif;
		if (bClientInstalled && bFullClientSel) then
			appFullClient.nInstallAction = ACTION_REINSTALL;
		endif;
		if (bServerInstalled && bServerSel) then
			appServer.nInstallAction = ACTION_REINSTALL;
		endif;
		if (bLightClientInstalled && bLightClientSel) then
			appLightClient.nInstallAction = ACTION_REINSTALL;
		endif;
	else
		// If we have been told to not install something that is already
		// installed, then do just that.
		if (bCcInstalled && bCcSel) then
			bCcSel = FALSE;
		endif;
		if (bClientInstalled && bFullClientSel) then
			bFullClientSel = FALSE;
		endif;
		if (bServerInstalled && bServerSel) then
			bServerSel = FALSE;
		endif;
		if (bLightClientInstalled && bLightClientSel) then
			bLightClientSel = FALSE;
		endif;
	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: RemoveCurrentVersion
//
//  Purpose: This function removes the currently installed version of the app.
//			 It provides a message to the user so they know what is going on.
//
///////////////////////////////////////////////////////////////////////////////
function RemoveCurrentVersion(pApp)
	string szMsg;
	string szFormat;
begin
	szFormat = "";

	switch(pApp->nInstallAction)
		case ACTION_REINSTALL:	szFormat = @REINSTALL_PREP_MSG;
		case ACTION_UPGRADE:	szFormat = @UPGRADE_PREP_MSG;
		case ACTION_DOWNGRADE:	szFormat = @DOWNGRADE_PREP_MSG;
	endswitch;

	if (szFormat == "") then
		return;
	endif;
	
	Sprintf(szMsg, szFormat, pApp->szProductName);
	
	if (!bWSPPInstall) then
   		SdShowMsg(szMsg, TRUE);
   	endif;

	RemoveInstalledBits(pApp->szProductName);

	if (!bWSPPInstall) then
   		SdShowMsg(szMsg, FALSE);
   	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: RemoveAllCurrentVersions
//
// Purpose: This function removes the current install of all apps that are
//          begin reinstalled, upgraded, or downgraded.
//
///////////////////////////////////////////////////////////////////////////////
function RemoveAllCurrentVersions()
begin
	if (bFullClientSel) then	
		RemoveCurrentVersion(&appFullClient);
	endif;
	
	if (bServerSel) then
		RemoveCurrentVersion(&appServer);
	endif;
	
	if (bCcSel) then
		RemoveCurrentVersion(&appControlCenter);
	endif;
	
	if (bLightClientSel) then
		RemoveCurrentVersion(&appLightClient);
	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: InstallApp
//
// Purpose: This function installs an application that is part of a suite.
//
///////////////////////////////////////////////////////////////////////////////
function InstallApp(pApp)
	NUMBER nResult;
begin
	if (pApp->nInstallAction = ACTION_NONE) then
		return 0;
	endif;

	// Start fresh with nothing selected
	UnselectComps();

	// Select the comps we want to install.  We will install the passed in app
	// as well as the comps that are shared by all the apps.  Because of weird
	// IS stuff, the app comp must be selected last else IS will autoselect
	// things we don't want.
	ComponentSelectItem(MEDIA, szReadmeComp, TRUE);

	// Lang comps are shared by all apps except the docs app
	if (pApp != &appDocs) then
		ComponentSelectItem(MEDIA, szLangComp, TRUE);
	endif;

    // Select the app's component
    ComponentSelectItem(MEDIA, pApp->szCompName, TRUE);

//	MessageBox("Install app: " + pApp->szCompName, INFORMATION);

    nResult = ProcessBeforeDataMove(pApp);
    if (nResult < 0) goto error;

    nResult = MoveFileData();
    if (nResult < 0) goto error;

    nResult = ProcessAfterDataMove();
    if (nResult < 0) goto error;
	
	nResult = CreateRegistrySets(pApp->szRegistrySets);
	if (nResult < 0) goto error;

	Disable(LOGGING);

	nResult = CreateRegistrySets(pApp->szNoLogRegistrySets);
	if (nResult < 0) goto error;

	nResult = ConfigUninstallDLL(pApp);
	if (nResult < 0) goto error;

	AddPath(pApp->szBinPath);

	// Now unselect it again
	ComponentSelectItem(MEDIA, pApp->szCompName, FALSE);

	pApp->bInstallSucceeded = TRUE;

	return 0;
	
error:
	return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: ProcessBeforeDataMove
//
//  Purpose: This function performs any necessary operations prior to the
//           actual file transfer.
//
///////////////////////////////////////////////////////////////////////////////
function ProcessBeforeDataMove(pApp)
    STRING svLogFile;
    NUMBER nResult;
begin
  	// Create app information and App Paths registry keys.
    InstallationInfo(pApp->szCompanyName, pApp->szProductName, pApp->Ver.szTitle, pApp->szProductKey);

    svLogFile = pApp->szUninstLogfileName;

    // Create the uninstall reg key and open the log file
    nResult = DeinstallStart(TARGETDIR, svLogFile, pApp->szUninstKey, 0 );
    if (nResult < 0) then
        ShowError( @ERROR_UNINSTSETUP, WARNING );
    endif;

    szAppPath = pApp->szAppPath;

	// Fill in reg values for this apps reg key and uninstall reg key
    RegDBSetItem( REGDB_APPPATH, szAppPath );
    RegDBSetItem( REGDB_APPPATH_DEFAULT, szAppPath ^ pApp->szProductKey);
    RegDBSetItem( REGDB_UNINSTALL_NAME, pApp->szUninstDisplayName);

    return 0;
end;


/*
function ShowIsSelected(comp)
	number nSel;
	string str;
begin
    nSel = ComponentIsItemSelected(MEDIA , comp);
    if (nSel) then
    	str = comp + " is selected.";
    	MessageBox(str, INFORMATION);
    else
    	str = comp + " is not selected.";
    endif;
end;


function ShowSelectedComponents()
begin
	// Visible components
	ShowIsSelected(CLIENT_COMP_NAME);
	ShowIsSelected(LIGHT_CLIENT_COMP_NAME);
	ShowIsSelected(SERVER_COMP_NAME);
	ShowIsSelected(CC_COMP_NAME);
	ShowIsSelected(DOCS_COMP_NAME);

    // Language components
	ShowIsSelected(LANG_COMP_NAME);
    ShowIsSelected(LANG_ENGLISH_COMP_NAME);
    ShowIsSelected(LANG_SIMP_CHINESE_COMP_NAME);
    ShowIsSelected(LANG_TRAD_CHINESE_COMP_NAME);
    ShowIsSelected(LANG_KOREAN_COMP_NAME);
    ShowIsSelected(LANG_JAPANESE_COMP_NAME);
    ShowIsSelected(LANG_GERMAN_COMP_NAME);
    ShowIsSelected(LANG_SPANISH_COMP_NAME);
    ShowIsSelected(LANG_PORTUGUESE_COMP_NAME);

	// Documentation components
	ShowIsSelected(DOCS_ENGLISH_COMP_NAME);
	ShowIsSelected(DOCS_JAPANESE_COMP_NAME);
	ShowIsSelected(DOCS_KOREAN_COMP_NAME);
	ShowIsSelected(DOCS_SIMP_CHINESE_COMP_NAME);
	ShowIsSelected(DOCS_TRAD_CHINESE_COMP_NAME);
	ShowIsSelected(DOCS_GERMAN_COMP_NAME);
	ShowIsSelected(DOCS_SPANISH_COMP_NAME);
	ShowIsSelected(DOCS_PORTUGUESE_COMP_NAME);
	
	// Readme files components
	ShowIsSelected(README_COMP_NAME);
	ShowIsSelected(README_ENGLISH_COMP_NAME);
	ShowIsSelected(README_JAPANESE_COMP_NAME);
	ShowIsSelected(README_KOREAN_COMP_NAME);
	ShowIsSelected(README_SIMP_CHINESE_COMP_NAME);
	ShowIsSelected(README_TRAD_CHINESE_COMP_NAME);
	ShowIsSelected(README_GERMAN_COMP_NAME);
	ShowIsSelected(README_SPANISH_COMP_NAME);
	ShowIsSelected(README_PORTUGUESE_COMP_NAME);
end;
*/


///////////////////////////////////////////////////////////////////////////////
//
//  Function:  MoveFileData
//
//  Purpose:  This function handles the file transfer for
//            the setup.
//
///////////////////////////////////////////////////////////////////////////////
function MoveFileData()
    NUMBER nResult, nDisk;

begin
	if (!bWSPPInstall) then
		Enable( INDVFILESTATUS );
    	SetStatusWindow( 0, "" );
    	Disable( DIALOGCACHE );
    	Enable( STATUS );
    	StatusUpdate( ON, 100 );
	endif;

    nResult = ComponentMoveData( MEDIA, nDisk, 0 );
	
	// Reinit this call so the progress indicator resets
	ComponentMoveData("", nDisk, 0);

    HandleMoveDataError( nResult );

    Disable( STATUS );

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: HandleMoveDataError
//
//  Purpose: This function handles the error (if any) during the file transfer
//           operation.
//
///////////////////////////////////////////////////////////////////////////////
function HandleMoveDataError( nResult )
    STRING szErrMsg, svComponent , svFileGroup , svFile;
	string szMsg;
begin
    svComponent = "";
    svFileGroup = "";
    svFile = "";

    switch (nResult)
        case 0:
            return 0;
        default:
            ComponentError ( MEDIA , svComponent , svFileGroup , svFile , nResult );
            szErrMsg = @ERROR_MOVEDATA  + "\n\n" +
                @ERROR_COMPONENT + " " + svComponent + "\n" +
                @ERROR_FILEGROUP + " " + svFileGroup + "\n" +
                @ERROR_FILE      + " " + svFile;
            Sprintf(szMsg, szErrMsg, nResult);
            ShowError(szMsg, SEVERE);
            bInstallAborted = TRUE;
            return nResult;
    endswitch;

end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: ProcessAfterDataMove
//
//  Purpose: This function performs any necessary operations needed after
//           all files have been transferred.
//
///////////////////////////////////////////////////////////////////////////////
function ProcessAfterDataMove()
    STRING szReferenceFile;

begin

    // TO DO : update self-registered files and other processes that
    //        should be performed after the files have been transferred.

    // DeinstallSetReference specifies a file to be checked before
    // uninstallation. If the file is in use, uninstallation will not proceed.

//	szReferenceFile = svDir ^ pApp->szProductKey; // TO DO : If your file is in a
                                            // subfolder of svDir add that here

//    DeinstallSetReference( szReferenceFile );

    return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: CleanUpInstall
//
//  Purpose: This cleans up the setup.  Anything that should
//           be released or deleted at the end of the setup should
//           be done here.
//
///////////////////////////////////////////////////////////////////////////////
function CleanUpInstall()

begin
    if (bInstallAborted) then
        return 0;
    endif;

    if (!bWSPPInstall) then
    	DialogShowSdFinishReboot();
    endif;

    if (BATCH_INSTALL) then // ensure locked files are properly transferred
        CommitSharedFiles(0);
    endif;

    return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: GetLicenseFilename
//
//  Purpose: This will determine the full path to the appropriate-language
//           license on the CD.  Will default to English if the locale cannot
//           be determined.
//
///////////////////////////////////////////////////////////////////////////////
function GetLicenseFilename(szLicense)
	number MajorLanguage;
begin
	MajorLanguage = SELECTED_LANGUAGE & 255;

	switch(MajorLanguage)
	case ISLANG_CHINESE:
		if (SELECTED_LANGUAGE == ISLANG_CHINESE_TAIWAN) then
			szLicense = SRCDIR ^ LICENSE_TRAD_CHINESE_FILENAME;
		else
			szLicense = SRCDIR ^ LICENSE_SIMP_CHINESE_FILENAME;
		endif;

	case ISLANG_KOREAN:
		szLicense = SRCDIR ^ LICENSE_KOREAN_FILENAME;

	case ISLANG_JAPANESE:
		szLicense = SRCDIR ^ LICENSE_JAPANESE_FILENAME;

	case ISLANG_GERMAN:
		szLicense = SRCDIR ^ LICENSE_GERMAN_FILENAME;

	case ISLANG_PORTUGUESE:
		szLicense = SRCDIR ^ LICENSE_PORTUGUESE_FILENAME;

	case ISLANG_SPANISH:
		szLicense = SRCDIR ^ LICENSE_SPANISH_FILENAME;

	default:
		szLicense = SRCDIR ^ LICENSE_ENGLISH_FILENAME;

	endswitch;

	return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: GetLanguageComp
//
//  Purpose: This will determine which language the locale is set to.  Uses
//           this info to determine which lang, readme, and doc comps to
//           install.  Will default to English if the locale cannot be
//           determined.
//
///////////////////////////////////////////////////////////////////////////////
function GetNlsComps(szLangComp, szReadmeComp, szDocsComp, szCodePage)
	number MajorLanguage;
begin
	MajorLanguage = SELECTED_LANGUAGE & 255;

	switch(MajorLanguage)
		case ISLANG_CHINESE:
			if (SELECTED_LANGUAGE == ISLANG_CHINESE_TAIWAN) then
               szLangComp = LANG_TRAD_CHINESE_COMP_NAME;
               szReadmeComp = README_TRAD_CHINESE_COMP_NAME;
               szDocsComp = DOCS_TRAD_CHINESE_COMP_NAME;
               szCodePage = "1028";
			else
               szLangComp = LANG_SIMP_CHINESE_COMP_NAME;
               szReadmeComp = README_SIMP_CHINESE_COMP_NAME;
               szDocsComp = DOCS_SIMP_CHINESE_COMP_NAME;
               szCodePage = "2052";
			endif;

		case ISLANG_KOREAN:
               szLangComp = LANG_KOREAN_COMP_NAME;
               szReadmeComp = README_KOREAN_COMP_NAME;
               szDocsComp = DOCS_KOREAN_COMP_NAME;
               szCodePage = "1042";

		case ISLANG_JAPANESE:
               szLangComp = LANG_JAPANESE_COMP_NAME;
               szReadmeComp = README_JAPANESE_COMP_NAME;
               szDocsComp = DOCS_JAPANESE_COMP_NAME;
               szCodePage = "1041";

        case ISLANG_GERMAN:
               szLangComp = LANG_GERMAN_COMP_NAME;
               szReadmeComp = README_GERMAN_COMP_NAME;
               szDocsComp = DOCS_GERMAN_COMP_NAME;
               szCodePage = "1032";

        case ISLANG_PORTUGUESE:
               szLangComp = LANG_PORTUGUESE_COMP_NAME;
               szReadmeComp = README_PORTUGUESE_COMP_NAME;
               szDocsComp = DOCS_PORTUGUESE_COMP_NAME;
               szCodePage = "1046";

        case ISLANG_SPANISH:
               szLangComp = LANG_SPANISH_COMP_NAME;
               szReadmeComp = README_SPANISH_COMP_NAME;
               szDocsComp = DOCS_SPANISH_COMP_NAME;
               szCodePage = "1034";

		default:
               szLangComp = LANG_ENGLISH_COMP_NAME;
               szReadmeComp = README_ENGLISH_COMP_NAME;
               szDocsComp = DOCS_ENGLISH_COMP_NAME;
               szCodePage = "1033";

	endswitch;

	return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: SetupVerInfo
//
//  Purpose: This will initialize the VERINFO structures for a product.
//
///////////////////////////////////////////////////////////////////////////////
function SetupVerInfo(pApp, szMajor, szMinor, szPatchLevel, szBetaLevel, szReleaseType, szTitle, bInstalledVerInfo)
	int nMajor;
	int nMinor;
	int nPatchLevel;
	int nBetaLevel;
begin
	StrToNum(nMajor, szMajor);
	StrToNum(nMinor, szMinor);
	StrToNum(nPatchLevel, szPatchLevel);
	StrToNum(nBetaLevel, szBetaLevel);

	if (bInstalledVerInfo) then
		pApp->iVer.nMajorVersion = nMajor;
		pApp->iVer.nMinorVersion = nMinor;
		pApp->iVer.nPatchLevel = nPatchLevel;
		pApp->iVer.nBetaLevel = nBetaLevel;
		pApp->iVer.szReleaseType = szReleaseType;
		pApp->iVer.szTitle = szTitle;	
	else
		pApp->Ver.nMajorVersion = nMajor;
		pApp->Ver.nMinorVersion = nMinor;
		pApp->Ver.nPatchLevel = nPatchLevel;
		pApp->Ver.nBetaLevel = nBetaLevel;
		pApp->Ver.szReleaseType = szReleaseType;
		pApp->Ver.szTitle = szTitle;
	endif;
end;


	
///////////////////////////////////////////////////////////////////////////////
//
// Function: FixTargetPaths
//
//  Purpose: This function updates the CommonBinPath and app paths if you
//			 choose to install to a different directory
//
///////////////////////////////////////////////////////////////////////////////
function FixTargetPaths()
begin
	// The AFS path must not contain spaces.  AFS code will break if it does.
	LongPathToShortPath(TARGETDIR);

	szCommonBinPath = TARGETDIR ^ "Common";
	
	// Full Client
	appFullClient.szAppPath = TARGETDIR ^ "Client";
	appFullClient.szBinPath = TARGETDIR ^ "Client\\Program";
	
	// Light Client
	appLightClient.szAppPath = TARGETDIR ^ "Client";
	appLightClient.szBinPath = TARGETDIR ^ "Client\\Program";

	// Server
	appServer.szAppPath = TARGETDIR ^ "Server";
	appServer.szBinPath = TARGETDIR ^ "Server\\usr\\afs\\bin";
	
	// Control Center
	appControlCenter.szAppPath = TARGETDIR ^ "Control Center";
	appControlCenter.szBinPath = TARGETDIR ^ "Control Center";
	
    // Docs
	appDocs.szAppPath = TARGETDIR ^ "Documentation";
	appDocs.szBinPath = TARGETDIR ^ "Documentation";
end;
	

	
///////////////////////////////////////////////////////////////////////////////
//
// Function: SetupAppInfo
//
//  Purpose: This will initialize the APPINFO structures for each product
//			 that we can install.
//
///////////////////////////////////////////////////////////////////////////////
function SetupAppInfo()
int n;
begin
	szCommonBinPath = TARGETDIR ^ "Common";
	
	// Full Client
	appFullClient.szCompName = CLIENT_COMP_NAME;		// Component name
	appFullClient.szCompanyName = @COMPANY_NAME;
	appFullClient.szProductName = @PRODUCT_NAME_CLIENT;
	appFullClient.szProductKey = @PRODUCT_KEY_CLIENT;
	appFullClient.bUseUninstDLL = TRUE;
	appFullClient.szUninstDllName = CLIENT_UNINST_DLL_NAME;
	appFullClient.szUninstLogfileName = CLIENT_UNINST_LOGFILE_NAME;
	appFullClient.szUninstKey = @UNINST_KEY_CLIENT;
	appFullClient.szAppPath = TARGETDIR ^ "Client";
	appFullClient.szBinPath = TARGETDIR ^ "Client\\Program";
	appFullClient.bAddToPath = TRUE;
	appFullClient.szUninstDisplayName = @UNINST_DISPLAY_NAME_CLIENT;
	appFullClient.szRegistrySets = "Client,Full_Client";
	appFullClient.szNoLogRegistrySets = "Client_NoUninstall,WinNT_Client_NoUninstall";
	appFullClient.bInstallSucceeded = FALSE;
	SetupVerInfo(&appFullClient, @PRODUCT_VERSION_MAJOR, @PRODUCT_VERSION_MINOR, @PRODUCT_VERSION_PATCH_LEVEL, @PRODUCT_VERSION_BETA_LEVEL, @PRODUCT_VERSION_RELEASE_TYPE, @PRODUCT_VERSION_TITLE, FALSE);
	
	// Light Client
	if (bWin95) then
		appLightClient.szCompName = LIGHT95_CLIENT_COMP_NAME;
	elseif (bWin98) then
		appLightClient.szCompName = LIGHT98_CLIENT_COMP_NAME;
	endif;
	appLightClient.szCompanyName = @COMPANY_NAME;
	appLightClient.szProductName = @PRODUCT_NAME_LIGHT_CLIENT;
	appLightClient.szProductKey = @PRODUCT_KEY_LIGHT_CLIENT;
	appLightClient.bUseUninstDLL = TRUE;
	appLightClient.szUninstDllName = LIGHT_CLIENT_UNINST_DLL_NAME;
	appLightClient.szUninstLogfileName = LIGHT_CLIENT_UNINST_LOGFILE_NAME;
	appLightClient.szUninstKey = @UNINST_KEY_LIGHT_CLIENT;
	appLightClient.szAppPath = TARGETDIR ^ "Client";
	appLightClient.szBinPath = TARGETDIR ^ "Client\\Program";
	appLightClient.bAddToPath = TRUE;
	appLightClient.szUninstDisplayName = @UNINST_DISPLAY_NAME_LIGHT_CLIENT;
	appLightClient.szRegistrySets = "Client,LightClient";
	appLightClient.szNoLogRegistrySets = "Client_NoUninstall";
	appLightClient.bInstallSucceeded = FALSE;
	SetupVerInfo(&appLightClient, @PRODUCT_VERSION_MAJOR, @PRODUCT_VERSION_MINOR, @PRODUCT_VERSION_PATCH_LEVEL, @PRODUCT_VERSION_BETA_LEVEL, @PRODUCT_VERSION_RELEASE_TYPE, @PRODUCT_VERSION_TITLE, FALSE);

	// Server
	appServer.szCompName = SERVER_COMP_NAME;
	appServer.szCompanyName = @COMPANY_NAME;
	appServer.szProductName = @PRODUCT_NAME_SERVER;
	appServer.szProductKey = @PRODUCT_KEY_SERVER;
	appServer.bUseUninstDLL = TRUE;
	appServer.szUninstDllName = SERVER_UNINST_DLL_NAME;
	appServer.szUninstLogfileName = SERVER_UNINST_LOGFILE_NAME;
	appServer.szUninstKey = @UNINST_KEY_SERVER;
	appServer.szAppPath = TARGETDIR ^ "Server";
	appServer.szBinPath = TARGETDIR ^ "Server\\usr\\afs\\bin";
	appServer.bAddToPath = TRUE;
	appServer.szUninstDisplayName = @UNINST_DISPLAY_NAME_SERVER;
	appServer.szRegistrySets = "Server";
	appServer.szNoLogRegistrySets = "";
	appServer.bInstallSucceeded = FALSE;
	SetupVerInfo(&appServer, @PRODUCT_VERSION_MAJOR, @PRODUCT_VERSION_MINOR, @PRODUCT_VERSION_PATCH_LEVEL, @PRODUCT_VERSION_BETA_LEVEL, @PRODUCT_VERSION_RELEASE_TYPE, @PRODUCT_VERSION_TITLE, FALSE);
	
	// Control Center
	appControlCenter.szCompName = CC_COMP_NAME;
	appControlCenter.szCompanyName = @COMPANY_NAME;
	appControlCenter.szProductName = @PRODUCT_NAME_CC;
	appControlCenter.szProductKey = @PRODUCT_KEY_CC;
	appControlCenter.bUseUninstDLL = TRUE;
	appControlCenter.szUninstDllName = CC_UNINST_DLL_NAME;
	appControlCenter.szUninstLogfileName = CC_UNINST_LOGFILE_NAME;
	appControlCenter.szUninstKey = @UNINST_KEY_CC;
	appControlCenter.szAppPath = TARGETDIR ^ "Control Center";
	appControlCenter.szBinPath = TARGETDIR ^ "Control Center";
	appControlCenter.bAddToPath = TRUE;
	appControlCenter.szUninstDisplayName = @UNINST_DISPLAY_NAME_CC;
	appControlCenter.szRegistrySets = "Control_Center";
	appControlCenter.szNoLogRegistrySets = "";
	appControlCenter.bInstallSucceeded = FALSE;
	SetupVerInfo(&appControlCenter, @PRODUCT_VERSION_MAJOR, @PRODUCT_VERSION_MINOR, @PRODUCT_VERSION_PATCH_LEVEL, @PRODUCT_VERSION_BETA_LEVEL, @PRODUCT_VERSION_RELEASE_TYPE, @PRODUCT_VERSION_TITLE, FALSE);
	
    // Docs
	appDocs.szCompName = DOCS_COMP_NAME;
	appDocs.szCompanyName = @COMPANY_NAME;
	appDocs.szProductName = @PRODUCT_NAME_DOCS;
	appDocs.szProductKey = @PRODUCT_KEY_DOCS;
	appDocs.bUseUninstDLL = TRUE;
	appDocs.szUninstDllName = DOCS_UNINST_DLL_NAME;
	appDocs.szUninstLogfileName = DOCS_UNINST_LOGFILE_NAME;
	appDocs.szUninstKey = @UNINST_KEY_DOCS;
	appDocs.szAppPath = TARGETDIR ^ "Documentation";
	appDocs.szBinPath = TARGETDIR ^ "Documentation";
	appDocs.bAddToPath = FALSE;
	appDocs.szUninstDisplayName = @UNINST_DISPLAY_NAME_DOCS;
	appDocs.szRegistrySets = "Docs";
	appDocs.szNoLogRegistrySets = "";
	appDocs.bInstallSucceeded = FALSE;
	SetupVerInfo(&appDocs, @PRODUCT_VERSION_MAJOR, @PRODUCT_VERSION_MINOR, @PRODUCT_VERSION_PATCH_LEVEL, @PRODUCT_VERSION_BETA_LEVEL, @PRODUCT_VERSION_RELEASE_TYPE, @PRODUCT_VERSION_TITLE, FALSE);
end;
	

///////////////////////////////////////////////////////////////////////////////
//
// Function: SetupInstall
//
//  Purpose: This will initialize the setup.  Any general initialization
//           needed for the installation should be performed here.
//
///////////////////////////////////////////////////////////////////////////////
function SetupInstall()
begin
    Enable( CORECOMPONENTHANDLING );

    szCellName=@CELLNAME_DEFAULT;
    bInstallAborted = FALSE;

    //  Create list of end user selections to be displayed by DialogShowSdStartCopy()

    svDir = PROGRAMFILES ^ @DEFAULT_INSTALL_DIR;

    TARGETDIR  = svDir;

    SdProductName( @PRODUCT_NAME );

    Enable( DIALOGCACHE );

    SetDialogTitle(DLG_ASK_YESNO, @TITLE_CAPTIONBAR);
  	SetDialogTitle(DLG_MSG_INFORMATION, @TITLE_CAPTIONBAR);
  	SetDialogTitle(DLG_MSG_WARNING, @TITLE_CAPTIONBAR);
  	SetDialogTitle(DLG_MSG_SEVERE, @TITLE_CAPTIONBAR);
  	SetDialogTitle(DLG_USER_CAPTION, @TITLE_CAPTIONBAR);
end;

///////////////////////////////////////////////////////////////////////////////
//
// Function:  SetupScreen
//
//  Purpose:  This function establishes the screen look.  This includes
//            colors, fonts, and text to be displayed.
//
///////////////////////////////////////////////////////////////////////////////
function SetupScreen()
begin
    Enable( FULLWINDOWMODE );
    SetTitle( @TITLE_MAIN, 24, WHITE );

    SetTitle( @TITLE_CAPTIONBAR, 0, BACKGROUNDCAPTION ); // Caption bar text.

    Enable( BACKGROUND );

    Delay( 1 );
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function:  CheckRequirements
//
//  Purpose:  This function checks all minimum requirements for the
//            application being installed.  If any fail, then the user
//            is informed and the setup is terminated.
//
///////////////////////////////////////////////////////////////////////////////
function CheckRequirements()
    NUMBER  nvDx, nvDy, nvResult;
    STRING  svResult;
begin
    bWinNT           = FALSE;
    bWin95			 = FALSE;
    bWin98			 = FALSE;
    bIsShellExplorer = FALSE;

    // Check screen resolution.
    GetExtents( nvDx, nvDy );

    if (nvDy < 480) then
        ShowError( @ERROR_VGARESOLUTION, WARNING );
        abort;
    endif;

    // set 'setup' operation mode
    bIs32BitSetup = TRUE;
    GetSystemInfo( ISTYPE, nvResult, svResult );
    if (nvResult = 16) then
        bIs32BitSetup = FALSE; // running 16-bit setup
        return 0; // no additional information required
    endif;

    // --- 32-bit testing after this point ---

    // Determine the target system's operating system.
    GetSystemInfo( OS, nvResult, svResult );

    if (nvResult =  IS_WINDOWSNT) then
        // Running Windows NT.
        bWinNT = TRUE;

        // If the user is not an admin, then abort
        if (CheckIfAdmin() = -1) then
            ShowError(@MUST_BE_AN_ADMIN_MSG, SEVERE);
            abort;
        endif;

        // Check to see if the shell being used is EXPLORER shell.
        if (GetSystemInfo( OSMAJOR, nvResult, svResult ) = 0) then
            if (nvResult >= 4) then
                bIsShellExplorer = TRUE;
            endif;
        endif;

    elseif (nvResult = IS_WINDOWS95) then
        // IS puts us here even for Win98
        if (IsWin98() = 0) then
            bWin98 = TRUE;
		else
		    bWin95 = TRUE;
		endif;

        bIsShellExplorer = TRUE;
    endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: DialogShowSdWelcome
//
//  Purpose: This function handles the standard welcome dialog.
//
//
///////////////////////////////////////////////////////////////////////////////
function DialogShowSdWelcome()
    NUMBER nResult;
    STRING szTitle, szMsg;

begin

    szTitle = "";
    szMsg   = @WELCOME_MESSAGE;
    nResult = SdWelcome( szTitle, szMsg );

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: DialogShowSdAskDestPath
//
//  Purpose: This function asks the user for the destination folder.
//
///////////////////////////////////////////////////////////////////////////////
function DialogShowSdAskDestPath()
    NUMBER nResult;
    STRING szTitle, szMsg;

begin

    szTitle = "";
    szMsg   = "";
    nResult = SdAskDestPath( szTitle, szMsg, svDir, 0 );

    TARGETDIR = svDir;
    FixTargetPaths();

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: GetVersionNumber
//
//  Purpose: This function converts a version number string into an integer.
//
///////////////////////////////////////////////////////////////////////////////
function GetVersionNumber(szVerion)
	int nVersion;
	int nMajorVersion;
	int nMinorVersion;
	string szVer[64];
begin
	// This code assumes a majorversion.minorversion format.
	szVer = szVerion;
		
	// This will get everything up to the '.'
	StrToNum(nMajorVersion, szVer);
	
	// Delete the part of the string we just converted
	StrSub(szVer, szVer, StrFind(szVer, ".") + 1, 64);
	
	// Now convert the part after the '.'
	StrToNum(nMinorVersion, szVer);
	
	// Turn in into a single number
	nVersion = (nMajorVersion * 10) + nMinorVersion;
	
	return nVersion;
end;
	

///////////////////////////////////////////////////////////////////////////////
//
// Function: CompareVersions
//
//  Purpose: This function compares an apps two version info structures and
//			 determines if one is greater than the other, or if they are equal.
//
///////////////////////////////////////////////////////////////////////////////
function CompareVersions(pApp)
	int nResult;
begin
	// Compare major versions
	nResult = pApp->Ver.nMajorVersion - pApp->iVer.nMajorVersion;
	if (nResult > 0) then return 1; endif;
	if (nResult < 0) then return -1; endif;
	
	// Major versions are equal, move on to minor versions
	nResult = pApp->Ver.nMinorVersion - pApp->iVer.nMinorVersion;
	if (nResult > 0) then return 1; endif;
	if (nResult < 0) then return -1; endif;

	// Minor versions are equal, move on to patch level.
	nResult = pApp->Ver.nPatchLevel - pApp->iVer.nPatchLevel;
	if (nResult > 0) then return 1; endif;
	if (nResult < 0) then return -1; endif;

	// Patch levels are equal, move on to release type.
	if ((pApp->Ver.szReleaseType = RELEASE_TYPE_GA) && (pApp->iVer.szReleaseType = RELEASE_TYPE_BETA)) then return 1; endif;
	if ((pApp->Ver.szReleaseType = RELEASE_TYPE_BETA) && (pApp->iVer.szReleaseType = RELEASE_TYPE_GA)) then return -1; endif;
	
	// Release types are equal.  Special handling now required:
	
	// If this is a GA release, then there is no more info to look at, and the versions are equal.
	if (pApp->Ver.szReleaseType = RELEASE_TYPE_GA) then return 0; endif;

	// We have a Beta release, so we still have some info to check.  Compare the beta release levels.
	nResult = pApp->Ver.nBetaLevel - pApp->iVer.nBetaLevel;
	if (nResult > 0) then return 1; endif;
	if (nResult < 0) then return -1; endif;
	
	// Beta versions are equal.
	return 0;
end;
	

///////////////////////////////////////////////////////////////////////////////
//
// Function: GetInstallAction
//
//  Purpose: This function decides what install action to perform for a
//           component and sets the display name accordingly.
//
///////////////////////////////////////////////////////////////////////////////
function GetInstallAction(szCompName, bInstalled, szInstallMsg, szUpgradeMsg, szDowngradeMsg, szReinstallMsg, pApp)
	string szDisplayName;
	string szVerMsg;
	int nResult;
begin
	szVerMsg = "";

	if (bInstalled) then
		nResult = CompareVersions(pApp);

		if (nResult = 0) then
			szDisplayName = szReinstallMsg;
			pApp->nInstallAction = ACTION_REINSTALL;
	
		elseif (nResult > 0) then
			szDisplayName = szUpgradeMsg;
			pApp->nInstallAction = ACTION_UPGRADE;
			Sprintf(szVerMsg, " %s", pApp->iVer.szTitle);
			
		else // Trying to install old version on top of new version
			szDisplayName = szDowngradeMsg;
			pApp->nInstallAction = ACTION_DOWNGRADE;
			Sprintf(szVerMsg, " %s", pApp->iVer.szTitle);
		endif;
	else
		szDisplayName = szInstallMsg;
		pApp->nInstallAction = ACTION_INSTALL;
	endif;

	szDisplayName = szDisplayName + szVerMsg;

	ComponentSetData(MEDIA, szCompName, COMPONENT_FIELD_DISPLAYNAME, 0, szDisplayName);
	
	return TRUE;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: GetInstallActions
//
//  Purpose: This function decides what install action to perform for each
//           component and sets the display name accordingly.
//
///////////////////////////////////////////////////////////////////////////////
function GetInstallActions()
begin
	// Decide what to do for each component and then set the display names appropriately
	GetInstallAction(CLIENT_COMP_NAME, bClientInstalled, @INSTALL_CLIENT_MSG, @UPGRADE_CLIENT_MSG, @DOWNGRADE_CLIENT_MSG, @REINSTALL_CLIENT_MSG, &appFullClient);
	GetInstallAction(SERVER_COMP_NAME, bServerInstalled, @INSTALL_SERVER_MSG, @UPGRADE_SERVER_MSG, @DOWNGRADE_SERVER_MSG, @REINSTALL_SERVER_MSG, &appServer);
	GetInstallAction(CC_COMP_NAME, bCcInstalled, @INSTALL_CC_MSG, @UPGRADE_CC_MSG, @DOWNGRADE_CC_MSG, @REINSTALL_CC_MSG, &appControlCenter);
	GetInstallAction(LIGHT_CLIENT_COMP_NAME, bLightClientInstalled, @INSTALL_LIGHT_CLIENT_MSG, @UPGRADE_LIGHT_CLIENT_MSG, @DOWNGRADE_LIGHT_CLIENT_MSG, @REINSTALL_LIGHT_CLIENT_MSG, &appLightClient);
	GetInstallAction(DOCS_COMP_NAME, bDocsInstalled, @INSTALL_DOCS_MSG, @UPGRADE_DOCS_MSG, @DOWNGRADE_DOCS_MSG, @REINSTALL_DOCS_MSG, &appDocs);
end;

///////////////////////////////////////////////////////////////////////////////
//
// Function: ClientSelectedOrInstalled
//
//  Purpose: This function checks whether or not the client is selected or if
//           it is already installed.
//
///////////////////////////////////////////////////////////////////////////////
function ClientSelectedOrInstalled()
begin
	if (bFullClientSel || bClientInstalled) then
		return TRUE;
	endif;
		
	return FALSE;
end;

///////////////////////////////////////////////////////////////////////////////
//
// Function: AppVersionOk
//
//  Purpose: This function determines if a given app will have the correct
//           version after installation.
//
///////////////////////////////////////////////////////////////////////////////
function AppVersionOk(bInstalled, bSel, pApp)
	BOOL bOk;
begin
	// Here's the logic of this:
	//
	// 1)  If the app is not installed and
	//     a) it's not being installed, then this app doesn't affect the version
	//        restrictions, so return true
	//     b) it will be installed, then it will get the version which this
	//        installer installs, so the version will be ok
	//
	// 2)  If the app is installed and
	//     a) the app is selected for reinstall, upgrade, or downgrade, then the
	//        newly installed version will be the version this installer installs,
	//        and so the version will be ok
	//     b) the app is not selected for reinstall, upgrade, or downgrade, then
	//        the version is ok only if the app's current version matches the
	//        the version of this installer

	bOk = !bInstalled || bSel || (CompareVersions(pApp) = 0);

	return bOk;
end;
	

///////////////////////////////////////////////////////////////////////////////
//
// Function: DialogShowSdAskComponentDialog
//
//  Purpose: This function asks the user which components to install
//			 and what the destination folder should be.
//
///////////////////////////////////////////////////////////////////////////////
function DialogShowSdAskComponentDialog()
    NUMBER nResult;
    STRING szTitle, szMsg, szComponent, szFilename;
    BOOL bClient, bServer, bCc, bDocs, bVersionsOK;
begin

    szTitle = "";
    szMsg   = "";
	szComponent = "";

	// If running WinNT hide the Light Client component.  If the user wants to only
	// allow client installs, then hide all but the Client component as well.  If not
	// running on NT, then hide all but the Light Client component.
	if (bWinNT) then
		ComponentSetData(MEDIA, LIGHT_CLIENT_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
		ComponentSelectItem(MEDIA, LIGHT_CLIENT_COMP_NAME, FALSE);
	
		if (FindFile(SRCDIR, ALLOW_ONLY_CLIENT_FLAG_FILENAME, szFilename) = 0) then
			ComponentSetData(MEDIA, SERVER_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
			ComponentSetData(MEDIA, CC_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
			ComponentSetData(MEDIA, DOCS_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
			ComponentSelectItem(MEDIA, DOCS_COMP_NAME, FALSE);
			endif;
		ComponentSelectItem(MEDIA, SERVER_COMP_NAME, FALSE);
		if (@CELLNAME_DEFAULT % ".") then
			ComponentSelectItem(MEDIA, CC_COMP_NAME, FALSE);
		else
			ComponentSelectItem(MEDIA, CC_COMP_NAME, TRUE);
		endif;
else
		ComponentSetData(MEDIA, CLIENT_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
		ComponentSetData(MEDIA, SERVER_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
		ComponentSetData(MEDIA, CC_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
		ComponentSetData(MEDIA, DOCS_COMP_NAME, COMPONENT_FIELD_VISIBLE, FALSE, "");
		
		ComponentSelectItem(MEDIA, SERVER_COMP_NAME, FALSE);
		ComponentSelectItem(MEDIA, CLIENT_COMP_NAME, FALSE);
		ComponentSelectItem(MEDIA, CC_COMP_NAME, FALSE);
		ComponentSelectItem(MEDIA, DOCS_COMP_NAME, FALSE);
	endif;

retry:
	nResult = SdComponentDialog(szTitle, szMsg, svDir, szComponent);

	// Enforce selection rules - something must be selected and
	// the client must be selected if the server is.  However, take into
	// account if it is already installed.
	bFullClientSel = ComponentIsItemSelected(MEDIA , CLIENT_COMP_NAME);
	bLightClientSel = ComponentIsItemSelected(MEDIA , LIGHT_CLIENT_COMP_NAME);
	bServerSel = ComponentIsItemSelected(MEDIA , SERVER_COMP_NAME);
	bCcSel = ComponentIsItemSelected(MEDIA , CC_COMP_NAME);
	bDocsSel = ComponentIsItemSelected(MEDIA , DOCS_COMP_NAME);

	if (!bFullClientSel && !bLightClientSel && !bServerSel && !bCcSel && !bDocsSel) then
		ShowError(@NOTHING_SELECTED_MSG, SEVERE);
		goto retry;
	endif;

	if (bServerSel && !ClientSelectedOrInstalled()) then
		ShowError(@SERVER_NEEDS_CLIENT_MSG, SEVERE);
		goto retry;
	endif;	

	// Also, if upgrading or downgrading, all apps must be at the same version level.
	// We won't upgrade one app to a higer version than another, and we won't downgrade
	// one app to a lowel version than another.  All must be at the same level when the
	// install program is done.  This is necessary because the apps share some files.
	if (!bWinNT) then
		bVersionsOK = TRUE;
	else
		bClient = AppVersionOk(bClientInstalled, bFullClientSel, &appFullClient);
		bServer = AppVersionOk(bServerInstalled, bServerSel, &appServer);
		bCc = AppVersionOk(bCcInstalled, bCcSel, &appControlCenter);
		bDocs = AppVersionOk(bDocsInstalled, bDocsSel, &appDocs);
		bVersionsOK = bClient && bServer && bCc && bDocs;
	endif;
	
	if (!bVersionsOK) then
		ShowError(@APPS_NOT_SAME_VERSION, SEVERE);
		goto retry;
	endif;

    TARGETDIR = svDir;
    FixTargetPaths();

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: DialogShowSdSetupType
//
//  Purpose: This function displays the standard setup type dialog.
//
///////////////////////////////////////////////////////////////////////////////
function DialogShowSdSetupType()
    NUMBER nResult, nType;
    STRING szTitle, szMsg, szReserved;

begin

    if (svSetupType == "") then
    	svSetupType = "AFS Server";
	endif;
	
    szTitle = "";
    szMsg   = @SETUP_TYPE_MSG;
    szReserved = "";

	nResult = SdSetupTypeEx(szTitle, szMsg, szReserved, svSetupType, 0);

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: DialogShowSdSelectFolder
//
//  Purpose: This function displays the standard folder selection dialog.
//
//
///////////////////////////////////////////////////////////////////////////////
function DialogShowSdSelectFolder()
    NUMBER nResult;
    STRING szTitle, szMsg;
begin
    if (SHELL_OBJECT_FOLDER = "") then
       	SHELL_OBJECT_FOLDER = @FOLDER_NAME;
    endif;

	// We are going to force the user to use the default folder name.  This is
	// because we create the folder unlogged, and must therefore remove it
	// ourselves in our uninstall dll (which we do because IS doesn't handle
	// removing them correctly).  Therefore, we must know the name of the
	// folder so we can remove it during uninstall.  Also, the user can install
	// the AFS components during several executions of the install program,
	// and we don't want to allow them to pick a different folder each time.
	// We could solve these problems in code but we don't have time, so we
	// are going to force them to use our default folder name.
	return 0;

    szTitle    = "";
    szMsg      = "";
    nResult    = SdSelectFolder( szTitle, szMsg, SHELL_OBJECT_FOLDER);

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: DialogShowSdFinishReboot
//
//  Purpose: This function will show the last dialog of the product.
//           It will allow the user to reboot and/or show some readme text.
//
///////////////////////////////////////////////////////////////////////////////
function DialogShowSdFinishReboot()
    NUMBER nResult, nDefOptions;
    STRING szTitle, szMsg1, szMsg2, szOption1, szOption2;
    NUMBER bOpt1, bOpt2;
begin
    if (!BATCH_INSTALL) then
        bOpt1 = FALSE;
        bOpt2 = FALSE;
        szMsg1 = @SETUP_FINISHED_MSG;
        szMsg2 = "";
        szOption1 = "";
        szOption2 = "";
        szTitle = "";
        nResult = SdFinish(szTitle, szMsg1, szMsg2, szOption1, szOption2, bOpt1, bOpt2 );
        return 0;
    endif;

    nDefOptions = SYS_BOOTMACHINE;
    szTitle     = "";
    szMsg1      = "";
    szMsg2      = "";
    nResult     = SdFinishReboot( szTitle, szMsg1, nDefOptions, szMsg2, 0 );

    return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: ConfigServerService
//
//  Purpose: This function will configure the AFS Server bos service via the
//			 SCM.
//
///////////////////////////////////////////////////////////////////////////////
function ConfigServerService()
    STRING szMsg;
    BOOL bError;
    number nStatus;
begin
    bError = TRUE;

    if (!bWSPPInstall) then
    	szMsg = @CONFIGURING_AFS_SERVER_SERVICE;
    	SdShowMsg(szMsg, TRUE);
    endif;

    nStatus = RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    if (nStatus < 0) goto error;

    nStatus = InstallServerService(TARGETDIR ^ "\\Server\\usr\\afs\\bin\\bosctlsvc.exe");
    if (nStatus < 0) goto error;

    bError = FALSE;

error:
    if (!bWSPPInstall) then
	    SdShowMsg(szMsg, FALSE);
	endif;

    if (bError) then
        Sprintf(szMsg, @AFS_SERVER_SERVICE_INSTALL_ERROR, nStatus);
        ShowError(szMsg, SEVERE);
        bInstallAborted = TRUE;
        return -1;
    endif;

    return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: ConfigClientService
//
//  Purpose: This function will configure the AFS Client service via the SCM.
//
///////////////////////////////////////////////////////////////////////////////
function ConfigClientService()
    STRING szMsg;
    BOOL bError;
    number nStatus;
begin
    bError = TRUE;

	if (!bWSPPInstall) then
    	szMsg = @CONFIGURING_AFS_CLIENT_SERVICE;
    	SdShowMsg(szMsg, TRUE);
    endif;

    nStatus = RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    if (nStatus < 0) goto error;

    nStatus = InstallClientService(TARGETDIR ^ "\\Client\\Program\\afsd_service.exe");
    if (nStatus < 0) goto error;

    bError = FALSE;

error:
    if (!bWSPPInstall) then
	    SdShowMsg(szMsg, FALSE);
	endif;

    if (bError) then
        Sprintf(szMsg, @AFS_CLIENT_SERVICE_INSTALL_ERROR, nStatus);
        ShowError(szMsg, SEVERE);
        bInstallAborted = TRUE;
        return -1;
    endif;

    return 0;
end;

///////////////////////////////////////////////////////////////////////////////
//
//  Function: AddPath
//
//  Purpose: This function will add the specified path to the system PATH
//			 environment variable.
//
///////////////////////////////////////////////////////////////////////////////
function AddPath(szPath)
begin
   LongPathToShortPath(szPath);
   if (bWin98 || bWin95) then
	   if (EzBatchAddPath ("Path", szPath, "", AFTER) < 0) then
       	 ShowError(@ADD_PATH_ERROR, WARNING);
	    endif;
    else
	   if (AddToPath(szPath) < 0) then
       	 ShowError(@ADD_PATH_ERROR, WARNING);
	    endif;
    endif;
	return 0;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: ConfigUninstallDLL
//
//  Purpose: This function will modify the uninstall entry for these products
//			 to use an uninstall dll.
//
///////////////////////////////////////////////////////////////////////////////
function ConfigUninstallDLL(pApp)
    string svValue;
    NUMBER nStatus;
begin
	if (!pApp->bUseUninstDLL) then
		return 0;
	endif;

    nStatus = RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    if (nStatus < 0) goto error;

    svValue = UNINST + " -c\"" + pApp->szBinPath ^ pApp->szUninstDllName + "\" -f\"" + TARGETDIR ^ pApp->szUninstLogfileName + "\"";

    nStatus = RegDBSetKeyValueEx(MSUNINSTALL_KEY ^ pApp->szProductName, "UninstallString", REGDB_STRING, svValue, -1);
    if (nStatus < 0) goto error;

    return 0;

error:
    return nStatus;
end;
		

///////////////////////////////////////////////////////////////////////////////
//
//  Function: CreateServerDirs
//
//  Purpose: This function will create directories that the server programs
//			 need.  The creation of these is not logged, and so they will be
//			 deleted by the uninstall dll.
//
///////////////////////////////////////////////////////////////////////////////
function CreateServerDirs()
begin
	CreateDir(TARGETDIR ^ "\\Server\\usr\\afs\\logs");
	CreateDir(TARGETDIR ^ "\\Server\\usr\\afs\\etc");
	CreateDir(TARGETDIR ^ "\\Server\\usr\\afs\\local");
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: GetDateTimeString()
//
//  Purpose: This function will return a string containing the current date
//           and time.
//
///////////////////////////////////////////////////////////////////////////////
function GetDateTimeString(szDateTime)
    STRING szDate, szTime;
    NUMBER nDate, nTime;
begin
	GetSystemInfo(DATE, nDate, szDate);
    GetSystemInfo(TIME, nTime, szTime);

    szDateTime = szDate + " " + szTime;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: SetUserVars()
//
//  Purpose: This function will set at runtime values for user defined variables
//			 we set up in the Registry Entries GUI tool.
//
///////////////////////////////////////////////////////////////////////////////
function SetUserVars()
    number nStatus;
    string szInstallDate;
    string szDesc;
    string szTitle;
    string szReleaseType;
begin
    // Set the install date variable's value
    GetDateTimeString(szInstallDate);

	ComponentSetTarget(MEDIA, "<INSTALL_DATE>", szInstallDate);

	// Set the proper client logon dll
	if (bFullClientSel) then
		ComponentSetTarget(MEDIA, "<LOGON_DLL>", TARGETDIR ^ FULL_CLIENT_LOGON_DLL);
	elseif (bLightClientSel) then
		ComponentSetTarget(MEDIA, "<LOGON_DLL>", TARGETDIR ^ LIGHT_CLIENT_LOGON_DLL);
	endif;

	// Set the client description and title values
	if (bFullClientSel || bLightClientSel) then

		if (bFullClientSel) then
			szDesc = @CLIENT_DESC;
			szTitle = @CLIENT_TITLE;
		else
			szDesc = @LIGHT_CLIENT_DESC;
			szTitle = @LIGHT_CLIENT_TITLE;
		endif;

		ComponentSetTarget(MEDIA, "<CLIENT_DESC>", szDesc);
		ComponentSetTarget(MEDIA, "<CLIENT_TITLE>", szTitle);
	endif;

	if (bServerSel) then
		ComponentSetTarget(MEDIA, "<EVENT_MSG_DLL>", TARGETDIR ^ "Common\\afseventmsg_" + szCodePage + ".dll");
	endif;

	szReleaseType = @PRODUCT_VERSION_RELEASE_TYPE;
	ComponentSetTarget(MEDIA, "<RELEASE_TYPE>", szReleaseType);

done:
	return nStatus;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: SetNetworkProviderOrder()
//
//  Purpose: This function will add the AFS Client service name to the
//			 ProviderOrder value of the
//			 HKLM\SYSTEM\CurrentControlSet\ControlNetworkProvider\Order key.
//			 It makes a call to the setup dll to do this.
///////////////////////////////////////////////////////////////////////////////
function SetNetworkProviderOrder()
	int nStatus;
begin
	nStatus = AddToNetworkProviderOrder(CLIENT_SERVICE_NAME);
	if (nStatus < 0) then
		ShowError(@SET_NETWORK_PROVIDER_ERROR, SEVERE);
	endif;

	return nStatus;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: CreateRegistrySets()
//
//  Purpose: This function will create the registry entries for each resgistry
//			 set in the passed in string.  The string must be a comma separated
//			 list of registry sets created using the IS Registry Entries GUI.
//
///////////////////////////////////////////////////////////////////////////////
function CreateRegistrySets(szRegistrySets)
	int nRegSetListID;
	int nResult;
	string szRegSet;
begin
   	nRegSetListID = ListCreate(STRINGLIST);
	
   	StrGetTokens(nRegSetListID, szRegistrySets, ",");

   	nResult = ListGetFirstString(nRegSetListID, szRegSet);
	while (nResult != END_OF_LIST)
//		MessageBox(szRegSet, INFORMATION);
		CreateRegistrySet(szRegSet);
		nResult = ListGetNextString(nRegSetListID, szRegSet);
	endwhile;
	
	ListDestroy(nRegSetListID);
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: ConfigAfsCreds()
//
//  Purpose: This function will config the AFS Client Credentials tool.
//
///////////////////////////////////////////////////////////////////////////////
function ConfigAfsCreds()
int nResult;
begin
	nResult = LaunchAppAndWait(TARGETDIR ^ "Client\\Program\\afscreds.exe", "/install", WAIT);
	if (nResult < 0) then
		ShowError(@CONFIGURING_AFS_CREDS_ERROR, INFORMATION);
	endif;
	
	return nResult;
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: IsAppInstalled
//
//  Purpose: This function will determine if an app is installed, and if it is,
//           will set its iVer info.
//
///////////////////////////////////////////////////////////////////////////////
function IsAppInstalled(pApp)
int nResult;
int nSize;
int nType;
string szKey;
string szMajorVersion, szMinorVersion, szPatchLevel, szBetaLevel, szReleaseType, szTitle;
begin
    nResult = RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    if (nResult < 0) goto error;

	szKey = COMPANY_REG_KEY ^ pApp->szProductName ^ "CurrentVersion";

	nResult = RegDBGetKeyValueEx(szKey, "MajorVersion", nType, szMajorVersion, nSize);
	if (nResult < 0) goto error;
	
	nResult = RegDBGetKeyValueEx(szKey, "MinorVersion", nType, szMinorVersion, nSize);
	if (nResult < 0) goto error;
	
	nResult = RegDBGetKeyValueEx(szKey, "PatchLevel", nType, szPatchLevel, nSize);
	if (nResult < 0) goto error;

	nResult = RegDBGetKeyValueEx(szKey, "BetaLevel", nType, szBetaLevel, nSize);
	// It's ok for this to fail.  Pre-3.5 3.32 releases did not use this.

	nResult = RegDBGetKeyValueEx(szKey, "VersionString", nType, szTitle, nSize);
	if (nResult < 0) goto error;

	nResult = RegDBGetKeyValueEx(szKey, "ReleaseType", nType, szReleaseType, nSize);
	if (nResult < 0) then
		if ((pApp->szProductName = "AFS Client") && (szTitle = "3.4a")) then
			// This value won't exist for 3.4a clients
			szReleaseType = RELEASE_TYPE_GA;
		else
			// This value won't exist for any 3.5 beta versions
			szReleaseType = RELEASE_TYPE_BETA;
		endif;
	endif;

	SetupVerInfo(pApp, szMajorVersion, szMinorVersion, szPatchLevel, szBetaLevel, szReleaseType, szTitle, TRUE);
	
	return TRUE;

error:
	return FALSE;
end;
	

///////////////////////////////////////////////////////////////////////////////
//
//  Function: LocalizeComponents()
//
//  Purpose: This function updates all components to use localized text
//           in their status fields as appropriate
//
///////////////////////////////////////////////////////////////////////////////
function LocalizeComponents()
begin
	LocalizeComponentStatusText ("Client\\Client_Common");
	LocalizeComponentStatusText ("Client\\Client_Program\\Client_Headers\\Client_Afs_Headers");
	LocalizeComponentStatusText ("Client\\Client_Program\\Client_Headers\\Client_Main_Headers");
	LocalizeComponentStatusText ("Client\\Client_Program\\Client_Headers\\Client_Rx_Headers");
	LocalizeComponentStatusText ("Client\\Client_Program\\Client_Headers");
	LocalizeComponentStatusText ("Client\\Client_Program\\Client_Sample");
	LocalizeComponentStatusText ("Client\\Client_Program");
	LocalizeComponentStatusText ("Client\\Client_System32");
	LocalizeComponentStatusText ("Client\\Client_WinDir");
	LocalizeComponentStatusText ("Client");
	LocalizeComponentStatusText ("Components");
	LocalizeComponentStatusText ("Control_Center\\Control_Center_Common");
	LocalizeComponentStatusText ("Control_Center\\Control_Center_Program");
	LocalizeComponentStatusText ("Control_Center\\Control_Center_System32");
	LocalizeComponentStatusText ("Control_Center\\Control_Center_WinDir");
	LocalizeComponentStatusText ("Control_Center");
	LocalizeComponentStatusText ("Documentation\\English\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\English\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\English\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\English");
	LocalizeComponentStatusText ("Documentation\\German\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\German\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\German\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\German");
	LocalizeComponentStatusText ("Documentation\\Japanese\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\Japanese\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\Japanese\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\Japanese");
	LocalizeComponentStatusText ("Documentation\\Korean\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\Korean\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\Korean\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\Korean");
	LocalizeComponentStatusText ("Documentation\\Portuguese\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\Portuguese\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\Portuguese\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\Portuguese");
	LocalizeComponentStatusText ("Documentation\\Simp_Chinese\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\Simp_Chinese\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\Simp_Chinese\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\Simp_Chinese");
	LocalizeComponentStatusText ("Documentation\\Spanish\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\Spanish\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\Spanish\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\Spanish");
	LocalizeComponentStatusText ("Documentation\\Trad_Chinese\\Cmd_Ref");
	LocalizeComponentStatusText ("Documentation\\Trad_Chinese\\Doc_Misc");
	LocalizeComponentStatusText ("Documentation\\Trad_Chinese\\Sys_Admin_Guide");
	LocalizeComponentStatusText ("Documentation\\Trad_Chinese");
	LocalizeComponentStatusText ("Documentation");
	LocalizeComponentStatusText ("Info");
	LocalizeComponentStatusText ("Languages\\Lang_English");
	LocalizeComponentStatusText ("Languages\\Lang_German");
	LocalizeComponentStatusText ("Languages\\Lang_Japanese");
	LocalizeComponentStatusText ("Languages\\Lang_Korean");
	LocalizeComponentStatusText ("Languages\\Lang_Portuguese");
	LocalizeComponentStatusText ("Languages\\Lang_Simp_Chinese");
	LocalizeComponentStatusText ("Languages\\Lang_Spanish");
	LocalizeComponentStatusText ("Languages\\Lang_Trad_Chinese");
	LocalizeComponentStatusText ("Languages");
	LocalizeComponentStatusText ("Light_Client\\Win95\\Light95_Client_Common");
	LocalizeComponentStatusText ("Light_Client\\Win95\\Light95_Client_Program");
	LocalizeComponentStatusText ("Light_Client\\Win95\\Light95_Client_System32");
	LocalizeComponentStatusText ("Light_Client\\Win95\\Light95_Client_WinDir");
	LocalizeComponentStatusText ("Light_Client\\Win95");
	LocalizeComponentStatusText ("Light_Client\\Win98\\Light_Client_Common");
	LocalizeComponentStatusText ("Light_Client\\Win98\\Light_Client_Program");
	LocalizeComponentStatusText ("Light_Client\\Win98\\Light_Client_System32");
	LocalizeComponentStatusText ("Light_Client\\Win98\\Light_Client_WinDir");
	LocalizeComponentStatusText ("Light_Client\\Win98");
	LocalizeComponentStatusText ("Light_Client");
	LocalizeComponentStatusText ("Readme\\English\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\English\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\English\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\English");
	LocalizeComponentStatusText ("Readme\\German\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\German\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\German\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\German");
	LocalizeComponentStatusText ("Readme\\Japanese\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\Japanese\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\Japanese\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\Japanese");
	LocalizeComponentStatusText ("Readme\\Korean\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\Korean\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\Korean\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\Korean");
	LocalizeComponentStatusText ("Readme\\Portuguese\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\Portuguese\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\Portuguese\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\Portuguese");
	LocalizeComponentStatusText ("Readme\\Simp_Chinese\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\Simp_Chinese\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\Simp_Chinese\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\Simp_Chinese");
	LocalizeComponentStatusText ("Readme\\Spanish\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\Spanish\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\Spanish\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\Spanish");
	LocalizeComponentStatusText ("Readme\\Trad_Chinese\\Doc_Misc");
	LocalizeComponentStatusText ("Readme\\Trad_Chinese\\Install_Guide");
	LocalizeComponentStatusText ("Readme\\Trad_Chinese\\Release_Notes");
	LocalizeComponentStatusText ("Readme\\Trad_Chinese");
	LocalizeComponentStatusText ("Readme");
	LocalizeComponentStatusText ("Server\\Server_Common");
	LocalizeComponentStatusText ("Server\\Server_Program");
	LocalizeComponentStatusText ("Server\\Server_System32");
	LocalizeComponentStatusText ("Server\\Server_WinDir");
	LocalizeComponentStatusText ("Server");
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: LocalizeComponentStatusText()
//
//  Purpose: This function updates one component to use localized text
//           in its status fields as appropriate
//
///////////////////////////////////////////////////////////////////////////////
function LocalizeComponentStatusText (svComponent)
	NUMBER dwResult;
	STRING svOriginal;
	STRING svLocalized;
begin
	ComponentGetData (MEDIA, svComponent, COMPONENT_FIELD_STATUS, dwResult, svOriginal);

	if (svOriginal == "CLIENT") then
		svLocalized = @STATUS_INSTALLING_CLIENT;
	elseif (svOriginal == "SERVER") then
		svLocalized = @STATUS_INSTALLING_SERVER;
	elseif (svOriginal == "CCENTER") then
		svLocalized = @STATUS_INSTALLING_CCENTER;
	elseif (svOriginal == "LIGHT") then
		svLocalized = @STATUS_INSTALLING_LIGHT;
	elseif (svOriginal == "HEADERS") then
		svLocalized = @STATUS_INSTALLING_HEADERS;
	elseif (svOriginal == "DOCS") then
		svLocalized = @STATUS_INSTALLING_DOCS;
	elseif (svOriginal == "LANGUAGE") then
		svLocalized = @STATUS_INSTALLING_LANGUAGE;
	else
		svLocalized = "";
	endif;

	ComponentSetData(MEDIA, svComponent, COMPONENT_FIELD_STATUS, 0, svLocalized);
end;


///////////////////////////////////////////////////////////////////////////////
//
//  Function: DetectInstalledComponents()
//
//  Purpose: This function will detect if any of our components is already
//           installed.
//
///////////////////////////////////////////////////////////////////////////////
function DetectInstalledComponents()
begin
	if (bWinNT) then
		bClientInstalled = IsAppInstalled(&appFullClient);
		bServerInstalled = IsAppInstalled(&appServer);
		bCcInstalled = IsAppInstalled(&appControlCenter);
		bDocsInstalled = IsAppInstalled(&appDocs);
	else
		// The light client uses the client's registry entries.  There is a light
		// client entry, but it contains nothing under it.  IS makes it but we
		// don't use it.
		bLightClientInstalled = IsAppInstalled(&appLightClient);
	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: ParseCommandLine
//
//  Purpose: This function parses the command line to set up a silent install
//
///////////////////////////////////////////////////////////////////////////////
function ParseCommandLine()
    NUMBER nResult;
    STRING szTemp, szResult[MAX_STRING_LEN], szParms;
    LIST listParms;
begin
    bWSPPInstall = FALSE;
	bPreinstallReplace = FALSE;

    szParms = CMDLINE;

    // Need a list to hold the parms
    listParms = ListCreate(STRINGLIST);

    // Break parms into semicolon separated tokens and put into list
    if (StrGetTokens(listParms, szParms, ";") = 0 ) then
       nResult = ListGetFirstString(listParms, szResult);

    	//  Do until the end of the list
    	while (nResult != END_OF_LIST)
			if (StrFind(szResult, "DIR=") > -1 ) then
            	nResult = StrSub(szTemp, szResult, 4, MAX_STRING_LEN);
            	TARGETDIR = szTemp + "\\AFS";
		
         	elseif (StrFind(szResult, "P=") > -1 ) then
            	nResult = StrSub(szTemp, szResult, StrFind(szResult, "P=") + 2, 1);
            	if (StrFind(szTemp, "Y") > -1 ) then
              		bPreinstallReplace = TRUE;
            	endif;

          	elseif (StrFind(szResult, "C=") > -1 ) then
          		ProcessCompsOnCmdLn(szResult);
          	endif;

			nResult = ListGetNextString(listParms, szResult);
		endwhile;
	endif;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: ProcessCompsOnCmdLn
//
//  Purpose: This function puts the components in a list and
//           checks for setup types on the command line.
//
//
///////////////////////////////////////////////////////////////////////////////
function ProcessCompsOnCmdLn(szParms)
     NUMBER nResult, nIndex;
     STRING szComp;
begin
    bWSPPInstall = TRUE;

	// Strip c= off cmdln string
	nResult = StrSub(szParms, szParms, StrFind(szParms, "C=") + 2, StrLength(szParms) - 2);

	// Get each component from the cmd line
    while (StrLength(szParms))
        nIndex = StrSub(szComp, szParms, 0, StrFind(szParms, ","));
        if (!nIndex) then  // if comma not found then last item in list
        	szComp = szParms;
        	nIndex = StrLength(szComp); // for extracting this string
		endif;

       	if (StrFind(szComp, "Client") > -1) then
        	bFullClientSel = TRUE;
       	elseif (StrFind(szComp, "Server") > -1) then
           	bServerSel = TRUE;
       	elseif (StrFind(szComp, "ControlCtr") > -1) then
        	bCcSel = TRUE;
        endif;

       // Delete component from the command line string
        StrSub(szParms, szParms, nIndex + 1, StrLength(szParms));
     endwhile;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: RemoveInstalledBits
//
//  Purpose: This function silently uninstalls a product.
//
///////////////////////////////////////////////////////////////////////////////
function RemoveInstalledBits(szProductName)
	int nStatus;
	int nType;
	string szValue[MAX_STRING_LEN];
	string szProgram[256];
	string szCmdLine[128];
	int nSize;
	int nIndex;
begin
	// Check for a special case - version 3.4a of the AFS Client
	if ((szProductName = "AFS Client") && (appFullClient.iVer.szTitle = "3.4a")) then
		return Eradicate34Client();
	endif;

    nStatus = RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    if (nStatus < 0) goto error;

	nStatus = RegDBGetKeyValueEx(MSUNINSTALL_KEY ^ szProductName, "UninstallString", nType, szValue, nSize);
    if (nStatus < 0) goto error;

	nIndex = StrFind(szValue, " ");
	if (nIndex < 0) goto error;
	
	StrSub(szProgram, szValue, 0, nIndex);
	StrSub(szCmdLine, szValue, nIndex + 1, 128);

	// Make the uninstall run silently
	szCmdLine = szCmdLine + " -a";

	nStatus = LaunchAppAndWait(szProgram, szCmdLine, WAIT);
	if (nStatus < 0) goto error;

	return 0;

error:
	return nStatus;
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: AddShortCut
//
//  Purpose: Adds a short cut to the start menu.
//
///////////////////////////////////////////////////////////////////////////////
function AddShortCut(szFolder, szName, szCmdPath, szArgs)
	int result;
	string szCmd;
begin
	szCmdPath = TARGETDIR ^ szCmdPath;
	LongPathToQuote(szCmdPath, TRUE);
	
	szCmd = szCmdPath + " " + szArgs;
	
	nResult = AddFolderIcon(SHELL_OBJECT_FOLDER ^ szFolder, szName, szCmd, "", "", 0, "", REPLACE);
	
	return nResult;
end;



























///////////////////////////////////////////////////////////////////////////////
//
// Function: CreateStartMenuEntries
//
//  Purpose: This function creates start menu entries for our apps.
//
///////////////////////////////////////////////////////////////////////////////
function CreateStartMenuEntries()
begin
	if (bServerSel) then
		AddShortCut(@SERVER_GROUP_NAME, @CFG_WIZARD_ITEM_NAME, CFG_WIZARD_CMD_PATH, CFG_WIZARD_ARGS);
	endif;
	
	if (bFullClientSel) then
		AddShortCut(@CLIENT_GROUP_NAME, @CREDS_TOOL_ITEM_NAME, CREDS_TOOL_CMD_PATH, CREDS_TOOL_ARGS);
		AddShortCut(@CLIENT_GROUP_NAME, @CLIENT_HELP_ITEM_NAME, CLIENT_HELP_CMD_PATH, CLIENT_HELP_ARGS);
	endif;
	
	if (bCcSel) then
		AddShortCut(@CCENTER_GROUP_NAME, @SERVER_MANAGER_ITEM_NAME, SERVER_MANAGER_CMD_PATH, SERVER_MANAGER_ARGS);
		AddShortCut(@CCENTER_GROUP_NAME, @ACCT_MANAGER_ITEM_NAME, ACCT_MANAGER_CMD_PATH, ACCT_MANAGER_ARGS);
	endif;
	
	if (bLightClientSel) then
		AddShortCut(@LIGHT_GROUP_NAME, @CREDS_TOOL_ITEM_NAME, CREDS_TOOL_CMD_PATH, CREDS_TOOL_ARGS);
		AddShortCut(@LIGHT_GROUP_NAME, @LIGHT_CLIENT_HELP_ITEM_NAME, LIGHT_CLIENT_HELP_CMD_PATH, LIGHT_CLIENT_HELP_ARGS);
	endif;

	AddShortCut("", @DOCUMENTATION_ITEM_NAME, DOCUMENTATION_CMD_PATH, DOCUMENTATION_ARGS);
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: ShowError
//
//  Purpose: This function shows an error to the user when not in silent mode,
//           and will log an error to a file when in silent mode.
//
///////////////////////////////////////////////////////////////////////////////
function ShowError(szMsg, nType)
    string szType;
    int nFileID;
begin
    if (!bWSPPInstall) then
        MessageBox(szMsg, nType);
        return;
    endif;

    switch (nType)
        case WARNING:       szType = "Warning: ";
        case SEVERE:        szType = "Error: ";
        case INFORMATION:   szType = "Note: ";
        default:            szType = "Unknown error type: ";
    endswitch;

    WriteToInstallErrorLog(szType + szMsg);
end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: CheckCopyCellServDB
//
//  Purpose: During install the CellServDB file is copied into the Common dir.
//			 If the user does not already have this file, we will copy it for
//           them into the windows directory.  If they already do have the
//           file, then we will do nothing.
///////////////////////////////////////////////////////////////////////////////
function CheckCopyCellServDB()
	int nResult;
	string szResult;
begin
	nResult = FindFile(WINDIR, CELLSERVDB_FILENAME, szResult);
	if (nResult < 0) then
		VarSave(SRCTARGETDIR);
		SRCDIR = TARGETDIR ^ "Common";
		TARGETDIR = WINDIR;
		CopyFile(CELLSERVDB_FILENAME, CELLSERVDB_FILENAME);
		VarRestore(SRCTARGETDIR);
	endif;
end;


// --- include script file section ---
#include "sddialog.rul"
