Back to index

lightning-sunbird  0.9+nobinonly
nsSoftwareUpdate.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nscore.h"
00039 #include "nsIGenericFactory.h"
00040 #include "nsIFactory.h"
00041 #include "nsISupports.h"
00042 #include "nsIComponentManager.h"
00043 #include "nsIComponentRegistrar.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsICategoryManager.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsCRT.h"
00048 #include "nsIObserverService.h"
00049 
00050 #include "nspr.h"
00051 #include "prlock.h"
00052 #include "nsXPIDLString.h"
00053 #include "NSReg.h"
00054 #include "VerReg.h"
00055 #include "nsIDirectoryService.h"
00056 #include "nsDirectoryServiceDefs.h"
00057 #include "nsAppDirectoryServiceDefs.h"
00058 
00059 #include "nsInstall.h"
00060 #include "nsSoftwareUpdateIIDs.h"
00061 #include "nsSoftwareUpdate.h"
00062 #include "nsSoftwareUpdateRun.h"
00063 #include "nsInstallTrigger.h"
00064 #include "nsInstallVersion.h"
00065 #include "ScheduledTasks.h"
00066 #include "InstallCleanupDefines.h"
00067 #include "nsXPInstallManager.h"
00068 
00069 #include "nsTopProgressNotifier.h"
00070 #include "nsLoggingProgressNotifier.h"
00071 
00072 #include "nsBuildID.h"
00073 #include "nsProcess.h"
00074 
00075 /* For Javascript Namespace Access */
00076 #include "nsDOMCID.h"
00077 #include "nsIServiceManager.h"
00078 #include "nsIScriptNameSpaceManager.h"
00079 #include "nsIScriptExternalNameSet.h"
00080 
00081 #include "nsIEventQueueService.h"
00082 #include "nsIProxyObjectManager.h"
00083 #include "nsProxiedService.h"
00084 #include "nsIChromeRegistry.h"
00085 
00086 #include "nsCURILoader.h"
00087 
00088 extern "C" void RunChromeInstallOnThread(void *data);
00089 
00091 // Globals
00093 
00094 
00095 
00096 static NS_DEFINE_CID(kIProcessCID, NS_PROCESS_CID);
00097 
00098 nsSoftwareUpdate* nsSoftwareUpdate::mInstance = nsnull;
00099 nsCOMPtr<nsIFile> nsSoftwareUpdate::mProgramDir = nsnull;
00100 char*             nsSoftwareUpdate::mLogName = nsnull;
00101 PRBool            nsSoftwareUpdate::mNeedCleanup = PR_FALSE;
00102 
00103 
00104 nsSoftwareUpdate *
00105 nsSoftwareUpdate::GetInstance()
00106 {
00107     if (mInstance == nsnull)
00108         mInstance = new nsSoftwareUpdate();
00109 
00110     NS_IF_ADDREF(mInstance);
00111     return mInstance;
00112 }
00113 
00114 
00115 
00116 nsSoftwareUpdate::nsSoftwareUpdate()
00117 : mInstalling(PR_FALSE),
00118   mMasterListener(0),
00119   mReg(0)
00120 {
00121     mLock = PR_NewLock();
00122 
00123     /***************************************/
00124     /* Startup the Version Registry        */
00125     /***************************************/
00126 
00127     NR_StartupRegistry();   /* startup the registry; if already started, this will essentially be a noop */
00128 
00129 
00130     nsresult rv;
00131     nsCOMPtr<nsIProperties> directoryService =
00132              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00133 
00134     if(!directoryService) return;
00135 
00136     nsCOMPtr<nsILocalFile> dir;
00137     directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(dir));
00138     if (dir)
00139     {
00140         nsCAutoString nativePath;
00141         dir->GetNativePath(nativePath);
00142         // EVIL version registry does not take a nsIFile.;
00143         VR_SetRegDirectory( nativePath.get() );
00144 
00145     }
00146     /***************************************/
00147     /* Add this as a shutdown observer     */
00148     /***************************************/
00149     nsCOMPtr<nsIObserverService> observerService =
00150              do_GetService("@mozilla.org/observer-service;1", &rv);
00151 
00152     if (NS_SUCCEEDED(rv))
00153         observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
00154 }
00155 
00156 
00157 nsSoftwareUpdate::~nsSoftwareUpdate()
00158 {
00159     PR_Lock(mLock);
00160 
00161     nsInstallInfo* element;
00162     for (PRInt32 i=0; i < mJarInstallQueue.Count(); i++)
00163     {
00164         element = (nsInstallInfo*)mJarInstallQueue.ElementAt(i);
00165         //FIX:  need to add to registry....
00166         delete element;
00167     }
00168 
00169     mJarInstallQueue.Clear();
00170 
00171     PR_Unlock(mLock);
00172     PR_DestroyLock(mLock);
00173 
00174     NR_ShutdownRegistry();
00175 
00176     NS_IF_RELEASE (mMasterListener);
00177     mInstance = nsnull;
00178 
00179     PR_FREEIF(mLogName);
00180 }
00181 
00182 
00183 //------------------------------------------------------------------------
00184 //  nsISupports implementation
00185 //------------------------------------------------------------------------
00186 
00187 NS_IMPL_THREADSAFE_ISUPPORTS3(nsSoftwareUpdate,
00188                               nsISoftwareUpdate,
00189                               nsPIXPIStubHook,
00190                               nsIObserver)
00191 
00192 void
00193 nsSoftwareUpdate::Shutdown()
00194 {
00195     if (mNeedCleanup)
00196     {
00197       // Create a non-blocking process to run the native platform cleanup utility
00198         nsresult rv;
00199         nsCOMPtr<nsILocalFile> pathToCleanupUtility;
00200         //Get the program directory
00201         nsCOMPtr<nsIProperties> directoryService =
00202                  do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00203 
00204         if (nsSoftwareUpdate::GetProgramDirectory()) // In the stub installer
00205         {
00206             nsCOMPtr<nsIFile> tmp;
00207             rv = nsSoftwareUpdate::GetProgramDirectory()->Clone(getter_AddRefs(tmp));
00208 #if defined (XP_MAC)
00209             tmp->AppendNative(ESSENTIAL_FILES);
00210 #endif
00211             pathToCleanupUtility = do_QueryInterface(tmp);
00212 
00213         }
00214         else
00215         {
00216             rv = directoryService->Get(NS_APP_INSTALL_CLEANUP_DIR,
00217                                       NS_GET_IID(nsIFile),
00218                                       getter_AddRefs(pathToCleanupUtility));
00219         }
00220 
00221         NS_ASSERTION(pathToCleanupUtility,"No path to cleanup utility in nsSoftwareUpdate::Shutdown()");
00222 
00223         //Create the Process framework
00224         pathToCleanupUtility->AppendNative(CLEANUP_UTIL);
00225         nsCOMPtr<nsIProcess> cleanupProcess = do_CreateInstance(kIProcessCID);
00226         rv = cleanupProcess->Init(pathToCleanupUtility);
00227         if (NS_SUCCEEDED(rv))
00228         {
00229             //Run the cleanup utility as a NON-blocking process
00230             rv = cleanupProcess->Run(PR_FALSE, nsnull, 0, nsnull);
00231         }
00232     }
00233 }
00234 
00235 NS_IMETHODIMP nsSoftwareUpdate::Observe(nsISupports *aSubject,
00236                                         const char *aTopic,
00237                                         const PRUnichar *aData)
00238 {
00239     if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
00240       Shutdown();
00241 
00242     return NS_OK;
00243 }
00244 
00245 NS_IMETHODIMP
00246 nsSoftwareUpdate::RegisterListener(nsIXPIListener *aListener)
00247 {
00248     // once you register a Listener, you can not remove it.
00249     // This should get changed at some point.
00250 
00251     if (!mMasterListener)
00252         CreateMasterListener();
00253 
00254     if (!mMasterListener)
00255         return NS_ERROR_FAILURE;
00256 
00257     mMasterListener->RegisterListener(aListener);
00258     return NS_OK;
00259 }
00260 
00261 NS_IMETHODIMP
00262 nsSoftwareUpdate::GetMasterListener(nsIXPIListener **aListener)
00263 {
00264     NS_ASSERTION(aListener, "getter has invalid return pointer");
00265     if (!aListener)
00266         return NS_ERROR_NULL_POINTER;
00267 
00268     if (!mMasterListener)
00269         CreateMasterListener();
00270 
00271     if (!mMasterListener)
00272         return NS_ERROR_FAILURE;
00273 
00274     NS_ADDREF (mMasterListener);
00275     *aListener = mMasterListener;
00276     return NS_OK;
00277 }
00278 
00279 
00280 NS_IMETHODIMP
00281 nsSoftwareUpdate::SetActiveListener(nsIXPIListener *aListener)
00282 {
00283     if (!mMasterListener)
00284         CreateMasterListener();
00285 
00286     if (!mMasterListener)
00287         return NS_ERROR_FAILURE;
00288 
00289     mMasterListener->SetActiveListener (aListener);
00290     return NS_OK;
00291 }
00292 
00293 void nsSoftwareUpdate::CreateMasterListener()
00294 {
00295     mMasterListener = new nsTopProgressListener;
00296     if (mMasterListener)
00297     {
00298         NS_ADDREF(mMasterListener);
00299 
00300         nsLoggingProgressListener *logger = new nsLoggingProgressListener();
00301         mMasterListener->RegisterListener(logger);
00302     }
00303 }
00304 
00305 NS_IMETHODIMP
00306 nsSoftwareUpdate::InstallJar(  nsIFile* aLocalFile,
00307                                const PRUnichar* aURL,
00308                                const PRUnichar* aArguments,
00309                                nsIPrincipal* aPrincipal,
00310                                PRUint32 flags,
00311                                nsIXPIListener* aListener)
00312 {
00313     if ( !aLocalFile )
00314         return NS_ERROR_NULL_POINTER;
00315 
00316     // we want to call this with or without a chrome registry
00317     nsInstallInfo *info = new nsInstallInfo( 0, aLocalFile, aURL, aArguments, aPrincipal,
00318                                              flags, aListener);
00319 
00320     if (!info)
00321         return NS_ERROR_OUT_OF_MEMORY;
00322 
00323     PR_Lock(mLock);
00324     mJarInstallQueue.AppendElement( info );
00325     PR_Unlock(mLock);
00326     RunNextInstall();
00327 
00328     return NS_OK;
00329 }
00330 
00331 
00332 NS_IMETHODIMP
00333 nsSoftwareUpdate::InstallChrome( PRUint32 aType,
00334                                  nsIFile* aFile,
00335                                  const PRUnichar* URL,
00336                                  const PRUnichar* aName,
00337                                  PRBool aSelect,
00338                                  nsIXPIListener* aListener)
00339 {
00340     nsInstallInfo *info = new nsInstallInfo( aType,
00341                                              aFile,
00342                                              URL,
00343                                              aName,
00344                                              nsnull,
00345                                              (PRUint32)aSelect,
00346                                              aListener);
00347     if (!info)
00348         return NS_ERROR_OUT_OF_MEMORY;
00349 
00350     if (!info->GetChromeRegistry() ||
00351 #ifdef MOZ_XUL_APP
00352         !info->GetExtensionManager() ||
00353         !info->GetFileJARURL() ||
00354         !info->GetManifestURL()
00355 #else
00356         info->GetFileJARSpec().IsEmpty()
00357 #endif
00358         ) {
00359       delete info;
00360       return NS_ERROR_FAILURE;
00361     }
00362 
00363     PR_CreateThread(PR_USER_THREAD,
00364                     RunChromeInstallOnThread,
00365                     (void*)info,
00366                     PR_PRIORITY_NORMAL,
00367                     PR_GLOBAL_THREAD,
00368                     PR_UNJOINABLE_THREAD,
00369                     0);
00370 
00371     return NS_OK;
00372 }
00373 
00374 
00375 NS_IMETHODIMP
00376 nsSoftwareUpdate::InstallJarCallBack()
00377 {
00378     PR_Lock(mLock);
00379 
00380     if (mJarInstallQueue.Count() != 0) // paranoia
00381     {
00382         nsInstallInfo *nextInstall = (nsInstallInfo*)mJarInstallQueue.ElementAt(0);
00383         if (nextInstall != nsnull)
00384             delete nextInstall;
00385 
00386         mJarInstallQueue.RemoveElementAt(0);
00387     }
00388     mInstalling = PR_FALSE;
00389 
00390     PR_Unlock(mLock);
00391 
00392     return RunNextInstall();
00393 }
00394 
00395 
00396 nsresult
00397 nsSoftwareUpdate::RunNextInstall()
00398 {
00399     nsresult        rv = NS_OK;
00400     nsInstallInfo*  info = nsnull;
00401 
00402     PR_Lock(mLock);
00403 
00404     // make sure master master listener exists
00405     if (!mMasterListener)
00406         CreateMasterListener();
00407 
00408     if (!mInstalling)
00409     {
00410         if ( mJarInstallQueue.Count() > 0 )
00411         {
00412             info = (nsInstallInfo*)mJarInstallQueue.ElementAt(0);
00413 
00414             if ( info )
00415                 mInstalling = PR_TRUE;
00416             else
00417             {
00418                 // bogus elements got into the queue
00419                 NS_ERROR("leaks remaining nsInstallInfos, please file bug!");
00420                 rv = NS_ERROR_NULL_POINTER;
00421                 VR_Close();
00422             }
00423         }
00424         else
00425         {
00426             // nothing more to do
00427             VR_Close();
00428         }
00429     }
00430     PR_Unlock(mLock);
00431 
00432     // make sure to RunInstall() outside of locked section due to callbacks
00433     if (info)
00434         RunInstall( info );
00435 
00436     return rv;
00437 }
00438 
00439 
00440 NS_IMETHODIMP
00441 nsSoftwareUpdate::StubInitialize(nsIFile *aDir, const char* logName)
00442 {
00443     if ( !aDir )
00444         return NS_ERROR_NULL_POINTER;
00445 
00446     // fix GetFolder return path
00447     nsresult rv = aDir->Clone(getter_AddRefs(mProgramDir));
00448 
00449     // make sure registry updates go to the right place
00450     nsCAutoString tempPath;
00451     rv = aDir->GetNativePath(tempPath);
00452     if (NS_SUCCEEDED(rv))
00453         VR_SetRegDirectory( tempPath.get() );
00454 
00455     // Optionally set logfile leafname
00456     if (logName)
00457     {
00458         mLogName = PL_strdup(logName);
00459         if (!mLogName)
00460             return NS_ERROR_OUT_OF_MEMORY;
00461     }
00462 
00463     return rv;
00464 }
00465 
00466 
00468 // nsSoftwareUpdateNameSet
00470 
00471 nsSoftwareUpdateNameSet::nsSoftwareUpdateNameSet()
00472 {
00473 }
00474 
00475 nsSoftwareUpdateNameSet::~nsSoftwareUpdateNameSet()
00476 {
00477 }
00478 
00479 NS_IMPL_ISUPPORTS1(nsSoftwareUpdateNameSet, nsIScriptExternalNameSet)
00480 
00481 
00482 NS_IMETHODIMP
00483 nsSoftwareUpdateNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
00484 {
00485     nsresult result = NS_OK;
00486 
00487     result = NS_InitInstallVersionClass(aScriptContext, nsnull);
00488     if (NS_FAILED(result)) return result;
00489 
00490     result = NS_InitInstallTriggerGlobalClass(aScriptContext, nsnull);
00491 
00492     return result;
00493 }
00494 
00495 
00496 //----------------------------------------------------------------------
00497 
00498 // Functions used to create new instances of a given object by the
00499 // generic factory.
00500 
00501 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSoftwareUpdate,
00502                                          nsSoftwareUpdate::GetInstance)
00503 NS_GENERIC_FACTORY_CONSTRUCTOR(nsInstallTrigger)
00504 NS_GENERIC_FACTORY_CONSTRUCTOR(nsInstallVersion)
00505 NS_GENERIC_FACTORY_CONSTRUCTOR(nsXPInstallManager)
00506 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSoftwareUpdateNameSet)
00507 
00508 //----------------------------------------------------------------------
00509 
00510 #define NS_SOFTWAREUPDATENAMESET_CID \
00511   { 0xcde48010, 0x9494, 0x4a73, \
00512   { 0x96, 0x9a, 0x26, 0x33, 0x50, 0x0, 0x70, 0xde }}
00513 
00514 #define NS_SOFTWAREUPDATENAMESET_CONTRACTID \
00515   "@mozilla.org/xpinstall/softwareupdatenameset;1"
00516 
00517 static NS_METHOD
00518 RegisterSoftwareUpdate( nsIComponentManager *aCompMgr,
00519                         nsIFile *aPath,
00520                         const char *registryLocation,
00521                         const char *componentType,
00522                         const nsModuleComponentInfo *info)
00523 {
00524   nsresult rv = NS_OK;
00525 
00526   nsCOMPtr<nsICategoryManager> catman =
00527     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
00528   NS_ENSURE_SUCCESS(rv, rv);
00529 
00530   nsXPIDLCString previous;
00531   rv = catman->AddCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY,
00532                                 "InstallVersion",
00533                                 NS_INSTALLVERSIONCOMPONENT_CONTRACTID,
00534                                 PR_TRUE, PR_TRUE, getter_Copies(previous));
00535   NS_ENSURE_SUCCESS(rv, rv);
00536 
00537   rv = catman->AddCategoryEntry(JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY,
00538                                 "InstallTrigger",
00539                                 NS_INSTALLTRIGGERCOMPONENT_CONTRACTID,
00540                                 PR_TRUE, PR_TRUE, getter_Copies(previous));
00541   NS_ENSURE_SUCCESS(rv, rv);
00542 
00543   return NS_OK;
00544 }
00545 
00546 
00547 // The list of components we register
00548 static const nsModuleComponentInfo components[] =
00549 {
00550     { "SoftwareUpdate Component",
00551        NS_SoftwareUpdate_CID,
00552        NS_IXPINSTALLCOMPONENT_CONTRACTID,
00553        nsSoftwareUpdateConstructor,
00554        RegisterSoftwareUpdate
00555     },
00556 
00557     { "InstallTrigger Component",
00558        NS_SoftwareUpdateInstallTrigger_CID,
00559        NS_INSTALLTRIGGERCOMPONENT_CONTRACTID,
00560        nsInstallTriggerConstructor
00561     },
00562 
00563     { "InstallVersion Component",
00564        NS_SoftwareUpdateInstallVersion_CID,
00565        NS_INSTALLVERSIONCOMPONENT_CONTRACTID,
00566        nsInstallVersionConstructor
00567     },
00568 
00569     { "XPInstall Content Handler",
00570       NS_SoftwareUpdateInstallTrigger_CID,
00571       NS_CONTENT_HANDLER_CONTRACTID_PREFIX"application/x-xpinstall",
00572       nsInstallTriggerConstructor
00573     },
00574 
00575     { "Software update nameset",
00576       NS_SOFTWAREUPDATENAMESET_CID,
00577       NS_SOFTWAREUPDATENAMESET_CONTRACTID,
00578       nsSoftwareUpdateNameSetConstructor
00579     },
00580 
00581     { "XPInstallManager Component",
00582       NS_XPInstallManager_CID,
00583       NS_XPINSTALLMANAGERCOMPONENT_CONTRACTID,
00584       nsXPInstallManagerConstructor
00585     }
00586 };
00587 
00588 
00589 
00590 NS_IMPL_NSGETMODULE(nsSoftwareUpdate, components)
00591