Files
Mozilla/mozilla/xpinstall/src/nsInstall.cpp
cathleen%netscape.com 0b23c5b307 fixed crash bug for patching, happened at cleanup() stage. removed the
enumerate call to delete the pointers in hash table, since it has
already been deleted.  also added some error checking and reset pointers
to null bug 24455, r=dbragg


git-svn-id: svn://10.0.0.236/trunk@59341 18797224-902f-48f8-a5cc-f745e15eee43
2000-02-01 01:51:25 +00:00

2387 lines
57 KiB
C++

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 client code,
* released March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Daniel Veditz <dveditz@netscape.com>
* Douglas Turner <dougt@netscape.com>
* Pierre Phaneuf <pp@ludusdesign.com>
*/
#include "nscore.h"
#include "nsIFactory.h"
#include "nsISupports.h"
#include "nsRepository.h"
#include "nsIServiceManager.h"
#include "nsHashtable.h"
#include "nsFileSpec.h"
#include "nsFileStream.h"
#include "nsSpecialSystemDirectory.h"
#include "nsIPref.h"
#include "prmem.h"
#include "plstr.h"
#include "prprf.h"
#include "VerReg.h"
#include "nsInstall.h"
#include "nsInstallFolder.h"
#include "nsInstallVersion.h"
#include "nsInstallFile.h"
#include "nsInstallDelete.h"
#include "nsInstallExecute.h"
#include "nsInstallPatch.h"
#include "nsInstallUninstall.h"
#include "nsInstallResources.h"
#include "nsNetUtil.h"
#include "nsProxiedService.h"
#include "nsINetSupportDialogService.h"
#include "nsIPrompt.h"
#ifdef _WINDOWS
#include "nsWinReg.h"
#include "nsWinProfile.h"
#endif
#include "nsInstallFileOpEnums.h"
#include "nsInstallFileOpItem.h"
#ifdef XP_MAC
#include "Gestalt.h"
#include "nsAppleSingleDecoder.h"
#endif
#include "nsILocalFile.h"
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID);
static NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
static NS_DEFINE_IID(kIStringBundleServiceIID, NS_ISTRINGBUNDLESERVICE_IID);
#define XPINSTALL_BUNDLE_URL "chrome://xpinstall/locale/xpinstall.properties"
// filename length maximums
#ifdef XP_MAC
#define MAX_NAME_LENGTH 31
#elif defined (XP_PC)
#define MAX_NAME_LENGTH 128
#elif defined (XP_UNIX)
#define MAX_NAME_LENGTH 1024 //got this one from nsComponentManager.h
#endif
MOZ_DECL_CTOR_COUNTER(nsInstallInfo);
nsInstallInfo::nsInstallInfo(nsIFileSpec* aFile,
const PRUnichar* aURL,
const PRUnichar* aArgs,
long flags,
nsIXPINotifier* aNotifier)
: mError(0),
mFlags(flags),
mURL(aURL),
mArgs(aArgs),
mFile(aFile),
mNotifier(aNotifier)
{
MOZ_COUNT_CTOR(nsInstallInfo);
}
nsInstallInfo::~nsInstallInfo()
{
MOZ_COUNT_DTOR(nsInstallInfo);
}
nsresult
nsInstallInfo::GetLocalFile(nsFileSpec& aSpec)
{
if (!mFile)
return NS_ERROR_NULL_POINTER;
return mFile->GetFileSpec(&aSpec);
}
static NS_DEFINE_IID(kISoftwareUpdateIID, NS_ISOFTWAREUPDATE_IID);
static NS_DEFINE_IID(kSoftwareUpdateCID, NS_SoftwareUpdate_CID);
static NS_DEFINE_IID(kIZipReaderIID, NS_IZIPREADER_IID);
static NS_DEFINE_IID(kZipReaderCID, NS_ZIPREADER_CID);
MOZ_DECL_CTOR_COUNTER(nsInstall);
nsInstall::nsInstall(nsIZipReader * theJARFile)
{
MOZ_COUNT_CTOR(nsInstall);
mScriptObject = nsnull; // this is the jsobject for our context
mVersionInfo = nsnull; // this is the version information passed to us in StartInstall()
mInstalledFiles = nsnull; // the list of installed objects
mRegistryPackageName = ""; // this is the name that we will add into the registry for the component we are installing
mUIName = ""; // this is the name that will be displayed in UI.
mPatchList = nsnull;
mUninstallPackage = PR_FALSE;
mRegisterPackage = PR_FALSE;
mStatusSent = PR_FALSE;
mStartInstallCompleted = PR_FALSE;
mJarFileLocation = "";
mInstallArguments = "";
// mJarFileData is an opaque handle to the jarfile.
mJarFileData = theJARFile;
nsISoftwareUpdate *su;
nsresult rv = nsServiceManager::GetService(kSoftwareUpdateCID,
kISoftwareUpdateIID,
(nsISupports**) &su);
if (NS_SUCCEEDED(rv))
{
su->GetMasterNotifier( &mNotifier );
}
su->Release();
// get the resourced xpinstall string bundle
mStringBundle = nsnull;
nsIStringBundleService *service;
rv = nsServiceManager::GetService( kStringBundleServiceCID,
NS_GET_IID(nsIStringBundleService),
(nsISupports**) &service );
if (NS_SUCCEEDED(rv) && service)
{
nsILocale* locale = nsnull;
rv = service->CreateBundle( XPINSTALL_BUNDLE_URL, locale,
getter_AddRefs(mStringBundle) );
nsServiceManager::ReleaseService( kStringBundleServiceCID, service );
}
}
nsInstall::~nsInstall()
{
if (mVersionInfo != nsnull)
delete mVersionInfo;
MOZ_COUNT_DTOR(nsInstall);
}
PRInt32
nsInstall::SetScriptObject(void *aScriptObject)
{
mScriptObject = (JSObject*) aScriptObject;
return NS_OK;
}
#ifdef _WINDOWS
PRInt32
nsInstall::SaveWinRegPrototype(void *aScriptObject)
{
mWinRegObject = (JSObject*) aScriptObject;
return NS_OK;
}
PRInt32
nsInstall::SaveWinProfilePrototype(void *aScriptObject)
{
mWinProfileObject = (JSObject*) aScriptObject;
return NS_OK;
}
JSObject*
nsInstall::RetrieveWinRegPrototype()
{
return mWinRegObject;
}
JSObject*
nsInstall::RetrieveWinProfilePrototype()
{
return mWinProfileObject;
}
#endif
PRInt32
nsInstall::GetUserPackageName(nsString& aUserPackageName)
{
aUserPackageName = mUIName;
return NS_OK;
}
PRInt32
nsInstall::GetRegPackageName(nsString& aRegPackageName)
{
aRegPackageName = mRegistryPackageName;
return NS_OK;
}
void
nsInstall::InternalAbort(PRInt32 errcode)
{
if (mNotifier)
{
mNotifier->FinalStatus(mInstallURL.GetUnicode(), errcode);
mStatusSent = PR_TRUE;
}
nsInstallObject* ie;
if (mInstalledFiles != nsnull)
{
for (PRInt32 i=mInstalledFiles->Count() - 1; i >= 0; i--)
{
ie = (nsInstallObject *)mInstalledFiles->ElementAt(i);
if (ie)
ie->Abort();
}
}
CleanUp();
}
PRInt32
nsInstall::AbortInstall(PRInt32 aErrorNumber)
{
InternalAbort(aErrorNumber);
return NS_OK;
}
PRInt32
nsInstall::AddDirectory(const nsString& aRegName,
const nsString& aVersion,
const nsString& aJarSource,
nsInstallFolder *aFolder,
const nsString& aSubdir,
PRBool aForceMode,
PRInt32* aReturn)
{
nsInstallFile* ie = nsnull;
PRInt32 result;
if ( aJarSource.Equals("") || aFolder == nsnull )
{
*aReturn = SaveError(nsInstall::INVALID_ARGUMENTS);
return NS_OK;
}
result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsString qualifiedRegName;
if ( aRegName.Equals(""))
{
// Default subName = location in jar file
*aReturn = GetQualifiedRegName( aJarSource, qualifiedRegName);
}
else
{
*aReturn = GetQualifiedRegName( aRegName, qualifiedRegName );
}
if (*aReturn != SUCCESS)
{
return NS_OK;
}
nsString qualifiedVersion = aVersion;
if (qualifiedVersion == "")
{
// assume package version for overriden forms that don't take version info
*aReturn = mVersionInfo->ToString(qualifiedVersion);
if (NS_FAILED(*aReturn))
{
SaveError( nsInstall::UNEXPECTED_ERROR );
return NS_OK;
}
}
nsString subdirectory(aSubdir);
if (subdirectory != "")
{
subdirectory.Append("/");
}
nsVoidArray *paths = new nsVoidArray();
if (paths == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
result = ExtractDirEntries(aJarSource, paths);
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
PRInt32 count = paths->Count();
if (count == 0)
{
*aReturn = SaveError( nsInstall::DOES_NOT_EXIST );
return NS_OK;
}
for (PRInt32 i=0; i < count; i++)
{
nsString *thisPath = (nsString *)paths->ElementAt(i);
nsString newJarSource = aJarSource;
newJarSource += "/";
newJarSource += *thisPath;
nsString fullRegName = qualifiedRegName;
fullRegName += "/";
fullRegName += *thisPath;
nsString newSubDir;
if (subdirectory != "")
{
newSubDir = subdirectory;
}
newSubDir += *thisPath;
ie = new nsInstallFile( this,
fullRegName,
qualifiedVersion,
newJarSource,
aFolder,
newSubDir,
aForceMode,
&result);
if (ie == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (result == nsInstall::SUCCESS)
{
result = ScheduleForInstall( ie );
}
else
{
delete ie;
}
}
DeleteVector(paths);
*aReturn = SaveError( result );
return NS_OK;
}
PRInt32
nsInstall::AddDirectory(const nsString& aRegName,
const nsString& aVersion,
const nsString& aJarSource,
nsInstallFolder *aFolder,
const nsString& aSubdir,
PRInt32* aReturn)
{
return AddDirectory(aRegName,
aVersion,
aJarSource,
aFolder,
aSubdir,
PR_FALSE,
aReturn);
}
PRInt32
nsInstall::AddDirectory(const nsString& aRegName,
const nsString& aJarSource,
nsInstallFolder *aFolder,
const nsString& aSubdir,
PRInt32* aReturn)
{
return AddDirectory(aRegName,
"",
aJarSource,
aFolder,
aSubdir,
PR_FALSE,
aReturn);
}
PRInt32
nsInstall::AddDirectory(const nsString& aJarSource,
PRInt32* aReturn)
{
return AddDirectory("",
"",
aJarSource,
nsnull,
"",
PR_FALSE,
aReturn);
}
PRInt32
nsInstall::AddSubcomponent(const nsString& aRegName,
const nsString& aVersion,
const nsString& aJarSource,
nsInstallFolder *aFolder,
const nsString& aTargetName,
PRBool aForceMode,
PRInt32* aReturn)
{
nsInstallFile* ie;
nsString qualifiedRegName;
nsString qualifiedVersion = aVersion;
nsString tempTargetName = aTargetName;
PRInt32 errcode = nsInstall::SUCCESS;
if(aJarSource.Equals("") || aFolder == nsnull )
{
*aReturn = SaveError( nsInstall::INVALID_ARGUMENTS );
return NS_OK;
}
if(aTargetName.Length() > MAX_NAME_LENGTH)
{
*aReturn = SaveError( nsInstall::FILENAME_TOO_LONG );
return NS_OK;
}
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if( aTargetName.Equals("") )
tempTargetName = aJarSource;
if (qualifiedVersion == "")
qualifiedVersion.SetString("0.0.0.0");
if ( aRegName.Equals("") )
{
// Default subName = location in jar file
*aReturn = GetQualifiedRegName( aJarSource, qualifiedRegName);
}
else
{
*aReturn = GetQualifiedRegName( aRegName, qualifiedRegName );
}
if (*aReturn != SUCCESS)
{
return NS_OK;
}
ie = new nsInstallFile( this,
qualifiedRegName,
qualifiedVersion,
aJarSource,
aFolder,
tempTargetName,
aForceMode,
&errcode );
if (ie == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (errcode == nsInstall::SUCCESS)
{
errcode = ScheduleForInstall( ie );
}
else
{
delete ie;
}
*aReturn = SaveError( errcode );
return NS_OK;
}
PRInt32
nsInstall::AddSubcomponent(const nsString& aRegName,
const nsString& aVersion,
const nsString& aJarSource,
nsInstallFolder* aFolder,
const nsString& aTargetName,
PRInt32* aReturn)
{
return AddSubcomponent(aRegName,
aVersion,
aJarSource,
aFolder,
aTargetName,
PR_FALSE,
aReturn);
}
PRInt32
nsInstall::AddSubcomponent(const nsString& aRegName,
const nsString& aJarSource,
nsInstallFolder* aFolder,
const nsString& aTargetName,
PRInt32* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsString version;
*aReturn = mVersionInfo->ToString(version);
if (NS_FAILED(*aReturn))
{
SaveError( nsInstall::UNEXPECTED_ERROR );
return NS_OK;
}
return AddSubcomponent(aRegName,
version,
aJarSource,
aFolder,
aTargetName,
PR_FALSE,
aReturn);
}
PRInt32
nsInstall::AddSubcomponent(const nsString& aJarSource,
PRInt32* aReturn)
{
if(mPackageFolder == nsnull)
{
*aReturn = SaveError( nsInstall::PACKAGE_FOLDER_NOT_SET );
return NS_OK;
}
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsString version;
*aReturn = mVersionInfo->ToString(version);
if (NS_FAILED(*aReturn))
{
SaveError( nsInstall::UNEXPECTED_ERROR );
return NS_OK;
}
return AddSubcomponent("",
version,
aJarSource,
mPackageFolder,
"",
PR_FALSE,
aReturn);
}
PRInt32
nsInstall::DeleteComponent(const nsString& aRegistryName, PRInt32* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsString qualifiedRegName;
*aReturn = GetQualifiedRegName( aRegistryName, qualifiedRegName);
if (*aReturn != SUCCESS)
{
return NS_OK;
}
nsInstallDelete* id = new nsInstallDelete(this, qualifiedRegName, &result);
if (id == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (result == nsInstall::SUCCESS)
{
result = ScheduleForInstall( id );
}
*aReturn = SaveError(result);
return NS_OK;
}
PRInt32
nsInstall::DeleteFile(nsInstallFolder* aFolder, const nsString& aRelativeFileName, PRInt32* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsInstallDelete* id = new nsInstallDelete(this, aFolder, aRelativeFileName, &result);
if (id == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (result == nsInstall::SUCCESS)
{
result = ScheduleForInstall( id );
}
if (result == nsInstall::DOES_NOT_EXIST)
{
result = nsInstall::SUCCESS;
}
*aReturn = SaveError(result);
return NS_OK;
}
PRInt32
nsInstall::DiskSpaceAvailable(const nsString& aFolder, PRInt64* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
double d = SaveError( result );
LL_L2D(d, *aReturn);
return NS_OK;
}
nsFileSpec fsFolder(aFolder);
*aReturn = fsFolder.GetDiskSpaceAvailable();
return NS_OK;
}
PRInt32
nsInstall::Execute(const nsString& aJarSource, const nsString& aArgs, PRInt32* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsInstallExecute* ie = new nsInstallExecute(this, aJarSource, aArgs, &result);
if (ie == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (result == nsInstall::SUCCESS)
{
result = ScheduleForInstall( ie );
}
*aReturn = SaveError(result);
return NS_OK;
}
PRInt32
nsInstall::Execute(const nsString& aJarSource, PRInt32* aReturn)
{
return Execute(aJarSource, "", aReturn);
}
PRInt32
nsInstall::FinalizeInstall(PRInt32* aReturn)
{
PRInt32 result = SUCCESS;
PRBool rebootNeeded = PR_FALSE;
*aReturn = SanityCheck();
if (*aReturn != nsInstall::SUCCESS)
{
SaveError( *aReturn );
if (mNotifier)
{
mNotifier->FinalStatus(mInstallURL.GetUnicode(), *aReturn);
mStatusSent = PR_TRUE;
}
return NS_OK;
}
if ( mInstalledFiles != NULL && mInstalledFiles->Count() > 0 )
{
if ( mUninstallPackage )
{
VR_UninstallCreateNode( (char*)(const char*) nsAutoCString(mRegistryPackageName),
(char*)(const char*) nsAutoCString(mUIName));
}
// Install the Component into the Version Registry.
if (mVersionInfo)
{
nsString versionString;
mVersionInfo->ToString(versionString);
VR_Install( (char*)(const char*)nsAutoCString(mRegistryPackageName),
nsnull,
(char*)(const char*)nsAutoCString(versionString),
PR_FALSE );
}
nsInstallObject* ie = nsnull;
for (PRInt32 i=0; i < mInstalledFiles->Count(); i++)
{
ie = (nsInstallObject*)mInstalledFiles->ElementAt(i);
NS_ASSERTION(ie, "NULL object in install queue!");
if (ie == NULL)
continue;
result = ie->Complete();
if (result != nsInstall::SUCCESS)
{
if ( result == REBOOT_NEEDED )
{
rebootNeeded = PR_TRUE;
result = SUCCESS;
}
else
{
InternalAbort( result );
break;
}
}
if (mNotifier)
{
char *objString = ie->toString();
if (objString)
{
mNotifier->FinalizeProgress(nsAutoString(objString).GetUnicode(),
(i+1), mInstalledFiles->Count());
delete [] objString;
}
}
}
if ( result != SUCCESS )
*aReturn = SaveError( result );
else if ( rebootNeeded )
*aReturn = SaveError( REBOOT_NEEDED );
if (mNotifier)
{
mNotifier->FinalStatus(mInstallURL.GetUnicode(), *aReturn);
mStatusSent = PR_TRUE;
}
}
else
{
// no actions queued: don't register the package version
// and no need for user confirmation
if (mNotifier)
{
mNotifier->FinalStatus(mInstallURL.GetUnicode(), *aReturn);
mStatusSent = PR_TRUE;
}
}
if((result == nsInstall::SUCCESS) || (result == REBOOT_NEEDED))
CleanUp();
return NS_OK;
}
#ifdef XP_MAC
#define GESTALT_CHAR_CODE(x) (((unsigned long) ((x[0]) & 0x000000FF)) << 24) \
| (((unsigned long) ((x[1]) & 0x000000FF)) << 16) \
| (((unsigned long) ((x[2]) & 0x000000FF)) << 8) \
| (((unsigned long) ((x[3]) & 0x000000FF)))
#endif /* XP_MAC */
PRInt32
nsInstall::Gestalt(const nsString& aSelector, PRInt32* aReturn)
{
*aReturn = nsnull;
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
#ifdef XP_MAC
long response = 0;
char selectorChars[4];
int i;
OSErr err = noErr;
OSType selector;
if (aSelector == "")
{
return NS_OK;
}
for (i=0; i<4; i++)
selectorChars[i] = aSelector.CharAt(i);
selector = GESTALT_CHAR_CODE(selectorChars);
err = ::Gestalt(selector, &response);
if (err != noErr)
*aReturn = err;
else
*aReturn = response;
#endif
return NS_OK;
}
PRInt32
nsInstall::GetComponentFolder(const nsString& aComponentName, const nsString& aSubdirectory, nsInstallFolder** aNewFolder)
{
long err;
char* componentCString;
char dir[MAXREGPATHLEN];
nsFileSpec nsfsDir;
if(!aNewFolder)
return INVALID_ARGUMENTS;
*aNewFolder = nsnull;
nsString tempString;
if ( GetQualifiedPackageName(aComponentName, tempString) != SUCCESS )
{
return NS_OK;
}
componentCString = tempString.ToNewCString();
if((err = VR_GetDefaultDirectory( componentCString, MAXREGPATHLEN, dir )) != REGERR_OK)
{
if((err = VR_GetPath( componentCString, MAXREGPATHLEN, dir )) == REGERR_OK)
{
int i;
nsString dirStr(dir);
if ( (i = dirStr.RFindChar(FILESEP)) > 0 )
{
// i is the index in the string, not the total number of
// characters in the string. ToCString() requires the
// total number of characters in the string to copy,
// therefore add 1 to it.
dirStr.Truncate(i + 1);
dirStr.ToCString(dir, MAXREGPATHLEN);
}
}
else
{
*dir = '\0';
}
}
else
{
*dir = '\0';
}
if(*dir != '\0')
{
*aNewFolder = new nsInstallFolder(dir, aSubdirectory);
}
if (componentCString)
Recycle(componentCString);
return NS_OK;
}
PRInt32
nsInstall::GetComponentFolder(const nsString& aComponentName, nsInstallFolder** aNewFolder)
{
return GetComponentFolder(aComponentName, "", aNewFolder);
}
PRInt32
nsInstall::GetFolder(const nsString& targetFolder, const nsString& aSubdirectory, nsInstallFolder** aNewFolder)
{
/* This version of GetFolder takes an nsString object as the first param */
if (!aNewFolder)
return INVALID_ARGUMENTS;
*aNewFolder = new nsInstallFolder(targetFolder, aSubdirectory);
if (*aNewFolder == nsnull)
{
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
PRInt32
nsInstall::GetFolder(const nsString& targetFolder, nsInstallFolder** aNewFolder)
{
/* This version of GetFolder takes an nsString object as the only param */
return GetFolder(targetFolder, "", aNewFolder);
}
PRInt32
nsInstall::GetFolder( nsInstallFolder& aTargetFolderObj, const nsString& aSubdirectory, nsInstallFolder** aNewFolder )
{
/* This version of GetFolder takes a nsInstallFolder object as the first param */
if (!aNewFolder)
return INVALID_ARGUMENTS;
*aNewFolder = new nsInstallFolder(aTargetFolderObj, aSubdirectory);
if (*aNewFolder == nsnull)
{
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
PRInt32
nsInstall::GetLastError(PRInt32* aReturn)
{
*aReturn = mLastError;
return NS_OK;
}
PRInt32
nsInstall::GetWinProfile(const nsString& aFolder, const nsString& aFile, JSContext* jscontext, JSClass* WinProfileClass, jsval* aReturn)
{
*aReturn = JSVAL_NULL;
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
#ifdef _WINDOWS
JSObject* winProfileObject;
nsWinProfile* nativeWinProfileObject = new nsWinProfile(this, aFolder, aFile);
if (nativeWinProfileObject == nsnull)
return NS_OK;
JSObject* winProfilePrototype = this->RetrieveWinProfilePrototype();
winProfileObject = JS_NewObject(jscontext, WinProfileClass, winProfilePrototype, NULL);
if(winProfileObject == NULL)
return NS_OK;
JS_SetPrivate(jscontext, winProfileObject, nativeWinProfileObject);
*aReturn = OBJECT_TO_JSVAL(winProfileObject);
#endif /* _WINDOWS */
return NS_OK;
}
PRInt32
nsInstall::GetWinRegistry(JSContext* jscontext, JSClass* WinRegClass, jsval* aReturn)
{
*aReturn = JSVAL_NULL;
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
#ifdef _WINDOWS
JSObject* winRegObject;
nsWinReg* nativeWinRegObject = new nsWinReg(this);
if (nativeWinRegObject == nsnull)
return NS_OK;
JSObject* winRegPrototype = this->RetrieveWinRegPrototype();
winRegObject = JS_NewObject(jscontext, WinRegClass, winRegPrototype, NULL);
if(winRegObject == NULL)
return NS_OK;
JS_SetPrivate(jscontext, winRegObject, nativeWinRegObject);
*aReturn = OBJECT_TO_JSVAL(winRegObject);
#endif /* _WINDOWS */
return NS_OK;
}
PRInt32
nsInstall::LoadResources(JSContext* cx, const nsString& aBaseName, jsval* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsresult ret;
nsFileSpec* resFile;
nsFileURL* resFileURL = nsnull;
nsIURI *url = nsnull;
nsILocale* locale = nsnull;
nsIStringBundleService* service = nsnull;
nsIEventQueueService* pEventQueueService = nsnull;
nsIStringBundle* bundle = nsnull;
nsIBidirectionalEnumerator* propEnum = nsnull;
*aReturn = JSVAL_NULL;
jsval v = JSVAL_NULL;
// set up JSObject to return
JS_GetProperty( cx, JS_GetGlobalObject( cx ), "Object", &v );
if (!v)
{
return NS_ERROR_NULL_POINTER;
}
JSClass *objclass = JS_GetClass( cx, JSVAL_TO_OBJECT(v) );
JSObject *res = JS_NewObject( cx, objclass, JSVAL_TO_OBJECT(v), 0 );
// extract properties file
// XXX append locale info: lang code, country code, .properties suffix to aBaseName
PRInt32 err = ExtractFileFromJar(aBaseName, nsnull, &resFile);
if ( (!resFile) || (err != nsInstall::SUCCESS) )
{
SaveError( err );
return NS_OK;
}
// initialize string bundle and related services
ret = nsServiceManager::GetService(kStringBundleServiceCID,
kIStringBundleServiceIID, (nsISupports**) &service);
if (NS_FAILED(ret))
goto cleanup;
ret = nsServiceManager::GetService(kEventQueueServiceCID,
kIEventQueueServiceIID, (nsISupports**) &pEventQueueService);
if (NS_FAILED(ret))
goto cleanup;
ret = pEventQueueService->CreateThreadEventQueue();
if (NS_FAILED(ret))
goto cleanup;
// construct properties file URL as required by StringBundle interface
resFileURL = new nsFileURL( *resFile );
ret = NS_NewURI(&url, resFileURL->GetURLString());
if (resFileURL)
delete resFileURL;
if (NS_FAILED(ret))
goto cleanup;
// get the string bundle using the extracted properties file
#if 1
{
char* spec = nsnull;
ret = url->GetSpec(&spec);
if (NS_FAILED(ret)) {
printf("cannot get url spec\n");
nsServiceManager::ReleaseService(kStringBundleServiceCID, service);
nsCRT::free(spec);
return ret;
}
ret = service->CreateBundle(spec, locale, &bundle);
nsCRT::free(spec);
}
#else
ret = service->CreateBundle(url, locale, &bundle);
#endif
if (NS_FAILED(ret))
goto cleanup;
ret = bundle->GetEnumeration(&propEnum);
if (NS_FAILED(ret))
goto cleanup;
// set the variables of the JSObject to return using the StringBundle's
// enumeration service
ret = propEnum->First();
if (NS_FAILED(ret))
goto cleanup;
while (NS_SUCCEEDED(ret))
{
nsIPropertyElement* propElem = nsnull;
ret = propEnum->CurrentItem((nsISupports**)&propElem);
if (NS_FAILED(ret))
goto cleanup;
nsString* key = nsnull;
nsString* val = nsnull;
ret = propElem->GetKey(&key);
if (NS_FAILED(ret))
goto cleanup;
ret = propElem->GetValue(&val);
if (NS_FAILED(ret))
goto cleanup;
char* keyCStr = key->ToNewCString();
PRUnichar* valCStr = val->ToNewUnicode();
if (keyCStr && valCStr)
{
JSString* propValJSStr = JS_NewUCStringCopyZ(cx, (jschar*) valCStr);
jsval propValJSVal = STRING_TO_JSVAL(propValJSStr);
JS_SetProperty(cx, res, keyCStr, &propValJSVal);
delete[] keyCStr;
delete[] valCStr;
}
if (key)
delete key;
if (val)
delete val;
ret = propEnum->Next();
}
*aReturn = OBJECT_TO_JSVAL(res);
ret = nsInstall::SUCCESS;
cleanup:
SaveError( ret );
// release services
NS_IF_RELEASE( service );
NS_IF_RELEASE( pEventQueueService );
// release file, URL, StringBundle, Enumerator
NS_IF_RELEASE( url );
NS_IF_RELEASE( bundle );
NS_IF_RELEASE( propEnum );
if (resFile)
{
// delete the transient properties file
resFile->Delete(PR_FALSE);
delete resFile;
}
return NS_OK;
}
PRInt32
nsInstall::Patch(const nsString& aRegName, const nsString& aVersion, const nsString& aJarSource, nsInstallFolder* aFolder, const nsString& aTargetName, PRInt32* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsString qualifiedRegName;
*aReturn = GetQualifiedRegName( aRegName, qualifiedRegName);
if (*aReturn != SUCCESS)
{
return NS_OK;
}
if (!mPatchList)
{
mPatchList = new nsHashtable();
if (mPatchList == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
}
nsInstallPatch* ip = new nsInstallPatch( this,
qualifiedRegName,
aVersion,
aJarSource,
aFolder,
aTargetName,
&result);
if (ip == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (result == nsInstall::SUCCESS)
{
result = ScheduleForInstall( ip );
}
*aReturn = SaveError(result);
return NS_OK;
}
PRInt32
nsInstall::Patch(const nsString& aRegName, const nsString& aJarSource, nsInstallFolder* aFolder, const nsString& aTargetName, PRInt32* aReturn)
{
return Patch(aRegName, "", aJarSource, aFolder, aTargetName, aReturn);
}
PRInt32
nsInstall::ResetError()
{
mLastError = nsInstall::SUCCESS;
return NS_OK;
}
PRInt32
nsInstall::SetPackageFolder(nsInstallFolder& aFolder)
{
mPackageFolder = new nsInstallFolder(aFolder, "");
return NS_OK;
}
PRInt32
nsInstall::StartInstall(const nsString& aUserPackageName, const nsString& aRegistryPackageName, const nsString& aVersion, PRInt32* aReturn)
{
if ( aUserPackageName.Length() == 0 )
{
// There must be some pretty name for the UI and the uninstall list
*aReturn = SaveError(INVALID_ARGUMENTS);
return NS_OK;
}
char szRegPackagePath[MAXREGPATHLEN];
char* szRegPackageName = aRegistryPackageName.ToNewCString();
if (szRegPackageName == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return nsInstall::OUT_OF_MEMORY;
}
*szRegPackagePath = '0';
*aReturn = nsInstall::SUCCESS;
ResetError();
mUserCancelled = PR_FALSE;
mUIName = aUserPackageName;
*aReturn = GetQualifiedPackageName( aRegistryPackageName, mRegistryPackageName );
if (*aReturn != nsInstall::SUCCESS)
{
return NS_OK;
}
if(REGERR_OK == VR_GetDefaultDirectory(szRegPackageName, MAXREGPATHLEN, szRegPackagePath))
{
mPackageFolder = new nsInstallFolder(szRegPackagePath, "");
}
else
{
mPackageFolder = nsnull;
}
if(szRegPackageName)
Recycle(szRegPackageName);
if (mVersionInfo != nsnull)
delete mVersionInfo;
mVersionInfo = new nsInstallVersion();
if (mVersionInfo == nsnull)
{
*aReturn = nsInstall::OUT_OF_MEMORY;
return SaveError(nsInstall::OUT_OF_MEMORY);
}
mVersionInfo->Init(aVersion);
mInstalledFiles = new nsVoidArray();
if (mInstalledFiles == nsnull)
{
*aReturn = nsInstall::OUT_OF_MEMORY;
return SaveError(nsInstall::OUT_OF_MEMORY);
}
if (mNotifier)
mNotifier->InstallStarted(mInstallURL.GetUnicode(), mUIName.GetUnicode());
mStartInstallCompleted = PR_TRUE;
return NS_OK;
}
PRInt32
nsInstall::Uninstall(const nsString& aRegistryPackageName, PRInt32* aReturn)
{
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
nsString qualifiedPackageName;
*aReturn = GetQualifiedPackageName( aRegistryPackageName, qualifiedPackageName );
if (*aReturn != SUCCESS)
{
return NS_OK;
}
nsInstallUninstall *ie = new nsInstallUninstall( this,
qualifiedPackageName,
&result );
if (ie == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (result == nsInstall::SUCCESS)
{
result = ScheduleForInstall( ie );
}
else
{
delete ie;
}
*aReturn = SaveError(result);
return NS_OK;
}
////////////////////////////////////////
void
nsInstall::AddPatch(nsHashKey *aKey, nsFileSpec* fileName)
{
if (mPatchList != nsnull)
{
mPatchList->Put(aKey, fileName);
}
}
void
nsInstall::GetPatch(nsHashKey *aKey, nsFileSpec** fileName)
{
if (!fileName)
return;
else
*fileName = nsnull;
if (mPatchList != nsnull)
{
*fileName = (nsFileSpec*) mPatchList->Get(aKey);
}
}
PRInt32
nsInstall::FileOpDirCreate(nsFileSpec& aTarget, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_DIR_CREATE, aTarget, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpDirGetParent(nsFileSpec& aTarget, nsFileSpec* aReturn)
{
// nsInstallFileOpItem ifop(this, aTarget, aReturn);
aTarget.GetParent(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpDirRemove(nsFileSpec& aTarget, PRInt32 aFlags, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_DIR_REMOVE, aTarget, aFlags, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpDirRename(nsFileSpec& aSrc, nsString& aTarget, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_DIR_RENAME, aSrc, aTarget, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileCopy(nsFileSpec& aSrc, nsFileSpec& aTarget, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_FILE_COPY, aSrc, aTarget, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileDelete(nsFileSpec& aTarget, PRInt32 aFlags, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_FILE_DELETE, aTarget, aFlags, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileExecute(nsFileSpec& aTarget, nsString& aParams, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_FILE_EXECUTE, aTarget, aParams, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileExists(nsFileSpec& aTarget, PRBool* aReturn)
{
*aReturn = aTarget.Exists();
return NS_OK;
}
PRInt32
nsInstall::FileOpFileGetNativeVersion(nsFileSpec& aTarget, nsString* aReturn)
{
return NS_OK;
}
PRInt32
nsInstall::FileOpFileGetDiskSpaceAvailable(nsFileSpec& aTarget, PRInt64* aReturn)
{
*aReturn = aTarget.GetDiskSpaceAvailable();
return NS_OK;
}
PRInt32
nsInstall::FileOpFileGetModDate(nsFileSpec& aTarget, nsFileSpec::TimeStamp* aReturn)
{
aTarget.GetModDate(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileGetSize(nsFileSpec& aTarget, PRUint32* aReturn)
{
*aReturn = aTarget.GetFileSize();
return NS_OK;
}
PRInt32
nsInstall::FileOpFileIsDirectory(nsFileSpec& aTarget, PRBool* aReturn)
{
*aReturn = aTarget.IsDirectory();
return NS_OK;
}
PRInt32
nsInstall::FileOpFileIsFile(nsFileSpec& aTarget, PRBool* aReturn)
{
*aReturn = aTarget.IsFile();
return NS_OK;
}
PRInt32
nsInstall::FileOpFileModDateChanged(nsFileSpec& aTarget, nsFileSpec::TimeStamp& aOldStamp, PRBool* aReturn)
{
*aReturn = aTarget.ModDateChanged(aOldStamp);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileMove(nsFileSpec& aSrc, nsFileSpec& aTarget, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_FILE_MOVE, aSrc, aTarget, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileRename(nsFileSpec& aSrc, nsString& aTarget, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_FILE_RENAME, aSrc, aTarget, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileWindowsShortcut(nsFileSpec& aTarget, nsFileSpec& aShortcutPath, nsString& aDescription, nsFileSpec& aWorkingPath, nsString& aParams, nsFileSpec& aIcon, PRInt32 aIconId, PRInt32* aReturn)
{
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_WIN_SHORTCUT, aTarget, aShortcutPath, aDescription, aWorkingPath, aParams, aIcon, aIconId, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
return NS_OK;
}
PRInt32
nsInstall::FileOpFileMacAlias(nsString& aSourcePath, nsString& aAliasPath, PRInt32* aReturn)
{
*aReturn = nsInstall::SUCCESS;
#ifdef XP_MAC
nsFileSpec nsfsSource(aSourcePath, PR_FALSE);
nsFileSpec nsfsAlias(aAliasPath, PR_TRUE);
nsInstallFileOpItem* ifop = new nsInstallFileOpItem(this, NS_FOP_MAC_ALIAS, nsfsSource, nsfsAlias, aReturn);
PRInt32 result = SanityCheck();
if (result != nsInstall::SUCCESS)
{
*aReturn = SaveError( result );
return NS_OK;
}
if (ifop == nsnull)
{
*aReturn = SaveError(nsInstall::OUT_OF_MEMORY);
return NS_OK;
}
if (*aReturn == nsInstall::SUCCESS)
{
*aReturn = ScheduleForInstall( ifop );
}
SaveError(*aReturn);
#endif
return NS_OK;
}
PRInt32
nsInstall::FileOpFileUnixLink(nsFileSpec& aTarget, PRInt32 aFlags, PRInt32* aReturn)
{
return NS_OK;
}
void
nsInstall::LogComment(nsString& aComment)
{
if(mNotifier)
mNotifier->LogComment(aComment.GetUnicode());
}
/////////////////////////////////////////////////////////////////////////
// Private Methods
/////////////////////////////////////////////////////////////////////////
/**
* ScheduleForInstall
* call this to put an InstallObject on the install queue
* Do not call installedFiles.addElement directly, because this routine also
* handles progress messages
*/
PRInt32
nsInstall::ScheduleForInstall(nsInstallObject* ob)
{
PRInt32 error = nsInstall::SUCCESS;
char *objString = ob->toString();
// flash current item
if (mNotifier)
mNotifier->ItemScheduled(nsAutoString(objString).GetUnicode());
// do any unpacking or other set-up
error = ob->Prepare();
if (error == nsInstall::SUCCESS)
{
// Add to installation list
mInstalledFiles->AppendElement( ob );
// turn on flags for creating the uninstall node and
// the package node for each InstallObject
if (ob->CanUninstall())
mUninstallPackage = PR_TRUE;
if (ob->RegisterPackageNode())
mRegisterPackage = PR_TRUE;
}
else if ( mNotifier )
{
// error in preparation step -- log it
char* errRsrc = GetResourcedString("ERROR");
if (errRsrc)
{
char* errprefix = PR_smprintf("%s (%d): ", errRsrc, error);
nsString errstr = errprefix;
errstr += objString;
mNotifier->LogComment( errstr.GetUnicode() );
PR_smprintf_free(errprefix);
nsCRT::free(errRsrc);
}
}
if (objString)
delete [] objString;
return error;
}
/**
* SanityCheck
*
* This routine checks if the packageName is null. It also checks the flag if the user cancels
* the install progress dialog is set and acccordingly aborts the install.
*/
PRInt32
nsInstall::SanityCheck(void)
{
if ( mInstalledFiles == nsnull || mStartInstallCompleted == PR_FALSE )
{
return INSTALL_NOT_STARTED;
}
if (mUserCancelled)
{
InternalAbort(USER_CANCELLED);
return USER_CANCELLED;
}
return 0;
}
/**
* GetQualifiedPackageName
*
* This routine converts a package-relative component registry name
* into a full name that can be used in calls to the version registry.
*/
PRInt32
nsInstall::GetQualifiedPackageName( const nsString& name, nsString& qualifiedName )
{
nsString startOfName;
name.Left(startOfName, 7);
if ( startOfName.Equals( "=USER=/") )
{
CurrentUserNode(qualifiedName);
qualifiedName += name;
}
else
{
qualifiedName = name;
}
if (BadRegName(qualifiedName))
{
return BAD_PACKAGE_NAME;
}
/* Check to see if the PackageName ends in a '/'. If it does nuke it. */
if (qualifiedName.Last() == '/')
{
PRInt32 index = qualifiedName.Length();
qualifiedName.Truncate(--index);
}
return SUCCESS;
}
/**
* GetQualifiedRegName
*
* This routine converts a package-relative component registry name
* into a full name that can be used in calls to the version registry.
*/
PRInt32
nsInstall::GetQualifiedRegName(const nsString& name, nsString& qualifiedRegName )
{
nsString startOfName;
name.Left(startOfName, 7);
nsString usr ();
if ( startOfName.Equals("=COMM=/") || startOfName.Equals("=USER=/"))
{
qualifiedRegName = name;
qualifiedRegName.Cut( 0, 7 );
}
else if ( name.CharAt(0) != '/' )
{
if (mRegistryPackageName != "")
{
qualifiedRegName = mRegistryPackageName;
qualifiedRegName += "/";
qualifiedRegName += name;
}
else
{
qualifiedRegName = name;
}
}
else
{
qualifiedRegName = name;
}
if (BadRegName(qualifiedRegName))
{
return BAD_PACKAGE_NAME;
}
return SUCCESS;
}
static NS_DEFINE_IID(kPrefsIID, NS_IPREF_IID);
static NS_DEFINE_IID(kPrefsCID, NS_PREF_CID);
void
nsInstall::CurrentUserNode(nsString& userRegNode)
{
char *profname;
nsIPref * prefs;
nsresult rv = nsServiceManager::GetService(kPrefsCID,
kPrefsIID,
(nsISupports**) &prefs);
if ( NS_SUCCEEDED(rv) )
{
rv = prefs->CopyCharPref("profile.name", &profname);
if ( NS_FAILED(rv) )
{
PR_FREEIF(profname); // Allocated by PREF_CopyCharPref
profname = NULL;
}
NS_RELEASE(prefs);
}
else
{
profname = NULL;
}
userRegNode = "/Netscape/Users/";
if (profname != nsnull)
{
userRegNode += nsString(profname);
userRegNode += "/";
PR_FREEIF(profname);
}
}
// catch obvious registry name errors proactively
// rather than returning some cryptic libreg error
PRBool
nsInstall::BadRegName(const nsString& regName)
{
if ((regName.First() == ' ' ) || (regName.Last() == ' ' ))
return PR_TRUE;
if ( regName.Find("//") != -1 )
return PR_TRUE;
if ( regName.Find(" /") != -1 )
return PR_TRUE;
if ( regName.Find("/ ") != -1 )
return PR_TRUE;
if ( regName.Find("=") != -1 )
return PR_TRUE;
return PR_FALSE;
}
PRInt32
nsInstall::SaveError(PRInt32 errcode)
{
if ( errcode != nsInstall::SUCCESS )
mLastError = errcode;
return errcode;
}
/*
* CleanUp
* call it when done with the install
*
*/
void
nsInstall::CleanUp(void)
{
nsInstallObject* ie;
if ( mInstalledFiles != NULL )
{
for (PRInt32 i=0; i < mInstalledFiles->Count(); i++)
{
ie = (nsInstallObject*)mInstalledFiles->ElementAt(i);
if (ie)
delete (ie);
}
mInstalledFiles->Clear();
delete (mInstalledFiles);
mInstalledFiles = nsnull;
}
if (mPatchList != nsnull)
{
mPatchList->Reset();
delete mPatchList;
mPatchList = nsnull;
}
if (mPackageFolder != nsnull)
{
delete (mPackageFolder);
mPackageFolder = nsnull;
}
mRegistryPackageName = ""; // used to see if StartInstall() has been called
mStartInstallCompleted = PR_FALSE;
}
void
nsInstall::GetJarFileLocation(nsString& aFile)
{
aFile = mJarFileLocation.GetCString();
}
void
nsInstall::SetJarFileLocation(const nsFileSpec& aFile)
{
mJarFileLocation = aFile;
}
void
nsInstall::GetInstallArguments(nsString& args)
{
args = mInstallArguments;
}
void
nsInstall::SetInstallArguments(const nsString& args)
{
mInstallArguments = args;
}
void nsInstall::GetInstallURL(nsString& url) { url = mInstallURL; }
void nsInstall::SetInstallURL(const nsString& url) { mInstallURL = url; }
PRInt32
nsInstall::Alert(nsString& string)
{
nsresult res;
NS_WITH_PROXIED_SERVICE(nsIPrompt, dialog, kNetSupportDialogCID, NS_UI_THREAD_EVENTQ, &res);
if (NS_FAILED(res))
return res;
return dialog->Alert(string.GetUnicode());
}
PRInt32
nsInstall::Confirm(nsString& string, PRBool* aReturn)
{
*aReturn = PR_FALSE; /* default value */
nsresult res;
NS_WITH_PROXIED_SERVICE(nsIPrompt, dialog, kNetSupportDialogCID, NS_UI_THREAD_EVENTQ, &res);
if (NS_FAILED(res))
return res;
return dialog->Confirm(string.GetUnicode(), aReturn);
}
// aJarFile - This is the filepath within the jar file.
// aSuggestedName - This is the name that we should try to extract to. If we can, we will create a new temporary file.
// aRealName - This is the name that we did extract to. This will be allocated by use and should be disposed by the caller.
PRInt32
nsInstall::ExtractFileFromJar(const nsString& aJarfile, nsFileSpec* aSuggestedName, nsFileSpec** aRealName)
{
PRInt32 extpos = 0;
nsFileSpec *extractHereSpec;
if (aSuggestedName == nsnull)
{
nsSpecialSystemDirectory tempFile(nsSpecialSystemDirectory::OS_TemporaryDirectory);
nsString tempFileName = "xpinstall";
// Get the extension of the file in the JAR
extpos = aJarfile.RFindChar('.');
if (extpos != -1)
{
// We found the extension; add it to the tempFileName string
nsString extension;
aJarfile.Right(extension, (aJarfile.Length() - extpos) );
tempFileName += extension;
}
tempFile += tempFileName;
// Create a temporary file to extract to
tempFile.MakeUnique();
extractHereSpec = new nsFileSpec(tempFile);
if (extractHereSpec == nsnull)
return nsInstall::OUT_OF_MEMORY;
}
else
{
// extract to the final destination.
extractHereSpec = new nsFileSpec(*aSuggestedName);
if (extractHereSpec == nsnull)
return nsInstall::OUT_OF_MEMORY;
extractHereSpec->MakeUnique();
}
// We will overwrite what is in the way. is this something that we want to do?
extractHereSpec->Delete(PR_FALSE);
nsresult rv;
nsCOMPtr<nsILocalFile> file;
rv = NS_NewLocalFile(*extractHereSpec, getter_AddRefs(file));
if (NS_SUCCEEDED(rv))
rv = mJarFileData->Extract(nsAutoCString(aJarfile), file);
if (NS_FAILED(rv))
{
if (extractHereSpec != nsnull)
delete extractHereSpec;
return EXTRACTION_FAILED;
}
#ifdef XP_MAC
FSSpec finalSpec, extractedSpec = extractHereSpec->GetFSSpec();
if ( nsAppleSingleDecoder::IsAppleSingleFile(&extractedSpec) )
{
nsAppleSingleDecoder *asd = new nsAppleSingleDecoder(&extractedSpec, &finalSpec);
OSErr decodeErr = fnfErr;
if (asd)
decodeErr = asd->Decode();
if (decodeErr != noErr)
{
if (extractHereSpec)
delete extractHereSpec;
if (asd)
delete asd;
return EXTRACTION_FAILED;
}
if ( !(extractedSpec.vRefNum == finalSpec.vRefNum) ||
!(extractedSpec.parID == finalSpec.parID) ||
!(nsAppleSingleDecoder::PLstrcmp(extractedSpec.name, finalSpec.name)) )
{
// delete the unique extracted file that got renamed in AS decoding
FSpDelete(&extractedSpec);
// "real name" in AppleSingle entry may cause file rename
*extractHereSpec = finalSpec;
}
}
#endif
*aRealName = extractHereSpec;
return nsInstall::SUCCESS;
}
/**
* GetResourcedString
*
* Obtains the string resource for actions and messages that are displayed
* in user interface confirmation and progress dialogs.
*
* @param aResName - property name/identifier of string resource
* @return rscdStr - corresponding resourced value in the string bundle
*/
char*
nsInstall::GetResourcedString(const nsString& aResName)
{
nsString rscdStr = "";
PRBool bStrBdlSuccess = PR_FALSE;
if (mStringBundle)
{
const PRUnichar *ucResName = aResName.GetUnicode();
PRUnichar *ucRscdStr = nsnull;
nsresult rv = mStringBundle->GetStringFromName(ucResName, &ucRscdStr);
if (NS_SUCCEEDED(rv))
{
bStrBdlSuccess = PR_TRUE;
rscdStr = ucRscdStr;
}
}
/*
** We don't have a string bundle, the necessary libs, or something went wrong
** so we failover to hardcoded english strings so we log something rather
** than nothing due to failure above: always the case for the Install Wizards.
*/
if (!bStrBdlSuccess)
{
char *cResName = aResName.ToNewCString();
rscdStr = nsInstallResources::GetDefaultVal(cResName);
if (cResName)
Recycle(cResName);
}
return rscdStr.ToNewCString();
}
PRInt32
nsInstall::ExtractDirEntries(const nsString& directory, nsVoidArray *paths)
{
char *buf;
nsISimpleEnumerator *jarEnum = nsnull;
nsIZipEntry *currZipEntry = nsnull;
if ( paths )
{
nsString pattern(directory);
pattern += "/*";
PRInt32 prefix_length = directory.Length()+1; // account for slash
nsresult rv = mJarFileData->FindEntries( nsAutoCString(pattern), &jarEnum );
if (NS_FAILED(rv) || !jarEnum)
goto handle_err;
PRBool bMore;
rv = jarEnum->HasMoreElements(&bMore);
while (bMore && NS_SUCCEEDED(rv))
{
rv = jarEnum->GetNext( (nsISupports**) &currZipEntry );
if (currZipEntry)
{
// expensive 'buf' callee malloc per iteration!
rv = currZipEntry->GetName(&buf);
if (NS_FAILED(rv))
goto handle_err;
if (buf)
{
PRInt32 namelen = PL_strlen(buf);
NS_ASSERTION( prefix_length <= namelen, "Match must be longer than pattern!" );
if ( buf[namelen-1] != '/' )
{
// XXX manipulation should be in caller
paths->AppendElement( new nsString(buf+prefix_length) );
}
PR_FREEIF( buf );
}
NS_IF_RELEASE(currZipEntry);
}
rv = jarEnum->HasMoreElements(&bMore);
}
}
NS_IF_RELEASE(jarEnum);
return SUCCESS;
handle_err:
NS_IF_RELEASE(jarEnum);
NS_IF_RELEASE(currZipEntry);
return EXTRACTION_FAILED;
}
void
nsInstall::DeleteVector(nsVoidArray* vector)
{
if (vector != nsnull)
{
for (PRInt32 i=0; i < vector->Count(); i++)
{
nsString* element = (nsString*)vector->ElementAt(i);
if (element != nsnull)
delete element;
}
vector->Clear();
delete (vector);
vector = nsnull;
}
}