Bug 928250 - Display an informative error when the selected download directory is write-protected, instead of failing silently. r=paolo

This commit is contained in:
ISHIKAWA, Chiaki 2014-03-04 18:24:51 +01:00
parent 06559f1667
commit 6352fe2769

View File

@ -1,5 +1,5 @@
/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2; js-indent-level: 2; -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/*
# 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
@ -35,12 +35,9 @@ nsUnknownContentTypeDialogProgressListener.prototype = {
// Look for error notifications and display alert to user.
onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
if ( aStatus != Components.results.NS_OK ) {
// Get prompt service.
var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
.getService( Components.interfaces.nsIPromptService );
// Display error alert (using text supplied by back-end).
// FIXME this.dialog is undefined?
prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
Services.prompt.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
// Close the dialog.
this.helperAppDlg.onCancel();
if ( this.helperAppDlg.mDialog ) {
@ -182,6 +179,20 @@ nsUnknownContentTypeDialog.prototype = {
this.mLauncher.setWebProgressListener(progressListener);
},
//
// displayBadPermissionAlert()
//
// Diplay an alert panel about the bad permission of folder/directory.
//
displayBadPermissionAlert: function () {
let bundle =
Services.strings.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
Services.prompt.alert(this.dialog,
bundle.GetStringFromName("badPermissions.title"),
bundle.GetStringFromName("badPermissions"));
},
// promptForSaveToFile: Display file picker dialog and return selected file.
// This is called by the External Helper App Service
// after the ucth dialog calls |saveToDisk| with a null
@ -193,6 +204,7 @@ nsUnknownContentTypeDialog.prototype = {
//
// Note - this function is called without a dialog, so it cannot access any part
// of the dialog XUL as other functions on this object do.
promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, aForcePrompt) {
throw new Components.Exception("Async version must be used", Components.results.NS_ERROR_NOT_AVAILABLE);
},
@ -204,9 +216,9 @@ nsUnknownContentTypeDialog.prototype = {
let prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
let bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].
getService(Components.interfaces.nsIStringBundleService).
createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
let bundle =
Services.strings
.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
Task.spawn(function() {
if (!aForcePrompt) {
@ -226,22 +238,13 @@ nsUnknownContentTypeDialog.prototype = {
result = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExtension);
}
catch (ex) {
if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
let prompter = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
getService(Components.interfaces.nsIPromptService);
// Display error alert (using text supplied by back-end)
prompter.alert(this.dialog,
bundle.GetStringFromName("badPermissions.title"),
bundle.GetStringFromName("badPermissions"));
aLauncher.saveDestinationAvailable(null);
return;
}
// When the default download directory is write-protected,
// prompt the user for a different target file.
}
// Check to make sure we have a valid directory, otherwise, prompt
if (result) {
// This path is taken when we have a writable default download directory.
aLauncher.saveDestinationAvailable(result);
return;
}
@ -278,7 +281,7 @@ nsUnknownContentTypeDialog.prototype = {
picker.appendFilters( nsIFilePicker.filterAll );
// Default to lastDir if it is valid, otherwise use the user's default
// downloads directory. getPreferredDownloadsDirectory should always
// downloads directory. getPreferredDownloadsDirectory should always
// return a valid directory path, so we can safely default to it.
let preferredDir = yield Downloads.getPreferredDownloadsDirectory();
picker.displayDirectory = new FileUtils.File(preferredDir);
@ -306,13 +309,31 @@ nsUnknownContentTypeDialog.prototype = {
if (result.exists())
result.remove(false);
}
catch (e) { }
catch (ex) {
// As it turns out, the failure to remove the file, for example due to
// permission error, will be handled below eventually somehow.
}
var newDir = result.parent.QueryInterface(Components.interfaces.nsILocalFile);
// Do not store the last save directory as a pref inside the private browsing mode
gDownloadLastDir.setFile(aLauncher.source, newDir);
result = this.validateLeafName(newDir, result.leafName, null);
try {
result = this.validateLeafName(newDir, result.leafName, null);
}
catch (ex) {
// When the chosen download directory is write-protected,
// display an informative error message.
// In all cases, download will be stopped.
if (ex.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED) {
this.displayBadPermissionAlert();
aLauncher.saveDestinationAvailable(null);
return;
}
}
}
aLauncher.saveDestinationAvailable(result);
}.bind(this));
@ -334,12 +355,15 @@ nsUnknownContentTypeDialog.prototype = {
* if aLeafName is non-empty
* @return nsILocalFile
* the created file
* @throw an error such as permission doesn't allow creation of
* file, etc.
*/
validateLeafName: function (aLocalFolder, aLeafName, aFileExt)
{
if (!(aLocalFolder && isUsableDirectory(aLocalFolder)))
return null;
if (!(aLocalFolder && isUsableDirectory(aLocalFolder))) {
throw new Components.Exception("Destination directory non-existing or permission error",
Components.results.NS_ERROR_FILE_ACCESS_DENIED);
}
// Remove any leading periods, since we don't want to save hidden files
// automatically.
aLeafName = aLeafName.replace(/^\.+/, "");
@ -348,6 +372,8 @@ nsUnknownContentTypeDialog.prototype = {
aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
aLocalFolder.append(aLeafName);
// The following assignment can throw an exception, but
// is now caught properly in the caller of validateLeafName.
var createdFile = DownloadPaths.createNiceUniqueFile(aLocalFolder);
#ifdef XP_WIN
@ -847,8 +873,7 @@ nsUnknownContentTypeDialog.prototype = {
// Show alert and try again.
var bundle = this.dialogElement("strings");
var msg = bundle.getFormattedString("badApp", [this.dialogElement("otherHandler").getAttribute("path")]);
var svc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
svc.alert(this.mDialog, bundle.getString("badApp.title"), msg);
Services.prompt.alert(this.mDialog, bundle.getString("badApp.title"), msg);
// Disable the OK button.
this.mDialog.document.documentElement.getButton("accept").disabled = true;