Bug 945429. r=wesj

This commit is contained in:
Richard Newman 2014-03-10 16:12:52 -07:00
parent 8c16249a71
commit 1cba8eb3c0

View File

@ -5,13 +5,15 @@
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
const APK_MIME_TYPE = "application/vnd.android.package-archive";
const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir"; const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir";
const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download"; const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Prompt.jsm");
Cu.import("resource://gre/modules/HelperApps.jsm"); Cu.import("resource://gre/modules/HelperApps.jsm");
Cu.import("resource://gre/modules/Prompt.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// HelperApp Launcher Dialog // HelperApp Launcher Dialog
@ -23,7 +25,110 @@ HelperAppLauncherDialog.prototype = {
classID: Components.ID("{e9d277a0-268a-4ec2-bb8c-10fdf3e44611}"), classID: Components.ID("{e9d277a0-268a-4ec2-bb8c-10fdf3e44611}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]), QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
getNativeWindow: function () {
try {
let win = Services.wm.getMostRecentWindow("navigator:browser");
if (win && win.NativeWindow) {
return win.NativeWindow;
}
} catch (e) {
}
return null;
},
/**
* Returns false if `url` represents a local or special URL that we don't
* wish to ever download.
*
* Returns true otherwise.
*/
_canDownload: function (url, alreadyResolved=false) {
Services.console.logStringMessage("_canDownload: " + url);
// The common case.
if (url.schemeIs("http") ||
url.schemeIs("https") ||
url.schemeIs("ftp")) {
Services.console.logStringMessage("_canDownload: true\n");
return true;
}
// The less-common opposite case.
if (url.schemeIs("chrome") ||
url.schemeIs("jar") ||
url.schemeIs("resource") ||
url.schemeIs("wyciwyg")) {
Services.console.logStringMessage("_canDownload: false\n");
return false;
}
// For all other URIs, try to resolve them to an inner URI, and check that.
if (!alreadyResolved) {
let ioSvc = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
let innerURI = ioSvc.newChannelFromURI(url).URI;
if (!url.equals(innerURI)) {
Services.console.logStringMessage("_canDownload: recursing.\n");
return this._canDownload(innerURI, true);
}
}
if (url.schemeIs("file")) {
// If it's in our app directory or profile directory, we never ever
// want to do anything with it, including saving to disk or passing the
// file to another application.
let file = url.QueryInterface(Ci.nsIFileURL).file;
// TODO: pref blacklist?
let appRoot = FileUtils.getFile("XREExeF", []);
if (appRoot.contains(file, true)) {
Services.console.logStringMessage("_canDownload: appRoot.\n");
return false;
}
let profileRoot = FileUtils.getFile("ProfD", []);
if (profileRoot.contains(file, true)) {
Services.console.logStringMessage("_canDownload: prof dir.\n");
return false;
}
Services.console.logStringMessage("_canDownload: safe.\n");
return true;
}
// Anything else is fine to download.
return true;
},
/**
* Returns true if `launcher` represents a download for which we wish
* to prompt.
*/
_shouldPrompt: function (launcher) {
let mimeType = this._getMimeTypeFromLauncher(launcher);
// Straight equality: nsIMIMEInfo normalizes.
return APK_MIME_TYPE == mimeType;
},
show: function hald_show(aLauncher, aContext, aReason) { show: function hald_show(aLauncher, aContext, aReason) {
if (!this._canDownload(aLauncher.source)) {
aLauncher.cancel(Cr.NS_BINDING_ABORTED);
let win = this.getNativeWindow();
if (!win) {
// Oops.
Services.console.logStringMessage("Refusing download, but can't show a toast.");
return;
}
Services.console.logStringMessage("Refusing download of non-downloadable file.");
let bundle = Services.strings.createBundle("chrome://browser/locale/handling.properties");
let failedText = bundle.GetStringFromName("protocol.failed");
win.toast.show(failedText, "long");
return;
}
let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let defaultHandler = new Object(); let defaultHandler = new Object();
@ -31,13 +136,13 @@ HelperAppLauncherDialog.prototype = {
mimeType: aLauncher.MIMEInfo.MIMEType, mimeType: aLauncher.MIMEInfo.MIMEType,
}); });
// Add a fake intent for save to disk at the top of the list // Add a fake intent for save to disk at the top of the list.
apps.unshift({ apps.unshift({
name: bundle.GetStringFromName("helperapps.saveToDisk"), name: bundle.GetStringFromName("helperapps.saveToDisk"),
packageName: "org.mozilla.gecko.Download", packageName: "org.mozilla.gecko.Download",
iconUri: "drawable://icon", iconUri: "drawable://icon",
launch: function() { launch: function() {
// Reset the preferredAction here // Reset the preferredAction here.
aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk; aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk;
aLauncher.saveToDisk(null, false); aLauncher.saveToDisk(null, false);
return true; return true;
@ -65,32 +170,38 @@ HelperAppLauncherDialog.prototype = {
} }
} }
if (apps.length > 1) { // If there's only one choice, and we don't want to prompt, go right ahead
HelperApps.prompt(apps, { // and choose that app automatically.
title: bundle.GetStringFromName("helperapps.pick"), if (!this._shouldPrompt(aLauncher) && (apps.length === 1)) {
buttons: [
bundle.GetStringFromName("helperapps.alwaysUse"),
bundle.GetStringFromName("helperapps.useJustOnce")
]
}, (data) => {
if (data.button < 0)
return;
callback(apps[data.icongrid0]);
if (data.button == 0)
this._setPreferredApp(aLauncher, apps[data.icongrid0]);
});
} else {
callback(apps[0]); callback(apps[0]);
return;
} }
// Otherwise, let's go through the prompt.
HelperApps.prompt(apps, {
title: bundle.GetStringFromName("helperapps.pick"),
buttons: [
bundle.GetStringFromName("helperapps.alwaysUse"),
bundle.GetStringFromName("helperapps.useJustOnce")
]
}, (data) => {
if (data.button < 0) {
return;
}
callback(apps[data.icongrid0]);
if (data.button === 0) {
this._setPreferredApp(aLauncher, apps[data.icongrid0]);
}
});
}, },
_getPrefName: function getPrefName(mimetype) { _getPrefName: function getPrefName(mimetype) {
return "browser.download.preferred." + mimetype.replace("\\", "."); return "browser.download.preferred." + mimetype.replace("\\", ".");
}, },
_getMimeTypeFromLauncher: function getMimeTypeFromLauncher(launcher) { _getMimeTypeFromLauncher: function (launcher) {
let mime = launcher.MIMEInfo.MIMEType; let mime = launcher.MIMEInfo.MIMEType;
if (!mime) if (!mime)
mime = ContentAreaUtils.getMIMETypeForURI(launcher.source) || ""; mime = ContentAreaUtils.getMIMETypeForURI(launcher.source) || "";
@ -105,7 +216,7 @@ HelperAppLauncherDialog.prototype = {
try { try {
return Services.prefs.getCharPref(this._getPrefName(mime)); return Services.prefs.getCharPref(this._getPrefName(mime));
} catch(ex) { } catch(ex) {
Services.console.logStringMessage("Error getting pref for " + mime + " " + ex); Services.console.logStringMessage("Error getting pref for " + mime + ".");
} }
return null; return null;
}, },