mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-21 17:59:34 +00:00
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:
parent
d451e5831e
commit
3427b3b32d
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user