RetroZilla/xpinstall/wizard/windows/setup/supersede.c
2015-10-20 23:03:22 -04:00

468 lines
16 KiB
C

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sean Su <ssu@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "setup.h"
#include "extern.h"
#include "extra.h"
#include "ifuncns.h"
#include "supersede.h"
void SaveGreInfo(grever *aGreInstalledListTmp, greInfo* aGre);
void ResolveSupersedeGre(siC *siCObject, greInfo *aGre);
HRESULT GetGreSupersedeVersionList(siC *siCObject, grever **aGreSupersedeList);
HRESULT GetGreInstalledVersionList(siC *siCObject, grever **aGreInstalledList);
grever *CreateGVerNode()
{
grever *gverNode;
if((gverNode = NS_GlobalAlloc(sizeof(struct structGreVer))) == NULL)
return(NULL);
gverNode->greHomePath[0] = '\0';
gverNode->greInstaller[0] = '\0';
gverNode->greUserAgent[0] = '\0';
gverNode->version.ullMajor = 0;
gverNode->version.ullMinor = 0;
gverNode->version.ullRelease = 0;
gverNode->version.ullBuild = 0;
gverNode->next = NULL;
return(gverNode);
}
void DeleteGverList(grever *gverHead)
{
grever *tmp;
while(gverHead != NULL)
{
tmp = gverHead;
gverHead = gverHead->next;
FreeMemory(&tmp);
}
}
/* function to build a linked list of GRE supersede versions */
HRESULT GetGreSupersedeVersionList(siC *siCObject, grever **aGreSupersedeList)
{
grever *gverTmp = NULL;
grever *gverTail = NULL;
char key[MAX_BUF_TINY];
char versionString[MAX_BUF_TINY];
DWORD index;
if(*aGreSupersedeList)
/* list already built, just return */
return(WIZ_OK);
index = 0;
wsprintf(key, "SupersedeVersion%d", index);
GetPrivateProfileString(siCObject->szReferenceName, key, "", versionString,
sizeof(versionString), szFileIniConfig);
while(*versionString != '\0')
{
gverTmp = CreateGVerNode();
if(!gverTmp)
// error has already been displayed.
exit(WIZ_OUT_OF_MEMORY);
TranslateVersionStr(versionString, &gverTmp->version);
if(*aGreSupersedeList == NULL)
{
/* brand new list */
*aGreSupersedeList = gverTmp;
gverTail = *aGreSupersedeList;
}
else if(gverTail)
{
/* append the new node to the end of the list */
gverTail->next = gverTmp;
gverTail = gverTail->next;
}
wsprintf(key, "SupersedeVersion%d", ++index);
GetPrivateProfileString(siCObject->szReferenceName, key, "", versionString,
sizeof(versionString), szFileIniConfig);
}
return(WIZ_OK);
}
/* function to build a list of GRE's installed on the local system */
HRESULT GetGreInstalledVersionList(siC *siCObject, grever **aGreInstalledList)
{
DWORD index;
DWORD enumIndex;
DWORD greVersionKeyLen;
grever *gverTmp = NULL;
grever *gverTail = NULL;
char szSupersedeWinRegPath[MAX_BUF];
char key[MAX_BUF_TINY];
char greVersionKey[MAX_BUF_TINY];
char subKey[MAX_BUF];
char subKeyInstaller[MAX_BUF];
char szBuf[MAX_BUF];
char greXpcomPath[MAX_BUF];
char greXpcomFile[MAX_BUF];
int greXpcomPathLen;
char xpcomFilename[] = "xpcom.dll";
char greKeyPath[MAX_BUF];
verBlock vbInstalledVersion;
HKEY hkeyRoot = NULL;
HKEY hkGreKeyParentPath = NULL;
HKEY hkGreKeyPath = NULL;
LONG rv;
if(*aGreInstalledList)
/* list already built, just return */
return(WIZ_OK);
index = 0;
wsprintf(key, "SupersedeWinReg%d", index);
GetPrivateProfileString(siCObject->szReferenceName, key, "", szSupersedeWinRegPath,
sizeof(szSupersedeWinRegPath), szFileIniConfig);
while(*szSupersedeWinRegPath != '\0')
{
BOOL skip = FALSE;
if(!GetKeyInfo(szSupersedeWinRegPath, szBuf, sizeof(szBuf), KEY_INFO_ROOT))
// Malformed windows registry key, continue to reading the next key.
skip = TRUE;
hkeyRoot = ParseRootKey(szBuf);
if(!GetKeyInfo(szSupersedeWinRegPath, subKey, sizeof(subKey), KEY_INFO_SUBKEY))
// Malformed windows registry key, continue to reading the next key.
skip = TRUE;
if(RegOpenKeyEx(hkeyRoot, subKey, 0, KEY_READ, &hkGreKeyParentPath) != ERROR_SUCCESS)
// Problems opening the registry key. Ignore and continue reading the next key.
skip = TRUE;
greVersionKeyLen = sizeof(greVersionKey);
enumIndex = 0;
while(!skip &&
(RegEnumKeyEx(hkGreKeyParentPath, enumIndex++, greVersionKey, &greVersionKeyLen,
NULL, NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS))
{
sprintf(greKeyPath, "%s\\%s", subKey, greVersionKey);
if(RegOpenKeyEx(hkeyRoot, greKeyPath, 0, KEY_READ, &hkGreKeyPath) != ERROR_SUCCESS)
// Encoutered problems trying to open key. Just continue.
// We don't care about any errors. If we can't open the key,
// we just go on to other keys. These errors are nonfatal.
continue;
greXpcomPathLen = sizeof(greXpcomPath);
rv = RegQueryValueEx(hkGreKeyPath, "GreHome", 0, NULL, (BYTE *)greXpcomPath, &greXpcomPathLen);
RegCloseKey(hkGreKeyPath);
if(rv != ERROR_SUCCESS)
// Encoutered problems trying to read a var name. Just continue.
// We don't care about any errors. If we can't open the key,
// we just go on to other keys. These errors are nonfatal.
continue;
if(MozCopyStr(greXpcomPath, greXpcomFile, sizeof(greXpcomFile)))
{
RegCloseKey(hkGreKeyParentPath);
PrintError(szEOutOfMemory, ERROR_CODE_HIDE);
exit(WIZ_OUT_OF_MEMORY);
}
if(sizeof(greXpcomFile) <= lstrlen(greXpcomFile) + sizeof(xpcomFilename) + 1)
{
RegCloseKey(hkGreKeyParentPath);
PrintError(szEOutOfMemory, ERROR_CODE_HIDE);
exit(WIZ_OUT_OF_MEMORY);
}
AppendBackSlash(greXpcomFile, sizeof(greXpcomFile));
lstrcat(greXpcomFile, xpcomFilename);
if(GetFileVersion(greXpcomFile, &vbInstalledVersion))
{
// Don't create a node list unless xpcom.dll file actually exists.
gverTmp = CreateGVerNode();
if(!gverTmp)
{
RegCloseKey(hkGreKeyParentPath);
// error has already been displayed.
exit(WIZ_OUT_OF_MEMORY);
}
if(MozCopyStr(greXpcomPath, gverTmp->greHomePath, sizeof(gverTmp->greHomePath)))
{
RegCloseKey(hkGreKeyParentPath);
PrintError(szEOutOfMemory, ERROR_CODE_HIDE);
exit(WIZ_OUT_OF_MEMORY);
}
gverTmp->version.ullMajor = vbInstalledVersion.ullMajor;
gverTmp->version.ullMinor = vbInstalledVersion.ullMinor;
gverTmp->version.ullRelease = vbInstalledVersion.ullRelease;
gverTmp->version.ullBuild = vbInstalledVersion.ullBuild;
if(*aGreInstalledList == NULL)
{
/* brand new list */
*aGreInstalledList = gverTmp;
gverTail = *aGreInstalledList;
}
else if(gverTail)
{
/* append the new node to the end of the list */
gverTail->next = gverTmp;
gverTail = gverTail->next;
}
/* get the GRE's installer app path */
sprintf(subKeyInstaller, "%s\\%s\\Installer", subKey, greVersionKey);
GetWinReg(hkeyRoot, subKeyInstaller, "PathToExe", gverTmp->greInstaller, sizeof(gverTmp->greInstaller));
MozCopyStr(greVersionKey, gverTmp->greUserAgent, sizeof(gverTmp->greUserAgent));
}
greVersionKeyLen = sizeof(greVersionKey);
}
if(hkGreKeyParentPath)
{
RegCloseKey(hkGreKeyParentPath);
hkGreKeyParentPath = NULL;
}
++index;
wsprintf(key, "SupersedeWinReg%d", index);
GetPrivateProfileString(siCObject->szReferenceName, key, "", szSupersedeWinRegPath, sizeof(szSupersedeWinRegPath), szFileIniConfig);
}
return(WIZ_OK);
}
void SaveGreInfo(grever *aGreInstalledListTmp, greInfo* aGre)
{
MozCopyStr(aGreInstalledListTmp->greInstaller, aGre->installerAppPath, sizeof(aGre->installerAppPath));
MozCopyStr(aGreInstalledListTmp->greUserAgent, aGre->userAgent, sizeof(aGre->userAgent));
MozCopyStr(aGreInstalledListTmp->greHomePath, aGre->homePath, sizeof(aGre->homePath));
}
void ResolveSupersedeGre(siC *siCObject, greInfo *aGre)
{
grever *greSupersedeListTmp = NULL;
grever *greInstalledListTmp = NULL;
char versionStr[MAX_BUF_TINY];
siC *siCTmp = NULL;
BOOL foundVersionWithinRange = FALSE;
BOOL minVerRead = FALSE;
BOOL maxVerRead = FALSE;
BOOL stillInRange = FALSE;
if(GetGreSupersedeVersionList(siCObject, &aGre->greSupersedeList))
return;
if(GetGreInstalledVersionList(siCObject, &aGre->greInstalledList))
return;
if(!aGre->greSupersedeList || !aGre->greInstalledList)
// nothing to compare, return
return;
GetPrivateProfileString(siCObject->szReferenceName, "SupersedeMinVersion", "",
versionStr, sizeof(versionStr), szFileIniConfig);
if(*versionStr != '\0')
{
TranslateVersionStr(versionStr, &aGre->minVersion);
minVerRead = TRUE;
}
GetPrivateProfileString(siCObject->szReferenceName, "SupersedeMaxVersion", "",
versionStr, sizeof(versionStr), szFileIniConfig);
if(*versionStr != '\0')
{
TranslateVersionStr(versionStr, &aGre->maxVersion);
maxVerRead = TRUE;
}
// do the version comparison here.
greInstalledListTmp = aGre->greInstalledList;
while(greInstalledListTmp)
{
greSupersedeListTmp = aGre->greSupersedeList;
while(greSupersedeListTmp)
{
if(CompareVersion(greInstalledListTmp->version, greSupersedeListTmp->version) == 0)
{
SaveGreInfo(greInstalledListTmp, aGre);
siCObject->bSupersede = TRUE;
aGre->siCGreComponent = siCObject;
break;
}
else if(!foundVersionWithinRange && (minVerRead || maxVerRead))
{
stillInRange = TRUE;
if(minVerRead)
stillInRange = CompareVersion(greInstalledListTmp->version, aGre->minVersion) >= 0;
if(stillInRange && maxVerRead)
stillInRange = CompareVersion(greInstalledListTmp->version, aGre->maxVersion) <= 0;
if(stillInRange)
{
// Find the first version within the range.
SaveGreInfo(greInstalledListTmp, aGre);
foundVersionWithinRange = TRUE;
}
}
greSupersedeListTmp = greSupersedeListTmp->next;
}
if(siCObject->bSupersede)
break;
greInstalledListTmp = greInstalledListTmp->next;
}
if(!siCObject->bSupersede && foundVersionWithinRange)
siCObject->bSupersede = TRUE;
if(siCObject->bSupersede)
{
siCObject->dwAttributes &= ~SIC_SELECTED;
siCObject->dwAttributes |= SIC_DISABLED;
siCObject->dwAttributes |= SIC_INVISIBLE;
}
else
/* Make sure to unset the DISABLED bit. If the Setup Type is other than
* Custom, then we don't care if it's DISABLED or not because this flag
* is only used in the Custom dialogs.
*
* If the Setup Type is Custom and this component is DISABLED by default
* via the config.ini, it's default value will be restored in the
* SiCNodeSetItemsSelected() function that called ResolveSupersede(). */
siCObject->dwAttributes &= ~SIC_DISABLED;
}
BOOL ResolveSupersede(siC *siCObject, greInfo *aGre)
{
DWORD dwIndex;
char szFilePath[MAX_BUF];
char szSupersedeFile[MAX_BUF];
char szSupersedeVersion[MAX_BUF];
char szType[MAX_BUF_TINY];
char szKey[MAX_BUF_TINY];
verBlock vbVersionNew;
verBlock vbFileVersion;
siCObject->bSupersede = FALSE;
if(siCObject->dwAttributes & SIC_SUPERSEDE)
{
dwIndex = 0;
GetPrivateProfileString(siCObject->szReferenceName, "SupersedeType", "", szType, sizeof(szType), szFileIniConfig);
if(*szType !='\0')
{
if(lstrcmpi(szType, "File Exists") == 0)
{
wsprintf(szKey, "SupersedeFile%d", dwIndex);
GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szSupersedeFile, sizeof(szSupersedeFile), szFileIniConfig);
while(*szSupersedeFile != '\0')
{
DecryptString(szFilePath, szSupersedeFile);
if(FileExists(szFilePath))
{
wsprintf(szKey, "SupersedeMinVersion%d",dwIndex);
GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szSupersedeVersion, sizeof(szSupersedeVersion), szFileIniConfig);
if(*szSupersedeVersion != '\0')
{
if(GetFileVersion(szFilePath,&vbFileVersion))
{
/* If we can get the version, and it is greater than or equal to the SupersedeVersion
* set supersede. If we cannot get the version, do not supersede the file. */
TranslateVersionStr(szSupersedeVersion, &vbVersionNew);
if(CompareVersion(vbFileVersion,vbVersionNew) >= 0)
{
siCObject->bSupersede = TRUE;
break; /* Found at least one file, so break out of while loop */
}
}
}
else
{ /* The file exists, and there's no version to check. set Supersede */
siCObject->bSupersede = TRUE;
break; /* Found at least one file, so break out of while loop */
}
}
wsprintf(szKey, "SupersedeFile%d", ++dwIndex);
GetPrivateProfileString(siCObject->szReferenceName, szKey, "", szSupersedeFile, sizeof(szSupersedeFile), szFileIniConfig);
}
}
else if(lstrcmpi(szType, "GRE") == 0)
{
/* save the GRE component */
aGre->siCGreComponent = siCObject;
/* If -fgre is passed in, and the current product to install is !GRE,
* and the current component is 'Component GRE' then select and
* disable it to force it to be installed regardless of supersede
* rules.
*
* If the product is GRE, then it won't have a 'Component GRE', but
* rather a 'Component XPCOM', in which case it will always get
* installed */
if((gbForceInstallGre) && (lstrcmpi(sgProduct.szProductNameInternal, "GRE") != 0))
{
siCObject->dwAttributes |= SIC_SELECTED;
siCObject->dwAttributes |= SIC_DISABLED;
}
else
ResolveSupersedeGre(siCObject, aGre);
}
}
if(siCObject->bSupersede)
{
siCObject->dwAttributes &= ~SIC_SELECTED;
siCObject->dwAttributes |= SIC_DISABLED;
siCObject->dwAttributes |= SIC_INVISIBLE;
}
else
/* Make sure to unset the DISABLED bit. If the Setup Type is other than
* Custom, then we don't care if it's DISABLED or not because this flag
* is only used in the Custom dialogs.
*
* If the Setup Type is Custom and this component is DISABLED by default
* via the config.ini, it's default value will be restored in the
* SiCNodeSetItemsSelected() function that called ResolveSupersede(). */
siCObject->dwAttributes &= ~SIC_DISABLED;
}
return(siCObject->bSupersede);
}