--- a/browser/components/downloads/DownloadsCommon.jsm
+++ b/browser/components/downloads/DownloadsCommon.jsm
@@ -457,25 +457,25 @@ this.DownloadsCommon = {
} else {
promiseShouldLaunch = Promise.resolve(true);
}
promiseShouldLaunch.then(shouldLaunch => {
if (!shouldLaunch) {
return;
}
-
+
// Actually open the file.
try {
if (aMimeInfo && aMimeInfo.preferredAction == aMimeInfo.useHelperApp) {
aMimeInfo.launchWithFile(aFile);
return;
}
} catch (ex) { }
-
+
// If either we don't have the mime info, or the preferred action failed,
// attempt to launch the file directly.
try {
aFile.launch();
} catch (ex) {
// If launch fails, try sending it through the system's external "file:"
// URL handler.
Cc["@mozilla.org/uriloader/external-protocol-service;1"]
@@ -516,59 +516,93 @@ this.DownloadsCommon = {
}
}
},
/**
* Displays an alert message box which asks the user if they want to
* unblock the downloaded file or not.
*
- * @param aVerdict
- * The detailed reason why the download was blocked, according to the
- * "Downloads.Error.BLOCK_VERDICT_" constants. If an unknown reason is
- * specified, "Downloads.Error.BLOCK_VERDICT_MALWARE" is assumed.
- * @param aOwnerWindow
- * The window with which this action is associated.
+ * @param options
+ * An object with the following properties:
+ * {
+ * verdict:
+ * The detailed reason why the download was blocked, according to
+ * the "Downloads.Error.BLOCK_VERDICT_" constants. If an unknown
+ * reason is specified, "Downloads.Error.BLOCK_VERDICT_MALWARE" is
+ * assumed.
+ * window:
+ * The window with which this action is associated.
+ * dialogType:
+ * String that determines which actions are available:
+ * - "unblock" to offer just "unblock".
+ * - "chooseUnblock" to offer "unblock" and "confirmBlock".
+ * - "chooseOpen" to offer "open" and "confirmBlock".
+ * }
*
* @return {Promise}
* @resolves String representing the action that should be executed:
+ * - "open" to allow the download and open the file.
* - "unblock" to allow the download without opening the file.
* - "confirmBlock" to delete the blocked data permanently.
* - "cancel" to do nothing and cancel the operation.
*/
- confirmUnblockDownload: Task.async(function* (aVerdict, aOwnerWindow) {
+ confirmUnblockDownload: Task.async(function* ({ verdict, window,
+ dialogType }) {
let s = DownloadsCommon.strings;
- let title = s.unblockHeader;
- let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
- (Ci.nsIPrompt.BUTTON_TITLE_CANCEL * Ci.nsIPrompt.BUTTON_POS_1);
- let type = "";
- let message = s.unblockTip;
- let unblockButton = s.unblockButtonContinue;
- let confirmBlockButton = s.unblockButtonCancel;
+
+ // All the dialogs have an action button and a cancel button, while only
+ // some of them have an additonal button to remove the file. The cancel
+ // button must always be the one at BUTTON_POS_1 because this is the value
+ // returned by confirmEx when using ESC or closing the dialog (bug 345067).
+ let title = s.unblockHeaderUnblock;
+ let firstButtonText = s.unblockButtonUnblock;
+ let firstButtonAction = "unblock";
+ let buttonFlags =
+ (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
+ (Ci.nsIPrompt.BUTTON_TITLE_CANCEL * Ci.nsIPrompt.BUTTON_POS_1);
- switch (aVerdict) {
+ switch (dialogType) {
+ case "unblock":
+ // Use only the unblock action. The default is to cancel.
+ buttonFlags += Ci.nsIPrompt.BUTTON_POS_1_DEFAULT;
+ break;
+ case "chooseUnblock":
+ // Use the unblock and remove file actions. The default is remove file.
+ buttonFlags +=
+ (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2) +
+ Ci.nsIPrompt.BUTTON_POS_2_DEFAULT;
+ break;
+ case "chooseOpen":
+ // Use the unblock and open file actions. The default is open file.
+ title = s.unblockHeaderOpen;
+ firstButtonText = s.unblockButtonOpen;
+ firstButtonAction = "open";
+ buttonFlags +=
+ (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2) +
+ Ci.nsIPrompt.BUTTON_POS_0_DEFAULT;
+ break;
+ default:
+ Cu.reportError("Unexpected dialog type: " + dialogType);
+ return "cancel";
+ }
+
+ let message;
+ switch (verdict) {
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
- type = s.unblockTypeUncommon;
- buttonFlags += (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2) +
- Ci.nsIPrompt.BUTTON_POS_0_DEFAULT;
+ message = s.unblockTypeUncommon;
break;
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
- type = s.unblockTypePotentiallyUnwanted;
- buttonFlags += (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2) +
- Ci.nsIPrompt.BUTTON_POS_2_DEFAULT;
+ message = s.unblockTypePotentiallyUnwanted;
break;
default: // Assume Downloads.Error.BLOCK_VERDICT_MALWARE
- type = s.unblockTypeMalware;
- buttonFlags += Ci.nsIPrompt.BUTTON_POS_1_DEFAULT;
+ message = s.unblockTypeMalware;
break;
}
-
- if (type) {
- message = type + "\n\n" + message;
- }
+ message += "\n\n" + s.unblockTip;
Services.ww.registerNotification(function onOpen(subj, topic) {
if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
// Make sure to listen for "DOMContentLoaded" because it is fired
// before the "load" event.
subj.addEventListener("DOMContentLoaded", function onLoad() {
subj.removeEventListener("DOMContentLoaded", onLoad);
if (subj.document.documentURI ==
@@ -579,22 +613,20 @@ this.DownloadsCommon = {
// Change the dialog to use a warning icon.
dialog.classList.add("alert-dialog");
}
}
});
}
});
- // The ordering of the ok/cancel buttons is used this way to allow "cancel"
- // to have the same result as hitting the ESC or Close button (see bug 345067).
- let rv = Services.prompt.confirmEx(aOwnerWindow, title, message, buttonFlags,
- unblockButton, null, confirmBlockButton,
- null, {});
- return ["unblock", "cancel", "confirmBlock"][rv];
+ let rv = Services.prompt.confirmEx(window, title, message, buttonFlags,
+ firstButtonText, null,
+ s.unblockButtonConfirmBlock, null, {});
+ return [firstButtonAction, "cancel", "confirmBlock"][rv];
}),
};
XPCOMUtils.defineLazyGetter(this.DownloadsCommon, "log", () => {
return DownloadsLogger.log.bind(DownloadsLogger);
});
XPCOMUtils.defineLazyGetter(this.DownloadsCommon, "error", () => {
return DownloadsLogger.error.bind(DownloadsLogger);
--- a/browser/components/downloads/DownloadsViewUI.jsm
+++ b/browser/components/downloads/DownloadsViewUI.jsm
@@ -232,17 +232,17 @@ this.DownloadsViewUI.DownloadElementShel
}
} else if (this.download.canceled) {
stateLabel = s.stateCanceled;
} else if (this.download.error.becauseBlockedByParentalControls) {
stateLabel = s.stateBlockedParentalControls;
} else if (this.download.error.becauseBlockedByReputationCheck) {
switch (this.download.error.reputationCheckVerdict) {
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
- stateLabel = s.blockedUncommon;
+ stateLabel = s.blockedUncommon2;
break;
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
stateLabel = s.blockedPotentiallyUnwanted;
break;
default: // Assume Downloads.Error.BLOCK_VERDICT_MALWARE
stateLabel = s.blockedMalware;
break;
}
@@ -266,21 +266,28 @@ this.DownloadsViewUI.DownloadElementShel
/**
* Shows the appropriate unblock dialog based on the verdict, and executes the
* action selected by the user in the dialog, which may involve unblocking,
* opening or removing the file.
*
* @param window
* The window to which the dialog should be anchored.
+ * @param dialogType
+ * Can be "unblock", "chooseUnblock", or "chooseOpen".
*/
- confirmUnblock(window) {
- let verdict = this.download.error.reputationCheckVerdict;
- DownloadsCommon.confirmUnblockDownload(verdict, window).then(action => {
- if (action == "unblock") {
+ confirmUnblock(window, dialogType) {
+ DownloadsCommon.confirmUnblockDownload({
+ verdict: this.download.error.reputationCheckVerdict,
+ window,
+ dialogType,
+ }).then(action => {
+ if (action == "open") {
+ return this.download.unblock().then(() => this.downloadsCmd_open());
+ } else if (action == "unblock") {
return this.download.unblock();
} else if (action == "confirmBlock") {
return this.download.confirmBlock();
}
}).catch(Cu.reportError);
},
/**
@@ -318,16 +325,18 @@ this.DownloadsViewUI.DownloadElementShel
switch (aCommand) {
case "downloadsCmd_retry":
return this.download.canceled || this.download.error;
case "downloadsCmd_pauseResume":
return this.download.hasPartialData && !this.download.error;
case "downloadsCmd_openReferrer":
return !!this.download.source.referrer;
case "downloadsCmd_confirmBlock":
+ case "downloadsCmd_chooseUnblock":
+ case "downloadsCmd_chooseOpen":
case "downloadsCmd_unblock":
return this.download.hasBlockedData;
}
return false;
},
downloadsCmd_cancel() {
// This is the correct way to avoid race conditions when cancelling.
--- a/browser/components/downloads/content/allDownloadsViewOverlay.js
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.js
@@ -372,17 +372,25 @@ HistoryDownloadElementShell.prototype =
}
if (this._historyDownload) {
let uri = NetUtil.newURI(this.download.source.url);
PlacesUtils.bhistory.removePage(uri);
}
},
downloadsCmd_unblock() {
- this.confirmUnblock(window);
+ this.confirmUnblock(window, "unblock");
+ },
+
+ downloadsCmd_chooseUnblock() {
+ this.confirmUnblock(window, "chooseUnblock");
+ },
+
+ downloadsCmd_chooseOpen() {
+ this.confirmUnblock(window, "chooseOpen");
},
// Returns whether or not the download handled by this shell should
// show up in the search results for the given term. Both the display
// name for the download and the url are searched.
matchesSearchTerm(aTerm) {
if (!aTerm) {
return true;
--- a/browser/components/downloads/content/allDownloadsViewOverlay.xul
+++ b/browser/components/downloads/content/allDownloadsViewOverlay.xul
@@ -58,16 +58,20 @@
events="focus,select,contextmenu"
oncommandupdate="goUpdateDownloadCommands();">
<command id="downloadsCmd_pauseResume"
oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
<command id="downloadsCmd_cancel"
oncommand="goDoCommand('downloadsCmd_cancel')"/>
<command id="downloadsCmd_unblock"
oncommand="goDoCommand('downloadsCmd_unblock')"/>
+ <command id="downloadsCmd_chooseUnblock"
+ oncommand="goDoCommand('downloadsCmd_chooseUnblock')"/>
+ <command id="downloadsCmd_chooseOpen"
+ oncommand="goDoCommand('downloadsCmd_chooseOpen')"/>
<command id="downloadsCmd_confirmBlock"
oncommand="goDoCommand('downloadsCmd_confirmBlock')"/>
<command id="downloadsCmd_open"
oncommand="goDoCommand('downloadsCmd_open')"/>
<command id="downloadsCmd_show"
oncommand="goDoCommand('downloadsCmd_show')"/>
<command id="downloadsCmd_retry"
oncommand="goDoCommand('downloadsCmd_retry')"/>
@@ -87,18 +91,18 @@
label="&cmd.resume.label;"
accesskey="&cmd.resume.accesskey;"/>
<menuitem command="downloadsCmd_cancel"
class="downloadCancelMenuItem"
label="&cmd.cancel.label;"
accesskey="&cmd.cancel.accesskey;"/>
<menuitem command="downloadsCmd_unblock"
class="downloadUnblockMenuItem"
- label="&cmd.unblock.label;"
- accesskey="&cmd.unblock.accesskey;"/>
+ label="&cmd.unblock2.label;"
+ accesskey="&cmd.unblock2.accesskey;"/>
<menuitem command="cmd_delete"
class="downloadRemoveFromHistoryMenuItem"
label="&cmd.removeFromHistory.label;"
accesskey="&cmd.removeFromHistory.accesskey;"/>
<menuitem command="downloadsCmd_show"
class="downloadShowMenuItem"
#ifdef XP_MACOSX
label="&cmd.showMac.label;"
--- a/browser/components/downloads/content/download.xml
+++ b/browser/components/downloads/content/download.xml
@@ -58,19 +58,22 @@
tooltiptext="&cmd.showMac.label;"
#else
tooltiptext="&cmd.show.label;"
#endif
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
<xul:button class="downloadButton downloadConfirmBlock downloadIconCancel"
tooltiptext="&cmd.removeFile.label;"
oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_confirmBlock');"/>
- <xul:button class="downloadButton downloadUnblock downloadIconShow"
- tooltiptext="&cmd.unblock.label;"
- oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_unblock');"/>
+ <xul:button class="downloadButton downloadChooseUnblock downloadIconShow"
+ tooltiptext="&cmd.chooseUnblock.label;"
+ oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_chooseUnblock');"/>
+ <xul:button class="downloadButton downloadChooseOpen downloadIconShow"
+ tooltiptext="&cmd.chooseOpen.label;"
+ oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_chooseOpen');"/>
</xul:stack>
</content>
</binding>
<binding id="download-toolbarbutton"
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
<content>
<children />
--- a/browser/components/downloads/content/downloads.css
+++ b/browser/components/downloads/content/downloads.css
@@ -122,23 +122,32 @@ richlistitem.download button {
.download-state:not( [state="8"] /* Blocked (dirty) */)
.downloadConfirmBlock,
.download-state[state="8"]:not(.temporary-block)
.downloadConfirmBlock,
.download-state[state="8"].temporary-block:not([verdict="Malware"])
.downloadConfirmBlock,
/* Blocked (dirty) downloads that have not been confirmed and
- have temporary data, for cases other than Malware. */
+ have temporary data, for the Potentially Unwanted case. */
.download-state:not( [state="8"] /* Blocked (dirty) */)
- .downloadUnblock,
+ .downloadChooseUnblock,
.download-state[state="8"]:not(.temporary-block)
- .downloadUnblock,
-.download-state[state="8"].temporary-block[verdict="Malware"]
- .downloadUnblock,
+ .downloadChooseUnblock,
+.download-state[state="8"].temporary-block:not([verdict="PotentiallyUnwanted"])
+ .downloadChooseUnblock,
+
+/* Blocked (dirty) downloads that have not been confirmed and
+ have temporary data, for the Uncommon case. */
+.download-state:not( [state="8"] /* Blocked (dirty) */)
+ .downloadChooseOpen,
+.download-state[state="8"]:not(.temporary-block)
+ .downloadChooseOpen,
+.download-state[state="8"].temporary-block:not([verdict="Uncommon"])
+ .downloadChooseOpen,
.download-state:not(:-moz-any([state="2"], /* Failed */
[state="3"]) /* Canceled */)
.downloadRetry,
.download-state:not( [state="1"] /* Finished */)
.downloadShow
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -1087,17 +1087,27 @@ DownloadsViewItem.prototype = {
cmd_delete() {
DownloadsCommon.removeAndFinalizeDownload(this.download);
PlacesUtils.bhistory.removePage(
NetUtil.newURI(this.download.source.url));
},
downloadsCmd_unblock() {
DownloadsPanel.hidePanel();
- this.confirmUnblock(window);
+ this.confirmUnblock(window, "unblock");
+ },
+
+ downloadsCmd_chooseUnblock() {
+ DownloadsPanel.hidePanel();
+ this.confirmUnblock(window, "chooseUnblock");
+ },
+
+ downloadsCmd_chooseOpen() {
+ DownloadsPanel.hidePanel();
+ this.confirmUnblock(window, "chooseOpen");
},
downloadsCmd_open() {
this.download.launch().catch(Cu.reportError);
// We explicitly close the panel here to give the user the feedback that
// their click has been received, and we're handling the action.
// Otherwise, we'd have to wait for the file-type handler to execute
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -18,16 +18,20 @@
<command id="downloadsCmd_doDefault"
oncommand="goDoCommand('downloadsCmd_doDefault')"/>
<command id="downloadsCmd_pauseResume"
oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
<command id="downloadsCmd_cancel"
oncommand="goDoCommand('downloadsCmd_cancel')"/>
<command id="downloadsCmd_unblock"
oncommand="goDoCommand('downloadsCmd_unblock')"/>
+ <command id="downloadsCmd_chooseUnblock"
+ oncommand="goDoCommand('downloadsCmd_chooseUnblock')"/>
+ <command id="downloadsCmd_chooseOpen"
+ oncommand="goDoCommand('downloadsCmd_chooseOpen')"/>
<command id="downloadsCmd_confirmBlock"
oncommand="goDoCommand('downloadsCmd_confirmBlock')"/>
<command id="downloadsCmd_open"
oncommand="goDoCommand('downloadsCmd_open')"/>
<command id="downloadsCmd_show"
oncommand="goDoCommand('downloadsCmd_show')"/>
<command id="downloadsCmd_retry"
oncommand="goDoCommand('downloadsCmd_retry')"/>
@@ -66,18 +70,18 @@
label="&cmd.resume.label;"
accesskey="&cmd.resume.accesskey;"/>
<menuitem command="downloadsCmd_cancel"
class="downloadCancelMenuItem"
label="&cmd.cancel.label;"
accesskey="&cmd.cancel.accesskey;"/>
<menuitem command="downloadsCmd_unblock"
class="downloadUnblockMenuItem"
- label="&cmd.unblock.label;"
- accesskey="&cmd.unblock.accesskey;"/>
+ label="&cmd.unblock2.label;"
+ accesskey="&cmd.unblock2.accesskey;"/>
<menuitem command="cmd_delete"
class="downloadRemoveFromHistoryMenuItem"
label="&cmd.removeFromHistory.label;"
accesskey="&cmd.removeFromHistory.accesskey;"/>
<menuitem command="downloadsCmd_show"
class="downloadShowMenuItem"
#ifdef XP_MACOSX
label="&cmd.showMac.label;"
--- a/browser/components/downloads/test/browser/browser_confirm_unblock_download.js
+++ b/browser/components/downloads/test/browser/browser_confirm_unblock_download.js
@@ -26,21 +26,91 @@ function addDialogOpenObserver(buttonAct
let doc = subj.document.documentElement;
doc.getButton(buttonAction).click();
}
});
}
});
}
-add_task(function* test_confirm_unblock_dialog_unblock() {
- addDialogOpenObserver("accept");
- let result = yield DownloadsCommon.confirmUnblockDownload(Downloads.Error.BLOCK_VERDICT_MALWARE,
- window);
- is(result, "unblock");
+function* assertDialogResult({ args, buttonToClick, expectedResult }) {
+ addDialogOpenObserver(buttonToClick);
+ is(yield DownloadsCommon.confirmUnblockDownload(args), expectedResult);
+}
+
+/**
+ * Tests the "unblock" dialog, for each of the possible verdicts.
+ */
+add_task(function* test_unblock_dialog_unblock() {
+ for (let verdict of [Downloads.Error.BLOCK_VERDICT_MALWARE,
+ Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED,
+ Downloads.Error.BLOCK_VERDICT_UNCOMMON]) {
+ let args = { verdict, window, dialogType: "unblock" };
+
+ // Test both buttons.
+ yield assertDialogResult({
+ args,
+ buttonToClick: "accept",
+ expectedResult: "unblock",
+ });
+ yield assertDialogResult({
+ args,
+ buttonToClick: "cancel",
+ expectedResult: "cancel",
+ });
+ }
});
-add_task(function* test_confirm_unblock_dialog_keep_safe() {
- addDialogOpenObserver("cancel");
- let result = yield DownloadsCommon.confirmUnblockDownload(Downloads.Error.BLOCK_VERDICT_MALWARE,
- window);
- is(result, "cancel");
+/**
+ * Tests the "chooseUnblock" dialog for potentially unwanted downloads.
+ */
+add_task(function* test_chooseUnblock_dialog() {
+ let args = {
+ verdict: Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED,
+ window,
+ dialogType: "chooseUnblock",
+ };
+
+ // Test each of the three buttons.
+ yield assertDialogResult({
+ args,
+ buttonToClick: "accept",
+ expectedResult: "unblock",
+ });
+ yield assertDialogResult({
+ args,
+ buttonToClick: "cancel",
+ expectedResult: "cancel",
+ });
+ yield assertDialogResult({
+ args,
+ buttonToClick: "extra1",
+ expectedResult: "confirmBlock",
+ });
});
+
+/**
+ * Tests the "chooseOpen" dialog for uncommon downloads.
+ */
+add_task(function* test_chooseOpen_dialog() {
+ let args = {
+ verdict: Downloads.Error.BLOCK_VERDICT_UNCOMMON,
+ window,
+ dialogType: "chooseOpen",
+ };
+
+ // Test each of the three buttons.
+ yield assertDialogResult({
+ args,
+ buttonToClick: "accept",
+ expectedResult: "open",
+ });
+ yield assertDialogResult({
+ args,
+ buttonToClick: "cancel",
+ expectedResult: "cancel",
+ });
+ yield assertDialogResult({
+ args,
+ buttonToClick: "extra1",
+ expectedResult: "confirmBlock",
+ });
+});
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
@@ -61,28 +61,37 @@
<!ENTITY cmd.copyDownloadLink.label "Copy Download Link">
<!ENTITY cmd.copyDownloadLink.accesskey "L">
<!ENTITY cmd.removeFromHistory.label "Remove From History">
<!ENTITY cmd.removeFromHistory.accesskey "e">
<!ENTITY cmd.clearList.label "Clear List">
<!ENTITY cmd.clearList.accesskey "a">
<!ENTITY cmd.clearDownloads.label "Clear Downloads">
<!ENTITY cmd.clearDownloads.accesskey "D">
-<!-- LOCALIZATION NOTE (cmd.unblock.label):
- This command may be shown in the context menu, as a menu button item, or as
- a text link when malware or potentially unwanted downloads are blocked.
+<!-- LOCALIZATION NOTE (cmd.unblock2.label):
+ This command is shown in the context menu when downloads are blocked.
-->
-<!ENTITY cmd.unblock.label "Unblock">
-<!ENTITY cmd.unblock.accesskey "U">
+<!ENTITY cmd.unblock2.label "Allow Download">
+<!ENTITY cmd.unblock2.accesskey "o">
<!-- LOCALIZATION NOTE (cmd.removeFile.label):
- This command may be shown in the context menu or as a menu button label
- when malware or potentially unwanted downloads are blocked.
+ This is the tooltip of the action button shown when malware is blocked.
-->
<!ENTITY cmd.removeFile.label "Remove File">
-<!ENTITY cmd.removeFile.accesskey "m">
+<!-- LOCALIZATION NOTE (cmd.chooseUnblock.tooltip):
+ This is the tooltip of the action button shown when potentially unwanted
+ downloads are blocked. This opens a dialog where the user can choose
+ whether to unblock or remove the download. Removing is the default option.
+ -->
+<!ENTITY cmd.chooseUnblock.label "Remove File or Allow Download">
+<!-- LOCALIZATION NOTE (cmd.chooseOpen.tooltip):
+ This is the tooltip of the action button shown when uncommon downloads are
+ blocked.This opens a dialog where the user can choose whether to open the
+ file or remove the download. Opening is the default option.
+ -->
+<!ENTITY cmd.chooseOpen.label "Open or Remove File">
<!-- LOCALIZATION NOTE (blocked.label):
Shown as a tag before the file name for some types of blocked downloads.
Note: This string doesn't exist in the UI yet. See bug 1053890.
-->
<!ENTITY blocked.label "BLOCKED">
<!-- LOCALIZATION NOTE (learnMore.label):
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.properties
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.properties
@@ -34,41 +34,43 @@ stateBlockedParentalControls=Blocked by
# languages:
# http://support.microsoft.com/kb/174360
stateBlockedPolicy=Blocked by your security zone policy
# LOCALIZATION NOTE (stateDirty):
# Indicates that the download was blocked after scanning.
stateDirty=Blocked: May contain a virus or spyware
# LOCALIZATION NOTE (blockedMalware, blockedPotentiallyUnwanted,
-# blockedUncommon):
+# blockedUncommon2):
# These strings are shown in the panel for some types of blocked downloads, and
# are immediately followed by the "Learn More" link, thus they must end with a
# period. You may need to adjust "downloadDetails.width" in "downloads.dtd" if
# this turns out to be longer than the other existing status strings.
# Note: These strings don't exist in the UI yet. See bug 1053890.
blockedMalware=This file contains a virus or malware.
blockedPotentiallyUnwanted=This file may harm your computer.
-blockedUncommon=This file may not be safe to open.
+blockedUncommon2=This file is not commonly downloaded.
-# LOCALIZATION NOTE (unblockHeader, unblockTypeMalware,
-# unblockTypePotentiallyUnwanted, unblockTypeUncommon,
-# unblockTip, unblockButtonContinue, unblockButtonCancel):
+# LOCALIZATION NOTE (unblockHeaderUnblock, unblockHeaderOpen,
+# unblockTypeMalware, unblockTypePotentiallyUnwanted,
+# unblockTypeUncommon, unblockTip, unblockButtonOpen,
+# unblockButtonUnblock, unblockButtonConfirmBlock):
# These strings are displayed in the dialog shown when the user asks a blocked
# download to be unblocked. The severity of the threat is expressed in
# descending order by the unblockType strings, it is higher for files detected
# as malware and lower for uncommon downloads.
-# Note: These strings don't exist in the UI yet. See bug 1053890.
-unblockHeader=Are you sure you want to unblock this file?
+unblockHeaderUnblock=Are you sure you want to allow this download?
+unblockHeaderOpen=Are you sure you want to open this file?
unblockTypeMalware=This file contains a virus or other malware that will harm your computer.
unblockTypePotentiallyUnwanted=This file, disguised as a helpful download, will make unexpected changes to your programs and settings.
unblockTypeUncommon=This file has been downloaded from an unfamiliar and potentially dangerous website and may not be safe to open.
unblockTip=You can search for an alternate download source or try to download the file again later.
-unblockButtonContinue=Unblock anyway
-unblockButtonCancel=Keep me safe
+unblockButtonOpen=Open
+unblockButtonUnblock=Allow download
+unblockButtonConfirmBlock=Remove file
# LOCALIZATION NOTE (sizeWithUnits):
# %1$S is replaced with the size number, and %2$S with the measurement unit.
sizeWithUnits=%1$S %2$S
sizeUnknown=Unknown size
# LOCALIZATION NOTE (shortTimeLeftSeconds, shortTimeLeftMinutes,
# shortTimeLeftHours, shortTimeLeftDays):