Back to index

lightning-sunbird  0.9+nobinonly
extra.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Sean Su <ssu@netscape.com>
00025  *   Curt Patrick <curt@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "extern.h"
00042 #include "extra.h"
00043 #include "process.h"
00044 #include "dialogs.h"
00045 #include "ifuncns.h"
00046 #include "xpnetHook.h"
00047 #include "time.h"
00048 #include "xpi.h"
00049 #include "logging.h"
00050 #include "nsEscape.h"
00051 #include <logkeys.h>
00052 #include <winnls.h>
00053 #include <winver.h>
00054 
00055 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
00056 #include <shellapi.h>
00057 
00058 #define HIDWORD(l)   ((DWORD) (((ULONG) (l) >> 32) & 0xFFFF))
00059 #define LODWORD(l)   ((DWORD) (l))
00060 
00061 #define DEFAULT_ICON_SIZE   32
00062 
00063 #define FTPSTR_LEN (sizeof(szFtp) - 1)
00064 #define HTTPSTR_LEN (sizeof(szHttp) - 1)
00065 
00066 ULONG  (PASCAL *NS_GetDiskFreeSpace)(LPCTSTR, LPDWORD, LPDWORD, LPDWORD, LPDWORD);
00067 ULONG  (PASCAL *NS_GetDiskFreeSpaceEx)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
00068 HRESULT InitGre(greInfo *gre);
00069 void    DeInitGre(greInfo *gre);
00070 void    UpdateGreInstallerCmdLine(greInfo *aGre, char *aParameter, DWORD aParameterBufSize, BOOL forExistingGre);
00071 void    LaunchExistingGreInstaller(greInfo *gre);
00072 HRESULT GetInstalledGreConfigIni(greInfo *aGre, char *aGreConfigIni, DWORD aGreConfigIniBufSize);
00073 HRESULT GetInfoFromInstalledGreConfigIni(greInfo *aGre);
00074 HRESULT DetermineGreComponentDestinationPath(char *aInPath, char *aOutPath, DWORD aOutPathBufSize);
00075 BOOL    IsOkToRemoveFileOrDirname(char *aFileOrDirname, char **aListToIgnore,
00076 int     aListToIgnoreLength, char **aListProfileObjects, int aListProfileLength);
00077 int     GetTotalNumKeys(char *aSectionName, char *aBaseKeyName);
00078 void    CleanupArrayList(char **aList, int aListLength);
00079 char    **BuildArrayList(char *aSectionName, char *aBaseKeyName, int *aArrayLength);
00080 BOOL    IsDirAProfileDir(char *aParentPath, char **aListProfileObjects, int aListLength);
00081 
00082 static greInfo gGre;
00083 
00084 char *ArchiveExtensions[] = {"zip",
00085                              "xpi",
00086                              "jar",
00087                              ""};
00088 
00089 // Path and filename to the GRE's uninstaller.  This is used to cleanup
00090 // old versions of GRE that have been orphaned when upgrading mozilla.
00091 #define GRE_UNINSTALLER_FILE "[WINDIR]\\GREUninstall.exe"
00092 
00093 #define GRE_REG_KEY "Software\\mozilla.org\\GRE"
00094 #define SETUP_STATE_REG_KEY "Software\\%s\\%s\\%s\\Setup"
00095 #define APP_PATHS_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s"
00096 
00097 //GRE app installer progress bar integration
00098 typedef LONG (CALLBACK* LPFNDLLFUNC)(LPCTSTR,INT);
00099 
00100 #define GRE_APP_INSTALLER_PROXY_DLL      "ProgUpd.dll"
00101 #define GRE_PROXY_UPD_FUNC               "StdUpdateProgress"
00102 #define GRE_INSTALLER_ID                 "gre"
00103 
00104 #define FOR_EXISTING_GRE                 TRUE
00105 #define FOR_NEW_GRE                      FALSE
00106 
00107 LPSTR szProxyDLLPath;
00108 LPFNDLLFUNC lpfnProgressUpd;
00109 HINSTANCE hGREAppInstallerProxyDLL;
00110 
00111 BOOL gGreInstallerHasRun = FALSE;
00112 
00113 BOOL InitDialogClass(HINSTANCE hInstance, HINSTANCE hSetupRscInst)
00114 {
00115   WNDCLASS  wc;
00116 
00117   wc.style         = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
00118   wc.lpfnWndProc   = DefDlgProc;
00119   wc.cbClsExtra    = 0;
00120   wc.cbWndExtra    = DLGWINDOWEXTRA;
00121   wc.hInstance     = hSetupRscInst;
00122   wc.hIcon         = LoadIcon(hSetupRscInst, MAKEINTRESOURCE(IDI_SETUP));
00123   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
00124   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
00125   wc.lpszMenuName  = NULL;
00126   wc.lpszClassName = CLASS_NAME_SETUP_DLG;
00127 
00128   return(RegisterClass(&wc));
00129 }
00130 
00131 BOOL InitApplication(HINSTANCE hInstance, HINSTANCE hSetupRscInst)
00132 {
00133   BOOL     bRv;
00134   WNDCLASS wc;
00135 
00136   wc.style         = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC | CS_SAVEBITS;
00137   wc.lpfnWndProc   = DefWindowProc;
00138   wc.cbClsExtra    = 0;
00139   wc.cbWndExtra    = 0;
00140   wc.hInstance     = hInstance;
00141   wc.hIcon         = LoadIcon(hSetupRscInst, MAKEINTRESOURCE(IDI_SETUP));
00142   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
00143   wc.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION + 1);
00144   wc.lpszMenuName  = NULL;
00145   wc.lpszClassName = CLASS_NAME_SETUP;
00146 
00147   bRv = RegisterClass(&wc);
00148   if(bRv == FALSE)
00149     return(bRv);
00150 
00151   return(InitDialogClass(hInstance, hSetupRscInst));
00152 }
00153 
00154 BOOL InitInstance(HINSTANCE hInstance, DWORD dwCmdShow)
00155 {
00156   HWND hWnd;
00157 
00158   gSystemInfo.dwScreenX = GetSystemMetrics(SM_CXSCREEN);
00159   gSystemInfo.dwScreenY = GetSystemMetrics(SM_CYSCREEN);
00160 
00161   gSystemInfo.lastWindowPosCenterX  = gSystemInfo.dwScreenX / 2;
00162   gSystemInfo.lastWindowPosCenterY  = gSystemInfo.dwScreenY / 2;
00163   gSystemInfo.lastWindowMinimized   = FALSE;
00164   gSystemInfo.lastWindowIsTopWindow = TRUE;
00165 
00166   hInst = hInstance;
00167 
00168   /* This window is only for the purpose of allowing the self-extracting .exe
00169    * code to detect that a setup.exe is currenly running and do the appropriate
00170    * action given certain conditions.  This window is created and left in the
00171    * invisible state.
00172    * There's no other purpose for this window at this time.
00173    */
00174   hWnd = CreateWindow(CLASS_NAME_SETUP,
00175                       DEFAULT_SETUP_WINDOW_NAME,
00176                       WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
00177                       -150,
00178                       -50,
00179                       1,
00180                       1,
00181                       NULL,
00182                       NULL,
00183                       hInstance,
00184                       NULL);
00185 
00186   if(!hWnd)
00187     return(FALSE);
00188 
00189   hWndMain = NULL;
00190 
00191   return(TRUE);
00192 }
00193 
00194 void PrintError(LPSTR szMsg, DWORD dwErrorCodeSH)
00195 {
00196   DWORD dwErr;
00197   char  szErrorString[MAX_BUF];
00198 
00199   if(dwErrorCodeSH == ERROR_CODE_SHOW)
00200   {
00201     dwErr = GetLastError();
00202     wsprintf(szErrorString, "%d : %s", dwErr, szMsg);
00203   }
00204   else
00205     wsprintf(szErrorString, "%s", szMsg);
00206 
00207   if((sgProduct.mode != SILENT) && (sgProduct.mode != AUTO))
00208   {
00209     ShowMessage(NULL, FALSE);
00210     MessageBox(hWndMain, szErrorString, NULL, MB_ICONEXCLAMATION);
00211   }
00212   else if(sgProduct.mode == AUTO)
00213   {
00214     ShowMessage(szErrorString, TRUE);
00215     Delay(5);
00216     ShowMessage(NULL, FALSE);
00217   }
00218 }
00219 
00220 /* Windows API does offer a GlobalReAlloc() routine, but it kept
00221  * returning an out of memory error for subsequent calls to it
00222  * after the first time, thus the reason for this routine. */
00223 void *NS_GlobalReAlloc(HGLOBAL *hgMemory,
00224                        DWORD dwMemoryBufSize,
00225                        DWORD dwNewSize)
00226 {
00227   HGLOBAL hgPtr = NULL;
00228 
00229   if((hgPtr = NS_GlobalAlloc(dwNewSize)) == NULL)
00230     return(NULL);
00231   else
00232   {
00233     memcpy(hgPtr, *hgMemory, dwMemoryBufSize);
00234     FreeMemory(hgMemory);
00235     *hgMemory = hgPtr;
00236     return(hgPtr);
00237   }
00238 }
00239 
00240 void *NS_GlobalAlloc(DWORD dwMaxBuf)
00241 {
00242   void *vBuf = NULL;
00243 
00244   if((vBuf = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, dwMaxBuf)) == NULL)
00245   {     
00246     if((szEGlobalAlloc == NULL) || (*szEGlobalAlloc == '\0'))
00247       PrintError(TEXT("Memory allocation error."), ERROR_CODE_HIDE);
00248     else
00249       PrintError(szEGlobalAlloc, ERROR_CODE_SHOW);
00250 
00251     return(NULL);
00252   }
00253   else
00254     return(vBuf);
00255 }
00256 
00257 void FreeMemory(void **vPointer)
00258 {
00259   if(*vPointer != NULL)
00260     *vPointer = GlobalFree(*vPointer);
00261 }
00262 
00263 HRESULT NS_LoadStringAlloc(HANDLE hInstance, DWORD dwID, LPSTR *szStringBuf, DWORD dwStringBuf)
00264 {
00265   char szBuf[MAX_BUF];
00266 
00267   if((*szStringBuf = NS_GlobalAlloc(MAX_BUF)) == NULL)
00268     exit(1);
00269   
00270   if(!LoadString(hInstance, dwID, *szStringBuf, dwStringBuf))
00271   {
00272     if((szEStringLoad == NULL) ||(*szEStringLoad == '\0'))
00273       wsprintf(szBuf, "Could not load string resource ID %d", dwID);
00274     else
00275       wsprintf(szBuf, szEStringLoad, dwID);
00276 
00277     PrintError(szBuf, ERROR_CODE_SHOW);
00278     return(1);
00279   }
00280   return(0);
00281 }
00282 
00283 HRESULT NS_LoadString(HANDLE hInstance, DWORD dwID, LPSTR szStringBuf, DWORD dwStringBuf)
00284 {
00285   char szBuf[MAX_BUF];
00286 
00287   if(!LoadString(hInstance, dwID, szStringBuf, dwStringBuf))
00288   {
00289     if((szEStringLoad == NULL) ||(*szEStringLoad == '\0'))
00290       wsprintf(szBuf, "Could not load string resource ID %d", dwID);
00291     else
00292       wsprintf(szBuf, szEStringLoad, dwID);
00293 
00294     PrintError(szBuf, ERROR_CODE_SHOW);
00295     return(1);
00296   }
00297   return(WIZ_OK);
00298 }
00299 
00300 void Delay(DWORD dwSeconds)
00301 {
00302   DWORD i;
00303   for(i = 0; i < dwSeconds * 10; i++)
00304   {
00305     SleepEx(100, FALSE);
00306     ProcessWindowsMessages();
00307   }
00308 }
00309 
00310 BOOL VerifyRestrictedAccess(void)
00311 {
00312   char  szSubKey[MAX_BUF];
00313   char  szSubKeyToTest[] = "Software\\%s - Test Key";
00314   BOOL  bRv;
00315   DWORD dwDisp = 0;
00316   DWORD dwErr;
00317   HKEY  hkRv;
00318 
00319   wsprintf(szSubKey, szSubKeyToTest, sgProduct.szCompanyName);
00320   dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
00321                          szSubKey,
00322                          0,
00323                          NULL,
00324                          REG_OPTION_NON_VOLATILE,
00325                          KEY_WRITE,
00326                          NULL,
00327                          &hkRv,
00328                          &dwDisp);
00329   if(dwErr == ERROR_SUCCESS)
00330   {
00331     RegCloseKey(hkRv);
00332     switch(dwDisp)
00333     {
00334       case REG_CREATED_NEW_KEY:
00335         RegDeleteKey(HKEY_LOCAL_MACHINE, szSubKey);
00336         break;
00337 
00338       case REG_OPENED_EXISTING_KEY:
00339         break;
00340     }
00341     bRv = FALSE;
00342   }
00343   else
00344     bRv = TRUE;
00345 
00346   return(bRv);
00347 }
00348 
00349 void SetInstallFilesVar(LPSTR szProdDir)
00350 {
00351   char szProgramPath[MAX_BUF];
00352 
00353   if(szProdDir[lstrlen(szProdDir) - 1] == '\\')
00354     wsprintf(szProgramPath, "%s%s", szProdDir, sgProduct.szProgramName);
00355   else
00356     wsprintf(szProgramPath, "%s\\%s", szProdDir, sgProduct.szProgramName);
00357 
00358   if((!gbForceInstall) && FileExists(szProgramPath))
00359     sgProduct.bInstallFiles = FALSE;
00360 }
00361 
00362 void UnsetSetupState(void)
00363 {
00364   char szKey[MAX_BUF_TINY];
00365 
00366   wsprintf(szKey,
00367            SETUP_STATE_REG_KEY,
00368            sgProduct.szCompanyName,
00369            sgProduct.szProductNameInternal,
00370            sgProduct.szUserAgent);
00371   DeleteWinRegValue(HKEY_CURRENT_USER, szKey, "Setup State");
00372 }
00373 
00374 void SetSetupState(char *szState)
00375 {
00376   char szKey[MAX_BUF_TINY];
00377 
00378   wsprintf(szKey,
00379            SETUP_STATE_REG_KEY,
00380            sgProduct.szCompanyName,
00381            sgProduct.szProductNameInternal,
00382            sgProduct.szUserAgent);
00383 
00384   SetWinReg(HKEY_CURRENT_USER, szKey, TRUE, "Setup State", TRUE,
00385             REG_SZ, szState, lstrlen(szState), TRUE, FALSE);
00386 }
00387 
00388 DWORD GetPreviousUnfinishedState(void)
00389 {
00390   char szBuf[MAX_BUF_TINY];
00391   char szKey[MAX_BUF_TINY];
00392   DWORD dwRv = PUS_NONE;
00393 
00394   if(sgProduct.szCompanyName &&
00395      sgProduct.szProductNameInternal &&
00396      sgProduct.szUserAgent)
00397   {
00398     wsprintf(szKey,
00399              SETUP_STATE_REG_KEY,
00400              sgProduct.szCompanyName,
00401              sgProduct.szProductNameInternal,
00402              sgProduct.szUserAgent);
00403     GetWinReg(HKEY_CURRENT_USER, szKey, "Setup State", szBuf, sizeof(szBuf));
00404     if(lstrcmpi(szBuf, SETUP_STATE_DOWNLOAD) == 0)
00405       dwRv = PUS_DOWNLOAD;
00406     else if(lstrcmpi(szBuf, SETUP_STATE_UNPACK_XPCOM) == 0)
00407       dwRv = PUS_UNPACK_XPCOM;
00408     else if(lstrcmpi(szBuf, SETUP_STATE_INSTALL_XPI) == 0)
00409       dwRv = PUS_INSTALL_XPI;
00410   }
00411 
00412   return(dwRv);
00413 }
00414 
00415 void UnsetSetupCurrentDownloadFile(void)
00416 {
00417   char szKey[MAX_BUF];
00418 
00419   wsprintf(szKey,
00420            SETUP_STATE_REG_KEY,
00421            sgProduct.szCompanyName,
00422            sgProduct.szProductNameInternal,
00423            sgProduct.szUserAgent);
00424   DeleteWinRegValue(HKEY_CURRENT_USER,
00425                     szKey,
00426                     "Setup Current Download");
00427 }
00428 
00429 void SetSetupCurrentDownloadFile(char *szCurrentFilename)
00430 {
00431   char szKey[MAX_BUF];
00432 
00433   wsprintf(szKey,
00434            SETUP_STATE_REG_KEY,
00435            sgProduct.szCompanyName,
00436            sgProduct.szProductNameInternal,
00437            sgProduct.szUserAgent);
00438   SetWinReg(HKEY_CURRENT_USER,
00439             szKey,
00440             TRUE,
00441             "Setup Current Download",
00442             TRUE,
00443             REG_SZ,
00444             szCurrentFilename,
00445             lstrlen(szCurrentFilename),
00446             TRUE,
00447             FALSE);
00448 }
00449 
00450 char *GetSetupCurrentDownloadFile(char *szCurrentDownloadFile,
00451                                   DWORD dwCurrentDownloadFileBufSize)
00452 {
00453   char szKey[MAX_BUF];
00454 
00455   if(!szCurrentDownloadFile)
00456     return(NULL);
00457 
00458   ZeroMemory(szCurrentDownloadFile, dwCurrentDownloadFileBufSize);
00459   if(sgProduct.szCompanyName &&
00460      sgProduct.szProductNameInternal &&
00461      sgProduct.szUserAgent)
00462   {
00463     wsprintf(szKey,
00464              SETUP_STATE_REG_KEY,
00465              sgProduct.szCompanyName,
00466              sgProduct.szProductNameInternal,
00467              sgProduct.szUserAgent);
00468     GetWinReg(HKEY_CURRENT_USER,
00469               szKey,
00470               "Setup Current Download", 
00471               szCurrentDownloadFile,
00472               dwCurrentDownloadFileBufSize);
00473   }
00474 
00475   return(szCurrentDownloadFile);
00476 }
00477 
00478 void UpdateGREAppInstallerProgress(int percent)
00479 {
00480   if (lpfnProgressUpd)
00481     lpfnProgressUpd(GRE_INSTALLER_ID, percent);
00482 }
00483 
00484 BOOL UpdateFile(char *szInFilename, char *szOutFilename, char *szIgnoreStr)
00485 {
00486   FILE *ifp;
00487   FILE *ofp;
00488   char szLineRead[MAX_BUF];
00489   char szLCIgnoreLongStr[MAX_BUF];
00490   char szLCIgnoreShortStr[MAX_BUF];
00491   char szLCLineRead[MAX_BUF];
00492   BOOL bFoundIgnoreStr = FALSE;
00493 
00494   if((ifp = fopen(szInFilename, "rt")) == NULL)
00495     return(bFoundIgnoreStr);
00496   if((ofp = fopen(szOutFilename, "w+t")) == NULL)
00497   {
00498     fclose(ifp);
00499     return(bFoundIgnoreStr);
00500   }
00501 
00502   if(lstrlen(szIgnoreStr) < sizeof(szLCIgnoreLongStr))
00503   {
00504     lstrcpy(szLCIgnoreLongStr, szIgnoreStr);
00505     CharLower(szLCIgnoreLongStr);
00506   }
00507   if(lstrlen(szIgnoreStr) < sizeof(szLCIgnoreShortStr))
00508   {
00509     GetShortPathName(szIgnoreStr, szLCIgnoreShortStr, sizeof(szLCIgnoreShortStr));
00510     CharLower(szLCIgnoreShortStr);
00511   }
00512 
00513   while(fgets(szLineRead, sizeof(szLineRead), ifp) != NULL)
00514   {
00515     lstrcpy(szLCLineRead, szLineRead);
00516     CharLower(szLCLineRead);
00517     if(!strstr(szLCLineRead, szLCIgnoreLongStr) && !strstr(szLCLineRead, szLCIgnoreShortStr))
00518       fputs(szLineRead, ofp);
00519     else
00520       bFoundIgnoreStr = TRUE;
00521   }
00522   fclose(ifp);
00523   fclose(ofp);
00524 
00525   return(bFoundIgnoreStr);
00526 }
00527 
00528 /* Function: RemoveDelayedDeleteFileEntries()
00529  *
00530  *       in: const char *aPathToMatch - path to match against
00531  *
00532  *  purpose: To remove windows registry entries (normally set by the uninstaller)
00533  *           that dictates what files to remove at system remove.
00534  *           The windows registry key that will be parsed is:
00535  *
00536  *             key : HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager
00537  *             name: PendingFileRenameOperations
00538  *
00539  *           This will not remove any entries that are set to be 'renamed'
00540  *           at system remove, only to be 'deleted'.
00541  *
00542  *           This function is multibyte safe.
00543  *
00544  *           To see what format the value of the var is in, look up the win32 API:
00545  *             MoveFileEx()
00546  */
00547 void RemoveDelayedDeleteFileEntries(const char *aPathToMatch)
00548 {
00549   HKEY  hkResult;
00550   DWORD dwErr;
00551   DWORD dwType = REG_NONE;
00552   DWORD oldMaxValueLen = 0;
00553   DWORD newMaxValueLen = 0;
00554   DWORD lenToEnd = 0;
00555   char  *multiStr = NULL;
00556   const char key[] = "SYSTEM\\CurrentControlSet\\Control\\Session Manager";
00557   const char name[] = "PendingFileRenameOperations";
00558   char  *pathToMatch;
00559   char  *lcName;
00560   char  *pName;
00561   char  *pRename;
00562   int   nameLen, renameLen;
00563 
00564   assert(aPathToMatch);
00565 
00566   /* if not NT systems (win2k, winXP) return */
00567   if (!(gSystemInfo.dwOSType & OS_NT))
00568     return;
00569 
00570   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ|KEY_WRITE, &hkResult) != ERROR_SUCCESS)
00571     return;
00572 
00573   dwErr = RegQueryValueEx(hkResult, name, 0, &dwType, NULL, &oldMaxValueLen);
00574   if (dwErr != ERROR_SUCCESS || oldMaxValueLen == 0 || dwType != REG_MULTI_SZ)
00575   {
00576     /* no value, no data, or wrong type */
00577     return;
00578   }
00579 
00580   multiStr = calloc(oldMaxValueLen, sizeof(BYTE));
00581   if (!multiStr)
00582     return;
00583 
00584   pathToMatch = strdup(aPathToMatch);
00585   if (!pathToMatch)
00586   {
00587       free(multiStr);
00588       return;
00589   }
00590 
00591   if (RegQueryValueEx(hkResult, name, 0, NULL, multiStr, &oldMaxValueLen) == ERROR_SUCCESS)
00592   {
00593       // The registry value consists of name/newname pairs of null-terminated
00594       // strings, with a final extra null termination. We're only interested
00595       // in files to be deleted, which are indicated by a null newname.
00596       CharLower(pathToMatch);
00597       lenToEnd = newMaxValueLen = oldMaxValueLen;
00598       pName = multiStr;
00599       while(*pName && lenToEnd > 0)
00600       {
00601           // find the locations and lengths of the current pair. Count the
00602           // nulls,  we need to know how much data to skip or move
00603           nameLen = strlen(pName) + 1;
00604           pRename = pName + nameLen;
00605           renameLen = strlen(pRename) + 1;
00606 
00607           // How much remains beyond the current pair
00608           lenToEnd -= (nameLen + renameLen);
00609 
00610           if (*pRename == '\0')
00611           {
00612               // No new name, it's a delete. Is it the one we want?
00613               lcName = strdup(pName);
00614               if (lcName)
00615               {
00616                   CharLower(lcName);
00617                   if (strstr(lcName, pathToMatch))
00618               {
00619                   // It's a match--
00620                   // delete this pair by moving the remainder on top
00621                   memmove(pName, pRename + renameLen, lenToEnd);
00622 
00623                   // update the total length to reflect the missing pair
00624                   newMaxValueLen -= (nameLen + renameLen);
00625 
00626                   // next pair is in place, continue w/out moving pName
00627                       free(lcName);
00628                   continue;
00629               }
00630                   free(lcName);
00631               }
00632           }
00633           // on to the next pair
00634           pName = pRename + renameLen;
00635       }
00636 
00637       if (newMaxValueLen != oldMaxValueLen)
00638       {
00639           // We've deleted something, save the changed data
00640           RegSetValueEx(hkResult, name, 0, REG_MULTI_SZ, multiStr, newMaxValueLen);
00641           RegFlushKey(hkResult);
00642       }
00643   }
00644 
00645   RegCloseKey(hkResult);
00646   free(multiStr);
00647   free(pathToMatch);
00648 }
00649 
00650 
00651 /* Looks for and removes the uninstaller from the Windows Registry
00652  * that is set to delete the uninstaller at the next restart of
00653  * Windows.  This key is set/created when the user does the following:
00654  *
00655  * 1) Runs the uninstaller from the previous version of the product.
00656  * 2) User does not reboot the OS and starts the installation of
00657  *    the next version of the product.
00658  *
00659  * This functions prevents the uninstaller from being deleted on a
00660  * system reboot after the user performs 2).
00661  */
00662 void ClearWinRegUninstallFileDeletion(void)
00663 {
00664   char  szLCUninstallFilenameLongBuf[MAX_BUF];
00665   char  szLCUninstallFilenameShortBuf[MAX_BUF];
00666   char  szWinInitFile[MAX_BUF];
00667   char  szTempInitFile[MAX_BUF];
00668   char  szWinDir[MAX_BUF];
00669 
00670   if(!GetWindowsDirectory(szWinDir, sizeof(szWinDir)))
00671     return;
00672 
00673   wsprintf(szLCUninstallFilenameLongBuf, "%s\\%s", szWinDir, sgProduct.szUninstallFilename);
00674   GetShortPathName(szLCUninstallFilenameLongBuf, szLCUninstallFilenameShortBuf, sizeof(szLCUninstallFilenameShortBuf));
00675 
00676   if(gSystemInfo.dwOSType & OS_NT)
00677   {
00678     RemoveDelayedDeleteFileEntries(szLCUninstallFilenameShortBuf);
00679   }
00680   else
00681   {
00682     /* OS type is win9x */
00683     wsprintf(szWinInitFile, "%s\\wininit.ini", szWinDir);
00684     wsprintf(szTempInitFile, "%s\\wininit.moz", szWinDir);
00685     if(FileExists(szWinInitFile))
00686     {
00687       if(UpdateFile(szWinInitFile, szTempInitFile, szLCUninstallFilenameLongBuf))
00688         CopyFile(szTempInitFile, szWinInitFile, FALSE);
00689 
00690       DeleteFile(szTempInitFile);
00691     }
00692   }
00693 }
00694 
00695 HRESULT Initialize(HINSTANCE hInstance)
00696 {
00697   char szBuf[MAX_BUF];
00698   char szCurrentProcessDir[MAX_BUF];
00699 
00700   bSDUserCanceled        = FALSE;
00701   hDlgMessage            = NULL;
00702 
00703   /* load strings from setup.exe */
00704   if(NS_LoadStringAlloc(hInstance, IDS_ERROR_GLOBALALLOC, &szEGlobalAlloc, MAX_BUF))
00705     return(1);
00706   if(NS_LoadStringAlloc(hInstance, IDS_ERROR_STRING_LOAD, &szEStringLoad,  MAX_BUF))
00707     return(1);
00708   if(NS_LoadStringAlloc(hInstance, IDS_ERROR_DLL_LOAD,    &szEDllLoad,     MAX_BUF))
00709     return(1);
00710   if(NS_LoadStringAlloc(hInstance, IDS_ERROR_STRING_NULL, &szEStringNull,  MAX_BUF))
00711     return(1);
00712   if(NS_LoadStringAlloc(hInstance, IDS_ERROR_OUTOFMEMORY, &szEOutOfMemory, MAX_BUF))
00713     return(1);
00714 
00715   GetModuleFileName(NULL, szBuf, sizeof(szBuf));
00716   ParsePath(szBuf, szCurrentProcessDir,
00717             sizeof(szCurrentProcessDir),
00718             FALSE,
00719             PP_PATH_ONLY);
00720   hAccelTable = LoadAccelerators(hInstance, CLASS_NAME_SETUP_DLG);
00721 
00722   if((hSetupRscInst = LoadLibraryEx("Setuprsc.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL)
00723   {
00724     char szFullFilename[MAX_BUF];
00725 
00726     lstrcpy(szFullFilename, szCurrentProcessDir);
00727     AppendBackSlash(szFullFilename, sizeof(szFullFilename));
00728     lstrcat(szFullFilename, "Setuprsc.dll");
00729     if((hSetupRscInst = LoadLibraryEx(szFullFilename, NULL, 0)) == NULL)
00730     {
00731       wsprintf(szBuf, szEDllLoad, szFullFilename);
00732       PrintError(szBuf, ERROR_CODE_HIDE);
00733       return(WIZ_ERROR_LOADING_RESOURCE_LIB);
00734     }
00735   }
00736 
00737   dwWizardState          = DLG_NONE;
00738   dwTempSetupType        = dwWizardState;
00739   siComponents           = NULL;
00740   bCreateDestinationDir  = FALSE;
00741   bReboot                = FALSE;
00742   gdwUpgradeValue        = UG_NONE;
00743   gdwSiteSelectorStatus  = SS_SHOW;
00744   gbILUseTemp            = TRUE;
00745   gbIgnoreRunAppX        = FALSE;
00746   gbIgnoreProgramFolderX = FALSE;
00747 
00748   if((szSetupDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
00749     return(1);
00750   lstrcpy(szSetupDir, szCurrentProcessDir);
00751 
00752   if((szTempDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
00753     return(1);
00754 
00755   if((szOSTempDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
00756     return(1);
00757 
00758   if((szProxyDLLPath = NS_GlobalAlloc(MAX_BUF)) == NULL)
00759     return(1);
00760 
00761   if((szFileIniConfig = NS_GlobalAlloc(MAX_BUF)) == NULL)
00762     return(1);
00763 
00764   if((szFileIniInstall = NS_GlobalAlloc(MAX_BUF)) == NULL)
00765     return(1);
00766 
00767   // determine the system's TEMP path
00768   if(GetTempPath(MAX_BUF, szTempDir) == 0)
00769   {
00770     if(GetWindowsDirectory(szTempDir, MAX_BUF) == 0)
00771     {
00772       char szEGetWinDirFailed[MAX_BUF];
00773 
00774       if(GetPrivateProfileString("Messages", "ERROR_GET_WINDOWS_DIRECTORY_FAILED", "", szEGetWinDirFailed, sizeof(szEGetWinDirFailed), szFileIniInstall))
00775         PrintError(szEGetWinDirFailed, ERROR_CODE_SHOW);
00776 
00777       return(1);
00778     }
00779 
00780     AppendBackSlash(szTempDir, MAX_BUF);
00781     lstrcat(szTempDir, "TEMP");
00782   }
00783   lstrcpy(szOSTempDir, szTempDir);
00784   AppendBackSlash(szTempDir, MAX_BUF);
00785   lstrcat(szTempDir, WIZ_TEMP_DIR);
00786 
00787   /*  if multiple installer instances are allowed; 
00788       each instance requires a unique temp directory
00789    */
00790   if(gbAllowMultipleInstalls)
00791   {
00792     DWORD dwLen = lstrlen(szTempDir);
00793 
00794     if (strncmp(szSetupDir, szTempDir, dwLen) == 0)
00795     {
00796       lstrcpy(szTempDir, szSetupDir);
00797     }
00798     else
00799     {
00800       int i;
00801       for(i = 1; i <= 100 && (FileExists(szTempDir) != FALSE); i++)
00802       {
00803         itoa(i, (szTempDir + dwLen), 10);
00804       }
00805     
00806       if (FileExists(szTempDir) != FALSE)
00807       {
00808         MessageBox(hWndMain, "Cannot create temp directory", NULL, MB_OK | MB_ICONEXCLAMATION);
00809         exit(1);
00810       }
00811     }
00812   }
00813   else
00814   {
00815     // we're not running in mmi mode (allow multiple instances of installer
00816     // to run at the same time), we should look for and remove the dirs
00817     // that are created in the mmi mode.
00818     DWORD dwLen;
00819     char tempDirToCleanup[MAX_BUF];
00820     int i = 1;
00821 
00822     lstrcpy(tempDirToCleanup, szTempDir);
00823     dwLen = lstrlen(tempDirToCleanup);
00824     itoa(i, (tempDirToCleanup + dwLen), 10);
00825     for(i = 2; i <= 100 && (FileExists(tempDirToCleanup)); i++)
00826     {
00827       DirectoryRemove(tempDirToCleanup, TRUE);
00828       itoa(i, (tempDirToCleanup + dwLen), 10);
00829     }
00830   }
00831 
00832   if(!FileExists(szTempDir))
00833   {
00834     AppendBackSlash(szTempDir, MAX_BUF);
00835     CreateDirectoriesAll(szTempDir, DO_NOT_ADD_TO_UNINSTALL_LOG);
00836     if(!FileExists(szTempDir))
00837     {
00838       char szECreateTempDir[MAX_BUF];
00839 
00840       if(GetPrivateProfileString("Messages", "ERROR_CREATE_TEMP_DIR", "", szECreateTempDir, sizeof(szECreateTempDir), szFileIniInstall))
00841       {
00842         wsprintf(szBuf, szECreateTempDir, szTempDir);
00843         PrintError(szBuf, ERROR_CODE_HIDE);
00844       }
00845       return(1);
00846     }
00847     RemoveBackSlash(szTempDir);
00848   }
00849 
00850   /* Check if we need to load GRE App installer proxy DLL;
00851      this DLL lives in the Windows temp directory when the 
00852      external GRE app installer is running. If found, it 
00853      will be loaded and fed with incremental progress updates.
00854   */  
00855 
00856   GetTempPath(MAX_BUF, szProxyDLLPath);
00857   AppendBackSlash(szProxyDLLPath, MAX_BUF);
00858   strcat(szProxyDLLPath, GRE_APP_INSTALLER_PROXY_DLL);
00859   
00860   if (FileExists(szProxyDLLPath) != FALSE)
00861     hGREAppInstallerProxyDLL = LoadLibrary(szProxyDLLPath);
00862   
00863   if (hGREAppInstallerProxyDLL != NULL)
00864     lpfnProgressUpd = (LPFNDLLFUNC) GetProcAddress(hGREAppInstallerProxyDLL, GRE_PROXY_UPD_FUNC);
00865                              
00866 
00867   hbmpBoxChecked         = LoadBitmap(hSetupRscInst, MAKEINTRESOURCE(IDB_BOX_CHECKED));
00868   hbmpBoxCheckedDisabled = LoadBitmap(hSetupRscInst, MAKEINTRESOURCE(IDB_BOX_CHECKED_DISABLED));
00869   hbmpBoxUnChecked       = LoadBitmap(hSetupRscInst, MAKEINTRESOURCE(IDB_BOX_UNCHECKED));
00870 
00871   DeleteIdiGetConfigIni();
00872   bIdiArchivesExists = DeleteIdiGetArchives();
00873   DeleteIdiGetRedirect();
00874   DeleteInstallLogFile(FILE_INSTALL_LOG);
00875   DeleteInstallLogFile(FILE_INSTALL_STATUS_LOG);
00876   LogISTime(W_START);
00877   DetermineOSVersionEx();
00878 
00879   SystemParametersInfo(SPI_GETSCREENREADER, 0, &(gSystemInfo.bScreenReader), 0);
00880 
00881   return(0);
00882 }
00883 
00884 /* Function to remove quotes from a string */
00885 void RemoveQuotes(LPSTR lpszSrc, LPSTR lpszDest, int iDestSize)
00886 {
00887   char *lpszBegin;
00888 
00889   if(lstrlen(lpszSrc) > iDestSize)
00890     return;
00891 
00892   if(*lpszSrc == '\"')
00893     lpszBegin = &lpszSrc[1];
00894   else
00895     lpszBegin = lpszSrc;
00896 
00897   lstrcpy(lpszDest, lpszBegin);
00898 
00899   if(lpszDest[lstrlen(lpszDest) - 1] == '\"')
00900     lpszDest[lstrlen(lpszDest) - 1] = '\0';
00901 }
00902 
00903 /* Function to copy strings safely.
00904  *   returns the amount of memory required (including NULL byte) if there's not enough
00905  *   else, it returns 0 for success.
00906  */
00907 int MozCopyStr(LPSTR szSrc, LPSTR szDest, DWORD dwDestBufSize)
00908 {
00909   DWORD length;
00910 
00911   assert(szSrc);
00912   assert(szDest);
00913 
00914   length = lstrlen(szSrc) + 1;
00915   strncpy(szDest, szSrc, dwDestBufSize);
00916   if(length > dwDestBufSize)
00917   {
00918     szDest[dwDestBufSize - 1] = '\0';
00919     return(length);
00920   }
00921   return(0);
00922 }
00923 
00924 /* Function to locate the first non space character in a string,
00925  * and return a pointer to it. */
00926 LPSTR GetFirstNonSpace(LPSTR lpszString)
00927 {
00928   int   i;
00929   int   iStrLength;
00930 
00931   iStrLength = lstrlen(lpszString);
00932 
00933   for(i = 0; i < iStrLength; i++)
00934   {
00935     if(!isspace(lpszString[i]))
00936       return(&lpszString[i]);
00937   }
00938 
00939   return(NULL);
00940 }
00941 
00942 /* Function to locate the first character c in lpszString,
00943  * and return a pointer to it. */
00944 LPSTR MozStrChar(LPSTR lpszString, char c)
00945 {
00946   char* p = lpszString;
00947 
00948   if(!p)
00949     return NULL;
00950 
00951   while (*p && (*p != c))
00952     p = CharNext(p);
00953 
00954   if (*p == '\0')  // null means end of string
00955     return NULL;
00956 
00957   return p;
00958 }
00959 
00960 /* Function to return the argument count given a command line input
00961  * format string */
00962 int GetArgC(LPSTR lpszCommandLine)
00963 {
00964   int   i;
00965   int   iArgCount;
00966   int   iStrLength;
00967   LPSTR lpszBeginStr;
00968   BOOL  bFoundQuote;
00969   BOOL  bFoundSpace;
00970 
00971   iArgCount    = 0;
00972   lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
00973 
00974   if(lpszBeginStr == NULL)
00975     return(iArgCount);
00976 
00977   iStrLength   = lstrlen(lpszBeginStr);
00978   bFoundQuote  = FALSE;
00979   bFoundSpace  = TRUE;
00980 
00981   for(i = 0; i < iStrLength; i++)
00982   {
00983     if(lpszCommandLine[i] == '\"')
00984     {
00985       if(bFoundQuote == FALSE)
00986       {
00987         ++iArgCount;
00988         bFoundQuote = TRUE;
00989       }
00990       else
00991       {
00992         bFoundQuote = FALSE;
00993       }
00994     }
00995     else if(bFoundQuote == FALSE)
00996     {
00997       if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
00998       {
00999         ++iArgCount;
01000         bFoundSpace = FALSE;
01001       }
01002       else if(isspace(lpszCommandLine[i]))
01003       {
01004         bFoundSpace = TRUE;
01005       }
01006     }
01007   }
01008 
01009   return(iArgCount);
01010 }
01011 
01012 /* Function to return a specific argument parameter from a given command line input
01013  * format string. */
01014 LPSTR GetArgV(LPSTR lpszCommandLine, int iIndex, LPSTR lpszDest, int iDestSize)
01015 {
01016   int   i;
01017   int   j;
01018   int   iArgCount;
01019   int   iStrLength;
01020   LPSTR lpszBeginStr;
01021   LPSTR lpszDestTemp;
01022   BOOL  bFoundQuote;
01023   BOOL  bFoundSpace;
01024 
01025   iArgCount    = 0;
01026   lpszBeginStr = GetFirstNonSpace(lpszCommandLine);
01027 
01028   if(lpszBeginStr == NULL)
01029     return(NULL);
01030 
01031   lpszDestTemp = (char *)calloc(iDestSize, sizeof(char));
01032   if(lpszDestTemp == NULL)
01033   {
01034     PrintError("Out of memory", ERROR_CODE_HIDE);
01035     exit(1);
01036   }
01037 
01038   ZeroMemory(lpszDest, iDestSize);
01039   iStrLength    = lstrlen(lpszBeginStr);
01040   bFoundQuote   = FALSE;
01041   bFoundSpace   = TRUE;
01042   j             = 0;
01043 
01044   for(i = 0; i < iStrLength; i++)
01045   {
01046     if(lpszCommandLine[i] == '\"')
01047     {
01048       if(bFoundQuote == FALSE)
01049       {
01050         ++iArgCount;
01051         bFoundQuote = TRUE;
01052       }
01053       else
01054       {
01055         bFoundQuote = FALSE;
01056       }
01057     }
01058     else if(bFoundQuote == FALSE)
01059     {
01060       if(!isspace(lpszCommandLine[i]) && (bFoundSpace == TRUE))
01061       {
01062         ++iArgCount;
01063         bFoundSpace = FALSE;
01064       }
01065       else if(isspace(lpszCommandLine[i]))
01066       {
01067         bFoundSpace = TRUE;
01068       }
01069     }
01070 
01071     if((iIndex == (iArgCount - 1)) &&
01072       ((bFoundQuote == TRUE) || (bFoundSpace == FALSE) ||
01073       ((bFoundQuote == FALSE) && (lpszCommandLine[i] == '\"'))))
01074     {
01075       if(j < iDestSize)
01076       {
01077         lpszDestTemp[j] = lpszCommandLine[i];
01078         ++j;
01079       }
01080       else
01081       {
01082         lpszDestTemp[j] = '\0';
01083       }
01084     }
01085   }
01086 
01087   RemoveQuotes(lpszDestTemp, lpszDest, iDestSize);
01088   free(lpszDestTemp);
01089   return(lpszDest);
01090 }
01091 
01092 BOOL IsInArchivesLst(siC *siCObject, BOOL bModify)
01093 {
01094   char *szBufPtr;
01095   char szBuf[MAX_BUF];
01096   char szArchiveLstFile[MAX_BUF_MEDIUM];
01097   BOOL bRet = FALSE;
01098 
01099   lstrcpy(szArchiveLstFile, szTempDir);
01100   AppendBackSlash(szArchiveLstFile, sizeof(szArchiveLstFile));
01101   lstrcat(szArchiveLstFile, "Archive.lst");
01102   GetPrivateProfileString("Archives", NULL, "", szBuf, sizeof(szBuf), szArchiveLstFile);
01103   if(*szBuf != '\0')
01104   {
01105     szBufPtr = szBuf;
01106     while(*szBufPtr != '\0')
01107     {
01108       if(lstrcmpi(siCObject->szArchiveName, szBufPtr) == 0)
01109       {
01110         if(bModify)
01111         {
01112           /* jar file found.  Unset attribute to download from the net */
01113           siCObject->dwAttributes &= ~SIC_DOWNLOAD_REQUIRED;
01114           /* save the path of where jar was found at */
01115           lstrcpy(siCObject->szArchivePath, szTempDir);
01116           AppendBackSlash(siCObject->szArchivePath, MAX_BUF);
01117         }
01118         bRet = TRUE;
01119 
01120         /* found what we're looking for.  No need to continue */
01121         break;
01122       }
01123       szBufPtr += lstrlen(szBufPtr) + 1;
01124     }
01125   }
01126   return(bRet);
01127 }
01128 
01129 HRESULT ParseSetupIni()
01130 {
01131   char szBuf[MAX_BUF];
01132   char szFileIniSetup[MAX_BUF];
01133   char szFileIdiGetConfigIni[MAX_BUF];
01134 
01135   lstrcpy(szFileIdiGetConfigIni, szTempDir);
01136   AppendBackSlash(szFileIdiGetConfigIni, sizeof(szFileIdiGetConfigIni));
01137   lstrcat(szFileIdiGetConfigIni, FILE_IDI_GETCONFIGINI);
01138 
01139   lstrcpy(szFileIniSetup, szSetupDir);
01140   AppendBackSlash(szFileIniSetup, sizeof(szFileIniSetup));
01141   lstrcat(szFileIniSetup, FILE_INI_SETUP);
01142 
01143   CopyFile(szFileIniSetup, szFileIdiGetConfigIni, FALSE);
01144 
01145   if(!FileExists(szFileIdiGetConfigIni))
01146   {
01147     char szEFileNotFound[MAX_BUF];
01148 
01149     if(GetPrivateProfileString("Messages", "ERROR_FILE_NOT_FOUND", "", szEFileNotFound, sizeof(szEFileNotFound), szFileIniInstall))
01150     {
01151       wsprintf(szBuf, szEFileNotFound, szFileIdiGetConfigIni);
01152       PrintError(szBuf, ERROR_CODE_HIDE);
01153     }
01154     return(1);
01155   }
01156 
01157   return(0);
01158 }
01159 
01160 HRESULT GetConfigIni()
01161 {
01162   char    szFileIniTempDir[MAX_BUF];
01163   char    szFileIniSetupDir[MAX_BUF];
01164   char    szMsgRetrieveConfigIni[MAX_BUF];
01165   char    szBuf[MAX_BUF];
01166   HRESULT hResult = 0;
01167 
01168   if(!GetPrivateProfileString("Messages", "MSG_RETRIEVE_CONFIGINI", "", szMsgRetrieveConfigIni, sizeof(szMsgRetrieveConfigIni), szFileIniInstall))
01169     return(1);
01170     
01171   lstrcpy(szFileIniTempDir, szTempDir);
01172   AppendBackSlash(szFileIniTempDir, sizeof(szFileIniTempDir));
01173   lstrcat(szFileIniTempDir, FILE_INI_CONFIG);
01174 
01175   /* set default value for szFileIniConfig here */
01176   lstrcpy(szFileIniConfig, szFileIniTempDir);
01177 
01178   lstrcpy(szFileIniSetupDir, szSetupDir);
01179   AppendBackSlash(szFileIniSetupDir, sizeof(szFileIniSetupDir));
01180   lstrcat(szFileIniSetupDir, FILE_INI_CONFIG);
01181 
01182   /* if config.ini exists, then use it, else download config.ini from the net */
01183   if(!FileExists(szFileIniTempDir))
01184   {
01185     if(FileExists(szFileIniSetupDir))
01186     {
01187       lstrcpy(szFileIniConfig, szFileIniSetupDir);
01188       hResult = 0;
01189     }
01190     else
01191     {
01192       char szEFileNotFound[MAX_BUF];
01193 
01194     if(GetPrivateProfileString("Messages", "ERROR_FILE_NOT_FOUND", "", szEFileNotFound, sizeof(szEFileNotFound), szFileIniInstall))
01195       {
01196         wsprintf(szBuf, szEFileNotFound, FILE_INI_CONFIG);
01197         PrintError(szBuf, ERROR_CODE_HIDE);
01198       }
01199       hResult = 1;
01200     }
01201   }
01202   else
01203     hResult = 0;
01204 
01205   return(hResult);
01206 }
01207 
01208 HRESULT GetInstallIni()
01209 {
01210   char    szFileIniTempDir[MAX_BUF];
01211   char    szFileIniSetupDir[MAX_BUF];
01212   char    szMsgRetrieveInstallIni[MAX_BUF];
01213   char    szBuf[MAX_BUF];
01214   HRESULT hResult = 0;
01215 
01216   if(NS_LoadString(hSetupRscInst, IDS_MSG_RETRIEVE_INSTALLINI, szMsgRetrieveInstallIni, MAX_BUF) != WIZ_OK)
01217     return(1);
01218     
01219   lstrcpy(szFileIniTempDir, szTempDir);
01220   AppendBackSlash(szFileIniTempDir, sizeof(szFileIniTempDir));
01221   lstrcat(szFileIniTempDir, FILE_INI_INSTALL);
01222 
01223   /* set default value for szFileIniInstall here */
01224   lstrcpy(szFileIniInstall, szFileIniTempDir);
01225 
01226   lstrcpy(szFileIniSetupDir, szSetupDir);
01227   AppendBackSlash(szFileIniSetupDir, sizeof(szFileIniSetupDir));
01228   lstrcat(szFileIniSetupDir, FILE_INI_INSTALL);
01229 
01230   /* if install.ini exists, then use it, else download install.ini from the net */
01231   if(!FileExists(szFileIniTempDir))
01232   {
01233     if(FileExists(szFileIniSetupDir))
01234     {
01235       lstrcpy(szFileIniInstall, szFileIniSetupDir);
01236       hResult = 0;
01237     }
01238     else
01239     {
01240       char szEFileNotFound[MAX_BUF];
01241 
01242       if(NS_LoadString(hSetupRscInst, IDS_ERROR_FILE_NOT_FOUND, szEFileNotFound, MAX_BUF) == WIZ_OK)
01243       {
01244         wsprintf(szBuf, szEFileNotFound, FILE_INI_INSTALL);
01245         PrintError(szBuf, ERROR_CODE_HIDE);
01246       }
01247       hResult = 1;
01248     }
01249   }
01250   else
01251     hResult = 0;
01252 
01253   return(hResult);
01254 }
01255 
01256 int LocateJar(siC *siCObject, LPSTR szPath, int dwPathSize, BOOL bIncludeTempDir)
01257 {
01258   BOOL bRet;
01259   char szBuf[MAX_BUF * 2];
01260   char szSEADirTemp[MAX_BUF];
01261   char szSetupDirTemp[MAX_BUF];
01262   char szTempDirTemp[MAX_BUF];
01263 
01264   /* initialize default behavior */
01265   bRet = AP_NOT_FOUND;
01266   if(szPath != NULL)
01267     ZeroMemory(szPath, dwPathSize);
01268   siCObject->dwAttributes |= SIC_DOWNLOAD_REQUIRED;
01269 
01270   lstrcpy(szSEADirTemp, sgProduct.szAlternateArchiveSearchPath);
01271   AppendBackSlash(szSEADirTemp, sizeof(szSEADirTemp));
01272   lstrcat(szSEADirTemp, siCObject->szArchiveName);
01273 
01274   /* XXX_QUICK_FIX 
01275    * checking sgProduct.szAlternateArchiveSearchPath for empty string
01276    * should be done prior to AppendBackSlash() above.
01277    * This is a quick fix for the time frame that we are currently in. */
01278   if((*sgProduct.szAlternateArchiveSearchPath != '\0') && (FileExists(szSEADirTemp)))
01279   {
01280     /* jar file found.  Unset attribute to download from the net */
01281     siCObject->dwAttributes &= ~SIC_DOWNLOAD_REQUIRED;
01282     /* save the path of where jar was found at */
01283     lstrcpy(siCObject->szArchivePath, sgProduct.szAlternateArchiveSearchPath);
01284     AppendBackSlash(siCObject->szArchivePath, MAX_BUF);
01285     bRet = AP_ALTERNATE_PATH;
01286 
01287     /* save path where archive is located */
01288     if((szPath != NULL) && (lstrlen(sgProduct.szAlternateArchiveSearchPath) < dwPathSize))
01289       lstrcpy(szPath, sgProduct.szAlternateArchiveSearchPath);
01290   }
01291   else
01292   {
01293     lstrcpy(szSetupDirTemp, szSetupDir);
01294     AppendBackSlash(szSetupDirTemp, sizeof(szSetupDirTemp));
01295 
01296     lstrcpy(szTempDirTemp,  szTempDir);
01297     AppendBackSlash(szTempDirTemp, sizeof(szTempDirTemp));
01298 
01299     if(lstrcmpi(szTempDirTemp, szSetupDirTemp) == 0)
01300     {
01301       /* check the temp dir for the .xpi file */
01302       lstrcpy(szBuf, szTempDirTemp);
01303       AppendBackSlash(szBuf, sizeof(szBuf));
01304       lstrcat(szBuf, siCObject->szArchiveName);
01305 
01306       if(FileExists(szBuf))
01307       {
01308         if(bIncludeTempDir == TRUE)
01309         {
01310           /* jar file found.  Unset attribute to download from the net */
01311           siCObject->dwAttributes &= ~SIC_DOWNLOAD_REQUIRED;
01312           /* save the path of where jar was found at */
01313           lstrcpy(siCObject->szArchivePath, szTempDirTemp);
01314           AppendBackSlash(siCObject->szArchivePath, MAX_BUF);
01315           bRet = AP_TEMP_PATH;
01316         }
01317 
01318         /* if the archive name is in the archive.lst file, then it was uncompressed
01319          * by the self extracting .exe file.  Assume that the .xpi file exists.
01320          * This is a safe assumption because the self extracting.exe creates the
01321          * archive.lst with what it uncompresses everytime it is run. */
01322         if(IsInArchivesLst(siCObject, TRUE))
01323           bRet = AP_SETUP_PATH;
01324 
01325         /* save path where archive is located */
01326         if((szPath != NULL) && (lstrlen(szTempDirTemp) < dwPathSize))
01327           lstrcpy(szPath, szTempDirTemp);
01328       }
01329     }
01330     else
01331     {
01332       /* check the setup dir for the .xpi file */
01333       lstrcpy(szBuf, szSetupDirTemp);
01334       AppendBackSlash(szBuf, sizeof(szBuf));
01335       lstrcat(szBuf, siCObject->szArchiveName);
01336 
01337       if(FileExists(szBuf))
01338       {
01339         /* jar file found.  Unset attribute to download from the net */
01340         siCObject->dwAttributes &= ~SIC_DOWNLOAD_REQUIRED;
01341         /* save the path of where jar was found at */
01342         lstrcpy(siCObject->szArchivePath, szSetupDirTemp);
01343         AppendBackSlash(siCObject->szArchivePath, MAX_BUF);
01344         bRet = AP_SETUP_PATH;
01345 
01346         /* save path where archive is located */
01347         if((szPath != NULL) && (lstrlen(sgProduct.szAlternateArchiveSearchPath) < dwPathSize))
01348           lstrcpy(szPath, szSetupDirTemp);
01349       }
01350       else
01351       {
01352         /* check the ns_temp dir for the .xpi file */
01353         lstrcpy(szBuf, szTempDirTemp);
01354         AppendBackSlash(szBuf, sizeof(szBuf));
01355         lstrcat(szBuf, siCObject->szArchiveName);
01356 
01357         if(FileExists(szBuf))
01358         {
01359           if(bIncludeTempDir == TRUE)
01360           {
01361             /* jar file found.  Unset attribute to download from the net */
01362             siCObject->dwAttributes &= ~SIC_DOWNLOAD_REQUIRED;
01363             /* save the path of where jar was found at */
01364             lstrcpy(siCObject->szArchivePath, szTempDirTemp);
01365             AppendBackSlash(siCObject->szArchivePath, MAX_BUF);
01366             bRet = AP_TEMP_PATH;
01367           }
01368 
01369           /* save path where archive is located */
01370           if((szPath != NULL) && (lstrlen(sgProduct.szAlternateArchiveSearchPath) < dwPathSize))
01371             lstrcpy(szPath, szTempDirTemp);
01372         }
01373       }
01374     }
01375   }
01376   return(bRet);
01377 }
01378 
01379 void SwapFTPAndHTTP(char *szInUrl, DWORD dwInUrlSize)
01380 {
01381   char szTmpBuf[MAX_BUF];
01382   char *ptr       = NULL;
01383   char szFtp[]    = "ftp://";
01384   char szHttp[]   = "http://";
01385 
01386   if((!szInUrl) || !diAdditionalOptions.bUseProtocolSettings)
01387     return;
01388 
01389   ZeroMemory(szTmpBuf, sizeof(szTmpBuf));
01390   switch(diAdditionalOptions.dwUseProtocol)
01391   {
01392     case UP_HTTP:
01393       if((strncmp(szInUrl, szFtp, FTPSTR_LEN) == 0) &&
01394          ((int)dwInUrlSize > lstrlen(szInUrl) + 1))
01395       {
01396         ptr = szInUrl + FTPSTR_LEN;
01397         memmove(ptr + 1, ptr, lstrlen(ptr) + 1);
01398         memcpy(szInUrl, szHttp, HTTPSTR_LEN);
01399       }
01400       break;
01401 
01402     case UP_FTP:
01403     default:
01404       if((strncmp(szInUrl, szHttp, HTTPSTR_LEN) == 0) &&
01405          ((int)dwInUrlSize > lstrlen(szInUrl) + 1))
01406       {
01407         ptr = szInUrl + HTTPSTR_LEN;
01408         memmove(ptr - 1, ptr, lstrlen(ptr) + 1);
01409         memcpy(szInUrl, szFtp, FTPSTR_LEN);
01410       }
01411       break;
01412   }
01413 }
01414 
01415 int UpdateIdiFile(char  *szPartialUrl,
01416                   DWORD dwPartialUrlBufSize,
01417                   siC   *siCObject,
01418                   char  *szSection,
01419                   char  *szKey,
01420                   char  *szFileIdiGetArchives)
01421 {
01422   char      szUrl[MAX_BUF];
01423   char      szBuf[MAX_BUF];
01424   char      szBufTemp[MAX_BUF];
01425 
01426   SwapFTPAndHTTP(szPartialUrl, dwPartialUrlBufSize);
01427   RemoveSlash(szPartialUrl);
01428   wsprintf(szUrl, "%s/%s", szPartialUrl, siCObject->szArchiveName);
01429   if(WritePrivateProfileString(szSection,
01430                                szKey,
01431                                szUrl,
01432                                szFileIdiGetArchives) == 0)
01433   {
01434     char szEWPPS[MAX_BUF];
01435 
01436     if(GetPrivateProfileString("Messages", "ERROR_WRITEPRIVATEPROFILESTRING", "", szEWPPS, sizeof(szEWPPS), szFileIniInstall))
01437     {
01438       wsprintf(szBufTemp,
01439                "%s\n    [%s]\n    url=%s",
01440                szFileIdiGetArchives,
01441                szSection,
01442                szUrl);
01443       wsprintf(szBuf, szEWPPS, szBufTemp);
01444       PrintError(szBuf, ERROR_CODE_SHOW);
01445     }
01446     return(1);
01447   }
01448   return(0);
01449 }
01450 
01451 HRESULT AddArchiveToIdiFile(siC *siCObject,
01452                             char *szSection,
01453                             char *szFileIdiGetArchives)
01454 {
01455   char      szFile[MAX_BUF];
01456   char      szBuf[MAX_BUF];
01457   char      szUrl[MAX_BUF];
01458   char      szIdentifier[MAX_BUF];
01459   char      szArchiveSize[MAX_ITOA];
01460   char      szKey[MAX_BUF_TINY];
01461   int       iIndex = 0;
01462   ssi       *ssiSiteSelectorTemp;
01463 
01464   WritePrivateProfileString(szSection,
01465                             "desc",
01466                             siCObject->szDescriptionShort,
01467                             szFileIdiGetArchives);
01468   _ui64toa(siCObject->ullInstallSizeArchive, szArchiveSize, 10);
01469   WritePrivateProfileString(szSection,
01470                             "size",
01471                             szArchiveSize,
01472                             szFileIdiGetArchives);
01473   itoa(siCObject->dwAttributes & SIC_IGNORE_DOWNLOAD_ERROR, szBuf, 10);
01474   WritePrivateProfileString(szSection,
01475                             "Ignore File Network Error",
01476                             szBuf,
01477                             szFileIdiGetArchives);
01478 
01479   lstrcpy(szFile, szTempDir);
01480   AppendBackSlash(szFile, sizeof(szFile));
01481   lstrcat(szFile, FILE_INI_REDIRECT);
01482 
01483   ZeroMemory(szIdentifier, sizeof(szIdentifier));
01484   ssiSiteSelectorTemp = SsiGetNode(szSiteSelectorDescription);
01485 
01486   GetPrivateProfileString("Redirect",
01487                           "Status",
01488                           "",
01489                           szBuf,
01490                           sizeof(szBuf),
01491                           szFileIniConfig);
01492   if(lstrcmpi(szBuf, "ENABLED") != 0)
01493   {
01494     /* redirect.ini is *not* enabled, so use the url from the
01495      * config.ini's [Site Selector] section */
01496     if(*ssiSiteSelectorTemp->szDomain != '\0')
01497     {
01498       wsprintf(szKey, "url%d", iIndex);
01499       lstrcpy(szUrl, ssiSiteSelectorTemp->szDomain);
01500       UpdateIdiFile(szUrl, sizeof(szUrl), siCObject, szSection, szKey, szFileIdiGetArchives);
01501       ++iIndex;
01502     }
01503 
01504     /* use the url from the config.ini's [General] section as well */
01505     GetPrivateProfileString("General",
01506                             "url",
01507                             "",
01508                             szUrl,
01509                             sizeof(szUrl),
01510                             szFileIniConfig);
01511     if(*szUrl != 0)
01512     {
01513       wsprintf(szKey, "url%d", iIndex);
01514       UpdateIdiFile(szUrl, sizeof(szUrl), siCObject, szSection, szKey, szFileIdiGetArchives);
01515     }
01516   }
01517   else if(FileExists(szFile))
01518   {
01519     /* redirect.ini is enabled *and* it exists */
01520     GetPrivateProfileString("Site Selector",
01521                             ssiSiteSelectorTemp->szIdentifier,
01522                             "",
01523                             szUrl,
01524                             sizeof(szUrl),
01525                             szFile);
01526     if(*szUrl != '\0')
01527     {
01528       wsprintf(szKey, "url%d", iIndex);
01529       UpdateIdiFile(szUrl, sizeof(szUrl), siCObject, szSection, szKey, szFileIdiGetArchives);
01530       ++iIndex;
01531     }
01532 
01533     /* use the url from the config.ini's [General] section as well */
01534     GetPrivateProfileString("General",
01535                             "url",
01536                             "",
01537                             szUrl,
01538                             sizeof(szUrl),
01539                             szFileIniConfig);
01540     if(*szUrl != 0)
01541     {
01542       wsprintf(szKey, "url%d", iIndex);
01543       UpdateIdiFile(szUrl, sizeof(szUrl), siCObject, szSection, szKey, szFileIdiGetArchives);
01544     }
01545   }
01546   else
01547   {
01548     /* redirect.ini is enabled, but the file does not exist,
01549      * so fail over to the url from the config.ini's [General] section */
01550     GetPrivateProfileString("General",
01551                             "url",
01552                             "",
01553                             szUrl,
01554                             sizeof(szUrl),
01555                             szFileIniConfig);
01556     if(*szUrl != 0)
01557     {
01558       wsprintf(szKey, "url%d", iIndex);
01559       UpdateIdiFile(szUrl, sizeof(szUrl), siCObject, szSection, szKey, szFileIdiGetArchives);
01560     }
01561   }
01562 
01563   return(0);
01564 }
01565 
01566 void SetSetupRunMode(LPSTR szMode)
01567 {
01568   /* Check to see if mode has already been set.  If so,
01569    * then do not override it.
01570    * We don't want to override this value because it could have been
01571    * set via the command line argument as opposed to the config.ini
01572    * having been parse.  Command line arguments take precedence.
01573    */
01574   if(sgProduct.mode != NOT_SET)
01575     return;
01576 
01577   if(lstrcmpi(szMode, "NORMAL") == 0)
01578     sgProduct.mode = NORMAL;
01579   if(lstrcmpi(szMode, "AUTO") == 0)
01580     sgProduct.mode = AUTO;
01581   if(lstrcmpi(szMode, "SILENT") == 0)
01582     sgProduct.mode = SILENT;
01583 }
01584 
01585 BOOL CheckForArchiveExtension(LPSTR szFile)
01586 {
01587   int  i;
01588   BOOL bRv = FALSE;
01589   char szExtension[MAX_BUF_TINY];
01590 
01591   /* if there is no extension in szFile, szExtension will be zero'ed out */
01592   ParsePath(szFile, szExtension, sizeof(szExtension), FALSE, PP_EXTENSION_ONLY);
01593   i = 0;
01594   while(*ArchiveExtensions[i] != '\0')
01595   {
01596     if(lstrcmpi(szExtension, ArchiveExtensions[i]) == 0)
01597     {
01598       bRv = TRUE;
01599       break;
01600     }
01601 
01602     ++i;
01603   }
01604   return(bRv);
01605 }
01606 
01607 long RetrieveRedirectFile()
01608 {
01609   long      lResult;
01610   char      szBuf[MAX_BUF];
01611   char      szBufUrl[MAX_BUF];
01612   char      szBufTemp[MAX_BUF];
01613   char      szIndex0[MAX_BUF];
01614   char      szFileIdiGetRedirect[MAX_BUF];
01615   char      szFileIniRedirect[MAX_BUF];
01616   ssi       *ssiSiteSelectorTemp;
01617 
01618   if(GetTotalArchivesToDownload() == 0)
01619     return(0);
01620 
01621   lstrcpy(szFileIniRedirect, szTempDir);
01622   AppendBackSlash(szFileIniRedirect, sizeof(szFileIniRedirect));
01623   lstrcat(szFileIniRedirect, FILE_INI_REDIRECT);
01624 
01625   if(FileExists(szFileIniRedirect))
01626     DeleteFile(szFileIniRedirect);
01627 
01628   GetPrivateProfileString("Redirect", "Status", "", szBuf, sizeof(szBuf), szFileIniConfig);
01629   if(lstrcmpi(szBuf, "ENABLED") != 0)
01630     return(0);
01631 
01632   ssiSiteSelectorTemp = SsiGetNode(szSiteSelectorDescription);
01633   if(ssiSiteSelectorTemp != NULL)
01634   {
01635     if(ssiSiteSelectorTemp->szDomain != NULL)
01636       lstrcpy(szBufUrl, ssiSiteSelectorTemp->szDomain);
01637   }
01638   else
01639     /* No domain to download the redirect.ini file from.
01640      * Assume that it does not exist.
01641      * This should trigger the backup/alternate url. */
01642     return(0);
01643 
01644   lstrcpy(szFileIdiGetRedirect, szTempDir);
01645   AppendBackSlash(szFileIdiGetRedirect, sizeof(szFileIdiGetRedirect));
01646   lstrcat(szFileIdiGetRedirect, FILE_IDI_GETREDIRECT);
01647 
01648   GetPrivateProfileString("Redirect", "Description", "", szBuf, sizeof(szBuf), szFileIniConfig);
01649   WritePrivateProfileString("File0", "desc", szBuf, szFileIdiGetRedirect);
01650   GetPrivateProfileString("Redirect", "Server Path", "", szBuf, sizeof(szBuf), szFileIniConfig);
01651   AppendSlash(szBufUrl, sizeof(szBufUrl));
01652   lstrcat(szBufUrl, szBuf);
01653   SwapFTPAndHTTP(szBufUrl, sizeof(szBufUrl));
01654   if(WritePrivateProfileString("File0", "url", szBufUrl, szFileIdiGetRedirect) == 0)
01655   {
01656     char szEWPPS[MAX_BUF];
01657 
01658     if(GetPrivateProfileString("Messages", "ERROR_WRITEPRIVATEPROFILESTRING", "", szEWPPS, sizeof(szEWPPS), szFileIniInstall))
01659     {
01660       wsprintf(szBufTemp, "%s\n    [%s]\n    %s=%s", szFileIdiGetRedirect, "File0", szIndex0, szBufUrl);
01661       wsprintf(szBuf, szEWPPS, szBufTemp);
01662       PrintError(szBuf, ERROR_CODE_SHOW);
01663     }
01664     return(1);
01665   }
01666 
01667   lResult = DownloadFiles(szFileIdiGetRedirect,               /* input idi file to parse                 */
01668                           szTempDir,                          /* download directory                      */
01669                           diAdvancedSettings.szProxyServer,   /* proxy server name                       */
01670                           diAdvancedSettings.szProxyPort,     /* proxy server port                       */
01671                           diAdvancedSettings.szProxyUser,     /* proxy server user (optional)            */
01672                           diAdvancedSettings.szProxyPasswd,   /* proxy password (optional)               */
01673                           FALSE,                              /* show retry message                      */
01674                           TRUE,                               /* ignore network error                    */
01675                           NULL,                               /* buffer to store the name of failed file */
01676                           0);                                 /* size of failed file name buffer         */
01677   return(lResult);
01678 }
01679 
01680 int CRCCheckDownloadedArchives(char *szCorruptedArchiveList,
01681                                DWORD dwCorruptedArchiveListSize,
01682                                char *szFileIdiGetArchives)
01683 {
01684   DWORD dwIndex0;
01685   DWORD dwFileCounter;
01686   siC   *siCObject = NULL;
01687   char  szArchivePathWithFilename[MAX_BUF];
01688   char  szArchivePath[MAX_BUF];
01689   char  szMsgCRCCheck[MAX_BUF];
01690   char  szSection[MAX_INI_SK];
01691   int   iRv;
01692   int   iResult;
01693 
01694   /* delete the getarchives.idi file because it needs to be recreated
01695    * if there are any files that fails the CRC check */
01696   if(szFileIdiGetArchives)
01697     DeleteFile(szFileIdiGetArchives);
01698 
01699   if(szCorruptedArchiveList != NULL)
01700     ZeroMemory(szCorruptedArchiveList, dwCorruptedArchiveListSize);
01701 
01702   GetPrivateProfileString("Strings", "Message Verifying Archives", "", szMsgCRCCheck, sizeof(szMsgCRCCheck), szFileIniConfig);
01703   ShowMessage(szMsgCRCCheck, TRUE);
01704   
01705   iResult           = WIZ_CRC_PASS;
01706   dwIndex0          = 0;
01707   dwFileCounter     = 0;
01708   siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
01709   while(siCObject)
01710   {
01711     if((siCObject->dwAttributes & SIC_SELECTED) &&
01712       !(siCObject->dwAttributes & SIC_IGNORE_DOWNLOAD_ERROR))
01713     {
01714       if((iRv = LocateJar(siCObject, szArchivePath, sizeof(szArchivePath), TRUE)) == AP_NOT_FOUND)
01715       {
01716         char szBuf[MAX_BUF];
01717         char szEFileNotFound[MAX_BUF];
01718 
01719        if(GetPrivateProfileString("Messages", "ERROR_FILE_NOT_FOUND", "", szEFileNotFound, sizeof(szEFileNotFound), szFileIniInstall))
01720         {
01721           wsprintf(szBuf, szEFileNotFound, siCObject->szArchiveName);
01722           PrintError(szBuf, ERROR_CODE_HIDE);
01723         }
01724         iResult = WIZ_ARCHIVES_MISSING; // not all .xpi files were downloaded
01725         break;
01726       }
01727 
01728       if(lstrlen(szArchivePath) < sizeof(szArchivePathWithFilename))
01729         lstrcpy(szArchivePathWithFilename, szArchivePath);
01730 
01731       AppendBackSlash(szArchivePathWithFilename, sizeof(szArchivePathWithFilename));
01732       if((lstrlen(szArchivePathWithFilename) + lstrlen(siCObject->szArchiveName)) < sizeof(szArchivePathWithFilename))
01733         lstrcat(szArchivePathWithFilename, siCObject->szArchiveName);
01734 
01735       if(CheckForArchiveExtension(szArchivePathWithFilename))
01736       {
01737         /* Make sure that the Archive that failed is located in the TEMP
01738          * folder.  This means that it was downloaded at one point and not
01739          * simply uncompressed from the self-extracting exe file. */
01740         if(VerifyArchive(szArchivePathWithFilename) != ZIP_OK)
01741         {
01742           if(iRv == AP_TEMP_PATH)
01743           {
01744             /* Delete the archive even though the download lib will automatically
01745              * overwrite the file.  This is in case that Setup is canceled, at the
01746              * next restart, the file will be downloaded during the first attempt,
01747              * not after a VerifyArchive() call. */
01748             DeleteFile(szArchivePathWithFilename);
01749             wsprintf(szSection, "File%d", dwFileCounter);
01750             ++dwFileCounter;
01751             if(szFileIdiGetArchives)
01752               if((AddArchiveToIdiFile(siCObject,
01753                                       szSection,
01754                                       szFileIdiGetArchives)) != 0)
01755                 return(WIZ_ERROR_UNDEFINED);
01756 
01757             ++siCObject->iCRCRetries;
01758             if(szCorruptedArchiveList != NULL)
01759             {
01760               if((DWORD)(lstrlen(szCorruptedArchiveList) + lstrlen(siCObject->szArchiveName + 1)) < dwCorruptedArchiveListSize)
01761               {
01762                 lstrcat(szCorruptedArchiveList, "        ");
01763                 lstrcat(szCorruptedArchiveList, siCObject->szArchiveName);
01764                 lstrcat(szCorruptedArchiveList, "\n");
01765               }
01766             }
01767           }
01768           iResult = WIZ_CRC_FAIL;
01769         }
01770       }
01771     }
01772 
01773     ++dwIndex0;
01774     siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
01775   }
01776   return(iResult);
01777 }
01778 
01779 long RetrieveArchives()
01780 {
01781   DWORD     dwIndex0;
01782   DWORD     dwFileCounter;
01783   BOOL      bDone;
01784   siC       *siCObject = NULL;
01785   long      lResult;
01786   char      szFileIdiGetArchives[MAX_BUF];
01787   char      szSection[MAX_BUF];
01788   char      szCorruptedArchiveList[MAX_BUF];
01789   char      szFailedFile[MAX_BUF];
01790   char      szBuf[MAX_BUF];
01791   char      szPartiallyDownloadedFilename[MAX_BUF];
01792   int       iCRCRetries;
01793   int       iRv;
01794 
01795   /* retrieve the redirect.ini file */
01796   RetrieveRedirectFile();
01797 
01798   ZeroMemory(szCorruptedArchiveList, sizeof(szCorruptedArchiveList));
01799   lstrcpy(szFileIdiGetArchives, szTempDir);
01800   AppendBackSlash(szFileIdiGetArchives, sizeof(szFileIdiGetArchives));
01801   lstrcat(szFileIdiGetArchives, FILE_IDI_GETARCHIVES);
01802   GetSetupCurrentDownloadFile(szPartiallyDownloadedFilename,
01803                               sizeof(szPartiallyDownloadedFilename));
01804 
01805   gbDownloadTriggered= FALSE;
01806   lResult            = WIZ_OK;
01807   dwIndex0           = 0;
01808   dwFileCounter      = 0;
01809   siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
01810   while(siCObject)
01811   {
01812     if(siCObject->dwAttributes & SIC_SELECTED)
01813     {
01814       /* If a previous unfinished setup was detected, then
01815        * include the TEMP dir when searching for archives.
01816        * Only download jars if not already in the local machine.
01817        * Also if the last file being downloaded should be resumed.
01818        * The resume detection is done automatically. */
01819       if((LocateJar(siCObject,
01820                     NULL,
01821                     0,
01822                     gbPreviousUnfinishedDownload) == AP_NOT_FOUND) ||
01823          (lstrcmpi(szPartiallyDownloadedFilename,
01824                    siCObject->szArchiveName) == 0))
01825       {
01826         wsprintf(szSection, "File%d", dwFileCounter);
01827         if((lResult = AddArchiveToIdiFile(siCObject,
01828                                           szSection,
01829                                           szFileIdiGetArchives)) != 0)
01830           return(lResult);
01831 
01832         ++dwFileCounter;
01833       }
01834     }
01835 
01836     ++dwIndex0;
01837     siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
01838   }
01839 
01840   SetSetupState(SETUP_STATE_DOWNLOAD);
01841 
01842   /* iCRCRetries is initially set to 0 because the first attemp at downloading
01843    * the archives is not considered a "retry".  Subsequent downloads are
01844    * considered retries. */
01845   iCRCRetries = 0;
01846   bDone = FALSE;
01847   do
01848   {
01849     /* the existence of the getarchives.idi file determines if there are
01850        any archives needed to be downloaded */
01851     if(FileExists(szFileIdiGetArchives))
01852     {
01853       gbDownloadTriggered = TRUE;
01854       lResult = DownloadFiles(szFileIdiGetArchives,               /* input idi file to parse                 */
01855                               szTempDir,                          /* download directory                      */
01856                               diAdvancedSettings.szProxyServer,   /* proxy server name                       */
01857                               diAdvancedSettings.szProxyPort,     /* proxy server port                       */
01858                               diAdvancedSettings.szProxyUser,     /* proxy server user (optional)            */
01859                               diAdvancedSettings.szProxyPasswd,   /* proxy password (optional)               */
01860                               iCRCRetries,                        /* show retry message                      */
01861                               FALSE,                              /* ignore network error                    */
01862                               szFailedFile,                       /* buffer to store the name of failed file */
01863                               sizeof(szFailedFile));              /* size of failed file name buffer         */
01864       if(lResult == WIZ_OK)
01865       {
01866         /* CRC check only the archives that were downloaded.
01867          * It will regenerate the idi file with the list of files
01868          * that have not passed the CRC check. */
01869         iRv = CRCCheckDownloadedArchives(szCorruptedArchiveList,
01870                                          sizeof(szCorruptedArchiveList),
01871                                          szFileIdiGetArchives);
01872         switch(iRv)
01873         {
01874           case WIZ_CRC_PASS:
01875             bDone = TRUE;
01876             break;
01877 
01878           default:
01879             bDone = FALSE;
01880             break;
01881         }
01882       }
01883       else
01884       {
01885         /* Download failed.  Error message was already shown by DownloadFiles().
01886          * Simple exit loop here  */
01887         bDone = TRUE;
01888       }
01889     }
01890     else
01891       /* no idi file, so exit loop */
01892       bDone = TRUE;
01893 
01894     if(!bDone)
01895     {
01896       ++iCRCRetries;
01897       if(iCRCRetries > MAX_CRC_FAILED_DOWNLOAD_RETRIES)
01898         bDone = TRUE;
01899     }
01900 
01901   } while(!bDone);
01902 
01903   if(iCRCRetries > MAX_CRC_FAILED_DOWNLOAD_RETRIES)
01904   {
01905     /* too many retries from failed CRC checks */
01906     char szMsg[MAX_BUF];
01907 
01908     LogISComponentsFailedCRC(szCorruptedArchiveList, W_DOWNLOAD);
01909     GetPrivateProfileString("Strings", "Error Too Many CRC Failures", "", szMsg, sizeof(szMsg), szFileIniConfig);
01910     if(*szMsg != '\0')
01911       PrintError(szMsg, ERROR_CODE_HIDE);
01912 
01913     lResult = WIZ_CRC_FAIL;
01914   }
01915   else
01916   {
01917     if(gbDownloadTriggered)
01918       LogISComponentsFailedCRC(NULL, W_DOWNLOAD);
01919   }
01920 
01921   LogISDownloadProtocol(diAdditionalOptions.dwUseProtocol);
01922   LogMSDownloadProtocol(diAdditionalOptions.dwUseProtocol);
01923 
01924   if(lResult == WIZ_OK)
01925   {
01926     LogISDownloadStatus("ok", NULL);
01927   }
01928   else if(gbDownloadTriggered)
01929   {
01930     wsprintf(szBuf, "failed: %d", lResult);
01931     LogISDownloadStatus(szBuf, szFailedFile);
01932   }
01933 
01934   /* We want to log the download status regardless if we downloaded or not. */
01935   LogMSDownloadStatus(lResult);
01936 
01937   if(lResult == WIZ_OK)
01938   {
01939     UnsetSetupCurrentDownloadFile();
01940     UnsetSetupState();
01941   }
01942 
01943   return(lResult);
01944 }
01945 
01946 void RemoveBackSlash(LPSTR szInput)
01947 {
01948   DWORD dwInputLen;
01949   BOOL  bDone;
01950   char  *ptrChar = NULL;
01951 
01952   if(szInput)
01953   {
01954     dwInputLen = lstrlen(szInput);
01955     bDone = FALSE;
01956     ptrChar = &szInput[dwInputLen];
01957     while(!bDone)
01958     {
01959       ptrChar = CharPrev(szInput, ptrChar);
01960       if(*ptrChar == '\\')
01961         *ptrChar = '\0';
01962       else
01963         bDone = TRUE;
01964     }
01965   }
01966 }
01967 
01968 void AppendBackSlash(LPSTR szInput, DWORD dwInputSize)
01969 {
01970   DWORD dwInputLen = lstrlen(szInput);
01971 
01972   if(szInput)
01973   {
01974     if(*szInput == '\0')
01975     {
01976       if((dwInputLen + 1) < dwInputSize)
01977       {
01978         lstrcat(szInput, "\\");
01979       }
01980     }
01981     else if(*CharPrev(szInput, &szInput[dwInputLen]) != '\\')
01982     {
01983       if((dwInputLen + 1) < dwInputSize)
01984       {
01985         lstrcat(szInput, "\\");
01986       }
01987     }
01988   }
01989 }
01990 
01991 void RemoveSlash(LPSTR szInput)
01992 {
01993   DWORD dwInputLen;
01994   BOOL  bDone;
01995   char  *ptrChar = NULL;
01996 
01997   if(szInput)
01998   {
01999     dwInputLen = lstrlen(szInput);
02000     bDone = FALSE;
02001     ptrChar = &szInput[dwInputLen];
02002     while(!bDone)
02003     {
02004       ptrChar = CharPrev(szInput, ptrChar);
02005       if(*ptrChar == '/')
02006         *ptrChar = '\0';
02007       else
02008         bDone = TRUE;
02009     }
02010   }
02011 }
02012 
02013 void AppendSlash(LPSTR szInput, DWORD dwInputSize)
02014 {
02015   DWORD dwInputLen = lstrlen(szInput);
02016 
02017   if(szInput)
02018   {
02019     if(*szInput == '\0')
02020     {
02021       if((dwInputLen + 1) < dwInputSize)
02022       {
02023         lstrcat(szInput, "/");
02024       }
02025     }
02026     else if(*CharPrev(szInput, &szInput[dwInputLen]) != '/')
02027     {
02028       if((dwInputLen + 1) < dwInputSize)
02029       {
02030         lstrcat(szInput, "/");
02031       }
02032     }
02033   }
02034 }
02035 
02036 void ParsePath(LPSTR szInput, LPSTR szOutput, DWORD dwOutputSize, BOOL bURLPath, DWORD dwType)
02037 {
02038   int   iFoundDelimiter;
02039   DWORD dwInputLen;
02040   DWORD dwOutputLen;
02041   BOOL  bFound;
02042   BOOL  bDone = FALSE;
02043   char  cDelimiter;
02044   char  *ptrChar = NULL;
02045   char  *ptrLastChar = NULL;
02046 
02047   if(bURLPath)
02048     cDelimiter = '/';
02049   else
02050     cDelimiter = '\\';
02051 
02052   if(szInput && szOutput)
02053   {
02054     bFound        = TRUE;
02055     dwInputLen    = lstrlen(szInput);
02056     ZeroMemory(szOutput, dwOutputSize);
02057 
02058     if(dwInputLen < dwOutputSize)
02059     {
02060       switch(dwType)
02061       {
02062         case PP_FILENAME_ONLY:
02063           ptrChar = &szInput[dwInputLen];
02064           bDone = FALSE;
02065           while(!bDone)
02066           {
02067             ptrChar = CharPrev(szInput, ptrChar);
02068             if(*ptrChar == cDelimiter)
02069             {
02070               lstrcpy(szOutput, CharNext(ptrChar));
02071               bDone = TRUE;
02072             }
02073             else if(ptrChar == szInput)
02074             {
02075               /* we're at the beginning of the string and still
02076                * nothing found.  So just return the input string. */
02077               lstrcpy(szOutput, szInput);
02078               bDone = TRUE;
02079             }
02080           }
02081           break;
02082 
02083         case PP_PATH_ONLY:
02084           lstrcpy(szOutput, szInput);
02085           dwOutputLen = lstrlen(szOutput);
02086           ptrChar = &szOutput[dwOutputLen];
02087           bDone = FALSE;
02088           while(!bDone)
02089           {
02090             ptrChar = CharPrev(szOutput, ptrChar);
02091             if(*ptrChar == cDelimiter)
02092             {
02093               *CharNext(ptrChar) = '\0';
02094               bDone = TRUE;
02095             }
02096             else if(ptrChar == szOutput)
02097             {
02098               /* we're at the beginning of the string and still
02099                * nothing found.  So just return the input string. */
02100               bDone = TRUE;
02101             }
02102           }
02103           break;
02104 
02105         case PP_EXTENSION_ONLY:
02106           /* check the last character first */
02107           ptrChar = CharPrev(szInput, &szInput[dwInputLen]);
02108           if(*ptrChar == '.')
02109             break;
02110 
02111           bDone = FALSE;
02112           while(!bDone)
02113           {
02114             ptrChar = CharPrev(szInput, ptrChar);
02115             if(*ptrChar == cDelimiter)
02116               /* found path delimiter before '.' */
02117               bDone = TRUE;
02118             else if(*ptrChar == '.')
02119             {
02120               lstrcpy(szOutput, CharNext(ptrChar));
02121               bDone = TRUE;
02122             }
02123             else if(ptrChar == szInput)
02124               bDone = TRUE;
02125           }
02126           break;
02127 
02128         case PP_ROOT_ONLY:
02129           lstrcpy(szOutput, szInput);
02130           dwOutputLen = lstrlen(szOutput);
02131           ptrLastChar = CharPrev(szOutput, &szOutput[dwOutputLen]);
02132           ptrChar     = CharNext(szOutput);
02133           if(*ptrChar == ':')
02134           {
02135             ptrChar = CharNext(ptrChar);
02136             *ptrChar = cDelimiter;
02137             *CharNext(ptrChar) = '\0';
02138           }
02139           else
02140           {
02141             iFoundDelimiter = 0;
02142             ptrChar = szOutput;
02143             while(!bDone)
02144             {
02145               if(*ptrChar == cDelimiter)
02146                 ++iFoundDelimiter;
02147 
02148               if(iFoundDelimiter == 4)
02149               {
02150                 *CharNext(ptrChar) = '\0';
02151                 bDone = TRUE;
02152               }
02153               else if(ptrChar == ptrLastChar)
02154                 bDone = TRUE;
02155               else
02156                 ptrChar = CharNext(ptrChar);
02157             }
02158           }
02159           break;
02160       }
02161     }
02162   }
02163 }
02164 
02165 /* Function: UpdateGreInstallerCmdLine()
02166  *       in: greInfo *aGre - contains infor needed by this function
02167  *           BOOL forExistingGre - to determine if the caller is needing the
02168  *               aParameter to be used by an existing GRE installer or by
02169  *               a new GRE installer.
02170  *   in/out: char *aParameter.
02171  *  purpose: To update the default GRE installer's command line parameters
02172  *           with new defaults depending on config.ini or cmdline arguments
02173  *           to this app's installer.
02174  *           It will also check to make sure GRE's default destination path
02175  *           is writable.  If not, it will change the GRE's destination path
02176  *           to [product path]\GRE\[gre ver].
02177  */
02178 void UpdateGreInstallerCmdLine(greInfo *aGre, char *aParameter, DWORD aParameterBufSize, BOOL forExistingGre)
02179 {
02180   char productPath[MAX_BUF];
02181 
02182   MozCopyStr(sgProduct.szPath, productPath, sizeof(productPath));
02183   RemoveBackSlash(productPath);
02184 
02185   /* Decide GRE installer's run mode.  Default should be -ma (AUTO).
02186    * The only other possibility is -ms (SILENT).  We don't want to allow
02187    * the GRE installer to run in NORMAL mode because we don't want to
02188    * let the user see more dialogs than they need to. */
02189   if(sgProduct.mode == SILENT)
02190     lstrcat(aParameter, " -ms");
02191   else
02192     lstrcat(aParameter, " -ma");
02193 
02194   /* Force the install of GRE if '-greForce' is passed or if GRE
02195    * is to be local.
02196    *
02197    * Passing '-f' to GRE's installer will force it to install
02198    * regardless of version found on system.  If '-f' is already
02199    * present in the parameter, it will do no harm to pass it again. */
02200   if(gbForceInstallGre || (sgProduct.greType == GRE_LOCAL))
02201     lstrcat(aParameter, " -f");
02202 
02203   /* If GRE is to be local, then instruct the GRE's installer to
02204    * install to this application's destination path stored in
02205    * sgProduct.szPath.
02206    *
02207    * We need to also instruct the GRE's installer to create a
02208    * private windows registry GRE key instead of the default one, so
02209    * that other apps attempting to use the global GRE will not find
02210    * this private, local copy.  They should not find this copy! */
02211   if(sgProduct.greType == GRE_LOCAL)
02212   {
02213     char buf[MAX_BUF];
02214 
02215     wsprintf(buf, " -dd \"%s\" -reg_path %s", productPath, sgProduct.grePrivateKey);
02216     lstrcat(aParameter, buf);
02217   }
02218   else if(!forExistingGre)
02219   {
02220     char buf[MAX_BUF];
02221 
02222     assert(aGre);
02223     assert(*aGre->homePath);
02224     assert(*aGre->userAgent);
02225 
02226     /* Append a backslash to the path so CreateDirectoriesAll() will see the
02227      * the last directory name as a directory instead of a file. */
02228     AppendBackSlash(aGre->homePath, sizeof(aGre->homePath));
02229 
02230     /* Attempt to create the GRE destination directory.  If it fails, we don't
02231      * have sufficient access to the default path.  We then need to install
02232      * GRE to:
02233      *   [product path]\GRE\[gre id]
02234      *
02235      * This path should be guaranteed to be writable because the user had
02236      * already created the parent path ([product path]). */
02237     if(DirHasWriteAccess(aGre->homePath) != WIZ_OK)
02238     {
02239       int rv = WIZ_OK;
02240 
02241       /* Update the homePath to the new destination path of where GRE will be
02242        * installed to. homePath is used elsewhere and it needs to be
02243        * referencing the new path, else things will break. */
02244       _snprintf(aGre->homePath, sizeof(aGre->homePath), "%s\\GRE\\%s\\", productPath, aGre->userAgent);
02245       aGre->homePath[sizeof(aGre->homePath) - 1] = '\0';
02246 
02247       /* CreateDirectoriesAll() is guaranteed to succeed using the new GRE
02248        * destination path because it is a subdir of this product's destination
02249        * path that has already been created successfully. */
02250       rv = CreateDirectoriesAll(aGre->homePath, ADD_TO_UNINSTALL_LOG);
02251       assert(rv == WIZ_OK);
02252 
02253       /* When using the -dd option to override the GRE's destination path, the
02254        * path must be a path which includes the GRE ID, ie:
02255        *   C:\Program Files\mozilla.org\Mozilla\GRE\1.4_0000000000
02256        */
02257       _snprintf(buf, sizeof(buf), " -dd \"%s\"", aGre->homePath);
02258       buf[sizeof(buf) - 1] = '\0';
02259       lstrcat(aParameter, buf);
02260     }
02261   }
02262 }
02263 
02264 /* Function: GetInstalledGreConfigIni()
02265  *       in: greInfo *aGre: gre class containing the location of GRE
02266  *           already installed.
02267  *      out: char *aGreConfigIni, DWORD aGreConfigIniBufSize: contains
02268  *           the full path to the installed GRE installer's config.ini
02269  *           file.
02270  *  purpose: To get the full path to the installed GRE installer's
02271  *           config.ini file.
02272  */
02273 HRESULT GetInstalledGreConfigIni(greInfo *aGre, char *aGreConfigIni, DWORD aGreConfigIniBufSize)
02274 {
02275   char buf[MAX_BUF];
02276 
02277   if(!aGre || !aGreConfigIni || (*aGre->homePath == '\0'))
02278     return(WIZ_ERROR_UNDEFINED);
02279 
02280   *aGreConfigIni = '\0';
02281   MozCopyStr(aGre->homePath, buf, sizeof(buf));
02282   AppendBackSlash(buf, sizeof(buf));
02283   wsprintf(aGreConfigIni, "%s%s\\%s", buf, GRE_SETUP_DIR_NAME, FILE_INI_CONFIG);
02284   return(WIZ_OK);
02285 }
02286 
02287 /* Function: GetInfoFromInstalledGreConfigIni()
02288  *       in: greInfo *aGre: gre class to fill the info for.
02289  *      out: returns info in aGre.
02290  *  purpose: To retrieve the GRE uninstaller file (full path) from
02291  *           the installed GRE's config.ini file.
02292  *           GetInfoFromGreInstaller() retrieves information from
02293  *           the (to be run) GRE installer's config.ini, not from the
02294  *           installed GRE installer's config.ini file.
02295  */
02296 HRESULT GetInfoFromInstalledGreConfigIni(greInfo *aGre)
02297 {
02298   HRESULT rv = WIZ_ERROR_UNDEFINED;
02299   char    greConfigIni[MAX_BUF];
02300   char    buf[MAX_BUF];
02301   char    greUninstallerFilename[MAX_BUF];
02302 
02303   if(!aGre)
02304     return(rv);
02305 
02306   *aGre->uninstallerAppPath = '\0';
02307   rv = GetInstalledGreConfigIni(aGre, greConfigIni, sizeof(greConfigIni));
02308   if(WIZ_OK == rv)
02309   {
02310     GetPrivateProfileString("General", "Uninstall Filename", "", greUninstallerFilename, sizeof(greUninstallerFilename), greConfigIni);
02311     wsprintf(buf, "[WINDIR]\\%s", greUninstallerFilename);
02312     DecryptString(aGre->uninstallerAppPath, buf);
02313     GetPrivateProfileString("General", "User Agent", "", aGre->userAgent, sizeof(aGre->userAgent), greConfigIni);
02314   }
02315   return(rv);
02316 }
02317 
02318 /* Function: GetInfoFromGreInstaller()
02319  *       in: char    *aGreInstallerFile: full path to the GRE installer.
02320  *           greInfo *aGre: gre class to fill the homePath for.
02321  *      out: returns homePath in aGre.
02322  *  purpose: To retrieve the GRE home path from the GRE installer.
02323  */
02324 void GetInfoFromGreInstaller(char *aGreInstallerFile, greInfo *aGre)
02325 {
02326   char szBuf[MAX_BUF];
02327   char extractedConfigFile[MAX_BUF];
02328   int  size = 0;
02329 
02330   if(!aGre)
02331     return;
02332 
02333   /* If GRE is to be installed locally, then set it to the
02334    * application's destination path. */
02335   if(sgProduct.greType == GRE_LOCAL)
02336   {
02337     MozCopyStr(sgProduct.szPath, aGre->homePath, sizeof(aGre->homePath));
02338     return;
02339   }
02340 
02341   *aGre->homePath = '\0';
02342 
02343   /* uncompress GRE installer's config.ini file in order to parse for:
02344    *   [General]
02345    *   Path=
02346    *   User Agent=
02347    */
02348   wsprintf(szBuf, "-mmi -ms -u %s", FILE_INI_CONFIG);
02349   WinSpawn(aGreInstallerFile, szBuf, szOSTempDir, SW_SHOWNORMAL, WS_WAIT);
02350   MozCopyStr(szOSTempDir, extractedConfigFile, sizeof(extractedConfigFile));
02351   AppendBackSlash(extractedConfigFile, sizeof(extractedConfigFile));
02352   lstrcat(extractedConfigFile, FILE_INI_CONFIG);
02353   GetPrivateProfileString("General", "Path", "", szBuf, sizeof(szBuf), extractedConfigFile);
02354   DecryptString(aGre->homePath, szBuf);
02355   GetPrivateProfileString("General", "User Agent", "", aGre->userAgent, sizeof(aGre->userAgent), extractedConfigFile);
02356   DeleteFile(extractedConfigFile);
02357 }
02358 
02359 /* Function: CleanupOrphanedGREs()
02360  *       in: none.
02361  *      out: none.
02362  *  purpose: To clean up GREs that were left on the system by previous
02363  *           installations of this product only (not by any other product).
02364  */
02365 HRESULT CleanupOrphanedGREs()
02366 {
02367   HKEY      greIDKeyHandle;
02368   HKEY      greAppListKeyHandle;
02369   DWORD     totalGreIDSubKeys;
02370   DWORD     totalGREAppListSubKeys;
02371   char      **greIDListToClean = NULL;
02372   char      **greAppListToClean = NULL;
02373   char      greKeyID[MAX_BUF_MEDIUM];
02374   char      greRegKey[MAX_BUF];
02375   char      greKeyAppList[MAX_BUF_MEDIUM];
02376   char      greAppListKeyPath[MAX_BUF];
02377   char      greUninstaller[MAX_BUF];
02378   DWORD     idKeySize;
02379   DWORD     appListKeySize;
02380   DWORD     indexOfGREID;
02381   DWORD     indexOfGREAppList;
02382   int       rv = WIZ_OK;
02383   int       regRv = WIZ_OK;
02384   char      buf[MAX_BUF];
02385 
02386   DecryptString(greUninstaller, GRE_UNINSTALLER_FILE);
02387 
02388   _snprintf(buf, sizeof(buf), "    GRE Cleanup Orphans: %s\n", sgProduct.greCleanupOrphans ? "true" : "false");
02389   buf[sizeof(buf) - 1] = '\0';
02390   UpdateInstallStatusLog(buf);
02391 
02392   _snprintf(buf, sizeof(buf), "    GRE Uninstaller Path: %s\n", greUninstaller);
02393   buf[sizeof(buf) - 1] = '\0';
02394   UpdateInstallStatusLog(buf);
02395 
02396   _snprintf(buf, sizeof(buf), "    GRE Uninstaller found: %s\n", FileExists(greUninstaller) ? "true" : "false");
02397   buf[sizeof(buf) - 1] = '\0';
02398   UpdateInstallStatusLog(buf);
02399 
02400   // If greCleanupOrphans is false (set either in config.ini or passed in
02401   // thru the cmdline) or GRE's uninstaller file does not exist, then
02402   // simply do nothing and return.
02403   if(!sgProduct.greCleanupOrphans || !FileExists(greUninstaller))
02404   {
02405     _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return: %d\n", WIZ_OK);
02406     buf[sizeof(buf) - 1] = '\0';
02407     UpdateInstallStatusLog(buf);
02408     return(WIZ_OK);
02409   }
02410 
02411   // If GRE is installed locally, then use the private GRE key, else
02412   // use the default global GRE key in the windows registry.
02413   if(sgProduct.greType == GRE_LOCAL)
02414     DecryptString(greRegKey, sgProduct.grePrivateKey);
02415   else
02416     MozCopyStr(GRE_REG_KEY, greRegKey, sizeof(greRegKey));
02417 
02418   if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, greRegKey, 0, KEY_READ, &greIDKeyHandle) != ERROR_SUCCESS)
02419   {
02420     _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return (RegOpenKeyEx: %s): %d\n", greRegKey, WIZ_ERROR_UNDEFINED);
02421     buf[sizeof(buf) - 1] = '\0';
02422     UpdateInstallStatusLog(buf);
02423     return(WIZ_ERROR_UNDEFINED);
02424   }
02425 
02426   // Build the list of GRE's given greRegKey.  For example, if greRegKey is:
02427   //
02428   //   HKLM\Software\mozilla.org\GRE
02429   //
02430   // then build a list of the GRE IDs inside this key.
02431   totalGreIDSubKeys = 0;
02432   regRv = RegQueryInfoKey(greIDKeyHandle, NULL, NULL, NULL, &totalGreIDSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
02433   if((regRv != ERROR_SUCCESS) || (totalGreIDSubKeys == 0))
02434   {
02435     rv = WIZ_ERROR_UNDEFINED;
02436     _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return (RegQueryInfoKey: all keys): %d\n", rv);
02437     buf[sizeof(buf) - 1] = '\0';
02438     UpdateInstallStatusLog(buf);
02439     return(rv);
02440   }
02441 
02442   if((rv == WIZ_OK) && (greIDListToClean = NS_GlobalAlloc(sizeof(char *) * totalGreIDSubKeys)) == NULL)
02443   {
02444     RegCloseKey(greIDKeyHandle);
02445     _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to allocate memory for greIDListToClean: %d\n", WIZ_OUT_OF_MEMORY);
02446     buf[sizeof(buf) - 1] = '\0';
02447     UpdateInstallStatusLog(buf);
02448     return(WIZ_OUT_OF_MEMORY);
02449   }
02450 
02451   // Show message that orphaned GREs are being cleaned up
02452   if(*sgProduct.greCleanupOrphansMessage != '\0')
02453     ShowMessage(sgProduct.greCleanupOrphansMessage, TRUE);
02454 
02455   if(rv == WIZ_OK)
02456   {
02457     // Initialize the array of pointers (of GRE ID keys) to NULL
02458     for(indexOfGREID = 0; indexOfGREID < totalGreIDSubKeys; indexOfGREID++)
02459       greIDListToClean[indexOfGREID] = NULL;
02460 
02461     // Enumerate the GRE ID list and save the GRE ID to each of its array element
02462     for(indexOfGREID = 0; indexOfGREID < totalGreIDSubKeys; indexOfGREID++)
02463     {
02464       idKeySize = sizeof(greKeyID);
02465       if(RegEnumKeyEx(greIDKeyHandle, indexOfGREID, greKeyID, &idKeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
02466       {
02467         if((greIDListToClean[indexOfGREID] = NS_GlobalAlloc(sizeof(char) * (idKeySize + 1))) == NULL)
02468         {
02469           RegCloseKey(greIDKeyHandle);
02470           rv = WIZ_OUT_OF_MEMORY;
02471           _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to add %s to greIDListToClean[]: %d\n", greKeyID, rv);
02472           buf[sizeof(buf) - 1] = '\0';
02473           UpdateInstallStatusLog(buf);
02474           break;
02475         }
02476         MozCopyStr(greKeyID, greIDListToClean[indexOfGREID], idKeySize + 1);
02477       }
02478     }
02479     RegCloseKey(greIDKeyHandle);
02480 
02481     if(rv == WIZ_OK)
02482     {
02483       // Enumerate the GRE ID list built from above to get to each of it's AppList key.
02484       // The list that we need to build now is from the following key:
02485       //
02486       //   HKLM\Software\mozilla.org\GRE\[GRE ID]\AppList
02487       for(indexOfGREID = 0; indexOfGREID < totalGreIDSubKeys; indexOfGREID++)
02488       {
02489         // If we find the same GRE version as what we're trying to install,
02490         // then we don't want to process it because if we do, it will
02491         // uninstall it.  Which means that it'll reinstall it again.  We don't
02492         // want to have reinstall when we don't need to.
02493         //
02494         // szUserAgent is the GRE unique id if this instance of the installer is
02495         // installing GRE.
02496         if(strcmpi(sgProduct.szUserAgent, greIDListToClean[indexOfGREID]) == 0)
02497           continue;
02498 
02499         _snprintf(greAppListKeyPath, sizeof(greAppListKeyPath), "%s\\%s\\AppList",
02500             GRE_REG_KEY, greIDListToClean[indexOfGREID]);
02501         greAppListKeyPath[sizeof(greAppListKeyPath) - 1] = '\0';
02502         if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, greAppListKeyPath, 0, KEY_READ, &greAppListKeyHandle) != ERROR_SUCCESS)
02503         {
02504           rv = WIZ_ERROR_UNDEFINED;
02505           _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to open key %s: %d\n", greAppListKeyPath, rv);
02506           buf[sizeof(buf) - 1] = '\0';
02507           UpdateInstallStatusLog(buf);
02508           break;
02509         }
02510 
02511         totalGREAppListSubKeys = 0;
02512         if(RegQueryInfoKey(greAppListKeyHandle, NULL, NULL, NULL, &totalGREAppListSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
02513         {
02514           RegCloseKey(greAppListKeyHandle);
02515           rv = WIZ_ERROR_UNDEFINED;
02516           _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to regquery for all keys in %s: %d\n", greAppListKeyPath, rv);
02517           buf[sizeof(buf) - 1] = '\0';
02518           UpdateInstallStatusLog(buf);
02519           break;
02520         }
02521     
02522         if((rv == WIZ_OK) && (greAppListToClean = NS_GlobalAlloc(sizeof(char *) * totalGREAppListSubKeys)) == NULL)
02523         {
02524           RegCloseKey(greAppListKeyHandle);
02525           rv = WIZ_OUT_OF_MEMORY;
02526           _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to allocate memory for greAppListToClean: %d\n", rv);
02527           buf[sizeof(buf) - 1] = '\0';
02528           UpdateInstallStatusLog(buf);
02529           break;
02530         }
02531 
02532         // Initialize the GREAppList elements to NULL.
02533         for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)
02534           greAppListToClean[indexOfGREAppList] = NULL;
02535 
02536         // enumerate the GRE AppList key and build a list.
02537         for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)
02538         {
02539           appListKeySize = sizeof(greKeyAppList);
02540           if(RegEnumKeyEx(greAppListKeyHandle, indexOfGREAppList, greKeyAppList, &appListKeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
02541           {
02542             if((greAppListToClean[indexOfGREAppList] = NS_GlobalAlloc(sizeof(char) * (appListKeySize + 1))) == NULL)
02543             {
02544               RegCloseKey(greAppListKeyHandle);
02545               rv = WIZ_OUT_OF_MEMORY;
02546               _snprintf(buf, sizeof(buf), "    Cleanup Orphaned GRE premature return.  Failed to add %s to greAppListToClean[]: %d\n", greKeyAppList, rv);
02547               buf[sizeof(buf) - 1] = '\0';
02548               UpdateInstallStatusLog(buf);
02549               break;
02550             }
02551             MozCopyStr(greKeyAppList, greAppListToClean[indexOfGREAppList], appListKeySize + 1);
02552           }
02553         }
02554         RegCloseKey(greAppListKeyHandle);
02555 
02556         if(rv != WIZ_OK)
02557           break;
02558 
02559         UpdateInstallStatusLog("\n    Cleanup Orphaned GRE's uninstall commandline:\n");
02560         // Enumerate the saved GREAppList and start calling GREUninstall.exe
02561         // to remove them if appropriate.
02562         // GREUninstall.exe will take care of determining if the particular
02563         // GRE should be fully removed or not.
02564         // We need to enumerate the list again instead of doing this in the
02565         // save loop as above because deleting keys while at the same time
02566         // enumerating thru its parent key is a Bad Thing(TM).
02567         for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)
02568         {
02569           char programNamePath[MAX_BUF];
02570           char greUninstallParam[MAX_BUF];
02571 
02572           DecryptString(programNamePath, sgProduct.szAppPath);
02573           _snprintf(greUninstallParam, sizeof(greUninstallParam), "-mmi -ms -ua \"%s\" -app \"%s\" -app_path \"%s\"",
02574               greIDListToClean[indexOfGREID], greAppListToClean[indexOfGREAppList], programNamePath);
02575           greUninstallParam[sizeof(greUninstallParam) - 1] = '\0';
02576           UpdateInstallStatusLog("        ");
02577           UpdateInstallStatusLog(greUninstallParam);
02578           UpdateInstallStatusLog("\n");
02579           WinSpawn(greUninstaller, greUninstallParam, szTempDir, SW_SHOWNORMAL, WS_WAIT);
02580         }
02581 
02582         // Cleanup allocated memory
02583         for(indexOfGREAppList = 0; indexOfGREAppList < totalGREAppListSubKeys; indexOfGREAppList++)
02584           FreeMemory(&greAppListToClean[indexOfGREAppList]);
02585         if(greAppListToClean)
02586           GlobalFree(greAppListToClean);
02587       }
02588     }
02589   }
02590 
02591   //
02592   // Cleanup allocated memory
02593   CleanupArrayList(greIDListToClean, totalGreIDSubKeys);
02594   if(greIDListToClean)
02595     GlobalFree(greIDListToClean);
02596 
02597   return(rv);
02598 }
02599 
02600 void LaunchOneComponent(siC *siCObject, greInfo *aGre)
02601 {
02602   BOOL      bArchiveFound;
02603   char      szArchive[MAX_BUF];
02604   char      szMsg[MAX_BUF];
02605 
02606   if(!siCObject)
02607     /* nothing to do return */
02608     return;
02609 
02610   GetPrivateProfileString("Messages", "MSG_CONFIGURING", "", szMsg, sizeof(szMsg), szFileIniInstall);
02611 
02612   /* launch 3rd party executable */
02613   if((siCObject->dwAttributes & SIC_SELECTED) && (siCObject->dwAttributes & SIC_LAUNCHAPP))
02614   {
02615     bArchiveFound = TRUE;
02616     lstrcpy(szArchive, sgProduct.szAlternateArchiveSearchPath);
02617     AppendBackSlash(szArchive, sizeof(szArchive));
02618     lstrcat(szArchive, siCObject->szArchiveName);
02619     if((*sgProduct.szAlternateArchiveSearchPath == '\0') || !FileExists(szArchive))
02620     {
02621       lstrcpy(szArchive, szSetupDir);
02622       AppendBackSlash(szArchive, sizeof(szArchive));
02623       lstrcat(szArchive, siCObject->szArchiveName);
02624       if(!FileExists(szArchive))
02625       {
02626         lstrcpy(szArchive, szTempDir);
02627         AppendBackSlash(szArchive, sizeof(szArchive));
02628         lstrcat(szArchive, siCObject->szArchiveName);
02629         if(!FileExists(szArchive))
02630         {
02631           bArchiveFound = FALSE;
02632         }
02633       }
02634     }
02635 
02636     if(bArchiveFound)
02637     {
02638       char szParameterBuf[MAX_BUF];
02639       char szSpawnFile[MAX_BUF];
02640       char szMessageString[MAX_BUF];
02641       DWORD dwErr = FO_SUCCESS;
02642 
02643       *szMessageString = '\0';
02644       if(*szMsg != '\0')
02645       {
02646         wsprintf(szMessageString, szMsg, siCObject->szDescriptionShort);
02647         ShowMessage(szMessageString, TRUE);
02648       }
02649 
02650       DecryptString(szParameterBuf, siCObject->szParameter);
02651       lstrcpy(szSpawnFile, szArchive);
02652       if(siCObject->dwAttributes & SIC_UNCOMPRESS)
02653       {
02654         if((dwErr = FileUncompress(szArchive, szTempDir)) == FO_SUCCESS)
02655         {
02656           lstrcpy(szSpawnFile, szTempDir);
02657           AppendBackSlash(szSpawnFile, sizeof(szSpawnFile));
02658           lstrcat(szSpawnFile, siCObject->szArchiveNameUncompressed);
02659         }
02660 
02661         LogISLaunchAppsComponentUncompress(siCObject->szDescriptionShort, dwErr);
02662         if(dwErr != FO_SUCCESS)
02663           return;
02664       }
02665 
02666       if(aGre)
02667       {
02668         GetInfoFromGreInstaller(szSpawnFile, aGre);
02669         UpdateGreInstallerCmdLine(aGre, szParameterBuf, sizeof(szParameterBuf), FOR_NEW_GRE);
02670       }
02671 
02672       LogISLaunchAppsComponent(siCObject->szDescriptionShort);
02673       WinSpawn(szSpawnFile, szParameterBuf, szTempDir, SW_SHOWNORMAL, WS_WAIT);
02674 
02675       if(siCObject->dwAttributes & SIC_UNCOMPRESS)
02676         FileDelete(szSpawnFile);
02677     }
02678   }
02679 }
02680 
02681 void LaunchExistingGreInstaller(greInfo *aGre)
02682 {
02683   char      szMsg[MAX_BUF];
02684   char      szParameterBuf[MAX_BUF];
02685   char      szMessageString[MAX_BUF];
02686   siC       *siCObject = aGre->siCGreComponent;
02687 
02688   if((!siCObject) || !FileExists(aGre->installerAppPath))
02689     /* nothing to do return */
02690     return;
02691 
02692   GetPrivateProfileString("Messages", "MSG_CONFIGURING", "", szMsg, sizeof(szMsg), szFileIniInstall);
02693 
02694   *szMessageString = '\0';
02695   if(*szMsg != '\0')
02696   {
02697     wsprintf(szMessageString, szMsg, siCObject->szDescriptionShort);
02698     ShowMessage(szMessageString, TRUE);
02699   }
02700 
02701   DecryptString(szParameterBuf, siCObject->szParameter);
02702   UpdateGreInstallerCmdLine(NULL, szParameterBuf, sizeof(szParameterBuf), FOR_EXISTING_GRE);
02703   LogISLaunchAppsComponent(siCObject->szDescriptionShort);
02704   WinSpawn(aGre->installerAppPath, szParameterBuf, szTempDir, SW_SHOWNORMAL, WS_WAIT);
02705 }
02706 
02707 HRESULT LaunchApps()
02708 {
02709   DWORD     dwIndex0;
02710   siC       *siCObject = NULL;
02711 
02712   LogISLaunchApps(W_START);
02713   dwIndex0 = 0;
02714   siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
02715   while(siCObject)
02716   {
02717     /* launch 3rd party executable */
02718     LaunchOneComponent(siCObject, NULL);
02719     ++dwIndex0;
02720     siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
02721   }
02722 
02723   LogISLaunchApps(W_END);
02724   return(0);
02725 }
02726 
02727 /* Function: IsPathWithinWindir()
02728  *       in: char *aTargetPath
02729  *      out: returns a BOOL type indicating whether the install path chosen
02730  *           by the user is within the %windir% or not.
02731  *  purpose: To see if aTargetPath is within the %windir% path.
02732  */
02733 BOOL IsPathWithinWindir(char *aTargetPath)
02734 {
02735   char windir[MAX_PATH];
02736   char targetPath[MAX_PATH];
02737 
02738   assert(aTargetPath);
02739 
02740   if(GetWindowsDirectory(windir, sizeof(windir)))
02741   {
02742     MozCopyStr(aTargetPath, targetPath, sizeof(targetPath));
02743     AppendBackSlash(targetPath, sizeof targetPath);
02744     CharUpperBuff(targetPath, sizeof(targetPath));
02745     AppendBackSlash(windir, sizeof(windir));
02746     CharUpperBuff(windir, sizeof(windir));
02747     if(strstr(targetPath, windir) == targetPath)
02748       return(TRUE);
02749   }
02750   else
02751   {
02752     /* If we can't get the windows path, just show error message and assume
02753      * the install path is not within the windows dir. */
02754     char szEGetWindirFailed[MAX_BUF];
02755 
02756     if(GetPrivateProfileString("Messages", "ERROR_GET_WINDOWS_DIRECTORY_FAILED", "", szEGetWindirFailed, sizeof(szEGetWindirFailed), szFileIniInstall))
02757       PrintError(szEGetWindirFailed, ERROR_CODE_SHOW);
02758   }
02759   return(FALSE);
02760 }
02761 
02762 /* Function: CleanupArrayList()
02763  *       in: char **aList - array to cleanup
02764  *           int  aListLength - length of array
02765  *      out: none.
02766  *  purpose: Cleans up memory.
02767  */
02768 void CleanupArrayList(char **aList, int aListLength)
02769 {
02770   int index = 0;
02771 
02772   // Free allocated memory
02773   for(index = 0; index < aListLength; index++)
02774     FreeMemory(&aList[index]);
02775 }
02776 
02777 /* Function: GetTotalNumKeys()
02778  *       in: char *aSectionName - name of section to get info on
02779  *           char *aBaseKeyName - base name of key to count
02780  *      out: none.
02781  *  purpose: To get the total number of 'aBaseKeyName's in aSection.
02782  *           A base key name is just the name of the key without the
02783  *           numbers, ie:
02784  *             base key name          : Object
02785  *             actual key in .ini file: Object0, Object1, etc...
02786  */
02787 int GetTotalNumKeys(char *aSectionName, char *aBaseKeyName)
02788 {
02789   int index = 0;
02790   char keyName[MAX_BUF_TINY];
02791   char buf[MAX_BUF];
02792 
02793   assert(aSectionName);
02794   assert(aBaseKeyName);
02795 
02796   _snprintf(keyName, sizeof(keyName), "%s%d", aBaseKeyName, index);
02797   keyName[sizeof(keyName) - 1] = '\0';
02798   GetPrivateProfileString(aSectionName, keyName, "", buf, sizeof(buf), szFileIniConfig);
02799   while(*buf != '\0')
02800   {
02801     ++index;
02802     _snprintf(keyName, sizeof(keyName), "%s%d", aBaseKeyName, index);
02803     keyName[sizeof(keyName) - 1] = '\0';
02804     GetPrivateProfileString(aSectionName, keyName, "", buf, sizeof(buf), szFileIniConfig);
02805   }
02806 
02807   return(index);
02808 }
02809 
02810 /* Function: BuildArrayList()
02811  *       in: char *aSectionName - section name to look for info to build array
02812  *           char *aBaseKeyName - base key name to use to build array from
02813  *      out: returns char ** - array list built
02814  *           int *aArrayLength - length of array built
02815  *  purpose: To build an Array list given the aSectionName and aBaseKeyName.
02816  *           Caller is responsible for cleaning up of allocated memory done
02817  *           in this function!
02818  */
02819 char **BuildArrayList(char *aSectionName, char *aBaseKeyName, int *aArrayLength)
02820 {
02821   int index = 0;
02822   int totalKeys = 0;
02823   char **list;
02824   char keyName[MAX_BUF_TINY];
02825   char buf[MAX_BUF];
02826 
02827   *aArrayLength = 0;
02828   totalKeys = GetTotalNumKeys(aSectionName, aBaseKeyName);
02829 
02830   // if totalKeys is <= 0, then there's nothing to do.
02831   if(totalKeys <= 0)
02832     return(NULL);
02833 
02834   if((list = NS_GlobalAlloc(sizeof(char *) * totalKeys)) == NULL)
02835     return(NULL);
02836 
02837   // Create and initialize the array of pointers
02838   for(index = 0; index < totalKeys; index++)
02839   {
02840     // build the actual key name to use.
02841     _snprintf(keyName, sizeof(keyName), "%s%d", aBaseKeyName, index);
02842     keyName[sizeof(keyName) - 1] = '\0';
02843     GetPrivateProfileString(aSectionName, keyName, "", buf, sizeof(buf), szFileIniConfig);
02844     if(*buf != '\0')
02845     {
02846       if((list[index] = NS_GlobalAlloc(sizeof(char) * (lstrlen(buf) + 1))) == NULL)
02847       {
02848         // couldn't allocate memory for an array, cleanup the array list that
02849         // has been currently built, and return NULL.
02850         CleanupArrayList(list, index);
02851         if(list)
02852           GlobalFree(list);
02853 
02854         return(NULL);
02855       }
02856       MozCopyStr(buf, list[index], lstrlen(buf) + 1);
02857     }
02858     else
02859       list[index] = NULL;
02860   }
02861   *aArrayLength = index;
02862 
02863   // caller is responsible for garbage cleanup of list.
02864   return(list);
02865 }
02866 
02867 /* Function: IsDirAProfileDir()
02868  *       in: char *aParentPath - path to start the check.
02869  *           char **aListProfileObjects - array list of profile files/dirs to
02870  *                  use to determine if a dir is a profile dir or not.
02871  *           int  aListLength
02872  *      out: BOOL
02873  *  purpose: To check to see if a dir is a profile dir or not.  If any of it's
02874  *           subdirectories is a profile dir, then the initial aParentPath is
02875  *           considered to be a profile dir.
02876  */
02877 BOOL IsDirAProfileDir(char *aParentPath, char **aListProfileObjects, int aListLength)
02878 {
02879   HANDLE          fileHandle;
02880   WIN32_FIND_DATA fdFile;
02881   char            destPathTemp[MAX_BUF];
02882   BOOL            found;
02883   BOOL            isProfileDir;
02884   int             index;
02885 
02886   if((aListLength <= 0) || !aListProfileObjects || !*aListProfileObjects)
02887     return(FALSE);
02888 
02889   /* check the initial aParentPath to see if the dir contains the
02890    * files/dirs that contitute a profile dir */
02891   isProfileDir = TRUE;
02892   for(index = 0; index < aListLength; index++)
02893   {
02894     /* create full path */
02895     _snprintf(destPathTemp, sizeof(destPathTemp), "%s\\%s", aParentPath, aListProfileObjects[index]);
02896     destPathTemp[sizeof(destPathTemp) - 1] = '\0';
02897 
02898     /* if any of the files/dirs that make up a profile dir is missing,
02899      * then it's not a profile dir */
02900     if(!FileExists(destPathTemp))
02901     {
02902       isProfileDir = FALSE;
02903       break;
02904     }
02905   }
02906 
02907   /* If it's determined to be a profile dir, then return immediately.  If it's
02908    * not, then continue searching the other dirs to see if any constitute a
02909    * profile dir. */
02910   if(isProfileDir)
02911     return(TRUE);
02912 
02913   _snprintf(destPathTemp, sizeof(destPathTemp), "%s\\*", aParentPath);
02914   destPathTemp[sizeof(destPathTemp) - 1] = '\0';
02915 
02916   found = TRUE;
02917   fileHandle = FindFirstFile(destPathTemp, &fdFile);
02918   while((fileHandle != INVALID_HANDLE_VALUE) && found)
02919   {
02920     if((lstrcmpi(fdFile.cFileName, ".") != 0) && (lstrcmpi(fdFile.cFileName, "..") != 0))
02921     {
02922       // if it's a directory, there we need to traverse it to see if there are
02923       // dirs that are profile dirs.
02924       if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
02925       {
02926         _snprintf(destPathTemp, sizeof(destPathTemp), "%s\\%s", aParentPath, fdFile.cFileName);
02927         destPathTemp[sizeof(destPathTemp) - 1] = '\0';
02928         isProfileDir = IsDirAProfileDir(destPathTemp, aListProfileObjects, aListLength);
02929         if(isProfileDir)
02930           break;
02931           
02932       }
02933     }
02934     found = FindNextFile(fileHandle, &fdFile);
02935   }
02936 
02937   FindClose(fileHandle);
02938   return(isProfileDir);
02939 }
02940 
02941 /* Function: IsOkToRemoveFileOrDir()
02942  *       in: char *aFileOrDirname
02943  *      out: bool return type
02944  *  purpose: To check if the file or dirname is not in the aListToIgnore.
02945  */
02946 BOOL IsOkToRemoveFileOrDirname(char *aFileOrDirname, char **aListToIgnore,
02947     int aListToIgnoreLength, char **aListProfileObjects, int aListProfileLength)
02948 {
02949   int  i;
02950   char filename[MAX_BUF];
02951 
02952   if(!aListToIgnore || !*aListToIgnore)
02953     return(TRUE);
02954 
02955   ParsePath(aFileOrDirname, filename, sizeof(filename), FALSE, PP_FILENAME_ONLY);
02956 
02957   // check to see if this is a profile folder
02958   if(FileExists(aFileOrDirname) & FILE_ATTRIBUTE_DIRECTORY)
02959     if(IsDirAProfileDir(aFileOrDirname, aListProfileObjects, aListProfileLength))
02960       return(FALSE);
02961 
02962   for(i = 0; i < aListToIgnoreLength; i++)
02963   {
02964     if(lstrcmpi(filename, aListToIgnore[i]) == 0)
02965       return(FALSE);
02966   }
02967   return(TRUE);
02968 }
02969 
02970 /* Function: CleanupOnUpgrade()
02971  *       in: none.
02972  *      out: none.
02973  *  purpose: To cleanup/remove files and dirs within the user chosen
02974  *           installation path, excluding the list in
02975  *           aListToIgnore.
02976  */
02977 void CleanupOnUpgrade()
02978 {
02979   HANDLE          fileHandle;
02980   WIN32_FIND_DATA fdFile;
02981   char            destPathTemp[MAX_BUF];
02982   char            targetPath[MAX_BUF];
02983   char            buf[MAX_BUF];
02984   BOOL            found;
02985   char            **listObjectsToIgnore;
02986   int             listTotalObjectsToIgnore;
02987   char            **listProfileObjects;
02988   int             listTotalProfileObjects;
02989   int             index;
02990 
02991   MozCopyStr(sgProduct.szPath, targetPath, sizeof(targetPath));
02992   RemoveBackSlash(targetPath);
02993 
02994   if(!FileExists(targetPath))
02995     return;
02996 
02997   UpdateInstallStatusLog("\n    Files/Dirs deleted on upgrade:\n");
02998 
02999   /* Check to see if the installation path is within the %windir%.  If so,
03000    * warn the user and do not delete any file! */
03001   if(IsPathWithinWindir(targetPath))
03002   {
03003     if(sgProduct.mode == NORMAL)
03004     {
03005       GetPrivateProfileString("Strings", "Message Cleanup On Upgrade Windir", "",
03006           buf, sizeof(buf), szFileIniConfig);
03007       MessageBox(hWndMain, buf, NULL, MB_ICONEXCLAMATION);
03008     }
03009 
03010     _snprintf(buf, sizeof(buf), "        None.  Installation path is within %windir%:\n            %s\n", targetPath);
03011     buf[sizeof(buf) - 1] = '\0';
03012     UpdateInstallStatusLog(buf);
03013     return;
03014   }
03015 
03016   // param1: section name
03017   // param2: base key name within section name
03018   //         ie: ObjectToIgnore0=
03019   //             ObjectToIgnore1=
03020   //             ObjectToIgnore2=
03021   listObjectsToIgnore = BuildArrayList("Cleanup On Upgrade", "ObjectToIgnore", &listTotalObjectsToIgnore);
03022   listProfileObjects  = BuildArrayList("Profile Dir Object List", "Object", &listTotalProfileObjects);
03023 
03024   _snprintf(destPathTemp, sizeof(destPathTemp), "%s\\*", targetPath);
03025   destPathTemp[sizeof(destPathTemp) - 1] = '\0';
03026 
03027   found = TRUE;
03028   fileHandle = FindFirstFile(destPathTemp, &fdFile);
03029   while((fileHandle != INVALID_HANDLE_VALUE) && found)
03030   {
03031     if((lstrcmpi(fdFile.cFileName, ".") != 0) && (lstrcmpi(fdFile.cFileName, "..") != 0))
03032     {
03033       /* create full path */
03034       _snprintf(destPathTemp, sizeof(destPathTemp), "%s\\%s", targetPath, fdFile.cFileName);
03035       destPathTemp[sizeof(destPathTemp) - 1] = '\0';
03036 
03037       if(IsOkToRemoveFileOrDirname(destPathTemp, listObjectsToIgnore,
03038             listTotalObjectsToIgnore, listProfileObjects, listTotalProfileObjects))
03039       {
03040         if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
03041         {
03042           AppendBackSlash(destPathTemp, sizeof(destPathTemp));
03043           DirectoryRemove(destPathTemp, TRUE);
03044         }
03045         else
03046           DeleteFile(destPathTemp);
03047 
03048         /* Check to see if the file/dir was deleted successfully */
03049         if(!FileExists(destPathTemp))
03050           _snprintf(buf, sizeof(buf), "        ok: %s\n", destPathTemp);
03051         else
03052           _snprintf(buf, sizeof(buf), "    failed: %s\n", destPathTemp);
03053       }
03054       else
03055         _snprintf(buf, sizeof(buf), "   skipped: %s\n", destPathTemp);
03056 
03057       buf[sizeof(buf) - 1] = '\0';
03058       UpdateInstallStatusLog(buf);
03059     }
03060 
03061     found = FindNextFile(fileHandle, &fdFile);
03062   }
03063 
03064   FindClose(fileHandle);
03065 
03066   // Log the array lists to make sure it matches the list of files/dirs that
03067   // were processed.
03068   UpdateInstallStatusLog("\n    Files/Dirs list to ignore:\n");
03069   for(index = 0; index < listTotalObjectsToIgnore; index++)
03070   {
03071     _snprintf(buf, sizeof(buf), "        ObjectToIgnore%d: %s\n", index + 1, listObjectsToIgnore[index]);
03072     buf[sizeof(buf) - 1] = '\0';
03073     UpdateInstallStatusLog(buf);
03074   }
03075 
03076   CleanupArrayList(listObjectsToIgnore, listTotalObjectsToIgnore);
03077   if(listObjectsToIgnore)
03078     GlobalFree(listObjectsToIgnore);
03079 
03080   UpdateInstallStatusLog("\n    Files/Dirs list to verify dir is a Profile dir:\n");
03081   for(index = 0; index < listTotalProfileObjects; index++)
03082   {
03083     _snprintf(buf, sizeof(buf), "        Object%d: %s\n", index + 1, listProfileObjects[index]);
03084     buf[sizeof(buf) - 1] = '\0';
03085     UpdateInstallStatusLog(buf);
03086   }
03087 
03088   CleanupArrayList(listProfileObjects, listTotalProfileObjects);
03089   if(listProfileObjects)
03090     GlobalFree(listProfileObjects);
03091 
03092 }
03093 
03094 /* Function: ProcessGre()
03095  *       in: none.
03096  *      out: path to where GRE is installed at.
03097  *  purpose: To install GRE on the system, so this installer can use it's
03098  *           xpinstall engine.  It uses gre->homePath to see if GRE is already
03099  *           installed on the system.  If GRE is already present on the system,
03100  *           gre->homePath is guaranteed to contain it's destination path.
03101  */
03102 HRESULT ProcessGre(greInfo *aGre)
03103 {
03104   char greUninstallCommand[MAX_BUF];
03105 
03106   if(!aGre)
03107     return(WIZ_OK);
03108 
03109   /* If aGre->homePath does not exist, it means that a compatible version of GRE was
03110    * not found on the system, so we need to install one.  We also need to get the
03111    * path to where it's going to install the GRE for in case we need to use it
03112    * as the xpinstall engine.
03113    *
03114    * If gbForceInstallGre is true, then force an installation of GRE regardless
03115    * if it's already on the system.  Also save the GRE's destination path to
03116    * aGre->homePath.
03117    *
03118    * If aGre->homePath does exist, then we simply call LaunchExistingGreInstaller()
03119    * to run the existing GRE's installer app to register mozilla.
03120    */
03121   UpdateInstallStatusLog("\n");
03122   if((*aGre->homePath == '\0') || (gbForceInstallGre))
03123     LaunchOneComponent(aGre->siCGreComponent, aGre);
03124   else
03125     LaunchExistingGreInstaller(aGre);
03126 
03127   /* XXX instead of unsetting the SELECTED attribute, set the DOWNLOAD_ONLY attribute
03128    * in the config.ini file.
03129    */
03130   /* Unset "Component GRE"'s SELECTED attribute so it doesn't get spawned again later from LaunchApps() */
03131   gGreInstallerHasRun = TRUE;
03132   if(aGre->siCGreComponent)
03133     aGre->siCGreComponent->dwAttributes &= ~SIC_SELECTED;
03134 
03135   /* Log the GRE uninstall command to call in order for this app's uninstaller to
03136    * uninstall GRE.
03137    */
03138   if(GetInfoFromInstalledGreConfigIni(aGre) == WIZ_OK)
03139   {
03140     /* If were installing GRE locally, then update the app's uninstall command
03141      * to pass the local/private windows GRE key path to GRE's uninstaller
03142      * during uninstall. */
03143     if(sgProduct.greType == GRE_LOCAL)
03144       wsprintf(greUninstallCommand,
03145                "\"%s\" -mmi -ms -app \"%s %s\" -ua \"%s\" -reg_path %s",
03146                aGre->uninstallerAppPath,
03147                sgProduct.szProductNameInternal,
03148                sgProduct.szUserAgent,
03149                aGre->userAgent,
03150                sgProduct.grePrivateKey);
03151     else
03152       wsprintf(greUninstallCommand,
03153                "\"%s\" -mmi -ms -app \"%s %s\" -ua \"%s\"",
03154                aGre->uninstallerAppPath,
03155                sgProduct.szProductNameInternal,
03156                sgProduct.szUserAgent,
03157                aGre->userAgent);
03158     UpdateInstallLog(KEY_UNINSTALL_COMMAND, greUninstallCommand, DNU_UNINSTALL);
03159   }
03160   return(WIZ_OK);
03161 }
03162 
03163 /* Function: GetXpinstallPath()
03164  *       in: none.
03165  *      out: path to where xpinstall engine is at.
03166  *  purpose: To retrieve the full path of where a valid xpinstall engine is
03167  *           installed at.
03168  *           * If we're using xpcom.xpi, then append 'bin' to the returned
03169  *             path because when xpcom.xpi is uncompressed, xpinstall will be
03170  *             within a 'bin' subdir.
03171  *           * If we're using GRE, then simply just return the GRE
03172  *             destination path.
03173  */
03174 void GetXpinstallPath(char *aPath, int aPathBufSize)
03175 {
03176   if(siCFXpcomFile.bStatus == STATUS_ENABLED)
03177   {
03178     MozCopyStr(siCFXpcomFile.szDestination, aPath, aPathBufSize);
03179     AppendBackSlash(aPath, aPathBufSize);
03180     lstrcat(aPath, "bin");
03181   }
03182   else
03183     MozCopyStr(gGre.homePath, aPath, aPathBufSize);
03184 }
03185 
03186 /* Function: ProcessXpinstallEngine()
03187  *       in: none.
03188  *      out: none.
03189  *  purpose: To setup the xpinstall engine either by:
03190  *             1) uncompressing xpcom.xpi into the temp dir.
03191  *             2) locating existing compatible version of GRE.
03192  *             3) installing GRE that was downloaded with this product.
03193  *
03194  *           Since GRE installer uses the same native installer as the Mozilla
03195  *           installer, xpcom.xpi should be used only by the GRE installer.
03196  *           All other installers should be using GRE (either finding one on
03197  *           the local system, or installer its own copy).
03198  */
03199 HRESULT ProcessXpinstallEngine()
03200 {
03201   HRESULT rv = WIZ_OK;
03202 
03203   /* If product to be installed is _not_ GRE, then call ProcessGRE.
03204    * ProcessGre() will either install GRE or simply run the existing
03205    * GRE's installer that's already on the system.  This will setup
03206    * GRE so it can be used as the xpinstall engine (if it's needed).
03207    */
03208   if(!IsInstallerProductGRE())
03209     rv = ProcessGre(&gGre);
03210 
03211   if(*siCFXpcomFile.szMessage != '\0')
03212     ShowMessage(siCFXpcomFile.szMessage, TRUE);
03213 
03214   if((WIZ_OK == rv) && (siCFXpcomFile.bStatus == STATUS_ENABLED))
03215     rv = ProcessXpcomFile();
03216 
03217   return(rv);
03218 }
03219 
03220 char *GetOSTypeString(char *szOSType, DWORD dwOSTypeBufSize)
03221 {
03222   ZeroMemory(szOSType, dwOSTypeBufSize);
03223 
03224   if(gSystemInfo.dwOSType & OS_WIN95_DEBUTE)
03225     lstrcpy(szOSType, "Win95 debute");
03226   else if(gSystemInfo.dwOSType & OS_WIN95)
03227     lstrcpy(szOSType, "Win95");
03228   else if(gSystemInfo.dwOSType & OS_WIN98)
03229     lstrcpy(szOSType, "Win98");
03230   else if(gSystemInfo.dwOSType & OS_NT3)
03231     lstrcpy(szOSType, "NT3");
03232   else if(gSystemInfo.dwOSType & OS_NT4)
03233     lstrcpy(szOSType, "NT4");
03234   else if(gSystemInfo.dwOSType & OS_NT50)
03235     lstrcpy(szOSType, "NT50");
03236   else if(gSystemInfo.dwOSType & OS_NT51)
03237     lstrcpy(szOSType, "NT51");
03238   else
03239     lstrcpy(szOSType, "NT5");
03240 
03241   return(szOSType);
03242 }
03243 
03244 void DetermineOSVersionEx()
03245 {
03246   BOOL          bIsWin95Debute;
03247   char          szBuf[MAX_BUF];
03248   char          szOSType[MAX_BUF];
03249   char          szESetupRequirement[MAX_BUF];
03250   DWORD         dwStrLen;
03251   OSVERSIONINFO osVersionInfo;
03252   MEMORYSTATUS  msMemoryInfo;
03253 
03254   gSystemInfo.dwOSType = 0;
03255   osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
03256   if(!GetVersionEx(&osVersionInfo))
03257   {
03258     /* GetVersionEx() failed for some reason.  It's not fatal, but could cause
03259      * some complications during installation */
03260     char szEMsg[MAX_BUF_TINY];
03261 
03262     if(GetPrivateProfileString("Messages", "ERROR_GETVERSION", "", szEMsg, sizeof(szEMsg), szFileIniInstall))
03263       PrintError(szEMsg, ERROR_CODE_SHOW);
03264   }
03265 
03266   bIsWin95Debute  = IsWin95Debute();
03267   switch(osVersionInfo.dwPlatformId)
03268   {
03269     case VER_PLATFORM_WIN32_WINDOWS:
03270       gSystemInfo.dwOSType |= OS_WIN9x;
03271       if(osVersionInfo.dwMinorVersion == 0)
03272       {
03273         gSystemInfo.dwOSType |= OS_WIN95;
03274         if(bIsWin95Debute)
03275           gSystemInfo.dwOSType |= OS_WIN95_DEBUTE;
03276       }
03277       else
03278         gSystemInfo.dwOSType |= OS_WIN98;
03279       break;
03280 
03281     case VER_PLATFORM_WIN32_NT:
03282       gSystemInfo.dwOSType |= OS_NT;
03283       switch(osVersionInfo.dwMajorVersion)
03284       {
03285         case 3:
03286           gSystemInfo.dwOSType |= OS_NT3;
03287           break;
03288 
03289         case 4:
03290           gSystemInfo.dwOSType |= OS_NT4;
03291           break;
03292 
03293         default:
03294           gSystemInfo.dwOSType |= OS_NT5;
03295           switch(osVersionInfo.dwMinorVersion)
03296           {
03297             case 0:
03298               /* a minor version of 0 (major.minor.build) indicates Win2000 */
03299               gSystemInfo.dwOSType |= OS_NT50;
03300               break;
03301 
03302             case 1:
03303               /* a minor version of 1 (major.minor.build) indicates WinXP */
03304               gSystemInfo.dwOSType |= OS_NT51;
03305           break;
03306       }
03307       break;
03308       }
03309       break;
03310 
03311     default:
03312       if(GetPrivateProfileString("Messages", "ERROR_SETUP_REQUIREMENT", "", szESetupRequirement, sizeof(szESetupRequirement), szFileIniInstall))
03313         PrintError(szESetupRequirement, ERROR_CODE_HIDE);
03314       break;
03315   }
03316 
03317   gSystemInfo.dwMajorVersion = osVersionInfo.dwMajorVersion;
03318   gSystemInfo.dwMinorVersion = osVersionInfo.dwMinorVersion;
03319   gSystemInfo.dwBuildNumber  = (DWORD)(LOWORD(osVersionInfo.dwBuildNumber));
03320 
03321   dwStrLen = sizeof(gSystemInfo.szExtraString) >
03322                     lstrlen(osVersionInfo.szCSDVersion) ?
03323                     lstrlen(osVersionInfo.szCSDVersion) :
03324                     sizeof(gSystemInfo.szExtraString) - 1;
03325   ZeroMemory(gSystemInfo.szExtraString, sizeof(gSystemInfo.szExtraString));
03326   strncpy(gSystemInfo.szExtraString, osVersionInfo.szCSDVersion, dwStrLen);
03327 
03328   msMemoryInfo.dwLength = sizeof(MEMORYSTATUS);
03329   GlobalMemoryStatus(&msMemoryInfo);
03330   gSystemInfo.dwMemoryTotalPhysical = msMemoryInfo.dwTotalPhys/1024;
03331   gSystemInfo.dwMemoryAvailablePhysical = msMemoryInfo.dwAvailPhys/1024;
03332 
03333   GetOSTypeString(szOSType, sizeof(szOSType));
03334   wsprintf(szBuf,
03335 "    System Info:\n\
03336         OS Type: %s\n\
03337         Major Version: %d\n\
03338         Minor Version: %d\n\
03339         Build Number: %d\n\
03340         Extra String: %s\n\
03341         Total Physical Memory: %dKB\n\
03342         Total Available Physical Memory: %dKB\n",
03343            szOSType,
03344            gSystemInfo.dwMajorVersion,
03345            gSystemInfo.dwMinorVersion,
03346            gSystemInfo.dwBuildNumber,
03347            gSystemInfo.szExtraString,
03348            gSystemInfo.dwMemoryTotalPhysical,
03349            gSystemInfo.dwMemoryAvailablePhysical);
03350 
03351   UpdateInstallStatusLog(szBuf);
03352 }
03353 
03354 HRESULT WinSpawn(LPSTR szClientName, LPSTR szParameters, LPSTR szCurrentDir, int iShowCmd, BOOL bWait)
03355 {
03356   SHELLEXECUTEINFO seInfo;
03357 
03358   seInfo.cbSize       = sizeof(SHELLEXECUTEINFO);
03359   seInfo.fMask        = SEE_MASK_DOENVSUBST | SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS;
03360   seInfo.hwnd         = hWndMain;
03361   seInfo.lpVerb       = NULL;
03362   seInfo.lpFile       = szClientName;
03363   seInfo.lpParameters = szParameters;
03364   seInfo.lpDirectory  = szCurrentDir;
03365   seInfo.nShow        = SW_SHOWNORMAL;
03366   seInfo.hInstApp     = 0;
03367   seInfo.lpIDList     = NULL;
03368   seInfo.lpClass      = NULL;
03369   seInfo.hkeyClass    = 0;
03370   seInfo.dwHotKey     = 0;
03371   seInfo.hIcon        = 0;
03372   seInfo.hProcess     = 0;
03373 
03374   if((ShellExecuteEx(&seInfo) != 0) && (seInfo.hProcess != NULL))
03375   {
03376     if(bWait)
03377     {
03378       for(;;)
03379       {
03380         if(WaitForSingleObject(seInfo.hProcess, 200) == WAIT_OBJECT_0)
03381           break;
03382 
03383         ProcessWindowsMessages();
03384       }
03385     }
03386     return(TRUE);
03387   }
03388   return(FALSE);
03389 }
03390 
03391 HRESULT InitDlgWelcome(diW *diDialog)
03392 {
03393   diDialog->bShowDialog = FALSE;
03394   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03395     return(1);
03396   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03397     return(1);
03398   if((diDialog->szMessage1 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03399     return(1);
03400   if((diDialog->szMessage2 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03401     return(1);
03402 
03403   return(0);
03404 }
03405 
03406 void DeInitDlgWelcome(diW *diDialog)
03407 {
03408   FreeMemory(&(diDialog->szTitle));
03409   FreeMemory(&(diDialog->szMessage0));
03410   FreeMemory(&(diDialog->szMessage1));
03411   FreeMemory(&(diDialog->szMessage2));
03412 }
03413 
03414 HRESULT InitDlgLicense(diL *diDialog)
03415 {
03416   diDialog->bShowDialog = FALSE;
03417   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03418     return(1);
03419   if((diDialog->szLicenseFilename = NS_GlobalAlloc(MAX_BUF)) == NULL)
03420     return(1);
03421   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03422     return(1);
03423   if((diDialog->szMessage1 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03424     return(1);
03425 
03426   return(0);
03427 }
03428 
03429 void DeInitDlgLicense(diL *diDialog)
03430 {
03431   FreeMemory(&(diDialog->szTitle));
03432   FreeMemory(&(diDialog->szLicenseFilename));
03433   FreeMemory(&(diDialog->szMessage0));
03434   FreeMemory(&(diDialog->szMessage1));
03435 }
03436 
03437 HRESULT InitDlgQuickLaunch(diQL *diDialog)
03438 {
03439   diDialog->bTurboMode         = FALSE;
03440   diDialog->bTurboModeEnabled  = FALSE;
03441   diDialog->bShowDialog = FALSE;
03442   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03443     return(1);
03444   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03445     return(1);
03446   if((diDialog->szMessage1 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03447     return(1);
03448   if((diDialog->szMessage2 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03449     return(1);
03450 
03451   return(0);
03452 }
03453 
03454 void DeInitDlgQuickLaunch(diQL *diDialog)
03455 {
03456   FreeMemory(&(diDialog->szTitle));
03457   FreeMemory(&(diDialog->szMessage0));
03458   FreeMemory(&(diDialog->szMessage1));
03459   FreeMemory(&(diDialog->szMessage2));
03460 }
03461 
03462 HRESULT InitDlgSetupType(diST *diDialog)
03463 {
03464   diDialog->bShowDialog = FALSE;
03465 
03466   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03467     return(1);
03468   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03469     return(1);
03470   if((diDialog->szReadmeFilename = NS_GlobalAlloc(MAX_BUF)) == NULL)
03471     return(1);
03472   if((diDialog->szReadmeApp = NS_GlobalAlloc(MAX_BUF)) == NULL)
03473     return(1);
03474 
03475   diDialog->stSetupType0.dwCItems = 0;
03476   diDialog->stSetupType1.dwCItems = 0;
03477   diDialog->stSetupType2.dwCItems = 0;
03478   diDialog->stSetupType3.dwCItems = 0;
03479   if((diDialog->stSetupType0.szDescriptionShort = NS_GlobalAlloc(MAX_BUF)) == NULL)
03480     return(1);
03481   if((diDialog->stSetupType0.szDescriptionLong = NS_GlobalAlloc(MAX_BUF)) == NULL)
03482     return(1);
03483 
03484   if((diDialog->stSetupType1.szDescriptionShort = NS_GlobalAlloc(MAX_BUF)) == NULL)
03485     return(1);
03486   if((diDialog->stSetupType1.szDescriptionLong = NS_GlobalAlloc(MAX_BUF)) == NULL)
03487     return(1);
03488 
03489   if((diDialog->stSetupType2.szDescriptionShort = NS_GlobalAlloc(MAX_BUF)) == NULL)
03490     return(1);
03491   if((diDialog->stSetupType2.szDescriptionLong = NS_GlobalAlloc(MAX_BUF)) == NULL)
03492     return(1);
03493 
03494   if((diDialog->stSetupType3.szDescriptionShort = NS_GlobalAlloc(MAX_BUF)) == NULL)
03495     return(1);
03496   if((diDialog->stSetupType3.szDescriptionLong = NS_GlobalAlloc(MAX_BUF)) == NULL)
03497     return(1);
03498 
03499   return(0);
03500 }
03501 
03502 void DeInitDlgSetupType(diST *diDialog)
03503 {
03504   FreeMemory(&(diDialog->szTitle));
03505   FreeMemory(&(diDialog->szMessage0));
03506 
03507   FreeMemory(&(diDialog->szReadmeFilename));
03508   FreeMemory(&(diDialog->szReadmeApp));
03509   FreeMemory(&(diDialog->stSetupType0.szDescriptionShort));
03510   FreeMemory(&(diDialog->stSetupType0.szDescriptionLong));
03511   FreeMemory(&(diDialog->stSetupType1.szDescriptionShort));
03512   FreeMemory(&(diDialog->stSetupType1.szDescriptionLong));
03513   FreeMemory(&(diDialog->stSetupType2.szDescriptionShort));
03514   FreeMemory(&(diDialog->stSetupType2.szDescriptionLong));
03515   FreeMemory(&(diDialog->stSetupType3.szDescriptionShort));
03516   FreeMemory(&(diDialog->stSetupType3.szDescriptionLong));
03517 }
03518 
03519 HRESULT InitDlgSelectComponents(diSC *diDialog, DWORD dwSM)
03520 {
03521   diDialog->bShowDialog = FALSE;
03522 
03523   /* set to show the Single dialog or the Multi dialog for the SelectComponents dialog */
03524   diDialog->bShowDialogSM = dwSM;
03525   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03526     return(1);
03527   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03528     return(1);
03529 
03530   return(0);
03531 }
03532 
03533 void DeInitDlgSelectComponents(diSC *diDialog)
03534 {
03535   FreeMemory(&(diDialog->szTitle));
03536   FreeMemory(&(diDialog->szMessage0));
03537 }
03538 
03539 HRESULT InitDlgWindowsIntegration(diWI *diDialog)
03540 {
03541   diDialog->bShowDialog = FALSE;
03542   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03543     exit(1);
03544   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03545     exit(1);
03546   if((diDialog->szMessage1 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03547     exit(1);
03548 
03549   diDialog->wiCB0.bEnabled = FALSE;
03550   diDialog->wiCB1.bEnabled = FALSE;
03551   diDialog->wiCB2.bEnabled = FALSE;
03552   diDialog->wiCB3.bEnabled = FALSE;
03553 
03554   diDialog->wiCB0.bCheckBoxState = FALSE;
03555   diDialog->wiCB1.bCheckBoxState = FALSE;
03556   diDialog->wiCB2.bCheckBoxState = FALSE;
03557   diDialog->wiCB3.bCheckBoxState = FALSE;
03558 
03559   if((diDialog->wiCB0.szDescription = NS_GlobalAlloc(MAX_BUF)) == NULL)
03560     return(1);
03561   if((diDialog->wiCB1.szDescription = NS_GlobalAlloc(MAX_BUF)) == NULL)
03562     return(1);
03563   if((diDialog->wiCB2.szDescription = NS_GlobalAlloc(MAX_BUF)) == NULL)
03564     return(1);
03565   if((diDialog->wiCB3.szDescription = NS_GlobalAlloc(MAX_BUF)) == NULL)
03566     return(1);
03567 
03568   if((diDialog->wiCB0.szArchive = NS_GlobalAlloc(MAX_BUF)) == NULL)
03569     return(1);
03570   if((diDialog->wiCB1.szArchive = NS_GlobalAlloc(MAX_BUF)) == NULL)
03571     return(1);
03572   if((diDialog->wiCB2.szArchive = NS_GlobalAlloc(MAX_BUF)) == NULL)
03573     return(1);
03574   if((diDialog->wiCB3.szArchive = NS_GlobalAlloc(MAX_BUF)) == NULL)
03575     return(1);
03576 
03577   return(0);
03578 }
03579 
03580 void DeInitDlgWindowsIntegration(diWI *diDialog)
03581 {
03582   FreeMemory(&(diDialog->szTitle));
03583   FreeMemory(&(diDialog->szMessage0));
03584   FreeMemory(&(diDialog->szMessage1));
03585 
03586   FreeMemory(&(diDialog->wiCB0.szDescription));
03587   FreeMemory(&(diDialog->wiCB1.szDescription));
03588   FreeMemory(&(diDialog->wiCB2.szDescription));
03589   FreeMemory(&(diDialog->wiCB3.szDescription));
03590   FreeMemory(&(diDialog->wiCB0.szArchive));
03591   FreeMemory(&(diDialog->wiCB1.szArchive));
03592   FreeMemory(&(diDialog->wiCB2.szArchive));
03593   FreeMemory(&(diDialog->wiCB3.szArchive));
03594 }
03595 
03596 HRESULT InitDlgProgramFolder(diPF *diDialog)
03597 {
03598   diDialog->bShowDialog = FALSE;
03599   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03600     return(1);
03601   if((diDialog->szMessage0 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03602     return(1);
03603 
03604   return(0);
03605 }
03606 
03607 void DeInitDlgProgramFolder(diPF *diDialog)
03608 {
03609   FreeMemory(&(diDialog->szTitle));
03610   FreeMemory(&(diDialog->szMessage0));
03611 }
03612 
03613 HRESULT InitDlgAdditionalOptions(diDO *diDialog)
03614 {
03615   diDialog->bShowDialog           = FALSE;
03616   diDialog->bSaveInstaller        = FALSE;
03617   diDialog->bRecaptureHomepage    = FALSE;
03618   diDialog->bShowHomepageOption   = FALSE;
03619   diDialog->dwUseProtocol         = UP_FTP;
03620   diDialog->bUseProtocolSettings  = TRUE;
03621   diDialog->bShowProtocols        = TRUE;
03622   if((diDialog->szTitle           = NS_GlobalAlloc(MAX_BUF)) == NULL)
03623     return(1);
03624   if((diDialog->szMessage0        = NS_GlobalAlloc(MAX_BUF)) == NULL)
03625     return(1);
03626   if((diDialog->szMessage1        = NS_GlobalAlloc(MAX_BUF)) == NULL)
03627     return(1);
03628 
03629   return(0);
03630 }
03631 
03632 void DeInitDlgAdditionalOptions(diDO *diDialog)
03633 {
03634   FreeMemory(&(diDialog->szTitle));
03635   FreeMemory(&(diDialog->szMessage0));
03636   FreeMemory(&(diDialog->szMessage1));
03637 }
03638 
03639 HRESULT InitDlgAdvancedSettings(diAS *diDialog)
03640 {
03641   diDialog->bShowDialog       = FALSE;
03642   if((diDialog->szTitle       = NS_GlobalAlloc(MAX_BUF)) == NULL)
03643     return(1);
03644   if((diDialog->szMessage0    = NS_GlobalAlloc(MAX_BUF)) == NULL)
03645     return(1);
03646   if((diDialog->szProxyServer = NS_GlobalAlloc(MAX_BUF)) == NULL)
03647     return(1);
03648   if((diDialog->szProxyPort   = NS_GlobalAlloc(MAX_BUF)) == NULL)
03649     return(1);
03650   if((diDialog->szProxyUser   = NS_GlobalAlloc(MAX_BUF)) == NULL)
03651     return(1);
03652   if((diDialog->szProxyPasswd = NS_GlobalAlloc(MAX_BUF)) == NULL)
03653     return(1);
03654 
03655   return(0);
03656 }
03657 
03658 void DeInitDlgAdvancedSettings(diAS *diDialog)
03659 {
03660   FreeMemory(&(diDialog->szTitle));
03661   FreeMemory(&(diDialog->szMessage0));
03662   FreeMemory(&(diDialog->szProxyServer));
03663   FreeMemory(&(diDialog->szProxyPort));
03664   FreeMemory(&(diDialog->szProxyUser));
03665   FreeMemory(&(diDialog->szProxyPasswd));
03666 }
03667 
03668 HRESULT InitDlgStartInstall(diSI *diDialog)
03669 {
03670   diDialog->bShowDialog        = FALSE;
03671   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF)) == NULL)
03672     return(1);
03673   if((diDialog->szMessageInstall = NS_GlobalAlloc(MAX_BUF)) == NULL)
03674     return(1);
03675   if((diDialog->szMessageDownload = NS_GlobalAlloc(MAX_BUF)) == NULL)
03676     return(1);
03677 
03678   return(0);
03679 }
03680 
03681 void DeInitDlgStartInstall(diSI *diDialog)
03682 {
03683   FreeMemory(&(diDialog->szTitle));
03684   FreeMemory(&(diDialog->szMessageInstall));
03685   FreeMemory(&(diDialog->szMessageDownload));
03686 }
03687 
03688 HRESULT InitDlgDownload(diD *diDialog)
03689 {
03690   diDialog->bShowDialog = FALSE;
03691   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF_TINY)) == NULL)
03692     return(1);
03693   if((diDialog->szMessageDownload0 = NS_GlobalAlloc(MAX_BUF_MEDIUM)) == NULL)
03694     return(1);
03695   if((diDialog->szMessageRetry0 = NS_GlobalAlloc(MAX_BUF_MEDIUM)) == NULL)
03696     return(1);
03697 
03698   return(0);
03699 }
03700 
03701 void DeInitDlgDownload(diD *diDialog)
03702 {
03703   FreeMemory(&(diDialog->szTitle));
03704   FreeMemory(&(diDialog->szMessageDownload0));
03705   FreeMemory(&(diDialog->szMessageRetry0));
03706 }
03707 
03708 DWORD InitDlgReboot(diR *diDialog)
03709 {
03710   diDialog->dwShowDialog = FALSE;
03711   if((diDialog->szTitle = NS_GlobalAlloc(MAX_BUF_MEDIUM)) == NULL)
03712     return(1);
03713   GetPrivateProfileString("Messages", "DLG_REBOOT_TITLE", "", diDialog->szTitle, MAX_BUF_MEDIUM, szFileIniInstall);
03714 
03715   return(0);
03716 }
03717 
03718 void DeInitDlgReboot(diR *diDialog)
03719 {
03720   FreeMemory(&(diDialog->szTitle));
03721 }
03722 
03723 HRESULT InitSetupGeneral()
03724 {
03725   gSystemInfo.bRefreshIcons      = FALSE; 
03726   sgProduct.mode                 = NOT_SET;
03727   sgProduct.bSharedInst          = FALSE;
03728   sgProduct.bInstallFiles        = TRUE;
03729   sgProduct.checkCleanupOnUpgrade = FALSE;
03730   sgProduct.doCleanupOnUpgrade    = FALSE;
03731   sgProduct.greType              = GRE_TYPE_NOT_SET;
03732   sgProduct.dwCustomType         = ST_RADIO0;
03733   sgProduct.dwNumberOfComponents = 0;
03734   sgProduct.bLockPath            = FALSE;
03735 
03736   if((sgProduct.szPath                        = NS_GlobalAlloc(MAX_BUF)) == NULL)
03737     return(1);
03738   if((sgProduct.szSubPath                     = NS_GlobalAlloc(MAX_BUF)) == NULL)
03739     return(1);
03740   if((sgProduct.szProgramName                 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03741     return(1);
03742   if((sgProduct.szCompanyName                 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03743     return(1);
03744   if((sgProduct.szProductName                 = NS_GlobalAlloc(MAX_BUF)) == NULL)
03745     return(1);
03746   if((sgProduct.szProductNameInternal         = NS_GlobalAlloc(MAX_BUF)) == NULL)
03747     return(1);
03748   if((sgProduct.szProductNamePrevious         = NS_GlobalAlloc(MAX_BUF)) == NULL)
03749     return(1);
03750   if((sgProduct.szUninstallFilename           = NS_GlobalAlloc(MAX_BUF)) == NULL)
03751     return(1);
03752   if((sgProduct.szUserAgent                   = NS_GlobalAlloc(MAX_BUF)) == NULL)
03753     return(1);
03754   if((sgProduct.szProgramFolderName           = NS_GlobalAlloc(MAX_BUF)) == NULL)
03755     return(1);
03756   if((sgProduct.szProgramFolderPath           = NS_GlobalAlloc(MAX_BUF)) == NULL)
03757     return(1);
03758   if((sgProduct.szAlternateArchiveSearchPath  = NS_GlobalAlloc(MAX_BUF)) == NULL)
03759     return(1);
03760   if((sgProduct.szParentProcessFilename       = NS_GlobalAlloc(MAX_BUF)) == NULL)
03761     return(1);
03762   if((szTempSetupPath                         = NS_GlobalAlloc(MAX_BUF)) == NULL)
03763     return(1);
03764 
03765   if((szSiteSelectorDescription               = NS_GlobalAlloc(MAX_BUF)) == NULL)
03766     return(1);
03767   if((sgProduct.szAppID                       = NS_GlobalAlloc(MAX_BUF)) == NULL)
03768     return(1);
03769   if((sgProduct.szAppPath                     = NS_GlobalAlloc(MAX_BUF)) == NULL)
03770     return(1);
03771   if((sgProduct.szRegPath                     = NS_GlobalAlloc(MAX_BUF)) == NULL)
03772     return(1);
03773 
03774   sgProduct.greCleanupOrphans = FALSE;
03775   *sgProduct.greCleanupOrphansMessage = '\0';
03776   *sgProduct.greID         = '\0';
03777   *sgProduct.grePrivateKey = '\0';
03778   return(0);
03779 }
03780 
03781 void DeInitSetupGeneral()
03782 {
03783   FreeMemory(&(sgProduct.szPath));
03784   FreeMemory(&(sgProduct.szSubPath));
03785   FreeMemory(&(sgProduct.szProgramName));
03786   FreeMemory(&(sgProduct.szCompanyName));
03787   FreeMemory(&(sgProduct.szProductName));
03788   FreeMemory(&(sgProduct.szProductNameInternal));
03789   FreeMemory(&(sgProduct.szProductNamePrevious));
03790   FreeMemory(&(sgProduct.szUninstallFilename));
03791   FreeMemory(&(sgProduct.szUserAgent));
03792   FreeMemory(&(sgProduct.szProgramFolderName));
03793   FreeMemory(&(sgProduct.szProgramFolderPath));
03794   FreeMemory(&(sgProduct.szAlternateArchiveSearchPath));
03795   FreeMemory(&(sgProduct.szParentProcessFilename));
03796   FreeMemory(&(sgProduct.szAppID));
03797   FreeMemory(&(sgProduct.szAppPath));
03798   FreeMemory(&(sgProduct.szRegPath));
03799   FreeMemory(&(szTempSetupPath));
03800   FreeMemory(&(szSiteSelectorDescription));
03801 }
03802 
03803 HRESULT InitSDObject()
03804 {
03805   if((siSDObject.szXpcomFile = NS_GlobalAlloc(MAX_BUF)) == NULL)
03806     return(1);
03807   if((siSDObject.szXpcomDir = NS_GlobalAlloc(MAX_BUF)) == NULL)
03808     return(1);
03809   if((siSDObject.szNoAds = NS_GlobalAlloc(MAX_BUF)) == NULL)
03810     return(1);
03811   if((siSDObject.szSilent = NS_GlobalAlloc(MAX_BUF)) == NULL)
03812     return(1);
03813   if((siSDObject.szExecution = NS_GlobalAlloc(MAX_BUF)) == NULL)
03814     return(1);
03815   if((siSDObject.szConfirmInstall = NS_GlobalAlloc(MAX_BUF)) == NULL)
03816     return(1);
03817   if((siSDObject.szExtractMsg = NS_GlobalAlloc(MAX_BUF)) == NULL)
03818     return(1);
03819   if((siSDObject.szExe = NS_GlobalAlloc(MAX_BUF)) == NULL)
03820     return(1);
03821   if((siSDObject.szExeParam = NS_GlobalAlloc(MAX_BUF)) == NULL)
03822     return(1);
03823   if((siSDObject.szXpcomFilePath = NS_GlobalAlloc(MAX_BUF)) == NULL)
03824     return(1);
03825 
03826   return(0);
03827 }
03828 
03829 void DeInitSDObject()
03830 {
03831   FreeMemory(&(siSDObject.szXpcomFile));
03832   FreeMemory(&(siSDObject.szXpcomDir));
03833   FreeMemory(&(siSDObject.szNoAds));
03834   FreeMemory(&(siSDObject.szSilent));
03835   FreeMemory(&(siSDObject.szExecution));
03836   FreeMemory(&(siSDObject.szConfirmInstall));
03837   FreeMemory(&(siSDObject.szExtractMsg));
03838   FreeMemory(&(siSDObject.szExe));
03839   FreeMemory(&(siSDObject.szExeParam));
03840   FreeMemory(&(siSDObject.szXpcomFilePath));
03841 }
03842 
03843 HRESULT InitSXpcomFile()
03844 {
03845   if((siCFXpcomFile.szSource = NS_GlobalAlloc(MAX_BUF)) == NULL)
03846     return(1);
03847   if((siCFXpcomFile.szDestination = NS_GlobalAlloc(MAX_BUF)) == NULL)
03848     return(1);
03849   if((siCFXpcomFile.szMessage = NS_GlobalAlloc(MAX_BUF)) == NULL)
03850     return(1);
03851 
03852   siCFXpcomFile.bCleanup         = TRUE;
03853   siCFXpcomFile.bStatus          = STATUS_ENABLED;
03854   siCFXpcomFile.ullInstallSize   = 0;
03855   return(0);
03856 }
03857 
03858 void DeInitSXpcomFile()
03859 {
03860   FreeMemory(&(siCFXpcomFile.szSource));
03861   FreeMemory(&(siCFXpcomFile.szDestination));
03862   FreeMemory(&(siCFXpcomFile.szMessage));
03863 }
03864 
03865 /* Function: InitGre()
03866  *       in: gre structure.
03867  *      out: gre structure.
03868  *  purpose: To initialize a newly created greInfo structure.
03869  */
03870 HRESULT InitGre(greInfo *gre)
03871 {
03872   gre->homePath[0]           = '\0';
03873   gre->installerAppPath[0]   = '\0';
03874   gre->uninstallerAppPath[0] = '\0';
03875   gre->userAgent[0]          = '\0';
03876   gre->minVersion.ullMajor   = 0;
03877   gre->minVersion.ullMinor   = 0;
03878   gre->minVersion.ullRelease = 0;
03879   gre->minVersion.ullBuild   = 0;
03880   gre->maxVersion.ullMajor   = 0;
03881   gre->maxVersion.ullMinor   = 0;
03882   gre->maxVersion.ullRelease = 0;
03883   gre->maxVersion.ullBuild   = 0;
03884   gre->greSupersedeList      = NULL;
03885   gre->greInstalledList      = NULL;
03886   gre->siCGreComponent       = NULL;
03887   return(WIZ_OK);
03888 }
03889 
03890 /* Function: DeInitGre()
03891  *       in: gre structure.
03892  *      out: gre structure.
03893  *  purpose: To cleanup allocated memory to a greInfo structure.
03894  */
03895 void DeInitGre(greInfo *gre)
03896 {
03897   DeleteGverList(gre->greSupersedeList);
03898   DeleteGverList(gre->greInstalledList);
03899 }
03900 
03901 siC *CreateSiCNode()
03902 {
03903   siC *siCNode;
03904 
03905   if((siCNode = NS_GlobalAlloc(sizeof(struct sinfoComponent))) == NULL)
03906     exit(1);
03907 
03908   siCNode->dwAttributes             = 0;
03909   siCNode->ullInstallSize           = 0;
03910   siCNode->ullInstallSizeSystem     = 0;
03911   siCNode->ullInstallSizeArchive    = 0;
03912   siCNode->lRandomInstallPercentage = 0;
03913   siCNode->lRandomInstallValue      = 0;
03914   siCNode->bForceUpgrade            = FALSE;
03915 
03916   if((siCNode->szArchiveName = NS_GlobalAlloc(MAX_BUF)) == NULL)
03917     exit(1);
03918   if((siCNode->szArchiveNameUncompressed = NS_GlobalAlloc(MAX_BUF)) == NULL)
03919     exit(1);
03920   if((siCNode->szArchivePath = NS_GlobalAlloc(MAX_BUF)) == NULL)
03921     exit(1);
03922   if((siCNode->szDestinationPath = NS_GlobalAlloc(MAX_BUF)) == NULL)
03923     exit(1);
03924   if((siCNode->szDescriptionShort = NS_GlobalAlloc(MAX_BUF)) == NULL)
03925     exit(1);
03926   if((siCNode->szDescriptionLong = NS_GlobalAlloc(MAX_BUF)) == NULL)
03927     exit(1);
03928   if((siCNode->szParameter = NS_GlobalAlloc(MAX_BUF)) == NULL)
03929     exit(1);
03930   if((siCNode->szReferenceName = NS_GlobalAlloc(MAX_BUF)) == NULL)
03931     exit(1);
03932 
03933   siCNode->iNetRetries      = 0;
03934   siCNode->iCRCRetries      = 0;
03935   siCNode->iNetTimeOuts     = 0;
03936   siCNode->siCDDependencies = NULL;
03937   siCNode->siCDDependees    = NULL;
03938   siCNode->Next             = NULL;
03939   siCNode->Prev             = NULL;
03940 
03941   return(siCNode);
03942 }
03943 
03944 void SiCNodeInsert(siC **siCHead, siC *siCTemp)
03945 {
03946   if(*siCHead == NULL)
03947   {
03948     *siCHead          = siCTemp;
03949     (*siCHead)->Next  = *siCHead;
03950     (*siCHead)->Prev  = *siCHead;
03951   }
03952   else
03953   {
03954     siCTemp->Next           = *siCHead;
03955     siCTemp->Prev           = (*siCHead)->Prev;
03956     (*siCHead)->Prev->Next  = siCTemp;
03957     (*siCHead)->Prev        = siCTemp;
03958   }
03959 }
03960 
03961 void SiCNodeDelete(siC *siCTemp)
03962 {
03963   if(siCTemp != NULL)
03964   {
03965     DeInitSiCDependencies(siCTemp->siCDDependencies);
03966     DeInitSiCDependencies(siCTemp->siCDDependees);
03967 
03968     siCTemp->Next->Prev = siCTemp->Prev;
03969     siCTemp->Prev->Next = siCTemp->Next;
03970     siCTemp->Next       = NULL;
03971     siCTemp->Prev       = NULL;
03972 
03973     FreeMemory(&(siCTemp->szDestinationPath));
03974     FreeMemory(&(siCTemp->szArchivePath));
03975     FreeMemory(&(siCTemp->szArchiveName));
03976     FreeMemory(&(siCTemp->szArchiveNameUncompressed));
03977     FreeMemory(&(siCTemp->szParameter));
03978     FreeMemory(&(siCTemp->szReferenceName));
03979     FreeMemory(&(siCTemp->szDescriptionLong));
03980     FreeMemory(&(siCTemp->szDescriptionShort));
03981     FreeMemory(&siCTemp);
03982   }
03983 }
03984 
03985 siCD *CreateSiCDepNode()
03986 {
03987   siCD *siCDepNode;
03988 
03989   if((siCDepNode = NS_GlobalAlloc(sizeof(struct sinfoComponentDep))) == NULL)
03990     exit(1);
03991 
03992   if((siCDepNode->szDescriptionShort = NS_GlobalAlloc(MAX_BUF)) == NULL)
03993     exit(1);
03994   if((siCDepNode->szReferenceName = NS_GlobalAlloc(MAX_BUF)) == NULL)
03995     exit(1);
03996   siCDepNode->Next = NULL;
03997   siCDepNode->Prev = NULL;
03998 
03999   return(siCDepNode);
04000 }
04001 
04002 void SiCDepNodeInsert(siCD **siCDepHead, siCD *siCDepTemp)
04003 {
04004   if(*siCDepHead == NULL)
04005   {
04006     *siCDepHead          = siCDepTemp;
04007     (*siCDepHead)->Next  = *siCDepHead;
04008     (*siCDepHead)->Prev  = *siCDepHead;
04009   }
04010   else
04011   {
04012     siCDepTemp->Next           = *siCDepHead;
04013     siCDepTemp->Prev           = (*siCDepHead)->Prev;
04014     (*siCDepHead)->Prev->Next  = siCDepTemp;
04015     (*siCDepHead)->Prev        = siCDepTemp;
04016   }
04017 }
04018 
04019 void SiCDepNodeDelete(siCD *siCDepTemp)
04020 {
04021   if(siCDepTemp != NULL)
04022   {
04023     siCDepTemp->Next->Prev = siCDepTemp->Prev;
04024     siCDepTemp->Prev->Next = siCDepTemp->Next;
04025     siCDepTemp->Next       = NULL;
04026     siCDepTemp->Prev       = NULL;
04027 
04028     FreeMemory(&(siCDepTemp->szDescriptionShort));
04029     FreeMemory(&(siCDepTemp->szReferenceName));
04030     FreeMemory(&siCDepTemp);
04031   }
04032 }
04033 
04034 ssi *CreateSsiSiteSelectorNode()
04035 {
04036   ssi *ssiNode;
04037 
04038   if((ssiNode = NS_GlobalAlloc(sizeof(struct ssInfo))) == NULL)
04039     exit(1);
04040   if((ssiNode->szDescription = NS_GlobalAlloc(MAX_BUF)) == NULL)
04041     exit(1);
04042   if((ssiNode->szDomain = NS_GlobalAlloc(MAX_BUF)) == NULL)
04043     exit(1);
04044   if((ssiNode->szIdentifier = NS_GlobalAlloc(MAX_BUF)) == NULL)
04045     exit(1);
04046 
04047   ssiNode->Next = NULL;
04048   ssiNode->Prev = NULL;
04049 
04050   return(ssiNode);
04051 }
04052 
04053 void SsiSiteSelectorNodeInsert(ssi **ssiHead, ssi *ssiTemp)
04054 {
04055   if(*ssiHead == NULL)
04056   {
04057     *ssiHead          = ssiTemp;
04058     (*ssiHead)->Next  = *ssiHead;
04059     (*ssiHead)->Prev  = *ssiHead;
04060   }
04061   else
04062   {
04063     ssiTemp->Next           = *ssiHead;
04064     ssiTemp->Prev           = (*ssiHead)->Prev;
04065     (*ssiHead)->Prev->Next  = ssiTemp;
04066     (*ssiHead)->Prev        = ssiTemp;
04067   }
04068 }
04069 
04070 void SsiSiteSelectorNodeDelete(ssi *ssiTemp)
04071 {
04072   if(ssiTemp != NULL)
04073   {
04074     ssiTemp->Next->Prev = ssiTemp->Prev;
04075     ssiTemp->Prev->Next = ssiTemp->Next;
04076     ssiTemp->Next       = NULL;
04077     ssiTemp->Prev       = NULL;
04078 
04079     FreeMemory(&(ssiTemp->szDescription));
04080     FreeMemory(&(ssiTemp->szDomain));
04081     FreeMemory(&(ssiTemp->szIdentifier));
04082     FreeMemory(&ssiTemp);
04083   }
04084 }
04085 
04086 HRESULT SiCNodeGetAttributes(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04087 {
04088   DWORD dwCount = 0;
04089   siC   *siCTemp = siComponents;
04090 
04091   if(siCTemp != NULL)
04092   {
04093     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04094        ((dwACFlag == AC_ALL) ||
04095        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04096        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04097     {
04098       if(dwIndex == 0)
04099         return(siCTemp->dwAttributes);
04100 
04101       ++dwCount;
04102     }
04103 
04104     siCTemp = siCTemp->Next;
04105     while((siCTemp != NULL) && (siCTemp != siComponents))
04106     {
04107       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04108          ((dwACFlag == AC_ALL) ||
04109          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04110          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04111       {
04112         if(dwIndex == dwCount)
04113           return(siCTemp->dwAttributes);
04114 
04115         ++dwCount;
04116       }
04117       
04118       siCTemp = siCTemp->Next;
04119     }
04120   }
04121   return(-1);
04122 }
04123 
04124 void SiCNodeSetAttributes(DWORD dwIndex, DWORD dwAttributes, BOOL bSet, BOOL bIncludeInvisible, DWORD dwACFlag, HWND hwndListBox)
04125 {
04126   DWORD dwCount        = 0;
04127   DWORD dwVisibleIndex = 0;
04128   siC   *siCTemp       = siComponents;
04129 
04130   LPSTR szTmpString;
04131   TCHAR tchBuffer[MAX_BUF];
04132 
04133   if(siCTemp != NULL)
04134   {
04135     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04136        ((dwACFlag == AC_ALL) ||
04137        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04138        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04139     {
04140       if(dwIndex == 0)
04141       {
04142         if(bSet)
04143           siCTemp->dwAttributes |= dwAttributes;
04144         else
04145           siCTemp->dwAttributes &= ~dwAttributes;
04146 
04147         if((!(siCTemp->dwAttributes & SIC_INVISIBLE))
04148            && (dwAttributes == SIC_SELECTED) 
04149            && gSystemInfo.bScreenReader 
04150            && hwndListBox)
04151         {
04152           szTmpString = SiCNodeGetDescriptionShort(dwVisibleIndex, FALSE, dwACFlag);
04153           lstrcpy(tchBuffer, szTmpString);
04154           lstrcat(tchBuffer, " - ");
04155           if(bSet)
04156             lstrcat(tchBuffer, sgInstallGui.szChecked);
04157           else
04158             lstrcat(tchBuffer, sgInstallGui.szUnchecked);
04159 
04160           //We've got to actually change the text in the listbox for the screen reader to see it.
04161           SendMessage(hwndListBox, LB_INSERTSTRING, 0, (LPARAM)tchBuffer);
04162           SendMessage(hwndListBox, LB_DELETESTRING, 1, 0);
04163         }
04164       }
04165 
04166       ++dwCount;
04167       if(!(siCTemp->dwAttributes & SIC_INVISIBLE))
04168         ++dwVisibleIndex;
04169     }
04170 
04171     siCTemp = siCTemp->Next;
04172     while((siCTemp != NULL) && (siCTemp != siComponents))
04173     {
04174       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04175          ((dwACFlag == AC_ALL) ||
04176          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04177          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04178       {
04179         if(dwIndex == dwCount)
04180         {
04181           if(bSet)
04182             siCTemp->dwAttributes |= dwAttributes;
04183           else
04184             siCTemp->dwAttributes &= ~dwAttributes;
04185 
04186           if((!(siCTemp->dwAttributes & SIC_INVISIBLE))
04187              && (dwAttributes == SIC_SELECTED) 
04188              && gSystemInfo.bScreenReader 
04189              && hwndListBox)
04190           {
04191             szTmpString = SiCNodeGetDescriptionShort(dwVisibleIndex, FALSE, dwACFlag);
04192             lstrcpy(tchBuffer, szTmpString);
04193             lstrcat(tchBuffer, " - ");
04194             if(bSet)
04195               lstrcat(tchBuffer, sgInstallGui.szChecked);
04196             else
04197               lstrcat(tchBuffer, sgInstallGui.szUnchecked);
04198 
04199             //We've got to actually change the text in the listbox for the screen reader to see it.
04200             SendMessage(hwndListBox, LB_INSERTSTRING, dwVisibleIndex, (LPARAM)tchBuffer);
04201             SendMessage(hwndListBox, LB_DELETESTRING, dwVisibleIndex+1, 0);
04202           }
04203         }
04204 
04205         ++dwCount;
04206         if(!(siCTemp->dwAttributes & SIC_INVISIBLE))
04207           ++dwVisibleIndex;
04208       }
04209 
04210       siCTemp = siCTemp->Next;
04211     }
04212   }
04213 }
04214 
04215 BOOL IsInList(DWORD dwCurrentItem, DWORD dwItems, DWORD *dwItemsSelected)
04216 {
04217   DWORD i;
04218 
04219   for(i = 0; i < dwItems; i++)
04220   {
04221     if(dwItemsSelected[i] == dwCurrentItem)
04222       return(TRUE);
04223   }
04224 
04225   return(FALSE);
04226 }
04227 
04228 void RestoreInvisibleFlag(siC *siCNode)
04229 {
04230   char szBuf[MAX_BUF_TINY];
04231   char szAttribute[MAX_BUF_TINY];
04232 
04233   GetPrivateProfileString(siCNode->szReferenceName, "Attributes", "", szBuf, sizeof(szBuf), szFileIniConfig);
04234   lstrcpy(szAttribute, szBuf);
04235   CharUpperBuff(szAttribute, sizeof(szAttribute));
04236 
04237   if(strstr(szAttribute, "INVISIBLE") || siCNode->bSupersede)
04238     siCNode->dwAttributes |= SIC_INVISIBLE;
04239   else
04240     siCNode->dwAttributes &= ~SIC_INVISIBLE;
04241 }
04242 
04243 void RestoreAdditionalFlag(siC *siCNode)
04244 {
04245   char szBuf[MAX_BUF_TINY];
04246   char szAttribute[MAX_BUF_TINY];
04247 
04248   GetPrivateProfileString(siCNode->szReferenceName, "Attributes", "", szBuf, sizeof(szBuf), szFileIniConfig);
04249   lstrcpy(szAttribute, szBuf);
04250   CharUpperBuff(szAttribute, sizeof(szAttribute));
04251 
04252   if(strstr(szAttribute, "ADDITIONAL") && !strstr(szAttribute, "NOTADDITIONAL"))
04253     siCNode->dwAttributes |= SIC_ADDITIONAL;
04254   else
04255     siCNode->dwAttributes &= ~SIC_ADDITIONAL;
04256 }
04257 
04258 void RestoreEnabledFlag(siC *siCNode)
04259 {
04260   char szBuf[MAX_BUF_TINY];
04261   char szAttribute[MAX_BUF_TINY];
04262 
04263   GetPrivateProfileString(siCNode->szReferenceName, "Attributes", "", szBuf, sizeof(szBuf), szFileIniConfig);
04264   lstrcpy(szAttribute, szBuf);
04265   CharUpperBuff(szAttribute, sizeof(szAttribute));
04266 
04267   if(strstr(szAttribute, "ENABLED") && !strstr(szAttribute, "DISABLED"))
04268     siCNode->dwAttributes |= SIC_DISABLED;
04269   else
04270     siCNode->dwAttributes &= ~SIC_DISABLED;
04271 }
04272 
04273 //  This function:
04274 //  - Zeros the SELECTED and ADDITIONAL attributes of all components.
04275 //  - Set all attributes as specified for the specific Setup Type
04276 //  - Overrides attributes designated in any [Component XXX-Overwrite-Setup TypeX]
04277 //    sections for the specific Setup Type.
04278 void SiCNodeSetItemsSelected(DWORD dwSetupType)
04279 {
04280   siC  *siCNode;
04281   char szBuf[MAX_BUF];
04282   char szSTSection[MAX_BUF];
04283   char szComponentKey[MAX_BUF];
04284   char szComponentSection[MAX_BUF];
04285   char szOverrideSection[MAX_BUF];
04286   char szOverrideAttributes[MAX_BUF];
04287   DWORD dwIndex0;
04288 
04289   lstrcpy(szSTSection, "Setup Type");
04290   itoa(dwSetupType, szBuf, 10);
04291   lstrcat(szSTSection, szBuf);
04292 
04293   // For each component in the global list unset its SELECTED and ADDITIONAL attributes
04294   siCNode = siComponents;
04295   do
04296   {
04297     if(siCNode == NULL)
04298       break;
04299 
04300     /* clear these flags for all components so they can be
04301      * reset later if they belong to the setup type the user
04302      * selected */
04303     siCNode->dwAttributes &= ~SIC_SELECTED;
04304     siCNode->dwAttributes &= ~SIC_ADDITIONAL;
04305     siCNode->dwAttributes |= SIC_INVISIBLE;
04306 
04307     /* Force Upgrade needs to be performed here because the user has just
04308      * selected the destination path for the product.  The destination path is
04309      * critical to the checking of the Force Upgrade. */
04310     ResolveForceUpgrade(siCNode);
04311     ResolveSupersede(siCNode, &gGre);
04312     siCNode = siCNode->Next;
04313   } while((siCNode != NULL) && (siCNode != siComponents));
04314 
04315   /* for each component in a setup type, set its ATTRIBUTES to the right values */
04316   dwIndex0 = 0;
04317   wsprintf(szComponentKey, "C%d", dwIndex0);
04318   GetPrivateProfileString(szSTSection, szComponentKey, "", szComponentSection, sizeof(szComponentSection), szFileIniConfig);
04319   while(*szComponentSection != '\0')
04320   {
04321     if((siCNode = SiCNodeFind(siComponents, szComponentSection)) != NULL)
04322     {
04323       /* Component is in the Setup Type the user selected, so we now need to
04324        * reset the INVISIBLE and ADDITIONAL flags because they were unset
04325        * above and also are not reset anywhere else. */
04326       RestoreInvisibleFlag(siCNode);
04327       RestoreAdditionalFlag(siCNode);
04328 
04329       wsprintf(szOverrideSection, "%s-Override-%s", siCNode->szReferenceName, szSTSection);
04330       GetPrivateProfileString(szOverrideSection, "Attributes", "", szOverrideAttributes, sizeof(szOverrideAttributes), szFileIniConfig);
04331 
04332       if((siCNode->lRandomInstallPercentage != 0) &&
04333          (siCNode->lRandomInstallPercentage <= siCNode->lRandomInstallValue) &&
04334          !(siCNode->dwAttributes & SIC_DISABLED))
04335       {
04336         /* Random Install Percentage check passed *and* the component
04337          * is not DISABLED */
04338         if(*szOverrideAttributes != '\0')
04339           siCNode->dwAttributes = ParseComponentAttributes(szOverrideAttributes, siCNode->dwAttributes, TRUE);
04340         siCNode->dwAttributes &= ~SIC_SELECTED;
04341       }
04342       else if(sgProduct.dwCustomType != dwSetupType)
04343       {
04344         /* Setup Type other than custom detected, so
04345          * make sure all components from this Setup Type
04346          * is selected (regardless if it's DISABLED or not). 
04347          * Don't select components that are Superseded */
04348         if(!siCNode->bSupersede)
04349           siCNode->dwAttributes |= SIC_SELECTED;
04350 
04351         /* We need to restore the ENBLED/DISABLED flag for this component
04352          * from config.ini because it could have been altered in
04353          * ResolveForceUpgrade().  We need to restore it here so the override
04354          * attribute can override it here. */
04355         RestoreEnabledFlag(siCNode);
04356         if(*szOverrideAttributes != '\0')
04357           siCNode->dwAttributes = ParseComponentAttributes(szOverrideAttributes, siCNode->dwAttributes, TRUE);
04358       }
04359       else if(!(siCNode->dwAttributes & SIC_DISABLED) && !siCNode->bForceUpgrade && !siCNode->bSupersede)
04360       {
04361         /* Custom setup type detected and the component is
04362          * not DISABLED and FORCE_UPGRADE.  Reset the component's 
04363          * attribute to default.  If the component is DISABLED and
04364          * happens not be SELECTED in the config.ini file, we leave
04365          * it as is.  The user will see the component in the Options
04366          * Dialogs as not selected and DISABLED.  Not sure why we
04367          * want this, but marketing might find it useful someday. */
04368 
04369         GetPrivateProfileString(siCNode->szReferenceName, "Attributes", "", szBuf, sizeof(szBuf), szFileIniConfig);
04370         siCNode->dwAttributes = ParseComponentAttributes(szBuf, 0, FALSE);
04371         if(*szOverrideAttributes != '\0')
04372           siCNode->dwAttributes = ParseComponentAttributes(szOverrideAttributes, siCNode->dwAttributes, TRUE);
04373       }
04374     }
04375 
04376     ++dwIndex0;
04377     wsprintf(szComponentKey, "C%d", dwIndex0);
04378     GetPrivateProfileString(szSTSection, szComponentKey, "", szComponentSection, sizeof(szComponentSection), szFileIniConfig);
04379   }
04380 }
04381 
04382 char *SiCNodeGetReferenceName(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04383 {
04384   DWORD dwCount = 0;
04385   siC   *siCTemp = siComponents;
04386 
04387   if(siCTemp != NULL)
04388   {
04389     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04390        ((dwACFlag == AC_ALL) ||
04391        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04392        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04393     {
04394       if(dwIndex == 0)
04395         return(siCTemp->szReferenceName);
04396 
04397       ++dwCount;
04398     }
04399 
04400     siCTemp = siCTemp->Next;
04401     while((siCTemp != NULL) && (siCTemp != siComponents))
04402     {
04403       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04404          ((dwACFlag == AC_ALL) ||
04405          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04406          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04407       {
04408         if(dwIndex == dwCount)
04409           return(siCTemp->szReferenceName);
04410       
04411         ++dwCount;
04412       }
04413 
04414       siCTemp = siCTemp->Next;
04415     }
04416   }
04417   return(NULL);
04418 }
04419 
04420 char *SiCNodeGetDescriptionShort(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04421 {
04422   DWORD dwCount = 0;
04423   siC   *siCTemp = siComponents;
04424 
04425   if(siCTemp != NULL)
04426   {
04427     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04428        ((dwACFlag == AC_ALL) ||
04429        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04430        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04431     {
04432       if(dwIndex == 0)
04433         return(siCTemp->szDescriptionShort);
04434 
04435       ++dwCount;
04436     }
04437 
04438     siCTemp = siCTemp->Next;
04439     while((siCTemp != NULL) && (siCTemp != siComponents))
04440     {
04441       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04442          ((dwACFlag == AC_ALL) ||
04443          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04444          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04445       {
04446         if(dwIndex == dwCount)
04447           return(siCTemp->szDescriptionShort);
04448       
04449         ++dwCount;
04450       }
04451 
04452       siCTemp = siCTemp->Next;
04453     }
04454   }
04455   return(NULL);
04456 }
04457 
04458 char *SiCNodeGetDescriptionLong(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04459 {
04460   DWORD dwCount = 0;
04461   siC   *siCTemp = siComponents;
04462 
04463   if(siCTemp != NULL)
04464   {
04465     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04466        ((dwACFlag == AC_ALL) ||
04467        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04468        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04469     {
04470       if(dwIndex == 0)
04471         return(siCTemp->szDescriptionLong);
04472 
04473       ++dwCount;
04474     }
04475 
04476     siCTemp = siCTemp->Next;
04477     while((siCTemp != NULL) && (siCTemp != siComponents))
04478     {
04479       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04480          ((dwACFlag == AC_ALL) ||
04481          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04482          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04483       {
04484         if(dwIndex == dwCount)
04485           return(siCTemp->szDescriptionLong);
04486       
04487         ++dwCount;
04488       }
04489 
04490       siCTemp = siCTemp->Next;
04491     }
04492   }
04493   return(NULL);
04494 }
04495 
04496 ULONGLONG SiCNodeGetInstallSize(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04497 {
04498   DWORD dwCount   = 0;
04499   siC   *siCTemp  = siComponents;
04500 
04501   if(siCTemp != NULL)
04502   {
04503     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04504        ((dwACFlag == AC_ALL) ||
04505        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04506        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04507     {
04508       if(dwIndex == 0)
04509         return(siCTemp->ullInstallSize);
04510 
04511       ++dwCount;
04512     }
04513     
04514     siCTemp = siCTemp->Next;
04515     while((siCTemp != NULL) && (siCTemp != siComponents))
04516     {
04517       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04518          ((dwACFlag == AC_ALL) ||
04519          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04520          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04521       {
04522         if(dwIndex == dwCount)
04523           return(siCTemp->ullInstallSize);
04524       
04525         ++dwCount;
04526       }
04527       
04528       siCTemp = siCTemp->Next;
04529     }
04530   }
04531   return(0L);
04532 }
04533 
04534 ULONGLONG SiCNodeGetInstallSizeSystem(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04535 {
04536   DWORD dwCount   = 0;
04537   siC   *siCTemp  = siComponents;
04538 
04539   if(siCTemp != NULL)
04540   {
04541     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04542        ((dwACFlag == AC_ALL) ||
04543        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04544        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04545     {
04546       if(dwIndex == 0)
04547         return(siCTemp->ullInstallSizeSystem);
04548 
04549       ++dwCount;
04550     }
04551     
04552     siCTemp = siCTemp->Next;
04553     while((siCTemp != NULL) && (siCTemp != siComponents))
04554     {
04555       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04556          ((dwACFlag == AC_ALL) ||
04557          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04558          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04559       {
04560         if(dwIndex == dwCount)
04561           return(siCTemp->ullInstallSizeSystem);
04562       
04563         ++dwCount;
04564       }
04565       
04566       siCTemp = siCTemp->Next;
04567     }
04568   }
04569   return(0L);
04570 }
04571 
04572 ULONGLONG SiCNodeGetInstallSizeArchive(DWORD dwIndex, BOOL bIncludeInvisible, DWORD dwACFlag)
04573 {
04574   DWORD dwCount   = 0;
04575   siC   *siCTemp  = siComponents;
04576 
04577   if(siCTemp != NULL)
04578   {
04579     if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04580        ((dwACFlag == AC_ALL) ||
04581        ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04582        ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04583     {
04584       if(dwIndex == 0)
04585         return(siCTemp->ullInstallSizeArchive);
04586 
04587       ++dwCount;
04588     }
04589     
04590     siCTemp = siCTemp->Next;
04591     while((siCTemp != NULL) && (siCTemp != siComponents))
04592     {
04593       if(((bIncludeInvisible == TRUE) || ((bIncludeInvisible == FALSE) && (!(siCTemp->dwAttributes & SIC_INVISIBLE)))) &&
04594          ((dwACFlag == AC_ALL) ||
04595          ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04596          ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04597       {
04598         if(dwIndex == dwCount)
04599           return(siCTemp->ullInstallSizeArchive);
04600       
04601         ++dwCount;
04602       }
04603       
04604       siCTemp = siCTemp->Next;
04605     }
04606   }
04607   return(0L);
04608 }
04609 
04610 /* retrieve Index of node containing short description */
04611 int SiCNodeGetIndexDS(char *szInDescriptionShort)
04612 {
04613   DWORD dwCount = 0;
04614   siC   *siCTemp = siComponents;
04615 
04616   if(siCTemp != NULL)
04617   {
04618     if(lstrcmpi(szInDescriptionShort, siCTemp->szDescriptionShort) == 0)
04619       return(dwCount);
04620 
04621     ++dwCount;
04622     siCTemp = siCTemp->Next;
04623     while((siCTemp != NULL) && (siCTemp != siComponents))
04624     {
04625       if(lstrcmpi(szInDescriptionShort, siCTemp->szDescriptionShort) == 0)
04626         return(dwCount);
04627       
04628       ++dwCount;
04629       siCTemp = siCTemp->Next;
04630     }
04631   }
04632   return(-1);
04633 }
04634 
04635 /* retrieve Index of node containing Reference Name */
04636 int SiCNodeGetIndexRN(char *szInReferenceName)
04637 {
04638   DWORD dwCount = 0;
04639   siC   *siCTemp = siComponents;
04640 
04641   if(siCTemp != NULL)
04642   {
04643     if(lstrcmpi(szInReferenceName, siCTemp->szReferenceName) == 0)
04644       return(dwCount);
04645 
04646     ++dwCount;
04647     siCTemp = siCTemp->Next;
04648     while((siCTemp != NULL) && (siCTemp != siComponents))
04649     {
04650       if(lstrcmpi(szInReferenceName, siCTemp->szReferenceName) == 0)
04651         return(dwCount);
04652       
04653       ++dwCount;
04654       siCTemp = siCTemp->Next;
04655     }
04656   }
04657   return(-1);
04658 }
04659 
04660 siC *SiCNodeGetObject(DWORD dwIndex, BOOL bIncludeInvisibleObjs, DWORD dwACFlag)
04661 {
04662   DWORD dwCount = -1;
04663   siC   *siCTemp = siComponents;
04664 
04665   if(siCTemp != NULL)
04666   {
04667     if((bIncludeInvisibleObjs) &&
04668       ((dwACFlag == AC_ALL) ||
04669       ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04670       ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04671     {
04672       ++dwCount;
04673     }
04674     else if((!(siCTemp->dwAttributes & SIC_INVISIBLE)) &&
04675            ((dwACFlag == AC_ALL) ||
04676            ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04677            ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04678     {
04679       ++dwCount;
04680     }
04681 
04682     if(dwIndex == dwCount)
04683       return(siCTemp);
04684 
04685     siCTemp = siCTemp->Next;
04686     while((siCTemp != siComponents) && (siCTemp != NULL))
04687     {
04688       if(bIncludeInvisibleObjs)
04689       {
04690         ++dwCount;
04691       }
04692       else if((!(siCTemp->dwAttributes & SIC_INVISIBLE)) &&
04693              ((dwACFlag == AC_ALL) ||
04694              ((dwACFlag == AC_COMPONENTS)            && (!(siCTemp->dwAttributes & SIC_ADDITIONAL))) ||
04695              ((dwACFlag == AC_ADDITIONAL_COMPONENTS) &&   (siCTemp->dwAttributes & SIC_ADDITIONAL))))
04696       {
04697         ++dwCount;
04698       }
04699 
04700       if(dwIndex == dwCount)
04701         return(siCTemp);
04702       
04703       siCTemp = siCTemp->Next;
04704     }
04705   }
04706   return(NULL);
04707 }
04708 
04709 DWORD GetAdditionalComponentsCount()
04710 {
04711   DWORD dwCount  = 0;
04712   siC   *siCTemp = siComponents;
04713 
04714   if(siCTemp != NULL)
04715   {
04716     if(siCTemp->dwAttributes & SIC_ADDITIONAL)
04717     {
04718       ++dwCount;
04719     }
04720 
04721     siCTemp = siCTemp->Next;
04722     while((siCTemp != siComponents) && (siCTemp != NULL))
04723     {
04724       if(siCTemp->dwAttributes & SIC_ADDITIONAL)
04725       {
04726         ++dwCount;
04727       }
04728       
04729       siCTemp = siCTemp->Next;
04730     }
04731   }
04732   return(dwCount);
04733 }
04734 
04735 dsN *CreateDSNode()
04736 {
04737   dsN *dsNode;
04738 
04739   if((dsNode = NS_GlobalAlloc(sizeof(struct diskSpaceNode))) == NULL)
04740     exit(1);
04741 
04742   dsNode->ullSpaceRequired = 0;
04743 
04744   if((dsNode->szVDSPath = NS_GlobalAlloc(MAX_BUF)) == NULL)
04745     exit(1);
04746   if((dsNode->szPath = NS_GlobalAlloc(MAX_BUF)) == NULL)
04747     exit(1);
04748   dsNode->Next             = dsNode;
04749   dsNode->Prev             = dsNode;
04750 
04751   return(dsNode);
04752 }
04753 
04754 void DsNodeInsert(dsN **dsNHead, dsN *dsNTemp)
04755 {
04756   if(*dsNHead == NULL)
04757   {
04758     *dsNHead          = dsNTemp;
04759     (*dsNHead)->Next  = *dsNHead;
04760     (*dsNHead)->Prev  = *dsNHead;
04761   }
04762   else
04763   {
04764     dsNTemp->Next           = *dsNHead;
04765     dsNTemp->Prev           = (*dsNHead)->Prev;
04766     (*dsNHead)->Prev->Next  = dsNTemp;
04767     (*dsNHead)->Prev        = dsNTemp;
04768   }
04769 }
04770 
04771 void DsNodeDelete(dsN **dsNTemp)
04772 {
04773   if(*dsNTemp != NULL)
04774   {
04775     (*dsNTemp)->Next->Prev = (*dsNTemp)->Prev;
04776     (*dsNTemp)->Prev->Next = (*dsNTemp)->Next;
04777     (*dsNTemp)->Next       = NULL;
04778     (*dsNTemp)->Prev       = NULL;
04779 
04780     FreeMemory(&((*dsNTemp)->szVDSPath));
04781     FreeMemory(&((*dsNTemp)->szPath));
04782     FreeMemory(dsNTemp);
04783   }
04784 }
04785 
04786 BOOL IsWin95Debute()
04787 {
04788   HINSTANCE hLib;
04789   BOOL      bIsWin95Debute;
04790 
04791   bIsWin95Debute = FALSE;
04792   if((hLib = LoadLibraryEx("kernel32.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) != NULL)
04793   {
04794     if(((FARPROC)NS_GetDiskFreeSpaceEx = GetProcAddress(hLib, "GetDiskFreeSpaceExA")) == NULL)
04795     {
04796       (FARPROC)NS_GetDiskFreeSpace = GetProcAddress(hLib, "GetDiskFreeSpaceA");
04797       bIsWin95Debute = TRUE;
04798     }
04799 
04800     FreeLibrary(hLib);
04801   }
04802   return(bIsWin95Debute);
04803 }
04804 
04805 /* returns the value in kilobytes */
04806 ULONGLONG GetDiskSpaceRequired(DWORD dwType)
04807 {
04808   ULONGLONG ullTotalSize = 0;
04809   siC       *siCTemp     = siComponents;
04810 
04811   if(siCTemp != NULL)
04812   {
04813     if(siCTemp->dwAttributes & SIC_SELECTED)
04814     {
04815       switch(dwType)
04816       {
04817         case DSR_DESTINATION:
04818           ullTotalSize += siCTemp->ullInstallSize;
04819           break;
04820 
04821         case DSR_SYSTEM:
04822           ullTotalSize += siCTemp->ullInstallSizeSystem;
04823           break;
04824 
04825         case DSR_TEMP:
04826         case DSR_DOWNLOAD_SIZE:
04827           if((LocateJar(siCTemp, NULL, 0, gbPreviousUnfinishedDownload) == AP_NOT_FOUND) ||
04828              (dwType == DSR_DOWNLOAD_SIZE))
04829             ullTotalSize += siCTemp->ullInstallSizeArchive;
04830           break;
04831       }
04832     }
04833 
04834     siCTemp = siCTemp->Next;
04835     while((siCTemp != NULL) && (siCTemp != siComponents))
04836     {
04837       if(siCTemp->dwAttributes & SIC_SELECTED)
04838       {
04839         switch(dwType)
04840         {
04841           case DSR_DESTINATION:
04842             ullTotalSize += siCTemp->ullInstallSize;
04843             break;
04844 
04845           case DSR_SYSTEM:
04846             ullTotalSize += siCTemp->ullInstallSizeSystem;
04847             break;
04848 
04849           case DSR_TEMP:
04850           case DSR_DOWNLOAD_SIZE:
04851             if((LocateJar(siCTemp, NULL, 0, gbPreviousUnfinishedDownload) == AP_NOT_FOUND) ||
04852                (dwType == DSR_DOWNLOAD_SIZE))
04853               ullTotalSize += siCTemp->ullInstallSizeArchive;
04854             break;
04855         }
04856       }
04857 
04858       siCTemp = siCTemp->Next;
04859     }
04860   }
04861 
04862   /* add the amount of disk space it will take for the 
04863      xpinstall engine in the TEMP area */
04864   if(dwType == DSR_TEMP)
04865     if(siCFXpcomFile.bStatus == STATUS_ENABLED)
04866       ullTotalSize += siCFXpcomFile.ullInstallSize;
04867 
04868   return(ullTotalSize);
04869 }
04870 
04871 int LocateExistingPath(char *szPath, char *szExistingPath, DWORD dwExistingPathSize)
04872 {
04873   char szBuf[MAX_BUF];
04874 
04875   lstrcpy(szExistingPath, szPath);
04876   AppendBackSlash(szExistingPath, dwExistingPathSize);
04877   while((FileExists(szExistingPath) == FALSE))
04878   {
04879     RemoveBackSlash(szExistingPath);
04880     ParsePath(szExistingPath, szBuf, sizeof(szBuf), FALSE, PP_PATH_ONLY);
04881     lstrcpy(szExistingPath, szBuf);
04882     AppendBackSlash(szExistingPath, dwExistingPathSize);
04883   }
04884   return(WIZ_OK);
04885 }
04886 
04887 /* returns the value in bytes */
04888 ULONGLONG GetDiskSpaceAvailable(LPSTR szPath)
04889 {
04890   char            szTempPath[MAX_BUF];
04891   char            szBuf[MAX_BUF];
04892   char            szExistingPath[MAX_BUF];
04893   char            szBuf2[MAX_BUF];
04894   ULARGE_INTEGER  uliFreeBytesAvailableToCaller;
04895   ULARGE_INTEGER  uliTotalNumberOfBytesToCaller;
04896   ULARGE_INTEGER  uliTotalNumberOfFreeBytes;
04897   ULONGLONG       ullReturn = 0;
04898   DWORD           dwSectorsPerCluster;
04899   DWORD           dwBytesPerSector;
04900   DWORD           dwNumberOfFreeClusters;
04901   DWORD           dwTotalNumberOfClusters;
04902 
04903   if(NS_GetDiskFreeSpaceEx != NULL)
04904   {
04905     LocateExistingPath(szPath, szExistingPath, sizeof(szExistingPath));
04906     AppendBackSlash(szExistingPath, sizeof(szExistingPath));
04907 
04908     /* Appearently under Win9x, the path still needs to be in 8.3 format
04909      * or GetDiskFreeSpaceEx() will fail. */
04910     if(gSystemInfo.dwOSType & OS_WIN9x)
04911     {
04912       lstrcpy(szBuf, szExistingPath);
04913       GetShortPathName(szBuf, szExistingPath, sizeof(szExistingPath));
04914     }
04915 
04916     if(NS_GetDiskFreeSpaceEx(szExistingPath,
04917                              &uliFreeBytesAvailableToCaller,
04918                              &uliTotalNumberOfBytesToCaller,
04919                              &uliTotalNumberOfFreeBytes) == FALSE)
04920     {
04921       char szEDeterminingDiskSpace[MAX_BUF];
04922 
04923       if(GetPrivateProfileString("Messages", "ERROR_DETERMINING_DISK_SPACE", "", szEDeterminingDiskSpace, sizeof(szEDeterminingDiskSpace), szFileIniInstall))
04924       {
04925         lstrcpy(szBuf2, "\n    ");
04926         lstrcat(szBuf2, szPath);
04927         wsprintf(szBuf, szEDeterminingDiskSpace, szBuf2);
04928         PrintError(szBuf, ERROR_CODE_SHOW);
04929       }
04930     }
04931     ullReturn = uliFreeBytesAvailableToCaller.QuadPart;
04932   }
04933   else if(NS_GetDiskFreeSpace != NULL)
04934   {
04935     ParsePath(szPath, szTempPath, MAX_BUF, FALSE, PP_ROOT_ONLY);
04936     NS_GetDiskFreeSpace(szTempPath, 
04937                         &dwSectorsPerCluster,
04938                         &dwBytesPerSector,
04939                         &dwNumberOfFreeClusters,
04940                         &dwTotalNumberOfClusters);
04941     ullReturn = ((ULONGLONG)dwBytesPerSector * (ULONGLONG)dwSectorsPerCluster * (ULONGLONG)dwNumberOfFreeClusters);
04942   }
04943 
04944 
04945   if(ullReturn > 1024)
04946     ullReturn /= 1024;
04947   else
04948     ullReturn = 0;
04949 
04950   return(ullReturn);
04951 }
04952 
04953 HRESULT ErrorMsgDiskSpace(ULONGLONG ullDSAvailable, ULONGLONG ullDSRequired, LPSTR szPath, BOOL bCrutialMsg)
04954 {
04955   char      szBuf0[MAX_BUF];
04956   char      szBuf1[MAX_BUF];
04957   char      szBuf2[MAX_BUF];
04958   char      szBuf3[MAX_BUF];
04959   char      szBufRootPath[MAX_BUF];
04960   char      szBufMsg[MAX_BUF];
04961   char      szDSAvailable[MAX_BUF];
04962   char      szDSRequired[MAX_BUF];
04963   char      szDlgDiskSpaceCheckTitle[MAX_BUF];
04964   char      szDlgDiskSpaceCheckMsg[MAX_BUF];
04965   DWORD     dwDlgType;
04966 
04967   if(!GetPrivateProfileString("Messages", "DLG_DISK_SPACE_CHECK_TITLE", "", szDlgDiskSpaceCheckTitle, sizeof(szDlgDiskSpaceCheckTitle), szFileIniInstall))
04968     exit(1);
04969 
04970   if(bCrutialMsg)
04971   {
04972     dwDlgType = MB_RETRYCANCEL;
04973     if(!GetPrivateProfileString("Messages", "DLG_DISK_SPACE_CHECK_CRUTIAL_MSG", "", szDlgDiskSpaceCheckMsg, sizeof(szDlgDiskSpaceCheckMsg), szFileIniInstall))
04974       exit(1);
04975   }
04976   else
04977   {
04978     dwDlgType = MB_OK;
04979     if(!GetPrivateProfileString("Messages", "DLG_DISK_SPACE_CHECK_MSG", "", szDlgDiskSpaceCheckMsg, sizeof(szDlgDiskSpaceCheckMsg), szFileIniInstall))
04980       exit(1);
04981   }
04982 
04983   ParsePath(szPath, szBufRootPath, sizeof(szBufRootPath), FALSE, PP_ROOT_ONLY);
04984   RemoveBackSlash(szBufRootPath);
04985   lstrcpy(szBuf0, szPath);
04986   RemoveBackSlash(szBuf0);
04987 
04988   _ui64toa(ullDSAvailable, szDSAvailable, 10);
04989   _ui64toa(ullDSRequired, szDSRequired, 10);
04990 
04991   wsprintf(szBuf1, "\n\n    %s\n\n    ", szBuf0);
04992   wsprintf(szBuf2, "%s KB\n    ",        szDSRequired);
04993   wsprintf(szBuf3, "%s KB\n\n",          szDSAvailable);
04994   wsprintf(szBufMsg, szDlgDiskSpaceCheckMsg, szBufRootPath, szBuf1, szBuf2, szBuf3);
04995 
04996   if((sgProduct.mode != SILENT) && (sgProduct.mode != AUTO))
04997   {
04998     ShowMessage(NULL, FALSE);
04999     return(MessageBox(hWndMain, szBufMsg, szDlgDiskSpaceCheckTitle, dwDlgType | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_APPLMODAL | MB_SETFOREGROUND));
05000   }
05001   else if(sgProduct.mode == AUTO)
05002   {
05003     ShowMessage(szBufMsg, TRUE);
05004     Delay(5);
05005     exit(1);
05006   }
05007 
05008   return(IDCANCEL);
05009 }
05010 
05011 BOOL ContainsReparseTag(char *szPath, char *szReparsePath, DWORD dwReparsePathSize)
05012 {
05013   BOOL  bFoundReparseTag  = FALSE;
05014   DWORD dwOriginalLen     = lstrlen(szPath);
05015   DWORD dwLen             = dwOriginalLen;
05016   char  *szPathTmp        = NULL;
05017   char  *szBuf            = NULL;
05018 
05019   if((szPathTmp = NS_GlobalAlloc(dwLen + 1)) == NULL)
05020     exit(1);
05021   if((szBuf = NS_GlobalAlloc(dwLen + 1)) == NULL)
05022     exit(1);
05023 
05024   lstrcpy(szPathTmp, szPath);
05025   while((szPathTmp[dwLen - 2] != ':') && (szPathTmp[dwLen - 2] != '\\'))
05026   {
05027     if(FileExists(szPathTmp) & FILE_ATTRIBUTE_REPARSE_POINT)
05028     {
05029       if((DWORD)lstrlen(szPathTmp) <= dwReparsePathSize)
05030         lstrcpy(szReparsePath, szPathTmp);
05031       else
05032         ZeroMemory(szReparsePath, dwReparsePathSize);
05033 
05034       bFoundReparseTag = TRUE;
05035       break;
05036     }
05037 
05038     lstrcpy(szBuf, szPathTmp);
05039     RemoveBackSlash(szBuf);
05040     ParsePath(szBuf, szPathTmp, dwOriginalLen + 1, FALSE, PP_PATH_ONLY);
05041     dwLen = lstrlen(szPathTmp);
05042   }
05043 
05044   FreeMemory(&szBuf);
05045   FreeMemory(&szPathTmp);
05046   return(bFoundReparseTag);
05047 }
05048 
05049 void UpdatePathDiskSpaceRequired(LPSTR szPath, ULONGLONG ullSize, dsN **dsnComponentDSRequirement)
05050 {
05051   BOOL  bFound = FALSE;
05052   dsN   *dsnTemp = *dsnComponentDSRequirement;
05053   char  szReparsePath[MAX_BUF];
05054   char  szVDSPath[MAX_BUF];
05055   char  szRootPath[MAX_BUF];
05056 
05057   if(ullSize > 0)
05058   {
05059     ParsePath(szPath, szRootPath, sizeof(szRootPath), FALSE, PP_ROOT_ONLY);
05060 
05061     if(gSystemInfo.dwOSType & OS_WIN95_DEBUTE)
05062       // check for Win95 debute version
05063       lstrcpy(szVDSPath, szRootPath);
05064     else if((gSystemInfo.dwOSType & OS_NT5) &&
05065              ContainsReparseTag(szPath, szReparsePath, sizeof(szReparsePath)))
05066     {
05067       // check for Reparse Tag (mount points under NT5 only)
05068       if(*szReparsePath == '\0')
05069       {
05070         // szReparsePath is not big enough to hold the Reparse path.  This is a
05071         // non fatal error.  Keep going using szPath instead.
05072         lstrcpy(szVDSPath, szPath);
05073       }
05074       else if(GetDiskSpaceAvailable(szReparsePath) == GetDiskSpaceAvailable(szPath))
05075         // Check for user quota on path.  It is very unlikely that the user quota
05076         // for the path will be the same as the quota for its root path when user
05077         // quota is enabled.
05078         //
05079         // If it happens to be the same, then I'm assuming that the disk space on
05080         // the path's root path will decrease at the same rate as the path with
05081         // user quota enabled.
05082         //
05083         // If user quota is not enabled on the folder, then use the root path.
05084         lstrcpy(szVDSPath, szReparsePath);
05085       else
05086         lstrcpy(szVDSPath, szPath);
05087     }
05088     else if(GetDiskSpaceAvailable(szRootPath) == GetDiskSpaceAvailable(szPath))
05089       // Check for user quota on path.  It is very unlikely that the user quota
05090       // for the path will be the same as the quota for its root path when user
05091       // quota is enabled.
05092       //
05093       // If it happens to be the same, then I'm assuming that the disk space on
05094       // the path's root path will decrease at the same rate as the path with
05095       // user quota enabled.
05096       //
05097       // If user quota is not enabled on the folder, then use the root path.
05098       lstrcpy(szVDSPath, szRootPath);
05099     else
05100       lstrcpy(szVDSPath, szPath);
05101 
05102     do
05103     {
05104       if(*dsnComponentDSRequirement == NULL)
05105       {
05106         *dsnComponentDSRequirement = CreateDSNode();
05107         dsnTemp = *dsnComponentDSRequirement;
05108         strcpy(dsnTemp->szVDSPath, szVDSPath);
05109         strcpy(dsnTemp->szPath, szPath);
05110         dsnTemp->ullSpaceRequired = ullSize;
05111         bFound = TRUE;
05112       }
05113       else if(lstrcmpi(dsnTemp->szVDSPath, szVDSPath) == 0)
05114       {
05115         dsnTemp->ullSpaceRequired += ullSize;
05116         bFound = TRUE;
05117       }
05118       else
05119         dsnTemp = dsnTemp->Next;
05120 
05121     } while((dsnTemp != *dsnComponentDSRequirement) && (dsnTemp != NULL) && (bFound == FALSE));
05122 
05123     if(bFound == FALSE)
05124     {
05125       dsnTemp = CreateDSNode();
05126       strcpy(dsnTemp->szVDSPath, szVDSPath);
05127       strcpy(dsnTemp->szPath, szPath);
05128       dsnTemp->ullSpaceRequired = ullSize;
05129       DsNodeInsert(dsnComponentDSRequirement, dsnTemp);
05130     }
05131   }
05132 }
05133 
05134 /* Function: DetermineGreComponentDestinationPath()
05135  *
05136  *       in: char *aInPath - original path to where the 'Component GRE' is to
05137  *               be installed to.
05138  *           char *aOutPath - out buffer of what the new destinaton path will
05139  *               be for 'Component GRE'.  This can be the same as aInPath.
05140  *
05141  *  purpose: To figure determine if the original path is writable or not.  If
05142  *           not, then use following as the new destination path:
05143  *
05144  *               [product path]\GRE\[gre id]
05145  *
05146  *           This path is guaranteed to work because the user chose it.  There
05147  *           is logic to make sure we have write access to this new path thru
05148  *           the Setup Type dialog.
05149  *           This path is also the same path that will be passed on to the GRE
05150  *           installer in it's -dd command line parameter.
05151  */
05152 HRESULT DetermineGreComponentDestinationPath(char *aInPath, char *aOutPath, DWORD aOutPathBufSize)
05153 {
05154   int  rv = WIZ_OK;
05155   char inPath[MAX_BUF];
05156 
05157   MozCopyStr(aInPath, inPath, sizeof(inPath));
05158   AppendBackSlash(inPath, sizeof(inPath));
05159   if(DirHasWriteAccess(inPath) != WIZ_OK)
05160   {
05161     char productPath[MAX_BUF];
05162 
05163     MozCopyStr(sgProduct.szPath, productPath, sizeof(productPath));
05164     RemoveBackSlash(productPath);
05165 
05166     assert(*sgProduct.greID);
05167     _snprintf(aOutPath, aOutPathBufSize, "%s\\GRE\\%s", productPath, sgProduct.greID);
05168     aOutPath[aOutPathBufSize - 1] = '\0';
05169   }
05170   else
05171     MozCopyStr(aInPath, aOutPath, aOutPathBufSize);
05172 
05173   return(rv);
05174 }
05175 
05176 HRESULT InitComponentDiskSpaceInfo(dsN **dsnComponentDSRequirement)
05177 {
05178   DWORD     dwIndex0;
05179   siC       *siCObject = NULL;
05180   HRESULT   hResult    = 0;
05181   char      szBuf[MAX_BUF];
05182   char      szIndex0[MAX_BUF];
05183   char      szSysPath[MAX_BUF];
05184   char      szBufSysPath[MAX_BUF];
05185   char      szBufTempPath[MAX_BUF];
05186 
05187   if(GetSystemDirectory(szSysPath, MAX_BUF) == 0)
05188   {
05189     ZeroMemory(szSysPath, MAX_BUF);
05190     ZeroMemory(szBufSysPath, MAX_BUF);
05191   }
05192   else
05193   {
05194     ParsePath(szSysPath, szBufSysPath, sizeof(szBufSysPath), FALSE, PP_ROOT_ONLY);
05195     AppendBackSlash(szBufSysPath, sizeof(szBufSysPath));
05196   }
05197 
05198   ParsePath(szTempDir, szBufTempPath, sizeof(szBufTempPath), FALSE, PP_ROOT_ONLY);
05199   AppendBackSlash(szBufTempPath, sizeof(szBufTempPath));
05200 
05201   dwIndex0 = 0;
05202   itoa(dwIndex0, szIndex0, 10);
05203   siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
05204   while(siCObject)
05205   {
05206     if(siCObject->dwAttributes & SIC_SELECTED)
05207     {
05208       if(*(siCObject->szDestinationPath) == '\0')
05209         lstrcpy(szBuf, sgProduct.szPath);
05210       else if((lstrcmpi(siCObject->szReferenceName, "Component GRE") == 0) &&
05211               !IsInstallerProductGRE())
05212         /* We found 'Component GRE' and this product is not 'GRE'.  The GRE
05213          * product happens to also have a 'Component GRE', but we don't
05214          * care about that one. */
05215         DetermineGreComponentDestinationPath(siCObject->szDestinationPath, szBuf, sizeof(szBuf));
05216       else
05217         lstrcpy(szBuf, siCObject->szDestinationPath);
05218 
05219       AppendBackSlash(szBuf, sizeof(szBuf));
05220       UpdatePathDiskSpaceRequired(szBuf, siCObject->ullInstallSize, dsnComponentDSRequirement);
05221 
05222       if(*szTempDir != '\0')
05223         UpdatePathDiskSpaceRequired(szTempDir, siCObject->ullInstallSizeArchive, dsnComponentDSRequirement);
05224 
05225       if(*szSysPath != '\0')
05226         UpdatePathDiskSpaceRequired(szSysPath, siCObject->ullInstallSizeSystem, dsnComponentDSRequirement);
05227     }
05228 
05229     ++dwIndex0;
05230     itoa(dwIndex0, szIndex0, 10);
05231     siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
05232   }
05233 
05234   /* take the uncompressed size of Xpcom into account */
05235   if(*szTempDir != '\0')
05236     if(siCFXpcomFile.bStatus == STATUS_ENABLED)
05237       UpdatePathDiskSpaceRequired(szTempDir, siCFXpcomFile.ullInstallSize, dsnComponentDSRequirement);
05238 
05239   return(hResult);
05240 }
05241 
05242 HRESULT VerifyDiskSpace()
05243 {
05244   ULONGLONG ullDSAvailable;
05245   HRESULT   hRetValue = FALSE;
05246   dsN       *dsnTemp = NULL;
05247 
05248   DeInitDSNode(&gdsnComponentDSRequirement);
05249   InitComponentDiskSpaceInfo(&gdsnComponentDSRequirement);
05250   if(gdsnComponentDSRequirement != NULL)
05251   {
05252     dsnTemp = gdsnComponentDSRequirement;
05253 
05254     do
05255     {
05256       if(dsnTemp != NULL)
05257       {
05258         ullDSAvailable = GetDiskSpaceAvailable(dsnTemp->szVDSPath);
05259         if(ullDSAvailable < dsnTemp->ullSpaceRequired)
05260         {
05261           hRetValue = ErrorMsgDiskSpace(ullDSAvailable, dsnTemp->ullSpaceRequired, dsnTemp->szPath, FALSE);
05262           break;
05263         }
05264 
05265         dsnTemp = dsnTemp->Next;
05266       }
05267     } while((dsnTemp != NULL) && (dsnTemp != gdsnComponentDSRequirement));
05268   }
05269   return(hRetValue);
05270 }
05271 
05272 /* Function: ParseOSType
05273  *
05274  * Input: char *
05275  *
05276  * Return: DWORD
05277  *
05278  * Description: This function parses an input string (szOSType) for specific
05279  * string keys:
05280  *     WIN95_DEBUTE, WIN95, WIN98, NT3, NT4, NT5, NT50, NT51
05281  *
05282  * It then stores the information in a DWORD, each bit corresponding to a
05283  * particular OS type.
05284  */ 
05285 DWORD ParseOSType(char *szOSType)
05286 {
05287   char  szBuf[MAX_BUF];
05288   DWORD dwOSType = 0;
05289 
05290   lstrcpy(szBuf, szOSType);
05291   CharUpperBuff(szBuf, sizeof(szBuf));
05292 
05293   if(strstr(szBuf, "WIN95 DEBUTE"))
05294     dwOSType |= OS_WIN95_DEBUTE;
05295   if(strstr(szBuf, "WIN95") &&
05296      !strstr(szBuf, "WIN95 DEBUTE"))
05297     dwOSType |= OS_WIN95;
05298   if(strstr(szBuf, "WIN98"))
05299     dwOSType |= OS_WIN98;
05300   if(strstr(szBuf, "NT3"))
05301     dwOSType |= OS_NT3;
05302   if(strstr(szBuf, "NT4"))
05303     dwOSType |= OS_NT4;
05304   if(strstr(szBuf, "NT50"))
05305     dwOSType |= OS_NT50;
05306   if(strstr(szBuf, "NT51"))
05307     dwOSType |= OS_NT51;
05308   if(strstr(szBuf, "NT5") &&
05309      !strstr(szBuf, "NT50") &&
05310      !strstr(szBuf, "NT51"))
05311     dwOSType |= OS_NT5;
05312 
05313   return(dwOSType);
05314 }
05315 
05316 HRESULT ParseComponentAttributes(char *szAttribute, DWORD dwAttributes, BOOL bOverride)
05317 {
05318   char  szBuf[MAX_BUF];
05319 
05320   lstrcpy(szBuf, szAttribute);
05321   CharUpperBuff(szBuf, sizeof(szBuf));
05322 
05323   if(bOverride != TRUE)
05324   {
05325     if(strstr(szBuf, "LAUNCHAPP"))
05326       dwAttributes |= SIC_LAUNCHAPP;
05327     if(strstr(szBuf, "DOWNLOAD_ONLY"))
05328       dwAttributes |= SIC_DOWNLOAD_ONLY;
05329     if(strstr(szBuf, "FORCE_UPGRADE"))
05330       dwAttributes |= SIC_FORCE_UPGRADE;
05331     if(strstr(szBuf, "IGNORE_DOWNLOAD_ERROR"))
05332       dwAttributes |= SIC_IGNORE_DOWNLOAD_ERROR;
05333     if(strstr(szBuf, "IGNORE_XPINSTALL_ERROR"))
05334       dwAttributes |= SIC_IGNORE_XPINSTALL_ERROR;
05335     if(strstr(szBuf, "UNCOMPRESS"))
05336       dwAttributes |= SIC_UNCOMPRESS;
05337   }
05338 
05339   if(strstr(szBuf, "UNSELECTED"))
05340     dwAttributes &= ~SIC_SELECTED;
05341   else if(strstr(szBuf, "SELECTED"))
05342     dwAttributes |= SIC_SELECTED;
05343 
05344   if(strstr(szBuf, "INVISIBLE"))
05345     dwAttributes |= SIC_INVISIBLE;
05346   else if(strstr(szBuf, "VISIBLE"))
05347     dwAttributes &= ~SIC_INVISIBLE;
05348 
05349   if(strstr(szBuf, "DISABLED"))
05350     dwAttributes |= SIC_DISABLED;
05351   if(strstr(szBuf, "ENABLED"))
05352     dwAttributes &= ~SIC_DISABLED;
05353 
05354   if(strstr(szBuf, "NOTADDITIONAL"))
05355     dwAttributes &= ~SIC_ADDITIONAL;
05356   else if(strstr(szBuf, "ADDITIONAL"))
05357     dwAttributes |= SIC_ADDITIONAL;
05358 
05359   if(strstr(szBuf, "NOTSUPERSEDE"))
05360     dwAttributes &= ~SIC_SUPERSEDE;
05361   else if(strstr(szBuf, "SUPERSEDE"))
05362     dwAttributes |= SIC_SUPERSEDE;
05363    
05364 
05365   return(dwAttributes);
05366 }
05367 
05368 long RandomSelect()
05369 {
05370   long lArbitrary = 0;
05371 
05372   srand((unsigned)time(NULL));
05373   lArbitrary = rand() % 100;
05374   return(lArbitrary);
05375 }
05376 
05377 siC *SiCNodeFind(siC *siCHeadNode, char *szInReferenceName)
05378 {
05379   siC *siCNode = siCHeadNode;
05380 
05381   do
05382   {
05383     if(siCNode == NULL)
05384       break;
05385 
05386     if(lstrcmpi(siCNode->szReferenceName, szInReferenceName) == 0)
05387       return(siCNode);
05388 
05389     siCNode = siCNode->Next;
05390   } while((siCNode != NULL) && (siCNode != siCHeadNode));
05391 
05392   return(NULL);
05393 }
05394 
05395 BOOL ResolveForceUpgrade(siC *siCObject)
05396 {
05397   DWORD dwIndex;
05398   char  szFilePath[MAX_BUF];
05399   char  szKey[MAX_BUF_TINY];
05400   char  szForceUpgradeFile[MAX_BUF];
05401 
05402   siCObject->bForceUpgrade = FALSE;
05403   if(siCObject->dwAttributes & SIC_FORCE_UPGRADE)
05404   {
05405     if(!sgProduct.doCleanupOnUpgrade)
05406     {
05407       dwIndex = 0;
05408       BuildNumberedString(dwIndex, NULL, "Force Upgrade File", szKey, sizeof(szKey));
05409       GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szForceUpgradeFile, sizeof(szForceUpgradeFile), szFileIniConfig);
05410       while(*szForceUpgradeFile != '\0')
05411       {
05412         DecryptString(szFilePath, szForceUpgradeFile);
05413         if(FileExists(szFilePath))
05414         {
05415           siCObject->bForceUpgrade = TRUE;
05416 
05417           /* Found at least one file, so break out of while loop */
05418           break;
05419         }
05420 
05421         BuildNumberedString(++dwIndex, NULL, "Force Upgrade File", szKey, sizeof(szKey));
05422         GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szForceUpgradeFile, sizeof(szForceUpgradeFile), szFileIniConfig);
05423       }
05424     }
05425 
05426     if(siCObject->bForceUpgrade)
05427     {
05428       siCObject->dwAttributes |= SIC_SELECTED;
05429       siCObject->dwAttributes |= SIC_DISABLED;
05430     }
05431     else
05432       /* Make sure to unset the DISABLED bit.  If the Setup Type is other than
05433        * Custom, then we don't care if it's DISABLED or not because this flag
05434        * is only used in the Custom dialogs.
05435        *
05436        * If the Setup Type is Custom and this component is DISABLED by default
05437        * via the config.ini, it's default value will be restored in the
05438        * SiCNodeSetItemsSelected() function that called ResolveForceUpgrade(). */
05439       siCObject->dwAttributes &= ~SIC_DISABLED;
05440   }
05441   return(siCObject->bForceUpgrade);
05442 }
05443 
05444 void InitSiComponents(char *szFileIni)
05445 {
05446   DWORD dwIndex0;
05447   DWORD dwIndex1;
05448   int   iCurrentLoop;
05449   char  szIndex0[MAX_BUF];
05450   char  szIndex1[MAX_BUF];
05451   char  szBuf[MAX_BUF];
05452   char  szComponentKey[MAX_BUF];
05453   char  szComponentSection[MAX_BUF];
05454   char  szDependency[MAX_BUF];
05455   char  szDependee[MAX_BUF];
05456   char  szSTSection[MAX_BUF];
05457   char  szDPSection[MAX_BUF];
05458   siC   *siCTemp            = NULL;
05459   siCD  *siCDepTemp         = NULL;
05460   siCD  *siCDDependeeTemp   = NULL;
05461 
05462   /* clean up the list before reading new components given the Setup Type */
05463   DeInitSiComponents(&siComponents);
05464 
05465   /* Parse the Setup Type sections in reverse order because
05466    * the Custom Setup Type is always last.  It needs to be parsed
05467    * first because the component list it has will be shown in its
05468    * other custom dialogs.  Order matters! */
05469   for(iCurrentLoop = 3; iCurrentLoop >= 0; iCurrentLoop--)
05470   {
05471     lstrcpy(szSTSection, "Setup Type");
05472     itoa(iCurrentLoop, szBuf, 10);
05473     lstrcat(szSTSection, szBuf);
05474 
05475     /* read in each component given a setup type */
05476     dwIndex0 = 0;
05477     itoa(dwIndex0, szIndex0, 10);
05478     lstrcpy(szComponentKey, "C");
05479     lstrcat(szComponentKey, szIndex0);
05480     GetPrivateProfileString(szSTSection, szComponentKey, "", szComponentSection, sizeof(szComponentSection), szFileIni);
05481     while(*szComponentSection != '\0')
05482     {
05483       GetPrivateProfileString(szComponentSection, "Archive", "", szBuf, sizeof(szBuf), szFileIni);
05484       if((*szBuf != '\0') && (SiCNodeFind(siComponents, szComponentSection) == NULL))
05485       {
05486         /* create and initialize empty node */
05487         siCTemp = CreateSiCNode();
05488 
05489         /* store name of archive for component */
05490         lstrcpy(siCTemp->szArchiveName, szBuf);
05491 
05492         /* store name of the uncompressed archive for the component */
05493         GetPrivateProfileString(szComponentSection,
05494                                 "Archive Uncompressed",
05495                                 "",
05496                                 siCTemp->szArchiveNameUncompressed,
05497                                 sizeof(szBuf),
05498                                 szFileIni);
05499         
05500         /* get short description of component */
05501         GetPrivateProfileString(szComponentSection, "Description Short", "", szBuf, sizeof(szBuf), szFileIni);
05502         lstrcpy(siCTemp->szDescriptionShort, szBuf);
05503 
05504         /* get long description of component */
05505         GetPrivateProfileString(szComponentSection, "Description Long", "", szBuf, sizeof(szBuf), szFileIni);
05506         lstrcpy(siCTemp->szDescriptionLong, szBuf);
05507 
05508         /* get commandline parameter for component */
05509         GetPrivateProfileString(szComponentSection, "Parameter", "", siCTemp->szParameter, MAX_BUF, szFileIni);
05510 
05511         /* set reference name for component */
05512         lstrcpy(siCTemp->szReferenceName, szComponentSection);
05513 
05514         /* get install size required in destination for component.  Sould be in Kilobytes */
05515         GetPrivateProfileString(szComponentSection, "Install Size", "", szBuf, sizeof(szBuf), szFileIni);
05516         if(*szBuf != '\0')
05517           siCTemp->ullInstallSize = _atoi64(szBuf);
05518         else
05519           siCTemp->ullInstallSize = 0;
05520 
05521         /* get install size required in system for component.  Sould be in Kilobytes */
05522         GetPrivateProfileString(szComponentSection, "Install Size System", "", szBuf, sizeof(szBuf), szFileIni);
05523         if(*szBuf != '\0')
05524           siCTemp->ullInstallSizeSystem = _atoi64(szBuf);
05525         else
05526           siCTemp->ullInstallSizeSystem = 0;
05527 
05528         /* get install size required in temp for component.  Sould be in Kilobytes */
05529         GetPrivateProfileString(szComponentSection, "Install Size Archive", "", szBuf, sizeof(szBuf), szFileIni);
05530         if(*szBuf != '\0')
05531           siCTemp->ullInstallSizeArchive = _atoi64(szBuf);
05532         else
05533           siCTemp->ullInstallSizeArchive = 0;
05534 
05535         /* get attributes of component */
05536         GetPrivateProfileString(szComponentSection, "Attributes", "", szBuf, sizeof(szBuf), szFileIni);
05537         siCTemp->dwAttributes = ParseComponentAttributes(szBuf, 0, FALSE);
05538 
05539         /* get the random percentage value and select or deselect the component (by default) for
05540          * installation */
05541         GetPrivateProfileString(szComponentSection, "Random Install Percentage", "", szBuf, sizeof(szBuf), szFileIni);
05542         if(*szBuf != '\0')
05543         {
05544           siCTemp->lRandomInstallPercentage = atol(szBuf);
05545           if(siCTemp->lRandomInstallPercentage != 0)
05546             siCTemp->lRandomInstallValue = RandomSelect();
05547         }
05548 
05549         /* get all dependencies for this component */
05550         dwIndex1 = 0;
05551         itoa(dwIndex1, szIndex1, 10);
05552         lstrcpy(szDependency, "Dependency");
05553         lstrcat(szDependency, szIndex1);
05554         GetPrivateProfileString(szComponentSection, szDependency, "", szBuf, sizeof(szBuf), szFileIni);
05555         while(*szBuf != '\0')
05556         {
05557           /* create and initialize empty node */
05558           siCDepTemp = CreateSiCDepNode();
05559 
05560           /* store name of archive for component */
05561           lstrcpy(siCDepTemp->szReferenceName, szBuf);
05562 
05563           /* inserts the newly created component into the global component list */
05564           SiCDepNodeInsert(&(siCTemp->siCDDependencies), siCDepTemp);
05565 
05566           ProcessWindowsMessages();
05567           ++dwIndex1;
05568           itoa(dwIndex1, szIndex1, 10);
05569           lstrcpy(szDependency, "Dependency");
05570           lstrcat(szDependency, szIndex1);
05571           GetPrivateProfileString(szComponentSection, szDependency, "", szBuf, sizeof(szBuf), szFileIni);
05572         }
05573 
05574         /* get all dependees for this component */
05575         dwIndex1 = 0;
05576         itoa(dwIndex1, szIndex1, 10);
05577         lstrcpy(szDependee, "Dependee");
05578         lstrcat(szDependee, szIndex1);
05579         GetPrivateProfileString(szComponentSection, szDependee, "", szBuf, sizeof(szBuf), szFileIni);
05580         while(*szBuf != '\0')
05581         {
05582           /* create and initialize empty node */
05583           siCDDependeeTemp = CreateSiCDepNode();
05584 
05585           /* store name of archive for component */
05586           lstrcpy(siCDDependeeTemp->szReferenceName, szBuf);
05587 
05588           /* inserts the newly created component into the global component list */
05589           SiCDepNodeInsert(&(siCTemp->siCDDependees), siCDDependeeTemp);
05590 
05591           ProcessWindowsMessages();
05592           ++dwIndex1;
05593           itoa(dwIndex1, szIndex1, 10);
05594           lstrcpy(szDependee, "Dependee");
05595           lstrcat(szDependee, szIndex1);
05596           GetPrivateProfileString(szComponentSection, szDependee, "", szBuf, sizeof(szBuf), szFileIni);
05597         }
05598 
05599         // locate previous path if necessary
05600         lstrcpy(szDPSection, szComponentSection);
05601         lstrcat(szDPSection, "-Destination Path");
05602         if(LocatePreviousPath(szDPSection, siCTemp->szDestinationPath, MAX_PATH) == FALSE)
05603           ZeroMemory(siCTemp->szDestinationPath, MAX_PATH);
05604 
05605         /* inserts the newly created component into the global component list */
05606         SiCNodeInsert(&siComponents, siCTemp);
05607       }
05608 
05609       ProcessWindowsMessages();
05610       ++dwIndex0;
05611       itoa(dwIndex0, szIndex0, 10);
05612       lstrcpy(szComponentKey, "C");
05613       lstrcat(szComponentKey, szIndex0);
05614       GetPrivateProfileString(szSTSection, szComponentKey, "", szComponentSection, sizeof(szComponentSection), szFileIni);
05615     }
05616   }
05617 
05618   sgProduct.dwNumberOfComponents = dwIndex0;
05619 }
05620 
05621 void ResetComponentAttributes(char *szFileIni)
05622 {
05623   char  szIndex[MAX_BUF];
05624   char  szBuf[MAX_BUF];
05625   char  szComponentItem[MAX_BUF];
05626   siC   *siCTemp;
05627   DWORD dwCounter;
05628 
05629   for(dwCounter = 0; dwCounter < sgProduct.dwNumberOfComponents; dwCounter++)
05630   {
05631     itoa(dwCounter, szIndex, 10);
05632     lstrcpy(szComponentItem, "Component");
05633     lstrcat(szComponentItem, szIndex);
05634 
05635     siCTemp = SiCNodeGetObject(dwCounter, TRUE, AC_ALL);
05636     GetPrivateProfileString(szComponentItem, "Attributes", "", szBuf, sizeof(szBuf), szFileIni);
05637     siCTemp->dwAttributes = ParseComponentAttributes(szBuf, 0, FALSE);
05638   }
05639 }
05640 
05641 void UpdateSiteSelector()
05642 {
05643   DWORD dwIndex;
05644   char  szIndex[MAX_BUF];
05645   char  szKDescription[MAX_BUF];
05646   char  szDescription[MAX_BUF];
05647   char  szKDomain[MAX_BUF];
05648   char  szDomain[MAX_BUF];
05649   char  szFileIniRedirect[MAX_BUF];
05650   ssi   *ssiSiteSelectorTemp;
05651 
05652   lstrcpy(szFileIniRedirect, szTempDir);
05653   AppendBackSlash(szFileIniRedirect, sizeof(szFileIniRedirect));
05654   lstrcat(szFileIniRedirect, FILE_INI_REDIRECT);
05655 
05656   if(FileExists(szFileIniRedirect) == FALSE)
05657     return;
05658 
05659   /* get all dependees for this component */
05660   dwIndex = 0;
05661   itoa(dwIndex, szIndex, 10);
05662   lstrcpy(szKDescription, "Description");
05663   lstrcpy(szKDomain,      "Domain");
05664   lstrcat(szKDescription, szIndex);
05665   lstrcat(szKDomain,      szIndex);
05666   GetPrivateProfileString("Site Selector", szKDescription, "", szDescription, sizeof(szDescription), szFileIniRedirect);
05667   while(*szDescription != '\0')
05668   {
05669     if(lstrcmpi(szDescription, szSiteSelectorDescription) == 0)
05670     {
05671       GetPrivateProfileString("Site Selector", szKDomain, "", szDomain, sizeof(szDomain), szFileIniRedirect);
05672       if(*szDomain != '\0')
05673       {
05674         ssiSiteSelectorTemp = SsiGetNode(szDescription);
05675         if(ssiSiteSelectorTemp != NULL)
05676         {
05677           lstrcpy(ssiSiteSelectorTemp->szDomain, szDomain);
05678         }
05679         else
05680         {
05681           /* no match found for the given domain description, so assume there's nothing
05682            * to change. just return. */
05683           return;
05684         }
05685       }
05686       else
05687       {
05688         /* found matched description, but domain was not set, so assume there's no
05689          * redirect required, just return. */
05690         return;
05691       }
05692     }
05693 
05694     ++dwIndex;
05695     itoa(dwIndex, szIndex, 10);
05696     lstrcpy(szKDescription, "Description");
05697     lstrcpy(szKDomain,      "Domain");
05698     lstrcat(szKDescription, szIndex);
05699     lstrcat(szKDomain,      szIndex);
05700     ZeroMemory(szDescription, sizeof(szDescription));
05701     ZeroMemory(szDomain,      sizeof(szDomain));
05702     GetPrivateProfileString("Site Selector", szKDescription, "", szDescription, sizeof(szDescription), szFileIniRedirect);
05703   }
05704 }
05705 
05706 void InitSiteSelector(char *szFileIni)
05707 {
05708   DWORD dwIndex;
05709   char  szIndex[MAX_BUF];
05710   char  szKDescription[MAX_BUF];
05711   char  szDescription[MAX_BUF];
05712   char  szKDomain[MAX_BUF];
05713   char  szDomain[MAX_BUF];
05714   char  szKIdentifier[MAX_BUF];
05715   char  szIdentifier[MAX_BUF];
05716   ssi   *ssiSiteSelectorNewNode;
05717 
05718   ssiSiteSelector = NULL;
05719 
05720   /* get all dependees for this component */
05721   dwIndex = 0;
05722   itoa(dwIndex, szIndex, 10);
05723   lstrcpy(szKDescription, "Description");
05724   lstrcpy(szKDomain,      "Domain");
05725   lstrcpy(szKIdentifier,  "Identifier");
05726   lstrcat(szKDescription, szIndex);
05727   lstrcat(szKDomain,      szIndex);
05728   lstrcat(szKIdentifier,  szIndex);
05729   GetPrivateProfileString("Site Selector", szKDescription, "", szDescription, sizeof(szDescription), szFileIni);
05730   while(*szDescription != '\0')
05731   {
05732     /* if the Domain and Identifier are not set, then skip */
05733     GetPrivateProfileString("Site Selector", szKDomain,     "", szDomain,     sizeof(szDomain), szFileIni);
05734     GetPrivateProfileString("Site Selector", szKIdentifier, "", szIdentifier, sizeof(szIdentifier), szFileIni);
05735     if((*szDomain != '\0') && (*szIdentifier != '\0'))
05736     {
05737       /* create and initialize empty node */
05738       ssiSiteSelectorNewNode = CreateSsiSiteSelectorNode();
05739 
05740       lstrcpy(ssiSiteSelectorNewNode->szDescription, szDescription);
05741       lstrcpy(ssiSiteSelectorNewNode->szDomain,      szDomain);
05742       lstrcpy(ssiSiteSelectorNewNode->szIdentifier,  szIdentifier);
05743 
05744       /* inserts the newly created node into the global node list */
05745       SsiSiteSelectorNodeInsert(&(ssiSiteSelector), ssiSiteSelectorNewNode);
05746     }
05747 
05748     ProcessWindowsMessages();
05749     ++dwIndex;
05750     itoa(dwIndex, szIndex, 10);
05751     lstrcpy(szKDescription, "Description");
05752     lstrcpy(szKDomain,      "Domain");
05753     lstrcpy(szKIdentifier,  "Identifier");
05754     lstrcat(szKDescription, szIndex);
05755     lstrcat(szKDomain,      szIndex);
05756     lstrcat(szKIdentifier,  szIndex);
05757     ZeroMemory(szDescription, sizeof(szDescription));
05758     ZeroMemory(szDomain,      sizeof(szDomain));
05759     ZeroMemory(szIdentifier,  sizeof(szIdentifier));
05760     GetPrivateProfileString("Site Selector", szKDescription, "", szDescription, sizeof(szDescription), szFileIni);
05761   }
05762 }
05763 
05764 void InitErrorMessageStream(char *szFileIni)
05765 {
05766   char szBuf[MAX_BUF_TINY];
05767 
05768   GetPrivateProfileString("Message Stream",
05769                           "Status",
05770                           "",
05771                           szBuf,
05772                           sizeof(szBuf),
05773                           szFileIni);
05774 
05775   if(lstrcmpi(szBuf, "disabled") == 0)
05776     gErrorMessageStream.bEnabled = FALSE;
05777   else
05778     gErrorMessageStream.bEnabled = TRUE;
05779 
05780   GetPrivateProfileString("Message Stream",
05781                           "url",
05782                           "",
05783                           gErrorMessageStream.szURL,
05784                           sizeof(gErrorMessageStream.szURL),
05785                           szFileIni);
05786 
05787   GetPrivateProfileString("Message Stream",
05788                           "Show Confirmation",
05789                           "",
05790                           szBuf,
05791                           sizeof(szBuf),
05792                           szFileIni);
05793   if(strcmpi(szBuf, "FALSE") == 0)
05794     gErrorMessageStream.bShowConfirmation = FALSE;
05795   else
05796     gErrorMessageStream.bShowConfirmation = TRUE;
05797 
05798   GetPrivateProfileString("Message Stream",
05799                           "Confirmation Message",
05800                           "",
05801                           gErrorMessageStream.szConfirmationMessage,
05802                           sizeof(szBuf),
05803                           szFileIni);
05804 
05805   gErrorMessageStream.bSendMessage = FALSE;
05806   gErrorMessageStream.dwMessageBufSize = MAX_BUF;
05807   gErrorMessageStream.szMessage = NS_GlobalAlloc(gErrorMessageStream.dwMessageBufSize);
05808 }
05809 
05810 void DeInitErrorMessageStream()
05811 {
05812   FreeMemory(&gErrorMessageStream.szMessage);
05813 }
05814 
05815 #ifdef SSU_DEBUG
05816 void ViewSiComponentsDependency(char *szBuffer, char *szIndentation, siC *siCNode)
05817 {
05818   siC  *siCNodeTemp;
05819   siCD *siCDependencyTemp;
05820 
05821   siCDependencyTemp = siCNode->siCDDependencies;
05822   if(siCDependencyTemp != NULL)
05823   {
05824     char  szIndentationPadding[MAX_BUF];
05825     DWORD dwIndex;
05826 
05827     lstrcpy(szIndentationPadding, szIndentation);
05828     lstrcat(szIndentationPadding, "    ");
05829 
05830     do
05831     {
05832       lstrcat(szBuffer, szIndentationPadding);
05833       lstrcat(szBuffer, siCDependencyTemp->szReferenceName);
05834       lstrcat(szBuffer, "::");
05835 
05836       if((dwIndex = SiCNodeGetIndexRN(siCDependencyTemp->szReferenceName)) != -1)
05837         lstrcat(szBuffer, SiCNodeGetDescriptionShort(dwIndex, TRUE, AC_ALL));
05838       else
05839         lstrcat(szBuffer, "Component does not exist");
05840 
05841       lstrcat(szBuffer, ":");
05842       lstrcat(szBuffer, "\n");
05843 
05844       if(dwIndex != -1)
05845       {
05846         if((siCNodeTemp = SiCNodeGetObject(dwIndex, TRUE, AC_ALL)) != NULL)
05847           ViewSiComponentsDependency(szBuffer, szIndentationPadding, siCNodeTemp);
05848         else
05849           lstrcat(szBuffer, "Node not found");
05850       }
05851 
05852       siCDependencyTemp = siCDependencyTemp->Next;
05853     }while((siCDependencyTemp != NULL) && (siCDependencyTemp != siCNode->siCDDependencies));
05854   }
05855 }
05856 
05857 void ViewSiComponentsDependee(char *szBuffer, char *szIndentation, siC *siCNode)
05858 {
05859   siC  *siCNodeTemp;
05860   siCD *siCDependeeTemp;
05861 
05862   siCDependeeTemp = siCNode->siCDDependees;
05863   if(siCDependeeTemp != NULL)
05864   {
05865     char  szIndentationPadding[MAX_BUF];
05866     DWORD dwIndex;
05867 
05868     lstrcpy(szIndentationPadding, szIndentation);
05869     lstrcat(szIndentationPadding, "    ");
05870 
05871     do
05872     {
05873       lstrcat(szBuffer, szIndentationPadding);
05874       lstrcat(szBuffer, siCDependeeTemp->szReferenceName);
05875       lstrcat(szBuffer, "::");
05876 
05877       if((dwIndex = SiCNodeGetIndexRN(siCDependeeTemp->szReferenceName)) != -1)
05878         lstrcat(szBuffer, SiCNodeGetDescriptionShort(dwIndex, TRUE, AC_ALL));
05879       else
05880         lstrcat(szBuffer, "Component does not exist");
05881 
05882       lstrcat(szBuffer, ":");
05883       lstrcat(szBuffer, "\n");
05884 
05885       if(dwIndex != -1)
05886       {
05887         if((siCNodeTemp = SiCNodeGetObject(dwIndex, TRUE, AC_ALL)) != NULL)
05888           ViewSiComponentsDependency(szBuffer, szIndentationPadding, siCNodeTemp);
05889         else
05890           lstrcat(szBuffer, "Node not found");
05891       }
05892 
05893       siCDependeeTemp = siCDependeeTemp->Next;
05894     }while((siCDependeeTemp != NULL) && (siCDependeeTemp != siCNode->siCDDependees));
05895   }
05896 }
05897 
05898 void ViewSiComponents()
05899 {
05900   char  szBuf[MAX_BUF];
05901   siC   *siCTemp = siComponents;
05902 
05903   // build dependency list
05904   ZeroMemory(szBuf, sizeof(szBuf));
05905   lstrcpy(szBuf, "Dependency:\n");
05906 
05907   do
05908   {
05909     if(siCTemp == NULL)
05910       break;
05911 
05912     lstrcat(szBuf, "    ");
05913     lstrcat(szBuf, siCTemp->szReferenceName);
05914     lstrcat(szBuf, "::");
05915     lstrcat(szBuf, siCTemp->szDescriptionShort);
05916     lstrcat(szBuf, ":\n");
05917 
05918     ViewSiComponentsDependency(szBuf, "    ", siCTemp);
05919 
05920     siCTemp = siCTemp->Next;
05921   } while((siCTemp != NULL) && (siCTemp != siComponents));
05922 
05923   MessageBox(hWndMain, szBuf, NULL, MB_ICONEXCLAMATION);
05924 
05925   // build dependee list
05926   ZeroMemory(szBuf, sizeof(szBuf));
05927   lstrcpy(szBuf, "Dependee:\n");
05928 
05929   do
05930   {
05931     if(siCTemp == NULL)
05932       break;
05933 
05934     lstrcat(szBuf, "    ");
05935     lstrcat(szBuf, siCTemp->szReferenceName);
05936     lstrcat(szBuf, "::");
05937     lstrcat(szBuf, siCTemp->szDescriptionShort);
05938     lstrcat(szBuf, ":\n");
05939 
05940     ViewSiComponentsDependee(szBuf, "    ", siCTemp);
05941 
05942     siCTemp = siCTemp->Next;
05943   } while((siCTemp != NULL) && (siCTemp != siComponents));
05944 
05945   MessageBox(hWndMain, szBuf, NULL, MB_ICONEXCLAMATION);
05946 }
05947 #endif /* SSU_DEBUG */
05948 
05949 void DeInitSiCDependencies(siCD *siCDDependencies)
05950 {
05951   siCD   *siCDepTemp;
05952   
05953   if(siCDDependencies == NULL)
05954   {
05955     return;
05956   }
05957   else if((siCDDependencies->Prev == NULL) || (siCDDependencies->Prev == siCDDependencies))
05958   {
05959     SiCDepNodeDelete(siCDDependencies);
05960     return;
05961   }
05962   else
05963   {
05964     siCDepTemp = siCDDependencies->Prev;
05965   }
05966 
05967   while(siCDepTemp != siCDDependencies)
05968   {
05969     SiCDepNodeDelete(siCDepTemp);
05970     siCDepTemp = siCDDependencies->Prev;
05971   }
05972   SiCDepNodeDelete(siCDepTemp);
05973 }
05974 
05975 void DeInitSiComponents(siC **siCHeadNode)
05976 {
05977   siC   *siCTemp;
05978   
05979   if((*siCHeadNode) == NULL)
05980   {
05981     return;
05982   }
05983   else if(((*siCHeadNode)->Prev == NULL) || ((*siCHeadNode)->Prev == (*siCHeadNode)))
05984   {
05985     SiCNodeDelete((*siCHeadNode));
05986     return;
05987   }
05988   else
05989   {
05990     siCTemp = (*siCHeadNode)->Prev;
05991   }
05992 
05993   while(siCTemp != (*siCHeadNode))
05994   {
05995     SiCNodeDelete(siCTemp);
05996     siCTemp = (*siCHeadNode)->Prev;
05997   }
05998   SiCNodeDelete(siCTemp);
05999 }
06000 
06001 void DeInitDSNode(dsN **dsnComponentDSRequirement)
06002 {
06003   dsN *dsNTemp;
06004   
06005   if(*dsnComponentDSRequirement == NULL)
06006   {
06007     return;
06008   }
06009   else if(((*dsnComponentDSRequirement)->Prev == NULL) || ((*dsnComponentDSRequirement)->Prev == *dsnComponentDSRequirement))
06010   {
06011     DsNodeDelete(dsnComponentDSRequirement);
06012     return;
06013   }
06014   else
06015   {
06016     dsNTemp = (*dsnComponentDSRequirement)->Prev;
06017   }
06018 
06019   while(dsNTemp != *dsnComponentDSRequirement)
06020   {
06021     DsNodeDelete(&dsNTemp);
06022     dsNTemp = (*dsnComponentDSRequirement)->Prev;
06023   }
06024   DsNodeDelete(dsnComponentDSRequirement);
06025 }
06026 
06027 BOOL ResolveComponentDependency(siCD *siCDInDependency, HWND hwndListBox)
06028 {
06029   int     dwIndex;
06030   siCD    *siCDepTemp = siCDInDependency;
06031   BOOL    bMoreToResolve = FALSE;
06032   DWORD   dwAttrib;
06033 
06034   if(siCDepTemp != NULL)
06035   {
06036     if((dwIndex = SiCNodeGetIndexRN(siCDepTemp->szReferenceName)) != -1)
06037     {
06038       dwAttrib = SiCNodeGetAttributes(dwIndex, TRUE, AC_ALL);
06039       if(!(dwAttrib & SIC_SELECTED) && !(dwAttrib & SIC_DISABLED))
06040       {
06041         bMoreToResolve = TRUE;
06042         SiCNodeSetAttributes(dwIndex, SIC_SELECTED, TRUE, TRUE, AC_ALL, hwndListBox);
06043       }
06044     }
06045 
06046     siCDepTemp = siCDepTemp->Next;
06047     while((siCDepTemp != NULL) && (siCDepTemp != siCDInDependency))
06048     {
06049       if((dwIndex = SiCNodeGetIndexRN(siCDepTemp->szReferenceName)) != -1)
06050       {
06051         dwAttrib = SiCNodeGetAttributes(dwIndex, TRUE, AC_ALL);
06052         if(!(dwAttrib & SIC_SELECTED) && !(dwAttrib & SIC_DISABLED))
06053         {
06054           bMoreToResolve = TRUE;
06055           SiCNodeSetAttributes(dwIndex, SIC_SELECTED, TRUE, TRUE, AC_ALL, hwndListBox);
06056         }
06057       }
06058 
06059       siCDepTemp = siCDepTemp->Next;
06060     }
06061   }
06062   return(bMoreToResolve);
06063 }
06064 
06065 BOOL ResolveDependencies(DWORD dwIndex, HWND hwndListBox)
06066 {
06067   BOOL  bMoreToResolve  = FALSE;
06068   DWORD dwCount         = 0;
06069   siC   *siCTemp        = siComponents;
06070 
06071   if(siCTemp != NULL)
06072   {
06073     /* can resolve specific component or all components (-1) */
06074     if((dwIndex == dwCount) || (dwIndex == -1))
06075     {
06076       if(SiCNodeGetAttributes(dwCount, TRUE, AC_ALL) & SIC_SELECTED)
06077       {
06078          bMoreToResolve = ResolveComponentDependency(siCTemp->siCDDependencies, hwndListBox);
06079          if(dwIndex == dwCount)
06080          {
06081            return(bMoreToResolve);
06082          }
06083       }
06084     }
06085 
06086     ++dwCount;
06087     siCTemp = siCTemp->Next;
06088     while((siCTemp != NULL) && (siCTemp != siComponents))
06089     {
06090       /* can resolve specific component or all components (-1) */
06091       if((dwIndex == dwCount) || (dwIndex == -1))
06092       {
06093         if(SiCNodeGetAttributes(dwCount, TRUE, AC_ALL) & SIC_SELECTED)
06094         {
06095            bMoreToResolve = ResolveComponentDependency(siCTemp->siCDDependencies, hwndListBox);
06096            if(dwIndex == dwCount)
06097            {
06098              return(bMoreToResolve);
06099            }
06100         }
06101       }
06102 
06103       ++dwCount;
06104       siCTemp = siCTemp->Next;
06105     }
06106   }
06107   return(bMoreToResolve);
06108 }
06109 
06110 BOOL ResolveComponentDependee(siCD *siCDInDependee)
06111 {
06112   int     dwIndex;
06113   siCD    *siCDDependeeTemp   = siCDInDependee;
06114   BOOL    bAtLeastOneSelected = FALSE;
06115 
06116   if(siCDDependeeTemp != NULL)
06117   {
06118     if((dwIndex = SiCNodeGetIndexRN(siCDDependeeTemp->szReferenceName)) != -1)
06119     {
06120       if((SiCNodeGetAttributes(dwIndex, TRUE, AC_ALL) & SIC_SELECTED) == TRUE)
06121       {
06122         bAtLeastOneSelected = TRUE;
06123       }
06124     }
06125 
06126     siCDDependeeTemp = siCDDependeeTemp->Next;
06127     while((siCDDependeeTemp != NULL) && (siCDDependeeTemp != siCDInDependee))
06128     {
06129       if((dwIndex = SiCNodeGetIndexRN(siCDDependeeTemp->szReferenceName)) != -1)
06130       {
06131         if((SiCNodeGetAttributes(dwIndex, TRUE, AC_ALL) & SIC_SELECTED) == TRUE)
06132         {
06133           bAtLeastOneSelected = TRUE;
06134         }
06135       }
06136 
06137       siCDDependeeTemp = siCDDependeeTemp->Next;
06138     }
06139   }
06140   return(bAtLeastOneSelected);
06141 }
06142 
06143 ssi* SsiGetNode(LPSTR szDescription)
06144 {
06145   ssi *ssiSiteSelectorTemp = ssiSiteSelector;
06146 
06147   do
06148   {
06149     if(ssiSiteSelectorTemp == NULL)
06150       break;
06151 
06152     if(lstrcmpi(ssiSiteSelectorTemp->szDescription, szDescription) == 0)
06153       return(ssiSiteSelectorTemp);
06154 
06155     ssiSiteSelectorTemp = ssiSiteSelectorTemp->Next;
06156   } while((ssiSiteSelectorTemp != NULL) && (ssiSiteSelectorTemp != ssiSiteSelector));
06157 
06158   return(NULL);
06159 }
06160 
06161 void ResolveDependees(LPSTR szToggledReferenceName, HWND hwndListBox)
06162 {
06163   BOOL  bAtLeastOneSelected;
06164   BOOL  bMoreToResolve  = FALSE;
06165   siC   *siCTemp        = siComponents;
06166   DWORD dwIndex;
06167   DWORD dwAttrib;
06168 
06169   do
06170   {
06171     if(siCTemp == NULL)
06172       break;
06173 
06174     if((siCTemp->siCDDependees != NULL) &&
06175        (lstrcmpi(siCTemp->szReferenceName, szToggledReferenceName) != 0))
06176     {
06177       bAtLeastOneSelected = ResolveComponentDependee(siCTemp->siCDDependees);
06178       if(bAtLeastOneSelected == FALSE)
06179       {
06180         if((dwIndex = SiCNodeGetIndexRN(siCTemp->szReferenceName)) != -1)
06181         {
06182           dwAttrib = SiCNodeGetAttributes(dwIndex, TRUE, AC_ALL);
06183           if((dwAttrib & SIC_SELECTED) && !(dwAttrib & SIC_DISABLED))
06184           {
06185             SiCNodeSetAttributes(dwIndex, SIC_SELECTED, FALSE, TRUE, AC_ALL, hwndListBox);
06186             bMoreToResolve = TRUE;
06187           }
06188         }
06189       }
06190       else
06191       {
06192         if((dwIndex = SiCNodeGetIndexRN(siCTemp->szReferenceName)) != -1)
06193         {
06194           dwAttrib = SiCNodeGetAttributes(dwIndex, TRUE, AC_ALL);
06195           if(!(dwAttrib & SIC_SELECTED) && !(dwAttrib & SIC_DISABLED))
06196           {
06197             SiCNodeSetAttributes(dwIndex, SIC_SELECTED, TRUE, TRUE, AC_ALL, hwndListBox);
06198             bMoreToResolve = TRUE;
06199           }
06200         }
06201       }
06202     }
06203 
06204     siCTemp = siCTemp->Next;
06205   } while((siCTemp != NULL) && (siCTemp != siComponents));
06206 
06207   if(bMoreToResolve == TRUE)
06208     ResolveDependees(szToggledReferenceName, hwndListBox);
06209 }
06210 
06211 /* Function: ReplacePrivateProfileStrCR()
06212  *
06213  *       in: LPSTR aInputOutputStr: In/out string to containing "\\n" to replace.
06214  *           
06215  *  purpose: To parse for and replace "\\n" string with "\n".  Strings stored
06216  *           in .ini files cannot contain "\n" because it's a key delimiter.
06217  *           To work around this limination, "\\n" chars can be used to
06218  *           represent '\n'.  This function will look for "\\n" and replace
06219  *           them with a true "\n".
06220  *           If it encounters a string of "\\\\n" (which looks like '\\n'),
06221  *           then this function will strip out the extra '\\' and just show
06222  *           "\\n";
06223  */
06224 void ReplacePrivateProfileStrCR(LPSTR aInputOutputStr)
06225 {
06226   LPSTR pSearch          = aInputOutputStr;
06227   LPSTR pSearchEnd       = aInputOutputStr + lstrlen(aInputOutputStr);
06228   LPSTR pPreviousSearch  = NULL;
06229 
06230   while (pSearch < pSearchEnd)
06231   {
06232     if (('\\' == *pSearch) || ('n' == *pSearch))
06233     {
06234       // found a '\\' or 'n'.  check to see if  the prefivous char is also a '\\'.
06235       if (pPreviousSearch && ('\\' == *pPreviousSearch))
06236       {
06237         if ('n' == *pSearch)
06238           *pSearch = '\n';
06239 
06240         memmove(pPreviousSearch, pSearch, pSearchEnd-pSearch+1);
06241 
06242         // our string is shorter now ...
06243         pSearchEnd -= pSearch - pPreviousSearch;
06244       }
06245     }
06246 
06247     pPreviousSearch = pSearch;
06248     pSearch = CharNext(pSearch);
06249   }
06250 }
06251 
06252 void PrintUsage(void)
06253 {
06254   char szBuf[MAX_BUF];
06255   char szUsageMsg[MAX_BUF];
06256   char szProcessFilename[MAX_BUF];
06257 
06258   /* -h: this help
06259    * -a [path]: Alternate archive search path
06260    * -app: ID of application which is launching the installer  (Shared installs)
06261    * -app_path: Points to representative file of app (Shared installs)
06262    * -dd [path]: Suggested install destination directory. (Shared installs)
06263    * -greLocal: Forces GRE to be installed into the application dir.
06264    * -greShared: Forces GRE to be installed into a global, shared dir (normally
06265    *    c:\program files\common files\mozilla.org\GRE
06266    * -reg_path [path]: Where to make entries in the Windows registry. (Shared installs)
06267    * -f: Force install of GRE installer (Shared installs), though it'll work
06268    *    for non GRE installers too.
06269    * -greForce: Force 'Component GRE' to be downloaded, run, and installed.  This
06270    *    bypasses GRE's logic of determining when to install by running its
06271    *    installer with a '-f' flag.
06272    * -n [filename]: setup's parent's process filename
06273    * -ma: run setup in Auto mode
06274    * -mmi: Allow multiple installer instances. (Shared installs)
06275    * -showBanner: Show the banner in the download and install process dialogs.
06276    *              This will override config.ini
06277    * -hideBanner: Hides the banner in the download and install process dialogs.
06278    *              This will override config.ini
06279    * -ms: run setup in Silent mode
06280    * -ira: ignore the [RunAppX] sections
06281    * -ispf: ignore the [Program FolderX] sections that show
06282    *        the Start Menu shortcut folder at the end of installation.
06283    */
06284 
06285   if(sgProduct.szParentProcessFilename && *sgProduct.szParentProcessFilename != '\0')
06286     ParsePath(sgProduct.szParentProcessFilename, szProcessFilename, sizeof(szProcessFilename), FALSE, PP_FILENAME_ONLY);
06287   else
06288   {
06289     GetModuleFileName(NULL, szBuf, sizeof(szBuf));
06290     ParsePath(szBuf, szProcessFilename, sizeof(szProcessFilename), FALSE, PP_FILENAME_ONLY);
06291   }
06292 
06293   GetPrivateProfileString("Strings", "UsageMsg Usage", "", szBuf, sizeof(szBuf), szFileIniConfig);
06294   if (lstrlen(szBuf) > 0)
06295   {
06296     char strUsage[MAX_BUF];
06297 
06298     ReplacePrivateProfileStrCR(szBuf);
06299     _snprintf(szUsageMsg, sizeof(szUsageMsg), szBuf, szProcessFilename);
06300     szUsageMsg[sizeof(szUsageMsg) - 1] = '\0';
06301     GetPrivateProfileString("Messages", "DLG_USAGE_TITLE", "", strUsage, sizeof(strUsage), szFileIniInstall);
06302     ShowMessage(NULL, FALSE);
06303     MessageBox(hWndMain, szUsageMsg, strUsage, MB_ICONEXCLAMATION);
06304   }
06305 }
06306 
06307 /* Function: ParseForStartupOptions()
06308  *       in: aCmdLine
06309  *  purpose: Parses for options that affect the initialization of setup.exe,
06310  *           such as -ms, -ma, -mmi.
06311  *           This is required to be parsed this early because setup needs to
06312  *           know if dialogs need to be shown (-ms, -ma) and also where to
06313  *           create the temp directory for temporary items to be placed at
06314  *           (-mmi).
06315  */
06316 DWORD ParseForStartupOptions(LPSTR aCmdLine)
06317 {
06318   char  szArgVBuf[MAX_BUF];
06319   int   i;
06320   int   iArgC;
06321 
06322 #ifdef XXX_DEBUG
06323   char  szBuf[MAX_BUF];
06324   char  szOutputStr[MAX_BUF];
06325 #endif
06326 
06327   iArgC = GetArgC(aCmdLine);
06328 
06329 #ifdef XXX_DEBUG
06330   wsprintf(szOutputStr, "ArgC: %d\n", iArgC);
06331 #endif
06332 
06333   i = 0;
06334   while(i < iArgC)
06335   {
06336     GetArgV(aCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06337 
06338     if(!lstrcmpi(szArgVBuf, "-mmi") || !lstrcmpi(szArgVBuf, "/mmi"))
06339     {
06340       gbAllowMultipleInstalls = TRUE;    
06341     }
06342     else if(!lstrcmpi(szArgVBuf, "-ma") || !lstrcmpi(szArgVBuf, "/ma"))
06343       SetSetupRunMode("AUTO");
06344     else if(!lstrcmpi(szArgVBuf, "-ms") || !lstrcmpi(szArgVBuf, "/ms"))
06345       SetSetupRunMode("SILENT");
06346 
06347 #ifdef XXX_DEBUG
06348     itoa(i, szBuf, 10);
06349     lstrcat(szOutputStr, "    ");
06350     lstrcat(szOutputStr, szBuf);
06351     lstrcat(szOutputStr, ": ");
06352     lstrcat(szOutputStr, szArgVBuf);
06353     lstrcat(szOutputStr, "\n");
06354 #endif
06355 
06356     ++i;
06357   }
06358 
06359 #ifdef XXX_DEBUG
06360   MessageBox(NULL, szOutputStr, "Output", MB_OK);
06361 #endif
06362   return(WIZ_OK);
06363 }
06364 
06365 DWORD ParseCommandLine(LPSTR lpszCmdLine)
06366 {
06367   char  szArgVBuf[MAX_BUF];
06368   int   i;
06369   int   iArgC;
06370 
06371 #ifdef XXX_DEBUG
06372   char  szBuf[MAX_BUF];
06373   char  szOutputStr[MAX_BUF];
06374 #endif
06375 
06376   iArgC = GetArgC(lpszCmdLine);
06377 
06378 #ifdef XXX_DEBUG
06379   wsprintf(szOutputStr, "ArgC: %d\n", iArgC);
06380 #endif
06381 
06382   i = 0;
06383   while(i < iArgC)
06384   {
06385     GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06386 
06387     if(!lstrcmpi(szArgVBuf, "-h") || !lstrcmpi(szArgVBuf, "/h"))
06388     {
06389       ShowMessage(NULL, FALSE);
06390       PrintUsage();
06391       return(WIZ_ERROR_UNDEFINED);
06392     }
06393     else if(!lstrcmpi(szArgVBuf, "-a") || !lstrcmpi(szArgVBuf, "/a"))
06394     {
06395       ++i;
06396       GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06397       lstrcpy(sgProduct.szAlternateArchiveSearchPath, szArgVBuf);
06398     }
06399     else if(!lstrcmpi(szArgVBuf, "-greForce") || !lstrcmpi(szArgVBuf, "/greForce"))
06400     {
06401       gbForceInstallGre = TRUE;
06402     }
06403     else if(!lstrcmpi(szArgVBuf, "-greLocal") || !lstrcmpi(szArgVBuf, "/greLocal"))
06404     {
06405       sgProduct.greType = GRE_LOCAL;
06406     }
06407     else if(!lstrcmpi(szArgVBuf, "-greShared") || !lstrcmpi(szArgVBuf, "/greShared"))
06408     {
06409       sgProduct.greType = GRE_SHARED;
06410     }
06411     else if(!lstrcmpi(szArgVBuf, "-f") || !lstrcmpi(szArgVBuf, "/f"))
06412     {
06413       gbForceInstall = TRUE;
06414     }
06415     else if(!lstrcmpi(szArgVBuf, "-n") || !lstrcmpi(szArgVBuf, "/n"))
06416     {
06417       ++i;
06418       GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06419       lstrcpy(sgProduct.szParentProcessFilename, szArgVBuf);
06420     }
06421     else if(!lstrcmpi(szArgVBuf, "-ira") || !lstrcmpi(szArgVBuf, "/ira"))
06422       /* ignore [RunAppX] sections */
06423       gbIgnoreRunAppX = TRUE;
06424     else if(!lstrcmpi(szArgVBuf, "-ispf") || !lstrcmpi(szArgVBuf, "/ispf"))
06425       /* ignore [Program FolderX] sections */
06426       gbIgnoreProgramFolderX = TRUE;
06427     else if(!lstrcmpi(szArgVBuf, "-dd") || !lstrcmpi(szArgVBuf, "/dd"))
06428     {
06429       ++i;
06430       GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06431       lstrcpy(sgProduct.szPath, szArgVBuf);
06432     }
06433     // identifies the app which is installing for shared installs
06434     else if(!lstrcmpi(szArgVBuf, "-app") || !lstrcmpi(szArgVBuf, "/app"))
06435     {
06436       ++i;
06437       GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06438       lstrcpy(sgProduct.szAppID, szArgVBuf);
06439     }
06440     // points to a file belonging to the app which can be searched to determine
06441     //    if the app is installed
06442     else if(!lstrcmpi(szArgVBuf, "-app_path") || !lstrcmpi(szArgVBuf, "/app_path"))
06443     {
06444       ++i;
06445       GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06446       lstrcpy(sgProduct.szAppPath, szArgVBuf);
06447     }
06448     // alternative path in Windows registry, for private sharable installations
06449     else if(!lstrcmpi(szArgVBuf, "-reg_path") || !lstrcmpi(szArgVBuf, "/reg_path"))
06450     {
06451       ++i;
06452       GetArgV(lpszCmdLine, i, szArgVBuf, sizeof(szArgVBuf));
06453       lstrcpy(sgProduct.szRegPath, szArgVBuf);
06454     }
06455     else if(!lstrcmpi(szArgVBuf, "-showBanner") || !lstrcmpi(szArgVBuf, "/showBanner"))
06456       gShowBannerImage = TRUE;
06457     else if(!lstrcmpi(szArgVBuf, "-hideBanner") || !lstrcmpi(szArgVBuf, "/hideBanner"))
06458       gShowBannerImage = FALSE;
06459     else if(!lstrcmpi(szArgVBuf, "-cleanupOnUpgrade") || !lstrcmpi(szArgVBuf, "/cleanupOnUpgrade"))
06460       sgProduct.checkCleanupOnUpgrade = TRUE;
06461     else if(!lstrcmpi(szArgVBuf, "-noCleanupOnUpgrade") || !lstrcmpi(szArgVBuf, "/noCleanupOnUpgrade"))
06462       sgProduct.checkCleanupOnUpgrade = FALSE;
06463     else if(!lstrcmpi(szArgVBuf, "-greCleanupOrphans") || !lstrcmpi(szArgVBuf, "/greCleanupOrphans"))
06464       sgProduct.greCleanupOrphans = TRUE;
06465     else if(!lstrcmpi(szArgVBuf, "-greNoCleanupOrphans") || !lstrcmpi(szArgVBuf, "/greNoCleanupOrphans"))
06466       sgProduct.greCleanupOrphans = FALSE;
06467 
06468 #ifdef XXX_DEBUG
06469     itoa(i, szBuf, 10);
06470     lstrcat(szOutputStr, "    ");
06471     lstrcat(szOutputStr, szBuf);
06472     lstrcat(szOutputStr, ": ");
06473     lstrcat(szOutputStr, szArgVBuf);
06474     lstrcat(szOutputStr, "\n");
06475 #endif
06476 
06477     ++i;
06478   }
06479 
06480 #ifdef XXX_DEBUG
06481   MessageBox(NULL, szOutputStr, "Output", MB_OK);
06482 #endif
06483   return(WIZ_OK);
06484 }
06485 
06486 void GetAlternateArchiveSearchPath(LPSTR lpszCmdLine)
06487 {
06488   char  szBuf[MAX_PATH];
06489   LPSTR lpszAASPath;
06490   LPSTR lpszEndPath;
06491   LPSTR lpszEndQuote;
06492 
06493   if(lstrcpy(szBuf, lpszCmdLine))
06494   {
06495     if((lpszAASPath = strstr(szBuf, "-a")) == NULL)
06496       return;
06497     else
06498       lpszAASPath += 2;
06499 
06500     if(*lpszAASPath == '\"')
06501     {
06502       lpszAASPath = lpszAASPath + 1;
06503       if((lpszEndQuote = strstr(lpszAASPath, "\"")) != NULL)
06504       {
06505         *lpszEndQuote = '\0';
06506       }
06507     }
06508     else if((lpszEndPath = strstr(lpszAASPath, " ")) != NULL)
06509     {
06510       *lpszEndPath = '\0';
06511     }
06512 
06513     lstrcpy(sgProduct.szAlternateArchiveSearchPath, lpszAASPath);
06514   }
06515 }
06516 
06517 int PreCheckInstance(char *szSection, char *szIniFile)
06518 {
06519   char  szBuf[MAX_BUF];
06520   char  szKey[MAX_BUF];
06521   char  szName[MAX_BUF];
06522   char  szParameter[MAX_BUF];
06523   char  szPath[MAX_BUF];
06524   char  szFile[MAX_BUF];
06525   char  *ptrName = NULL;
06526   HKEY  hkeyRoot;
06527   int   iRv = WIZ_OK;
06528   DWORD dwCounter = 0;
06529   BOOL  bContinue = TRUE;
06530   char  szExtraCmd[] = "Extra Cmd";
06531   char  szExtraCmdKey[MAX_BUF];
06532 
06533   do
06534   {
06535     /* Read the win reg key path */
06536     wsprintf(szExtraCmdKey, "%s%d Reg Key", szExtraCmd, dwCounter);
06537     GetPrivateProfileString(szSection,
06538                             szExtraCmdKey,
06539                             "",
06540                             szKey,
06541                             sizeof(szKey),
06542                             szIniFile);
06543     if(*szKey == '\0')
06544     {
06545       bContinue = FALSE;
06546       continue;
06547     }
06548 
06549     /* Read the win reg root key */
06550     wsprintf(szExtraCmdKey, "%s%d Reg Key Root", szExtraCmd, dwCounter);
06551     GetPrivateProfileString(szSection,
06552                             szExtraCmdKey,
06553                             "",
06554                             szBuf,
06555                             sizeof(szBuf),
06556                             szIniFile);
06557     if(*szBuf == '\0')
06558     {
06559       bContinue = FALSE;
06560       continue;
06561     }
06562     hkeyRoot = ParseRootKey(szBuf);
06563 
06564     /* Read the win reg name value */
06565     wsprintf(szExtraCmdKey, "%s%d Reg Name", szExtraCmd, dwCounter);
06566     GetPrivateProfileString(szSection,
06567                             szExtraCmdKey,
06568                             "",
06569                             szName,
06570                             sizeof(szName),
06571                             szIniFile);
06572     if(*szName == '\0')
06573       ptrName = NULL;
06574     else
06575       ptrName = szName;
06576 
06577     /* Read the parameter to use for quitting the browser's turbo mode */
06578     wsprintf(szExtraCmdKey, "%s%d Parameter", szExtraCmd, dwCounter);
06579     GetPrivateProfileString(szSection,
06580                             szExtraCmdKey,
06581                             "",
06582                             szParameter,
06583                             sizeof(szParameter),
06584                             szIniFile);
06585 
06586     /* Read the win reg key that contains the path to the browser */
06587     GetWinReg(hkeyRoot, szKey, ptrName, szFile, sizeof(szFile));
06588     ParsePath(szFile, szPath, sizeof(szPath), FALSE, PP_PATH_ONLY);
06589 
06590     /* Make sure the file exists */
06591     if(FileExists(szFile))
06592     {
06593       // we've found a file, so let's execute it and stop.  No need to look
06594       // for other keys to parse.  We only want to do that if the file is
06595       // _not_ found.  This is for when we change the name of the browser
06596       // app file and still need to deal with locating it and calling
06597       // -kill on it. ie.
06598       //   previous name: netscp6.exe
06599       //   new name: netscp.exe
06600       // We only need to call one of them, not both.
06601       bContinue = FALSE;
06602 
06603       /* Run the file */
06604       WinSpawn(szFile, szParameter, szPath, SW_HIDE, WS_WAIT);
06605 
06606       /* Even though WinSpawn is suppose to wait for the app to finish, this
06607        * does not really work that way for trying to quit the browser when
06608        * it's in turbo mode, so we wait 2 secs for it to complete. */
06609       Delay(2);
06610     }
06611 
06612     ++dwCounter;
06613   } while(bContinue);
06614 
06615   return(iRv);
06616 }
06617 
06618 HRESULT GetCheckInstanceQuitMessage(char *aSection, char *aMessage, DWORD aMessageBufSize)
06619 {
06620   char messageFullInstaller[MAX_BUF];
06621 
06622   *aMessage = '\0';
06623   *messageFullInstaller = '\0';
06624 
06625   GetPrivateProfileString(aSection, "Message", "", aMessage, aMessageBufSize, szFileIniConfig);
06626   GetPrivateProfileString(aSection, "Message Full Installer", "", messageFullInstaller, sizeof(messageFullInstaller), szFileIniConfig);
06627   if(!gbDownloadTriggered && !gbPreviousUnfinishedDownload && (*messageFullInstaller != '\0'))
06628     MozCopyStr(messageFullInstaller, aMessage, aMessageBufSize);
06629 
06630   return(WIZ_OK);
06631 }
06632 
06633 HRESULT ShowMessageAndQuitProcess(HWND aHwndFW, char *aMsgQuitProcess, char *aMsgWait, BOOL aCloseAllWindows, char *aProcessName, BOOL aForceQuit)
06634 {
06635   switch(sgProduct.mode)
06636   {
06637     case NORMAL:
06638     {
06639       char msgTitleStr[MAX_BUF];
06640       GetPrivateProfileString("Messages", "MB_ATTENTION_STR", "", msgTitleStr, sizeof(msgTitleStr), szFileIniInstall);
06641       ShowMessage(NULL, TRUE);
06642       MessageBox(hWndMain, aMsgQuitProcess, msgTitleStr, MB_ICONEXCLAMATION | MB_SETFOREGROUND);
06643       break;
06644     }
06645 
06646     case AUTO:
06647     {
06648       /* Setup mode is AUTO.  Show message, timeout, then auto close
06649        * all the windows associated with the process */
06650       ShowMessage(aMsgQuitProcess, TRUE);
06651       Delay(5);
06652       break;
06653     }
06654 
06655     case SILENT:
06656       break;
06657   }
06658 
06659   if(aForceQuit)
06660   {
06661     assert(aProcessName);
06662     FindAndKillProcess(aProcessName, KP_KILL_PROCESS);
06663   }
06664   else
06665   {
06666     assert(aHwndFW);
06667     /* First try sending a WM_QUIT message to the window because this is the
06668      * preferred way to quit a process.  If it works, then we're good and
06669      * CloseAllWindowsOfWindowHandle() will have nothing to do.
06670      * If it doesn't work, then CloseAllWindowsOfWindowHandle will try to
06671      * quit the process. */
06672     SendMessageTimeout(aHwndFW, WM_QUIT, (WPARAM)1, (LPARAM)0, SMTO_NORMAL, WM_CLOSE_TIMEOUT_VALUE, NULL);
06673     if(aCloseAllWindows)
06674       CloseAllWindowsOfWindowHandle(aHwndFW, aMsgWait);
06675   }
06676   Delay(2);
06677   return(WIZ_OK);
06678 }
06679 
06680 HRESULT CheckInstances()
06681 {
06682   char  section[MAX_BUF];
06683   char  processName[MAX_BUF];
06684   char  className[MAX_BUF];
06685   char  windowName[MAX_BUF];
06686   char  closeAllWindows[MAX_BUF];
06687   char  message[MAX_BUF];
06688   char  msgTitleStr[MAX_BUF];
06689   char  prettyName[MAX_BUF];
06690   char  buf[MAX_BUF];
06691   char  msgWait[MAX_BUF];
06692   int   index;
06693   int   killProcessTries = 0;
06694   int   instanceOfFoundProcess = 0;
06695   BOOL  bContinue;
06696   BOOL  bCloseAllWindows;
06697   HWND  hwndFW;
06698   LPSTR szWN;
06699   LPSTR szCN;
06700   DWORD dwRv0;
06701   DWORD dwRv1;
06702 
06703   GetPrivateProfileString("Messages", "MB_ATTENTION_STR", "", msgTitleStr, sizeof(msgTitleStr), szFileIniInstall);
06704   bContinue = TRUE;
06705   index    = -1;
06706   while(bContinue)
06707   {
06708     *className  = '\0';
06709     *windowName = '\0';
06710     *message    = '\0';
06711 
06712     wsprintf(section, "Check Instance%d", ++index);
06713     GetPrivateProfileString(section, "Process Name", "", processName, sizeof(processName), szFileIniConfig);
06714     GetPrivateProfileString(section, "Pretty Name", "", prettyName, sizeof(prettyName), szFileIniConfig);
06715     GetPrivateProfileString(section, "Message Wait", "", msgWait, sizeof(msgWait), szFileIniConfig);
06716     GetPrivateProfileString(section, "Close All Process Windows", "", closeAllWindows, sizeof(closeAllWindows), szFileIniConfig);
06717     if(lstrcmpi(closeAllWindows, "TRUE") == 0)
06718       bCloseAllWindows = TRUE;
06719     else
06720       bCloseAllWindows = FALSE;
06721 
06722     if(instanceOfFoundProcess != index)
06723     {
06724       killProcessTries = 0;
06725       instanceOfFoundProcess = index;
06726     }
06727 
06728     if((killProcessTries == 1) && (*processName != '\0'))
06729     {
06730       if(FindAndKillProcess(processName, KP_DO_NOT_KILL_PROCESS))
06731       {
06732         /* found process, display warning message, then kill process */
06733         GetPrivateProfileString("Messages", "MSG_FORCE_QUIT_PROCESS", "", message, sizeof(message), szFileIniInstall);
06734         if(*message != '\0')
06735         {
06736           wsprintf(buf, message, prettyName, processName, prettyName, prettyName);
06737           ShowMessageAndQuitProcess(NULL, buf, msgWait, bCloseAllWindows, processName, CI_FORCE_QUIT_PROCESS);
06738           ++killProcessTries;
06739           instanceOfFoundProcess = index--;
06740         }
06741       }
06742       continue;
06743     }
06744     else if(killProcessTries == MAX_KILL_PROCESS_RETRIES)
06745     {
06746       GetPrivateProfileString("Messages", "MSG_FORCE_QUIT_PROCESS_FAILED", "", message, sizeof(message), szFileIniInstall);
06747       if(*message != '\0')
06748       {
06749         wsprintf(buf, message, prettyName, processName, prettyName);
06750         switch(sgProduct.mode)
06751         {
06752           case NORMAL:
06753             ShowMessage(NULL, FALSE);
06754             MessageBox(hWndMain, buf, msgTitleStr, MB_ICONEXCLAMATION | MB_SETFOREGROUND);
06755             break;
06756 
06757           case AUTO:
06758             /* Setup mode is AUTO.  Show message, timeout, then auto close
06759              * all the windows associated with the process */
06760             ShowMessage(buf, TRUE);
06761             Delay(5);
06762             break;
06763 
06764           default:
06765             break;
06766         }
06767       }
06768 
06769       /* can't kill the process for some unknown reason.  Stop the installation. */
06770       return(TRUE);
06771     }
06772     else if((killProcessTries > 1) &&
06773             (killProcessTries < MAX_KILL_PROCESS_RETRIES) &&
06774             (*processName != '\0'))
06775     {
06776       if(FindAndKillProcess(processName, KP_KILL_PROCESS))
06777       {
06778         ++killProcessTries;
06779         instanceOfFoundProcess = index--;
06780       }
06781       continue;
06782     }
06783 
06784     dwRv0 = GetPrivateProfileString(section, "Class Name",  "", className,  sizeof(className), szFileIniConfig);
06785     dwRv1 = GetPrivateProfileString(section, "Window Name", "", windowName, sizeof(windowName), szFileIniConfig);
06786     if((dwRv0 == 0L) && (dwRv1 == 0L) && (*processName == '\0'))
06787     {
06788       bContinue = FALSE;
06789     }
06790     else if((*className != '\0') || (*windowName != '\0'))
06791     {
06792       if(*className == '\0')
06793         szCN = NULL;
06794       else
06795         szCN = className;
06796 
06797       if(*windowName == '\0')
06798         szWN = NULL;
06799       else
06800         szWN = windowName;
06801 
06802       /* If an instance is found, call PreCheckInstance first.
06803        * PreCheckInstance will try to disable the browser's
06804        * QuickLaunch feature. If the browser was in QuickLaunch
06805        * mode without any windows open, PreCheckInstance would
06806        * shutdown the browser, thus a second call to FindAndKillProcess
06807        * is required to see if the process is still around. */
06808       if((hwndFW = FindWindow(szCN, szWN)) != NULL)
06809         PreCheckInstance(section, szFileIniConfig);
06810 
06811       if((hwndFW = FindWindow(szCN, szWN)) != NULL)
06812       {
06813         GetCheckInstanceQuitMessage(section, message, sizeof(message));
06814         if(*message != '\0')
06815         {
06816           ShowMessageAndQuitProcess(hwndFW, message, msgWait, bCloseAllWindows, processName, CI_CLOSE_PROCESS);
06817           ++killProcessTries;
06818           instanceOfFoundProcess = index--;
06819         }
06820         else
06821         {
06822           /* No message to display.  Assume cancel because we can't allow user to continue */
06823           return(TRUE);
06824         }
06825       }
06826     }
06827 
06828     if((killProcessTries == 0) && (*processName != '\0'))
06829     {
06830       /* The first attempt used FindWindow(), but sometimes the browser can be
06831        * in a state where there's no window open and still not fully shutdown.
06832        * In this case, we need to check for the process itself and kill it. */
06833       if(FindAndKillProcess(processName, KP_DO_NOT_KILL_PROCESS))
06834       {
06835         GetCheckInstanceQuitMessage(section, message, sizeof(message));
06836         if(*message != '\0')
06837         {
06838           ShowMessageAndQuitProcess(hwndFW, message, msgWait, bCloseAllWindows, processName, CI_FORCE_QUIT_PROCESS);
06839           ++killProcessTries;
06840           instanceOfFoundProcess = index--;
06841         }
06842         else
06843         {
06844           /* No message to display.  Assume cancel because we can't allow user to continue */
06845           return(TRUE);
06846         }
06847       }
06848     }
06849   }
06850 
06851   return(FALSE);
06852 }
06853 
06854 void RefreshIcons()
06855 {
06856   char subKey[MAX_BUF];
06857   char iconConstraint[MAX_BUF];
06858   BYTE iconConstraintNew[MAX_BUF];
06859   HKEY hkResult;
06860   DWORD dwValueType;
06861   long iconConstraintSize;
06862   long rv;
06863 
06864   // Get the size of the icon from the windows registry.
06865   // When this registry value is changed, the OS can flush the
06866   // icon cache and thus update the icons.
06867   iconConstraintSize = sizeof(iconConstraint);
06868   strcpy(subKey, "Control Panel\\Desktop\\WindowMetrics");
06869   RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, KEY_ALL_ACCESS, &hkResult);
06870   rv = RegQueryValueEx(hkResult, "Shell Icon Size", 0, &dwValueType, iconConstraint, &iconConstraintSize);
06871   if(rv != ERROR_SUCCESS || iconConstraintSize == 0)
06872   {
06873     // Key not found or value not found, so use default OS value.
06874     int iIconSize = GetSystemMetrics(SM_CXICON);
06875     if(iIconSize == 0)
06876       // Getting default OS value failed, use hard coded value
06877       iIconSize = DEFAULT_ICON_SIZE;
06878 
06879     sprintf(iconConstraint, "%d", iIconSize);
06880   }
06881 
06882   // decrease the size of the icon by 1
06883   // and tell the system to refresh the icons
06884   sprintf(iconConstraintNew, "%d", atoi(iconConstraint) - 1);
06885   iconConstraintSize = lstrlen(iconConstraintNew);
06886   RegSetValueEx(hkResult, "Shell Icon Size", 0, dwValueType, iconConstraintNew, iconConstraintSize);
06887   SendMessageTimeout(HWND_BROADCAST,
06888                      WM_SETTINGCHANGE,
06889                      SPI_SETNONCLIENTMETRICS,
06890                      (LPARAM)"WindowMetrics",
06891                      SMTO_NORMAL|SMTO_ABORTIFHUNG, 
06892                      10000, NULL); 
06893 
06894   // reset the original size of the icon
06895   // and tell the system to refresh the icons
06896   iconConstraintSize = lstrlen(iconConstraint);
06897   RegSetValueEx(hkResult, "Shell Icon Size", 0, dwValueType, iconConstraint, iconConstraintSize);
06898   SendMessageTimeout(HWND_BROADCAST,
06899                      WM_SETTINGCHANGE,
06900                      SPI_SETNONCLIENTMETRICS,
06901                      (LPARAM)"WindowMetrics",
06902                      SMTO_NORMAL|SMTO_ABORTIFHUNG, 
06903                      10000, NULL); 
06904 }
06905 
06906 int CRCCheckArchivesStartup(char *szCorruptedArchiveList, DWORD dwCorruptedArchiveListSize, BOOL bIncludeTempPath)
06907 {
06908   DWORD dwIndex0;
06909   DWORD dwFileCounter;
06910   siC   *siCObject = NULL;
06911   char  szArchivePathWithFilename[MAX_BUF];
06912   char  szArchivePath[MAX_BUF];
06913   char  szMsgCRCCheck[MAX_BUF];
06914   char  szPartiallyDownloadedFilename[MAX_BUF];
06915   int   iRv;
06916   int   iResult;
06917 
06918   if(szCorruptedArchiveList != NULL)
06919     ZeroMemory(szCorruptedArchiveList, dwCorruptedArchiveListSize);
06920 
06921   GetSetupCurrentDownloadFile(szPartiallyDownloadedFilename,
06922                               sizeof(szPartiallyDownloadedFilename));
06923   GetPrivateProfileString("Strings", "Message Verifying Archives", "", szMsgCRCCheck, sizeof(szMsgCRCCheck), szFileIniConfig);
06924   ShowMessage(szMsgCRCCheck, TRUE);
06925   
06926   iResult           = WIZ_CRC_PASS;
06927   dwIndex0          = 0;
06928   dwFileCounter     = 0;
06929   siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
06930   while(siCObject)
06931   {
06932     /* only download jars if not already in the local machine */
06933     iRv = LocateJar(siCObject, szArchivePath, sizeof(szArchivePath), bIncludeTempPath);
06934     if((iRv != AP_NOT_FOUND) &&
06935        (lstrcmpi(szPartiallyDownloadedFilename,
06936                  siCObject->szArchiveName) != 0))
06937     {
06938       if(lstrlen(szArchivePath) < sizeof(szArchivePathWithFilename))
06939         lstrcpy(szArchivePathWithFilename, szArchivePath);
06940 
06941       AppendBackSlash(szArchivePathWithFilename, sizeof(szArchivePathWithFilename));
06942       if((lstrlen(szArchivePathWithFilename) + lstrlen(siCObject->szArchiveName)) < sizeof(szArchivePathWithFilename))
06943         lstrcat(szArchivePathWithFilename, siCObject->szArchiveName);
06944 
06945       if(CheckForArchiveExtension(szArchivePathWithFilename))
06946       {
06947         /* Make sure that the Archive that failed is located in the TEMP
06948          * folder.  This means that it was downloaded at one point and not
06949          * simply uncompressed from the self-extracting exe file. */
06950         if(VerifyArchive(szArchivePathWithFilename) != ZIP_OK)
06951         {
06952           if(iRv == AP_TEMP_PATH)
06953             DeleteFile(szArchivePathWithFilename);
06954           else if(szCorruptedArchiveList != NULL)
06955           {
06956             iResult = WIZ_CRC_FAIL;
06957             if((DWORD)(lstrlen(szCorruptedArchiveList) + lstrlen(siCObject->szArchiveName + 1)) < dwCorruptedArchiveListSize)
06958             {
06959               lstrcat(szCorruptedArchiveList, "        ");
06960               lstrcat(szCorruptedArchiveList, siCObject->szArchiveName);
06961               lstrcat(szCorruptedArchiveList, "\n");
06962             }
06963             else
06964             {
06965               iResult = WIZ_OUT_OF_MEMORY;
06966               break;
06967             }
06968           }
06969         }
06970       }
06971     }
06972 
06973     ++dwIndex0;
06974     siCObject = SiCNodeGetObject(dwIndex0, TRUE, AC_ALL);
06975   }
06976   return(iResult);
06977 }
06978 
06979 int StartupCheckArchives(void)
06980 {
06981   int  iRv;
06982   char szBuf[MAX_BUF_SMALL];
06983   char szCorruptedArchiveList[MAX_BUF];
06984 
06985   iRv = CRCCheckArchivesStartup(szCorruptedArchiveList, sizeof(szCorruptedArchiveList), gbPreviousUnfinishedDownload);
06986   switch(iRv)
06987   {
06988     char szMsg[MAX_BUF];
06989     char szBuf2[MAX_BUF];
06990     char szTitle[MAX_BUF_TINY];
06991 
06992     case WIZ_CRC_FAIL:
06993       switch(sgProduct.mode)
06994       {
06995         case NORMAL:
06996           if(GetPrivateProfileString("Messages", "STR_MESSAGEBOX_TITLE", "", szBuf, sizeof(szBuf), szFileIniInstall))
06997             lstrcpy(szTitle, "Setup");
06998           else
06999             wsprintf(szTitle, szBuf, sgProduct.szProductName);
07000 
07001           GetPrivateProfileString("Strings", "Error Corrupted Archives Detected", "", szBuf, sizeof(szBuf), szFileIniConfig);
07002           if(*szBuf != '\0')
07003           {
07004             lstrcpy(szBuf2, "\n\n");
07005             lstrcat(szBuf2, szCorruptedArchiveList);
07006             lstrcat(szBuf2, "\n");
07007             wsprintf(szMsg, szBuf, szBuf2);
07008           }
07009           MessageBox(hWndMain, szMsg, szTitle, MB_OK | MB_ICONSTOP);
07010           break;
07011 
07012         case AUTO:
07013           GetPrivateProfileString("Strings", "Error Corrupted Archives Detected AUTO mode", "", szBuf, sizeof(szBuf), szFileIniConfig);
07014           ShowMessage(szBuf, TRUE);
07015           Delay(5);
07016           break;
07017       }
07018 
07019       LogISComponentsFailedCRC(szCorruptedArchiveList, W_STARTUP);
07020       return(WIZ_CRC_FAIL);
07021 
07022     case WIZ_CRC_PASS:
07023       break;
07024 
07025     default:
07026       break;
07027   }
07028   LogISComponentsFailedCRC(NULL, W_STARTUP);
07029   return(iRv);
07030 }
07031 
07032 HRESULT ParseConfigIni(LPSTR lpszCmdLine)
07033 {
07034   int  iRv;
07035   char szBuf[MAX_BUF];
07036   char szMsgInitSetup[MAX_BUF];
07037   char szPreviousPath[MAX_BUF];
07038   char szShowDialog[MAX_BUF];
07039   DWORD dwPreviousUnfinishedState;
07040 
07041   if(InitDlgWelcome(&diWelcome))
07042     return(1);
07043   if(InitDlgLicense(&diLicense))
07044     return(1);
07045   if(InitDlgSetupType(&diSetupType))
07046     return(1);
07047   if(InitDlgSelectComponents(&diSelectComponents, SM_SINGLE))
07048     return(1);
07049   if(InitDlgSelectComponents(&diSelectAdditionalComponents, SM_SINGLE))
07050     return(1);
07051   if(InitDlgWindowsIntegration(&diWindowsIntegration))
07052     return(1);
07053   if(InitDlgProgramFolder(&diProgramFolder))
07054     return(1);
07055   if(InitDlgAdditionalOptions(&diAdditionalOptions))
07056     return(1);
07057   if(InitDlgAdvancedSettings(&diAdvancedSettings))
07058     return(1);
07059   if(InitDlgQuickLaunch(&diQuickLaunch))
07060     return(1);
07061   if(InitDlgStartInstall(&diStartInstall))
07062     return(1);
07063   if(InitDlgDownload(&diDownload))
07064     return(1);
07065   if(InitDlgReboot(&diReboot))
07066     return(1);
07067   if(InitSDObject())
07068     return(1);
07069   if(InitSXpcomFile())
07070     return(1);
07071   if(InitGre(&gGre))
07072     return(WIZ_ERROR_INIT);
07073  
07074   /* get install Mode information */
07075   GetPrivateProfileString("General", "Run Mode", "", szBuf, sizeof(szBuf), szFileIniConfig);
07076   SetSetupRunMode(szBuf);
07077 
07078   /* find out if we are doing a shared install */
07079   GetPrivateProfileString("General", "Shared Install", "", szBuf, sizeof(szBuf), szFileIniConfig);
07080   if(lstrcmpi(szBuf, "TRUE") == 0)
07081     sgProduct.bSharedInst = TRUE;
07082 
07083   /* find out if we need to cleanup previous installation on upgrade
07084    * (installing ontop of - not related to cleaning up olde GRE's
07085    *  installed elsewhere) */
07086   GetPrivateProfileString("Cleanup On Upgrade", "Cleanup", "", szBuf, sizeof(szBuf), szFileIniConfig);
07087   if(lstrcmpi(szBuf, "TRUE") == 0)
07088     sgProduct.checkCleanupOnUpgrade = TRUE;
07089 
07090   /* this is a default value so don't change it if it has already been set */
07091   if(*sgProduct.szAppID == '\0')
07092     GetPrivateProfileString("General", "Default AppID",   "", sgProduct.szAppID, MAX_BUF, szFileIniConfig);
07093 
07094   if(GetPrivateProfileString("Messages", "MSG_INIT_SETUP", "", szMsgInitSetup, sizeof(szMsgInitSetup), szFileIniInstall))
07095     ShowMessage(szMsgInitSetup, TRUE);
07096 
07097   /* get product name description */
07098   GetPrivateProfileString("General", "Company Name", "", sgProduct.szCompanyName, MAX_BUF, szFileIniConfig);
07099   GetPrivateProfileString("General", "Product Name", "", sgProduct.szProductName, MAX_BUF, szFileIniConfig);
07100   GetPrivateProfileString("General", "Product Name Internal", "", sgProduct.szProductNameInternal, MAX_BUF, szFileIniConfig);
07101   if (sgProduct.szProductNameInternal[0] == 0)
07102     lstrcpy(sgProduct.szProductNameInternal, sgProduct.szProductName);
07103  
07104   GetPrivateProfileString("General", "Product Name Previous", "", sgProduct.szProductNamePrevious, MAX_BUF, szFileIniConfig);
07105   GetPrivateProfileString("General", "Uninstall Filename", "", sgProduct.szUninstallFilename, MAX_BUF, szFileIniConfig);
07106   GetPrivateProfileString("General", "User Agent",   "", sgProduct.szUserAgent,   MAX_BUF, szFileIniConfig);
07107   GetPrivateProfileString("General", "Sub Path",     "", sgProduct.szSubPath,     MAX_BUF, szFileIniConfig);
07108   GetPrivateProfileString("General", "Program Name", "", sgProduct.szProgramName, MAX_BUF, szFileIniConfig);
07109   GetPrivateProfileString("General", "Lock Path",    "", szBuf,                   sizeof(szBuf), szFileIniConfig);
07110   if(lstrcmpi(szBuf, "TRUE") == 0)
07111     sgProduct.bLockPath = TRUE;
07112   
07113   /* this is a default value so don't change it if it has already been set */
07114   if (sgProduct.szRegPath[0] == 0)
07115     wsprintf(sgProduct.szRegPath, "Software\\%s\\%s\\%s", sgProduct.szCompanyName, sgProduct.szProductNameInternal, sgProduct.szUserAgent);
07116 
07117   gbRestrictedAccess = VerifyRestrictedAccess();
07118 
07119   /* get main install path */
07120   if(LocatePreviousPath("Locate Previous Product Path", szPreviousPath, sizeof(szPreviousPath)) == FALSE)
07121   {
07122     GetPrivateProfileString("General", "Path", "", szBuf, sizeof(szBuf), szFileIniConfig);
07123     DecryptString(sgProduct.szPath, szBuf);
07124   }
07125   else
07126   {
07127     /* If the previous path is located in the registry, then we need to check to see if the path from
07128      * the registry plus the Sub Path contains the Program Name file.  If it does, then we have the
07129      * correct path, so just use it.
07130      *
07131      * If it does not contain the Program Name file, then check the parent path (from the registry) +
07132      * SubPath.  If this path contains the Program Name file, then we found an older path format.  We
07133      * then need to use the parent path as the default path.
07134      *
07135      * Only do the older path format checking if the Sub Path= and Program Name= keys exist.  If
07136      * either are not set, then assume that the path from the registry is what we want.
07137      */
07138     if((*sgProduct.szSubPath != '\0') && (*sgProduct.szProgramName != '\0'))
07139     {
07140       /* If the Sub Path= and Program Name= keys exist, do extra parsing for the correct path */
07141       lstrcpy(szBuf, szPreviousPath);
07142       AppendBackSlash(szBuf, sizeof(szBuf));
07143       lstrcat(szBuf, sgProduct.szSubPath);
07144       AppendBackSlash(szBuf, sizeof(szBuf));
07145       lstrcat(szBuf, sgProduct.szProgramName);
07146 
07147       /* Check to see if PreviousPath + SubPath + ProgramName exists.  If it does, then we have the
07148        * correct path.
07149        */
07150       if(FileExists(szBuf))
07151       {
07152         lstrcpy(sgProduct.szPath, szPreviousPath);
07153       }
07154       else
07155       {
07156         /* If not, try parent of PreviousPath + SubPath + ProgramName.
07157          * If this exists, then we need to use the parent path of PreviousPath.
07158          */
07159         RemoveBackSlash(szPreviousPath);
07160         ParsePath(szPreviousPath, szBuf, sizeof(szBuf), FALSE, PP_PATH_ONLY);
07161         AppendBackSlash(szBuf, sizeof(szBuf));
07162         lstrcat(szBuf, sgProduct.szSubPath);
07163         AppendBackSlash(szBuf, sizeof(szBuf));
07164         lstrcat(szBuf, sgProduct.szProgramName);
07165 
07166         if(FileExists(szBuf))
07167         {
07168           RemoveBackSlash(szPreviousPath);
07169           ParsePath(szPreviousPath, szBuf, sizeof(szBuf), FALSE, PP_PATH_ONLY);
07170           lstrcpy(sgProduct.szPath, szBuf);
07171         }
07172         else
07173         {
07174           /* If we still can't locate ProgramName file, then use the default in the config.ini */
07175           GetPrivateProfileString("General", "Path", "", szBuf, sizeof(szBuf), szFileIniConfig);
07176           DecryptString(sgProduct.szPath, szBuf);
07177         }
07178       }
07179     }
07180     else
07181     {
07182       lstrcpy(sgProduct.szPath, szPreviousPath);
07183     }
07184   }
07185   RemoveBackSlash(sgProduct.szPath);
07186 
07187   /* get main program folder path */
07188   GetPrivateProfileString("General", "Program Folder Path", "", szBuf, sizeof(szBuf), szFileIniConfig);
07189   DecryptString(sgProduct.szProgramFolderPath, szBuf);
07190   
07191   /* get main program folder name */
07192   GetPrivateProfileString("General", "Program Folder Name", "", szBuf, sizeof(szBuf), szFileIniConfig);
07193   DecryptString(sgProduct.szProgramFolderName, szBuf);
07194 
07195   GetPrivateProfileString("General", "Refresh Icons", "", szBuf, sizeof(szBuf), szFileIniConfig);
07196   if(lstrcmpi(szBuf, "TRUE") == 0)
07197     gSystemInfo.bRefreshIcons = TRUE;
07198 
07199   /* Set default value for greType if not already set. If already set,
07200    * it was set via cmdline argumen. Do not override the setting. */
07201   if(sgProduct.greType == GRE_TYPE_NOT_SET)
07202   {
07203     sgProduct.greType = GRE_SHARED; /* Always default to installing GRE to global area. */
07204     GetPrivateProfileString("General", "GRE Type", "", szBuf, sizeof(szBuf), szFileIniConfig);
07205     if(lstrcmpi(szBuf, "Local") == 0)
07206       sgProduct.greType = GRE_LOCAL;
07207     else
07208       sgProduct.greType = GRE_SHARED;
07209   }
07210 
07211   GetPrivateProfileString("General", "GRE Cleanup