michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */ 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: /** michael@0: * Main entry point to get references to all the back-end objects. michael@0: */ michael@0: michael@0: "use strict"; michael@0: michael@0: this.EXPORTED_SYMBOLS = [ michael@0: "Downloads", michael@0: ]; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Globals michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/DownloadCore.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyModuleGetter(this, "DownloadCombinedList", michael@0: "resource://gre/modules/DownloadList.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration", michael@0: "resource://gre/modules/DownloadIntegration.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "DownloadList", michael@0: "resource://gre/modules/DownloadList.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "DownloadSummary", michael@0: "resource://gre/modules/DownloadList.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper", michael@0: "resource://gre/modules/DownloadUIHelper.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "Promise", michael@0: "resource://gre/modules/Promise.jsm"); michael@0: XPCOMUtils.defineLazyModuleGetter(this, "Task", michael@0: "resource://gre/modules/Task.jsm"); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: //// Downloads michael@0: michael@0: /** michael@0: * This object is exposed directly to the consumers of this JavaScript module, michael@0: * and provides the only entry point to get references to back-end objects. michael@0: */ michael@0: this.Downloads = { michael@0: /** michael@0: * Work on downloads that were not started from a private browsing window. michael@0: */ michael@0: get PUBLIC() "{Downloads.PUBLIC}", michael@0: /** michael@0: * Work on downloads that were started from a private browsing window. michael@0: */ michael@0: get PRIVATE() "{Downloads.PRIVATE}", michael@0: /** michael@0: * Work on both Downloads.PRIVATE and Downloads.PUBLIC downloads. michael@0: */ michael@0: get ALL() "{Downloads.ALL}", michael@0: michael@0: /** michael@0: * Creates a new Download object. michael@0: * michael@0: * @param aProperties michael@0: * Provides the initial properties for the newly created download. michael@0: * This matches the serializable representation of a Download object. michael@0: * Some of the most common properties in this object include: michael@0: * { michael@0: * source: String containing the URI for the download source. michael@0: * Alternatively, may be an nsIURI, a DownloadSource object, michael@0: * or an object with the following properties: michael@0: * { michael@0: * url: String containing the URI for the download source. michael@0: * isPrivate: Indicates whether the download originated from a michael@0: * private window. If omitted, the download is public. michael@0: * referrer: String containing the referrer URI of the download michael@0: * source. Can be omitted or null if no referrer should michael@0: * be sent or the download source is not HTTP. michael@0: * }, michael@0: * target: String containing the path of the target file. michael@0: * Alternatively, may be an nsIFile, a DownloadTarget object, michael@0: * or an object with the following properties: michael@0: * { michael@0: * path: String containing the path of the target file. michael@0: * }, michael@0: * saver: String representing the class of the download operation. michael@0: * If omitted, defaults to "copy". Alternatively, may be the michael@0: * serializable representation of a DownloadSaver object. michael@0: * } michael@0: * michael@0: * @return {Promise} michael@0: * @resolves The newly created Download object. michael@0: * @rejects JavaScript exception. michael@0: */ michael@0: createDownload: function D_createDownload(aProperties) michael@0: { michael@0: try { michael@0: return Promise.resolve(Download.fromSerializable(aProperties)); michael@0: } catch (ex) { michael@0: return Promise.reject(ex); michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Downloads data from a remote network location to a local file. michael@0: * michael@0: * This download method does not provide user interface, or the ability to michael@0: * cancel or restart the download programmatically. For that, you should michael@0: * obtain a reference to a Download object using the createDownload function. michael@0: * michael@0: * Since the download cannot be restarted, any partially downloaded data will michael@0: * not be kept in case the download fails. michael@0: * michael@0: * @param aSource michael@0: * String containing the URI for the download source. Alternatively, michael@0: * may be an nsIURI or a DownloadSource object. michael@0: * @param aTarget michael@0: * String containing the path of the target file. Alternatively, may michael@0: * be an nsIFile or a DownloadTarget object. michael@0: * @param aOptions michael@0: * An optional object used to control the behavior of this function. michael@0: * You may pass an object with a subset of the following fields: michael@0: * { michael@0: * isPrivate: Indicates whether the download originated from a michael@0: * private window. michael@0: * } michael@0: * michael@0: * @return {Promise} michael@0: * @resolves When the download has finished successfully. michael@0: * @rejects JavaScript exception if the download failed. michael@0: */ michael@0: fetch: function (aSource, aTarget, aOptions) { michael@0: return this.createDownload({ michael@0: source: aSource, michael@0: target: aTarget, michael@0: }).then(function D_SD_onSuccess(aDownload) { michael@0: if (aOptions && ("isPrivate" in aOptions)) { michael@0: aDownload.source.isPrivate = aOptions.isPrivate; michael@0: } michael@0: return aDownload.start(); michael@0: }); michael@0: }, michael@0: michael@0: /** michael@0: * Retrieves the specified type of DownloadList object. There is one download michael@0: * list for each type, and this method always retrieves a reference to the michael@0: * same download list when called with the same argument. michael@0: * michael@0: * Calling this function may cause the list of public downloads to be reloaded michael@0: * from the previous session, if it wasn't loaded already. michael@0: * michael@0: * @param aType michael@0: * This can be Downloads.PUBLIC, Downloads.PRIVATE, or Downloads.ALL. michael@0: * Downloads added to the Downloads.PUBLIC and Downloads.PRIVATE lists michael@0: * are reflected in the Downloads.ALL list, and downloads added to the michael@0: * Downloads.ALL list are also added to either the Downloads.PUBLIC or michael@0: * the Downloads.PRIVATE list based on their properties. michael@0: * michael@0: * @return {Promise} michael@0: * @resolves The requested DownloadList or DownloadCombinedList object. michael@0: * @rejects JavaScript exception. michael@0: */ michael@0: getList: function (aType) michael@0: { michael@0: if (!this._promiseListsInitialized) { michael@0: this._promiseListsInitialized = Task.spawn(function () { michael@0: let publicList = new DownloadList(); michael@0: let privateList = new DownloadList(); michael@0: let combinedList = new DownloadCombinedList(publicList, privateList); michael@0: michael@0: try { michael@0: yield DownloadIntegration.addListObservers(publicList, false); michael@0: yield DownloadIntegration.addListObservers(privateList, true); michael@0: yield DownloadIntegration.initializePublicDownloadList(publicList); michael@0: } catch (ex) { michael@0: Cu.reportError(ex); michael@0: } michael@0: michael@0: let publicSummary = yield this.getSummary(Downloads.PUBLIC); michael@0: let privateSummary = yield this.getSummary(Downloads.PRIVATE); michael@0: let combinedSummary = yield this.getSummary(Downloads.ALL); michael@0: michael@0: yield publicSummary.bindToList(publicList); michael@0: yield privateSummary.bindToList(privateList); michael@0: yield combinedSummary.bindToList(combinedList); michael@0: michael@0: this._lists[Downloads.PUBLIC] = publicList; michael@0: this._lists[Downloads.PRIVATE] = privateList; michael@0: this._lists[Downloads.ALL] = combinedList; michael@0: }.bind(this)); michael@0: } michael@0: michael@0: return this._promiseListsInitialized.then(() => this._lists[aType]); michael@0: }, michael@0: michael@0: /** michael@0: * Promise resolved when the initialization of the download lists has michael@0: * completed, or null if initialization has never been requested. michael@0: */ michael@0: _promiseListsInitialized: null, michael@0: michael@0: /** michael@0: * After initialization, this object is populated with one key for each type michael@0: * of download list that can be returned (Downloads.PUBLIC, Downloads.PRIVATE, michael@0: * or Downloads.ALL). The values are the DownloadList objects. michael@0: */ michael@0: _lists: {}, michael@0: michael@0: /** michael@0: * Retrieves the specified type of DownloadSummary object. There is one michael@0: * download summary for each type, and this method always retrieves a michael@0: * reference to the same download summary when called with the same argument. michael@0: * michael@0: * Calling this function does not cause the list of public downloads to be michael@0: * reloaded from the previous session. The summary will behave as if no michael@0: * downloads are present until the getList method is called. michael@0: * michael@0: * @param aType michael@0: * This can be Downloads.PUBLIC, Downloads.PRIVATE, or Downloads.ALL. michael@0: * michael@0: * @return {Promise} michael@0: * @resolves The requested DownloadList or DownloadCombinedList object. michael@0: * @rejects JavaScript exception. michael@0: */ michael@0: getSummary: function (aType) michael@0: { michael@0: if (aType != Downloads.PUBLIC && aType != Downloads.PRIVATE && michael@0: aType != Downloads.ALL) { michael@0: throw new Error("Invalid aType argument."); michael@0: } michael@0: michael@0: if (!(aType in this._summaries)) { michael@0: this._summaries[aType] = new DownloadSummary(); michael@0: } michael@0: michael@0: return Promise.resolve(this._summaries[aType]); michael@0: }, michael@0: michael@0: /** michael@0: * This object is populated by the getSummary method with one key for each michael@0: * type of object that can be returned (Downloads.PUBLIC, Downloads.PRIVATE, michael@0: * or Downloads.ALL). The values are the DownloadSummary objects. michael@0: */ michael@0: _summaries: {}, michael@0: michael@0: /** michael@0: * Returns the system downloads directory asynchronously. michael@0: * Mac OSX: michael@0: * User downloads directory michael@0: * XP/2K: michael@0: * My Documents/Downloads michael@0: * Vista and others: michael@0: * User downloads directory michael@0: * Linux: michael@0: * XDG user dir spec, with a fallback to Home/Downloads michael@0: * Android: michael@0: * standard downloads directory i.e. /sdcard michael@0: * michael@0: * @return {Promise} michael@0: * @resolves The downloads directory string path. michael@0: */ michael@0: getSystemDownloadsDirectory: function D_getSystemDownloadsDirectory() { michael@0: return DownloadIntegration.getSystemDownloadsDirectory(); michael@0: }, michael@0: michael@0: /** michael@0: * Returns the preferred downloads directory based on the user preferences michael@0: * in the current profile asynchronously. michael@0: * michael@0: * @return {Promise} michael@0: * @resolves The downloads directory string path. michael@0: */ michael@0: getPreferredDownloadsDirectory: function D_getPreferredDownloadsDirectory() { michael@0: return DownloadIntegration.getPreferredDownloadsDirectory(); michael@0: }, michael@0: michael@0: /** michael@0: * Returns the temporary directory where downloads are placed before the michael@0: * final location is chosen, or while the document is opened temporarily michael@0: * with an external application. This may or may not be the system temporary michael@0: * directory, based on the platform asynchronously. michael@0: * michael@0: * @return {Promise} michael@0: * @resolves The downloads directory string path. michael@0: */ michael@0: getTemporaryDownloadsDirectory: function D_getTemporaryDownloadsDirectory() { michael@0: return DownloadIntegration.getTemporaryDownloadsDirectory(); michael@0: }, michael@0: michael@0: /** michael@0: * Constructor for a DownloadError object. When you catch an exception during michael@0: * a download, you can use this to verify if "ex instanceof Downloads.Error", michael@0: * before reading the exception properties with the error details. michael@0: */ michael@0: Error: DownloadError, michael@0: };