michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef downloadmanager___h___ michael@0: #define downloadmanager___h___ michael@0: michael@0: #if defined(XP_WIN) michael@0: #define DOWNLOAD_SCANNER michael@0: #endif michael@0: michael@0: #include "nsIDownload.h" michael@0: #include "nsIDownloadManager.h" michael@0: #include "nsIDownloadProgressListener.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIMIMEInfo.h" michael@0: #include "nsINavHistoryService.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIStringBundle.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsWeakReference.h" michael@0: #include "nsITimer.h" michael@0: #include "nsString.h" michael@0: michael@0: #include "mozStorageHelper.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMArray.h" michael@0: michael@0: typedef int16_t DownloadState; michael@0: typedef int16_t DownloadType; michael@0: michael@0: class nsIArray; michael@0: class nsDownload; michael@0: michael@0: #ifdef DOWNLOAD_SCANNER michael@0: #include "nsDownloadScanner.h" michael@0: #endif michael@0: michael@0: class nsDownloadManager : public nsIDownloadManager, michael@0: public nsINavHistoryObserver, michael@0: public nsIObserver, michael@0: public nsSupportsWeakReference michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIDOWNLOADMANAGER michael@0: NS_DECL_NSINAVHISTORYOBSERVER michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: nsresult Init(); michael@0: michael@0: static nsDownloadManager *GetSingleton(); michael@0: michael@0: virtual ~nsDownloadManager(); michael@0: nsDownloadManager() michael@0: #ifdef DOWNLOAD_SCANNER michael@0: : mScanner(nullptr) michael@0: #endif michael@0: { michael@0: } michael@0: michael@0: protected: michael@0: nsresult InitDB(); michael@0: nsresult InitFileDB(); michael@0: void CloseAllDBs(); michael@0: void CloseDB(mozIStorageConnection* aDBConn, michael@0: mozIStorageStatement* aUpdateStmt, michael@0: mozIStorageStatement* aGetIdsStmt); michael@0: nsresult InitPrivateDB(); michael@0: already_AddRefed GetFileDBConnection(nsIFile *dbFile) const; michael@0: already_AddRefed GetPrivateDBConnection() const; michael@0: nsresult CreateTable(mozIStorageConnection* aDBConn); michael@0: michael@0: /** michael@0: * Fix up the database after a crash such as dealing with previously-active michael@0: * downloads. Call this before RestoreActiveDownloads to get the downloads michael@0: * fixed here to be auto-resumed. michael@0: */ michael@0: nsresult RestoreDatabaseState(); michael@0: michael@0: /** michael@0: * Paused downloads that survive across sessions are considered active, so michael@0: * rebuild the list of these downloads. michael@0: */ michael@0: nsresult RestoreActiveDownloads(); michael@0: michael@0: nsresult GetDownloadFromDB(const nsACString& aGUID, nsDownload **retVal); michael@0: nsresult GetDownloadFromDB(uint32_t aID, nsDownload **retVal); michael@0: nsresult GetDownloadFromDB(mozIStorageConnection* aDBConn, michael@0: mozIStorageStatement* stmt, michael@0: nsDownload **retVal); michael@0: michael@0: /** michael@0: * Specially track the active downloads so that we don't need to check michael@0: * every download to see if they're in progress. michael@0: */ michael@0: nsresult AddToCurrentDownloads(nsDownload *aDl); michael@0: michael@0: void SendEvent(nsDownload *aDownload, const char *aTopic); michael@0: michael@0: /** michael@0: * Adds a download with the specified information to the DB. michael@0: * michael@0: * @return The id of the download, or 0 if there was an error. michael@0: */ michael@0: int64_t AddDownloadToDB(const nsAString &aName, michael@0: const nsACString &aSource, michael@0: const nsACString &aTarget, michael@0: const nsAString &aTempPath, michael@0: int64_t aStartTime, michael@0: int64_t aEndTime, michael@0: const nsACString &aMimeType, michael@0: const nsACString &aPreferredApp, michael@0: nsHandlerInfoAction aPreferredAction, michael@0: bool aPrivate, michael@0: nsACString &aNewGUID); michael@0: michael@0: void NotifyListenersOnDownloadStateChange(int16_t aOldState, michael@0: nsDownload *aDownload); michael@0: void NotifyListenersOnProgressChange(nsIWebProgress *aProgress, michael@0: nsIRequest *aRequest, michael@0: int64_t aCurSelfProgress, michael@0: int64_t aMaxSelfProgress, michael@0: int64_t aCurTotalProgress, michael@0: int64_t aMaxTotalProgress, michael@0: nsDownload *aDownload); michael@0: void NotifyListenersOnStateChange(nsIWebProgress *aProgress, michael@0: nsIRequest *aRequest, michael@0: uint32_t aStateFlags, michael@0: nsresult aStatus, michael@0: nsDownload *aDownload); michael@0: michael@0: nsDownload *FindDownload(const nsACString& aGUID); michael@0: nsDownload *FindDownload(uint32_t aID); michael@0: michael@0: /** michael@0: * First try to resume the download, and if that fails, retry it. michael@0: * michael@0: * @param aDl The download to resume and/or retry. michael@0: */ michael@0: nsresult ResumeRetry(nsDownload *aDl); michael@0: michael@0: /** michael@0: * Pause all active downloads and remember if they should try to auto-resume michael@0: * when the download manager starts again. michael@0: * michael@0: * @param aSetResume Indicate if the downloads that get paused should be set michael@0: * as auto-resume. michael@0: */ michael@0: nsresult PauseAllDownloads(bool aSetResume); michael@0: michael@0: /** michael@0: * Resume all paused downloads unless we're only supposed to do the automatic michael@0: * ones; in that case, try to retry them as well if resuming doesn't work. michael@0: * michael@0: * @param aResumeAll If true, all downloads will be resumed; otherwise, only michael@0: * those that are marked as auto-resume will resume. michael@0: */ michael@0: nsresult ResumeAllDownloads(bool aResumeAll); michael@0: michael@0: /** michael@0: * Stop tracking the active downloads. Only use this when we're about to quit michael@0: * the download manager because we destroy our list of active downloads to michael@0: * break the dlmgr<->dl cycle. Active downloads that aren't real-paused will michael@0: * be canceled. michael@0: */ michael@0: nsresult RemoveAllDownloads(); michael@0: michael@0: /** michael@0: * Find all downloads from a source URI and delete them. michael@0: * michael@0: * @param aURI michael@0: * The source URI to remove downloads michael@0: */ michael@0: nsresult RemoveDownloadsForURI(nsIURI *aURI); michael@0: michael@0: /** michael@0: * Callback used for resuming downloads after getting a wake notification. michael@0: * michael@0: * @param aTimer michael@0: * Timer object fired after some delay after a wake notification michael@0: * @param aClosure michael@0: * nsDownloadManager object used to resume downloads michael@0: */ michael@0: static void ResumeOnWakeCallback(nsITimer *aTimer, void *aClosure); michael@0: nsCOMPtr mResumeOnWakeTimer; michael@0: michael@0: void ConfirmCancelDownloads(int32_t aCount, michael@0: nsISupportsPRBool *aCancelDownloads, michael@0: const char16_t *aTitle, michael@0: const char16_t *aCancelMessageMultiple, michael@0: const char16_t *aCancelMessageSingle, michael@0: const char16_t *aDontCancelButton); michael@0: michael@0: int32_t GetRetentionBehavior(); michael@0: michael@0: /** michael@0: * Type to indicate possible behaviors for active downloads across sessions. michael@0: * michael@0: * Possible values are: michael@0: * QUIT_AND_RESUME - downloads should be auto-resumed michael@0: * QUIT_AND_PAUSE - downloads should be paused michael@0: * QUIT_AND_CANCEL - downloads should be cancelled michael@0: */ michael@0: enum QuitBehavior { michael@0: QUIT_AND_RESUME = 0, michael@0: QUIT_AND_PAUSE = 1, michael@0: QUIT_AND_CANCEL = 2 michael@0: }; michael@0: michael@0: /** michael@0: * Indicates user-set behavior for active downloads across sessions, michael@0: * michael@0: * @return value of user-set pref for active download behavior michael@0: */ michael@0: enum QuitBehavior GetQuitBehavior(); michael@0: michael@0: void OnEnterPrivateBrowsingMode(); michael@0: void OnLeavePrivateBrowsingMode(); michael@0: michael@0: nsresult RetryDownload(const nsACString& aGUID); michael@0: nsresult RetryDownload(nsDownload* dl); michael@0: michael@0: nsresult RemoveDownload(const nsACString& aGUID); michael@0: michael@0: nsresult NotifyDownloadRemoval(nsDownload* aRemoved); michael@0: michael@0: // Virus scanner for windows michael@0: #ifdef DOWNLOAD_SCANNER michael@0: private: michael@0: nsDownloadScanner* mScanner; michael@0: #endif michael@0: michael@0: private: michael@0: nsresult CleanUp(mozIStorageConnection* aDBConn); michael@0: nsresult InitStatements(mozIStorageConnection* aDBConn, michael@0: mozIStorageStatement** aUpdateStatement, michael@0: mozIStorageStatement** aGetIdsStatement); michael@0: nsresult RemoveAllDownloads(nsCOMArray& aDownloads); michael@0: nsresult PauseAllDownloads(nsCOMArray& aDownloads, bool aSetResume); michael@0: nsresult ResumeAllDownloads(nsCOMArray& aDownloads, bool aResumeAll); michael@0: nsresult RemoveDownloadsForURI(mozIStorageStatement* aStatement, nsIURI *aURI); michael@0: michael@0: bool mUseJSTransfer; michael@0: nsCOMArray mListeners; michael@0: nsCOMArray mPrivacyAwareListeners; michael@0: nsCOMPtr mBundle; michael@0: nsCOMPtr mDBConn; michael@0: nsCOMPtr mPrivateDBConn; michael@0: nsCOMArray mCurrentDownloads; michael@0: nsCOMArray mCurrentPrivateDownloads; michael@0: nsCOMPtr mObserverService; michael@0: nsCOMPtr mUpdateDownloadStatement; michael@0: nsCOMPtr mUpdatePrivateDownloadStatement; michael@0: nsCOMPtr mGetIdsForURIStatement; michael@0: nsCOMPtr mGetPrivateIdsForURIStatement; michael@0: nsAutoPtr mHistoryTransaction; michael@0: michael@0: static nsDownloadManager *gDownloadManagerService; michael@0: michael@0: friend class nsDownload; michael@0: }; michael@0: michael@0: class nsDownload : public nsIDownload michael@0: { michael@0: public: michael@0: NS_DECL_NSIWEBPROGRESSLISTENER michael@0: NS_DECL_NSIWEBPROGRESSLISTENER2 michael@0: NS_DECL_NSITRANSFER michael@0: NS_DECL_NSIDOWNLOAD michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: nsDownload(); michael@0: virtual ~nsDownload(); michael@0: michael@0: /** michael@0: * This method MUST be called when changing states on a download. It will michael@0: * notify the download listener when a change happens. This also updates the michael@0: * database, by calling UpdateDB(). michael@0: */ michael@0: nsresult SetState(DownloadState aState); michael@0: michael@0: protected: michael@0: /** michael@0: * Finish up the download by breaking reference cycles and clearing unneeded michael@0: * data. Additionally, the download removes itself from the download michael@0: * manager's list of current downloads. michael@0: * michael@0: * NOTE: This method removes the cycle created when starting the download, so michael@0: * make sure to use kungFuDeathGrip if you want to access member variables. michael@0: */ michael@0: void Finalize(); michael@0: michael@0: /** michael@0: * For finished resumed downloads that came in from exthandler, perform the michael@0: * action that would have been done if the download wasn't resumed. michael@0: */ michael@0: nsresult ExecuteDesiredAction(); michael@0: michael@0: /** michael@0: * Move the temporary file to the final destination by removing the existing michael@0: * dummy target and renaming the temporary. michael@0: */ michael@0: nsresult MoveTempToTarget(); michael@0: michael@0: /** michael@0: * Update the start time which also implies the last update time is the same. michael@0: */ michael@0: void SetStartTime(int64_t aStartTime); michael@0: michael@0: /** michael@0: * Update the amount of bytes transferred and max bytes; and recalculate the michael@0: * download percent. michael@0: */ michael@0: void SetProgressBytes(int64_t aCurrBytes, int64_t aMaxBytes); michael@0: michael@0: /** michael@0: * All this does is cancel the connection that the download is using. It does michael@0: * not remove it from the download manager. michael@0: */ michael@0: nsresult CancelTransfer(); michael@0: michael@0: /** michael@0: * Download is not transferring? michael@0: */ michael@0: bool IsPaused(); michael@0: michael@0: /** michael@0: * Download can continue from the middle of a transfer? michael@0: */ michael@0: bool IsResumable(); michael@0: michael@0: /** michael@0: * Download was resumed? michael@0: */ michael@0: bool WasResumed(); michael@0: michael@0: /** michael@0: * Indicates if the download should try to automatically resume or not. michael@0: */ michael@0: bool ShouldAutoResume(); michael@0: michael@0: /** michael@0: * Download is in a state to stop and complete the download? michael@0: */ michael@0: bool IsFinishable(); michael@0: michael@0: /** michael@0: * Download is totally done transferring and all? michael@0: */ michael@0: bool IsFinished(); michael@0: michael@0: /** michael@0: * Update the DB with the current state of the download including time, michael@0: * download state and other values not known when first creating the michael@0: * download DB entry. michael@0: */ michael@0: nsresult UpdateDB(); michael@0: michael@0: /** michael@0: * Fail a download because of a failure status and prompt the provided michael@0: * message or use a generic download failure message if nullptr. michael@0: */ michael@0: nsresult FailDownload(nsresult aStatus, const char16_t *aMessage); michael@0: michael@0: /** michael@0: * Opens the downloaded file with the appropriate application, which is michael@0: * either the OS default, MIME type default, or the one selected by the user. michael@0: * michael@0: * This also adds the temporary file to the "To be deleted on Exit" list, if michael@0: * the corresponding user preference is set (except on OS X). michael@0: * michael@0: * This function was adopted from nsExternalAppHandler::OpenWithApplication michael@0: * (uriloader/exthandler/nsExternalHelperAppService.cpp). michael@0: */ michael@0: nsresult OpenWithApplication(); michael@0: michael@0: nsDownloadManager *mDownloadManager; michael@0: nsCOMPtr mTarget; michael@0: michael@0: private: michael@0: nsString mDisplayName; michael@0: nsCString mEntityID; michael@0: nsCString mGUID; michael@0: michael@0: nsCOMPtr mSource; michael@0: nsCOMPtr mReferrer; michael@0: nsCOMPtr mCancelable; michael@0: nsCOMPtr mRequest; michael@0: nsCOMPtr mTempFile; michael@0: nsCOMPtr mMIMEInfo; michael@0: michael@0: DownloadState mDownloadState; michael@0: michael@0: uint32_t mID; michael@0: int32_t mPercentComplete; michael@0: michael@0: /** michael@0: * These bytes are based on the position of where the request started, so 0 michael@0: * doesn't necessarily mean we have nothing. Use GetAmountTransferred and michael@0: * GetSize for the real transferred amount and size. michael@0: */ michael@0: int64_t mCurrBytes; michael@0: int64_t mMaxBytes; michael@0: michael@0: PRTime mStartTime; michael@0: PRTime mLastUpdate; michael@0: int64_t mResumedAt; michael@0: double mSpeed; michael@0: michael@0: bool mHasMultipleFiles; michael@0: bool mPrivate; michael@0: michael@0: /** michael@0: * Track various states of the download trying to auto-resume when starting michael@0: * the download manager or restoring from a crash. michael@0: * michael@0: * DONT_RESUME: Don't automatically resume the download michael@0: * AUTO_RESUME: Automaically resume the download michael@0: */ michael@0: enum AutoResume { DONT_RESUME, AUTO_RESUME }; michael@0: AutoResume mAutoResume; michael@0: michael@0: /** michael@0: * Stores the SHA-256 hash associated with the downloaded file. michael@0: */ michael@0: nsAutoCString mHash; michael@0: michael@0: /** michael@0: * Stores the certificate chains in an nsIArray of nsIX509CertList of michael@0: * nsIX509Cert, if this binary is signed. michael@0: */ michael@0: nsCOMPtr mSignatureInfo; michael@0: michael@0: friend class nsDownloadManager; michael@0: }; michael@0: michael@0: #endif