diff --git a/common/modules/downloads.jsm b/common/modules/downloads.jsm index 73d69f26..1bd6f65a 100644 --- a/common/modules/downloads.jsm +++ b/common/modules/downloads.jsm @@ -7,7 +7,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("downloads", { exports: ["Download", "Downloads", "downloads"], - use: ["io", "services", "template", "util"] + use: ["io", "prefs", "services", "template", "util"] }, this); Cu.import("resource://gre/modules/DownloadUtils.jsm", this); @@ -19,17 +19,19 @@ var states = iter([v, k.slice(prefix.length).toLowerCase()] .toObject(); var Download = Class("Download", { - init: function init(id, document) { + init: function init(id, list) { let self = XPCSafeJSObjectWrapper(services.downloadManager.getDownload(id)); self.__proto__ = this; this.instance = this; + this.list = list; this.nodes = {}; util.xmlToDom(
  • - {self.displayName} + {self.displayName} {self.targetFile.path} @@ -50,7 +52,7 @@ var Download = Class("Download", { {self.source.spec}
  • , - document, this.nodes); + this.list.document, this.nodes); for (let [key, node] in Iterator(this.nodes)) { node.dactylDownload = self; @@ -81,6 +83,7 @@ var Download = Class("Download", { allowed: Class.memoize(function () let (self = this) ({ get cancel() self.cancelable && self.inState(["downloading", "paused", "starting"]), get delete() !this.cancel && self.targetFile.exists(), + get launch() self.targetFile.exists() && self.inState(["finished"]), get pause() self.inState(["downloading"]), get remove() self.inState(["blocked_parental", "blocked_policy", "canceled", "dirty", "failed", "finished"]), @@ -102,6 +105,31 @@ var Download = Class("Download", { delete: function delete() { this.targetFile.remove(false); this.updateStatus(); + }, + launch: function launch() { + let self = this; + // Behavior mimics that of the builtin Download Manager. + function action() { + try { + if (this.MIMEInfo && this.MIMEInfo.preferredAction == this.MIMEInfo.useHelperApp) + this.MIMEInfo.launchWithFile(file) + else + file.launch(); + } + catch (e) { + services.externalProtocol.loadUrl(this.target); + } + } + + let file = io.File(this.targetFile); + if (file.isExecutable() && prefs.get("browser.download.manager.alertOnEXEOpen", true)) + this.list.modules.commandline.input("This will launch an executable download. Continue? (yes/[no]) ", + function (resp) { + if (resp && resp.match(/^y(es)?$/i)) + action.call(self); + }); + else + action.call(this); } }, @@ -181,7 +209,7 @@ var DownloadList = Class("DownloadList", addDownload: function addDownload(id) { if (!(id in this.downloads)) { - this.downloads[id] = Download(id, this.document); + this.downloads[id] = Download(id, this); let index = values(this.downloads).sort(function (a, b) a.compare(b)) .indexOf(this.downloads[id]); diff --git a/common/modules/services.jsm b/common/modules/services.jsm index 74cac15e..1f39cf2c 100644 --- a/common/modules/services.jsm +++ b/common/modules/services.jsm @@ -38,6 +38,7 @@ var Services = Module("Services", { this.add("downloadManager", "@mozilla.org/download-manager;1", Ci.nsIDownloadManager); this.add("environment", "@mozilla.org/process/environment;1", Ci.nsIEnvironment); this.add("extensionManager", "@mozilla.org/extensions/manager;1", Ci.nsIExtensionManager); + this.add("externalProtocol", "@mozilla.org/uriloader/external-protocol-service;1", Ci.nsIExternalProtocolService); this.add("favicon", "@mozilla.org/browser/favicon-service;1", Ci.nsIFaviconService); this.add("focus", "@mozilla.org/focus-manager;1", Ci.nsIFocusManager); this.add("fuel", "@mozilla.org/fuel/application;1", Ci.extIApplication);