/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; this.EXPORTED_SYMBOLS = [ "DownloadImport", ]; // Globals const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Downloads", "resource://gre/modules/Downloads.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm") XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Sqlite", "resource://gre/modules/Sqlite.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); /** * These values come from the previous interface * nsIDownloadManager, which has now been deprecated. * These are the only types of download states that * we will import. */ const DOWNLOAD_NOTSTARTED = -1; const DOWNLOAD_DOWNLOADING = 0; const DOWNLOAD_PAUSED = 4; const DOWNLOAD_QUEUED = 5; // DownloadImport /** * Provides an object that has a method to import downloads * from the previous SQLite storage format. * * @param aList A DownloadList where each successfully * imported download will be added. * @param aPath The path to the database file. */ this.DownloadImport = function (aList, aPath) { this.list = aList; this.path = aPath; } this.DownloadImport.prototype = { /** * Imports unfinished downloads from the previous SQLite storage * format (supporting schemas 7 and up), to the new Download object * format. Each imported download will be added to the DownloadList * * @return {Promise} * @resolves When the operation has completed (i.e., every download * from the previous database has been read and added to * the DownloadList) */ import: function () { return Task.spawn(function* task_DI_import() { let connection = yield Sqlite.openConnection({ path: this.path }); try { let schemaVersion = yield connection.getSchemaVersion(); // We don't support schemas older than version 7 (from 2007) // - Version 7 added the columns mimeType, preferredApplication // and preferredAction in 2007 // - Version 8 added the column autoResume in 2007 // (if we encounter version 7 we will treat autoResume = false) // - Version 9 is the last known version, which added a unique // GUID text column that is not used here if (schemaVersion < 7) { throw new Error("Unable to import in-progress downloads because " + "the existing profile is too old."); } let rows = yield connection.execute("SELECT * FROM moz_downloads"); for (let row of rows) { try { // Get the DB row data let source = row.getResultByName("source"); let target = row.getResultByName("target"); let tempPath = row.getResultByName("tempPath"); let startTime = row.getResultByName("startTime"); let state = row.getResultByName("state"); let referrer = row.getResultByName("referrer"); let maxBytes = row.getResultByName("maxBytes"); let mimeType = row.getResultByName("mimeType"); let preferredApplication = row.getResultByName("preferredApplication"); let preferredAction = row.getResultByName("preferredAction"); let entityID = row.getResultByName("entityID"); let autoResume = false; try { autoResume = (row.getResultByName("autoResume") == 1); } catch (ex) { // autoResume wasn't present in schema version 7 } if (!source) { throw new Error("Attempted to import a row with an empty " + "source column."); } let resumeDownload = false; switch (state) { case DOWNLOAD_NOTSTARTED: case DOWNLOAD_QUEUED: case DOWNLOAD_DOWNLOADING: resumeDownload = true; break; case DOWNLOAD_PAUSED: resumeDownload = autoResume; break; default: // We won't import downloads in other states continue; } // Transform the data let targetPath = NetUtil.newURI(target) .QueryInterface(Ci.nsIFileURL).file.path; let launchWhenSucceeded = (preferredAction != Ci.nsIMIMEInfo.saveToDisk); let downloadOptions = { source: { url: source, referrer: referrer }, target: { path: targetPath, partFilePath: tempPath, }, saver: { type: "copy", entityID: entityID }, startTime: new Date(startTime / 1000), totalBytes: maxBytes, hasPartialData: !!tempPath, tryToKeepPartialData: true, launchWhenSucceeded: launchWhenSucceeded, contentType: mimeType, launcherPath: preferredApplication }; // Paused downloads that should not be auto-resumed are considered // in a "canceled" state. if (!resumeDownload) { downloadOptions.canceled = true; } let download = yield Downloads.createDownload(downloadOptions); yield this.list.add(download); if (resumeDownload) { download.start().catch(() => {}); } else { yield download.refresh(); } } catch (ex) { Cu.reportError("Error importing download: " + ex); } } } catch (ex) { Cu.reportError(ex); } finally { yield connection.close(); } }.bind(this)); } }