Subversion Repositories DevTools

Rev

Rev 1530 | Blame | Compare with Previous | Last modification | View Log | RSS feed

// Include header files /////////////////////////////////////////////////////

#include "ishieldlib.h"          
                               
                                                                                      


/*-------------------------------------------------------------------------*/
/*   FileStrReplace - Search and replace a string in a file                */
/*     Mark Kendzior - mrk@amlibs.com                                     */
/*                                                                         */
/*   Function: FileStrReplace(svFileName, //Full path of file to be updated*/
/*                            szSubStr, //String to be replaced            */
/*                            szReplaceStr) //String to replace            */
/*                                                                         */
/*   Descrip:  Convienence procedure to replace the szSubStr with          */
/*             with szRelpaceStr in the file specified.                    */
/*             Return Values:                                              */
/*               1 - String replace worked.                                */
/*               0 - String replace failed.                                */
/*                                                                         */
/*   Update: 05 August 1999 - Fixed endless loop when the original string  */
/*           is replaced with a string that contains the original string.  */
/*                                                                         */
/*-------------------------------------------------------------------------*/

function islib_FileStrReplace (svFileName, szSubStr, szReplaceStr)
    NUMBER nvPos, nResult;
    STRING svString, svSubStr1, svSubStr2, svNewString;
    BOOL   bListUpdated, bFound;
    LIST   listID, listNew;    
    
begin
  // create lists
   listID = ListCreate(STRINGLIST);
   listNew = ListCreate(STRINGLIST);
   if (ListReadFromFile(listID, svFileName) < 0) then // read list from file
      islib_MessageBox("ListReadFromFile failed.", SEVERE);
      return 0;
   endif;
//
//   SdShowInfoList ("", "Before replace", listID);

   bListUpdated = FALSE;
   nResult = ListGetFirstString (listID, svString);         // start at the top of the list
   while (nResult = 0)

     bFound = FALSE; svNewString = "";
     nvPos = StrFind (svString, szSubStr);        // find position in string
     while (nvPos >= 0)
       StrSub (svSubStr1, svString, 0, nvPos);    // replace string
       StrSub (svSubStr2, svString, nvPos+StrLength (szSubStr), StrLength (svString));
       svNewString = svNewString + svSubStr1 + szReplaceStr;
       svString = svSubStr2;
       bFound = TRUE;
       nvPos = StrFind (svString, szSubStr);        // find position in string
     endwhile;
     if bFound = TRUE then
       svNewString = svNewString + svString;      // append rest of line
       ListAddString (listNew, svNewString, AFTER);  // insert new string into new list
       bListUpdated = TRUE;                       // flag to write new list to file
     else // Add unchanged string to new list
       ListAddString (listNew, svString, AFTER);  // insert string into new list
     endif;

     nResult = ListGetNextString (listID, svString);
   endwhile;

   if bListUpdated then
     ListWriteToFile (listNew, svFileName);        // write list to file
   endif;
//
//   SdShowInfoList ("", "After replace", listNew);

   ListDestroy (listID);
   ListDestroy (listNew);
   return 1;
end;





//////////////////////////////////////////////////////////////////////////////////////////
//
// Function:    islib_ModString
//
// Purpose:     Function to search and replace text in a string. 
//                              Handy for reversing forward slashes in path descriptions.
//
//////////////////////////////////////////////////////////////////////////////////////////


function islib_ModString( szSubStr, szReplaceStr, szTargetString)

STRING  szInputDirectory;   
STRING  szNewString, szSubStr1, szSubStr2, szString;
NUMBER  nError, nPos; 
BOOL    bFound;
         
begin  
        szString = szTargetString;         
        bFound = FALSE; 
        szNewString = "";
        
        nPos = StrFind (szString, szSubStr);                            // find position in string
    
    while (nPos >= 0)
        StrSub (szSubStr1, szString, 0, nPos);                  // replace string       
        StrSub (szSubStr2, szString, nPos+StrLength (szSubStr), StrLength (szString));
       
        szNewString = szNewString + szSubStr1 + szReplaceStr;
        szString = szSubStr2;
        
        bFound = TRUE;
        nPos = StrFind (szString, szSubStr);                    // find position in string
     endwhile;
     
     if bFound = TRUE then
       szTargetString = szNewString + szString;                 // append rest of line
     endif;

end;



///////////////////////////////////////////////////////////////////////////////
//
// Function: islib_UpdateIniFile
//
// Purpose: Add all configuration data to the properties files supplied.
//                      General purpose function, calls specific functions to reduce code.
//
///////////////////////////////////////////////////////////////////////////////

function islib_UpdateIniFile(szMyFileName, szMyTag, szMyReplaceStr)
begin   
    
    if ( islib_FileStrReplace (szMyFileName, szMyTag, szMyReplaceStr) = 0 )
    then
        islib_MessageBox ( "Failed to update file=[" + szMyFileName + "], replace tag=[" +szMyTag+ "], update string=[" + szMyReplaceStr + "].\n" +
                     "Installation did not complete successfully.", SEVERE);                
    endif;                        
                                                                             
end;  


 


//////////////////////////////////////////////////////////////////////////////
//                                                                           
//  FUNCTION:   islib_LocalHostname                                            
//                                                                           
//  EVENT:      Function to extract the system hostname from the registry. It
//                              may not be accurate however, if the system has 2 ethernet cards or
//                              runs on DHCP.
//                                                                           
///////////////////////////////////////////////////////////////////////////////

function islib_LocalHostname( szHostname )

        STRING szRegKey;  
        NUMBER nvType, nvSize;
        
begin 

        szRegKey = "\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters";
        
        RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
        if (RegDBKeyExist (szRegKey) = 1) then    
                RegDBGetKeyValueEx ( szRegKey, "Hostname", nvType, szHostname, nvSize );
                return 1;
        else
                return 0;
        endif;

end;



//////////////////////////////////////////////////////////////////////////////
//                                                                           
//  FUNCTION:   islib_Interbase                                         
//                                                                           
//  EVENT:      Function to extract the install location of Borland or Firebird
//                              Interbase from the registry. Function provides 2 strings of data
//                              - first the location of the Interbase, and then the specific type.
//                                                                           
///////////////////////////////////////////////////////////////////////////////

function islib_Interbase( szIBType, szIBDir )

        STRING szRegKey;  
        NUMBER nvType, nvSize;
        
begin 

    RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
        szRegKey = "\\SOFTWARE\\Borland\\InterBase\\CurrentVersion";
        
        if (RegDBKeyExist (szRegKey) = 1) then
                RegDBGetKeyValueEx ( szRegKey, "RootDirectory", nvType, szIBDir, nvSize );
                szIBType = "BORLAND"; 
                return 1;
        else
                szRegKey = "\\SOFTWARE\\FirebirdSQL\\Firebird\\CurrentVersion";

                if (RegDBKeyExist (szRegKey) = 1) then 
                        RegDBGetKeyValueEx ( szRegKey, "RootDirectory", nvType, szIBDir, nvSize );
                        szIBType = "FIREBIRD";
                        return 1;
                else
                        return 0;
                endif; 
         endif;
end;




//////////////////////////////////////////////////////////////////////////////
//                                                                           
//  FUNCTION:   islib_AccessControl                                         
//                                                                           
//  EVENT:      Function to extract the install location of the access control
//                              client and return the value.
//                                                                           
///////////////////////////////////////////////////////////////////////////////

function islib_AccessControl( szACDir )

        STRING szRegKey;  
        NUMBER nvType, nvSize;
        
begin 

    RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
        szRegKey = ERGAFC_PKG_REGISTRY_BASE + "ERGacclnt";
        
        if (RegDBKeyExist (szRegKey) = 1) then
                RegDBGetKeyValueEx ( szRegKey, "BaseInstallDir", nvType, szACDir, nvSize );
                return 1;
        else                            
                return 0;
        endif; 

end;


//////////////////////////////////////////////////////////////////////////////
//                                                                           
//  FUNCTION:   islib_setErgAfcPkgRegistryKeys       
//
//  This function sets the predefined registry key
//  for an ERG AFC package.
//
//  We assume the key(s) shall exist in the following
//  default location of the registry:
//  
//  HKEY_LOCAL_MACHINE\SOFTWARE\ERG\AFC
//
//  the key name shall be defined by the 
//  InstallShield project string ID_STING2.
//
//  i.e. PKG_NAME = "ERGpxyif"
//
//  The function shall also create the following string
//  parameters under this key these shall incllude:
//  
//  PkgName         = PKG_NAME 
//  PkgNameLong     = PKG_NAMELONG 
//  PkgVersion      = PKG_VERSION 
//  PkgBuilbNum     = PKG_BUILDNUM
//  PkgProjAcronym  = PKG_PROJECTACRONYM
//  PkgDesc         = PKG_DESC
//  BaseInstallDir  = [INSTALLDIR]
//  PkgInstalled    = Date/Time Package was installed
//
//  Return Values:
//
//   SUCCESS: 1
//   ERROR:  -1
//
//   The function shall abort the installation if the 
//   package subject string is greater that the predefined
//   allowable length size @MAX_PKGNAME_LENGTH.
//
//////////////////////////////////////////////////////////////////////////////                       
function islib_setErgAfcPkgRegistryKeys( nzType )  

    STRING  szKey;
    STRING  szItem;
    STRING  szValue;
    STRING  szClass;             
    STRING  szMaxPkgNameLength;
    STRING  szTime;
    STRING  szDate;              

    NUMBER nzResult;
    NUMBER nzERROR;
    NUMBER nzSUCCESS; 
    NUMBER nzMaxPkgNameLength;         
    
begin 


    if ( nzType != DEVICE_REGTYPE && nzType != PKG_REGTYPE )
    then  
    
        islib_MessageBox("Invalid parameter passed to islib_setErgAfcPkgRegistryKeys().", SEVERE);
        abort;
    
    endif; 

    
    // now we just check to see if the project version numbers entered match
    // if they do not we warn, it not good to exit at this point we need to ensure the rest of 
    // the install completes so we have a chnace of uninstall.
    //
    // we canot however check the build number and project acronym easily.
    //                    
    if ( PKG_VERSION != @PRODUCT_VERSION )
    then
        
         islib_MessageBox("The build.pl PKG_VERSION=[" +PKG_VERSION+ "] property does not match the Ishield PRODUCT_VERSION=["+@PRODUCT_VERSION+"] property.\n" +
                          "Please review the IShield Product Properties with the local build.pl details before compiling.", SEVERE);            
    
    endif; 

                              
    // Define my local return values.                  
    //
    nzMaxPkgNameLength = MAX_PKGNAME_LENGTH;  
    NumToStr ( szMaxPkgNameLength, nzMaxPkgNameLength );             
            
            
    // we shall check to ensure the package name
    // that is stored in the ID_STRING2 string
    // does not exceed the predeifned 10 character limit.
    if ( StrLengthChars ( PKG_NAME ) < 0 )
    then       
   
        islib_MessageBox ("ERROR: Installation could not determine the package subject [" +
                     PKG_NAME + "].", SEVERE);
        return ISLIB_ERROR;      
   
    endif;
    
    if ( StrLengthChars ( PKG_NAME ) > nzMaxPkgNameLength )
    then       
   
        islib_MessageBox ("ERROR: The package subject [" +
                     PKG_NAME + "] exceeds the max allowable length of " + 
                     szMaxPkgNameLength + " characters.", SEVERE);
        return ISLIB_ERROR;       
   
    endif;
    
   
                       
    // lets define the base key root location
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    
    
    // lets stop the logging of this change
    // as we do not want to remove it on uninstall.
    //          
    Disable(LOGGING); 
    
    
    // lets deal with the reg type we have been
    // told about.    
    if ( nzType = DEVICE_REGTYPE )
    then    
        szKey = ERGAFC_DEVICE_REGISTRY_BASE;        
    else
        szKey = ERGAFC_PKG_REGISTRY_BASE;
    endif;    
    
    
    szClass = "";
    if(RegDBCreateKeyEx (szKey, szClass) < 0)
    then                                  
    
        islib_MessageBox( "ERROR creating registry.", SEVERE );
        return ISLIB_ERROR;
        
    endif;
    
    // re-enable logging.
    //  
    Enable(LOGGING);  
    
    
    
    // lets deal with the reg type we have been
    // told about.
    if ( nzType = DEVICE_REGTYPE )
    then    
        szKey   = ERGAFC_DEVICE_REGISTRY_BASE + PKG_NAME + "_" + PKG_VERSION + "-" + PKG_BUILDNUM + "." + PKG_PROJACRONYM;        
    else
        szKey   = ERGAFC_PKG_REGISTRY_BASE + PKG_NAME;
    endif; 
    
    szClass = "";
    if(RegDBCreateKeyEx (szKey, szClass) < 0)
    then                                  
    
        islib_MessageBox( "ERROR creating registry key=["+szKey+"].", SEVERE );
        return ISLIB_ERROR;
        
    else

        // Check if the newly created multi-level key exists.
        //
        if (RegDBKeyExist (szKey) < 0)
        then          
        
            islib_MessageBox ("ERROR: [" + szKey + "] registry key does not exist.", SEVERE);
            return ISLIB_ERROR;
            
        else            
                                 
        
            // lets create the Version item.
            szItem  = "PkgVersion"; 
             
            // lets verify the version string before we set it. 
            if ( islib_verifyVersionFormat( PKG_VERSION ) < 0 )
            then  
            
                islib_MessageBox ("ERROR: PKG_VERSION field [" + PKG_VERSION + "] failed verification.", SEVERE);
                return ISLIB_ERROR;
            
            endif;
            
            szValue = PKG_VERSION;
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif; 
                                    
            
            // lets create the PkgBuildNum item.
            szItem  = "PkgBuildNum";
            szValue = PKG_BUILDNUM;                  
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;  
                    
                    
            // lets create the PkgProjAcronym item.
            szItem  = "PkgProjAcronym";
            szValue = PKG_PROJACRONYM;       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;            
            
                        
            // lets create the PkgName item.
            szItem  = "PkgName";
            szValue = PKG_NAME;       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;            
                
            
            // lets create the PkgNameLong item.
            szItem  = "PkgNameLong";
            szValue = PKG_NAMELONG;       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;                                     
            
                        
            // lets create the PkgDesc item.
            szItem  = "PkgDesc";
            szValue = PKG_DESC;       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif; 
                                                            
            
            // lets create the BaseInstallDir item.
            szItem  = "BaseInstallDir";
            szValue = INSTALLDIR;       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING_EXPAND,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;


            // lets create the Installed item.
            szItem  = "PkgInstalled";
            GetSystemInfo ( TIME, nzResult, szTime );
            GetSystemInfo ( DATE, nzResult, szDate );

            szValue = szDate + " " + szTime;       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;

             
            // lets create the LatestPatchID item.
            szItem  = "LatestPatchID";
            szValue = "0000000000000-00";       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;


            // lets create the Installed item.
            szItem  = "LatestPatchInstalled";
            szValue = "00-00-0000 0:00:00";       
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "Error creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue + "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;                                                           

        endif; 
        
    endif;
                     
                     
    // we are done dude.
    //
    return ISLIB_SUCCESS;                                          
    
end;  

            
     
//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_setSystemPathEntry  
//
// This function is used to maniplulate the System
// environement path variable, by adding a pre-specified
// entry to a pre-spcified location in the path variable.
//
// We pass:
// 1. the new path we wish to add to the system path.
// 2. the type of path (ie FULL, PARTIAL)
// 3. the position of the new path (i.e. BEFORE or AFTER)
//                                   
// In the event that a parameter is passed that is not supported
// shall result in the user being notified and the installation
// being aborted.
//
// Return Values:
//
// SUCCESSFULL PATH CREATION: 1
// PATH EXISTS: 2
// ERROR:  -1
//
//////////////////////////////////////////////////////////////////////////////  
function islib_setSystemPathEntry( szNewPathEntry, bType, bPosition )

    STRING szKey;
    STRING szName;
    STRING szPathBuff;
    
    NUMBER nType, nSize;  
    NUMBER nERROR, nSUCCESS1, nSUCCESS2;
    
begin  
     
    nSUCCESS1 = ISLIB_SUCCESS;
    nSUCCESS2 = 2;
    nERROR   = ISLIB_ERROR;
        
    // lets verify the supported parameters
    //
    if ( bPosition != BEFORE && bPosition != AFTER  )
    then      
    
        islib_MessageBox("ERROR: Incorrect parameter [bPosition] supplied to setSystemPathVariable(), check config. Installation aborting.", SEVERE );
        abort;
        
    endif;  
    
    
    // lets verify the supported parameters
    //
    if ( bType != FULL && bType != PARTIAL )
    then      
    
        islib_MessageBox("ERROR: Incorrect parameter [bType] supplied to setSystemPathVariable(), check config. Installation aborting.", SEVERE );
        abort;
        
    endif;  
    
        
    // first we need to get access to the current system
    // path.
    //
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    szKey  = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
    szName = "Path";

    // Read the system path
    if (RegDBGetKeyValueEx(szKey, szName, nType, szPathBuff, nSize) < 0)
    then
 
        islib_MessageBox("ERROR: SYSTEM path environment variable not found. Installation aborting.", SEVERE );
        abort;
        
    endif;
              
            
    // Check whether or new entry has already been added
    // to the system path.
    //  
    if ( szPathBuff % ( szNewPathEntry ) = TRUE )
    then   
        
        //islib_MessageBox("System PATH already contains a reference to [" + szNewPathEntry + "], not updating.", INFORMATION);
        return nSUCCESS2; 
        
    endif;                                           
                      
    
    // Initialize the path buffer.
    PathSet (szPathBuff); 
    
           
    // Add C:\MSOffice as the first path in the search path.
    if (PathAdd(szNewPathEntry, "", bType, bPosition) < 0) 
    then
    
        islib_MessageBox ("Unable to add [ " + szNewPathEntry + "] to path buffer.", SEVERE);
        abort;
        
    endif;

    // Get the search path from the path buffer; 
    // this call also releases the memory allocated 
    // for the path buffer.
    PathGet (szPathBuff);
                     
               
    // lets stop the logging of this change
    // as we do not want to remove it on uninstall.
    //          
    Disable(LOGGING);  
                 
    
    // Now we need to update the registry setting with 
    // our change.
    //
    if (RegDBSetKeyValueEx( szKey, szName, REGDB_STRING_EXPAND, szPathBuff, -1 ) < 0) 
    then   
    
          islib_MessageBox( "Error writing System PATH registry key. Installation aborting.", SEVERE );
          abort;
          
    endif;
      
          
    // re-enable logging.
    //          
    Enable(LOGGING);
      
      
    // done dude.
    return nSUCCESS1;               

end;    


//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_removeSystemPathEntry  
//
// This function is used to maniplulate the System
// environement path variable by deleting a pre-specified
// entry.
//
// We pass:
// 1. the new path we wish to add to the system path.
// 2. the type of path (ie FULL, PARTIAL)
//                                   
// In the event that a parameter is passed that is not supported
// shall result in the user being notified and the installation
// being aborted.
//
// Return Values:
//
// SUCCESS: 1
// ERROR:  -1
//
//////////////////////////////////////////////////////////////////////////////  
function islib_removeSystemPathEntry( szNewPathEntry, bType )

    STRING szKey;
    STRING szName;
    STRING szPathBuff;
    
    NUMBER nType, nSize;  
    NUMBER nERROR, nSUCCESS; 
     
begin  
     
    nSUCCESS = ISLIB_SUCCESS;
    nERROR   = ISLIB_ERROR;
        
    // lets verify the supported parameters
    //
    if ( bType != FULL && bType != PARTIAL )
    then      
    
        islib_MessageBox("ERROR: Incorrect parameter [bType] supplied to setSystemPathVariable(), check config. Installation aborting.", SEVERE );
        abort;
        
    endif;  
    
        
    // first we need to get access to the current system
    // path.
    //
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    szKey  = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
    szName = "Path";

    // Read the system path
    if (RegDBGetKeyValueEx(szKey, szName, nType, szPathBuff, nSize) < 0)
    then
 
        islib_MessageBox("ERROR: SYSTEM path environment variable not found. Installation aborting.", SEVERE );
        abort;
        
    endif;
              
            
    // Check whether the entry is part of the buff
    //  
    if ( szPathBuff % ( szNewPathEntry ) != TRUE )
    then   
        
        //islib_MessageBox("System PATH does not contain a reference to [ " + szNewPathEntry + " ], not updating.", INFORMATION);             
        return nSUCCESS; 
        
    endif;                                           
                      
    
    // Initialize the path buffer.
    PathSet (szPathBuff); 
    
           
    // Add C:\MSOffice as the first path in the search path.
    if (PathDelete(szNewPathEntry, bType) < 0) 
    then
    
        islib_MessageBox ("Unable to delete [ " + szNewPathEntry + " ] from path buffer.", SEVERE);
        abort;
        
    endif;

    // Get the search path from the path buffer; 
    // this call also releases the memory allocated 
    // for the path buffer.
    PathGet (szPathBuff);
                     
               
    // lets stop the logging of this change
    // as we do not want to remove it on uninstall.
    //          
    Disable(LOGGING);  
                 
    
    // Now we need to update the registry setting with 
    // our change.
    //
    if (RegDBSetKeyValueEx( szKey, szName, REGDB_STRING_EXPAND, szPathBuff, -1 ) < 0) 
    then   
    
          islib_MessageBox( "Error writing System PATH registry key. Installation aborting.", SEVERE );
          abort;
          
    endif;
      
          
    // re-enable logging.
    //          
    Enable(LOGGING);
      
      
    // done dude.
    return nSUCCESS;               

end;    


//////////////////////////////////////////////////////////////////////////////
//                                                                           
//  FUNCTION:   islib_setErgAfcPatchRegistryKeys       
//
//  This function sets the predefined registry key
//  for an ERG AFC patch.
//
//  We assume the key(s) shall exist in the following
//  default location of the registry:
//  
//  HKEY_LOCAL_MACHINE\SOFTWARE\ERG\AFC\patch
//
//  the key name shall be defined by PATCH_ID
//
//  i.e. PATCH_ID = "ERGCDXML050100-01"
//
//  The function shall also create the following
//  parameters under this key
//  
//  PatchNum          = The patch number (taken from the PATCH_ID, the last 2 characters).
//  ParentPkgVersion  = The version number of the parent package (PKG_VERSION).
//  Installed         = The date and time the patch was installed ().
//
//  Return Values:
//
//   ISLIB_SUCCESS: registry key set.
//   ISLIB_ERROR:   failed to set registry key.
//
//////////////////////////////////////////////////////////////////////////////                       
function islib_setErgAfcPatchRegistryKeys()  

    STRING szKey;
    STRING szItem;
    STRING szValue;
    STRING szClass;             
    STRING szDate;             
    STRING szTime;             
        
    STRING szPatchNumber;
    
    STRING szPkgBaseInstallDir;
    STRING szPkgVersion;
    STRING szPkgInstalled; 
    STRING szPkgLatestPatchID;
    STRING szPkgLatestPatchInstalled;
        
    STRING szPkgLatestPatchNumber;
    NUMBER nzPkgLatestPatchNumber;
                                           
    NUMBER nzResult;    
    
begin              
                  


    // lets verify our PatchID
    //
    if ( islib_verifyPatchIDFormat( PATCH_ID ) < 0 )
    then     
   
        islib_MessageBox("ERROR: PatchID [" + PATCH_ID + 
                   "] failed verification.", SEVERE);
        return ISLIB_ERROR; 
        
    endif;


    // lets define the base key root location
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 
    szKey   = ERGAFC_PATCH_REGISTRY_BASE + PATCH_ID;
    szClass = "";
    if(RegDBCreateKeyEx (szKey, szClass) < 0)
    then                                  
    
        islib_MessageBox( "ERROR: updating registry.", SEVERE );
        return ISLIB_ERROR;
        
    else

        // Check if the newly created multi-level key exists.
        //
        if (RegDBKeyExist (szKey) < 0)
        then          
        
            islib_MessageBox ("ERROR: [" + szKey + "] registry key does not exist.", SEVERE);
            return ISLIB_ERROR;
            
        else                                
        
            // lets create the ParentPkgVersion item.
            szItem  = "ParentPkgVersion";
            
            // lets verify the version string before we set it. 
            if ( islib_verifyVersionFormat( PKG_VERSION ) < 0 )
            then  
            
                islib_MessageBox ("ERROR: PKG_VERSION field [" + PKG_VERSION + "] failed verification.", SEVERE);
                return ISLIB_ERROR;
            
            endif;
            
            szValue = PKG_VERSION;
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then  
            
                islib_MessageBox( "ERROR: creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;
            

            // lets get the patch number identifier
            //
            if ( islib_getPatchNumber ( PATCH_ID , szPatchNumber ) < 0 )
            then  
            
                islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE);
                return ISLIB_ERROR;
            
            endif;
            

            // lets create the PatchNum item.
            szItem  = "PatchNumber";                      

            // lets write the reg item.
            //
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szPatchNumber, -1 ) < 0)
            then  
            
                islib_MessageBox( "ERROR: creating [" + 
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szPatchNumber +
                            "].", SEVERE );
                    
                return ISLIB_ERROR; 
                
            endif;                       


            // lets create the Installed item.
            szItem  = "PatchInstalled";
            GetSystemInfo ( TIME, nzResult, szTime );
            GetSystemInfo ( DATE, nzResult, szDate );

            szValue = szDate + " " + szTime;
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING_EXPAND,
                 szValue, -1 ) < 0)
            then 
           
                islib_MessageBox( "ERROR: creating [" +
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );

                return ISLIB_ERROR;

            endif;          
            
            
            // lets create the obsoleted patch information.
            //
            
            // first we need to get the current product patch number
            // we are going to obsolete
            //
            if (islib_getErgAfcPkgLatestPatchIDRegistryDetails( szPkgLatestPatchID,                                                                                                       
                                                                szPkgLatestPatchInstalled) < 0 )
            then
            
                islib_MessageBox("ERROR: islib_getErgAfcPkgLatestPatchIDRegistryDetails() did not complete successfully.", SEVERE);
                return ISLIB_ERROR;
            
            endif; 
                                    
        
            // lets get our patch number.
            //   
            if ( islib_getPatchNumber( szPkgLatestPatchID, szPkgLatestPatchNumber ) < 0 )
            then
        
                islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE); 
                return ISLIB_ERROR;                                  
        
            endif;
            StrToNum(nzPkgLatestPatchNumber, szPkgLatestPatchNumber);

    
            // lets see what our latest patch is?
            //
            if ( nzPkgLatestPatchNumber = 0 )
            then            
                szValue = "0000000000-00";             
            else            
                szValue = szPkgLatestPatchID;            
            endif;
                                                                

            // we have the product details lets update the
            // our patch details.
            // 
            szItem  = "ObsoletedPatchID";                              
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then 
           
                islib_MessageBox( "ERROR: creating [" +
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );

                return ISLIB_ERROR;

            endif;     
                                    
            
            
            // lets see what our latest patch is?
            //
            if ( nzPkgLatestPatchNumber = 0 )
            then            
                szValue = "00-00-0000 0:00:00";                
            else            
                szValue = szPkgLatestPatchInstalled;           
            endif;            
                                               
            szItem  = "ObsoletedPatchInstalled";                               
            if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
            then 
           
                islib_MessageBox( "ERROR: creating [" +
                            szKey + "\\" +  szItem +
                            "] registry key, value [" +
                            szValue +
                            "].", SEVERE );

                return ISLIB_ERROR;

            endif;                 

        endif; 
        
    endif;
                     
                     
    // we are done dude.
    //
    return ISLIB_SUCCESS;                                          
    
end;          


//////////////////////////////////////////////////////////////////////////////                       
//
//  FUNCTION:   islib_getPatchNumber
//
//  This function extracts the numeric section from the supplied
//  PatchID.  It sets the szPatchNum variable thus returning the
//  patch number to the calling function.
//
//  Return Value:
//
//  ISLIB_SUCCESS: ok
//  ISLIB_ERROR:   encountered a problem.
//
//////////////////////////////////////////////////////////////////////////////                       
function islib_getPatchNumber( szPatchID, szPatchIDNum )

    LIST   listID;

    STRING szPatchIDName;

begin

    // lets verify our PatchID passed in.
    //
    if ( islib_verifyPatchIDFormat( szPatchID ) < 0 )
    then

        islib_MessageBox("ERROR: PatchID [" + 
                   szPatchID +
                   "] failed verification.", SEVERE);
        return ISLIB_ERROR;

    endif;
        

    // Create a list to hold the bits that make up the
    // patch name.
    listID = ListCreate (STRINGLIST);


    // Get each bit from the passed value. 
    // we have already verified that the format is ok
    // from above.
    //
    StrGetTokens (listID, szPatchID, "-");


    // lets get the patch number section.
    ListGetFirstString ( listID, szPatchIDName );
    ListGetNextString  ( listID, szPatchIDNum );


    // Remove the list from memory.
    ListDestroy (listID);


    // we are done dure.
    //
    return ISLIB_SUCCESS;

end;


//////////////////////////////////////////////////////////////////////////////                       
//
//  FUNCTION:   islib_verifyPatchIDFormat 
//
//  This function is used to verify the format of the parameter passed to that
//  of a PatchID.  The format of a PatchID is defined in the Build & Release
//  Guidelines document.
//
//  Return Values:
//
//  ISLIB_SUCCESS: format correct.
//  ISLIB_ERROR:   format incorrect.
//
//  The function shall abort processing if it detects that the PatchId is
//  of an incorrect format.  This information is critical to the configuration
//  management and must be correct before proceeding.
//
//////////////////////////////////////////////////////////////////////////////                       
function islib_verifyPatchIDFormat( szPatchID )

    LIST   listID;

    STRING  szSection1;             
    STRING  szSection2;             

    STRING  szLengthSec1;             
    STRING  szLengthSec2;             

    NUMBER nzLengthSec1;
    NUMBER nzLengthSec2;

    NUMBER nzNumSections;

    NUMBER nzPatchIDLength;
    NUMBER nzVar;

    BOOL bzReturnFlag;

begin

    // Make available the predefined 
    // definitions.
    //
    nzPatchIDLength = MAX_PATCHID_FORMAT_LENGTH;
    nzLengthSec1    = MAX_PATCHID_NAME_FORMAT_LENGTH;
    nzLengthSec2    = MAX_PATCHID_NUMBER_FORMAT_LENGTH;
    nzNumSections   = NUM_PATCHID_SECTIONS;

    bzReturnFlag = TRUE;


    // Create a list to hold the bits that make up the
    // patch name.
    listID = ListCreate (STRINGLIST);


    // Get each path from the search path into the list.
    if (StrGetTokens (listID, szPatchID, "-") > 0)
    then

        // Report the error.
        islib_MessageBox ("Patch ID [" + szPatchID + 
                    "] has an incorrect format." +
                    "\n\n(Info: A PatchID MUST use the following format, PPPPPPPPPPNNNNNN-NN).",
                    SEVERE);

        bzReturnFlag = FALSE;

    else

        // we have our bits lets verify them
       
        // how many bits did we get?
        //
        if ( ListCount ( listID ) != nzNumSections )
        then

            islib_MessageBox ( "Patch ID [" +
                         szPatchID    +
                         "] has an incorrect format.\n\n(Info: A PatchID MUST use the following format, PPPPPPPPPPNNNNNN-NN) .",
                         SEVERE );

            bzReturnFlag = FALSE;

        endif;
 

        // lets go through the sections,


        // lets check the patch name section.
        ListGetFirstString ( listID, szSection1 );
        if ( StrLengthChars ( szSection1 ) > nzLengthSec1 )
        then

            NumToStr( szLengthSec1, nzLengthSec1 );
            islib_MessageBox ("Patch ID [" + szPatchID +
                        "] has an incorrectly formatted patch name component [" +
                        szSection1 + 
                        "].\n\n(Info: A PatchID name MUST use upto " + szLengthSec1 + 
                        " alpha-numeric characters, PPPPPPPPPPNNNNNN).",
                        SEVERE);

            bzReturnFlag = FALSE;
 
        endif;

       
        // lets check the patch number section.
        // first we check the length.
        ListGetNextString  ( listID, szSection2 );
        if ( StrLengthChars ( szSection2 ) != nzLengthSec2 )
        then

            NumToStr( szLengthSec2, nzLengthSec2 );
            islib_MessageBox ("Patch ID [" + szPatchID +
                        "] has an incorrectly formatted patch number component [" +
                        szSection2 + 
                        "].\n\n(Info: A PatchID number MUST use " + szLengthSec2 + " numeric digits ONLY, NN).",
                        SEVERE);

            bzReturnFlag = FALSE;
 
        endif;

        // second we check the contents to be numeric.
        if ( StrToNum ( nzVar, szSection2 ) < 0 )
        then

            islib_MessageBox ("Patch ID [" + szPatchID +
                        "] has an non-numeric patch number component [" + szSection2 + 
                        "].\n\n(Info: A PatchID number MUST use " + szLengthSec2 + 
                        " numeric digits ONLY, NN).",
                        SEVERE);

            bzReturnFlag = FALSE;

        endif;
 
    endif;

    // Remove the list from memory.
    ListDestroy (listID);


    // we are done, and things are ok.
    if ( bzReturnFlag = TRUE )
    then
        return ISLIB_SUCCESS;
    else
        return ISLIB_ERROR;
    endif;

end;
    

//////////////////////////////////////////////////////////////////////////////                       
//
//  FUNCTION:   islib_verifyLocationIDFormat 
//
//  This function is used to ensure that the parameter passed is of the 
//  required location ID format, i.e. PPPPPPPPPP-LLL-SSS-NNNNNNNN
//
//  Return Values:
//    ISLIB_SUCCESS - correct format
//    ISLIB_ERROR   - incorrect format
//
//////////////////////////////////////////////////////////////////////////////                       
function islib_verifyLocationIDFormat ( szLocationID )

    LIST   listID;
    STRING svSearchPath;
    STRING szTitle, szMsg;
    NUMBER nzNumberLocationIDSections;
    STRING szSec1, szSec2, szSec3, szSec4;
    NUMBER nzLengthSec1, nzLengthSec2, nzLengthSec3, nzLengthSec4;

begin

    nzNumberLocationIDSections = NUM_LOCATIONID_SECTIONS;
    nzLengthSec1               = MAX_LOCATIONID_SECTION_1_FORMAT_LENGTH;
    nzLengthSec2               = MAX_LOCATIONID_SECTION_2_FORMAT_LENGTH;
    nzLengthSec3               = MAX_LOCATIONID_SECTION_3_FORMAT_LENGTH;
    nzLengthSec4               = MAX_LOCATIONID_SECTION_4_FORMAT_LENGTH;


    // Create a list to hold the bits that make up the
    // location ID.
    listID = ListCreate (STRINGLIST);


    // Get each path from the search path into the list.
    if (StrGetTokens (listID, szLocationID, "-") > 0)
    then

        // Report the error.
        islib_MessageBox ("Location ID [" + szLocationID + "] has incorrect format,\n(use PPPPPPPPPP-LLL-SSSSSS-NNNNNNNN).",
                     WARNING);

    else

        // We have our bits lets just check to see
        // if they are of the correct format.

        // how many bits did we get?
        //
        if ( ListCount ( listID ) != nzNumberLocationIDSections )
        then

            islib_MessageBox ( "Location ID [" + 
                         szLocationID    + 
                         "] has incorrect number of sections,\n(i.e. does not follow format PPPPPPPPPP-LLL-SSSSSS-NNNNNNNN) .",
                         WARNING );

        endif;

        
        // lets go through the sections,
        ListGetFirstString ( listID, szSec1 );
        if ( StrLengthChars ( szSec1 ) != nzLengthSec1 )
        then

            islib_MessageBox ("Location ID [" + szLocationID +
                        "] has incorrectly formated section 1 [" +
                        szSec1 + "],\n(use format PPPPPPPPPP-LLL-SSSSSS-NNNNNNNN).",
                        WARNING);
        endif;


        ListGetNextString  ( listID, szSec2 );
        if ( StrLengthChars ( szSec2 ) != nzLengthSec2 )
        then

            islib_MessageBox ("Location ID [" + szLocationID +
                        "] has incorrectly formated section 2 [" +
                        szSec2 + "],\n(use format PPPPPPPPPP-LLL-SSSSSS-NNNNNNNN).",
                        WARNING);
        endif;

        ListGetNextString  ( listID, szSec3 );
        if ( StrLengthChars ( szSec3 ) != nzLengthSec3 )
        then

            islib_MessageBox ("Location ID [" + szLocationID +
                        "] has incorrectly formated section 3 [" +
                        szSec3 + "],\n(use format PPPPPPPPPP-LLL-SSSSSS-NNNNNNNN).",
                        WARNING);
        endif;

        ListGetNextString  ( listID, szSec4 );
        if ( StrLengthChars ( szSec4 ) != nzLengthSec4 )
        then

            islib_MessageBox ("Location ID [" + szLocationID +
                        "] has incorrectly formated section 4 [" +
                        szSec4 + "],\n(use format PPPPPPPPPP-LLL-SSSSSS-NNNNNNNN).",
                        WARNING);
        endif;

    endif;

    // Remove the list from memory.
    ListDestroy (listID);

    return TRUE;

end;


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_patchPreInstall
//
//  1. initialise predefined parameters
//  2. verifyPatchIDFormat.
//  3. verifyPatch Installation can proceed.
//  3. create patch save location
//  4. extract the filelist                     
//  5. create patchLog file
//  6. copy old items and log original locations in patchLog file.
//    
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_patchPreInstall ()

    STRING szPatchIDDir;
    STRING szPatchIDSaveDir;
    STRING szPatchIDLogFileLocation;
    STRING szPatchIDLogFileName;

    STRING szMySrcFile;
    STRING szMyDstFile;
    
    STRING szResult;
    NUMBER nzResult;    
    
    STRING szMsg;  
    STRING szTitle;

    LIST PatchItemsListID;

    NUMBER nzRetVal;
    NUMBER nzFileHandle;  

begin

    // lets initialse the predefined parameter
    // so we can use them.
    //
    szPatchIDDir             = PATCHID_DIR;
    szPatchIDSaveDir         = PATCHID_SAVE_DIR;
    szPatchIDLogFileLocation = PATCHID_LOGFILE_LOCATION;        
    szPatchIDLogFileName     = PATCHID_LOGFILE_NAME;        
    
             
    //SprintfBox (INFORMATION, "Debug Information",
    //           "id=[%s], save=[%s], file=[%s]. ",
    //            szPatchIDDir, szPatchIDSaveDir, szPatchIDLogFileLocation);       
    

    // we need to determine if we can install this patch based on the
    // patching rules we have predefined.  These rules govern the
    // patch sequencing and obseletion criteria.
    //
    if ( islib_checkInstallPatch () < 0 ) 
    then

        islib_MessageBox("This patch cannot be installed on this system.", SEVERE);
        return ISLIB_ERROR;  
                
    endif;


    // disable the  logging 
    // functions, we shall clean up later.
    //               
    Disable(LOGGING);    
    

    // Lets get our list of items that we are going to patch.
    //
    PatchItemsListID = ListCreate (STRINGLIST);
    if ( islib_getPatchItemsList(PatchItemsListID) < 0 )
    then

        islib_MessageBox ("Error failed to create the patch items list.", SEVERE);                  
        return ISLIB_ERROR;        

    endif;
                                                       
       
    // lets see if anyone has left any junk 
    // behind.
    //
    if ( Is(PATH_EXISTS, szPatchIDSaveDir) = TRUE )
    then 
    
         islib_MessageBox("Patch directory [" + szPatchIDDir + "] already exists." +
                    "\nPlease rectify prior to installing patch.", SEVERE);
         return ISLIB_ERROR;   
 
    endif;
    
       
    // lets create our patch store
    //           
    if ( CreateDir ( szPatchIDSaveDir ) < 0 )
    then      
    
         islib_MessageBox("Failed to create [" + szPatchIDSaveDir + "] dir.", SEVERE);
         return ISLIB_ERROR;                    
                             
    endif;                                                        

    
    // lets populate our patch store
    //
    if ( islib_savePatchItems(PatchItemsListID) < 0 )
    then

        islib_MessageBox ("ERROR: Failed to complete patch save action.", SEVERE); 
        return ISLIB_ERROR;
        
    endif;

                                                                                
    // lets free resources.
    //
    ListDestroy(PatchItemsListID);


    // lets re-enable logging here.
    // we have created our patch store
    // we need to clean it up later.
    //        
    Enable(LOGGING);


    // we are done. 
    return ISLIB_SUCCESS;
   
end;


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_checkInstallPatch
//
//   This function is used to check if the patch can be installed.
//   The rules that govern if a patch can be installed are:
//
//   1. A parent package that has a name equal that defined in the 
//      project Subject field has already been installed on the system.
//
//      This condition shall be checked ensuring the BaseInstallDir registry key
//      exists for the parent package defined in the project Subject setting.
//
//      If the parent package registry key does not exist the patch shall stop
//      the patch installation.
//
//   2. The parent package version number is equal to that of the patch.
//      The patch version number is defined in the PKG_VERSION variable.
//
//      (i.e. The patch MYPKG010001-0N can only be used to patch any item installed by the package
//            MYPKG of version 1.0.1).
//
//      This check shall be completed by comparing the Version registry setting of the package
//      with the PKG_VERSION variable of the patch.
//
//      A patch can only be used to update a pre-defined specific parent package version.
//
//   3. The same patch has not already been installed.
//      (ie you cannot install MYPKG010001-01 twice.
//
//      This shall be ensured by the use of the OnMaintUIBefore() function.  This 
//      function ensures that a package with the same product codes cannot be installed twice. 
//
//   4. The patch has a patch number that is greater in value that the most recently 
//      applied patch. 
//
//      (ie the patch MYPKG010001-01 cannot be applied after MYPKG010001-02).
//       
//       This shall be checked by retrieving the most parent package registry key
//       containing the patch number of the most recently installed patch and comparing it
//       to the current patch number.  
//
//       You can apply patch MYPKG010001-06 to a parent package that has had all
//       patches applied upto MYPKG010001-04.  
//       
//       You will not how ever be able to subsequnetly apply patch MYPKG010001-05
//       as this patch has been obsoleted by MYPKG010001-06.
//       
//
//  Return Values:                
//
//    ISLIB_SUCCESS - completed ok
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_checkInstallPatch ()
        
    STRING szPkgName;            
        
    STRING szPatchID;     
    STRING szPatchIDNumber; 
    STRING szPatchPkgVersion; 
    STRING szPatchPkgProjAcronym;    
    
    STRING szPkgBaseInstallDir; 
    STRING szPkgVersion; 
    STRING szPkgInstalled; 
    STRING szPkgLatestPatchID;  
    STRING szPkgLatestPatchInstalled;
    STRING szPkgBuildNum;  
    STRING szPkgProjAcronym;
    STRING szPkgDesc;
    
    STRING szMyPkgLatestPatchNumber;
    
    NUMBER nzPatchIDNumber; 
    NUMBER nzMyPkgLatestPatchNumber;
    
    NUMBER nResult;   

begin 
             
    // initialise local variables.
    //             
    szPatchID             = PATCH_ID;    
    szPatchPkgVersion     = PKG_VERSION;
    szPkgName             = PKG_NAME;
    szPatchPkgProjAcronym = PKG_PROJACRONYM;    
    
    
    // lets verify our PatchID format
    //
    if ( islib_verifyPatchIDFormat( szPatchID ) < 0 )
    then     
    
        islib_MessageBox("PatchID [" + szPatchID + "] failed format verification.", SEVERE);                   
        return ISLIB_ERROR; 
        
    endif;       
    

    // 1. lets check to see if our parent package exists
    //   
    if ( islib_checkErgAfcPkgExists(szPkgName) < 0 )
    then    
    
        // we could not confirm that the parent package exists
        // so we assume that the package was removed.
        // 
        // This implies we cannot install this patch
        //
        islib_MessageBox("Failed to detect parent package, " + szPkgName + " on system.\n" +
                         "Parent package may not be not installed.", SEVERE); 
        return ISLIB_ERROR; 
        
    else
    
        // our parent package exists lets get its current details
        //
        if (islib_getErgAfcPkgRegistryDetails( szPkgBaseInstallDir, 
                                               szPkgVersion,
                                               szPkgInstalled, 
                                               szPkgLatestPatchID,                                               
                                               szPkgLatestPatchInstalled,
                                               szPkgBuildNum,
                                               szPkgProjAcronym,
                                               szPkgDesc ) < 0 )
        then                                       
                            
            // we encountered an error getting the details
            //
            islib_MessageBox("ERROR: islib_getErgAfcPkgRegistryDetails() did not complete successfully.", SEVERE); 
            return ISLIB_ERROR;                          
        
        endif; 
          
          
        // lets get our patch number. 
        //
        if ( islib_getPatchNumber( szPatchID, szPatchIDNumber ) < 0 )
        then
        
            islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE); 
            return ISLIB_ERROR;                                  
        
        endif;  
                
                
        // we got our details lets apply the business rules
        // of our patch management strategy.
        //         
        
        // 2. version numbers must be equal to install a patch
        // 
        if ( islib_verifyVersionFormat(szPkgVersion) < 0 )
        then                   
            islib_MessageBox("ERROR: Package version [" + szPkgVersion + "] failed format verification." +
                       "\nCheck configuration.", SEVERE);
    
            return ISLIB_ERROR;
    
        endif;
        
        if ( islib_verifyVersionFormat(szPatchPkgVersion) < 0 )
        then                   
            islib_MessageBox("ERROR: Patch version [" + szPatchPkgVersion + "] failed format verification." +
                       "\nCheck configuration.", SEVERE);
    
            return ISLIB_ERROR;
    
        endif; 
        
        
        // lets check to see that the patch projects are ok
        //
        if (szPatchPkgProjAcronym != szPkgProjAcronym)
        then                   
            islib_MessageBox("ERROR: Patch project [" + szPatchPkgProjAcronym + 
                             "] does not match parent package project [" + szPkgProjAcronym +
                             "].\n" +
                             "Check configuration.", SEVERE);
    
            return ISLIB_ERROR;
        endif; 
                           
         
        // our versions are of the correct format lest
        // compare them.
        nResult = islib_compareVersions(szPkgVersion, szPatchPkgVersion);
        if ( nResult != ISLIB_VERSION_EQUALS )
        then    
        
            islib_MessageBox("The patch you trying to install does not have a compatible version number." +
                       "\n\nThis patch [" + szPatchID + "] version [" + szPatchPkgVersion + "] is not the same as " +
                       "\nthe [" + szPkgName + "] parent package version [" + szPkgVersion + "]." +                      
                       "\n\nCheck patch configuration.", WARNING); 
                       
            return ISLIB_ERROR;               
        
        endif;
        

        // 3 and 4. the patch number is greater than the latest
        // patch previously installed.  You cannot install the same 
        // patch number again.
        //
        
        // lets get the latest patch installed patch number.
        //   
        if ( islib_getPatchNumber( szPkgLatestPatchID, szMyPkgLatestPatchNumber ) < 0 )
        then
        
            islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE); 
            return ISLIB_ERROR;                                  
        
        endif; 
        
        StrToNum(nzPatchIDNumber, szPatchIDNumber);
        StrToNum(nzMyPkgLatestPatchNumber, szMyPkgLatestPatchNumber);
        if ( nzPatchIDNumber = nzMyPkgLatestPatchNumber )
        then    
        
            islib_MessageBox("The patch you trying to install has already been installed on [" +
                       szPkgLatestPatchInstalled + "].", WARNING); 
                       
            return ISLIB_ERROR;               
            
        elseif (nzPatchIDNumber < nzMyPkgLatestPatchNumber )
        then
        
            islib_MessageBox("The patch you trying to install [" + szPatchID + "] has been obsoleted " +
                       "\nby a patch that has been previously installed." +
                       "\n\nThe latest patch to be installed for the parent package [" + szPkgName + "] has " + 
                       "\npatch ID [" + szPkgLatestPatchID + "], installed on [" +
                       szPkgLatestPatchInstalled + "].", WARNING); 
                       
            return ISLIB_ERROR;               
                                          
        endif;          
            
    endif;  
    
    
    // if we got to here things are ok, we now need to ensure that the
    // INSTALLDIR variable is set to the PkgBaseInstallDir variable
    // we retieved from the registry.  this ensures that the patch 
    // starts from the same point as the parent package.
    //
    INSTALLDIR = szPkgBaseInstallDir;
            
            
    // done.
    return ISLIB_SUCCESS;

end;


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_compareVersions
//
//  This function is used to compare two string that contain version numbers
//  The version has a pre-defined format of M.M.M where M is any integer.
//
//  Version A is passed in as parameter 1,
//  Version B is passed in as parameter 2.
//
//  The priority for comparision shall be left to right,
//  (ie the left most integer is the major number, whilst the right mose integer
//   is the minor number).
//
//   Return Values:
//
//   -1: encountered a processing error.
//    0: versions are equal
//    1: version A, is greater that version B
//    2: version A, is less than version B
//
//////////////////////////////////////////////////////////////////////////////                                     
function islib_compareVersions(szVersionA, szVersionB)
    
    LIST lzVersionA;
    LIST lzVersionB; 
    
    STRING szVersionAMajor;
    STRING szVersionAMiddle;
    STRING szVersionAMinor;
    
    STRING szVersionBMajor;
    STRING szVersionBMiddle;
    STRING szVersionBMinor;
                        
    NUMBER nzVersionAMajor;
    NUMBER nzVersionAMiddle;
    NUMBER nzVersionAMinor;
    
    NUMBER nzVersionBMajor;
    NUMBER nzVersionBMiddle;
    NUMBER nzVersionBMinor;        
    
begin                     
    
    // lets first verify that the format of each
    // version string is ok.
    //        
    if ( islib_verifyVersionFormat(szVersionA) < 0 )
    then                   
        islib_MessageBox("ERROR: Version [" + szVersionA + "] failed format verification." +
                   "\nCheck version configuration.", SEVERE);
    
        return ISLIB_ERROR;
    
    endif;
    
    if ( islib_verifyVersionFormat(szVersionB) < 0 )
    then                   
        islib_MessageBox("ERROR: Version [" + szVersionB + "] failed format verification." +
                   "\nCheck version configuration.", SEVERE);
    
        return ISLIB_ERROR;
    
    endif;
            
            
    // first we need to check the formaat of each
    // version number 
    lzVersionA = ListCreate(STRINGLIST);
    // If an error occurred, report it.
    if (lzVersionA = LIST_NULL) then
        islib_MessageBox ("ERROR: Unable to create list lzVersionA.", SEVERE);
        return ISLIB_ERROR;
    endif;
    
    // lets parse our version A string. 
    // and load our local variables.
    StrGetTokens(lzVersionA, szVersionA, ".");     
    ListGetFirstString( lzVersionA, szVersionAMajor );
    ListGetNextString ( lzVersionA, szVersionAMiddle);
    ListGetNextString ( lzVersionA, szVersionAMinor);
    
    StrToNum(nzVersionAMajor,  szVersionAMajor);
    StrToNum(nzVersionAMiddle, szVersionAMiddle);
    StrToNum(nzVersionAMinor,  szVersionAMinor);
    

    lzVersionB = ListCreate(STRINGLIST);
    // If an error occurred, report it.
    if (lzVersionB = LIST_NULL) then
        islib_MessageBox ("ERROR: Unable to create list lzVersionB.", SEVERE);
        return ISLIB_ERROR;
    endif;           
    
    // lets parse our version B string. 
    // and load our local variables.
    //
    StrGetTokens(lzVersionB, szVersionB, ".");
    ListGetFirstString( lzVersionB, szVersionBMajor );
    ListGetNextString ( lzVersionB, szVersionBMiddle);
    ListGetNextString ( lzVersionB, szVersionBMinor);
    
    StrToNum(nzVersionBMajor,  szVersionBMajor);
    StrToNum(nzVersionBMiddle, szVersionBMiddle);
    StrToNum(nzVersionBMinor,  szVersionBMinor); 
                               

    // now we are ready to do the comparision. 
    // remember we are comparing A to B 
    // lets check the major numbers first
    //
    if ( nzVersionAMajor = nzVersionBMajor )
    then
                          
        // we need to check the middle numbers
        if ( nzVersionAMiddle = nzVersionBMiddle)
        then   
                           
            // we need to check the minor numbers
            if ( nzVersionAMinor = nzVersionBMinor)
            then           
                // if we get here the versions are equal
                //
                return  ISLIB_VERSION_EQUALS;
            elseif(nzVersionAMinor > nzVersionBMinor)
            then 
                // here version A minor is greater than version B minor
                // this implies the version A is greater than version B.
                //
                return ISLIB_VERSION_GREATER_THAN;                                        
            else   
                // here version A minor is less than version B minor
                // this implies the version A is less than version B.
                //
                return ISLIB_VERSION_LESS_THAN;              
            endif;                              
        
        elseif (nzVersionAMiddle > nzVersionBMiddle)
        then
            // here version A middle is greater than version B middle
            // this implies the version A is greater than version B.
            //
            return ISLIB_VERSION_GREATER_THAN;
        else 
            // here version A middle is less than version B middle
            // this implies that version A is less than version B.
            return ISLIB_VERSION_LESS_THAN;
        endif;                                                     
        
    elseif (nzVersionAMajor > nzVersionBMajor) 
    then   
        // here version A major is greater than version B major
        // this implies the version A is greater than version B.
        //
        return ISLIB_VERSION_GREATER_THAN;
    else
        // here version A major is less than version B major
        // this implies that version A is less than version B.
        return ISLIB_VERSION_LESS_THAN;
    endif;
                                              
                                                                                    
                                          
    // free resources.
    //                               
    ListDestroy(lzVersionA);      
    ListDestroy(lzVersionB);   
                         
    // done. but we should never get here.                         
    return ISLIB_SUCCESS;

end;                                


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_verifyVersionFormat 
//
//  This function is used to verify the format of version number.
//  A version has a pre-defined format of M.M.M where M is any integer.
//
//  Return Values:
//    ISLIB_SUCCESS - format ok
//    ISLIB_ERROR   - format NOT ok.
//
//////////////////////////////////////////////////////////////////////////////
function islib_verifyVersionFormat( szVersion )

    LIST   lzVersionID;                
    NUMBER nzCount;
    NUMBER nzRetVal; 
    
    STRING szBit;    
    NUMBER nzBit;    
    
begin                               

    lzVersionID = ListCreate(STRINGLIST);
    // If an error occurred, report it.
    if (lzVersionID = LIST_NULL) then
        islib_MessageBox ("ERROR: Unable to create list lzVersionID.", SEVERE);
        return ISLIB_ERROR;
    endif;
     
    // lets parse our version string.
    StrGetTokens(lzVersionID, szVersion, "."); 
    
                
    // Count the number of program folders in the list.
    nzCount = ListCount (lzVersionID); 
    if (  nzCount != MAX_NUM_VERSION_FORMAT_SECTIONS )
    then
                
         islib_MessageBox ("ERROR: Version [" + szVersion + "] has an incorrect format, " +
                     "(i.e. use N.N.N).", SEVERE);
         return ISLIB_ERROR;
    
    endif; 
    
    
    // lets confirm all the bits are numeric.
    //
    nzRetVal = ListGetFirstString ( lzVersionID, szBit );
    while ( nzRetVal != END_OF_LIST )              
        
        if ( StrToNum(nzBit, szBit) < 0 )
        then
    
            islib_MessageBox ("Version ["+szVersion+"] contains non-numeric component.", SEVERE); 
            return ISLIB_ERROR;
    
        endif;
        
        // get next bit.
        nzRetVal = ListGetNextString ( lzVersionID, szBit );   
       
    endwhile;          
                           
                           
    // lets free resources.
    ListDestroy(lzVersionID);
                        
    // done.                        
    return ISLIB_SUCCESS;
    
end;




//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_getPatchItemsList
//
//   This function is used to retireive all file items to be delivered by this
//   patch package.
//
//   We make use of the information avaiable in the installshield config
//   An we populate a List variable that can be accessed by the calling
//   function later.
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_getPatchItemsList ( lzPatchItemsListID )

    NUMBER nzResult;
    NUMBER nzTmpVar;
    
    LIST lzTopFeatureListID;
    LIST lzSubFeatureListID; 
    LIST lzSubFeatureItemListID; 
    LIST lzParseFeatureListID;
    
    STRING szTmpVar;    
    STRING szTopFeature;
    STRING szSubFeature; 
    STRING szSubFeatureOnlyStr;
    STRING szTmpVar1;    
    STRING szSubFeatureItem; 
    STRING szSubFeatureItem_lc;
    STRING szSubFeatureDescField; 
    STRING szSubFeatureDescType; 
    STRING szSubFeatureItemsLocation; 
    STRING szString;
    
    NUMBER nzSubFeatureItemRetVal;    
    NUMBER nzTopFeatureCount;
    NUMBER nzSubFeatureCount;
    NUMBER nzSubFeatureItemCount;  
    NUMBER nzTopFeatureRetVal;
    NUMBER nzSubFeatureRetVal;

begin
              
    // Initialize the string list.
    lzTopFeatureListID = ListCreate (STRINGLIST); 
    if (lzTopFeatureListID = LIST_NULL) 
    then  
    
        islib_MessageBox ("System error, unable to create top-level feature list.", SEVERE);
        return ISLIB_ERROR;        
        
    endif;
    
                                                                           
    // Create a list of top-level features in the specified media.
    if ( FeatureListItems (MEDIA, "", lzTopFeatureListID) < 0 )
    then      
    
        islib_MessageBox ("System error, failed to get top-level feature list.", SEVERE);
        return ISLIB_ERROR;                    
    
    endif;
        
        
    // Count the number of program folders in the list.
    nzTopFeatureCount = ListCount (lzTopFeatureListID); 
    if (  nzTopFeatureCount <= 0 )
    then
                
        islib_MessageBox ("Failed to detect any top-level features in patch configuration." +
                    "\nCheck patch configuration.", SEVERE);
        return ISLIB_ERROR;
    
    endif;  
    
    
    // check to see if we exceed the max supported top-level
    // features
    //
    if (  nzTopFeatureCount > MAX_NUM_TOP_LEVEL_FEATURES )
    then
    
        nzTmpVar =  MAX_NUM_TOP_LEVEL_FEATURES;
        NumToStr(szTmpVar, nzTmpVar);          
        islib_MessageBox ("ERROR: current patch strategy ONLY supports [" +
                    szTmpVar + "] top-level feature. Check patch features configuration.", SEVERE);
        return ISLIB_ERROR;
    
    endif;  
  
                
    // lets process the top level list.
    // now we need to get the sub-features of each top-level feature.   
    //
    nzTopFeatureRetVal = ListGetFirstString ( lzTopFeatureListID, szTopFeature );     
    while ( nzTopFeatureRetVal != END_OF_LIST )           
        
        // Now for each top-level feature we need to get the associated
        // sub features. 
                         
        // Initialize the string list.
        lzSubFeatureListID = ListCreate (STRINGLIST);                                
        if (lzSubFeatureListID = LIST_NULL) 
        then  
    
            islib_MessageBox ("System error, unable to create sub-feature list.", SEVERE);
            return ISLIB_ERROR;
        
        endif;
    
                                                                           
        // Create a list of sub-features in the specified media.
        if ( FeatureListItems (MEDIA, szTopFeature, lzSubFeatureListID) < 0 )
        then      
    
            islib_MessageBox ("System error, failed to get sub-feature list.", SEVERE);
            return ISLIB_ERROR;                    
    
        endif;
        
        
        // Count the number of program folders in the list.
        nzSubFeatureCount = ListCount (lzSubFeatureListID); 
        if (  nzSubFeatureCount <= 0 )
        then
                
            islib_MessageBox ("Failed to detect any sub-features in patch configuration." +
                        "\nCheck patch configuration.", SEVERE);
            return ISLIB_ERROR; 
    
        endif;
           
        
        // now we need to get the sub-features of each top-level
        // feature.   
        nzSubFeatureRetVal = ListGetFirstString ( lzSubFeatureListID, szSubFeature );            
        while ( nzSubFeatureRetVal != END_OF_LIST )   
                            
            // we need to process each sub-feature, tht directly relates to
            // a component that delivers a file.
            // 
            // first we need to extract the sub-feature from the string we have,
            // the format is "topfeature\subfeature" 
            lzParseFeatureListID = ListCreate(STRINGLIST);
            StrGetTokens (lzParseFeatureListID, szSubFeature, "\\"); 
            
            // Count the number of program folders in the list.
            nzResult = ListCount (lzParseFeatureListID); 
            if (  nzResult != MAX_NUM_FEATURE_LEVELS )
            then
                
                islib_MessageBox ("ERROR: [" + szSubFeature + "] feature exceedes 2 levels." +
                            "\nCheck patch features configuration.", SEVERE);
                return ISLIB_ERROR;
    
            endif; 
                                              
            ListGetFirstString ( lzParseFeatureListID, szTmpVar1 );
            ListGetNextString  ( lzParseFeatureListID, szSubFeatureOnlyStr );                                   
              
              
            // lets create the list to contain all sub-feature items
            //  
            lzSubFeatureItemListID = ListCreate(STRINGLIST);                   
            
            
            // let extract all the items for my sub-feature
            //
            FeatureFileEnum ( MEDIA, szTopFeature, szSubFeatureOnlyStr+"\\*.*", lzSubFeatureItemListID, NO_SUBDIR );    
            
                                    
            // Count the number of sub-feature component items in the list.
            nzSubFeatureItemCount = ListCount (lzSubFeatureItemListID); 
            if (  nzSubFeatureItemCount <= 0 )
            then
                
                islib_MessageBox ("Failed to detect any items to patch in configuration. " +
                            "\nCheck [" + szSubFeature + "] features/components relationship in patch configuration.", SEVERE);
                return ISLIB_ERROR;
    
            endif;                        
              
              
            // Get the description property for sub-feature.   
            // This field contains the relative path from the INSTALLDIR
            // for the items in the component == subFeature.
            //
            FeatureGetData (MEDIA, szSubFeature, FEATURE_FIELD_DESCRIPTION, nzResult, szSubFeatureDescField);
            if ( szSubFeatureDescField = "" )
            then 
            
                islib_MessageBox (szSubFeature + " feature description field is blank." + 
                            "Check feature in patch configuration.", SEVERE);
                return ISLIB_ERROR;
            
            endif;
              
              
            // we need to determine if the description field is relative or
            // absolute.  This is done by looking for ":\" in the contents
            // if find this then it must be absolute, else it is a relative path
            // evaluated from INSTALLDIR.
            //                             
            if ( szSubFeatureDescField % ":\\" ) 
            then            
                szSubFeatureDescType = "Absolute";                
            else                                              
                szSubFeatureDescType = "Relative";            
            endif;
                                       

            // lets determine the location of our items
            //
            if ( szSubFeatureDescType = "Absolute" )
            then              
                szSubFeatureItemsLocation =  szSubFeatureDescField;            
            else                                                               
                szSubFeatureItemsLocation =  INSTALLDIR ^ szSubFeatureDescField;            
            endif;
               
               
            // for each item in the list we need to add it to the
            // larger list in a pre-defined format.
            //
            // the format being:
            //
            // item;location
            //          
            //
            nzSubFeatureItemRetVal = ListGetFirstString ( lzSubFeatureItemListID, szSubFeatureItem );            
            while ( nzSubFeatureItemRetVal != END_OF_LIST )   
                  
                // we will only add an item to the list if it exist
                // on disk.  a patch by definition cannot add new files
                // to a distribution.
                //
                // !!!! Need to think about libraries.  these files
                // break the rule!!!!
                //                        
                szString =  szSubFeatureItemsLocation ^ szSubFeatureItem;             
                if ( Is (FILE_EXISTS, szString) = FALSE )
                then    
                        
                    // there is a special case for dll items
                    // if we do not locate them on disk we can still 
                    // proceed with the patch
                    // 
                    StrToLower(szSubFeatureItem_lc, szSubFeatureItem);
                    if ( (szSubFeatureItem_lc % ".dll") != TRUE  )
                    then
                                                    
                        islib_MessageBox ("Failed to locate pre-installed package item [" +
                                    szString + "] on disk." +
                                    "\nA patch cannot add new items to an existing installation.", SEVERE);
                        return ISLIB_ERROR;
                        
                    else                                                    
                    
                        islib_MessageBox ("Patch is changing default installation by delivering new dll item [" +
                                    szSubFeatureItem + "].", INFORMATION);                                                                                                                    
                    
                    endif;
                                                       
                else                                                                    
                    
                    // we located the item on our disk
                    // lets log it for patching.
                    //
                    szString = szSubFeatureItem+ ";" + szSubFeatureItemsLocation;
                    if (ListAddString (lzPatchItemsListID, szString, AFTER) < 0) 
                    then
            
                        islib_MessageBox ("System error, failed to add entry to item list.", INFORMATION);
                        return ISLIB_ERROR;
                        
                    endif;
                
                endif;
                    
                // get next top-level feature.              
                nzSubFeatureItemRetVal = ListGetNextString ( lzSubFeatureItemListID, szSubFeatureItem );
            
            endwhile;                
                 
                        
            // lets free system resources
            //
            ListDestroy(lzSubFeatureItemListID);
            ListDestroy(lzParseFeatureListID);
                       
            
            // get next top-level feature.              
            nzSubFeatureRetVal = ListGetNextString ( lzSubFeatureListID, szSubFeature );
            
        endwhile;                                             
                                      
        // Clear list for next cycle.
        //                                      
        ListDestroy( lzSubFeatureListID );                                     
              
        // get next top-level feature.              
        nzTopFeatureRetVal = ListGetNextString ( lzTopFeatureListID, szTopFeature );
    
    endwhile;
             
    // Clear list for next cycle.
    //                                      
    ListDestroy( lzTopFeatureListID );        
                
    return ISLIB_SUCCESS;

end;
               

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_patchSaveItems
//
//   This function is used to create a copy of all items
//   that are to be updated by the patch.
//
//   We pass the list of items to be saved and the location of the
//   directory to save the item in.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////                              
function islib_savePatchItems(lzPatchItemsListID )
            
    NUMBER  nzTmpVar; 
    NUMBER  nzRetVal;
    NUMBER  nzItemCount; 
    NUMBER  nzItemRetVal;
    
    STRING  szTmpVar;
    STRING  szRetVal;            
    STRING  szMySrcFile;
    STRING  szMyDstFile;
    STRING  szListItem;
    
    STRING  szItemName;
    STRING  szItemLocation; 
    
    STRING  szPatchIDSaveDir;
    
    LIST    lzParseItemListID;

begin  
                           
    // we do not wnat to record 
    // what we save in InstallShiell.
    // 
    // we manage this stuff our-selves.
    //                           
    Disable(LOGGING); 
        
    // we know where our save dir is
    // it is predefined.
    //
    szPatchIDSaveDir = PATCHID_SAVE_DIR;
      
    // lets count the number of items we have to save
    // 
    nzItemCount = ListCount (lzPatchItemsListID);      
    if ( nzItemCount = 0 )
    then
    
        // we have nothing to save the patch
        // must contain new dlls only
        //
        return ISLIB_SUCCESS;
    
    else
    
        // we have work to do.              
        // Lets get our first item.
        //
        nzItemRetVal = ListGetFirstString ( lzPatchItemsListID, szListItem );            
        while ( nzItemRetVal != END_OF_LIST )  
        
            // lets parse the item from our list, we know
            // it contains item name and location delimited by a ";"
            //                      
            lzParseItemListID = ListCreate(STRINGLIST);
            StrGetTokens (lzParseItemListID, szListItem, ";"); 
              
                               
            // lets load the bits so we can use the information
            //                               
            ListGetFirstString ( lzParseItemListID, szItemName );
            ListGetNextString  ( lzParseItemListID, szItemLocation );                          
              
               
            // lets setup the source and destination items
            //                         
            szMySrcFile = szItemLocation ^  szItemName;
            szMyDstFile = szPatchIDSaveDir ^ szItemName;
                                                                                   
          
            // lets save the item in our predefined
            // patch save dir.
            //
            nzRetVal = CopyFile (szMySrcFile, szMyDstFile );              
            if ( nzRetVal < 0 )
            then 
        
                NumToStr(szRetVal, nzRetVal);
                islib_MessageBox("Failed to copy (save) item to be patched [" +
                           szMySrcFile + 
                           "], retVal: [" + 
                           szRetVal + 
                           "].", SEVERE);
                return ISLIB_ERROR;
    
            endif;
        
        
            // now we need to record the fact that we saved something
            //
            if ( islib_updatePatchLog(szItemName, szItemLocation) < 0 )
            then 
                                                                 
                islib_MessageBox("Failed to update patch log item.", SEVERE);            
                return ISLIB_ERROR;
            
            endif;
                                          
              
            // lets free resources for the next item
            // 
            ListDestroy(lzParseItemListID); 
              
              
            // lets get the next item.
            //
            nzItemRetVal = ListGetNextString ( lzPatchItemsListID, szListItem );            
            
        endwhile; 
        
    endif;        

    
    // lets enable the log.
    //                 
    Enable(LOGGING); 
          
                      
    return ISLIB_SUCCESS;
    
end;


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_updatePatchLog
//
//   This function is used to create a copy of all items
//   that are to be updated by the patch.
//
//   We pass the list of items to be saved and the location of the
//   directory to save the item in.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////               
               
function islib_updatePatchLog(szItemName, szItemLocation)
    
    STRING szPatchIDDir;
    STRING szPatchIDLogFileLocation;
    STRING szPatchIDLogFileName; 
    STRING szLine;
    
    NUMBER nzFileHandle;
    
begin   
    
    // lets initialise where we believe the
    // patch log file exists
    //         
    szPatchIDDir             = PATCHID_DIR;
    szPatchIDLogFileLocation = PATCHID_LOGFILE_LOCATION;        
    szPatchIDLogFileName     = PATCHID_LOGFILE_NAME;        
    
     
    // now we need to create the patchinfo file
    // that shall contain the details of what
    // we save abd where it goes back to.
    // format:
    // item;putBackLocation
    //
       
    // Set the file mode to read-write
    //
    OpenFileMode (FILE_MODE_APPEND);
      
    // lets check to see if the file
    // already exists.
    //        
    if ( Is (EXISTS,szPatchIDLogFileLocation) = TRUE )
    then                         
             
        // Open the text file.
        if (OpenFile (nzFileHandle, szPatchIDDir, szPatchIDLogFileName) < 0) 
        then
                       
            // Report the error.
            islib_MessageBox ("System error, failed to open patch log file.", SEVERE);
            return ISLIB_ERROR;
               
       endif;                         
                  
   else          
          
       // Create a new file and leave it open.
       if (CreateFile (nzFileHandle, szPatchIDDir, szPatchIDLogFileName) < 0) 
       then
       
           // Report the error.
           islib_MessageBox ("System error, failed to create patch log file.", SEVERE);
           return ISLIB_ERROR;
       
       endif;       

    endif;
    
        
    // Set the message to write to the file.
    //
    szLine = szItemName + ";" + szItemLocation;    
       
            
    // Write a line to the end of our file.
    //
    if (WriteLine(nzFileHandle, szLine) < 0) 
    then      
            
        // Report the error.
        islib_MessageBox ("System error, failed to write line to patch log.", SEVERE);
        return ISLIB_ERROR;
                          
    endif;

   
    // Close the file.
    CloseFile (nzFileHandle);                                                    
    
    
    // we are done.
    return  ISLIB_SUCCESS;

end;
        

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_patchPostRemove
//
//  1. initialise predefined parameters 
//
//  2. determine if patch can be removed.
//
//  3. if patch can be removed determine type of patch removal
//     (ie restore or no-restore) 
//
//  4. if we are to restore, 
//     4.1 we need to load our patch log and put back each item.
//
//  5. remove patch store.
//    
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_patchPostRemove()

    STRING szPatchIDDir;
    STRING szPatchIDSaveDir;
    STRING szPatchIDLogFileLocation;
    STRING szPatchIDLogFileName;  
    
    STRING szRemovalType; 
    
    NUMBER nzSaveItemsCount;
    
    LIST   lzPatchSavedItemsListID;
    
begin   
         
    // lets initialise info we are going to need
    //
    szPatchIDDir             = PATCHID_DIR;
    szPatchIDSaveDir         = PATCHID_SAVE_DIR;
    szPatchIDLogFileLocation = PATCHID_LOGFILE_LOCATION;          
         
                                                                      
    // lets verify we can remove the package just in-case
    // we didn't do it in the preremove phase 
    //
    // The type of removal is based on the parent package
    // if it still exist on the system then we need to rollback.
    // if the parent package for whatever reason has been removed
    // we can just need to clean-up.
    // 
    if ( islib_checkRemovePatch(szRemovalType) < 0 )
    then
        
        islib_MessageBox("This patch cannot be removed from this system yet.", SEVERE);                
        return ISLIB_ERROR;  
        
    endif;                    
                        
                         
    // we can remove the patch and we must restore
    // the save items
    //
    if ( szRemovalType = "Restore" )
    then   
                               
        // lets create save list 
        //                               
        lzPatchSavedItemsListID = ListCreate(STRINGLIST);
        
        // If an error occurred, report it; then terminate.
        if (lzPatchSavedItemsListID = LIST_NULL) then
        
            islib_MessageBox ("ERROR: Unable to create lzPatchSavedItemsListID.", SEVERE);
            return ISLIB_ERROR;
            
        endif;

        
                    
        // lets get all the items we previously saved
        // into a manageble list
        //
        if ( islib_getPatchSaveItemsList(lzPatchSavedItemsListID) < 0 )
        then  
    
            islib_MessageBox("ERROR: islib_getPatchSaveItemsList() did not complete successfully.", SEVERE);
            return ISLIB_ERROR;        
        
        endif; 
        
        
        // lets restore the items in our list if we have some
        //
        nzSaveItemsCount = ListCount (lzPatchSavedItemsListID);
        if (nzSaveItemsCount > 0)
        then                
            
            // we have work to do.
            //    
            if ( islib_restorePatchItems(lzPatchSavedItemsListID) < 0 )
            then  
    
                islib_MessageBox("ERROR: islib_restorePatchItems() did not complete successfully.", SEVERE);
                return ISLIB_ERROR;        
        
            endif;  
            
        endif;            
                                               

        // we have restored lets now putback 
        // the parent pkg patch details.
        //
        if ( islib_updatePkgPatchRegistryKeys("Restore", svRestorePatchID, svRestorePatchInstalled) < 0 )
        then  
    
            islib_MessageBox("ERROR: islib_updatePkgPatchRegistryKeys() did not complete successfully.", SEVERE);
            return ISLIB_ERROR;        
        
        endif;
        
        
        // lets free resources.  
        //
        ListDestroy(lzPatchSavedItemsListID);                         

    endif;             
      
                           
    // everything is ok upto here
    // lets delete the evidence.
    //                      
    if ( islib_deletePatchIDDir() < 0 )
    then 
        
        islib_MessageBox("islib_deletePatchDir() did not complete successfully.", WARNING);        
        
    endif;                               
    
    
    // we are done!
    return ISLIB_SUCCESS;
    
end;


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_restorePatchItems
//
//  This function restores all items in the saved list
//  back to the original location.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_restorePatchItems(lzPatchSavedItemsListID)
    
    STRING szPatchIDSaveDir; 
    STRING szListItem; 
    STRING szItemName;
    STRING szItemLocation; 
    STRING szMySrcFile;
    STRING szMyDstFile;
    
    NUMBER nzItemCount;
    NUMBER nzItemRetVal;
    
    STRING szRetVal;
    NUMBER nzRetVal;
    
    LIST lzParseItemListID;
    
begin                   
                   
    // Stop recording of any
    // of these actions.
    //                   
    Disable(LOGGING);
   
    
    // we know where our save dir is
    // it is predefined.
    //
    szPatchIDSaveDir = PATCHID_SAVE_DIR;
            
    // lets count the number of items we have to restore
    // 
    nzItemCount = ListCount (lzPatchSavedItemsListID);      
    if ( nzItemCount = 0 )
    then
    
        // we have nothing to restore the patch
        //
        return ISLIB_SUCCESS;
    
    else
    
        // we have work to do.              
        // Lets get our first item.
        //
        nzItemRetVal = ListGetFirstString ( lzPatchSavedItemsListID, szListItem );            
        while ( nzItemRetVal != END_OF_LIST )  
        
            // lets create a list to parse the retireved item.
            //                  
            lzParseItemListID = ListCreate(STRINGLIST); 
            
            // If an error occurred, report it, and return error.
            if (lzParseItemListID = LIST_NULL) then
        
                islib_MessageBox ("ERROR: Unable to create lzParseItemListID.", SEVERE);
                return ISLIB_ERROR;
            
            endif;
        
            // lets parse the item from our list, we know
            // it contains item name and location delimited by a ";"
            //
            StrGetTokens (lzParseItemListID, szListItem, ";");               
                               
            // lets load the bits so we can use the information
            //                               
            ListGetFirstString ( lzParseItemListID, szItemName );
            ListGetNextString  ( lzParseItemListID, szItemLocation );                          
              
               
            // lets setup the source and destination items
            //                         
            szMySrcFile = szPatchIDSaveDir ^ szItemName;
            szMyDstFile = szItemLocation ^ szItemName;
                                                                                   
          
            // lets restore the item from patch save dir.
            //
            nzRetVal = CopyFile (szMySrcFile, szMyDstFile );              
            if ( nzRetVal < 0 )
            then 
        
                NumToStr(szRetVal, nzRetVal);
                islib_MessageBox("Failed to copy (restore) item [" +
                           szMySrcFile + 
                           "], retVal: [" + 
                           szRetVal + 
                           "].", SEVERE);
                return ISLIB_ERROR;
    
            endif;                
                                                        
            // lets free resources for the next item
            // 
            ListDestroy(lzParseItemListID);               
              
            // lets get the next item.
            //
            nzItemRetVal = ListGetNextString ( lzPatchSavedItemsListID, szListItem );            
            
        endwhile; 
        
    endif;        

    
    // lets enable the log.
    //                 
    Enable(LOGGING);            


    // we are done.    
    return ISLIB_SUCCESS;
    
end;    
                            

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_getPatchSaveItemsList
//
//  This function generates a manageable list of all
//  saved items.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_getPatchSaveItemsList(lzPatchSavedItemsListID)
    
    STRING szPatchIDDir;    
    STRING szPatchIDLogFileName;  
    STRING szPatchIDLogFileLocation;
    
    STRING szLine; 
    
    NUMBER nzFileHandle;
    NUMBER nzRetVal;
    
begin

    // initialise local variables.
    //
    szPatchIDDir             = PATCHID_DIR;    
    szPatchIDLogFileLocation = PATCHID_LOGFILE_LOCATION;
    szPatchIDLogFileName     = PATCHID_LOGFILE_NAME;
    
    
    // Set the file mode to read-write
    //
    OpenFileMode (FILE_MODE_BINARY);
             
             
    // lets check to see if the file
    // already exists.
    //        
    if ( Is (EXISTS,szPatchIDLogFileLocation) = TRUE )
    then                                 
             
        // Open the text file.
        if (OpenFile (nzFileHandle, szPatchIDDir, szPatchIDLogFileName) < 0) 
        then
                       
            // Report the error.
            islib_MessageBox ("ERROR: Failed to open patch log file.", SEVERE);
            return ISLIB_ERROR;
               
        endif;                         
                         
                         
        // Get lines from the file into the list.
        // 
        nzRetVal = islib_getline (nzFileHandle, szLine);
        while (nzRetVal = 0)
        
            ListAddString (lzPatchSavedItemsListID, szLine, AFTER);                                                                                       
            nzRetVal = islib_getline (nzFileHandle, szLine);
            
        endwhile;                                            
                
        
        // Close the file.
        CloseFile (nzFileHandle);    
                      
    else                      
                                                        
       // no save file, there is nothing to restore.
       //                             
       return ISLIB_SUCCESS;
      
    endif;
                     
        
    // we are done. 
    return ISLIB_SUCCESS;
    
end;    
    

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_deletePatchIDDir
//
//  This function deletes the predefined 
//  patch directory and all its contents.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//
//    we do not return an error if the directory is not removed
//    it may have been removed previously.
//
//////////////////////////////////////////////////////////////////////////////
function islib_deletePatchIDDir() 
    
    STRING szPatchIDDir;
    
begin

    szPatchIDDir = PATCHID_DIR;
    
    // lets check to see if the dir exists
    // before we try to remove it.
    //
    if ( Is (PATH_EXISTS, szPatchIDDir) = TRUE )
    then
    
        if (DeleteDir (szPatchIDDir, ALLCONTENTS) < 0) 
        then
    
            islib_MessageBox ("ERROR: Unable to delete patch directory [" +
                         szPatchIDDir + "].", SEVERE);                                                                

            // we still proceed...
            return ISLIB_SUCCESS;                                     
                             
        endif;             
        
    endif;        
                         
    // done.                         
    return ISLIB_SUCCESS;
    
end;    
    


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_checkRemovePatch
//
//   This function is used to check if the patch can be removed.
//   The rules that govern if a patch can be removed are:
//
//   1. A parent package that has a name equal to that defined in the 
//      project Subject field does not exists on the system.
//
//      This condition shall be checked by ensuring the BaseInstallDir registry key
//      does not exist for the parent package defined in the project Subject setting.
//
//   2. If the a parent package exists see item 1) and the associated version number
//      is not equal to that that of the patch.
//
//      The patch version number is defined in the PKG_VERSION variable.
//
//      (i.e. The preinstalled patch MYPKG010001-0N can be removed if the parent package
//            MYPKG is of version 1.0.2).
//
//      This check shall be completed by comparing the Version registry setting of the package
//      with the PKG_VERSION variable of the patch.
//
//      This case implies a CLEAN install as the version number link no longer
//      exists. 
//
//      A patch can only be removed and thus used to restore a pre-defined specific 
//      parent package version.
//
//   3. An obsoleted patch cannot be removed until the patch that obsoletes
//      it is removed first.                                 
//
//      (ie you cannot remove patch MYPKG010001-01 before patch MYPKG010001-02).
//
//   4. A patch can be removed and restored if it the most recently applied patch to an 
//      existing parent package of the correct version number.
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//  The function also sets a variable  szRemovalType to be one of
//  two possible values "Restore" or "Clean", this refers to the type of
//  removal action, assuming we can procceed.
//
//////////////////////////////////////////////////////////////////////////////
function islib_checkRemovePatch ( szRemovalType )

    STRING szPatchID; 
    STRING szPkgName;            
    STRING szPatchIDNumber;
    STRING szPatchVersion;
    
    STRING szPkgBaseInstallDir; 
    STRING szPkgVersion; 
    STRING szPkgInstalled;  
    STRING szPkgLatestPatchID; 
    STRING szPkgLatestPatchInstalled; 
    STRING szPkgLatestPatchNumber;
    STRING szPkgBuildNum;
    STRING szPkgProjAcronym;
    STRING szPkgDesc; 
    
    NUMBER nzPkgLatestPatchNumber; 
    NUMBER nzPatchIDNumber;
    NUMBER nResult;      

begin  

    // initialise local variables.
    //
    szRemovalType = "Restore";
    szPatchID     = PATCH_ID;
    szPatchVersion= PKG_VERSION;
    szPkgName     = PKG_NAME;
    
    
    // 1. lets extract my parent packages details
    //   
    if ( islib_checkErgAfcPkgExists(szPkgName) < 0 )
    then    
    
        // we could not confirm that the parent package exists
        // so we assume that the package was removed.
        // 
        // This implies we need to simply cleanup our installation
        // 
        islib_MessageBox("The patch you trying to remove [" + szPatchID + "] has no parent package." +
                   "\n\nPatch shall not attempt to restore any previously saved items.", INFORMATION);        
        szRemovalType = "Clean";
        return ISLIB_SUCCESS; 
        
    else
    
        // our parent package exists lets get its current details
        //
        if (islib_getErgAfcPkgRegistryDetails( szPkgBaseInstallDir, 
                                               szPkgVersion,
                                               szPkgInstalled,
                                               szPkgLatestPatchID,                                                                                              
                                               szPkgLatestPatchInstalled,                                               
                                               szPkgBuildNum,
                                               szPkgProjAcronym,
                                               szPkgDesc ) < 0 )
        then                                       
                            
            // we encountered an error getting the details
            //
            islib_MessageBox("ERROR: islib_getErgAfcPkgRegistryDetails() did not complete successfully.", SEVERE);  
            return ISLIB_ERROR;                          
        
        endif;  
        
        
        // lets get our patch number.
        //   
        if ( islib_getPatchNumber( szPatchID, szPatchIDNumber ) < 0 )
        then
        
            islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE); 
            return ISLIB_ERROR;                                  
        
        endif;
        StrToNum(nzPatchIDNumber, szPatchIDNumber);
                

        // lets get the previous latest patch number.
        //   
        if ( islib_getPatchNumber( szPkgLatestPatchID, szPkgLatestPatchNumber ) < 0 )
        then
        
            islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE); 
            return ISLIB_ERROR;                                  
        
        endif;
        StrToNum(nzPkgLatestPatchNumber, szPkgLatestPatchNumber);                        
        
                
        // we got our details lets apply the business rules
        // of our patch management strategy.
        //
        
        // 2. we assume that our version are of the correct format
        //    lets compare them.
        //
        //    if the version differ then we can assume the version 
        //    of parent package we previously patched no longer
        //    exists and we cannot restore anything we saved.
        //    It is no longer relevant.
        //
        nResult = islib_compareVersions(szPkgVersion, szPatchVersion);
        if ( nResult != ISLIB_VERSION_EQUALS )
        then    
        
            // we could not confirm that the parent package exists
            // so we assume that the package was removed.
            // 
            // This implies we need to simply cleanup our installation
            // 
             islib_MessageBox("The patch you trying to remove [" + szPatchID + "] has an incompatible version number" +
                        "\nwith the current parent package." +
                        "\n\nPatch shall not attempt to restore any previously saved items.", INFORMATION);         
            szRemovalType = "Clean";
            return ISLIB_SUCCESS;  
        
        endif;
         
        
        // our versions must equal so now we need to use the patch
        // number we have versus the lastest number install 
        // for our package.
        //
        // 3. A patch cannot be removed if it is obsoleted.
        //
        //    A patch is deemed obsoleted if an installed patch 
        //    has a patch number less than that of the latest patch 
        //    applied to the parent package.
        //
        if ( nzPatchIDNumber < nzPkgLatestPatchNumber )
        then                                  
        
            // the patch we are trying to remove is obsolete
            // therefore we should not remove it until
            // all other patches that obsolete this patch
            // have sequentially been removed.
            //
            islib_MessageBox("The patch you trying to remove [" + szPatchID + "] has been obsoleted " +
                       "by a patch that has been \npreviously installed." +
                       
                       "\n\nThis patch cannot be removed until all other patches that obsolete this " +
                       "patch have been sequentially \nremoved." + 
                       
                       "\n\nThis patch is currently obsoleted by patch [" + szPkgLatestPatchID + "], installed on [" +
                       szPkgLatestPatchInstalled + "].", WARNING); 
              
            return ISLIB_ERROR; 
            
        elseif ( nzPatchIDNumber = nzPkgLatestPatchNumber )
        then  
        
            // we are the lastest pkg patch
            // we can proceed with restore and removal
            //
            szRemovalType = "Restore";
            return ISLIB_SUCCESS; 
            
        else
        
            // this is an impossible error
            islib_MessageBox("ERROR: You have probably not updated your package GUIs, patches must be unique.", SEVERE);
            return ISLIB_ERROR;
                               
        endif;                 
            
    endif;   
    
    
    // if we got to here things are ok, we now need to ensure that the
    // INSTALLDIR variable is set to the PkgBaseInstallDir variable
    // we retieved from the registry.  this ensures that the patch 
    // starts from the same point as the parent package.
    //
    INSTALLDIR = szPkgBaseInstallDir;     
    
    
    // done.
    return ISLIB_SUCCESS;

end;
             

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_updatePkgPatchRegistryKeys    
//
//  This function is used to update the parent package
//  patch registry keys so we can identiffy the latest
//  patch that has been installed.                
//
//  It is passed 3 parameters, these include:
//  szUpdateType, szPatchNumber, szPatchInstalled,
//
//  If the  szUpdateType parameter == "Restore" then the
//  fuction uses the other two parameters to update the registry.
//
//  If the szUpdateType != "Restore" the function uses the Patch configuration PATCH_ID and
//  current date/time values to upadte the registry.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_updatePkgPatchRegistryKeys( szUpdateType, szPatchID, szPatchInstalled)

    STRING szPkgName;
    STRING szTime;
    STRING szDate; 
    STRING szMyPatchID; 
    STRING szMyPatchInstalled;
    
    STRING szKey;
    STRING szClass;
    STRING szItem; 
    STRING szValue;
    
    NUMBER nzResult;
    
begin   
    
    // we do not want to record this
    //
    Disable(LOGGING);
              
                                                          
    szPkgName = PKG_NAME;  
       
       
    // what type of action are we
    // performing.
    //             
    if ( szUpdateType = "Restore" )
    then                         
    
        // use the passed values.
        szMyPatchInstalled = szPatchInstalled; 
        szMyPatchID        = szPatchID;
    
    else
                   
        // this is a normal install lets
        // evaluate the information
        
        // lets extract the patch ID from the config
        //
        szMyPatchID = PATCH_ID;                              
        
        // use now as our instllation date/time
        //
        GetSystemInfo ( TIME, nzResult, szTime );
        GetSystemInfo ( DATE, nzResult, szDate ); 
        szMyPatchInstalled = szDate + " " + szTime;                        
    
    endif;
    

    // lets define the base key root location
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 
    szKey   = ERGAFC_PKG_REGISTRY_BASE + szPkgName;
    szClass = "";   
    
            
    // we assume here that the key must exist to
    // get this far. we check for it anyway.
    // 
    // we do NOT create the key, if it happens
    // not to exist we need to report an error.          
    //
    if (RegDBKeyExist (szKey) < 0)
    then          
        
        islib_MessageBox ("ERROR: [" + szKey + "] registry key does not exist.", SEVERE);
        return ISLIB_ERROR;
            
    else  
    
        // lets update the LatestPatchID item. 
        //    
        szItem  = "LatestPatchID";
        szValue = szMyPatchID;
        if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
        then  
            
            islib_MessageBox( "Error updating [" + 
                         szKey + "\\" +  szItem +
                         "] registry key, with value [" +
                         szValue +
                         "].", SEVERE );
                    
            return ISLIB_ERROR; 
                
        endif;                              
                                
                
        // lets update the LatestPatchInstalled item.
        szItem  = "LatestPatchInstalled"; 
        GetSystemInfo ( TIME, nzResult, szTime );
        GetSystemInfo ( DATE, nzResult, szDate );
        szValue = szMyPatchInstalled;
        if (RegDBSetKeyValueEx(
                 szKey,
                 szItem,
                 REGDB_STRING,
                 szValue, -1 ) < 0)
        then  
            
            islib_MessageBox( "Error updating [" + 
                         szKey + "\\" +  szItem +
                         "] registry key, with value [" +
                         szValue +
                         "].", SEVERE );
                    
            return ISLIB_ERROR; 
                
        endif;  
                             
    endif;        
            
                                     
    // lets enable the logging again.
    //
    Enable(LOGGING);
        
        
    return ISLIB_SUCCESS;
    
end;
                                               
   
//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_patchPostInstall 
//
//  1. Set the patch registry key information
//
//  2. Update the product patch registry key information  
//
//  3. Create the obsolete.txt file that shall contain the
//     details of the patch that we are obsoleting.
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_patchPostInstall()

begin                       
                                                                                                                      
    // lets update our product registry setting.
    //
    if ( islib_setErgAfcPatchRegistryKeys() < 0 )
    then    
    
        islib_MessageBox("ERROR: islib_setErgAfcPatchRegistryKeys() did not complete successfully.", SEVERE);
        return ISLIB_ERROR;
        
    endif;                                                      
    
    
    // lets update the parent pkg patch registry keys
    //
    if ( islib_updatePkgPatchRegistryKeys("Install", "", "") < 0 )
    then    
    
        islib_MessageBox("ERROR: islib_updatePkgPatchRegistryKeys() did not complete successfully.", SEVERE);
        return ISLIB_ERROR;
        
    endif;
      

    return ISLIB_SUCCESS;
    
end;
      
                                               
//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_patchPreRemove 
//
//  1. Determine if we can remove the patch
//    
//  2. Determine if we are going to restore the
//     previous patch
//
//  3. If we are to restore, determine the patch number that was 
//     previously obsoloeted so we can restore its details.
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_patchPreRemove()

    STRING szRemovalType;

begin                   
    
    // initialse local variables. 
    szRemovalType = "Restore";
      
      
    // assuming we are going to restore
    //
    if (islib_checkRemovePatch(szRemovalType) < 0 )
    then 
    
        islib_MessageBox("This patch cannot be removed from this system yet.", SEVERE);        
        return ISLIB_ERROR;
    
    else
    
        // Display the AskYesNo dialog box.  The default is set to Yes.
        if (AskYesNo("This patch can be removed. Would you like to proceed?", YES) = NO)
        then
        
            islib_MessageBox("User has terminated installation.", SEVERE);
            abort;
            
        endif;  
        
    endif;
    
          
    // lets get the details of the patch we are going to
    // restore
    //
    if ( szRemovalType = "Restore" )
    then
    
        if ( islib_getPatchDetailsToRestore(svRestorePatchID,
                                            svRestorePatchInstalled) < 0 )
        then  
    
            islib_MessageBox("ERROR: islib_getPatchDetailsToRestore() did not complete successfully.", SEVERE);
            return ISLIB_ERROR;
    
        endif;      
                
    endif;
            
            
    // done.
    return ISLIB_SUCCESS;
    
end;  

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_getPatchDetailsToRestore
//
//  this function is used to get the patch number and installed date
//  recorded in the patch registry settings for the patch we
//  previously obsoleted.
//
//  The items of interest are: 
//  ObsoletedPatchInstalled, and ObsoletedPatchNumber
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error, product registry does not exist.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_getPatchDetailsToRestore(szRestorePatchID, szRestorePatchInstalled)

    STRING szPatchID;
    
    STRING szKey;
    STRING szClass;
    STRING szItem; 
    
    NUMBER nzType;
    NUMBER nzSize;

begin  

    szPatchID = PATCH_ID;

    // lets define the base key root location
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 
    szKey   =  ERGAFC_PATCH_REGISTRY_BASE + szPatchID;
    szClass = "";
     
     
    // Check if the newly created multi-level key exists.
    //
    if (RegDBKeyExist (szKey) < 0)
    then          
        
        islib_MessageBox ("ERROR: [" + szKey + "] registry key does not exist.", SEVERE);                    
        return ISLIB_ERROR;
            
    else    
    
    
        // Retrieve ObsoletedPatchID information. 
        szItem = "ObsoletedPatchID";
        if (RegDBGetKeyValueEx (szKey, szItem, nzType , szRestorePatchID, nzSize) < 0) 
        then  
          
            islib_MessageBox( "Error reading [" + 
                        szKey + "\\" +  szItem +
                        "] registry key.", SEVERE );
            return ISLIB_ERROR;
         
        endif; 
    
                          
        // Retrieve ObsoletedPatchInstalled information. 
        szItem = "ObsoletedPatchInstalled";
        if (RegDBGetKeyValueEx (szKey, szItem, nzType , szRestorePatchInstalled, nzSize) < 0) 
        then  
          
            islib_MessageBox( "Error reading [" + 
                        szKey + "\\" +  szItem +
                        "] registry key.", SEVERE );
            return ISLIB_ERROR;
         
        endif;                    
                   
    endif;
       
    // we are done.          
    return ISLIB_SUCCESS;

end;
      
      
//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_checkErgAfcPkgExists  
//
//  This function is used to determine if a parent package
//  exists.  It check for the base registry key.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error, product registry does not exist.
//                                                                             
//////////////////////////////////////////////////////////////////////////////

function islib_checkErgAfcPkgExists(szPkgName)

    STRING szKey, szClass, szItem;
    STRING szTmpVar;
    NUMBER nSize, nType;
    
begin  

    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 
    szKey   =  ERGAFC_PKG_REGISTRY_BASE + szPkgName;
    szClass = "";
     
    // Check if the base key exists.

    if (RegDBKeyExist (szKey) < 0)
    then          
        /* The message box is only usefull when debugging. 
        It becomes confusing to the operator in a production install. */
        
        // islib_MessageBox ("ERROR: Failed to access [" + szKey + "] registry key does not exist.", SEVERE);
        return ISLIB_ERROR;  
    endif;  
    
    
    /* We have found our base key. Lets check for the BaseInstallDir subkey
       Retrieve BaseInstallDir information. */
  
    szItem = "BaseInstallDir";
    if (RegDBGetKeyValueEx (szKey, szItem, nType , szTmpVar, nSize) < 0) 
    then     
        // islib_MessageBox( "ERROR: Failed to access [" + szKey + "\\" +  szItem + "] registry key.", SEVERE );
        return ISLIB_ERROR;
    endif; 
        
    // We have confirmed the package has a registry key, and is probably installed correctly.
    return ISLIB_SUCCESS;
    
end;    
        
 
 

//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_preinstallCheckErgAfcPkgExists  
//
//  This function is used to display a message box
//  if the parent package does not exists.
//                                                                             
//////////////////////////////////////////////////////////////////////////////

function islib_preinstallCheckErgAfcPkgExists(szPkgName, szPkgDesc)

   
begin  
    if ( islib_checkErgAfcPkgExists(szPkgName) < 0 )
    then    

        islib_MessageBox("The installer could not locate the prerequisite " + szPkgDesc + " package ("+szPkgName+"). Install will now abort.", SEVERE);
        abort;

    endif;
end;     
    
    


//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_preinstallCheckJavaJREExists  
//
//  This function is used to display a message box
//  if the JRE package does not exist.
//                                                                             
//////////////////////////////////////////////////////////////////////////////

function islib_preinstallCheckJavaJREExists()
begin  
    islib_preinstallCheckJavaJREExists2("");    
end;



//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_preinstallCheckJavaJREExists2
//
//  This function is used to display a message box
//  if the JRE package does not exist.
//                                                                             
//////////////////////////////////////////////////////////////////////////////

function islib_preinstallCheckJavaJREExists2(szJavaVer)

STRING  szKey;
   
begin  
    
    if ( szJavaVer = "" )
    then
        szJavaVer = JAVA_JRE_VERSION;
    endif;

    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    szKey   =  "SOFTWARE\\JavaSoft\\Java Runtime Environment\\"+szJavaVer;
        
    if (RegDBKeyExist (szKey) < 0)
    then          
        islib_MessageBox("The installer could not locate Java JRE version "+szJavaVer+". Install will now abort.", SEVERE);
        abort;  
    endif; 
    
end;



//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_preinstallCheckJavaExists
//
//  This function is used to display a message box
//  if the JRE package does not exist.
// 
//  islib_preinstallCheckJavaExists ( JRE|J2SDK|J2EE , VERSION , ABORT|WARN );  
//  
//  Default values are JRE, 1.4 & WARN
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error, product registry does not exist.
//  
//                                                                             
//////////////////////////////////////////////////////////////////////////////

function islib_preinstallCheckJavaExists(szJavaType, szJavaVer, szResponse)

STRING  szKey;
STRING  szRegPath; 
STRING  szMessage;
   
begin  
    
    if ( szJavaVer = "" )
    then
        szJavaVer = JAVA_JRE_VERSION;
    endif;
    
    switch (szJavaType)
        case "J2SDK":
                szRegPath = "SOFTWARE\\JavaSoft\\Java Development Kit";
                szMessage = "The installer could not locate Java SDK version " + szJavaVer + ".";
        case "J2EE":         
                szRegPath = "SOFTWARE\\SUNW\\Java 2 SDK, Enterprise Edition";
                szMessage = "The installer could not locate the Java 2 Enterprise Edition SDK.";
        default:
                 szJavaType = "JRE";
                 szRegPath = "SOFTWARE\\JavaSoft\\Java Runtime Environment";    
                 szMessage = "The installer could not locate Java JRE version " + szJavaVer + ".";
    endswitch;
    
    if ( szResponse != "ABORT" )
    then
        szResponse = "WARN";
    endif;

    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    szKey = szRegPath ^ szJavaVer;
        
    if (RegDBKeyExist (szKey) < 0)
    then
        islib_MessageBox( szMessage, SEVERE);

        if (szResponse = "ABORT")
        then
                abort;
        endif;

        return ISLIB_ERROR;        
    else  
        return ISLIB_SUCCESS;
    endif;     
    
end;

    
  
  
//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_getErgAfcPkgLatestPatchIDRegistryDetails
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error, product registry does not exist.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_getErgAfcPkgLatestPatchIDRegistryDetails
(         
    szLatestPatchID, szPatchLatestInstalled          
)
    
    STRING szKey;
    STRING szClass;
    STRING szItem; 
    
    NUMBER nzSize;  
    NUMBER nzType;
    
begin      

    // lets define the base key root location
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 
    szKey   =  ERGAFC_PKG_REGISTRY_BASE + PKG_NAME;
    szClass = "";
     
    // Check if the newly created multi-level key exists.
    //
    if (RegDBKeyExist (szKey) < 0)
    then          
        
        islib_MessageBox ("ERROR: [" + szKey + "] registry key does not exist.", SEVERE);                                                                              
        return ISLIB_ERROR;
            
    else              
                    
        // Retrieve key value information. 
        szItem = "LatestPatchID";
        if (RegDBGetKeyValueEx (szKey, szItem, nzType , szLatestPatchID, nzSize) < 0) 
        then  
          
            islib_MessageBox( "Error reading [" + 
                        szKey + "\\" +  szItem +
                        "] registry key.", SEVERE );
            return ISLIB_ERROR;
          
        endif; 
                
                                             
        // Retrieve key value information. 
        szItem = "LatestPatchInstalled";
        if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPatchLatestInstalled, nzSize) < 0) 
        then  
          
            islib_MessageBox( "Error reading [" + 
                        szKey + "\\" +  szItem +
                        "] registry key.", SEVERE );
            return ISLIB_ERROR;
          
        endif;         
                                                                                      
    endif; 
                                                                                 
    // we are done.
    return ISLIB_SUCCESS;

end;
 
 
//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_getErgAfcPkgRegistryDetails
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error, product registry does not exist.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_getErgAfcPkgRegistryDetails
( 
    szPkgBaseInstallDir , szPkgVersion, szPkgInstalled, 
    szLatestPatchID, szPatchLatestInstalled, 
    szPkgBuildNum,  szPkgProjAcronym, szPkgDesc
)

    STRING szKey;
    STRING szClass;
    STRING szItem; 
    
    NUMBER nzSize;  
    NUMBER nzType;
    
begin      

    // lets define the base key root location
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 
    szKey   =  ERGAFC_PKG_REGISTRY_BASE + PKG_NAME;
    szClass = "";
     
    // Check if the newly created multi-level key exists.
    //
    if (RegDBKeyExist (szKey) < 0)
    then          
        
        islib_MessageBox ("ERROR: [" + szKey + "] registry key does not exist.", SEVERE);                                                                             
        return ISLIB_ERROR;
            
    else              
            
          // Retrieve key value information. 
          szItem = "BaseInstallDir";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType, szPkgBaseInstallDir, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif; 
                   
          
          // Retrieve key value information. 
          szItem = "PkgVersion";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPkgVersion, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif; 
                   
          
          // Retrieve key value information. 
          szItem = "PkgInstalled";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPkgInstalled, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );                            
              return ISLIB_ERROR;
          
          endif; 
          
          
          // Retrieve key value information. 
          szItem = "LatestPatchID";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szLatestPatchID, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif; 
                
                                             
          // Retrieve key value information. 
          szItem = "LatestPatchInstalled";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPatchLatestInstalled, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif; 
          
          
          // Retrieve key value information. 
          szItem = "PkgBuildNum";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPkgBuildNum, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif; 
                  
                  
          // Retrieve key value information. 
          szItem = "PkgProjAcronym";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPkgProjAcronym, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif; 
          
          // Retrieve key value information. 
          szItem = "PkgDesc";
          if (RegDBGetKeyValueEx (szKey, szItem, nzType , szPkgDesc, nzSize) < 0) 
          then  
          
              islib_MessageBox( "Error reading [" + 
                          szKey + "\\" +  szItem +
                          "] registry key.", SEVERE );
              return ISLIB_ERROR;
          
          endif;                               
                                            
    endif; 
                                 
                                                 
    // we are done.
    return ISLIB_SUCCESS;

end;




//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_pkgPreRemove 
//
//  1. Determine if we can remove the pkg by checking to
//     see if the LatestPatchID number is equal to "00".
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_pkgPreRemove()

begin                            
      
    // assuming we are going to restore
    //
    if (islib_checkRemovePkg() < 0 )
    then 
    
        islib_MessageBox("This package cannot be removed from this system yet.", SEVERE);        
        return ISLIB_ERROR;  
        
    endif;                      
            
    // done.
    return ISLIB_SUCCESS;
    
end; 



//////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_checkRemovePkg
//
//   This function is used to check if the pkg can be removed.
//   The rules that govern if a pkg can be removed are:
//
//   1. It does not have any patches currently installed.
//      Patches should be removed prior to the package being removed.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//
//////////////////////////////////////////////////////////////////////////////
function islib_checkRemovePkg()
        
    STRING szPkgLatestPatchID; 
    STRING szPkgLatestPatchInstalled; 
    STRING szPkgLatestPatchNumber; 
    
    NUMBER nzPkgLatestPatchNumber; 
    NUMBER nResult;      

begin 

                                                                  
    // our parent package exists lets get its current details
    //
    if (islib_getErgAfcPkgLatestPatchIDRegistryDetails( szPkgLatestPatchID,                                                                                                       
                                                        szPkgLatestPatchInstalled) < 0 )
    then                                       
                            
        // we encountered an error getting the details
        // if we are in maintenance mode anyway lets just remove the package.
        //
        if (MAINTENANCE) 
        then
            return ISLIB_SUCCESS;
        else
                
            islib_MessageBox("ERROR: islib_getErgAfcPkgLatestPatchIDRegistryDetails() did not complete successfully.", SEVERE);  
            return ISLIB_ERROR;     
                                 
        endif;
        
    endif;          
        
        
    // lets get our patch number.
    //   
    if ( islib_getPatchNumber( szPkgLatestPatchID, szPkgLatestPatchNumber ) < 0 )
    then
        
        islib_MessageBox("ERROR: islib_getPatchNumber() did not complete successfully.", SEVERE); 
        return ISLIB_ERROR;                                  
        
    endif;
    StrToNum(nzPkgLatestPatchNumber, szPkgLatestPatchNumber);
    
    // lets see what our latest patch is?
    //
    if ( nzPkgLatestPatchNumber != 0 )
    then
    
        // a patch must still be installed
        //
        islib_MessageBox("This package has an associated patch still installed." +
                   "\n\nThe latest patch for this package is [" + szPkgLatestPatchID + "], " +
                   "installed on [" + szPkgLatestPatchInstalled + "]." +
                   "\n\nAll patches applied to a package must be sequentially removed prior to removing " +
                   "the package.", WARNING);
        return ISLIB_ERROR;        
    
    endif;
                                                  
    // we are done.                         
    return ISLIB_SUCCESS;      
        
end;   


//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_setSystemEnvironmentVariable  
//
// This function is used to set a System environment
// variable.
//
// We pass:
// 1. the name of the variable to be set (ie created).
// 2. the value to set the new variable.
//                                   
// In the event that a parameter is passed that is not supported
// shall result in the user being notified and the installation
// being aborted.
//
// Return Values:
//
// SUCCESSFULL ENVIRONMENT CREATION: 1
// ENVIRONMENT ALREADY EXISTS: 2
// ERROR:  -1
//
//////////////////////////////////////////////////////////////////////////////  

function islib_setSystemEnvironmentVariable( szNewVar, szNewVal )

    STRING szKey;
    STRING szName;
    STRING szPathBuff;
    
    NUMBER nType, nSize;  
    NUMBER nSUCCESS1, nSUCCESS2;
        
begin      
    
    nSUCCESS1 = ISLIB_SUCCESS;
    nSUCCESS2 = 2;
    
    // first we need to get access to the current system
    // path.
    //
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    szKey  = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
    szName = szNewVar;


    // Read the system variable if it exists
    //
    if (RegDBGetKeyValueEx(szKey, szName, nType, szPathBuff, nSize) < 0)
    then
    
        // we did not find it so lets create it
        //
        if (RegDBSetKeyValueEx( szKey, szName, REGDB_STRING_EXPAND, szNewVal, -1 ) < 0) 
        then   
    
            islib_MessageBox( "ERROR: Failed to create System variable registry key:\n" +
                        "[" + szKey + "\\" + szName + "]=[" + szNewVal + "].", SEVERE );
                        
            return ISLIB_ERROR;
          
        endif;
    
    else
    
        // we found the variable.
        //
        islib_MessageBox("INFO: SYSTEM environment variable previously created.\n" +
                   "[" + szKey + "\\" + szName + "]=[" + szNewVal + "].", INFORMATION );
        return nSUCCESS2;
        
    endif;
                                                                  
      
    // done dude.
    return nSUCCESS1;               

end;           



//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_forceSetSystemEnvironmentVariable  
//
// Added by D.Greeve - 24/10/05
//
// This function is used to set a System environment
// variable - code is based on islib_setSystemEnvironmentVariable.
// 
// Unlike islib_setSystemEnvironmentVariable this 
// function will always overwrite an existing environment variable 
// and flag the change so that it is not uninstalled.
//
// We pass:
// 1. the name of the variable to be set (ie created).
// 2. the value to set the new variable.
//                                   
// In the event that a parameter is passed that is not supported
// shall result in the user being notified and the installation
// being aborted.
//
// Return Values:
//
// SUCCESSFULL ENVIRONMENT CREATION: 1
// ENVIRONMENT ALREADY EXISTS: 2
// ERROR:  -1
//
//////////////////////////////////////////////////////////////////////////////  

function islib_forceSetSystemEnvironmentVariable( szNewVar, szNewVal )

    STRING szKey;
    STRING szName;
    STRING szPathBuff;
    
    NUMBER nType, nSize;  
    NUMBER nSUCCESS1, nSUCCESS2;
        
begin      
    
    nSUCCESS1 = ISLIB_SUCCESS;
    nSUCCESS2 = 2;
    
    // first we need to get access to the current system
    // path.
    //
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    szKey  = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
    szName = szNewVar;


    // Read the system variable if it exists
    //
    if (RegDBGetKeyValueEx(szKey, szName, nType, szPathBuff, nSize) < 0)
    then
    
        // we did not find it so lets create it
        //
        if (RegDBSetKeyValueEx( szKey, szName, REGDB_STRING_EXPAND, szNewVal, -1 ) < 0) 
        then   
    
            islib_MessageBox( "ERROR: Failed to create System variable registry key:\n" +
                        "[" + szKey + "\\" + szName + "]=[" + szNewVal + "].", SEVERE );
                        
            return ISLIB_ERROR;
          
        endif;
    
    else
    
        // we found the variable.
        //
        
        Disable(LOGGING);       
        
        if (RegDBSetKeyValueEx( szKey, szName, REGDB_STRING_EXPAND, szNewVal, -1 ) < 0) 
        then   
    
            islib_MessageBox( "ERROR: Failed to create System variable registry key:\n" +
                        "[" + szKey + "\\" + szName + "]=[" + szNewVal + "].", SEVERE );
                        
            return ISLIB_ERROR;
          
        endif;  
        
        Enable(LOGGING);
        return nSUCCESS2;
        
    endif;
                                                                  
      
    // done dude.
    return nSUCCESS1;               

end;           



//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_addAtItem  
//
// This function is used to add an item to the system AT manager
//
// We pass:
// 1. a tag to match against any possible existing items
// 2. the item to be added
//                                   
// Return Values:
//
// SUCCESS: ISLIB_SUCCESS
// ERROR:   ISLIB_ERROR
//
//////////////////////////////////////////////////////////////////////////////  
function islib_addAtItem( szTag, szItem )

    STRING szListItem;  
    
    STRING szItemNo;
     
    NUMBER nzItemRetVal;
    
    LIST   lzAtItemsListID; 
    LIST   lzParseItemListID;  
    
begin     
               
    // lets remove any existing
    // entries that match our tag before
    // we add our new item
    //           
    if ( islib_removeAtItem( szTag ) < 0 )
    then
    
        islib_MessageBox("ERROR: returned by islib_removeAtItem().", SEVERE);
        return ISLIB_ERROR;    
    
    endif;
    
    // if we get to here we should be able to
    // load our new AT item
    //     
    LaunchAppAndWait ( "at", szItem, WAIT );                                                                                               
              
    // done dude.
    return ISLIB_SUCCESS;     
      
end; 


//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_removeAtItem  
//
// This function is used to remove an item to the system AT manager
//
// We pass:
// 1. a tag to match against the item you wish to remove.
//                                   
// Return Values:
//
// SUCCESS: ISLIB_SUCCESS
// ERROR:   ISLIB_ERROR
//
//////////////////////////////////////////////////////////////////////////////  
function islib_removeAtItem( szTag )

    STRING szListItem;  
    
    STRING szItemNo;
     
    NUMBER nzItemRetVal;
    
    LIST   lzAtItemsListID; 
    LIST   lzParseItemListID;  
    
    STRING szMyCmd;
    
begin        

    szMyCmd = "at";                      
        
    // lets create save list.
    // if an error occurred, report it; then terminate.
    //
    lzAtItemsListID = ListCreate(STRINGLIST);
    if (lzAtItemsListID = LIST_NULL) 
    then
        
        islib_MessageBox ("ERROR: Unable to create lzAtItemsListID.", SEVERE);
        return ISLIB_ERROR;
            
    endif;                                        
    
    // lets get a listing of what the AT mgr currently
    // contains.
    //   
    if ( islib_getCmdOutputItemList(lzAtItemsListID, szMyCmd) < 0 )
    then                      
            
        // we could not get a listing so i will assume 
        // there was nothing in the AT manager
        //                                                   
        islib_MessageBox ("ERROR: returned by islib_getAtItemList().", SEVERE);        
             
    else              
    
        // we have a list at this point.
        // 
        //SdShowInfoList ("Debug Display", "Current AT mgr listing...", lzAtItemsListID);
    
        // we have work to do.              
        // Lets get our first item.
        //  
        // the first two strings are not required in our 
        // listing, they are just some frilly bit as seen below.
        // the good stuff usually begins at line 3.
        //
        // line1: There are no entries in the list.
        //
        // or
        // 
        // line1: Status ID   Day                     Time          Command Line
        // line2: -------------------------------------------------------------------------------
        //
        ListGetFirstString ( lzAtItemsListID, szListItem );            
        
        nzItemRetVal = ListGetNextString ( lzAtItemsListID, szListItem );                    
        if ( szListItem != "" && nzItemRetVal != END_OF_LIST )
        then  
                            
            // now lets deal with any content.
            //
            nzItemRetVal = ListGetNextString ( lzAtItemsListID, szListItem );                                
            while ( nzItemRetVal != END_OF_LIST )  
        
                // lets create a list to parse the retireved item.
                //                  
                lzParseItemListID = ListCreate(STRINGLIST); 
            
                // If an error occurred, report it, and return error.
                if (lzParseItemListID = LIST_NULL) 
                then
        
                    islib_MessageBox ("ERROR: Unable to create lzParseItemListID.", SEVERE);
                    return ISLIB_ERROR;
            
                endif;                   
                   
                // we want to know if the item we are trying to add
                // already exists in the AT listing so we need to compare
                // our tag to the line, if we find a match we shall
                // proceed to delete the entry and add our new one.
                // This should not happen in normal practice as
                // when packages get removed they should remove the 
                // AT items that belong to them.
                //                                
                if ( szListItem % (szTag) )
                then
                
                    //islib_MessageBox("matched szListItem=[" + szListItem + "], szItemNo=[" + szItemNo + "].", INFORMATION);                
             
                    // we have found a match between my tag
                    // and a list item (ie an AT entry).
                    // lets parse the item, we know
                    // it contains the item number as the first field 
                    // delimited by a whitespace or " "
                    //
                    StrGetTokens (lzParseItemListID, szListItem, " ");               
                               
                    // lets load the bits so we can use the information
                    //                               
                    ListGetFirstString ( lzParseItemListID, szItemNo );                                                                
                
                    // what do we do with this item.
                    //                                                    
                    LaunchApp("at", szItemNo + " /delete" );
                    //islib_MessageBox ("INFO: we have deleted AT item number " + szItemNo, INFORMATION);                    
                                                                                                                                                                                                                  
                    // lets free resources for the next item
                    // 
                    ListDestroy(lzParseItemListID);               
            
                endif;
              
                // lets get the next item.
                //
                nzItemRetVal = ListGetNextString ( lzAtItemsListID, szListItem );            
            
            endwhile;                                      
            
        endif;            
                                                
    endif;
        
    // lets free resources for the next item
    // 
    ListDestroy(lzAtItemsListID);       
                                                                                                
          
    // done dude.
    return ISLIB_SUCCESS;               
      
end;

        



//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_updateRegistryKey  
//
// This function is used to add a a registry key. Current version is
// just an extention of the RegDBSetKeyValueEx function - with better 
// interaction for the user if the entry fails.
//
// We pass:
// - The key name
// - The specific key entry
// - The type of key to be generated
// - The value of the key we are changing/creating
// - The size of the value. 
//
//      For further information check the help menus.
//                                   
// Return Values:
//
// SUCCESS: ISLIB_SUCCESS
// ERROR:   ISLIB_ERROR
//
//////////////////////////////////////////////////////////////////////////////  

function islib_updateRegistryKey (szKey, szName, nType, szValue, nSize )

begin  
    
    RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    
    if (RegDBSetKeyValueEx( szKey, szName, nType, szValue, nSize  ) < 0)
    then  
        islib_MessageBox( "Error updating [" + szKey + "\\" +  szName + "] registry key, with value [" + szValue + "].", SEVERE );
        return ISLIB_ERROR;
    endif;
    
    return ISLIB_SUCCESS;
    
end;     



//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_getHostIPAddress  
//
// This function is used to determine the host's primary
// IP Address as returned by the 'ipconfig /all' system command
//
// We pass:
// 1. a tag to match against the item you wish to remove.
//                                   
// Return Values:
//
// Set the string szIPAddress and return.
//
// SUCCESS: ISLIB_SUCCESS
// ERROR:   ISLIB_ERROR
//
//////////////////////////////////////////////////////////////////////////////  
function islib_getHostIPAddress( szIPAddress )

    STRING szListItem;  
    STRING szItemNo;
     
    NUMBER nzItemRetVal;
    
    LIST   lzIpconfigItemsListID; 
    LIST   lzParseItemListID;  
    
    STRING szMyCmd;
    STRING szTmpStr, szTmpIPAddress;
    NUMBER nzStrLength;
    
begin              

    szMyCmd = "ipconfig /all";         
        
    // lets create save list.
    // if an error occurred, report it; then terminate.
    //
    lzIpconfigItemsListID = ListCreate(STRINGLIST);
    if (lzIpconfigItemsListID = LIST_NULL) 
    then
        
        islib_MessageBox ("ERROR: Unable to create lzIpconfigItemsListID.", SEVERE);
        return ISLIB_ERROR;
            
    endif;                                        
    
    
    // lets get a listing of what the 'ipconfig /all' command
    //   
    if ( islib_getCmdOutputItemList(lzIpconfigItemsListID, szMyCmd) < 0 )
    then                      
            
        // something went wrong with the command execution.
        //                                                   
        islib_MessageBox ("ERROR: returned by islib_getCmdOutputItemList().", SEVERE);        
             
    else              
    
        // we have a list at this point.
        // 
        //SdShowInfoList ("Debug Display", "Current command listing...", lzIpconfigItemsListID);
    
        // we have work to do.              
        // we are looking for the line that contains the follwing
        // string "IP Address".        
        //                
        nzItemRetVal = ListGetFirstString ( lzIpconfigItemsListID, szListItem );                    
        if ( szListItem != "" && nzItemRetVal != END_OF_LIST )
        then  
                            
            // now lets deal with any content.
            //
            nzItemRetVal = ListGetNextString ( lzIpconfigItemsListID, szListItem );                                
            while ( nzItemRetVal != END_OF_LIST )  
        
                // lets create a list to parse the retireved item.
                //                  
                lzParseItemListID = ListCreate(STRINGLIST); 
            
                // If an error occurred, report it, and return error.
                if (lzParseItemListID = LIST_NULL) 
                then
        
                    islib_MessageBox ("ERROR: Unable to create lzParseItemListID.", SEVERE);
                    return ISLIB_ERROR;
            
                endif;                   
                                   
                // we are searching for the line with the "IP Address...                               
                if ( szListItem % ("IP Address.") )
                then
                    
                    // Debug help
                    //islib_MessageBox("matched szListItem=[" + szListItem + "].", INFORMATION);                
             
                    // we have found a match between my tag
                    // and a list item.
                    // lets parse the item, we know something about the format.
                    // it contains two bits delimited by a colon or ":"
                    //
                    StrGetTokens (lzParseItemListID, szListItem, ":");               
                               
                    // lets load the bits so we can use the information
                    //                               
                    ListGetFirstString ( lzParseItemListID, szTmpStr );                                                                                                                                             
                    ListGetNextString ( lzParseItemListID, szTmpIPAddress );                                                                                                                                                                                                           
                    
                    // we have our ip address but it contains a leading space
                    //
                    nzStrLength = StrLength(szTmpIPAddress);
                    StrSub(szIPAddress,szTmpIPAddress,1,nzStrLength);
                                     
                    // lets free resources for the next item
                    // 
                    ListDestroy(lzParseItemListID); 
                                        
                    // done dude.
                    return ISLIB_SUCCESS;                                     
            
                endif;
              
                // lets get the next item.
                //
                nzItemRetVal = ListGetNextString ( lzIpconfigItemsListID, szListItem );            
            
            endwhile;                                      
            
        endif;            
                                                
    endif;
        
    // lets free resources for the next item
    // 
    ListDestroy(lzIpconfigItemsListID);       
                                                                                                
          
    // done dude.
    return ISLIB_SUCCESS;               
      
end;


//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_getCmdOutputItemList  
//
// This function is used to get a listing of the current
// content of the "ipconfig" system command.  
// It populates a string list that we pass by reference.
//
// We pass:
// 1. a List (by ref) to populate.
//                                   
// Return Values:
//
// SUCCESS: ISLIB_SUCCESS
// ERROR:   ISLIB_ERROR
//
//////////////////////////////////////////////////////////////////////////////
function   islib_getCmdOutputItemList (lzListID, szCmd)  

    STRING szCmdDir;
    STRING szCmdOutputFileName; 
    STRING szCmdFileName;
    STRING szCmdOutputFileLocation;   
    STRING szCmdFileLocation;
    
    STRING szLine; 
    
    NUMBER nzFileHandle;
    NUMBER nzRetVal;      

begin 

    // lets initialise our variables.                               
    //
    szCmdDir                = WINDIR^"temp\\xx_var\\";
    szCmdOutputFileName     = "xx_cmd.txt"; 
    szCmdFileName           = "xx_cmd.bat"; 
    szCmdOutputFileLocation =  szCmdDir +  szCmdOutputFileName;      
    szCmdFileLocation       =  szCmdDir +  szCmdFileName;            
     
     
    // if the CmdDir does not already exist lets create
    // it for free 
    //
    if (ExistsDir (szCmdDir) != EXISTS) 
    then
    
        // lets create our cmd dir
        //           
        if ( CreateDir ( szCmdDir ) < 0 )
        then      
    
             islib_MessageBox("Failed to create [" + szCmdDir + "] dir.", SEVERE);
             return ISLIB_ERROR;                    
                             
        endif;   
    
    endif;       
    
    
    // we need to create an interim file to capture
    // a listing of the cmd.  Trying to re-direct the output
    // using the LaunchApp command does not appear to work???
    // anyway...
    // 
    OpenFileMode (FILE_MODE_APPEND);
         
          
    // Create a new file and leave it open.
    if (CreateFile (nzFileHandle, szCmdDir, szCmdFileName) < 0) 
    then
       
        // Report the error.
        islib_MessageBox ("System error, failed to create file " + szCmdFileLocation, SEVERE);
        return ISLIB_ERROR;
       
    endif;       

    
    // Write a line to the end of our file.
    //
    if (WriteLine(nzFileHandle, szCmd + " > " + szCmdOutputFileLocation) < 0) 
    then      
            
        // Report the error.
        islib_MessageBox ("System error, failed to write line to " + szCmdFileLocation, SEVERE);
        return ISLIB_ERROR;
                          
    endif;

   
    // Close the file.
    CloseFile (nzFileHandle); 
    
                                                  
    // lets create the current view of the AT manager
    // by running our tmp bat file.
    //                                     
    LaunchAppAndWait ( szCmdFileLocation, "", WAIT );    
    
    
    // Set the file mode to read-only
    //
    OpenFileMode (FILE_MODE_BINARY);
      
      
    // lets check to see if the output file
    // exists.
    //        
    if ( Is (EXISTS,szCmdOutputFileLocation) = TRUE )
    then                         
             
        // Open the text file.
        if (OpenFile (nzFileHandle, szCmdDir, szCmdOutputFileName) < 0) 
        then
                       
            // Report the error.
            islib_MessageBox ("System error, failed to open file [" +
                        szCmdOutputFileLocation + "].", SEVERE);
            return ISLIB_ERROR;
               
        endif;  
       
       
        // Get lines from the file into the list.
        // 
        nzRetVal = islib_getline (nzFileHandle, szLine);
        while (nzRetVal = 0)                                               
        
            ListAddString (lzListID, szLine, AFTER);                                                                                       
            nzRetVal = islib_getline (nzFileHandle, szLine);
            
        endwhile; 
    
        
        // Close the file.
        CloseFile (nzFileHandle);                                                                
    
    else                                 
    
         // output file does not exist...
         //
         islib_MessageBox ("System error, failed to find command output file [" +
                      szCmdOutputFileLocation + "].", SEVERE);
            
         return ISLIB_ERROR;
                       
    endif;
    
    
    // we are done.
    return ISLIB_SUCCESS;                   
      
end;  




//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_MessageBox  
//
// This function is an alternative to the MessageBox funtion.
// It prevents errant warning messages from breaking Silent Installs.
// 
//
//////////////////////////////////////////////////////////////////////////////

function islib_MessageBox (szMsg, nType)     

begin 
    
    // If we are running in silent mode or record mode we do not want 
    // messages to pop up
    
    if ( MODE = NORMALMODE ) then
        MessageBox( szMsg, nType);
    endif;                                    

end;





//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_CheckCSTrace 
//
//                      This function checks for the existance/correctness of the DRWatson
//                      debugger in the registry. If it finds an inconsistancy with the
//                      default WinNT settings - it returns a failure code.
//
//                      Return Values:
//
//                      SUCCESS: ISLIB_SUCCESS
//                      ERROR:   ISLIB_ERROR  
// 
//
//////////////////////////////////////////////////////////////////////////////

function islib_CheckCSTrace ()     

NUMBER  nResult, nType, nSize;
STRING  szAuto, szDebugger;
STRING  szAutoValue, szDebuggerValue;
STRING  szKey;

begin 
                                            
        szAuto = DEFAULT_DEBUGGER_AUTO;
        szDebugger = DEFAULT_DEBUGGER;          
        szKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug";
                                
        RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);
    
    // Check for the basic key. The system is in a bad way if this isnt here.
    // We also check for the two key values and return the appropriate error codes.
    //
    if ( (RegDBGetKeyValueEx (szKey, "Auto", nType , szAutoValue, nSize) < 0) ||
         (RegDBGetKeyValueEx (szKey, "Debugger", nType , szDebuggerValue, nSize) < 0) )
        then
            islib_MessageBox ("ERROR: Failed to locate [" + szKey + "] Registry key does not exist.", SEVERE);
        abort;                  
    else
        // If we get to here then both keys exist. Now to compare with the defaults.
        //
        if ( szAuto = szAutoValue) && ( szDebugger = szDebuggerValue)
        then
                return ISLIB_SUCCESS;
        else
                return ISLIB_ERROR;
        endif;
    endif;  
                           
end;                                            




//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_SetCSTrace 
//
//                      This function sets the DRWatson debugger in the registry. 
//                      It sets the two important values to what is required by
//                      ERG's core services system (which is coincidentally the same
//                      as the NT4 default.    
//
//                      This is an irreversible system change. Logging is disabled.
//
//                      Return Values:
//
//                      SUCCESS: ISLIB_SUCCESS
//                      ERROR:   ABORT  
// 
//
//////////////////////////////////////////////////////////////////////////////

function islib_SetCSTrace ()     

STRING  szAuto, szDebugger;
STRING  szKey;

begin

        szAuto = DEFAULT_DEBUGGER_AUTO;
        szDebugger = DEFAULT_DEBUGGER;          
        szKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug";
                                
        RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE);

    /* 
    We wont check for the presence of the keys first. Two things are assumed.
    1. islib_CheckCSTrace() has been run first so you know the keys are there/need to be changed
    2. You are running this function because you _want_ the keys to be created/changed 
    */

        Disable (LOGGING);
        
        if ( RegDBSetKeyValueEx ( szKey, "Auto", REGDB_STRING, szAuto, -1 ) < 0 )
        then
                MessageBox ("ERROR: Failed to set [" + szKey + " - Auto]", SEVERE);
                abort;
    endif;
    
    if ( RegDBSetKeyValueEx ( szKey, "Debugger", REGDB_STRING, szDebugger, -1 ) < 0 )
        then
                MessageBox ("ERROR: Failed to set [" + szKey + " - Debugger]", SEVERE);
                abort;
    endif;
        
        Enable (LOGGING);
        
        return ISLIB_SUCCESS;
        
end;      

//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_checkActiveStatePerl 
//
//      This function is used to check for the existence of a
//  specific version of PERL on the system.
//
//  Parameters:
//
//  1) Build Version,
//     the perl build version number (ie "635"), 
//     it is recorded as a registry value string under the base key,
//     
//     HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActivePerl\\CurrentVersion
//                   
//  2) PERL install dir,
//     the location of the PERL install, this is recored as a default regestry
//     value string entry under the base registry key,                                      
//
//     HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\ActivePerl\\<BuildVersion>
//
//      Return Values:
//
//      SUCCESS: ISLIB_SUCCESS
//      ERROR:   abort  
//
//////////////////////////////////////////////////////////////////////////////
function islib_checkActiveStatePerl(nzMinRequiredVersion, szInstallDir)

    NUMBER nzType, nzSize; 
    STRING szCurrentVersion, szMinRequiredVersion;
    NUMBER nzCurrentVersion;   
    
    STRING szCurrentInstallDir;
    STRING szCurrentInstallDir_lc;
    
    STRING szInstallDir_lc;
        
    STRING szRegKey;
    
begin                                             

    NumToStr(szMinRequiredVersion, nzMinRequiredVersion);                                                                                                               

    RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
        szRegKey = "\\SOFTWARE\\ActiveState\\ActivePerl";
        
        if (RegDBKeyExist (szRegKey) < 0) 
        then                            
        
            // we did not find the key          
            islib_MessageBox("The installer could not locate the prerequisite package, ActiveState PERL [" +szMinRequiredVersion+ "]. Install will now abort.", SEVERE);
        abort;          
                
        else                        
                                                   
            // we found the key                        
            // lets see what version of perl is installed
            RegDBGetKeyValueEx ( szRegKey, "CurrentVersion", nzType, szCurrentVersion, nzSize );                                                        

        // need to convert the strings into numbers for comparison
        StrToNum(nzCurrentVersion, szCurrentVersion);                                                                                                           
            if(  nzMinRequiredVersion > nzCurrentVersion )
            then  
            
                // current version of perl required is not current
                // we assume that they are both the same version, though
                //
                islib_MessageBox("The installer has located and earlier version of ActiveState PERL " 
                                 +szCurrentVersion+ "].\n" +
                                 "The recommended version of ActiveState PERL is [" +szMinRequiredVersion+ "].", WARNING);                      
            
            endif;
            
                                                                                                                                                                         
            // perl is installed, now lets check where...
            //
            szRegKey = "\\SOFTWARE\\ActiveState\\ActivePerl\\" + szCurrentVersion;
        RegDBGetKeyValueEx ( szRegKey, "", nzType, szCurrentInstallDir, nzSize );
        
        // lets make the string lower case so we can compare them
        //
        StrToLower(szCurrentInstallDir_lc, szCurrentInstallDir);
        StrToLower(szInstallDir_lc, szInstallDir);
        
                if ( szCurrentInstallDir_lc != szInstallDir_lc )
                then 
                
                // default install is not where we expected it.
                //
                islib_MessageBox("The installer has detected that ActiveState PERL has been previously incorrectly installed in [" 
                                 +szCurrentInstallDir_lc+ 
                                 "].\n" +
                                 "The required default install location is [" 
                                 +szInstallDir_lc+ 
                                 "]. Install will now abort.", SEVERE);
            abort;              
                
                endif;  
                
                        
         endif;   

end;


///////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:   islib_verifyIPAddressStrFormat (STRING)
//
// This function is used to verify that the input parameter has
// a correct format of an IP address.
//
// We know the string is delimeted by a "."s
// We know that the string must have 4 components
// We know that each components are integers
// We know that each integer can have a value of 0 to 254
// If any discrepancy is detected we return an error. 
//
// Return Values:
//    ISLIB_SUCCESS = string has correct IP address format.
//    ISLIB_ERROR   = string does NOT have a correct
//                    IP address format.
//
///////////////////////////////////////////////////////////////////////////////
             
function islib_verifyIPAddressStrFormat(szIPAdress)

    LIST lzIPAddressComponents;
    NUMBER nCount;
    NUMBER nResult;
    
    STRING szItem;
    NUMBER nzItem;

begin  

    //islib_MessageBox("input szIPAdress=[" +szIPAdress+ "].", INFORMATION); 
    
    // we need to break the input string into the 4 components
    // that define an IPAddress. 
    
    // Create an empty number list.
    lzIPAddressComponents = ListCreate (STRINGLIST);

    // If an error occurred, report it; then terminate.
    if (lzIPAddressComponents = LIST_NULL) 
    then
    
        // Report the error.
        islib_MessageBox ("Unable to create list.", SEVERE);
        return ISLIB_ERROR; 
        
    endif; 
    
    // Get each path from the search path into the list.
    if (StrGetTokens (lzIPAddressComponents, szIPAdress, "\.") > 0) 
    then
    
        // Report the error.
        islib_MessageBox ("StrGetTokens failed.", SEVERE);
        return ISLIB_ERROR;
        
    endif;

     
    // Count the number of program folders in the list.
    nCount = ListCount (lzIPAddressComponents);

    // Report error or display the folder count.
    if (nCount < 0) 
    then
    
        islib_MessageBox ("ListCount failed.", SEVERE);
        return ISLIB_ERROR;
        
    elseif (nCount != 4)
    then
    
        islib_MessageBox ("IP address supplied [" +szIPAdress+ "] has an incorrect format.\n" +
                    "\nNote:\trequired IP address format: [NNN.NNN.NNN.NNN]\n" +
                    "\twhere NNN is an integer 0 to 254.", WARNING);
        return ISLIB_ERROR;        
    
    endif;
      
    // we have the correct number of sections
    // now lets check to see each segment is
    // a number and falls within the rewuired
    // range. 
    // 
    nResult = ListGetFirstString (lzIPAddressComponents, szItem);

    // Loop while not at end of list.
    while (nResult != END_OF_LIST)
             
        // check to see if the item is a number
        //
        if ( StrToNum(nzItem, szItem) < 0 )
        then  
                              
            islib_MessageBox ("IP address supplied [" +szIPAdress+ "] has a NON-numeric " + 
                        "section ["+szItem+"].\n" +
                        "\nNote:\trequired IP address format: [NNN.NNN.NNN.NNN]\n" +
                        "\twhere NNN is an integer 0 to 254.", WARNING);                                           
            return ISLIB_ERROR;
        
        endif;
        
        // we have a numeric section lets check to see if
        // it exists within the allowed range
        //
        if ( nzItem < 0 || nzItem > 254 )
        then
        
            islib_MessageBox ("IP address supplied [" +szIPAdress+ 
                        "] has a section ["+szItem+"] that is outside the allowable \nbounds of 0 to 254.\n" +
                        "\nNote:\trequired IP address format: [NNN.NNN.NNN.NNN]\n" +
                        "\twhere NNN is an integer 0 to 254.", WARNING);                                           
            return ISLIB_ERROR;        
        
        endif;
        
        
        // Get the next number from the list.
        nResult = ListGetNextString (lzIPAddressComponents, szItem);
    endwhile;

    
    // if we get to here things are ok.
    
    
    // Remove the list from memory.
    ListDestroy (lzIPAddressComponents);
                         
                         
    // we are done.                         
    return ISLIB_SUCCESS;

end;


///////////////////////////////////////////////////////////////////////////////
//
// Function: islib_WriteLineToEndOfFile
//
// Purpose: This function is used to write a line to the end of a file
//          and trap the error if the action does not succeed.
//
//  Return Values:
//  ISLIB_ERROR   : write fails
//  ISLIB_SUCCESS : write succeeds.
//   
//
///////////////////////////////////////////////////////////////////////////////                  
function islib_WriteLineToEndOfFile(szDir, szFile, szLine)

    NUMBER nzFileHandle;
    
begin  
          
    // Set the file mode to read-write
    //
    OpenFileMode (FILE_MODE_APPEND);
     
      
    // lets check to see if the file
    // already exists.
    //        
    if ( Is (EXISTS,szDir + szFile) = TRUE )
    then                         
             
        // Open the text file.
        if (OpenFile (nzFileHandle, szDir, szFile) < 0) 
        then
                       
            // Report the error.
            islib_MessageBox ("System error, failed to open " + szDir + szFile + " file.", SEVERE);
            return ISLIB_ERROR;
               
       endif;                         
                  
    else          
          
       // Create a new file and leave it open.
       if (CreateFile (nzFileHandle, szDir, szFile) < 0) 
       then
       
           // Report the error.
           islib_MessageBox ("System error, failed to create " + szDir + szFile + " file.", SEVERE);
           return ISLIB_ERROR;
       
       endif;       

    endif;                 
      
    // lets update the file
    //      
    if (WriteLine(nzFileHandle, szLine) < 0) 
    then      
            
        // Report the error.
        islib_MessageBox ("System error, failed to write line to " + szFile + "] file.", SEVERE);
        return ISLIB_ERROR;
                          
    endif; 
    
    
    // Close the file.
    CloseFile (nzFileHandle);      
    
    
    // we are done.
    return  ISLIB_SUCCESS;   
        
end;       


/////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_pkgPreInstall 
//
//  Determine if we can install the pkg by:
//
//  1. checking to see if the PKG_VERSION definition == @PRODUCT_VERSION string.
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_pkgPreInstall()

begin

    // now we just check to see if the project version numbers entered match
    // if they do not we need to exit.
    // we canot however check the build number and project acronym easily.
    //                    
    if ( PKG_VERSION != @PRODUCT_VERSION )
    then
        
         islib_MessageBox("The build.pl PKG_VERSION=[" +PKG_VERSION+ "] property does not match the Ishield PRODUCT_VERSION=["+@PRODUCT_VERSION+"] property.\n" +
                          "Please review the IShield Product Properties with the local build.pl details before proceeding.", SEVERE);            
         return ISLIB_ERROR;
    
    endif; 
    
    // done.
    return ISLIB_SUCCESS;
        
end;   


/////////////////////////////////////////////////////////////////////////////
//
//  FUNCTION: islib_verifyProcmgrInstall 
//
//  Determine if we have successfully updated the Registry when registering
//  the pmsi service.
//
//  1. The service information exists in the CurrentControl set, under the
//     registry key:
//
//     HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services
//
//     The Procmgr service is called "ERG Process Manager" if this key exists
//     we would be reasonably confident that the installation has
//     succeeded.
//
//     Therefore we are looking for:
//
//     HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\ERG Process Manager\\Parameters    
//
//
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//////////////////////////////////////////////////////////////////////////////
function islib_verifyProcmgrInstall()

    NUMBER nzType, nzSize; 
    STRING szRegKey;

begin


    RegDBSetDefaultRoot (HKEY_LOCAL_MACHINE);
    szRegKey = "\\SYSTEM\\CurrentControlSet\\Services\\ERG Process Manager\\Parameters";
        
    if (RegDBKeyExist (szRegKey) < 0) 
    then                            
        
        // we did not find the key              
        islib_MessageBox("ERROR: Failed to verify ERG Process Manager Service Installation.\n" +
                         "The service did not install successfully!", SEVERE);
        return ISLIB_ERROR;             
                
    endif;
    

    // we are done and all went well
    //
    return ISLIB_SUCCESS;
    
end;

    
                                                   
                                                                                                                                                                         
//////////////////////////////////////////////////////////////////////////////
//                                                                   
// FUNCTION:  islib_validateHexString(STRING)                                                             
//                                                                       
// DESCRIPTION:                                                                  
//                              This function validates a Hexadecimal string. If the string isnt hex,
//                              it returns an appropriate code.      
//                              This function also performs lowercase conversion.
//            
//  Return Values:
//    ISLIB_SUCCESS - It's a Hex string
//    ISLIB_ERROR   - error during processing or it's not hex.
//                                                                             
//                                                                   
//////////////////////////////////////////////////////////////////////////////

function islib_validateHexString (szString)

NUMBER  nSequence, nLength;
STRING  szElement;

begin
    nSequence = 0;
    
    // Convert it to lowercase
    if (StrToLower ( szElement, szString ) < 0)
    then
        islib_MessageBox ("ERROR: Conversion of szString to lowercase failed.", WARNING);
    endif;

    szString = szElement;
                   
    // Get the string's length in characters...
    //
    nLength = StrLengthChars (szString) - 1;

    // Check it character by character...
    //  
    for nSequence = 0 to nLength 
                        
        StrSub ( szElement, szString, nSequence, 1 );
                
        switch (szElement)
                case "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","x":
                    // This is okay  
                default:  
                   // This is not.
                   return ISLIB_ERROR;
        endswitch;      
   endfor;
        
        return ISLIB_SUCCESS;
end;




//////////////////////////////////////////////////////////////////////////////
//                                                                   
// FUNCTION:  islib_convertHexStringToIntString(STRING)                                                           
//                                                                       
// DESCRIPTION:                                                                  
//                              This function converts a Hexadecimal string into an Integer string.      
//            
//  Return Values:
//    ISLIB_SUCCESS - completed
//    ISLIB_ERROR   - error during processing.
//                                                                             
//                                                                   
//////////////////////////////////////////////////////////////////////////////


function islib_convertHexStringToIntString (szHexString)
   
NUMBER  nInteger;
BOOL    bResult;

begin

  bResult = StrToIntExA ( szHexString, STIF_SUPPORT_HEX, &nInteger);
  
  // Verify conversion worked.
  if ( bResult = FALSE ) 
  then 
        return ISLIB_ERROR;
  endif;
  
  // verify conversion from Int to Str worked.
  if ( NumToStr ( szHexString, nInteger ) < 0 )
  then
        return ISLIB_ERROR;
  endif;
  
  return ISLIB_SUCCESS;
  
end;                                               
                                                                                                                                                                         

//////////////////////////////////////////////////////////////////////////////
//                                                                   
// FUNCTION:  islib_getline(NUMBER, BYREF STRING)
//                                                                       
// DESCRIPTION:                                                                  
//                              Replace the flawed GetLine() function
//
//              This version will treat /r and /n as line endings
//              GetLine only works on lines that have both
//
//              NOTE: The file MUSt be opened with OpenFileMode(FILE_MODE_BINARY)
//                    as NORMAL mode appears to confuse line endings.
//                              
//
// Return Values:
//    0 - Not end of file (there's more to read)
//    1 - End of file is reached
//                                                                             
//                                                                   
//////////////////////////////////////////////////////////////////////////////
function islib_getline(nzFileHandle, szLine)
        STRING szChar;
        BOOL bzMore, bzNotEof;
        
begin

        bzMore = 1;
    bzNotEof = 1;
        szLine = "";

    //
    //  Read data skipping /r and /n charcaters
    //
    while ( bzMore && bzNotEof )
        if ( ReadBytes (nzFileHandle, szChar, 0, 1) > 0)
        then
            if ((szChar != "\n") &&  (szChar != "\r"))
            then
                bzMore = 0;
                szLine = szLine + szChar;
            endif;
        else
            bzNotEof = 0;
        endif;
        endwhile;

    //
    //  Now read data up until the end of the line or end of file
    //
        bzMore = 1;
    while ( bzMore && bzNotEof )
        if ( ReadBytes (nzFileHandle, szChar, 0, 1) > 0)
        then
            if ((szChar = "\n") ||  (szChar = "\r"))
            then
                bzMore = 0;
            else
                szLine = szLine + szChar;
            endif;
        else
            bzNotEof = 0;
        endif;
        endwhile;

    //
    //  Determine if we are at the end of the file
    //  If bzMore is True then we have been looking for characters, but have not
    //  bean able to read any. Thus we are at the end of the file.
    //
    return bzMore;

end;