diff options
Diffstat (limited to 'toolkit/components/jsdownloads/src/DownloadImport.jsm')
-rw-r--r-- | toolkit/components/jsdownloads/src/DownloadImport.jsm | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/toolkit/components/jsdownloads/src/DownloadImport.jsm b/toolkit/components/jsdownloads/src/DownloadImport.jsm new file mode 100644 index 000000000..5fb7fd0c7 --- /dev/null +++ b/toolkit/components/jsdownloads/src/DownloadImport.jsm @@ -0,0 +1,193 @@ +/* -*- 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)); + } +} + |