Bug 1366591,
Bug 28211 - When save to Sent (or Drafts or Templates) fails, save to subfolder of local folders. r=jorgk,aceman
When save to Sent, Drafts or Templates folders fails, e.g., due to IMAP connection issues,
prompts now occurs to save to <local folder account>/Sent-<account>, <local folder account>/Drafts-<account> or
<local folder account>/Templates-<account>, where <account> is the account name having the network issue.
Also supports sending by right-click on Outbox after messages composed and saved with "Send Later".
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -3884,17 +3884,17 @@ function ComposeCanClose()
// call window.focus, since we need to pop up a dialog
// and therefore need to be visible (to prevent user confusion)
window.focus();
let draftFolderURI = gCurrentIdentity.draftFolder;
let draftFolderName = MailUtils.getFolderForURI(draftFolderURI).prettyName;
let result = Services.prompt
.confirmEx(window,
getComposeBundle().getString("saveDlogTitle"),
- getComposeBundle().getFormattedString("saveDlogMessages",[draftFolderName]),
+ getComposeBundle().getFormattedString("saveDlogMessages2", [draftFolderName]),
(Services.prompt.BUTTON_TITLE_SAVE * Services.prompt.BUTTON_POS_0) +
(Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1) +
(Services.prompt.BUTTON_TITLE_DONT_SAVE * Services.prompt.BUTTON_POS_2),
null, null, null,
null, {value:0});
switch (result)
{
case 0: //Save
--- a/mail/locales/en-US/chrome/messenger/messengercompose/composeMsgs.properties
+++ b/mail/locales/en-US/chrome/messenger/messengercompose/composeMsgs.properties
@@ -108,18 +108,20 @@ smtpAuthMechNotSupported=The Outgoing se
smtpAuthenticationNotSupported=Unable to authenticate to Outgoing server (SMTP) %S. It does not support authentication (SMTP-AUTH) but you have chosen to use authentication. Please change the 'Authentication method' to 'None' in the 'Account Settings | Outgoing Server (SMTP)' or contact your email service provider for instructions.
# LOCALIZATION NOTE (errorIllegalLocalPart): %s is an email address with an illegal localpart
errorIllegalLocalPart=There are non-ASCII characters in the local part of the recipient address %s. This is not yet supported. Please change this address and try again.
## Strings used for the save message dialog shown when the user closes a message compose window
saveDlogTitle=Save Message
-## LOCALIZATION NOTE (SaveDlogMessages): %1$S is the folder name
-saveDlogMessages=Message has not been sent. Do you want to save the message in your drafts folder (%1$S)?
+## LOCALIZATION NOTE (saveDlogMessages2): Do not translate the words %1$S and \n.
+## %1$S is replaced by the folder name configured for saving drafts (typically the "Drafts" folder).
+## Translate "Write" to match the translation of item "windowTitlePrefix" below.
+saveDlogMessages2=Message has not been sent or saved in your drafts folder (%1$S).\n"Save" copies the message to your drafts folder (%1$S) and closes the Write window.\n"Don't Save" closes the Write window without saving a draft.\n"Cancel" allows you continue writing without saving a draft.
## generics string
defaultSubject=(no subject)
chooseFileToAttach=Attach File(s)
genericFailureExplanation=Please verify that your account settings are correct and try again.
## LOCALIZATION NOTE (undisclosedRecipients): this string must use only US_ASCII characters
undisclosedRecipients=undisclosed-recipients
@@ -326,22 +328,44 @@ smtpEnterPasswordPrompt=Enter your passw
## and %2$S where the user name should appear.
smtpEnterPasswordPromptWithUsername=Enter your password for %2$S on %1$S:
smtpEnterPasswordPromptTitle=Outgoing server (SMTP) Password Required
# LOCALIZATION NOTE (removeAttachmentMsgs): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/Localization_and_Plurals
removeAttachmentMsgs=Remove Attachment;Remove Attachments
-## LOCALIZATION NOTE(errorSavingMsg): Do not translate the word %S. It
-## will be replaced with the name of the folder the message is being saved to.
-errorSavingMsg=There was an error saving the message to %S. Retry?
+## LOCALIZATION NOTE(promptToSaveSentLocally): Do not translate the stings %1$S, %2$S, %3$S and \n.
+## %2$S will be replaced with the account name. $1$S will be replaced by the folder name
+## configured to contain saved sent messages (typically the "Sent" folder).
+## %3$S will be replaced with the local folders account name (typically "Local Folders").
+## Translate "Write" to match the translation of item "windowTitlePrefix" above.
+promptToSaveSentLocally=Your message was sent but not saved to your sent folder (%1$S) probably because of network errors.\n"Retry" attempts the save again.\n"Save" copies the message to %3$S/%1$S-%2$S and closes the Write window if it is present.\n"Cancel" does not save the sent message and closes the Write window if it is present.
errorFilteringMsg=Your message has been sent and saved, but there was an error while running message filters on it.
errorCloudFileAuth.title=Authentication Error
+## LOCALIZATION NOTE(promptToSaveDraftLocally): Do not translate the stings %1$S, %2$S, %3$S and \n.
+## %2$S will be replaced with the account name. $1$S will be replaced by the folder name
+## configured to contain saved draft messages (typically the "Drafts" folder).
+## %3$S will be replaced with the local folders account name (typically "Local Folders").
+promptToSaveDraftLocally=Your draft message was not saved to your drafts folder (%1$S) probably because of network errors.\n"Retry" attempts to save again.\n"Save" copies the message to %3$S/%1$S-%2$S and you can continue writing.\n"Cancel" allows you to continue writing without saving your draft.
+buttonLabelRetry=Retry
+
+## LOCALIZATION NOTE(promptToSaveTemplateLocally): Do not translate the stings %1$S, %2$S, %3$S and \n.
+## %2$S will be replaced with the account name. $1$S will be replaced by the folder name
+## configured to contain saved templates (typically the "Templates" folder).
+## %3$S will be replaced with the local folders account name (typically "Local Folders").
+promptToSaveTemplateLocally=Your template was not saved to your templates folder (%1$S) probably because of network errors.\n"Retry" attempts to save again.\n"Save" copies the message to %3$S/%1$S-%2$S and you can continue writing.\n"Cancel" allows you to continue writing without saving your template.
+
+## LOCALIZATION NOTE(saveToLocalFoldersFailed): Message appears after normal
+## save fails (e.g., to Sent) and save to Local Folders also fails. This could
+## occur if network is down and filesystem problems are present such as disk
+## full, permission issues or hardware failure.
+saveToLocalFoldersFailed=Unable to save your message to local folders. Possibly out of file storage space.
+
## LOCALIZATION NOTE(errorCloudFileAuth.message):
## %1$S is the name of the online storage service against which the authentication failed.
errorCloudFileAuth.message=Unable to authenticate to %1$S.
errorCloudFileUpload.title=Upload Error
## LOCALIZATION NOTE(errorCloudFileUpload.message):
## %1$S is the name of the online storage service against which the uploading failed.
## %2$S is the name of the file that failed to upload.
--- a/mailnews/compose/src/nsMsgSend.cpp
+++ b/mailnews/compose/src/nsMsgSend.cpp
@@ -3621,41 +3621,62 @@ nsMsgComposeAndSend::DeliverAsMailExit(n
NS_IMETHODIMP
nsMsgComposeAndSend::DeliverAsNewsExit(nsIURI *aUrl, nsresult aExitCode)
{
DoDeliveryExitProcessing(aUrl, aExitCode, mSendMailAlso);
return NS_OK;
}
-bool nsMsgComposeAndSend::CanSaveMessagesToFolder(const char *folderURL)
+nsresult
+nsMsgComposeAndSend::GetIncomingServer(const char *folderURL, nsIMsgIncomingServer **aServer)
{
nsresult rv;
nsCOMPtr<nsIRDFService> rdf(do_GetService("@mozilla.org/rdf/rdf-service;1", &rv));
if (NS_FAILED(rv))
- return false;
+ return rv;
nsCOMPtr<nsIRDFResource> resource;
rv = rdf->GetResource(nsDependentCString(folderURL), getter_AddRefs(resource));
if (NS_FAILED(rv))
- return false;
+ return rv;
nsCOMPtr <nsIMsgFolder> thisFolder;
thisFolder = do_QueryInterface(resource, &rv);
if (NS_FAILED(rv) || !thisFolder)
- return false;
+ return rv;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = thisFolder->GetServer(getter_AddRefs(server));
- if (NS_FAILED(rv) || !server)
+ if (NS_FAILED(rv))
+ return rv;
+ if (!server)
+ return NS_ERROR_NULL_POINTER;
+
+ server.forget(aServer);
+ return NS_OK;
+}
+
+bool
+nsMsgComposeAndSend::CanSaveMessagesToFolder(const char *folderURL)
+{
+ bool canSave = false;
+ // Get pointer to server.
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ nsresult rv = GetIncomingServer(folderURL, getter_AddRefs(server));
+ if (NS_FAILED(rv))
return false;
// See if we are allowed to save/file msgs to this folder.
- bool canSave;
- rv = server->GetCanFileMessagesOnServer(&canSave);
+ if (server)
+ {
+ rv = server->GetCanFileMessagesOnServer(&canSave);
+ if (NS_FAILED(rv))
+ canSave = false;
+ }
return canSave;
}
//
// Now, start the appropriate copy operation.
//
nsresult
nsMsgComposeAndSend::DoFcc()
@@ -3827,36 +3848,123 @@ nsMsgComposeAndSend::NotifyListenerOnSto
nsresult rv;
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
- nsString msg;
- const char16_t *formatStrings[] = { mSavedToFolderName.get() };
-
- rv = bundle->FormatStringFromName(u"errorSavingMsg",
- formatStrings, 1,
- getter_Copies(msg));
+ // Obtain account name for local folders.
+ nsString localFoldersAccountName;
+ nsCOMPtr<nsIMsgAccountManager> accountManager =
+ do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
{
- bool retry = false;
- nsMsgAskBooleanQuestionByString(prompt, msg.get(), &retry, nullptr);
- if (retry)
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ rv = accountManager->GetLocalFoldersServer(getter_AddRefs(server));
+ if (NS_SUCCEEDED(rv))
+ rv = server->GetPrettyName(localFoldersAccountName);
+ }
+ if (NS_FAILED(rv) || localFoldersAccountName.IsEmpty())
+ {
+ // Unable to obtain localFoldersAccountName.
+ Fail(NS_OK, nullptr, &aStatus);
+ return NS_ERROR_FAILURE;
+ }
+
+ // Get the user account name where "save to" failed.
+ nsString accountName;
+ const char* fcc = mCompFields->GetFcc();
+ if (fcc && *fcc)
+ {
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ rv = GetIncomingServer(fcc, getter_AddRefs(server));
+ if (NS_SUCCEEDED(rv) && server)
+ rv = server->GetPrettyName(accountName);
+ }
+ else
+ rv = NS_ERROR_FAILURE;
+ if (NS_FAILED(rv) || accountName.IsEmpty())
+ {
+ // Unable to obtain accountName.
+ Fail(NS_OK, nullptr, &aStatus);
+ return NS_ERROR_FAILURE;
+ }
+
+ const char16_t *formatStrings[] = { mSavedToFolderName.get(), accountName.get(),
+ localFoldersAccountName.get() };
+
+ nsString msg;
+ switch (m_deliver_mode)
+ {
+ case nsMsgDeliverNow:
+ case nsMsgSendUnsent:
+ rv = bundle->FormatStringFromName(u"promptToSaveSentLocally",
+ formatStrings, 3,
+ getter_Copies(msg));
+ break;
+ case nsMsgSaveAsDraft:
+ rv = bundle->FormatStringFromName(u"promptToSaveDraftLocally",
+ formatStrings, 3,
+ getter_Copies(msg));
+ break;
+ case nsMsgSaveAsTemplate:
+ rv = bundle->FormatStringFromName(u"promptToSaveTemplateLocally",
+ formatStrings, 3,
+ getter_Copies(msg));
+ break;
+ default:
+ rv = NS_ERROR_UNEXPECTED;
+ }
+ NS_ENSURE_SUCCESS(rv, rv);
+ int32_t buttonPressed = 0;
+ bool showCheckBox = false;
+ uint32_t buttonFlags = (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
+ (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL) +
+ (nsIPrompt::BUTTON_POS_2 * nsIPrompt::BUTTON_TITLE_SAVE);
+ nsString dialogTitle, buttonLabelRetry;
+ bundle->GetStringFromName(u"SaveDialogTitle", getter_Copies(dialogTitle));
+ bundle->GetStringFromName(u"buttonLabelRetry", getter_Copies(buttonLabelRetry));
+ prompt->ConfirmEx(dialogTitle.get(), msg.get(), buttonFlags, buttonLabelRetry.get(),
+ nullptr, nullptr, nullptr, &showCheckBox, &buttonPressed);
+ if (buttonPressed == 0)
+ {
+ // retry button clicked
+ mSendProgress = nullptr; // this was canceled, so we need to clear it.
+ return SendToMagicFolder(m_deliver_mode);
+ }
+
+ bool saveLocally = (buttonPressed == 2);
+
+ if (saveLocally)
+ {
+ // Try to save to Local Folders/<account name>.
+ // Pass in "nsMsgDeliverNow" so draft saves too. Also, fcc pointer
+ // is nullptr to tell function to save to local folders and not the
+ // configured fcc.
+ rv = MimeDoFCC(mTempFile,
+ nsIMsgSend::nsMsgDeliverNow,
+ mCompFields->GetBcc(),
+ nullptr,
+ mCompFields->GetNewspostUrl());
+
+ if (NS_FAILED(rv))
{
- mSendProgress = nullptr; // this was cancelled, so we need to clear it.
- return SendToMagicFolder(m_deliver_mode);
+ // Save to Local Folders failed. Inform the user.
+ nsCOMPtr<nsIPrompt> prompt;
+ GetDefaultPrompt(getter_AddRefs(prompt));
+ nsMsgDisplayMessageByName(prompt, u"saveToLocalFoldersFailed");
}
}
- // We failed, and the user decided not to retry. So we're just going to
- // fail out. However, give Fail a success code so that it doesn't prompt
- // the user a second time as they already know about the failure.
+ // Failure detected when user saved to default folder and the user did not
+ // retry; instead the user saved to Local Folders or canceled the save. So
+ // just call Fail() with a success code so that it doesn't prompt the user
+ // again since the user already knows about the failure and has reacted.
Fail(NS_OK, nullptr, &aStatus);
}
if (NS_SUCCEEDED(aStatus) &&
!mPerformingSecondFCC && m_messageKey != nsMsgKey_None &&
(m_deliver_mode == nsMsgDeliverNow || m_deliver_mode == nsMsgSendUnsent))
{
nsresult rv = FilterSentMessage();
@@ -4210,31 +4318,23 @@ nsMsgComposeAndSend::MimeDoFCC(nsIFile
const char *bcc_header,
const char *fcc_header,
const char *news_url)
{
nsresult status = NS_OK;
char *ibuffer = nullptr;
uint32_t n;
bool folderIsLocal = true;
- nsCString turi;
+ nsCString tmpUri;
char16_t *printfString = nullptr;
nsString msg;
nsCOMPtr<nsIMsgFolder> folder;
- // Before continuing, just check the user has not cancel the operation
if (mSendProgress)
- {
- bool canceled = false;
- mSendProgress->GetProcessCanceledByUser(&canceled);
- if (canceled)
- return NS_ERROR_ABORT;
- else
- mSendProgress->OnProgressChange(nullptr, nullptr, 0, 0, 0, -1);
- }
+ mSendProgress->OnProgressChange(nullptr, nullptr, 0, 0, 0, -1);
//
// Ok, this is here to keep track of this for 2 copy operations...
//
if (mCopyFile)
{
mCopyFile2 = mCopyFile;
mCopyFile = nullptr;
@@ -4291,33 +4391,113 @@ nsMsgComposeAndSend::MimeDoFCC(nsIFile
// First, we we need to put a Berkeley "From - " delimiter at the head of
// the file for parsing...
//
if (fcc_header && *fcc_header)
GetExistingFolder(nsDependentCString(fcc_header), getter_AddRefs(folder));
if ((mode == nsMsgDeliverNow || mode == nsMsgSendUnsent) && folder)
- turi = fcc_header;
+ {
+ tmpUri = fcc_header;
+ }
+ else if (!fcc_header)
+ {
+ // Set fcc_header to a special folder in Local Folders "account" since can't
+ // save to Sent mbox, typically because imap connection is down. This
+ // folder is created if it doesn't yet exist.
+
+ nsCString folder;
+ // First, in folder string, obtain the uri for the local folders account
+ // which is typically "mailbox://nobody@Local%20Folders/"
+ nsCOMPtr<nsIMsgAccountManager> accountManager =
+ do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv) && accountManager)
+ {
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ rv = accountManager->GetLocalFoldersServer(getter_AddRefs(server));
+ if (NS_SUCCEEDED(rv) && server)
+ {
+ nsCOMPtr<nsIMsgFolder> rootFolder;
+ rv = server->GetRootMsgFolder(getter_AddRefs(rootFolder));
+ if (NS_SUCCEEDED(rv) && rootFolder)
+ {
+ rv = rootFolder->GetURI(folder);
+ folder.Append("/");
+ }
+ }
+ }
+ if (NS_FAILED(rv) || folder.IsEmpty())
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+
+ // Now append the special folder name folder to the local folder uri.
+ switch (m_deliver_mode)
+ {
+ case nsMsgDeliverNow:
+ case nsMsgSendUnsent:
+ case nsMsgSaveAsDraft:
+ case nsMsgSaveAsTemplate:
+ // Typically, this appends "Sent-", "Drafts-" or "Templates-" to folder
+ // and then has the account name appended, e.g., .../Sent-MyImapAccount.
+ folder.Append(NS_ConvertUTF16toUTF8(mSavedToFolderName));
+ folder.Append("-");
+ break;
+ default:
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+
+ // Get the account name where the "save to" failed.
+ nsString accountName;
+ const char* fcc = mCompFields->GetFcc();
+ if (fcc && *fcc)
+ {
+ nsCOMPtr<nsIMsgIncomingServer> server;
+ rv = GetIncomingServer(fcc, getter_AddRefs(server));
+ if (NS_SUCCEEDED(rv) && server)
+ {
+ rv = server->GetPrettyName(accountName);
+ }
+ }
+ else
+ rv = NS_ERROR_FAILURE;
+ if (NS_FAILED(rv) || accountName.IsEmpty())
+ {
+ status = NS_ERROR_FAILURE;
+ goto FAIL;
+ }
+
+ // Now append the imap account name (escaped) to the folder uri.
+ nsCString escAccountName;
+ MsgEscapeString(NS_ConvertUTF16toUTF8(accountName), nsINetUtil::ESCAPE_URL_PATH, escAccountName);
+ folder += escAccountName;
+ fcc_header = ToNewCString(folder);
+ tmpUri = fcc_header;
+ }
else
- GetFolderURIFromUserPrefs(mode, mUserIdentity, turi);
- status = MessageFolderIsLocal(mUserIdentity, mode, turi.get(), &folderIsLocal);
+ {
+ GetFolderURIFromUserPrefs(mode, mUserIdentity, tmpUri);
+ }
+ status = MessageFolderIsLocal(mUserIdentity, mode, tmpUri.get(), &folderIsLocal);
if (NS_FAILED(status))
goto FAIL;
// Tell the user we are copying the message...
mComposeBundle->GetStringFromName(u"copyMessageStart",
getter_Copies(msg));
if (!msg.IsEmpty())
{
nsCOMPtr<nsIRDFService> rdfService = do_GetService(kRDFServiceCID);
if (rdfService)
{
nsCOMPtr<nsIRDFResource> res;
- rdfService->GetResource(turi, getter_AddRefs(res));
+ rdfService->GetResource(tmpUri, getter_AddRefs(res));
nsCOMPtr<nsIMsgFolder> folder = do_QueryInterface(res);
if (folder)
folder->GetName(mSavedToFolderName);
}
if (!mSavedToFolderName.IsEmpty())
printfString = nsTextFormatter::smprintf(msg.get(), mSavedToFolderName.get());
else
printfString = nsTextFormatter::smprintf(msg.get(), "?");
@@ -4639,17 +4819,17 @@ FAIL:
// When we get here, we have to see if we have been successful so far.
// If we have, then we should start up the async copy service operation.
// If we weren't successful, then we should just return the error and
// bail out.
if (NS_SUCCEEDED(status))
{
// If we are here, time to start the async copy service operation!
- status = StartMessageCopyOperation(mCopyFile, mode, turi);
+ status = StartMessageCopyOperation(mCopyFile, mode, tmpUri);
}
return status;
}
//
// This is pretty much a wrapper to the functionality that lives in the
// nsMsgCopy class
//
--- a/mailnews/compose/src/nsMsgSend.h
+++ b/mailnews/compose/src/nsMsgSend.h
@@ -128,16 +128,17 @@
#include "nsWeakReference.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMWindow.h"
#include "nsIMsgComposeSecure.h"
#include "nsAutoPtr.h"
#include "nsMsgAttachmentData.h"
#include "nsIMsgFilterService.h"
#include "nsIMsgOperationListener.h"
+#include "nsMsgIncomingServer.h"
//
// Some necessary defines...
//
#define MIME_BUFFER_SIZE 4096 // must be greater than 1000
// SMTP (RFC821) limit
// Maximum number of bytes we allow in a line before we force
// encoding to base64 if not already QR-encoded or of type message/rfc822.
@@ -193,16 +194,19 @@ public:
nsresult DoFcc();
nsresult StartMessageCopyOperation(nsIFile *aFileSpec,
nsMsgDeliverMode mode,
const nsCString& dest_uri);
nsresult SendToMagicFolder(nsMsgDeliverMode flag);
+ // For the folderURL return the corresponding pointer to the incoming server.
+ nsresult GetIncomingServer(const char *folderURL, nsIMsgIncomingServer **aServer);
+
// Check to see if it's ok to save msgs to the configured folder.
bool CanSaveMessagesToFolder(const char *folderURL);
//
// FCC operations...
//
nsresult MimeDoFCC (nsIFile *input_file,
nsMsgDeliverMode mode,
--- a/suite/locales/en-US/chrome/mailnews/compose/composeMsgs.properties
+++ b/suite/locales/en-US/chrome/mailnews/compose/composeMsgs.properties
@@ -107,18 +107,21 @@ smtpAuthMechNotSupported=The Outgoing se
# LOCALIZATION NOTE (smtpAuthenticationNotSupported): %S is the server hostname
smtpAuthenticationNotSupported=Unable to authenticate to Outgoing server (SMTP) %S. It does not support authentication (SMTP-AUTH) but you have chosen to use authentication. Please change the 'Authentication method' to 'None' in 'Account Settings | Outgoing server (SMTP)' or contact your email service provider for instructions.
# LOCALIZATION NOTE (errorIllegalLocalPart): %s is an email address with an illegal localpart
errorIllegalLocalPart=There are non-ASCII characters in the local part of the recipient address %s. This is not yet supported. Please change this address and try again.
## Strings used for the save message dialog shown when the user closes a message compose window
saveDlogTitle=Save Message
-## LOCALIZATION NOTE (SaveDlogMessages): %1$S is the folder name
-saveDlogMessages=Message has not been sent. Do you want to save the message in your drafts folder (%1$S)?
+
+## LOCALIZATION NOTE (saveDlogMessages2): Do not translate the words %1$S and \n.
+## %1$S is replaced by the folder name configured for saving drafts (typically the "Drafts" folder).
+## Translate "Compose" to match the translation of item "windowTitlePrefix" below.
+saveDlogMessages2=Message has not been sent or saved in your drafts folder (%1$S).\n"Save" copies the message to your drafts folder (%1$S) and closes the Compose window.\n"Don't Save" closes the Compose window without saving a draft.\n"Cancel" allows you continue writing without saving a draft.
## generics string
defaultSubject=(no subject)
chooseFileToAttach=Attach File(s)
##
windowTitlePrefix=Compose:
@@ -233,12 +236,34 @@ renameAttachmentMessage=New attachment n
smtpEnterPasswordPrompt=Enter your password for %S:
## LOCALIZATION NOTE(smtpEnterPasswordPromptWithUsername): Do not translate the
## words %1$S and %2$S. Place the word %1$S where the host name should appear,
## and %2$S where the user name should appear.
smtpEnterPasswordPromptWithUsername=Enter your password for %2$S on %1$S:
smtpEnterPasswordPromptTitle=Outgoing server (SMTP) Server Password Required
-## LOCALIZATION NOTE(errorSavingMsg): Do not translate the word %S. It
-## will be replaced with the name of the folder the message is being saved to.
-errorSavingMsg=There was an error saving the message to %S. Retry?
+## LOCALIZATION NOTE(promptToSaveSentLocally): Do not translate the stings %1$S, %2$S, %3$S and \n.
+## %2$S will be replaced with the account name. $1$S will be replaced by the folder name
+## configured to contain saved sent messages (typically the "Sent" folder).
+## %3$S will be replaced with the local folders account name (typically "Local Folders").
+## Translate "Compose" to match the translation of item "windowTitlePrefix" above.
+promptToSaveSentLocally=Your message was sent but not saved to your sent folder (%1$S) probably because of network errors.\n"Retry" attempts the save again.\n"Save" copies the message to %3$S/%1$S-%2$S and closes the Compose window if it is present.\n"Cancel" does not save the sent message and closes the Compose window if it is present.
errorFilteringMsg=Your message has been sent and saved, but there was an error while running message filters on it.
+
+## LOCALIZATION NOTE(promptToSaveDraftLocally): Do not translate the stings %1$S, %2$S, %3$S and \n.
+## %2$S will be replaced with the account name. $1$S will be replaced by the folder name
+## configured to contain saved draft messages (typically the "Drafts" folder).
+## %3$S will be replaced with the local folders account name (typically "Local Folders").
+promptToSaveDraftLocally=Your draft message was not saved to your drafts folder (%1$S) probably because of network errors.\n"Retry" attempts to save again.\n"Save" copies the message to %3$S/%1$S-%2$S and you can continue writing.\n"Cancel" allows you to continue writing without saving your draft.
+buttonLabelRetry=Retry
+
+## LOCALIZATION NOTE(promptToSaveTemplateLocally): Do not translate the stings %1$S, %2$S, %3$S and \n.
+## %2$S will be replaced with the account name. $1$S will be replaced by the folder name
+## configured to contain saved templates (typically the "Templates" folder).
+## %3$S will be replaced with the local folders account name (typically "Local Folders").
+promptToSaveTemplateLocally=Your template was not saved to your templates folder (%1$S) probably because of network errors.\n"Retry" attempts to save again.\n"Save" copies the message to %3$S/%1$S-%2$S and you can continue writing.\n"Cancel" allows you to continue writing without saving your template.
+
+## LOCALIZATION NOTE(saveToLocalFoldersFailed): Message appears after normal
+## save fails (e.g., to Sent) and save to Local Folders also fails. This could
+## occur if network is down and filesystem problems are present such as disk
+## full, permission issues or hardware failure.
+saveToLocalFoldersFailed=Unable to save your message to local folders. Possibly out of file storage space.
--- a/suite/mailnews/compose/MsgComposeCommands.js
+++ b/suite/mailnews/compose/MsgComposeCommands.js
@@ -2141,17 +2141,17 @@ function ComposeCanClose()
{
// call window.focus, since we need to pop up a dialog
// and therefore need to be visible (to prevent user confusion)
window.focus();
let draftFolderURI = gCurrentIdentity.draftFolder;
let draftFolderName = MailUtils.getFolderForURI(draftFolderURI).prettyName;
switch (Services.prompt.confirmEx(window,
sComposeMsgsBundle.getString("saveDlogTitle"),
- sComposeMsgsBundle.getFormattedString("saveDlogMessages",[draftFolderName]),
+ sComposeMsgsBundle.getFormattedString("saveDlogMessages2", [draftFolderName]),
(Services.prompt.BUTTON_TITLE_SAVE * Services.prompt.BUTTON_POS_0) +
(Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1) +
(Services.prompt.BUTTON_TITLE_DONT_SAVE * Services.prompt.BUTTON_POS_2),
null, null, null, null, {value:0}))
{
case 0: //Save
// we can close immediately if we already autosaved the draft
if (!gContentChanged && !gMsgCompose.bodyModified)