Back to index

lightning-sunbird  0.9+nobinonly
nsXPInstallManager.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  *   Daniel Veditz <dveditz@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nscore.h"
00040 #include "pratom.h"
00041 #include "prmem.h"
00042 #include "prprf.h"
00043 #include "nsInt64.h"
00044 
00045 #include "nsISupports.h"
00046 #include "nsIServiceManager.h"
00047 
00048 #include "nsIURL.h"
00049 #include "nsIFileURL.h"
00050 
00051 #include "nsITransport.h"
00052 #include "nsIOutputStream.h"
00053 #include "nsNetUtil.h"
00054 #include "nsIInputStream.h"
00055 #include "nsIFileStreams.h"
00056 #include "nsIStreamListener.h"
00057 #include "nsICryptoHash.h"
00058 
00059 #include "nsISoftwareUpdate.h"
00060 #include "nsSoftwareUpdateIIDs.h"
00061 
00062 #include "nsXPITriggerInfo.h"
00063 #include "nsXPInstallManager.h"
00064 #include "nsInstallTrigger.h"
00065 #include "nsInstallResources.h"
00066 #include "nsIProxyObjectManager.h"
00067 #include "nsIWindowWatcher.h"
00068 #include "nsIAuthPrompt.h"
00069 #include "nsIWindowMediator.h"
00070 #include "nsIDOMWindowInternal.h"
00071 #include "nsDirectoryService.h"
00072 #include "nsDirectoryServiceDefs.h"
00073 #include "nsAppDirectoryServiceDefs.h"
00074 
00075 #include "nsReadableUtils.h"
00076 #include "nsProxiedService.h"
00077 #include "nsIPromptService.h"
00078 #include "nsIScriptGlobalObject.h"
00079 #include "nsXPCOM.h"
00080 #include "nsISupportsPrimitives.h"
00081 #include "nsIObserverService.h"
00082 
00083 #include "nsIPrefService.h"
00084 #include "nsIPrefBranch.h"
00085 
00086 #include "CertReader.h"
00087 
00088 #include "nsEmbedCID.h"
00089 
00090 static NS_DEFINE_IID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
00091 static NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
00092 
00093 #include "nsIEventQueueService.h"
00094 
00095 #define PREF_XPINSTALL_ENABLED                "xpinstall.enabled"
00096 #define PREF_XPINSTALL_CONFIRM_DLG            "xpinstall.dialog.confirm"
00097 #define PREF_XPINSTALL_STATUS_DLG_SKIN        "xpinstall.dialog.progress.skin"
00098 #define PREF_XPINSTALL_STATUS_DLG_CHROME      "xpinstall.dialog.progress.chrome"
00099 #define PREF_XPINSTALL_STATUS_DLG_TYPE_SKIN   "xpinstall.dialog.progress.type.skin"
00100 #define PREF_XPINSTALL_STATUS_DLG_TYPE_CHROME "xpinstall.dialog.progress.type.chrome"
00101 
00102 #define UPDATE_DLG(x)  (((x) - mLastUpdate) > 250000)
00103 
00104 // Mac can't handle PRTime as integers, must go through this hell
00105 inline PRBool nsXPInstallManager::TimeToUpdate(PRTime now)
00106 {
00107        // XXX lets revisit this when dveditz gets back
00108 
00109        return PR_TRUE;
00110 }
00111 
00112 
00113 nsXPInstallManager::nsXPInstallManager()
00114   : mTriggers(0), mItem(0), mNextItem(0), mNumJars(0), mChromeType(NOT_CHROME),
00115     mContentLength(0), mDialogOpen(PR_FALSE), mCancelled(PR_FALSE),
00116     mSelectChrome(PR_FALSE), mNeedsShutdown(PR_FALSE)
00117 {
00118     // we need to own ourself because we have a longer
00119     // lifetime than the scriptlet that created us.
00120     NS_ADDREF_THIS();
00121 
00122     // initialize mLastUpdate to the current time
00123     mLastUpdate = PR_Now();
00124 }
00125 
00126 
00127 nsXPInstallManager::~nsXPInstallManager()
00128 {
00129     NS_ASSERTION(!mTriggers, "Shutdown not called, triggers still alive");
00130 }
00131 
00132 
00133 NS_IMPL_THREADSAFE_ISUPPORTS9( nsXPInstallManager,
00134                                nsIXPIListener,
00135                                nsIXPIDialogService,
00136                                nsIXPInstallManager,
00137                                nsIObserver,
00138                                nsIStreamListener,
00139                                nsIProgressEventSink,
00140                                nsIInterfaceRequestor,
00141                                nsPICertNotification,
00142                                nsISupportsWeakReference)
00143 
00144 NS_IMETHODIMP
00145 nsXPInstallManager::InitManagerFromChrome(const PRUnichar **aURLs,
00146                                           PRUint32 aURLCount,
00147                                           nsIXPIProgressDialog* aListener)
00148 {
00149     return InitManagerWithHashes(aURLs, nsnull, aURLCount, aListener);
00150 }
00151 
00152 NS_IMETHODIMP
00153 nsXPInstallManager::InitManagerWithHashes(const PRUnichar **aURLs,
00154                                           const char **aHashes,
00155                                           PRUint32 aURLCount,
00156                                           nsIXPIProgressDialog* aListener)
00157 {
00158     // If Software Installation is not enabled, we don't want to proceed with
00159     // update. 
00160     PRBool xpinstallEnabled = PR_TRUE;
00161     nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
00162     if (pref) 
00163         pref->GetBoolPref(PREF_XPINSTALL_ENABLED, &xpinstallEnabled);
00164 
00165     if (!xpinstallEnabled)
00166         return NS_OK;
00167   
00168     mTriggers = new nsXPITriggerInfo();
00169     if (!mTriggers)
00170         return NS_ERROR_OUT_OF_MEMORY;
00171 
00172     mNeedsShutdown = PR_TRUE;
00173 
00174     nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
00175     if (os)
00176         os->AddObserver(this, XPI_PROGRESS_TOPIC, PR_TRUE);
00177 
00178     for (PRUint32 i = 0; i < aURLCount; ++i) 
00179     {
00180         nsXPITriggerItem* item = new nsXPITriggerItem(0, aURLs[i], nsnull,
00181                                                       aHashes ? aHashes[i] : nsnull);
00182         if (!item)
00183         {
00184             delete mTriggers; // nsXPITriggerInfo frees any alloc'ed nsXPITriggerItems
00185             mTriggers = nsnull;
00186             Shutdown();
00187             return NS_ERROR_OUT_OF_MEMORY;
00188         }
00189         mTriggers->Add(item);
00190     }
00191 
00192     nsresult rv;
00193     mInstallSvc = do_GetService(nsSoftwareUpdate::GetCID(), &rv);
00194     if (NS_FAILED(rv)) 
00195     {
00196         delete mTriggers;
00197         mTriggers = nsnull;
00198         Shutdown();
00199         return rv;
00200     }
00201 
00202     rv = Observe(aListener, XPI_PROGRESS_TOPIC, NS_LITERAL_STRING("open").get());
00203     if (NS_FAILED(rv))
00204         Shutdown();
00205     return rv;
00206 }
00207 
00208 
00209 NS_IMETHODIMP
00210 nsXPInstallManager::InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITriggerInfo* aTriggers, PRUint32 aChromeType)
00211 {
00212     if ( !aTriggers || aTriggers->Size() == 0 )
00213     {
00214         NS_WARNING("XPInstallManager called with no trigger info!");
00215         NS_RELEASE_THIS();
00216         return NS_ERROR_INVALID_POINTER;
00217     }
00218 
00219     nsresult rv = NS_OK;
00220 
00221     mNeedsShutdown = PR_TRUE;
00222     mTriggers = aTriggers;
00223     mChromeType = aChromeType;
00224 
00225     mParentWindow = do_QueryInterface(aGlobalObject);
00226 
00227     // Start downloading initial chunks looking for signatures,
00228     mOutstandingCertLoads = mTriggers->Size();
00229 
00230     nsXPITriggerItem *item = mTriggers->Get(--mOutstandingCertLoads);
00231 
00232     nsCOMPtr<nsIURI> uri;
00233     NS_NewURI(getter_AddRefs(uri), NS_ConvertUCS2toUTF8(item->mURL));
00234     nsCOMPtr<nsIStreamListener> listener = new CertReader(uri, nsnull, this);
00235     if (listener)
00236         rv = NS_OpenURI(listener, nsnull, uri);
00237     else
00238         rv = NS_ERROR_OUT_OF_MEMORY;
00239 
00240     if (NS_FAILED(rv)) {
00241         Shutdown();
00242     }
00243     return rv;
00244 }
00245 
00246 
00247 nsresult 
00248 nsXPInstallManager::InitManagerInternal()
00249 {
00250     nsresult rv;
00251     PRBool OKtoInstall = PR_FALSE; // initialize to secure state
00252 
00253     //-----------------------------------------------------
00254     // *** Do not return early after this point ***
00255     //
00256     // We have to clean up the triggers in case of error
00257     //-----------------------------------------------------
00258 
00259     // --- use embedding dialogs if any registered
00260     nsCOMPtr<nsIXPIDialogService> dlgSvc(do_CreateInstance(NS_XPIDIALOGSERVICE_CONTRACTID));
00261     if ( !dlgSvc )
00262         dlgSvc = this; // provide our own dialogs
00263 
00264     // --- make sure we can get the install service
00265     mInstallSvc = do_GetService(nsSoftwareUpdate::GetCID(), &rv);
00266 
00267     // --- prepare dialog params
00268     PRUint32 numTriggers = mTriggers->Size();
00269     PRUint32 numStrings = 4 * numTriggers;
00270     const PRUnichar** packageList =
00271         (const PRUnichar**)malloc( sizeof(PRUnichar*) * numStrings );
00272 
00273     if ( packageList && NS_SUCCEEDED(rv) )
00274     {
00275         // populate the list. The list doesn't own the strings
00276         for ( PRUint32 i=0, j=0; i < numTriggers; i++ )
00277         {
00278             nsXPITriggerItem *item = mTriggers->Get(i);
00279             packageList[j++] = item->mName.get();
00280             packageList[j++] = item->GetSafeURLString();
00281             packageList[j++] = item->mIconURL.get();
00282             packageList[j++] = item->mCertName.get();
00283         }
00284 
00285         //-----------------------------------------------------
00286         // Get permission to install
00287         //-----------------------------------------------------
00288 
00289 #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI
00290         if ( mChromeType == CHROME_SKIN )
00291         {
00292             // We may want to enable the simple installation UI once
00293             // bug 343037 is fixed
00294 
00295             // skins get a simpler/friendlier dialog
00296             // XXX currently not embeddable
00297             OKtoInstall = ConfirmChromeInstall( mParentWindow, packageList );
00298         }
00299         else
00300         {
00301 #endif
00302             rv = dlgSvc->ConfirmInstall( mParentWindow,
00303                                          packageList,
00304                                          numStrings,
00305                                          &OKtoInstall );
00306             if (NS_FAILED(rv))
00307                 OKtoInstall = PR_FALSE;
00308 #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI
00309         }
00310 #endif
00311 
00312         if (OKtoInstall)
00313         {
00314             nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
00315             if (os)
00316                 os->AddObserver(this, XPI_PROGRESS_TOPIC, PR_TRUE);
00317 
00318             //-----------------------------------------------------
00319             // Open the progress dialog
00320             //-----------------------------------------------------
00321 
00322             rv = dlgSvc->OpenProgressDialog( packageList, numStrings, this );
00323         }
00324     }
00325     else
00326         rv = NS_ERROR_OUT_OF_MEMORY;
00327 
00328     //-----------------------------------------------------
00329     // cleanup and signal callbacks if there were errors
00330     //-----------------------------------------------------
00331 
00332     if (packageList)
00333         free(packageList);
00334 
00335     PRInt32 cbstatus = 0;  // callback status
00336     if (NS_FAILED(rv))
00337         cbstatus = nsInstall::UNEXPECTED_ERROR;
00338     else if (!OKtoInstall)
00339         cbstatus = nsInstall::USER_CANCELLED;
00340 
00341     if ( cbstatus != 0 )
00342     {
00343         // --- inform callbacks of error
00344         for (PRUint32 i = 0; i < mTriggers->Size(); i++)
00345         {
00346             mTriggers->SendStatus( mTriggers->Get(i)->mURL.get(), cbstatus );
00347         }
00348 
00349         // --- must delete ourselves if not continuing
00350         NS_RELEASE_THIS();
00351     }
00352 
00353     return rv;
00354 }
00355 
00356 
00357 NS_IMETHODIMP
00358 nsXPInstallManager::ConfirmInstall(nsIDOMWindow *aParent, const PRUnichar **aPackageList, PRUint32 aCount, PRBool *aRetval)
00359 {
00360     *aRetval = PR_FALSE;
00361 
00362     nsCOMPtr<nsIDOMWindowInternal> parentWindow( do_QueryInterface(aParent) );
00363     nsCOMPtr<nsIDialogParamBlock> params;
00364     nsresult rv = LoadParams( aCount, aPackageList, getter_AddRefs(params) );
00365 
00366     if ( NS_SUCCEEDED(rv) && parentWindow && params)
00367     {
00368         nsCOMPtr<nsIDOMWindow> newWindow;
00369 
00370         nsCOMPtr<nsISupportsInterfacePointer> ifptr =
00371             do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
00372         NS_ENSURE_SUCCESS(rv, rv);
00373 
00374         ifptr->SetData(params);
00375         ifptr->SetDataIID(&NS_GET_IID(nsIDialogParamBlock));
00376 
00377         char* confirmDialogURL;
00378         nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
00379         if (pref) {
00380           rv = pref->GetCharPref(PREF_XPINSTALL_CONFIRM_DLG, &confirmDialogURL);
00381           NS_ASSERTION(NS_SUCCEEDED(rv), "Can't invoke XPInstall FE without a FE URL! Set xpinstall.dialog.confirm");
00382           if (NS_FAILED(rv))
00383             return rv;
00384         }
00385 
00386         rv = parentWindow->OpenDialog(NS_ConvertASCIItoUCS2(confirmDialogURL),
00387                                       NS_LITERAL_STRING("_blank"),
00388                                       NS_LITERAL_STRING("chrome,centerscreen,modal,titlebar"),
00389                                       ifptr,
00390                                       getter_AddRefs(newWindow));
00391 
00392         if (NS_SUCCEEDED(rv))
00393         {
00394             //Now get which button was pressed from the ParamBlock
00395             PRInt32 buttonPressed = 0;
00396             params->GetInt( 0, &buttonPressed );
00397             *aRetval = buttonPressed ? PR_FALSE : PR_TRUE;
00398         }
00399     }
00400 
00401     return rv;
00402 }
00403 
00404 #ifdef ENABLE_SKIN_SIMPLE_INSTALLATION_UI
00405 PRBool nsXPInstallManager::ConfirmChromeInstall(nsIDOMWindowInternal* aParentWindow, const PRUnichar **aPackage)
00406 {
00407     // get the dialog strings
00408     nsXPIDLString applyNowText;
00409     nsXPIDLString confirmText;
00410     nsCOMPtr<nsIStringBundleService> bundleSvc =
00411              do_GetService( kStringBundleServiceCID );
00412     if (!bundleSvc)
00413         return PR_FALSE;
00414 
00415     nsCOMPtr<nsIStringBundle> xpiBundle;
00416     bundleSvc->CreateBundle( XPINSTALL_BUNDLE_URL,
00417                              getter_AddRefs(xpiBundle) );
00418     if (!xpiBundle)
00419         return PR_FALSE;
00420 
00421     const PRUnichar *formatStrings[2] = { aPackage[0], aPackage[1] }; 
00422     if ( mChromeType == CHROME_LOCALE )
00423     {
00424         xpiBundle->GetStringFromName(
00425             NS_LITERAL_STRING("ApplyNowLocale").get(),
00426             getter_Copies(applyNowText));
00427         xpiBundle->FormatStringFromName(
00428             NS_LITERAL_STRING("ConfirmLocale").get(),
00429             formatStrings, 
00430             2, 
00431             getter_Copies(confirmText));
00432     }
00433     else
00434     {
00435         xpiBundle->GetStringFromName(
00436             NS_LITERAL_STRING("ApplyNowSkin").get(),
00437             getter_Copies(applyNowText));
00438         xpiBundle->FormatStringFromName(
00439             NS_LITERAL_STRING("ConfirmSkin").get(),
00440             formatStrings, 
00441             2, 
00442             getter_Copies(confirmText));
00443     }
00444     
00445     if (confirmText.IsEmpty())
00446         return PR_FALSE;
00447 
00448     // confirmation dialog
00449     PRBool bInstall = PR_FALSE;
00450     nsCOMPtr<nsIPromptService> dlgService(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
00451     if (dlgService)
00452     {
00453         dlgService->Confirm(
00454             aParentWindow,
00455             nsnull,
00456             confirmText,
00457             &bInstall );
00458     }
00459 
00460     return bInstall;
00461 }
00462 #endif
00463 
00464 NS_IMETHODIMP
00465 nsXPInstallManager::OpenProgressDialog(const PRUnichar **aPackageList, PRUint32 aCount, nsIObserver *aObserver)
00466 {
00467     // --- convert parameters into nsISupportArray members
00468     nsCOMPtr<nsIDialogParamBlock> list;
00469     nsresult rv = LoadParams( aCount, aPackageList, getter_AddRefs(list) );
00470     if (NS_FAILED(rv))
00471         return rv;
00472 
00473     nsCOMPtr<nsISupportsInterfacePointer> listwrap(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID));
00474     if (listwrap) {
00475         listwrap->SetData(list);
00476         listwrap->SetDataIID(&NS_GET_IID(nsIDialogParamBlock));
00477     }
00478 
00479     nsCOMPtr<nsISupportsInterfacePointer> callbackwrap(do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID));
00480     if (callbackwrap) {
00481         callbackwrap->SetData(aObserver);
00482         callbackwrap->SetDataIID(&NS_GET_IID(nsIObserver));
00483     }
00484 
00485     nsCOMPtr<nsISupportsArray> params(do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID));
00486 
00487     if ( !params || !listwrap || !callbackwrap )
00488         return NS_ERROR_FAILURE;
00489 
00490     params->AppendElement(listwrap);
00491     params->AppendElement(callbackwrap);
00492 
00493     // --- open the window
00494     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
00495     if (wwatch) {
00496         char *statusDialogURL, *statusDialogType;
00497         nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
00498         if (pref) {
00499           const char* statusDlg = mChromeType == CHROME_SKIN ? PREF_XPINSTALL_STATUS_DLG_SKIN
00500                                                              : PREF_XPINSTALL_STATUS_DLG_CHROME;
00501           rv = pref->GetCharPref(statusDlg, &statusDialogURL);
00502           NS_ASSERTION(NS_SUCCEEDED(rv), "Can't invoke XPInstall FE without a FE URL! Set xpinstall.dialog.status");
00503           if (NS_FAILED(rv))
00504             return rv;
00505 
00506           const char* statusType = mChromeType == CHROME_SKIN ? PREF_XPINSTALL_STATUS_DLG_TYPE_SKIN
00507                                                               : PREF_XPINSTALL_STATUS_DLG_TYPE_CHROME;
00508           rv = pref->GetCharPref(statusType, &statusDialogType);
00509           nsAutoString type; 
00510           type.AssignWithConversion(statusDialogType);
00511           if (NS_SUCCEEDED(rv) && !type.IsEmpty()) {
00512             nsCOMPtr<nsIWindowMediator> wm = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
00513           
00514             nsCOMPtr<nsIDOMWindowInternal> recentWindow;
00515             wm->GetMostRecentWindow(type.get(), getter_AddRefs(recentWindow));
00516             if (recentWindow) {
00517               nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
00518               os->NotifyObservers(params, "xpinstall-download-started", nsnull);
00519 
00520               recentWindow->Focus();
00521               return NS_OK;
00522             }
00523           }
00524         }
00525 
00526         nsCOMPtr<nsIDOMWindow> newWindow;
00527         rv = wwatch->OpenWindow(0, 
00528                                 statusDialogURL,
00529                                 "_blank", 
00530                                 "chrome,centerscreen,titlebar,dialog=no,resizable",
00531                                 params, 
00532                                 getter_AddRefs(newWindow));
00533     }
00534 
00535     return rv;
00536 }
00537 
00538 
00539 NS_IMETHODIMP nsXPInstallManager::Observe( nsISupports *aSubject,
00540                                            const char *aTopic,
00541                                            const PRUnichar *aData )
00542 {
00543     nsresult rv = NS_ERROR_ILLEGAL_VALUE;
00544 
00545     if ( !aTopic || !aData )
00546         return rv;
00547 
00548     if ( nsDependentCString( aTopic ).Equals( XPI_PROGRESS_TOPIC ) )
00549     {
00550         //------------------------------------------------------
00551         // Communication from the XPInstall Progress Dialog
00552         //------------------------------------------------------
00553 
00554         nsDependentString data( aData );
00555 
00556         if ( data.Equals( NS_LITERAL_STRING("open") ) )
00557         {
00558             // -- The dialog has been opened
00559             if (mDialogOpen)
00560                 return NS_OK; // We've already been opened, nothing more to do
00561 
00562             mDialogOpen = PR_TRUE;
00563             rv = NS_OK;
00564 
00565             nsCOMPtr<nsIXPIProgressDialog> dlg( do_QueryInterface(aSubject) );
00566             if (dlg)
00567             {
00568                 // --- create and save a proxy for the dialog
00569                 nsCOMPtr<nsIProxyObjectManager> pmgr =
00570                             do_GetService(kProxyObjectManagerCID, &rv);
00571                 if (pmgr)
00572                 {
00573                     pmgr->GetProxyForObject( NS_UI_THREAD_EVENTQ,
00574                                              NS_GET_IID(nsIXPIProgressDialog),
00575                                              dlg,
00576                                              PROXY_SYNC | PROXY_ALWAYS,
00577                                              getter_AddRefs(mDlg) );
00578                 }
00579             }
00580 
00581             // -- get the ball rolling
00582             DownloadNext();
00583         }
00584 
00585         else if ( data.Equals( NS_LITERAL_STRING("cancel") ) )
00586         {
00587             // -- The dialog/user wants us to cancel the download
00588             mCancelled = PR_TRUE;
00589             if ( !mDialogOpen )
00590             {
00591                 // if we've never been opened then we can shutdown right here,
00592                 // otherwise we need to let mCancelled get discovered elsewhere
00593                 Shutdown();
00594             }
00595             rv = NS_OK;
00596         }
00597     }
00598 
00599     return rv;
00600 }
00601 
00602 
00603 NS_IMETHODIMP nsXPInstallManager::DownloadNext()
00604 {
00605     nsresult rv;
00606     mContentLength = 0;
00607 
00608     if (mCancelled)
00609     {
00610         // Don't download any more if we were cancelled
00611         Shutdown();
00612         return NS_OK;
00613     }
00614 
00615     if ( mNextItem < mTriggers->Size() )
00616     {
00617         //-------------------------------------------------
00618         // There are items to download, get the next one
00619         //-------------------------------------------------
00620         mItem = (nsXPITriggerItem*)mTriggers->Get(mNextItem++);
00621 
00622         NS_ASSERTION( mItem, "bogus Trigger slipped through" );
00623         NS_ASSERTION( !mItem->mURL.IsEmpty(), "bogus trigger");
00624         if ( !mItem || mItem->mURL.IsEmpty() )
00625         {
00626             // serious problem with trigger! Can't notify anyone of the
00627             // error without the URL, just try to carry on.
00628             return DownloadNext();
00629         }
00630 
00631         // --- Tell the dialog we're starting a download
00632         if (mDlg)
00633             mDlg->OnStateChange( mNextItem-1, nsIXPIProgressDialog::DOWNLOAD_START, 0 );
00634 
00635         if ( mItem->IsFileURL() && mChromeType == NOT_CHROME )
00636         {
00637             //--------------------------------------------------
00638             // Already local, we can open it where it is
00639             //--------------------------------------------------
00640             nsCOMPtr<nsIURI> pURL;
00641             rv = NS_NewURI(getter_AddRefs(pURL), mItem->mURL);
00642 
00643             if (NS_SUCCEEDED(rv))
00644             {
00645                 nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(pURL,&rv);
00646                 if (fileURL)
00647                 {
00648                     nsCOMPtr<nsIFile> localFile;
00649                     rv = fileURL->GetFile(getter_AddRefs(localFile));
00650                     if (NS_SUCCEEDED(rv))
00651                     {
00652                         mItem->mFile = do_QueryInterface(localFile,&rv);
00653                     }
00654                 }
00655             }
00656 
00657             if ( NS_FAILED(rv) || !mItem->mFile )
00658             {
00659                 // send error status back
00660                 if (mDlg)
00661                     mDlg->OnStateChange( mNextItem-1,
00662                                          nsIXPIProgressDialog::INSTALL_DONE,
00663                                          nsInstall::UNEXPECTED_ERROR );
00664                 mTriggers->SendStatus( mItem->mURL.get(),
00665                                        nsInstall::UNEXPECTED_ERROR );
00666                 mItem->mFile = 0;
00667             }
00668             else if (mDlg)
00669             {
00670                 mDlg->OnStateChange( mNextItem-1,
00671                                      nsIXPIProgressDialog::DOWNLOAD_DONE, 0);
00672             }
00673 
00674             // --- on to the next one
00675             return DownloadNext();
00676         }
00677         else
00678         {
00679             //--------------------------------------------------
00680             // We have one to download
00681             //--------------------------------------------------
00682             rv = GetDestinationFile(mItem->mURL, getter_AddRefs(mItem->mFile));
00683             if (NS_SUCCEEDED(rv))
00684             {
00685                 nsCOMPtr<nsIURI> pURL;
00686                 rv = NS_NewURI(getter_AddRefs(pURL), mItem->mURL);
00687                 if (NS_SUCCEEDED(rv))
00688                 {
00689                     nsCOMPtr<nsIChannel> channel;
00690 
00691                     rv = NS_NewChannel(getter_AddRefs(channel), pURL, nsnull, nsnull, this);
00692                     if (NS_SUCCEEDED(rv))
00693                     {
00694                         rv = channel->AsyncOpen(this, nsnull);
00695                     }
00696                 }
00697             }
00698 
00699             if (NS_FAILED(rv))
00700             {
00701                 // announce failure
00702                 if (mDlg)
00703                     mDlg->OnStateChange( mNextItem-1,
00704                                          nsIXPIProgressDialog::INSTALL_DONE,
00705                                          nsInstall::DOWNLOAD_ERROR );
00706                 mTriggers->SendStatus( mItem->mURL.get(),
00707                                        nsInstall::DOWNLOAD_ERROR );
00708                 mItem->mFile = 0;
00709 
00710                 // We won't get Necko callbacks so start the next one now
00711                 return DownloadNext();
00712             }
00713         }
00714     }
00715     else
00716     {
00717         //------------------------------------------------------
00718         // all downloaded, queue them for installation
00719         //------------------------------------------------------
00720 
00721         // can't cancel from here on cause we can't undo installs in a multitrigger
00722         for (PRUint32 i = 0; i < mTriggers->Size(); ++i)
00723         {
00724             mItem = (nsXPITriggerItem*)mTriggers->Get(i);
00725             if ( !mItem || !mItem->mFile )
00726             {
00727                 // notification for these errors already handled
00728                 continue;
00729             }
00730 
00731             // If there was hash info in the trigger, but
00732             // there wasn't a hash object created, then the
00733             // algorithm used isn't known.
00734 
00735             if (mItem->mHashFound && !mItem->mHasher)
00736             {
00737                 // report failure
00738                 mTriggers->SendStatus( mItem->mURL.get(), nsInstall::INVALID_HASH_TYPE );
00739                 if (mDlg)
00740                     mDlg->OnStateChange( i, nsIXPIProgressDialog::INSTALL_DONE,
00741                                          nsInstall::INVALID_HASH_TYPE );
00742                 continue;
00743             }
00744 
00745             // Don't install if we can't verify the hash (if specified)
00746             if (mItem->mHasher && !VerifyHash(mItem))
00747             {
00748                 // report failure
00749                 mTriggers->SendStatus( mItem->mURL.get(), nsInstall::INVALID_HASH );
00750                 if (mDlg)
00751                     mDlg->OnStateChange( i, nsIXPIProgressDialog::INSTALL_DONE,
00752                                          nsInstall::INVALID_HASH );
00753                 continue;
00754             }
00755 
00756             // We've got one to install; increment count first so we
00757             // don't have to worry about thread timing.
00758             PR_AtomicIncrement(&mNumJars);
00759 
00760             if ( mChromeType == NOT_CHROME ) {
00761                 rv = mInstallSvc->InstallJar( mItem->mFile,
00762                                               mItem->mURL.get(),
00763                                               mItem->mArguments.get(),
00764                                               mItem->mPrincipal,
00765                                               mItem->mFlags,
00766                                               this );
00767             }
00768             else {
00769                 rv = mInstallSvc->InstallChrome(mChromeType,
00770                                                 mItem->mFile,
00771                                                 mItem->mURL.get(),
00772                                                 mItem->mName.get(),
00773                                                 mSelectChrome,
00774                                                 this );
00775             }
00776 
00777             if (NS_FAILED(rv))
00778             {
00779                 // it failed so remove it from the count
00780                 PR_AtomicDecrement(&mNumJars);
00781                 // send the error status to any trigger callback
00782                 mTriggers->SendStatus( mItem->mURL.get(),
00783                                        nsInstall::UNEXPECTED_ERROR );
00784                 if (mDlg)
00785                     mDlg->OnStateChange( i, nsIXPIProgressDialog::INSTALL_DONE,
00786                                          nsInstall::UNEXPECTED_ERROR );
00787             }
00788         }
00789 
00790         if ( mNumJars == 0 )
00791         {
00792             // We must clean ourself up now -- we won't be called back
00793             Shutdown();
00794         }
00795     }
00796 
00797     return rv;
00798 }
00799 
00800 
00801 //-------------------------------------------------------------------
00802 // VerifyHash
00803 //
00804 // Returns true if the file hash matches the expected value (or if
00805 // the item has no hash value). False if we can't verify the hash
00806 // for any reason
00807 //
00808 PRBool nsXPInstallManager::VerifyHash(nsXPITriggerItem* aItem)
00809 {
00810     NS_ASSERTION(aItem, "Null nsXPITriggerItem passed to VerifyHash");
00811 
00812     nsresult rv;
00813     if (!aItem->mHasher)
00814       return PR_FALSE;
00815     
00816     nsCOMPtr<nsIInputStream> stream;
00817     rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), aItem->mFile);
00818     if (NS_FAILED(rv)) return PR_FALSE;
00819 
00820     rv = aItem->mHasher->UpdateFromStream(stream, PR_UINT32_MAX);
00821     if (NS_FAILED(rv)) return PR_FALSE;
00822 
00823     nsCAutoString binaryHash;
00824     rv = aItem->mHasher->Finish(PR_FALSE, binaryHash);
00825     if (NS_FAILED(rv)) return PR_FALSE;
00826 
00827     char* hash = nsnull;
00828     for (PRUint32 i=0; i < binaryHash.Length(); ++i)
00829     {
00830         hash = PR_sprintf_append(hash,"%.2x", (PRUint8)binaryHash[i]);
00831     }
00832 
00833     PRBool result = aItem->mHash.EqualsIgnoreCase(hash);
00834 
00835     PR_smprintf_free(hash);
00836     return result;
00837 }
00838 
00839 
00840 void nsXPInstallManager::Shutdown()
00841 {
00842     if (mDlg)
00843     {
00844         // tell the dialog it can go away
00845         mDlg->OnStateChange(0, nsIXPIProgressDialog::DIALOG_CLOSE, 0 );
00846         mDlg = nsnull;
00847         mDialogOpen = PR_FALSE;
00848     }
00849 
00850     if (mNeedsShutdown)
00851     {
00852         mNeedsShutdown = PR_FALSE;
00853 
00854         // Send remaining status notifications if we were cancelled early
00855         nsXPITriggerItem* item;
00856         while ( mNextItem < mTriggers->Size() )
00857         {
00858             item = (nsXPITriggerItem*)mTriggers->Get(mNextItem++);
00859             if ( item && !item->mURL.IsEmpty() )
00860             {
00861                 mTriggers->SendStatus( item->mURL.get(),
00862                                        nsInstall::USER_CANCELLED );
00863             }
00864         }
00865 
00866         // Clean up downloaded files (regular install only, not chrome installs)
00867         nsCOMPtr<nsIFile> tmpSpec;
00868         if ( mChromeType == NOT_CHROME )
00869         {
00870             for (PRUint32 i = 0; i < mTriggers->Size(); i++ )
00871             {
00872                 item = NS_STATIC_CAST(nsXPITriggerItem*, mTriggers->Get(i));
00873                 if ( item && item->mFile && !item->IsFileURL() )
00874                     item->mFile->Remove(PR_FALSE);
00875             }
00876         }
00877 
00878         nsCOMPtr<nsIObserverService> os(do_GetService("@mozilla.org/observer-service;1"));
00879         if (os)
00880         {
00881             nsresult rv;
00882             nsCOMPtr<nsIProxyObjectManager> pmgr =
00883                         do_GetService(kProxyObjectManagerCID, &rv);
00884             if (pmgr)
00885             {
00886                 nsCOMPtr<nsIObserverService> pos;
00887                 rv = pmgr->GetProxyForObject( NS_UI_THREAD_EVENTQ,
00888                                               NS_GET_IID(nsIObserverService),
00889                                               os,
00890                                               PROXY_SYNC | PROXY_ALWAYS,
00891                                               getter_AddRefs(pos) );
00892                 if (NS_SUCCEEDED(rv))
00893                     pos->RemoveObserver(this, XPI_PROGRESS_TOPIC);
00894             }
00895         }
00896 
00897         if (mTriggers)
00898         {
00899             delete mTriggers;
00900             mTriggers = nsnull;
00901         }
00902 
00903         NS_RELEASE_THIS();
00904     }
00905 }
00906 
00907 NS_IMETHODIMP
00908 nsXPInstallManager::LoadParams(PRUint32 aCount, const PRUnichar** aPackageList, nsIDialogParamBlock** aParams)
00909 {
00910     nsresult rv;
00911     nsCOMPtr<nsIDialogParamBlock> paramBlock = do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &rv);
00912     if (NS_SUCCEEDED(rv))
00913     {
00914         // set OK and Cancel buttons
00915         paramBlock->SetInt( 0, 2 );
00916         // pass in number of strings
00917         paramBlock->SetInt( 1, aCount );
00918         // add strings
00919         paramBlock->SetNumberStrings( aCount );
00920         for (PRUint32 i = 0; i < aCount; i++)
00921             paramBlock->SetString( i, aPackageList[i] );
00922     }
00923 
00924     NS_IF_ADDREF(*aParams = paramBlock);
00925     return rv;
00926 }
00927 
00928 
00929 NS_IMETHODIMP
00930 nsXPInstallManager::GetDestinationFile(nsString& url, nsILocalFile* *file)
00931 {
00932     NS_ENSURE_ARG_POINTER(file);
00933 
00934     nsresult rv;
00935     nsAutoString leaf;
00936 
00937     PRInt32 pos = url.RFindChar('/');
00938     url.Mid( leaf, pos+1, url.Length() );
00939 
00940     nsCOMPtr<nsIProperties> directoryService =
00941              do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00942 
00943     if (mChromeType == NOT_CHROME )
00944     {
00945         // a regular XPInstall, not chrome
00946         if (NS_SUCCEEDED(rv))
00947         {
00948             nsCOMPtr<nsILocalFile> temp;
00949             rv = directoryService->Get(NS_OS_TEMP_DIR,
00950                                        NS_GET_IID(nsIFile),
00951                                        getter_AddRefs(temp));
00952             if (NS_SUCCEEDED(rv))
00953             { 
00954                 temp->AppendNative(NS_LITERAL_CSTRING("tmp.xpi"));
00955                 temp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
00956                 *file = temp;
00957                 NS_IF_ADDREF(*file);
00958             }
00959         }
00960     }
00961     else
00962     {
00963         // a chrome install, download straight to final destination
00964         if (NS_SUCCEEDED(rv)) // Getting directoryService
00965         {
00966             nsCOMPtr<nsILocalFile>  userChrome;
00967 
00968             // Get the user's Chrome directory, create if necessary
00969 
00970             rv = directoryService->Get(NS_APP_USER_CHROME_DIR,
00971                                        NS_GET_IID(nsIFile),
00972                                        getter_AddRefs(userChrome));
00973 
00974             NS_ASSERTION(NS_SUCCEEDED(rv) && userChrome,
00975                          "App_UserChromeDirectory not defined!");
00976             if (NS_SUCCEEDED(rv))
00977             {
00978                 PRBool exists;
00979                 rv = userChrome->Exists(&exists);
00980                 if (NS_SUCCEEDED(rv) && !exists)
00981                 {
00982                     rv = userChrome->Create(nsIFile::DIRECTORY_TYPE, 0775);
00983                 }
00984 
00985                 if (NS_SUCCEEDED(rv))
00986                 {
00987                     userChrome->Append(leaf);
00988                     userChrome->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0644);
00989                     *file = userChrome;
00990                     NS_IF_ADDREF(*file);
00991                 }
00992             }
00993         }
00994     }
00995     return rv;
00996 }
00997 
00998 
00999 
01000 NS_IMETHODIMP
01001 nsXPInstallManager::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
01002 {
01003     nsresult rv = NS_ERROR_FAILURE;
01004 
01005     // If we are dealing with a HTTP request, then treat HTTP error pages as
01006     // download failures.
01007     nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(request);
01008     if (httpChan) {
01009         PRBool succeeded;
01010         if (NS_SUCCEEDED(httpChan->GetRequestSucceeded(&succeeded)) && !succeeded) {
01011             // HTTP response is not a 2xx!
01012             request->Cancel(NS_BINDING_ABORTED);
01013             return NS_OK;
01014         }
01015     }
01016 
01017     NS_ASSERTION( mItem && mItem->mFile, "XPIMgr::OnStartRequest bad state");
01018     if ( mItem && mItem->mFile )
01019     {
01020         NS_ASSERTION( !mItem->mOutStream, "Received double OnStartRequest from Necko");
01021 
01022         rv = NS_NewLocalFileOutputStream(getter_AddRefs(mItem->mOutStream),
01023                                          mItem->mFile,
01024                                          PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
01025                                          0600);
01026     }
01027     return rv;
01028 }
01029 
01030 
01031 NS_IMETHODIMP
01032 nsXPInstallManager::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
01033                                   nsresult status)
01034 {
01035     nsresult rv;
01036 
01037     switch( status )
01038     {
01039 
01040         case NS_BINDING_SUCCEEDED:
01041             rv = NS_OK;
01042             break;
01043 
01044         case NS_BINDING_FAILED:
01045         case NS_BINDING_ABORTED:
01046             rv = status;
01047             // XXX need to note failure, both to send back status
01048             // to the callback, and also so we don't try to install
01049             // this probably corrupt file.
01050             break;
01051 
01052         default:
01053             rv = NS_ERROR_ILLEGAL_VALUE;
01054     }
01055 
01056     NS_ASSERTION( mItem, "Bad state in XPIManager");
01057     NS_ASSERTION( mItem->mOutStream, "XPIManager: output stream doesn't exist");
01058     if ( mItem && mItem->mOutStream )
01059     {
01060         mItem->mOutStream->Close();
01061         mItem->mOutStream = nsnull;
01062     }
01063 
01064     if (NS_FAILED(rv) || mCancelled)
01065     {
01066         // Download error!
01067         // -- first clean up partially downloaded file
01068         if ( mItem->mFile )
01069         {
01070             PRBool flagExists;
01071             nsresult rv2 ;
01072             rv2 = mItem->mFile->Exists(&flagExists);
01073             if (NS_SUCCEEDED(rv2) && flagExists)
01074                 mItem->mFile->Remove(PR_FALSE);
01075 
01076             mItem->mFile = 0;
01077         }
01078 
01079         // -- then notify interested parties
01080         PRInt32 errorcode = mCancelled ? nsInstall::USER_CANCELLED 
01081                                        : nsInstall::DOWNLOAD_ERROR;
01082         if (mDlg)
01083             mDlg->OnStateChange( mNextItem-1,
01084                                  nsIXPIProgressDialog::INSTALL_DONE,
01085                                  errorcode );
01086         mTriggers->SendStatus( mItem->mURL.get(), errorcode );
01087     }
01088     else if (mDlg)
01089     {
01090         mDlg->OnStateChange( mNextItem-1, nsIXPIProgressDialog::DOWNLOAD_DONE, 0);
01091     }
01092 
01093     DownloadNext();
01094     return rv;
01095 }
01096 
01097 
01098 NS_IMETHODIMP
01099 nsXPInstallManager::OnDataAvailable(nsIRequest* request, nsISupports *ctxt,
01100                                     nsIInputStream *pIStream,
01101                                     PRUint32 sourceOffset,
01102                                     PRUint32 length)
01103 {
01104 #define XPI_ODA_BUFFER_SIZE 8*1024
01105     PRUint32 amt = PR_MIN(XPI_ODA_BUFFER_SIZE, length);
01106     nsresult err;
01107     char buffer[XPI_ODA_BUFFER_SIZE];
01108     PRUint32 writeCount;
01109 
01110     if (mCancelled)
01111     {
01112         // We must cancel this download in progress. We may get extra
01113         // OnData calls if they were already queued so beware
01114         request->Cancel(NS_BINDING_ABORTED);
01115         return NS_ERROR_FAILURE;
01116     }
01117 
01118     do
01119     {
01120         err = pIStream->Read(buffer, amt, &amt);
01121 
01122         if (amt == 0) break;
01123         if (NS_FAILED(err)) return err;
01124 
01125         err = mItem->mOutStream->Write( buffer, amt, &writeCount);
01126         if (NS_FAILED(err) || writeCount != amt)
01127         {
01128             return NS_ERROR_FAILURE;
01129         }
01130         length -= amt;
01131 
01132         amt = PR_MIN(XPI_ODA_BUFFER_SIZE, length);
01133 
01134     } while (length > 0);
01135 
01136     return NS_OK;
01137 }
01138 
01139 
01140 NS_IMETHODIMP
01141 nsXPInstallManager::OnProgress(nsIRequest* request, nsISupports *ctxt, PRUint64 aProgress, PRUint64 aProgressMax)
01142 {
01143     nsresult rv = NS_OK;
01144 
01145     PRTime now = PR_Now();
01146     if (mDlg && !mCancelled && TimeToUpdate(now))
01147     {
01148         if (mContentLength < 1) {
01149             nsCOMPtr<nsIChannel> channel = do_QueryInterface(request,&rv);
01150             NS_ASSERTION(channel, "should have a channel");
01151             if (NS_FAILED(rv)) return rv;
01152             rv = channel->GetContentLength(&mContentLength);
01153             if (NS_FAILED(rv)) return rv;
01154         }
01155         mLastUpdate = now;
01156         // XXX once channels support that, use 64-bit contentlength
01157         rv = mDlg->OnProgress( mNextItem-1, aProgress, nsUint64(mContentLength) );
01158     }
01159 
01160     return rv;
01161 }
01162 
01163 NS_IMETHODIMP
01164 nsXPInstallManager::OnStatus(nsIRequest* request, nsISupports *ctxt,
01165                              nsresult aStatus, const PRUnichar *aStatusArg)
01166 {
01167     // don't need to do anything
01168     return NS_OK;
01169 }
01170 
01171 // nsIInterfaceRequestor method
01172 NS_IMETHODIMP
01173 nsXPInstallManager::GetInterface(const nsIID & eventSinkIID, void* *_retval)
01174 {
01175     if (eventSinkIID.Equals(NS_GET_IID(nsIAuthPrompt))) {    
01176         *_retval = nsnull;
01177  
01178         nsresult rv;
01179         nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
01180         NS_ENSURE_SUCCESS(rv, rv);
01181  
01182         nsCOMPtr<nsIAuthPrompt> prompt;
01183         rv = ww->GetNewAuthPrompter(nsnull, getter_AddRefs(prompt));
01184         NS_ENSURE_SUCCESS(rv, rv);
01185  
01186         nsIAuthPrompt *p = prompt.get();
01187         NS_ADDREF(p);
01188         *_retval = p;
01189         return NS_OK;
01190     }
01191     return QueryInterface(eventSinkIID, (void**)_retval);
01192 }
01193 
01194 // IXPIListener methods
01195 
01196 PRInt32 
01197 nsXPInstallManager::GetIndexFromURL(const PRUnichar* aUrl)
01198 {
01199     // --- figure out which index corresponds to this URL
01200     PRUint32 i;
01201     for (i=0; i < mTriggers->Size(); i++)
01202     {
01203         if ( (nsXPITriggerInfo*)mTriggers->Get(i)->mURL.Equals(aUrl) )
01204             break;
01205     }
01206     NS_ASSERTION( i < mTriggers->Size(), "invalid result URL!" );
01207 
01208     return i;
01209 }
01210 
01211 NS_IMETHODIMP
01212 nsXPInstallManager::OnInstallStart(const PRUnichar *URL)
01213 {
01214     if (mDlg)
01215         mDlg->OnStateChange( GetIndexFromURL( URL ),
01216                              nsIXPIProgressDialog::INSTALL_START,
01217                              0 );
01218 
01219     return NS_OK;
01220 }
01221 
01222 NS_IMETHODIMP
01223 nsXPInstallManager::OnPackageNameSet(const PRUnichar *URL, const PRUnichar *UIPackageName, const PRUnichar *aVersion)
01224 {
01225     // Don't need to do anything
01226     return NS_OK;
01227 }
01228 
01229 NS_IMETHODIMP
01230 nsXPInstallManager::OnItemScheduled(const PRUnichar *message)
01231 {
01232     // Don't need to do anything
01233     return NS_OK;
01234 }
01235 
01236 NS_IMETHODIMP
01237 nsXPInstallManager::OnFinalizeProgress(const PRUnichar *message, PRInt32 itemNum, PRInt32 totNum)
01238 {
01239     // Don't need to do anything
01240     return NS_OK;
01241 }
01242 
01243 NS_IMETHODIMP
01244 nsXPInstallManager::OnInstallDone(const PRUnichar *URL, PRInt32 status)
01245 {
01246     // --- send the final success/error status on to listeners
01247     mTriggers->SendStatus( URL, status );
01248 
01249     if (mDlg)
01250         mDlg->OnStateChange( GetIndexFromURL( URL ),
01251                              nsIXPIProgressDialog::INSTALL_DONE,
01252                              status );
01253 
01254     PR_AtomicDecrement( &mNumJars );
01255     if ( mNumJars == 0 )
01256         Shutdown();
01257 
01258     return NS_OK;
01259 }
01260 
01261 NS_IMETHODIMP
01262 nsXPInstallManager::OnLogComment(const PRUnichar* comment)
01263 {
01264     // Don't need to do anything
01265     return NS_OK;
01266 }
01267 
01268 
01269 NS_IMETHODIMP 
01270 nsXPInstallManager::OnCertAvailable(nsIURI *aURI, 
01271                                     nsISupports* context, 
01272                                     nsresult aStatus, 
01273                                     nsIPrincipal *aPrincipal)
01274 {
01275     if (NS_FAILED(aStatus) && aStatus != NS_BINDING_ABORTED) {
01276         // Check for a bad status.  The only acceptable failure status code we accept 
01277         // is NS_BINDING_ABORTED.  For all others we want to ensure that the 
01278         // nsIPrincipal is nsnull.
01279 
01280         NS_ASSERTION(aPrincipal == nsnull, "There has been an error, but we have a principal!");
01281         aPrincipal = nsnull;
01282     }
01283 
01284     // get the current one and assign the cert name
01285     nsXPITriggerItem *item = mTriggers->Get(mOutstandingCertLoads);
01286     item->SetPrincipal(aPrincipal);
01287 
01288     if (mOutstandingCertLoads == 0) {
01289         InitManagerInternal();
01290         return NS_OK;
01291     }
01292 
01293     // get the next one to load.  If there is any failure, we just go on to the 
01294     // next trigger.  When all triggers items are handled, we call into InitManagerInternal
01295 
01296     item = mTriggers->Get(--mOutstandingCertLoads);
01297 
01298     nsCOMPtr<nsIURI> uri;
01299     NS_NewURI(getter_AddRefs(uri), NS_ConvertUCS2toUTF8(item->mURL.get()).get());
01300 
01301     if (!uri || mChromeType != NOT_CHROME)
01302         return OnCertAvailable(uri, context, NS_ERROR_FAILURE, nsnull);
01303 
01304     nsIStreamListener* listener = new CertReader(uri, nsnull, this);
01305     if (!listener)
01306         return OnCertAvailable(uri, context, NS_ERROR_FAILURE, nsnull);
01307 
01308     NS_ADDREF(listener);
01309     nsresult rv = NS_OpenURI(listener, nsnull, uri);
01310 
01311     NS_ASSERTION(NS_SUCCEEDED(rv), "OpenURI failed");
01312     NS_RELEASE(listener);
01313 
01314     if (NS_FAILED(rv))
01315         return OnCertAvailable(uri, context, NS_ERROR_FAILURE, nsnull);
01316 
01317     return NS_OK;
01318 }
01319