예제 #1
0
nsresult
nsMsgAskBooleanQuestionByID(nsIPrompt * aPrompt, PRInt32 msgID, PRBool *answer, const PRUnichar * windowTitle)
{
    nsresult rv;
    nsCOMPtr<nsIStringBundleService> bundleService(do_GetService("@mozilla.org/intl/stringbundle;1", &rv));
    NS_ENSURE_SUCCESS(rv, rv);
    nsCOMPtr<nsIStringBundle> bundle;
    rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(bundle));
    NS_ENSURE_SUCCESS(rv, rv);

    nsString msg;
    bundle->GetStringFromID(msgID, getter_Copies(msg));
    return nsMsgAskBooleanQuestionByString(aPrompt, msg.get(), answer, windowTitle);
}
예제 #2
0
nsresult
nsMsgAttachmentHandler::UrlExit(nsresult status, const PRUnichar* aMsg)
{
  NS_ASSERTION(m_mime_delivery_state != nsnull, "not-null m_mime_delivery_state");

  // Close the file, but don't delete the disk file (or the file spec.)
  if (mOutFile)
  {
    mOutFile->Close();
    mOutFile = nsnull;
  }
  // this silliness is because Windows nsILocalFile caches its file size
  // so if an output stream writes to it, it will still return the original
  // cached size.
  if (mTmpFile)
  {
    nsCOMPtr <nsIFile> tmpFile;
    mTmpFile->Clone(getter_AddRefs(tmpFile));
    mTmpFile = do_QueryInterface(tmpFile);
  }
  mRequest = nsnull;

  // First things first, we are now going to see if this is an HTML
  // Doc and if it is, we need to see if we can determine the charset
  // for this part by sniffing the HTML file.
  // This is needed only when the charset is not set already.
  // (e.g. a charset may be specified in HTTP header)
  //
  if (!m_type.IsEmpty() && m_charset.IsEmpty() &&
      m_type.LowerCaseEqualsLiteral(TEXT_HTML))
    m_charset = nsMsgI18NParseMetaCharset(mTmpFile);

  nsresult mimeDeliveryStatus;
  m_mime_delivery_state->GetStatus(&mimeDeliveryStatus);

  if (mimeDeliveryStatus == NS_ERROR_ABORT)
    status = NS_ERROR_ABORT;

  if (NS_FAILED(status) && status != NS_ERROR_ABORT && NS_SUCCEEDED(mimeDeliveryStatus))
  {
    // At this point, we should probably ask a question to the user
    // if we should continue without this attachment.
    //
    bool              keepOnGoing = true;
    nsCString    turl;
    nsString     msg;
    PRUnichar         *printfString = nsnull;
    nsresult rv;
    nsCOMPtr<nsIStringBundleService> bundleService(do_GetService("@mozilla.org/intl/stringbundle;1", &rv));
    NS_ENSURE_SUCCESS(rv, rv);
    nsCOMPtr<nsIStringBundle> bundle;
    rv = bundleService->CreateBundle("chrome://messenger/locale/messengercompose/composeMsgs.properties", getter_AddRefs(bundle));
    NS_ENSURE_SUCCESS(rv, rv);
    nsMsgDeliverMode mode = nsIMsgSend::nsMsgDeliverNow;
    m_mime_delivery_state->GetDeliveryMode(&mode);
    if (mode == nsIMsgSend::nsMsgSaveAsDraft || mode == nsIMsgSend::nsMsgSaveAsTemplate)
      bundle->GetStringFromID(NS_MSG_FAILURE_ON_OBJ_EMBED_WHILE_SAVING, getter_Copies(msg));
    else
      bundle->GetStringFromID(NS_MSG_FAILURE_ON_OBJ_EMBED_WHILE_SENDING, getter_Copies(msg));
    if (!m_realName.IsEmpty())
      printfString = nsTextFormatter::smprintf(msg.get(), m_realName.get());
    else if (NS_SUCCEEDED(mURL->GetSpec(turl)) && !turl.IsEmpty())
    {
      nsCAutoString unescapedUrl;
      MsgUnescapeString(turl, 0, unescapedUrl);
      if (unescapedUrl.IsEmpty())
        printfString = nsTextFormatter::smprintf(msg.get(), turl.get());
      else
        printfString = nsTextFormatter::smprintf(msg.get(), unescapedUrl.get());
    }
    else
      printfString = nsTextFormatter::smprintf(msg.get(), "?");

    nsCOMPtr<nsIPrompt> aPrompt;
    if (m_mime_delivery_state)
      m_mime_delivery_state->GetDefaultPrompt(getter_AddRefs(aPrompt));
    nsMsgAskBooleanQuestionByString(aPrompt, printfString, &keepOnGoing);
    PR_FREEIF(printfString);

    if (keepOnGoing)
    {
      status = 0;
      m_bogus_attachment = true; //That will cause this attachment to be ignored.
    }
    else
    {
      status = NS_ERROR_ABORT;
      m_mime_delivery_state->SetStatus(status);
      nsresult ignoreMe;
      m_mime_delivery_state->Fail(status, nsnull, &ignoreMe);
      m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, 0, nsnull);
      SetMimeDeliveryState(nsnull);
      return status;
    }
  }

  m_done = true;

  //
  // Ok, now that we have the file here on disk, we need to see if there was
  // a need to do conversion to plain text...if so, the magic happens here,
  // otherwise, just move on to other attachments...
  //
  if (NS_SUCCEEDED(status) && !m_type.LowerCaseEqualsLiteral(TEXT_PLAIN) &&
      m_desiredType.LowerCaseEqualsLiteral(TEXT_PLAIN))
  {
    //
    // Conversion to plain text desired.
    //
    PRInt32       width = 72;
    nsCOMPtr<nsIPrefBranch> pPrefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
    if (pPrefBranch)
      pPrefBranch->GetIntPref("mailnews.wraplength", &width);
    // Let sanity reign!
    if (width == 0)
      width = 72;
    else if (width < 10)
      width = 10;
    else if (width > 30000)
      width = 30000;

    //
    // Now use the converter service here to do the right
    // thing and convert this data to plain text for us!
    //
    nsAutoString      conData;

    if (NS_SUCCEEDED(LoadDataFromFile(mTmpFile, conData, true)))
    {
      if (NS_SUCCEEDED(ConvertBufToPlainText(conData, UseFormatFlowed(m_charset.get()))))
      {
        if (mDeleteFile)
          mTmpFile->Remove(false);

        nsCOMPtr<nsIOutputStream> outputStream;
        nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mTmpFile,  PR_WRONLY | PR_CREATE_FILE, 00600);

        if (NS_SUCCEEDED(rv))
        {
          nsCAutoString tData;
          if (NS_FAILED(ConvertFromUnicode(m_charset.get(), conData, tData)))
            LossyCopyUTF16toASCII(conData, tData);
          if (!tData.IsEmpty())
          {
            PRUint32 bytesWritten;
            (void) outputStream->Write(tData.get(), tData.Length(), &bytesWritten);
          }
          outputStream->Close();
          // this silliness is because Windows nsILocalFile caches its file size
          // so if an output stream writes to it, it will still return the original
          // cached size.
          if (mTmpFile)
          {
            nsCOMPtr <nsIFile> tmpFile;
            mTmpFile->Clone(getter_AddRefs(tmpFile));
            mTmpFile = do_QueryInterface(tmpFile);
          }

        }
      }
    }

    m_type = m_desiredType;
    m_desiredType.Truncate();
    m_encoding.Truncate();
  }

  PRUint32 pendingAttachmentCount = 0;
  m_mime_delivery_state->GetPendingAttachmentCount(&pendingAttachmentCount);
  NS_ASSERTION (pendingAttachmentCount > 0, "no more pending attachment");

  m_mime_delivery_state->SetPendingAttachmentCount(pendingAttachmentCount - 1);

  bool processAttachmentsSynchronously = false;
  m_mime_delivery_state->GetProcessAttachmentsSynchronously(&processAttachmentsSynchronously);
  if (NS_SUCCEEDED(status) && processAttachmentsSynchronously)
  {
    /* Find the next attachment which has not yet been loaded,
     if any, and start it going.
     */
    PRUint32 i;
    nsMsgAttachmentHandler *next = 0;
    nsMsgAttachmentHandler *attachments = nsnull;
    PRUint32 attachmentCount = 0;

    m_mime_delivery_state->GetAttachmentCount(&attachmentCount);
    if (attachmentCount)
      m_mime_delivery_state->GetAttachmentHandlers(&attachments);

    for (i = 0; i < attachmentCount; i++)
    {
      if (!attachments[i].m_done)
      {
        next = &attachments[i];
        //
        // rhp: We need to get a little more understanding to failed URL
        // requests. So, at this point if most of next is NULL, then we
        // should just mark it fetched and move on! We probably ignored
        // this earlier on in the send process.
        //
        if ( (!next->mURL) && (next->m_uri.IsEmpty()) )
        {
          attachments[i].m_done = true;
          m_mime_delivery_state->GetPendingAttachmentCount(&pendingAttachmentCount);
          m_mime_delivery_state->SetPendingAttachmentCount(pendingAttachmentCount - 1);
          next->mPartUserOmissionOverride = true;
          next = nsnull;
          continue;
        }

        break;
      }
    }

    if (next)
    {
      int status = next->SnarfAttachment(mCompFields);
      if (NS_FAILED(status))
      {
        nsresult ignoreMe;
        m_mime_delivery_state->Fail(status, nsnull, &ignoreMe);
        m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, 0, nsnull);
        SetMimeDeliveryState(nsnull);
        return NS_ERROR_UNEXPECTED;
      }
    }
  }

  m_mime_delivery_state->GetPendingAttachmentCount(&pendingAttachmentCount);
  if (pendingAttachmentCount == 0)
  {
    // If this is the last attachment, then either complete the
    // delivery (if successful) or report the error by calling
    // the exit routine and terminating the delivery.
    if (NS_FAILED(status))
    {
      nsresult ignoreMe;
      m_mime_delivery_state->Fail(status, aMsg, &ignoreMe);
      m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, aMsg, nsnull);
      SetMimeDeliveryState(nsnull);
      return NS_ERROR_UNEXPECTED;
    }
    else
    {
      status = m_mime_delivery_state->GatherMimeAttachments ();
      if (NS_FAILED(status))
      {
        nsresult ignoreMe;
        m_mime_delivery_state->Fail(status, aMsg, &ignoreMe);
        m_mime_delivery_state->NotifyListenerOnStopSending(nsnull, status, aMsg, nsnull);
        SetMimeDeliveryState(nsnull);
        return NS_ERROR_UNEXPECTED;
      }
    }
  }
  else
  {
    // If this is not the last attachment, but it got an error,
    // then report that error and continue
    if (NS_FAILED(status))
    {
      nsresult ignoreMe;
      m_mime_delivery_state->Fail(status, aMsg, &ignoreMe);
    }
  }

  SetMimeDeliveryState(nsnull);
  return NS_OK;
}
예제 #3
0
/* nsresult displayReport (in nsIPrompt prompt, in boolean showErrorOnly, in boolean dontShowReportTwice); */
NS_IMETHODIMP nsMsgSendReport::DisplayReport(nsIPrompt *prompt, PRBool showErrorOnly, PRBool dontShowReportTwice, nsresult *_retval)
{
  NS_ENSURE_ARG_POINTER(_retval);

  nsresult currError = NS_OK;
  mProcessReport[mCurrentProcess]->GetError(&currError);
  *_retval = currError;
  
  if (dontShowReportTwice && mAlreadyDisplayReport)
    return NS_OK;
  
  if (showErrorOnly && NS_SUCCEEDED(currError))
    return NS_OK;
  
  nsXPIDLString currMessage;
  mProcessReport[mCurrentProcess]->GetMessage(getter_Copies(currMessage));


  nsCOMPtr<nsIMsgStringService> composebundle (do_GetService(NS_MSG_COMPOSESTRINGSERVICE_CONTRACTID));
  if (!composebundle)
  {
    //TODO need to display a generic hardcoded message
    mAlreadyDisplayReport = PR_TRUE;
    return NS_OK;
  }

  nsXPIDLString dialogTitle;
  nsXPIDLString 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())
  {
      switch (currError)
      {
        case NS_BINDING_ABORTED:
        case NS_ERROR_SEND_FAILED:
        case NS_ERROR_SEND_FAILED_BUT_NNTP_OK:
        case NS_MSG_FAILED_COPY_OPERATION:
        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;
        case NS_ERROR_MSG_MULTILINGUAL_SEND:
          // already displayed an alert, no additional message is needed
          // return to the compose window
          mAlreadyDisplayReport = PR_TRUE;
          return NS_OK;
        default:
          nsAutoString errorMsg;
          nsMsgBuildErrorMessageByID(currError, errorMsg);

          if (! errorMsg.IsEmpty())
            currMessage.Assign(errorMsg);
          break;
      }
  }
  
  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 = PR_TRUE;
      return NS_OK;
    }
  
    composebundle->GetStringByID(NS_MSG_SEND_ERROR_TITLE, getter_Copies(dialogTitle));

    PRInt32 preStrId = NS_ERROR_SEND_FAILED;
    PRBool askToGoBackToCompose = PR_FALSE;
    switch (mCurrentProcess)
    {
      case process_BuildMessage :
        preStrId = NS_ERROR_SEND_FAILED;
        askToGoBackToCompose = PR_FALSE;
        break;
      case process_NNTP :
        preStrId = NS_ERROR_SEND_FAILED;
        askToGoBackToCompose = PR_FALSE;
        break;
      case process_SMTP :
        PRBool nntpProceeded;
        mProcessReport[process_NNTP]->GetProceeded(&nntpProceeded);
        if (nntpProceeded)
          preStrId = NS_ERROR_SEND_FAILED_BUT_NNTP_OK;
        else
          preStrId = NS_ERROR_SEND_FAILED;
        askToGoBackToCompose = PR_FALSE;
        break;
      case process_Copy:
        preStrId = NS_MSG_FAILED_COPY_OPERATION;
        askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now);
        break;
      case process_FCC:
        preStrId = NS_MSG_FAILED_COPY_OPERATION;
        askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now);
        break;
    }
    composebundle->GetStringByID(preStrId, getter_Copies(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
      composebundle->GetStringByID(NS_MSG_GENERIC_FAILURE_EXPLANATION, getter_Copies(currMessage));
    }
    
    if (!currMessage.IsEmpty())
    {
      nsAutoString temp((const PRUnichar *)dialogMessage);  // Because of bug 74726, we cannot use directly an XPIDLString

      //Don't need to repeat ourself!
      if (! currMessage.Equals(temp))
      {
        if (! dialogMessage.IsEmpty())
          temp.AppendLiteral("\n");
        temp.Append(currMessage);
        dialogMessage.Assign(temp);
      }
    }
      
    if (askToGoBackToCompose)
    {
      PRBool oopsGiveMeBackTheComposeWindow = PR_TRUE;
      nsXPIDLString text1;
      composebundle->GetStringByID(NS_MSG_ASK_TO_COMEBACK_TO_COMPOSE, getter_Copies(text1));
      nsAutoString temp((const PRUnichar *)dialogMessage);  // Because of bug 74726, we cannot use directly an XPIDLString
      if (! dialogMessage.IsEmpty())
        temp.AppendLiteral("\n");
      temp.Append(text1);
      dialogMessage.Assign(temp);
      nsMsgAskBooleanQuestionByString(prompt, dialogMessage, &oopsGiveMeBackTheComposeWindow, dialogTitle);
      if (!oopsGiveMeBackTheComposeWindow)
        *_retval = NS_OK;
    }
    else
      nsMsgDisplayMessageByString(prompt, dialogMessage, dialogTitle);
  }
  else
  {
    PRInt32 titleID;
    PRInt32 preStrId;

    switch (mDeliveryMode)
    {
      case nsIMsgCompDeliverMode::Later:
        titleID = NS_MSG_SENDLATER_ERROR_TITLE;
        preStrId = NS_MSG_UNABLE_TO_SEND_LATER;
        break;

      case nsIMsgCompDeliverMode::AutoSaveAsDraft:
      case nsIMsgCompDeliverMode::SaveAsDraft:
        titleID = NS_MSG_SAVE_DRAFT_TITLE;
        preStrId = NS_MSG_UNABLE_TO_SAVE_DRAFT;
        break;

      case nsIMsgCompDeliverMode::SaveAsTemplate:
        titleID = NS_MSG_SAVE_TEMPLATE_TITLE;
        preStrId = NS_MSG_UNABLE_TO_SAVE_TEMPLATE;
        break;

      default:
        /* This should never happend! */
        titleID = NS_MSG_SEND_ERROR_TITLE;
        preStrId = NS_ERROR_SEND_FAILED;
        break;
    }

    composebundle->GetStringByID(titleID, getter_Copies(dialogTitle));
    composebundle->GetStringByID(preStrId, getter_Copies(dialogMessage));

    //Do we have an error message...
    if (currMessage.IsEmpty())
    {
      //we don't have an error description but we can put a generic explanation
      composebundle->GetStringByID(NS_MSG_GENERIC_FAILURE_EXPLANATION, getter_Copies(currMessage));
    }

    if (!currMessage.IsEmpty())
    {
      nsAutoString temp((const PRUnichar *)dialogMessage);  // Because of bug 74726, we cannot use directly an XPIDLString
      if (! dialogMessage.IsEmpty())
        temp.AppendLiteral("\n");
      temp.Append(currMessage);
      dialogMessage.Assign(temp);
    }

    nsMsgDisplayMessageByString(prompt, dialogMessage, dialogTitle);
  }
  
  mAlreadyDisplayReport = PR_TRUE;
  return NS_OK;
}
예제 #4
0
/* nsresult displayReport (in nsIPrompt prompt, in boolean showErrorOnly, in boolean dontShowReportTwice); */
NS_IMETHODIMP nsMsgSendReport::DisplayReport(nsIPrompt *prompt, bool showErrorOnly, bool dontShowReportTwice, nsresult *_retval)
{
  NS_ENSURE_ARG_POINTER(_retval);

  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(do_GetService("@mozilla.org/intl/stringbundle;1", &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  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())
  {
    switch (currError)
    {
      case NS_BINDING_ABORTED:
      case NS_ERROR_SEND_FAILED:
      case NS_ERROR_SEND_FAILED_BUT_NNTP_OK:
      case NS_MSG_FAILED_COPY_OPERATION:
      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:
        nsMsgGetMessageByID(currError, currMessage);
        break;
    }
  }

  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->GetStringFromID(NS_MSG_SEND_ERROR_TITLE, getter_Copies(dialogTitle));

    PRInt32 preStrId = NS_ERROR_SEND_FAILED;
    bool askToGoBackToCompose = false;
    switch (mCurrentProcess)
    {
      case process_BuildMessage :
        preStrId = NS_ERROR_SEND_FAILED;
        askToGoBackToCompose = false;
        break;
      case process_NNTP :
        preStrId = NS_ERROR_SEND_FAILED;
        askToGoBackToCompose = false;
        break;
      case process_SMTP :
        bool nntpProceeded;
        mProcessReport[process_NNTP]->GetProceeded(&nntpProceeded);
        if (nntpProceeded)
          preStrId = NS_ERROR_SEND_FAILED_BUT_NNTP_OK;
        else
          preStrId = NS_ERROR_SEND_FAILED;
        askToGoBackToCompose = false;
        break;
      case process_Copy:
        preStrId = NS_MSG_FAILED_COPY_OPERATION;
        askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now);
        break;
      case process_FCC:
        preStrId = NS_MSG_FAILED_COPY_OPERATION;
        askToGoBackToCompose = (mDeliveryMode == nsIMsgCompDeliverMode::Now);
        break;
    }
    bundle->GetStringFromID(preStrId, getter_Copies(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->GetStringFromID(NS_MSG_GENERIC_FAILURE_EXPLANATION, getter_Copies(currMessage));
    }

    if (!currMessage.IsEmpty())
    {
      //Don't need to repeat ourself!
      if (!currMessage.Equals(dialogMessage))
      {
        if (!dialogMessage.IsEmpty())
          dialogMessage.Append(PRUnichar('\n'));
        dialogMessage.Append(currMessage);
      }
    }

    if (askToGoBackToCompose)
    {
      bool oopsGiveMeBackTheComposeWindow = true;
      nsString text1;
      bundle->GetStringFromID(NS_MSG_ASK_TO_COMEBACK_TO_COMPOSE, getter_Copies(text1));
      if (!dialogMessage.IsEmpty())
        dialogMessage.AppendLiteral("\n");
      dialogMessage.Append(text1);
      nsMsgAskBooleanQuestionByString(prompt, dialogMessage.get(), &oopsGiveMeBackTheComposeWindow, dialogTitle.get());
      if (!oopsGiveMeBackTheComposeWindow)
        *_retval = NS_OK;
    }
    else
      nsMsgDisplayMessageByString(prompt, dialogMessage.get(), dialogTitle.get());
  }
  else
  {
    PRInt32 titleID;
    PRInt32 preStrId;

    switch (mDeliveryMode)
    {
      case nsIMsgCompDeliverMode::Later:
        titleID = NS_MSG_SENDLATER_ERROR_TITLE;
        preStrId = NS_MSG_UNABLE_TO_SEND_LATER;
        break;

      case nsIMsgCompDeliverMode::AutoSaveAsDraft:
      case nsIMsgCompDeliverMode::SaveAsDraft:
        titleID = NS_MSG_SAVE_DRAFT_TITLE;
        preStrId = NS_MSG_UNABLE_TO_SAVE_DRAFT;
        break;

      case nsIMsgCompDeliverMode::SaveAsTemplate:
        titleID = NS_MSG_SAVE_TEMPLATE_TITLE;
        preStrId = NS_MSG_UNABLE_TO_SAVE_TEMPLATE;
        break;

      default:
        /* This should never happend! */
        titleID = NS_MSG_SEND_ERROR_TITLE;
        preStrId = NS_ERROR_SEND_FAILED;
        break;
    }

    bundle->GetStringFromID(titleID, getter_Copies(dialogTitle));
    // preStrId could be a string ID or it could be an error code...yuck.
    bundle->GetStringFromID(NS_IS_MSG_ERROR(preStrId) ? NS_ERROR_GET_CODE(preStrId) : preStrId, getter_Copies(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->GetStringFromID(NS_MSG_GENERIC_FAILURE_EXPLANATION, getter_Copies(currMessage));
    }

    if (!currMessage.IsEmpty())
    {
      if (!dialogMessage.IsEmpty())
        dialogMessage.Append(PRUnichar('\n'));
      dialogMessage.Append(currMessage);
    }
    nsMsgDisplayMessageByString(prompt, dialogMessage.get(), dialogTitle.get());
  }

  mAlreadyDisplayReport = true;
  return NS_OK;
}
/* nsresult displayReport (in nsIPrompt prompt, in boolean showErrorOnly, in
 * boolean dontShowReportTwice); */
NS_IMETHODIMP nsMsgSendReport::DisplayReport(nsIPrompt *prompt,
                                             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::services::GetStringBundleService();
  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(prompt, dialogMessage.get(),
                                      &oopsGiveMeBackTheComposeWindow,
                                      dialogTitle.get());
      if (!oopsGiveMeBackTheComposeWindow) *_retval = NS_OK;
    } else
      nsMsgDisplayMessageByString(prompt, 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(prompt, dialogMessage.get(), dialogTitle.get());
  }

  mAlreadyDisplayReport = true;
  return NS_OK;
}