/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (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. * * Contributors: * Daniel Veditz * Douglas Turner */ #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" #ifdef NECKO #include "nsNeckoUtil.h" #endif #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 #ifdef XP_PC #define FILESEP '\\' #elif defined(XP_MAC) #define FILESEP ':' #else #define FILESEP '/' #endif static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); #ifdef NECKO #else static NS_DEFINE_IID(kNetServiceCID, NS_NETSERVICE_CID); static NS_DEFINE_IID(kINetServiceIID, NS_INETSERVICE_IID); #endif 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" 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) {} nsInstallInfo::~nsInstallInfo() { } void nsInstallInfo::GetLocalFile(char **aPath) { if (mFile) mFile->GetNSPRPath(aPath); else *aPath = 0; } static NS_DEFINE_IID(kISoftwareUpdateIID, NS_ISOFTWAREUPDATE_IID); static NS_DEFINE_IID(kSoftwareUpdateCID, NS_SoftwareUpdate_CID); static NS_DEFINE_IID(kIJARIID, NS_IJAR_IID); static NS_DEFINE_IID(kJARCID, NS_JAR_CID); nsInstall::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. mUninstallPackage = PR_FALSE; mRegisterPackage = PR_FALSE; mStatusSent = PR_FALSE; mJarFileLocation = ""; mInstallArguments = ""; // mJarFileData is an opaque handle to the jarfile. nsresult rv = nsComponentManager::CreateInstance(kJARCID, nsnull, kIJARIID, (void**) &mJarFileData); nsISoftwareUpdate *su; 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, nsIStringBundleService::GetIID(), (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; } PRInt32 nsInstall::SetScriptObject(void *aScriptObject) { mScriptObject = (JSObject*) aScriptObject; return NS_OK; } #ifdef _WINDOWS nsInstall::SaveWinRegPrototype(void *aScriptObject) { mWinRegObject = (JSObject*) aScriptObject; return NS_OK; } 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=0; i < mInstalledFiles->Count(); i++) { ie = (nsInstallObject *)mInstalledFiles->ElementAt(i); if (ie) ie->Abort(); } } CleanUp(); } PRInt32 nsInstall::AbortInstall() { InternalAbort(ABORT_INSTALL); return NS_OK; } PRInt32 nsInstall::AddDirectory(const nsString& aRegName, const nsString& aVersion, const nsString& aJarSource, const nsString& aFolder, const nsString& aSubdir, PRBool aForceMode, PRInt32* aReturn) { nsInstallFile* ie = nsnull; PRInt32 result; if ( aJarSource.Equals("") || aFolder.Equals("") ) { *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::FILE_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, const nsString& 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, const nsString& 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, "", "", PR_FALSE, aReturn); } PRInt32 nsInstall::AddSubcomponent(const nsString& aRegName, const nsString& aVersion, const nsString& aJarSource, const nsString& 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.Equals("") ) { *aReturn = SaveError( nsInstall::INVALID_ARGUMENTS ); 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, const nsString& 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, const nsString& aFolder, const nsString& aTargetName, PRInt32* aReturn) { 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.Equals("")) { *aReturn = SaveError( nsInstall::PACKAGE_FOLDER_NOT_SET ); 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(const nsString& 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::FILE_DOES_NOT_EXIST) { result = nsInstall::SUCCESS; } *aReturn = SaveError(result); return NS_OK; } PRInt32 nsInstall::DiskSpaceAvailable(const nsString& aFolder, PRInt64* aReturn) { 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; 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; #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, nsString** aFolder) { long err; char* componentCString; char dir[MAXREGPATHLEN]; nsFileSpec nsfsDir; *aFolder = 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') { nsfsDir = dir; if(aSubdirectory != "") { nsfsDir += aSubdirectory; } *aFolder = new nsString(nsfsDir.GetNativePathCString()); } if (componentCString) Recycle(componentCString); return NS_OK; } PRInt32 nsInstall::GetComponentFolder(const nsString& aComponentName, nsString** aFolder) { return GetComponentFolder(aComponentName, "", aFolder); } PRInt32 nsInstall::GetFolder(const nsString& targetFolder, const nsString& aSubdirectory, nsString** aFolder) { nsInstallFolder* spec = nsnull; *aFolder = nsnull; spec = new nsInstallFolder(targetFolder, aSubdirectory); if (spec != nsnull) { nsString dirString; spec->GetDirectoryPath(dirString); *aFolder = new nsString(dirString); } return NS_OK; } PRInt32 nsInstall::GetFolder(const nsString& targetFolder, nsString** aFolder) { return GetFolder(targetFolder, "", aFolder); } 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; #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; #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) { nsresult ret; nsFileSpec* resFile; nsFileURL* resFileURL = nsnull; nsIURI *url = nsnull; nsILocale* locale = nsnull; nsIStringBundleService* service = nsnull; #ifndef NECKO nsINetService* pNetService = nsnull; #endif 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; #ifndef NECKO ret = nsServiceManager::GetService(kNetServiceCID, kINetServiceIID, (nsISupports**) &pNetService); if (NS_FAILED(ret)) goto cleanup; #endif 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 ); #ifdef NECKO ret = NS_NewURI(&url, resFileURL->GetURLString()); #else ret = pNetService->CreateURL(&url, nsString( resFileURL->GetURLString()), nsnull, nsnull, nsnull); #endif if (resFileURL) delete resFileURL; if (NS_FAILED(ret)) goto cleanup; // get the string bundle using the extracted properties file #if 1 { #ifndef NECKO const char* spec = nsnull; #else char* spec = nsnull; #endif /* NECKO */ ret = url->GetSpec(&spec); if (NS_FAILED(ret)) { printf("cannot get url spec\n"); nsServiceManager::ReleaseService(kStringBundleServiceCID, service); #ifdef NECKO nsCRT::free(spec); #endif /* NECKO */ return ret; } ret = service->CreateBundle(spec, locale, &bundle); #ifdef NECKO nsCRT::free(spec); #endif /* NECKO */ } #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 ); #ifndef NECKO NS_IF_RELEASE( pNetService ); #endif // 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, const nsString& 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; } 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, const nsString& 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(const nsString& aFolder) { mPackageFolder = 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 PR_FALSE; } *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 = szRegPackagePath; } else { mPackageFolder.SetString(""); } if(szRegPackageName) Recycle(szRegPackageName); if (mVersionInfo != nsnull) delete mVersionInfo; mVersionInfo = new nsInstallVersion(); if (mVersionInfo == nsnull) { *aReturn = nsInstall::OUT_OF_MEMORY; return nsInstall::OUT_OF_MEMORY; } mVersionInfo->Init(aVersion); mInstalledFiles = new nsVoidArray(); mPatchList = new nsHashtable(); if (mInstalledFiles == nsnull || mPatchList == nsnull) { *aReturn = nsInstall::OUT_OF_MEMORY; return nsInstall::OUT_OF_MEMORY; } /* this function should also check security!!! */ *aReturn = OpenJARFile(); if (*aReturn != nsInstall::SUCCESS) // XXX must use NS_SUCCEEDED macro! { /* if we can not continue with the javascript return a JAR error*/ return -1; /* FIX: need real error code */ } SaveError(*aReturn); if (mNotifier) mNotifier->InstallStarted(mInstallURL.GetUnicode(), mUIName.GetUnicode()); 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 (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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ); } if (*aReturn == nsInstall::FILE_DOES_NOT_EXIST) { *aReturn = nsInstall::SUCCESS; } 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 ) { 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; } PRBool DeleteEntry(nsHashKey *aKey, void *aData, void *closure) { nsFileSpec* data = (nsFileSpec *)aData; delete data; data = nsnull; return PR_TRUE; } /* * CleanUp * call it when done with the install * */ void nsInstall::CleanUp(void) { nsInstallObject* ie; CloseJARFile(); 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) { mPatchList->Enumerate(DeleteEntry, nsnull); mPatchList->Reset(); delete mPatchList; } mRegistryPackageName = ""; // used to see if StartInstall() has been called } void nsInstall::GetJarFileLocation(nsString& aFile) { aFile = mJarFileLocation; } void nsInstall::SetJarFileLocation(const nsString& 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, nsnull, &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, nsnull, &res); if (NS_FAILED(res)) return res; return dialog->Confirm(string.GetUnicode(), aReturn); } PRInt32 nsInstall::OpenJARFile(void) { PRInt32 result; nsresult rv = mJarFileData->Open( nsAutoCString(mJarFileLocation), &result ); if (NS_FAILED(rv)) return UNEXPECTED_ERROR; return result; } void nsInstall::CloseJARFile(void) { NS_IF_RELEASE(mJarFileData); } // 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 result; nsFileSpec *extractHereSpec; if (aSuggestedName == nsnull) { nsSpecialSystemDirectory tempFile(nsSpecialSystemDirectory::OS_TemporaryDirectory); nsString tempFileName = "xpinstall"; // Get the extension of the file in the JAR result = aJarfile.RFindChar('.'); if (result != -1) { // We found the extension; add it to the tempFileName string nsString extension; aJarfile.Right(extension, (aJarfile.Length() - result) ); 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 = mJarFileData->Extract( nsAutoCString(aJarfile), nsNSPRPath( *extractHereSpec ), &result ); if (NS_FAILED(rv)) { if (extractHereSpec != nsnull) delete extractHereSpec; return EXTRACTION_FAILED; } if (result == 0) { #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; } else { if (extractHereSpec != nsnull) delete extractHereSpec; } return result; } /** * 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; nsIJARItem *currJARItem = nsnull; if ( paths ) { nsString pattern(directory); pattern += "/*"; PRInt32 prefix_length = directory.Length()+1; // account for slash nsresult rv = mJarFileData->Find( 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**) &currJARItem ); if (currJARItem) { // expensive 'buf' callee malloc per iteration! rv = currJARItem->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(currJARItem); } rv = jarEnum->HasMoreElements(&bMore); } } NS_IF_RELEASE(jarEnum); return SUCCESS; handle_err: NS_IF_RELEASE(jarEnum); NS_IF_RELEASE(currJARItem); 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; } }