diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/compose/src/nsMsgSendReport.cpp | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/comm/mailnews/compose/src/nsMsgSendReport.cpp b/comm/mailnews/compose/src/nsMsgSendReport.cpp new file mode 100644 index 0000000000..5cab724810 --- /dev/null +++ b/comm/mailnews/compose/src/nsMsgSendReport.cpp @@ -0,0 +1,385 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsMsgSendReport.h" + +#include "msgCore.h" +#include "nsIMsgCompose.h" +#include "nsMsgPrompts.h" +#include "nsError.h" +#include "nsComposeStrings.h" +#include "nsIStringBundle.h" +#include "nsServiceManagerUtils.h" +#include "mozilla/Components.h" + +NS_IMPL_ISUPPORTS(nsMsgProcessReport, nsIMsgProcessReport) + +nsMsgProcessReport::nsMsgProcessReport() { Reset(); } + +nsMsgProcessReport::~nsMsgProcessReport() {} + +/* attribute boolean proceeded; */ +NS_IMETHODIMP nsMsgProcessReport::GetProceeded(bool* aProceeded) { + NS_ENSURE_ARG_POINTER(aProceeded); + *aProceeded = mProceeded; + return NS_OK; +} +NS_IMETHODIMP nsMsgProcessReport::SetProceeded(bool aProceeded) { + mProceeded = aProceeded; + return NS_OK; +} + +/* attribute nsresult error; */ +NS_IMETHODIMP nsMsgProcessReport::GetError(nsresult* aError) { + NS_ENSURE_ARG_POINTER(aError); + *aError = mError; + return NS_OK; +} +NS_IMETHODIMP nsMsgProcessReport::SetError(nsresult aError) { + mError = aError; + return NS_OK; +} + +/* attribute wstring message; */ +NS_IMETHODIMP nsMsgProcessReport::GetMessage(char16_t** aMessage) { + NS_ENSURE_ARG_POINTER(aMessage); + *aMessage = ToNewUnicode(mMessage); + return NS_OK; +} +NS_IMETHODIMP nsMsgProcessReport::SetMessage(const char16_t* aMessage) { + mMessage = aMessage; + return NS_OK; +} + +/* void Reset (); */ +NS_IMETHODIMP nsMsgProcessReport::Reset() { + mProceeded = false; + mError = NS_OK; + mMessage.Truncate(); + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsMsgSendReport, nsIMsgSendReport) + +nsMsgSendReport::nsMsgSendReport() { + uint32_t i; + for (i = 0; i <= SEND_LAST_PROCESS; i++) + mProcessReport[i] = new nsMsgProcessReport(); + + Reset(); +} + +nsMsgSendReport::~nsMsgSendReport() { + uint32_t i; + for (i = 0; i <= SEND_LAST_PROCESS; i++) mProcessReport[i] = nullptr; +} + +/* attribute long currentProcess; */ +NS_IMETHODIMP nsMsgSendReport::GetCurrentProcess(int32_t* aCurrentProcess) { + NS_ENSURE_ARG_POINTER(aCurrentProcess); + *aCurrentProcess = mCurrentProcess; + return NS_OK; +} +NS_IMETHODIMP nsMsgSendReport::SetCurrentProcess(int32_t aCurrentProcess) { + if (aCurrentProcess < 0 || aCurrentProcess > SEND_LAST_PROCESS) + return NS_ERROR_ILLEGAL_VALUE; + + mCurrentProcess = aCurrentProcess; + if (mProcessReport[mCurrentProcess]) + mProcessReport[mCurrentProcess]->SetProceeded(true); + + return NS_OK; +} + +/* attribute long deliveryMode; */ +NS_IMETHODIMP nsMsgSendReport::GetDeliveryMode(int32_t* aDeliveryMode) { + NS_ENSURE_ARG_POINTER(aDeliveryMode); + *aDeliveryMode = mDeliveryMode; + return NS_OK; +} +NS_IMETHODIMP nsMsgSendReport::SetDeliveryMode(int32_t aDeliveryMode) { + mDeliveryMode = aDeliveryMode; + return NS_OK; +} + +/* void Reset (); */ +NS_IMETHODIMP nsMsgSendReport::Reset() { + uint32_t i; + for (i = 0; i <= SEND_LAST_PROCESS; i++) + if (mProcessReport[i]) mProcessReport[i]->Reset(); + + mCurrentProcess = 0; + mDeliveryMode = 0; + mAlreadyDisplayReport = false; + + return NS_OK; +} + +/* void setProceeded (in long process, in boolean proceeded); */ +NS_IMETHODIMP nsMsgSendReport::SetProceeded(int32_t process, bool proceeded) { + if (process < process_Current || process > SEND_LAST_PROCESS) + return NS_ERROR_ILLEGAL_VALUE; + + if (process == process_Current) process = mCurrentProcess; + + if (!mProcessReport[process]) return NS_ERROR_NOT_INITIALIZED; + + return mProcessReport[process]->SetProceeded(proceeded); +} + +/* void setError (in long process, in nsresult error, in boolean + * overwriteError); */ +NS_IMETHODIMP nsMsgSendReport::SetError(int32_t process, nsresult newError, + bool overwriteError) { + if (process < process_Current || process > SEND_LAST_PROCESS) + return NS_ERROR_ILLEGAL_VALUE; + + if (process == process_Current) { + if (mCurrentProcess == process_Current) + // We don't know what we're currently trying to do + return NS_ERROR_ILLEGAL_VALUE; + + process = mCurrentProcess; + } + + if (!mProcessReport[process]) return NS_ERROR_NOT_INITIALIZED; + + nsresult currError = NS_OK; + mProcessReport[process]->GetError(&currError); + if (overwriteError || NS_SUCCEEDED(currError)) + return mProcessReport[process]->SetError(newError); + else + return NS_OK; +} + +/* void setMessage (in long process, in wstring message, in boolean + * overwriteMessage); */ +NS_IMETHODIMP nsMsgSendReport::SetMessage(int32_t process, + const char16_t* message, + bool overwriteMessage) { + if (process < process_Current || process > SEND_LAST_PROCESS) + return NS_ERROR_ILLEGAL_VALUE; + + if (process == process_Current) { + if (mCurrentProcess == process_Current) + // We don't know what we're currently trying to do + return NS_ERROR_ILLEGAL_VALUE; + + process = mCurrentProcess; + } + + if (!mProcessReport[process]) return NS_ERROR_NOT_INITIALIZED; + + nsString currMessage; + mProcessReport[process]->GetMessage(getter_Copies(currMessage)); + if (overwriteMessage || currMessage.IsEmpty()) + return mProcessReport[process]->SetMessage(message); + else + return NS_OK; +} + +/* nsIMsgProcessReport getProcessReport (in long process); */ +NS_IMETHODIMP nsMsgSendReport::GetProcessReport(int32_t process, + nsIMsgProcessReport** _retval) { + NS_ENSURE_ARG_POINTER(_retval); + if (process < process_Current || process > SEND_LAST_PROCESS) + return NS_ERROR_ILLEGAL_VALUE; + + if (process == process_Current) { + if (mCurrentProcess == process_Current) + // We don't know what we're currently trying to do + return NS_ERROR_ILLEGAL_VALUE; + + process = mCurrentProcess; + } + + NS_IF_ADDREF(*_retval = mProcessReport[process]); + return NS_OK; +} + +NS_IMETHODIMP nsMsgSendReport::DisplayReport(mozIDOMWindowProxy* window, + bool showErrorOnly, + bool dontShowReportTwice, + nsresult* _retval) { + NS_ENSURE_ARG_POINTER(_retval); + + NS_ENSURE_TRUE(mCurrentProcess >= 0 && mCurrentProcess <= SEND_LAST_PROCESS, + NS_ERROR_NOT_INITIALIZED); + + nsresult currError = NS_OK; + mProcessReport[mCurrentProcess]->GetError(&currError); + *_retval = currError; + + if (dontShowReportTwice && mAlreadyDisplayReport) return NS_OK; + + if (showErrorOnly && NS_SUCCEEDED(currError)) return NS_OK; + + nsString currMessage; + mProcessReport[mCurrentProcess]->GetMessage(getter_Copies(currMessage)); + + nsresult rv; // don't step on currError. + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::components::StringBundle::Service(); + NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED); + nsCOMPtr<nsIStringBundle> bundle; + rv = bundleService->CreateBundle( + "chrome://messenger/locale/messengercompose/composeMsgs.properties", + getter_AddRefs(bundle)); + if (NS_FAILED(rv)) { + // TODO need to display a generic hardcoded message + mAlreadyDisplayReport = true; + return NS_OK; + } + + nsString dialogTitle; + nsString dialogMessage; + + if (NS_SUCCEEDED(currError)) { + // TODO display a success error message + return NS_OK; + } + + // Do we have an explanation of the error? if no, try to build one... + if (currMessage.IsEmpty()) { +#ifdef __GNUC__ +// Temporary workaround until bug 783526 is fixed. +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wswitch" +#endif + switch (currError) { + case NS_BINDING_ABORTED: + case NS_MSG_UNABLE_TO_SEND_LATER: + case NS_MSG_UNABLE_TO_SAVE_DRAFT: + case NS_MSG_UNABLE_TO_SAVE_TEMPLATE: + // Ignore, don't need to repeat ourself. + break; + default: + const char* errorString = errorStringNameForErrorCode(currError); + nsMsgGetMessageByName(errorString, currMessage); + break; + } +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + } + + if (mDeliveryMode == nsIMsgCompDeliverMode::Now || + mDeliveryMode == nsIMsgCompDeliverMode::SendUnsent) { + // SMTP is taking care of it's own error message and will return + // NS_ERROR_BUT_DONT_SHOW_ALERT as error code. In that case, we must not + // show an alert ourself. + if (currError == NS_ERROR_BUT_DONT_SHOW_ALERT) { + mAlreadyDisplayReport = true; + return NS_OK; + } + + bundle->GetStringFromName("sendMessageErrorTitle", dialogTitle); + + const char* preStrName = "sendFailed"; + bool askToGoBackToCompose = false; + switch (mCurrentProcess) { + case process_BuildMessage: + preStrName = "sendFailed"; + askToGoBackToCompose = false; + break; + case process_NNTP: + preStrName = "sendFailed"; + askToGoBackToCompose = false; + break; + case process_SMTP: + bool nntpProceeded; + mProcessReport[process_NNTP]->GetProceeded(&nntpProceeded); + if (nntpProceeded) + preStrName = "sendFailedButNntpOk"; + else + preStrName = "sendFailed"; + askToGoBackToCompose = false; + break; + case process_Copy: + preStrName = "failedCopyOperation"; + askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now); + break; + case process_FCC: + preStrName = "failedCopyOperation"; + askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now); + break; + } + bundle->GetStringFromName(preStrName, dialogMessage); + + // Do we already have an error message? + if (!askToGoBackToCompose && currMessage.IsEmpty()) { + // we don't have an error description but we can put a generic explanation + bundle->GetStringFromName("genericFailureExplanation", currMessage); + } + + if (!currMessage.IsEmpty()) { + // Don't need to repeat ourself! + if (!currMessage.Equals(dialogMessage)) { + if (!dialogMessage.IsEmpty()) dialogMessage.Append(char16_t('\n')); + dialogMessage.Append(currMessage); + } + } + + if (askToGoBackToCompose) { + bool oopsGiveMeBackTheComposeWindow = true; + nsString text1; + bundle->GetStringFromName("returnToComposeWindowQuestion", text1); + if (!dialogMessage.IsEmpty()) dialogMessage.AppendLiteral("\n"); + dialogMessage.Append(text1); + nsMsgAskBooleanQuestionByString(window, dialogMessage.get(), + &oopsGiveMeBackTheComposeWindow, + dialogTitle.get()); + if (!oopsGiveMeBackTheComposeWindow) *_retval = NS_OK; + } else + nsMsgDisplayMessageByString(window, dialogMessage.get(), + dialogTitle.get()); + } else { + const char* title; + const char* messageName; + + switch (mDeliveryMode) { + case nsIMsgCompDeliverMode::Later: + title = "sendLaterErrorTitle"; + messageName = "unableToSendLater"; + break; + + case nsIMsgCompDeliverMode::AutoSaveAsDraft: + case nsIMsgCompDeliverMode::SaveAsDraft: + title = "saveDraftErrorTitle"; + messageName = "unableToSaveDraft"; + break; + + case nsIMsgCompDeliverMode::SaveAsTemplate: + title = "saveTemplateErrorTitle"; + messageName = "unableToSaveTemplate"; + break; + + default: + /* This should never happen! */ + title = "sendMessageErrorTitle"; + messageName = "sendFailed"; + break; + } + + bundle->GetStringFromName(title, dialogTitle); + bundle->GetStringFromName(messageName, dialogMessage); + + // Do we have an error message... + if (currMessage.IsEmpty()) { + // we don't have an error description but we can put a generic explanation + bundle->GetStringFromName("genericFailureExplanation", currMessage); + } + + if (!currMessage.IsEmpty()) { + if (!dialogMessage.IsEmpty()) dialogMessage.Append(char16_t('\n')); + dialogMessage.Append(currMessage); + } + nsMsgDisplayMessageByString(window, dialogMessage.get(), dialogTitle.get()); + } + + mAlreadyDisplayReport = true; + return NS_OK; +} |