Back to index

lightning-sunbird  0.9+nobinonly
supersede.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2003
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Sean Su <ssu@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "setup.h"
00039 #include "extern.h"
00040 #include "extra.h"
00041 #include "ifuncns.h"
00042 #include "supersede.h"
00043 
00044 void              SaveGreInfo(grever *aGreInstalledListTmp, greInfo* aGre);
00045 void              ResolveSupersedeGre(siC *siCObject, greInfo *aGre);
00046 HRESULT           GetGreSupersedeVersionList(siC *siCObject, grever **aGreSupersedeList);
00047 HRESULT           GetGreInstalledVersionList(siC *siCObject, grever **aGreInstalledList);
00048 
00049 grever *CreateGVerNode()
00050 {
00051   grever *gverNode;
00052 
00053   if((gverNode = NS_GlobalAlloc(sizeof(struct structGreVer))) == NULL)
00054     return(NULL);
00055 
00056   gverNode->greHomePath[0]         = '\0';
00057   gverNode->greInstaller[0]        = '\0';
00058   gverNode->greUserAgent[0]        = '\0';
00059   gverNode->version.ullMajor       = 0;
00060   gverNode->version.ullMinor       = 0;
00061   gverNode->version.ullRelease     = 0;
00062   gverNode->version.ullBuild       = 0;
00063   gverNode->next                   = NULL;
00064   return(gverNode);
00065 }
00066 
00067 void DeleteGverList(grever *gverHead)
00068 {
00069   grever *tmp;
00070 
00071   while(gverHead != NULL)
00072   {
00073     tmp = gverHead;
00074     gverHead = gverHead->next;
00075     FreeMemory(&tmp);
00076   }
00077 }
00078 
00079 /* function to build a linked list of GRE supersede versions */
00080 HRESULT GetGreSupersedeVersionList(siC *siCObject, grever **aGreSupersedeList)
00081 {
00082   grever  *gverTmp = NULL;
00083   grever  *gverTail = NULL;
00084   char    key[MAX_BUF_TINY];
00085   char    versionString[MAX_BUF_TINY];
00086   DWORD   index;
00087 
00088   if(*aGreSupersedeList)
00089     /* list already built, just return */
00090     return(WIZ_OK);
00091 
00092   index = 0;
00093   wsprintf(key, "SupersedeVersion%d", index);        
00094   GetPrivateProfileString(siCObject->szReferenceName, key, "", versionString,
00095                           sizeof(versionString), szFileIniConfig);
00096   while(*versionString != '\0')
00097   {
00098     gverTmp = CreateGVerNode();
00099     if(!gverTmp)
00100       // error has already been displayed.
00101       exit(WIZ_OUT_OF_MEMORY);
00102 
00103     TranslateVersionStr(versionString, &gverTmp->version);
00104     if(*aGreSupersedeList == NULL)
00105     {
00106       /* brand new list */
00107       *aGreSupersedeList = gverTmp;
00108       gverTail = *aGreSupersedeList;
00109     }
00110     else if(gverTail)
00111     {
00112       /* append the new node to the end of the list */
00113       gverTail->next = gverTmp;
00114       gverTail = gverTail->next;
00115     }
00116     
00117     wsprintf(key, "SupersedeVersion%d", ++index);        
00118     GetPrivateProfileString(siCObject->szReferenceName, key, "", versionString,
00119                             sizeof(versionString), szFileIniConfig);
00120   }
00121   return(WIZ_OK);
00122 }
00123 
00124 /* function to build a list of GRE's installed on the local system */
00125 HRESULT GetGreInstalledVersionList(siC *siCObject, grever **aGreInstalledList)
00126 {
00127   DWORD     index;
00128   DWORD     enumIndex;
00129   DWORD     greVersionKeyLen;
00130   grever    *gverTmp = NULL;
00131   grever    *gverTail = NULL;
00132   char      szSupersedeWinRegPath[MAX_BUF];
00133   char      key[MAX_BUF_TINY];
00134   char      greVersionKey[MAX_BUF_TINY];
00135   char      subKey[MAX_BUF];
00136   char      subKeyInstaller[MAX_BUF];
00137   char      szBuf[MAX_BUF];
00138   char      greXpcomPath[MAX_BUF];
00139   char      greXpcomFile[MAX_BUF];
00140   int       greXpcomPathLen;
00141   char      xpcomFilename[] = "xpcom.dll";
00142   char      greKeyPath[MAX_BUF];
00143   verBlock  vbInstalledVersion;
00144   HKEY      hkeyRoot = NULL;
00145   HKEY      hkGreKeyParentPath = NULL;
00146   HKEY      hkGreKeyPath = NULL;
00147   LONG      rv;
00148 
00149   if(*aGreInstalledList)
00150     /* list already built, just return */
00151     return(WIZ_OK);
00152 
00153   index = 0;
00154   wsprintf(key, "SupersedeWinReg%d", index);        
00155   GetPrivateProfileString(siCObject->szReferenceName, key, "", szSupersedeWinRegPath,
00156                           sizeof(szSupersedeWinRegPath), szFileIniConfig);
00157   while(*szSupersedeWinRegPath != '\0')
00158   {
00159     BOOL skip = FALSE;
00160     if(!GetKeyInfo(szSupersedeWinRegPath, szBuf, sizeof(szBuf), KEY_INFO_ROOT))
00161       // Malformed windows registry key, continue to reading the next key.
00162       skip = TRUE;
00163 
00164     hkeyRoot = ParseRootKey(szBuf);
00165     if(!GetKeyInfo(szSupersedeWinRegPath, subKey, sizeof(subKey), KEY_INFO_SUBKEY))
00166       // Malformed windows registry key, continue to reading the next key.
00167       skip = TRUE;
00168 
00169     if(RegOpenKeyEx(hkeyRoot, subKey, 0, KEY_READ, &hkGreKeyParentPath) != ERROR_SUCCESS)
00170       // Problems opening the registry key.  Ignore and continue reading the next key.
00171       skip = TRUE;
00172 
00173     greVersionKeyLen = sizeof(greVersionKey);
00174     enumIndex = 0;
00175     while(!skip &&
00176          (RegEnumKeyEx(hkGreKeyParentPath, enumIndex++, greVersionKey, &greVersionKeyLen,
00177                        NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS))
00178     {
00179       sprintf(greKeyPath, "%s\\%s", subKey, greVersionKey);
00180       if(RegOpenKeyEx(hkeyRoot, greKeyPath, 0, KEY_READ, &hkGreKeyPath) != ERROR_SUCCESS)
00181         // Encoutered problems trying to open key. Just continue.
00182         // We don't care about any errors.  If we can't open the key,
00183         // we just go on to other keys.  These errors are nonfatal.
00184         continue;
00185 
00186       greXpcomPathLen = sizeof(greXpcomPath);
00187       rv = RegQueryValueEx(hkGreKeyPath, "GreHome", 0, NULL, (BYTE *)greXpcomPath, &greXpcomPathLen);
00188       RegCloseKey(hkGreKeyPath);
00189 
00190       if(rv != ERROR_SUCCESS)
00191         // Encoutered problems trying to read a var name. Just continue.
00192         // We don't care about any errors.  If we can't open the key,
00193         // we just go on to other keys.  These errors are nonfatal.
00194         continue;
00195  
00196       if(MozCopyStr(greXpcomPath, greXpcomFile, sizeof(greXpcomFile)))
00197       {
00198         RegCloseKey(hkGreKeyParentPath);
00199         PrintError(szEOutOfMemory, ERROR_CODE_HIDE);
00200         exit(WIZ_OUT_OF_MEMORY);
00201       }
00202 
00203       if(sizeof(greXpcomFile) <= lstrlen(greXpcomFile) + sizeof(xpcomFilename) + 1)
00204       {
00205         RegCloseKey(hkGreKeyParentPath);
00206         PrintError(szEOutOfMemory, ERROR_CODE_HIDE);
00207         exit(WIZ_OUT_OF_MEMORY);
00208       }
00209 
00210       AppendBackSlash(greXpcomFile, sizeof(greXpcomFile));
00211       lstrcat(greXpcomFile, xpcomFilename);
00212 
00213       if(GetFileVersion(greXpcomFile, &vbInstalledVersion))
00214       {
00215         // Don't create a node list unless xpcom.dll file actually exists.
00216         gverTmp = CreateGVerNode();
00217         if(!gverTmp)
00218         {
00219           RegCloseKey(hkGreKeyParentPath);
00220           // error has already been displayed.
00221           exit(WIZ_OUT_OF_MEMORY);
00222         }
00223 
00224         if(MozCopyStr(greXpcomPath, gverTmp->greHomePath, sizeof(gverTmp->greHomePath)))
00225         {
00226           RegCloseKey(hkGreKeyParentPath);
00227           PrintError(szEOutOfMemory, ERROR_CODE_HIDE);
00228           exit(WIZ_OUT_OF_MEMORY);
00229         }
00230 
00231         gverTmp->version.ullMajor   = vbInstalledVersion.ullMajor;
00232         gverTmp->version.ullMinor   = vbInstalledVersion.ullMinor;
00233         gverTmp->version.ullRelease = vbInstalledVersion.ullRelease;
00234         gverTmp->version.ullBuild   = vbInstalledVersion.ullBuild;
00235         if(*aGreInstalledList == NULL)
00236         {
00237           /* brand new list */
00238           *aGreInstalledList = gverTmp;
00239           gverTail = *aGreInstalledList;
00240         }
00241         else if(gverTail)
00242         {
00243           /* append the new node to the end of the list */
00244           gverTail->next = gverTmp;
00245           gverTail = gverTail->next;
00246         }
00247 
00248         /* get the GRE's installer app path */
00249         sprintf(subKeyInstaller, "%s\\%s\\Installer", subKey, greVersionKey);
00250         GetWinReg(hkeyRoot, subKeyInstaller, "PathToExe", gverTmp->greInstaller, sizeof(gverTmp->greInstaller));
00251         MozCopyStr(greVersionKey, gverTmp->greUserAgent, sizeof(gverTmp->greUserAgent));
00252       }
00253 
00254       greVersionKeyLen = sizeof(greVersionKey);
00255     }
00256 
00257     if(hkGreKeyParentPath)
00258     {
00259       RegCloseKey(hkGreKeyParentPath);
00260       hkGreKeyParentPath = NULL;
00261     }
00262 
00263     ++index;
00264     wsprintf(key, "SupersedeWinReg%d", index);        
00265     GetPrivateProfileString(siCObject->szReferenceName, key, "", szSupersedeWinRegPath, sizeof(szSupersedeWinRegPath), szFileIniConfig);
00266   }
00267   return(WIZ_OK);
00268 }
00269 
00270 void SaveGreInfo(grever *aGreInstalledListTmp, greInfo* aGre)
00271 {
00272   MozCopyStr(aGreInstalledListTmp->greInstaller,     aGre->installerAppPath, sizeof(aGre->installerAppPath));
00273   MozCopyStr(aGreInstalledListTmp->greUserAgent,     aGre->userAgent,        sizeof(aGre->userAgent));
00274   MozCopyStr(aGreInstalledListTmp->greHomePath,      aGre->homePath,         sizeof(aGre->homePath));
00275 }
00276 
00277 void ResolveSupersedeGre(siC *siCObject, greInfo *aGre)
00278 {
00279   grever  *greSupersedeListTmp = NULL;
00280   grever  *greInstalledListTmp = NULL;
00281   char    versionStr[MAX_BUF_TINY];
00282   siC     *siCTmp = NULL;
00283   BOOL    foundVersionWithinRange = FALSE;
00284   BOOL    minVerRead = FALSE;
00285   BOOL    maxVerRead = FALSE;
00286   BOOL    stillInRange = FALSE;
00287 
00288   if(GetGreSupersedeVersionList(siCObject, &aGre->greSupersedeList))
00289     return;
00290   if(GetGreInstalledVersionList(siCObject, &aGre->greInstalledList))
00291     return;
00292   if(!aGre->greSupersedeList || !aGre->greInstalledList)
00293     // nothing to compare, return
00294     return;
00295 
00296   GetPrivateProfileString(siCObject->szReferenceName, "SupersedeMinVersion", "",
00297                           versionStr, sizeof(versionStr), szFileIniConfig);
00298   if(*versionStr != '\0')
00299   {
00300     TranslateVersionStr(versionStr, &aGre->minVersion);
00301     minVerRead = TRUE;
00302   }
00303 
00304   GetPrivateProfileString(siCObject->szReferenceName, "SupersedeMaxVersion", "",
00305                           versionStr, sizeof(versionStr), szFileIniConfig);
00306   if(*versionStr != '\0')
00307   {
00308     TranslateVersionStr(versionStr, &aGre->maxVersion);
00309     maxVerRead = TRUE;
00310   }
00311 
00312 
00313   // do the version comparison here.
00314   greInstalledListTmp = aGre->greInstalledList;
00315   while(greInstalledListTmp)
00316   {
00317     greSupersedeListTmp = aGre->greSupersedeList;
00318     while(greSupersedeListTmp)
00319     {
00320       if(CompareVersion(greInstalledListTmp->version, greSupersedeListTmp->version) == 0)
00321       {
00322         SaveGreInfo(greInstalledListTmp, aGre);
00323         siCObject->bSupersede = TRUE;
00324         aGre->siCGreComponent = siCObject;
00325         break;
00326       }
00327       else if(!foundVersionWithinRange && (minVerRead || maxVerRead))
00328       {
00329         stillInRange = TRUE;
00330 
00331         if(minVerRead)
00332           stillInRange = CompareVersion(greInstalledListTmp->version, aGre->minVersion) >= 0;
00333 
00334         if(stillInRange && maxVerRead)
00335           stillInRange = CompareVersion(greInstalledListTmp->version, aGre->maxVersion) <= 0;
00336 
00337         if(stillInRange)
00338         {
00339           // Find the first version within the range.
00340           SaveGreInfo(greInstalledListTmp, aGre);
00341           foundVersionWithinRange = TRUE;
00342         }
00343       }
00344       greSupersedeListTmp = greSupersedeListTmp->next;
00345     }
00346 
00347     if(siCObject->bSupersede)
00348       break;
00349 
00350     greInstalledListTmp = greInstalledListTmp->next;
00351   }
00352 
00353   if(!siCObject->bSupersede && foundVersionWithinRange)
00354     siCObject->bSupersede = TRUE;
00355 
00356   if(siCObject->bSupersede)
00357   {
00358     siCObject->dwAttributes &= ~SIC_SELECTED;
00359     siCObject->dwAttributes |= SIC_DISABLED;
00360     siCObject->dwAttributes |= SIC_INVISIBLE;
00361   }
00362   else
00363     /* Make sure to unset the DISABLED bit.  If the Setup Type is other than
00364      * Custom, then we don't care if it's DISABLED or not because this flag
00365      * is only used in the Custom dialogs.
00366      *
00367      * If the Setup Type is Custom and this component is DISABLED by default
00368      * via the config.ini, it's default value will be restored in the
00369      * SiCNodeSetItemsSelected() function that called ResolveSupersede(). */
00370     siCObject->dwAttributes &= ~SIC_DISABLED;
00371 }
00372 
00373 BOOL ResolveSupersede(siC *siCObject, greInfo *aGre)
00374 {
00375   DWORD dwIndex;
00376   char  szFilePath[MAX_BUF];
00377   char  szSupersedeFile[MAX_BUF];
00378   char  szSupersedeVersion[MAX_BUF];
00379   char  szType[MAX_BUF_TINY];
00380   char  szKey[MAX_BUF_TINY];
00381   verBlock  vbVersionNew;
00382   verBlock  vbFileVersion;
00383 
00384   siCObject->bSupersede = FALSE;
00385   if(siCObject->dwAttributes & SIC_SUPERSEDE)
00386   {
00387     dwIndex = 0;
00388     GetPrivateProfileString(siCObject->szReferenceName, "SupersedeType", "", szType, sizeof(szType), szFileIniConfig);
00389     if(*szType !='\0')
00390     {
00391       if(lstrcmpi(szType, "File Exists") == 0)
00392       {
00393         wsprintf(szKey, "SupersedeFile%d", dwIndex);        
00394         GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szSupersedeFile, sizeof(szSupersedeFile), szFileIniConfig);
00395         while(*szSupersedeFile != '\0')
00396         {
00397           DecryptString(szFilePath, szSupersedeFile);
00398           if(FileExists(szFilePath))
00399           {
00400             wsprintf(szKey, "SupersedeMinVersion%d",dwIndex);
00401             GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szSupersedeVersion, sizeof(szSupersedeVersion), szFileIniConfig);
00402             if(*szSupersedeVersion != '\0')
00403             {
00404               if(GetFileVersion(szFilePath,&vbFileVersion))
00405               {
00406                 /* If we can get the version, and it is greater than or equal to the SupersedeVersion
00407                  * set supersede.  If we cannot get the version, do not supersede the file. */
00408                 TranslateVersionStr(szSupersedeVersion, &vbVersionNew);
00409                 if(CompareVersion(vbFileVersion,vbVersionNew) >= 0)
00410                 {  
00411                   siCObject->bSupersede = TRUE;
00412                   break;  /* Found at least one file, so break out of while loop */
00413                 }
00414               }
00415             }
00416             else
00417             { /* The file exists, and there's no version to check.  set Supersede */
00418               siCObject->bSupersede = TRUE;
00419               break;  /* Found at least one file, so break out of while loop */
00420             }
00421           }
00422           wsprintf(szKey, "SupersedeFile%d", ++dwIndex);        
00423           GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szSupersedeFile, sizeof(szSupersedeFile), szFileIniConfig);
00424         }
00425       }
00426       else if(lstrcmpi(szType, "GRE") == 0)
00427       {
00428         /* save the GRE component */
00429         aGre->siCGreComponent = siCObject;
00430 
00431         /* If -fgre is passed in, and the current product to install is !GRE,
00432          * and the current component is 'Component GRE' then select and
00433          * disable it to force it to be installed regardless of supersede
00434          * rules.
00435          *
00436          * If the product is GRE, then it won't have a 'Component GRE', but
00437          * rather a 'Component XPCOM', in which case it will always get
00438          * installed */
00439         if((gbForceInstallGre) && (lstrcmpi(sgProduct.szProductNameInternal, "GRE") != 0))
00440         {
00441           siCObject->dwAttributes |= SIC_SELECTED;
00442           siCObject->dwAttributes |= SIC_DISABLED;
00443         }
00444         else
00445           ResolveSupersedeGre(siCObject, aGre);
00446       }
00447     }
00448 
00449     if(siCObject->bSupersede)
00450     {
00451       siCObject->dwAttributes &= ~SIC_SELECTED;
00452       siCObject->dwAttributes |= SIC_DISABLED;
00453       siCObject->dwAttributes |= SIC_INVISIBLE;
00454     }
00455     else
00456       /* Make sure to unset the DISABLED bit.  If the Setup Type is other than
00457        * Custom, then we don't care if it's DISABLED or not because this flag
00458        * is only used in the Custom dialogs.
00459        *
00460        * If the Setup Type is Custom and this component is DISABLED by default
00461        * via the config.ini, it's default value will be restored in the
00462        * SiCNodeSetItemsSelected() function that called ResolveSupersede(). */
00463       siCObject->dwAttributes &= ~SIC_DISABLED;
00464   }
00465   return(siCObject->bSupersede);
00466 }
00467