'**************************************************************************
'*                       MSSetup Toolkit XSCOPE installation
'**************************************************************************


'$INCLUDE 'setupapi.inc'
'$INCLUDE 'msdetect.inc'

''Dialog ID's
CONST ASKQUIT       = 200
CONST DESTPATH      = 300
CONST EXITFAILURE   = 400
CONST EXITQUIT      = 600
CONST EXITSUCCESS   = 700
CONST OPTIONS       = 800
CONST EXITPOST	    = 1000
CONST DISKSPACE	    = 1100
CONST EXISTING	    = 1200
CONST SYSCONFIG	    = 1300
CONST BADPATH       = 6400
CONST BADDRIVE	    = 6500
CONST BADSYNTAX	    = 6600

CONST RETRY         = 1
CONST CANCEL        = 2
CONST NO            = 3
CONST YES           = 4
CONST MODIFY        = 5

''Bitmap ID
CONST LOGO = 1

''File Types
CONST APPFILES     = 1

GLOBAL CUIDLL$      ''Name of the customize user interface DLL
GLOBAL DEST$        ''Default destination directory.
GLOBAL DESTDRIVE$   ''Default destination drive.
GLOBAL DESTROOT$    ''Default destination root directory.
GLOBAL WINDRIVE$    ''Windows drive letter.

GLOBAL DRIVETEXT$   ''Dialog interface list (needed/avail space on drives)
GLOBAL RELFNAME$    ''Dialog interface list (release filename)
GLOBAL DRVINFO$     ''Dialog interface list (drive letter)    

GLOBAL INSTALLED%

DECLARE FUNCTION RemoveDirectory LIB "rmdir.dll" (dirname$) AS INTEGER
DECLARE FUNCTION pmDeleteGroup LIB "pmdde.dll" (Group$) AS INTEGER
DECLARE FUNCTION pmShowGroup LIB "pmdde.dll" (Group$, Cmd%) AS INTEGER
DECLARE FUNCTION pmDeleteItem LIB "pmdde.dll" (Item$) AS INTEGER
DECLARE FUNCTION pmGetFirstItem LIB "pmdde.dll" (Group$) AS INTEGER
DECLARE FUNCTION pmGetNextItem LIB "pmdde.dll" AS INTEGER
DECLARE FUNCTION pmCloseGetItem LIB "pmdde.dll" AS INTEGER
DECLARE FUNCTION pmShutdownDde LIB "pmdde.dll" AS INTEGER

DECLARE FUNCTION MakePath (szDir$, szFile$) AS STRING
DECLARE FUNCTION CheckDiskSpace AS LONG
DECLARE FUNCTION CheckSyntax (path$) AS INTEGER
DECLARE SUB CheckSystemConfig
DECLARE SUB Install
DECLARE SUB UnInstall
DECLARE SUB RemoveIcons

INIT:
    INSTALLED% = NO
    CUIDLL$ = "mscuistf.dll"            ''Custom user interface dll

    SetBitmap CUIDLL$, LOGO
    SetTitle "X-Scope 1.4.2"

    szInf$ = GetSymbolValue("STF_SRCINFPATH")
    IF szInf$ = "" THEN
        szInf$ = GetSymbolValue("STF_CWDDIR") + "XSCOPE.INF"
    END IF
    ReadInfFile szInf$

    WINDRIVE$ = ucase$(MID$(GetWindowsDir, 1, 1))
    DEST$ = "C:\XSST14"
    DESTDRIVE$ = ucase$(MID$(DEST$, 1, 1))
    DESTROOT$ = MID$(DEST$, 1, 3)

    '' Drive letter information
    DRVINFO$ = "DriveInfoText"
    AddListItem DRVINFO$, ""

    '' Release information for existing X-Scope
    RELFNAME$   = "ReleaseFileText"
    AddListItem RELFNAME$, ""

    '' Drive available/needed information
    DRIVETEXT$  = "DriveStatusText"
    FOR i% = 1 TO 7 STEP 1
        AddListItem DRIVETEXT$, ""
    NEXT i%

GETPATH:
    SetSymbolValue "EditTextIn", DEST$
    SetSymbolValue "EditFocus", "END"
GETPATHL1:
    sz$ = UIStartDlg(CUIDLL$, DESTPATH, "FEditDlgProc", 0, "")
    DEST$ = GetSymbolValue("EditTextOut")

    IF sz$ = "OK" THEN
        IF CheckSyntax(DEST$) = 0 THEN
            GOSUB BADSYNTAX
            GOTO GETPATHL1
        END IF

        DESTDRIVE$ = ucase$(MID$(DEST$, 1, 1))
        DESTROOT$ = MID$(DEST$, 1, 3)

TESTDRIVE:
        IF IsDriveValid(DESTDRIVE$) = 0 OR IsDirWritable(DESTROOT$) = 0 THEN
            GOSUB BADDRIVE
            IF action% = RETRY THEN
                GOTO TESTDRIVE
            ELSE    
                GOTO GETPATHL1
            END IF    
        END IF
        IF DoesDirExist(DEST$) = 0 THEN
            GOSUB BADPATH
            IF action% = NO THEN
                GOTO GETPATHL1
            END IF    
        END IF
        IF DoesFileExist(MakePath(DEST$, "xscope.exe"), femExists) = 1 THEN
            GOSUB EXISTED
            IF action% = CANCEL THEN
                GOSUB ASKQUIT
                GOTO GETPATH
            ELSEIF action% = MODIFY THEN
                GOTO GETPATHL1
            END IF
        END IF
        UIPop 1
    ELSEIF sz$ = "REACTIVATE" THEN
        GOTO GETPATHL1
    ELSE
        GOSUB ASKQUIT
        GOTO GETPATH
    END IF

    '' The subroutine that will perform an XSCOPE installation is called.    
    Install

QUIT:
    ON ERROR GOTO ERRQUIT

    IF ERR = 0 THEN
QUITL1:
        sz$ = UIStartDlg(CUIDLL$, EXITSUCCESS, "FInfo0DlgProc", 0, "")
        IF sz$ = "REACTIVATE" THEN
            GOTO QUITL1
        END IF
        UIPop 1

        '' Check the system configuration for minimum requirements
        CheckSystemConfig

EXITOK:
        sz$ = UIStartDlg(CUIDLL$, EXITPOST, "FInfo0DlgProc", 0, "")
        IF sz$ = "REACTIVATE" THEN
            GOTO EXITOK
        END IF
        UIPop 1
        END
    END IF

    '' In case of a failure uninstall XSCOPE
    UnInstall

    IF ERR = STFQUIT THEN
        END
    END IF    

EXITFAIL:
    sz$ = UIStartDlg(CUIDLL$, EXITFAILURE, "FInfo0DlgProc", 0, "")
    IF sz$ = "REACTIVATE" THEN
        GOTO EXITFAIL
    END IF
    UIPop 1

    END

ERRQUIT:
    UnInstall
    i% = DoMsgBox("X-Scope diskettes were corrupted!", "Installation Message", MB_OK+MB_TASKMODAL+MB_ICONHAND)
    END

BADPATH:
    action% = YES
    sz$ = UIStartDlg(CUIDLL$, BADPATH, "FInfo1DlgProc", 0, "")
    IF sz$ = "NO" THEN
        action% = NO
    ELSEIF sz$ = "REACTIVATE" THEN
        GOTO BADPATH
    END IF
    UIPop 1
    RETURN

BADDRIVE:
    action% = RETRY
    ReplaceListItem DRVINFO$, 1, DESTDRIVE$ + ":"
    sz$ = UIStartDlg(CUIDLL$, BADDRIVE, "FInfo2DlgProc", 0, "")
    IF sz$ = "CANCEL" THEN
        action% = CANCEL
    ELSEIF sz$ = "REACTIVATE" THEN
        GOTO BADDRIVE
    END IF
    UIPop 1
    RETURN

BADSYNTAX:
    sz$ = UIStartDlg(CUIDLL$, BADSYNTAX, "FInfo0DlgProc", 0, "")
    IF sz$ = "REACTIVATE" THEN
        GOTO BADSYNTAX
    END IF
    UIPop 1
    RETURN

EXISTED:
    action% = OK
    release$ = GetIniKeyString(MakePath(DEST$, "xscope.ini"), "Release_Data", "Release")
    ReplaceListItem RELFNAME$, 1, release$

EXISTEDL1:
    sz$ = UIStartDlg(CUIDLL$, EXISTING, "FExistDlgProc", 0, "")
    IF sz$ = "CANCEL" THEN
        action% = CANCEL
    ELSEIF sz$ = "MODIFY" THEN
        action% = MODIFY
    ELSEIF sz$ = "REACTIVATE" THEN
        GOTO EXISTEDL1
    END IF
    '' Check if Overwrite has been selected by the user (action OK)    
    IF action% = OK THEN
        '' Try to create the program manager group to make sure it's there.
        '' It should be because a previous X-Scope version is installed.
        CreateProgmanGroup "X-Scope 1.4", "", cmoNone

        '' Remove any icons that point to overwritten files
        RemoveIcons
    END IF
    UIPop 1
    RETURN

ASKQUIT:
    sz$ = UIStartDlg(CUIDLL$, ASKQUIT, "FQuitDlgProc", 0, "")

    IF sz$ = "YES" THEN
        UIPopAll
        ERROR STFQUIT
    ELSEIF sz$ = "REACTIVATE" THEN
        GOTO ASKQUIT
    ELSE
        UIPop 1
    END IF
    RETURN

'**
'** Purpose:
'**     Scans for icons in the "X-Scope" group and removes any icons
'**     that point to files that will be overwritten.
'** Arguments:
'**     none.
'** Returns:
'**     none.
'*************************************************************************
SUB RemoveIcons STATIC
    DELETELIST$ = "DELETE_LIST"

    '' First minimize the group, then activate and display it
    res% = pmShowGroup("X-Scope 1.4", 6)
    IF res% = 0 THEN 
        GOTO SHUTDOWNSCAN
    END IF

    res% = pmShowGroup("X-Scope 1.4", 1)
    IF res% = 0 THEN 
        GOTO SHUTDOWNSCAN
    END IF

    '' Get information on the first icon 
    res% = pmGetFirstItem("X-Scope 1.4")

ICONSCAN:
    '' If no more icons then exit the scan loop
    IF res% = 0 THEN 
        GOTO CLOSESCAN
    END IF

    '' Get the icon name and the icon information
    Icon$ = GetSymbolValue("ICON_DATA")
    Item$ = GetSymbolValue("ITEM_DATA")

    '' Only check for item info that refers to installation defined icons
    IF MakePath(DEST$, "XSCOPE.EXE") = UCASE$(Item$) THEN
        '' Mark the icon in the group for deletion
        AddListItem DELETELIST$, Icon$
    END IF

    '' Only check for item info that refers to installation defined icons
    IF MakePath(DEST$, "README.TXT") = UCASE$(Item$) THEN
        '' Mark the icon in the group for deletion
        AddListItem DELETELIST$, Icon$
    END IF

    '' PLJ remove old helpfile icon
    '' Only check for item info that refers to installation defined icons
    IF MakePath(DEST$, "XSCOPE.HLP") = UCASE$(Item$) THEN
        '' Mark the icon in the group for deletion
        AddListItem DELETELIST$, Icon$
    END IF

    '' Get information on the next icon 
    res% = pmGetNextItem

    GOTO ICONSCAN

CLOSESCAN:
    '' Shutdown the get item code (releases globally allocated memory)
    res% = pmCloseGetItem

    FOR i% = 1 TO GetListLength(DELETELIST$) STEP 1
        Icon$ = GetListItem(DELETELIST$, i%)
        res% = pmDeleteItem(Icon$)
    NEXT i%


SHUTDOWNSCAN:
    '' Shutdown the DDE code
    res% = pmShutdownDde
END SUB

'**
'** Purpose:
'**     Builds the copy list and performs all installation operations.
'**     Also checks if the diskspace needed suffices.
'** Arguments:
'**     none.
'** Returns:
'**     none.
'*************************************************************************
SUB Install STATIC

    '' Set the indication that an install has been started
    INSTALLED% = YES

    SrcDir$ = GetSymbolValue("STF_SRCDIR")
    CreateDir DEST$, cmoNone

    '' Add the files section to the copy list
    AddSectionFilesToCopyList "PrgFiles", SrcDir$, DEST$
    '' Add the DllFiles section to the copy list
    '' AddSectionFilesToCopyList "DllFiles", SrcDir$, GetWindowsDir

    '' Perform a check on the available diskspace
    StillNeeded& = CheckDiskSpace

    '' If there is insufficient diskspace then abort the installation
    IF StillNeeded& > 0 THEN
NOROOM1:
        sz$ = UIStartDlg(CUIDLL$, DISKSPACE, "FDiskDlgProc", 0, "")
        IF sz$ = "REACTIVATE" THEN
            GOTO NOROOM1
        END IF
        UIPop 1

        '' Remove the X-Scope directory
        res% = RemoveDirectory(DEST$)
        
        END    
    END IF

    '' Delete the file with the X-Scope default settings
    RemoveFile MakePath(DEST$, "XSDEFLT.SET"), CmoForce

    '' Copy files to the windows and install directory
    CopyFilesInCopyList

    '' Get the release string from the new xscope.ini file
    release$ = GetIniKeyString(MakePath(DEST$, "xscope.ini"), "Release_Data", "Release")

    CreateProgmanGroup "X-Scope 1.4", "", cmoNone
    ShowProgmanGroup  "X-Scope 1.4", 1, cmoNone
    CreateProgmanItem "X-Scope 1.4", "X-Scope "+release$, MakePath(DEST$,"xscope.exe"), "", cmoOverwrite
    CreateProgmanItem "X-Scope 1.4", "README X-Scope "+release$, "notepad.exe "+MakePath(DEST$,"readme.txt"), "", cmoOverwrite
    '' PLJ new for release 142
    CreateProgmanItem "X-Scope 1.4", "HELP X-Scope "+release$, MakePath(DEST$,"xscope.hlp"), "", cmoOverwrite

END SUB

'**
'** Purpose:
'**     Uninstalls X-Scope
'** Arguments:
'**     none.
'** Returns:
'**     none.
'*************************************************************************
SUB UnInstall STATIC

    '' Check if the installation has already started
    IF INSTALLED% = YES THEN

        '' Delete all the files in the X-Scope directory
        KILL MakePath(DEST$, "*.*")

        '' Remove the X-Scope directory
        res% = RemoveDirectory(DEST$)
    END IF

END SUB

'**
'** Purpose:
'**     Checks the minimum requirements for the system configuration.
'** Arguments:
'**     none.
'** Returns:
'**     none.
'*************************************************************************
SUB CheckSystemConfig STATIC

    IF GetConfigNumFiles() < 30 THEN
SYSCONFIGL1:
        sz$ = UIStartDlg(CUIDLL$, SYSCONFIG, "FInfo0DlgProc", 0, "")
        IF sz$ = "REACTIVATE" THEN
            GOTO SYSCONFIGL1
        END IF
        UIPop 1
    END IF    
END SUB

'**
'** Purpose:
'**     Checks the available diskspace and returns the diskspace that 
'**     is still needed for the installation.
'** Arguments:
'** Returns:
'**     The diskspace still needed for the installation.
'*************************************************************************
FUNCTION CheckDiskSpace STATIC AS LONG

    APPNEEDS$   = "AppNeeds"
    EXTRACOSTS$ = "ExtraCosts"

    '' Set the installation destination path in the list
    ReplaceListItem DRIVETEXT$, 7, DEST$

    '' Initialise the extracosts list    
    FOR i% = 1 TO 26 STEP 1
        AddListItem EXTRACOSTS$, "0"
    NEXT i%

    CursorSave% = ShowWaitCursor()

    ''Add extra cost to Windows drive for ini/progman, etc.
    wndrive% = ASC(ucase$(WINDRIVE$)) - ASC("A") + 1
    ReplaceListItem EXTRACOSTS$, wndrive%, "262144"   '' 256 Kb

    ''Add extra cost to X-Scope drive for X-Scope data files and decompress
    ndrive% = ASC(ucase$(DESTDRIVE$)) - ASC("A") + 1
    ReplaceListItem EXTRACOSTS$, ndrive%, "2097152"   '' 2 Mb

    StillNeed& = GetCopyListCost(EXTRACOSTS$, APPNEEDS$, "")

    StillNeed& = StillNeed& - 716800       '' 700 Kbytes (setup overhead)

    cost& = 0
    FOR i% = 1 TO 26 STEP 1
        cost&  = cost& + VAL(GetListItem(APPNEEDS$, i%))
    NEXT i%

    ReplaceListItem EXTRACOSTS$, wndrive%, "0"
    ReplaceListItem EXTRACOSTS$, ndrive%, "0"

    RestoreCursor CursorSave%

    ndrive% = ASC(ucase$(DESTDRIVE$)) - ASC("A") + 1
    cost& = VAL(GetListItem(APPNEEDS$, ndrive%))
    free& = GetFreeSpaceForDrive(DESTDRIVE$)
    free& = free& + 716800       '' 700 Kbytes (setup overhead)
    ReplaceListItem DRIVETEXT$, 1, DESTDRIVE$ + ":"
    ReplaceListItem DRIVETEXT$, 2, STR$(cost& / 1024) + " K"
    ReplaceListItem DRIVETEXT$, 3, STR$(free& / 1024) + " K"

    IF DESTDRIVE$ = WINDRIVE$ THEN
        ReplaceListItem DRIVETEXT$, 4, ""
        ReplaceListItem DRIVETEXT$, 5, ""
        ReplaceListItem DRIVETEXT$, 6, ""
    ELSE
        wndrive% = ASC(ucase$(WINDRIVE$)) - ASC("A") + 1
        cost& = VAL(GetListItem(APPNEEDS$, wndrive%))
        IF cost& = 0 THEN
            ReplaceListItem DRIVETEXT$, 4, ""
            ReplaceListItem DRIVETEXT$, 5, ""
            ReplaceListItem DRIVETEXT$, 6, ""
        ELSE
            free& = GetFreeSpaceForDrive(WINDRIVE$)
            ReplaceListItem DRIVETEXT$, 4, WINDRIVE$ + ":"
            ReplaceListItem DRIVETEXT$, 5, STR$(cost& / 1024) + " K"
            ReplaceListItem DRIVETEXT$, 6, STR$(free& / 1024) + " K"
        END IF
    END IF

    CheckDiskSpace = StillNeed&
END FUNCTION

'**
'** Purpose:
'**     Checks the syntax of the specified path.
'** Arguments:
'** Returns:
'**     1 of correct syntax, - if not.
'*************************************************************************
FUNCTION CheckSyntax (path$) STATIC AS INTEGER

    '' Initially assume bad syntax for the specified path
    result% = 0

    '' Check if a colon is specified
    IF MID$(path$, 2, 1) = ":" THEN

    '' Check if a backslash is specified
    IF MID$(path$, 3, 1) = "\" THEN

    '' Check if a driveletter is specified
    IF ASC(ucase$(MID$(path$, 1, 1))) >= ASC("A") AND ASC(ucase$(MID$(path$, 1, 1))) <= ASC("Z") THEN

    '' Check if a terminating backslash is NOT specified
    IF MID$(path$, LEN(path$), 1) <> "\" THEN

    '' Assume OK for now (assume all characters to be valid)
    result% = 1

    '' Scans the path to validate all characters
    cnt% = 0
    max% = 8
    backslash% = 0
    FOR i% = 1 TO LEN(path$) STEP 1
        IF result% = 1 THEN
        IF INSTR("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.!$()-_{}@#%^&'`~:\\", ucase$(MID$(path$, i%, 1))) = 0 THEN
            '' The end result is NOT OK (invalid char detected)
            result% = 0
        END IF
        
        IF MID$(path$, i%, 1) = "\" OR MID$(path$, i%, 1) = "." THEN
            '' Check if the maximum subdir length has been exceeded
            IF cnt% > max% THEN
                '' The end result is NOT OK (subdir too long)
                result% = 0
            END IF    

            '' Adjust the counter and the maximum subdir length counters
            IF MID$(path$, i%, 1) = "\" THEN
                IF backslash% = 1 THEN
                    result% = 0
                END IF
                backslash% = 1
                cnt% = 0
                max% = 8
            ELSE
                IF cnt% = 0 THEN
                    result% = 0
                END IF
                cnt% = cnt% + 1         '' The dot is also counted
                backslash% = 0
                max% = 12
            END IF
        ELSE
            cnt% = cnt% + 1
            backslash% = 0
        END IF

        ENDIF
    NEXT

    '' Check if the maximum subdir length has been exceeded
    IF cnt% > max% THEN
        '' The end result is NOT OK (subdir too long)
        result% = 0
    END IF

    END IF
    END IF
    END IF
    END IF

    CheckSyntax = result%

END FUNCTION

'**
'** Purpose:
'**     Appends a file name to the end of a directory path,
'**     inserting a backslash character as needed.
'** Arguments:
'**     szDir$  - full directory path (with optional ending "\")
'**     szFile$ - filename to append to directory
'** Returns:
'**     Resulting fully qualified path name.
'*************************************************************************
FUNCTION MakePath (szDir$, szFile$) STATIC AS STRING
    IF szDir$ = "" THEN
        MakePath = UCASE$(szFile$)
    ELSEIF szFile$ = "" THEN
        MakePath = UCASE$(szDir$)
    ELSEIF MID$(szDir$, LEN(szDir$), 1) = "\" THEN
        MakePath = UCASE$(szDir$ + szFile$)
    ELSE
        MakePath = UCASE$(szDir$ + "\" + szFile$)
    END IF
END FUNCTION


'' 18 October 1995
''      MDONKERS: doubled the extra costs for Windows drive and X-Scope drive
'' 19 January 1996
''      MDONKERS: implemented deletion of existing icons if they reference 
''                overwritten files
'' 24 March 1997
''      MDONKERS: added CB5.DLL and updated version number from 1.2 to 1.4
'' 14-11-97 
''      PJANSON:  updated for r 142 added help icon?
'' 6-1-1998 
''      PJANSON:  path and group for R1.4.2 will be xsst14 and X-Scope 1.4
