/* -*- Mode: C++; tab-width: 2; 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. * * 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. */ #include "nscore.h" #include "nsIFactory.h" #include "nsISupports.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsCOMPtr.h" #include "nspr.h" #include "nsVector.h" #include "VerReg.h" #include "nsSpecialSystemDirectory.h" #include "nsInstall.h" #include "nsSoftwareUpdateIIDs.h" #include "nsSoftwareUpdate.h" #include "nsSoftwareUpdateRun.h" #include "nsInstallTrigger.h" #include "nsInstallVersion.h" #include "ScheduledTasks.h" #include "nsTopProgressNotifier.h" #include "nsLoggingProgressNotifier.h" #include "nsInstallProgressDialog.h" #include "nsIAppShellComponent.h" #include "nsIRegistry.h" /* For Javascript Namespace Access */ #include "nsDOMCID.h" #include "nsIServiceManager.h" #include "nsINameSpaceManager.h" #include "nsIScriptObjectOwner.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptNameSetRegistry.h" #include "nsIScriptNameSpaceManager.h" #include "nsIScriptExternalNameSet.h" #include "nsIEventQueueService.h" #include "nsProxyObjectManager.h" //////////////////////////////////////////////////////////////////////////////// // Globals //////////////////////////////////////////////////////////////////////////////// static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID); static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID); static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); static NS_DEFINE_IID(kIScriptNameSetRegistryIID, NS_ISCRIPTNAMESETREGISTRY_IID); static NS_DEFINE_IID(kCScriptNameSetRegistryCID, NS_SCRIPT_NAMESET_REGISTRY_CID); static NS_DEFINE_IID(kIScriptExternalNameSetIID, NS_ISCRIPTEXTERNALNAMESET_IID); static NS_DEFINE_IID(kISoftwareUpdate_IID, NS_ISOFTWAREUPDATE_IID); static NS_DEFINE_IID(kSoftwareUpdate_CID, NS_SoftwareUpdate_CID); static NS_DEFINE_IID(kIInstallTrigger_IID, NS_IDOMINSTALLTRIGGERGLOBAL_IID); static NS_DEFINE_IID(kInstallTrigger_CID, NS_SoftwareUpdateInstallTrigger_CID); static NS_DEFINE_IID(kIInstallVersion_IID, NS_IDOMINSTALLVERSION_IID); static NS_DEFINE_IID(kInstallVersion_CID, NS_SoftwareUpdateInstallVersion_CID); static NS_DEFINE_IID(kProxyObjectManagerIID, NS_IPROXYEVENT_MANAGER_IID); static NS_DEFINE_IID(kEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); nsSoftwareUpdate::nsSoftwareUpdate() { #ifdef NS_DEBUG printf("XPInstall Component created\n"); #endif NS_INIT_ISUPPORTS(); /***************************************/ /* Create us a queue */ /***************************************/ mInstalling = nsnull; mJarInstallQueue = new nsVector(); /***************************************/ /* Add us to the Javascript Name Space */ /***************************************/ new nsSoftwareUpdateNameSet(); /***************************************/ /* Register us with NetLib */ /***************************************/ // FIX /***************************************/ /* Startup the Version Registry */ /***************************************/ NR_StartupRegistry(); /* startup the registry; if already started, this will essentially be a noop */ nsSpecialSystemDirectory appDir(nsSpecialSystemDirectory::OS_CurrentProcessDirectory); VR_SetRegDirectory( appDir.GetNativePathCString() ); /***************************************/ /* Stupid Hack to test js env*/ /***************************************/ // FIX: HACK HACK HACK! #if 0 nsSpecialSystemDirectory jarFile(nsSpecialSystemDirectory::OS_TemporaryDirectory); jarFile += "test.jar"; if (jarFile.Exists()) { InstallJar(nsString(nsFileURL(jarFile)), "", ""); } #endif /***************************************/ /* Perform Scheduled Tasks */ /***************************************/ PR_CreateThread(PR_USER_THREAD, PerformScheduledTasks, nsnull, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); /***************************************/ /* Create a top level observer */ /***************************************/ mTopLevelObserver = new nsTopProgressNotifier(); nsLoggingProgressNotifier *logger = new nsLoggingProgressNotifier(); RegisterNotifier(logger); nsIProxyObjectManager *manager; nsInstallProgressDialog *dialog = new nsInstallProgressDialog(); nsInstallProgressDialog *proxy; nsISupports *dialogBase; nsresult rv = dialog->QueryInterface(kISupportsIID, (void**)&dialogBase); if (NS_SUCCEEDED(rv)) { rv = nsServiceManager::GetService( NS_XPCOMPROXY_PROGID, kProxyObjectManagerIID, (nsISupports **)&manager); if (NS_SUCCEEDED(rv)) { // I am assuming that the thread that starts us up is the UI thread. this will/may break // I need to make a generic way of getting at the UI event queue. nsIEventQueueService *eventQService; rv = nsServiceManager::GetService(NS_EVENTQUEUESERVICE_PROGID, kEventQueueServiceIID, (nsISupports **)&eventQService); if (NS_SUCCEEDED(rv)) { nsIEventQueue *eventQ; eventQService->GetThreadEventQueue(PR_GetCurrentThread(), &eventQ); rv = manager->GetProxyObject(eventQ, nsIXPInstallProgress::GetIID(), dialogBase, PROXY_SYNC, (void**)&proxy); if (NS_SUCCEEDED(rv)) { RegisterNotifier(proxy); } } } } if (dialog) dialog->Release(); } nsSoftwareUpdate::~nsSoftwareUpdate() { #ifdef NS_DEBUG printf("*** XPInstall Component destroyed\n"); #endif if (mJarInstallQueue != nsnull) { PRUint32 i=0; for (; i < mJarInstallQueue->GetSize(); i++) { nsInstallInfo* element = (nsInstallInfo*)mJarInstallQueue->Get(i); //FIX: need to add to registry.... delete element; } mJarInstallQueue->RemoveAll(); delete (mJarInstallQueue); mJarInstallQueue = nsnull; } NR_ShutdownRegistry(); } NS_IMPL_ADDREF( nsSoftwareUpdate ); NS_IMPL_RELEASE( nsSoftwareUpdate ); NS_IMETHODIMP nsSoftwareUpdate::QueryInterface( REFNSIID anIID, void **anInstancePtr ) { nsresult rv = NS_OK; /* Check for place to return result. */ if ( !anInstancePtr ) { rv = NS_ERROR_NULL_POINTER; } else { /* Initialize result. */ *anInstancePtr = 0; /* Check for IIDs we support and cast this appropriately. */ if ( anIID.Equals( nsISoftwareUpdate::GetIID() ) ) { *anInstancePtr = (void*) ( (nsISoftwareUpdate*)this ); NS_ADDREF_THIS(); } else if ( anIID.Equals( nsIAppShellComponent::GetIID() ) ) { *anInstancePtr = (void*) ( (nsIAppShellComponent*)this ); NS_ADDREF_THIS(); } else if ( anIID.Equals( kISupportsIID ) ) { *anInstancePtr = (void*) ( (nsISupports*) (nsISoftwareUpdate*) this ); NS_ADDREF_THIS(); } else { /* Not an interface we support. */\ rv = NS_NOINTERFACE; } } return rv; } NS_IMETHODIMP nsSoftwareUpdate::Initialize( nsIAppShellService *anAppShell, nsICmdLineService *aCmdLineService ) { nsresult rv; rv = nsServiceManager::RegisterService( NS_IXPINSTALLCOMPONENT_PROGID, ( (nsISupports*) (nsISoftwareUpdate*) this ) ); return rv; } NS_IMETHODIMP nsSoftwareUpdate::Shutdown() { nsresult rv; rv = nsServiceManager::ReleaseService( NS_IXPINSTALLCOMPONENT_PROGID, ( (nsISupports*) (nsISoftwareUpdate*) this ) ); return rv; } NS_IMETHODIMP nsSoftwareUpdate::RegisterNotifier(nsIXPInstallProgress *notifier) { // we are going to ignore the returned ID and enforce that once you // register a notifier, you can not remove it. This should at some // point be fixed. (void) mTopLevelObserver->RegisterNotifier(notifier); return NS_OK; } NS_IMETHODIMP nsSoftwareUpdate::GetTopLevelNotifier(nsIXPInstallProgress **notifier) { *notifier = mTopLevelObserver; return NS_OK; } NS_IMETHODIMP nsSoftwareUpdate::InstallJar( const nsString& fromURL, const nsString& localFile, long flags) { nsInstallInfo *installInfo = new nsInstallInfo(fromURL, localFile, flags); mJarInstallQueue->Add( installInfo ); RunNextInstall(); return NS_OK; } NS_IMETHODIMP nsSoftwareUpdate::InstallPending(void) { if (mInstalling || mJarInstallQueue->GetSize() > 0) { return 1; } else { return 0; } } NS_IMETHODIMP nsSoftwareUpdate::InstallJarCallBack() { nsInstallInfo *nextInstall = (nsInstallInfo*)mJarInstallQueue->Get(0); if (nextInstall != nsnull) delete nextInstall; mJarInstallQueue->Remove(0); mInstalling = PR_FALSE; return RunNextInstall(); } nsresult nsSoftwareUpdate::RunNextInstall() { if (mInstalling == PR_TRUE) return NS_OK; mInstalling = PR_TRUE; // check to see if there is anything in our queue if (mJarInstallQueue->GetSize() <= 0) { mInstalling = PR_FALSE; return NS_OK; } nsInstallInfo *nextInstall = (nsInstallInfo*)mJarInstallQueue->Get(0); if (nextInstall->IsMultipleTrigger() == PR_FALSE) { RunInstall( nextInstall ); } else { ; // should we do something different?! } return NS_OK; } ///////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////// static PRInt32 gSoftwareUpdateLock = 0; nsSoftwareUpdateFactory::nsSoftwareUpdateFactory(void) { NS_INIT_ISUPPORTS(); } nsSoftwareUpdateFactory::~nsSoftwareUpdateFactory(void) { } NS_IMPL_ISUPPORTS(nsSoftwareUpdateFactory,kIFactoryIID) NS_IMETHODIMP nsSoftwareUpdateFactory::CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult) { if (aResult == NULL) { return NS_ERROR_NULL_POINTER; } *aResult = NULL; nsSoftwareUpdate *inst = new nsSoftwareUpdate(); if (inst == NULL) return NS_ERROR_OUT_OF_MEMORY; nsresult result = inst->QueryInterface(aIID, aResult); if (NS_FAILED(result)) { *aResult = NULL; } NS_ADDREF(inst); // Are we sure that we need to addref??? return result; } NS_IMETHODIMP nsSoftwareUpdateFactory::LockFactory(PRBool aLock) { if (aLock) PR_AtomicIncrement(&gSoftwareUpdateLock); else PR_AtomicDecrement(&gSoftwareUpdateLock); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// // nsSoftwareUpdateNameSet //////////////////////////////////////////////////////////////////////////////// nsSoftwareUpdateNameSet::nsSoftwareUpdateNameSet() { NS_INIT_REFCNT(); nsIScriptNameSetRegistry *scriptNameSet; nsresult result = nsServiceManager::GetService(kCScriptNameSetRegistryCID, kIScriptNameSetRegistryIID, (nsISupports **)&scriptNameSet); if (NS_SUCCEEDED(result)) { scriptNameSet->AddExternalNameSet(this); } } nsSoftwareUpdateNameSet::~nsSoftwareUpdateNameSet() { } NS_IMPL_ISUPPORTS(nsSoftwareUpdateNameSet, kIScriptExternalNameSetIID); NS_IMETHODIMP nsSoftwareUpdateNameSet::InitializeClasses(nsIScriptContext* aScriptContext) { nsresult result = NS_OK; result = NS_InitInstallVersionClass(aScriptContext, nsnull); if (NS_FAILED(result)) return result; result = NS_InitInstallTriggerGlobalClass(aScriptContext, nsnull); return result; } NS_IMETHODIMP nsSoftwareUpdateNameSet::AddNameSet(nsIScriptContext* aScriptContext) { nsresult result = NS_OK; nsIScriptNameSpaceManager* manager; result = aScriptContext->GetNameSpaceManager(&manager); if (NS_SUCCEEDED(result)) { result = manager->RegisterGlobalName("InstallVersion", kInstallVersion_CID, PR_TRUE); if (NS_FAILED(result)) return result; result = manager->RegisterGlobalName("InstallTrigger", kInstallTrigger_CID, PR_FALSE); } if (manager != nsnull) NS_RELEASE(manager); return result; } //////////////////////////////////////////////////////////////////////////////// // DLL Entry Points: //////////////////////////////////////////////////////////////////////////////// extern "C" NS_EXPORT PRBool NSCanUnload(nsISupports* aServMgr) { return PR_FALSE; } extern "C" NS_EXPORT nsresult NSRegisterSelf(nsISupports* aServMgr, const char *path) { nsresult rv; nsCOMPtr servMgr(do_QueryInterface(aServMgr, &rv)); if (NS_FAILED(rv)) return rv; nsIComponentManager* compMgr; rv = servMgr->GetService(kComponentManagerCID, nsIComponentManager::GetIID(), (nsISupports**)&compMgr); if (NS_FAILED(rv)) return rv; #ifdef NS_DEBUG printf("*** XPInstall is being registered\n"); #endif rv = compMgr->RegisterComponent( kSoftwareUpdate_CID, NS_IXPINSTALLCOMPONENT_CLASSNAME, NS_IXPINSTALLCOMPONENT_PROGID, path, PR_TRUE, PR_TRUE ); if (NS_FAILED(rv)) goto done; nsIRegistry *registry; rv = servMgr->GetService( NS_REGISTRY_PROGID, nsIRegistry::GetIID(), (nsISupports**)®istry ); if ( NS_SUCCEEDED( rv ) ) { registry->Open(); char buffer[256]; char *cid = nsSoftwareUpdate::GetCID().ToString(); PR_snprintf( buffer, sizeof buffer, "%s/%s", NS_IAPPSHELLCOMPONENT_KEY, cid ? cid : "unknown" ); delete [] cid; nsIRegistry::Key key; rv = registry->AddSubtree( nsIRegistry::Common, buffer, &key ); servMgr->ReleaseService( NS_REGISTRY_PROGID, registry ); } rv = compMgr->RegisterComponent(kInstallTrigger_CID, NULL, NULL, path, PR_TRUE, PR_TRUE); if (NS_FAILED(rv)) goto done; rv = compMgr->RegisterComponent(kInstallVersion_CID, NULL, NULL, path, PR_TRUE, PR_TRUE); done: (void)servMgr->ReleaseService(kComponentManagerCID, compMgr); return rv; } extern "C" NS_EXPORT nsresult NSUnregisterSelf(nsISupports* aServMgr, const char *path) { nsresult rv; nsCOMPtr servMgr(do_QueryInterface(aServMgr, &rv)); if (NS_FAILED(rv)) return rv; nsIComponentManager* compMgr; rv = servMgr->GetService(kComponentManagerCID, nsIComponentManager::GetIID(), (nsISupports**)&compMgr); if (NS_FAILED(rv)) return rv; #ifdef NS_DEBUG printf("*** XPInstall is being unregistered\n"); #endif rv = compMgr->UnregisterComponent(kSoftwareUpdate_CID, path); if (NS_FAILED(rv)) goto done; rv = compMgr->UnregisterComponent(kInstallTrigger_CID, path); if (NS_FAILED(rv)) goto done; rv = compMgr->UnregisterComponent(kInstallVersion_CID, path); done: (void)servMgr->ReleaseService(kComponentManagerCID, compMgr); return rv; } extern "C" NS_EXPORT nsresult NSGetFactory(nsISupports* serviceMgr, const nsCID &aClass, const char *aClassName, const char *aProgID, nsIFactory **aFactory) { if (aFactory == NULL) { return NS_ERROR_NULL_POINTER; } *aFactory = NULL; nsISupports *inst; if (aClass.Equals(kInstallTrigger_CID) ) { inst = new nsInstallTriggerFactory(); } else if (aClass.Equals(kInstallVersion_CID) ) { inst = new nsInstallVersionFactory(); } else if (aClass.Equals(kSoftwareUpdate_CID) ) { inst = new nsSoftwareUpdateFactory(); } else { return NS_ERROR_ILLEGAL_VALUE; } if (inst == NULL) { return NS_ERROR_OUT_OF_MEMORY; } nsresult res = inst->QueryInterface(kIFactoryIID, (void**) aFactory); if (NS_FAILED(res)) { delete inst; } return res; }