nsresult
TestPlainTextSerializer()
{
  nsString test;
  test.AppendLiteral("<html><base>base</base><head><span>span</span></head>"
                     "<body>body</body></html>");
  ConvertBufToPlainText(test, 0);
  if (!test.EqualsLiteral("basespanbody")) {
    fail("Wrong html to text serialization");
    return NS_ERROR_FAILURE;
  }

  passed("HTML to text serialization test");

  nsresult rv = TestASCIIWithFlowedDelSp();
  NS_ENSURE_SUCCESS(rv, rv);

  rv = TestCJKWithFlowedDelSp();
  NS_ENSURE_SUCCESS(rv, rv);

  rv = TestPrettyPrintedHtml();
  NS_ENSURE_SUCCESS(rv, rv);

  rv = TestPreElement();
  NS_ENSURE_SUCCESS(rv, rv);

  rv = TestBlockElement();
  NS_ENSURE_SUCCESS(rv, rv);

  rv = TestPreWrapElementForThunderbird();
  NS_ENSURE_SUCCESS(rv, rv);

  // Add new tests here...
  return NS_OK;
}
// Test for ASCII with format=flowed; delsp=yes
nsresult
TestASCIIWithFlowedDelSp()
{
  nsString test;
  nsString result;

  test.AssignLiteral("<html><body>"
                     "Firefox Firefox Firefox Firefox "
                     "Firefox Firefox Firefox Firefox "
                     "Firefox Firefox Firefox Firefox"
                     "</body></html>");

  ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted |
                              nsIDocumentEncoder::OutputCRLineBreak |
                              nsIDocumentEncoder::OutputLFLineBreak |
                              nsIDocumentEncoder::OutputFormatFlowed |
                              nsIDocumentEncoder::OutputFormatDelSp);

  // create result case
  result.AssignLiteral("Firefox Firefox Firefox Firefox "
                       "Firefox Firefox Firefox Firefox "
                       "Firefox  \r\nFirefox Firefox Firefox\r\n");

  if (!test.Equals(result)) {
    fail("Wrong HTML to ASCII text serialization with format=flowed; delsp=yes");
    return NS_ERROR_FAILURE;
  }

  passed("HTML to ASCII text serialization with format=flowed; delsp=yes");

  return NS_OK;
}
// Test for CJK with DisallowLineBreaking
TEST(PlainTextSerializer, CJKWithDisallowLineBreaking)
{
    nsString test;
    nsString result;

    test.AssignLiteral("<html><body>");
    for (uint32_t i = 0; i < 400; i++) {
        // Insert Kanji (U+5341)
        test.Append(0x5341);
    }
    test.AppendLiteral("</body></html>");

    ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted |
                          nsIDocumentEncoder::OutputCRLineBreak |
                          nsIDocumentEncoder::OutputLFLineBreak |
                          nsIDocumentEncoder::OutputFormatFlowed |
                          nsIDocumentEncoder::OutputDisallowLineBreaking);

    // create result case
    for (uint32_t i = 0; i < 400; i++) {
        result.Append(0x5341);
    }
    result.AppendLiteral("\r\n");

    ASSERT_TRUE(test.Equals(result)) <<
                                     "Wrong HTML to CJK text serialization with OutputDisallowLineBreaking";
}
nsresult
TestPreWrapElementForThunderbird()
{
  // This test examines the magic pre-wrap setup that Thunderbird relies on.
  nsString test;
  test.AppendLiteral(
    "<html>" NS_LINEBREAK
    "<body style=\"white-space: pre-wrap; width: 10ch;\">" NS_LINEBREAK
    "<pre>" NS_LINEBREAK
    "  first line is too long" NS_LINEBREAK
    "  second line is even loooonger  " NS_LINEBREAK
    "</pre>" NS_LINEBREAK
    "</body>" NS_LINEBREAK "</html>");

  ConvertBufToPlainText(test, nsIDocumentEncoder::OutputWrap);
  // "\n\n  first\nline is\ntoo long\n  second\nline is\neven\nloooonger\n\n\n"
  if (!test.EqualsLiteral(NS_LINEBREAK NS_LINEBREAK
                          "  first" NS_LINEBREAK
                          "line is" NS_LINEBREAK
                          "too long" NS_LINEBREAK
                          "  second" NS_LINEBREAK
                          "line is" NS_LINEBREAK
                          "even" NS_LINEBREAK
                          "loooonger" NS_LINEBREAK
                          NS_LINEBREAK NS_LINEBREAK)) {
    fail("Wrong prettyprinted html to text serialization");
    return NS_ERROR_FAILURE;
  }

  passed("prettyprinted HTML to text serialization test");
  return NS_OK;
}
// Test for ASCII with format=flowed; delsp=yes
TEST(PlainTextSerializer, ASCIIWithFlowedDelSp)
{
    nsString test;
    nsString result;

    test.AssignLiteral("<html><body>"
                       "Firefox Firefox Firefox Firefox "
                       "Firefox Firefox Firefox Firefox "
                       "Firefox Firefox Firefox Firefox"
                       "</body></html>");

    ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted |
                          nsIDocumentEncoder::OutputCRLineBreak |
                          nsIDocumentEncoder::OutputLFLineBreak |
                          nsIDocumentEncoder::OutputFormatFlowed |
                          nsIDocumentEncoder::OutputFormatDelSp);

    // create result case
    result.AssignLiteral("Firefox Firefox Firefox Firefox "
                         "Firefox Firefox Firefox Firefox "
                         "Firefox  \r\nFirefox Firefox Firefox\r\n");

    ASSERT_TRUE(test.Equals(result)) <<
                                     "Wrong HTML to ASCII text serialization with format=flowed; delsp=yes";
}
// Test for ASCII with format=flowed; and quoted lines in preformatted span.
TEST(PlainTextSerializer, PreformatFlowedQuotes)
{
    nsString test;
    nsString result;

    test.AssignLiteral("<html><body>"
                       "<span style=\"white-space: pre-wrap;\">"
                       "&gt; Firefox Firefox Firefox Firefox <br>"
                       "&gt; Firefox Firefox Firefox Firefox<br>"
                       "&gt;<br>"
                       "&gt;&gt; Firefox Firefox Firefox Firefox <br>"
                       "&gt;&gt; Firefox Firefox Firefox Firefox<br>"
                       "</span></body></html>");

    ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted |
                          nsIDocumentEncoder::OutputCRLineBreak |
                          nsIDocumentEncoder::OutputLFLineBreak |
                          nsIDocumentEncoder::OutputFormatFlowed);

    // create result case
    result.AssignLiteral("> Firefox Firefox Firefox Firefox \r\n"
                         "> Firefox Firefox Firefox Firefox\r\n"
                         ">\r\n"
                         ">> Firefox Firefox Firefox Firefox \r\n"
                         ">> Firefox Firefox Firefox Firefox\r\n");

    ASSERT_TRUE(test.Equals(result)) <<
                                     "Wrong HTML to ASCII text serialization with format=flowed; and quoted "
                                     "lines";
}
TEST(PlainTextSerializer, PreWrapElementForThunderbird)
{
    // This test examines the magic pre-wrap setup that Thunderbird relies on.
    nsString test;
    test.AppendLiteral(
        "<html>" NS_LINEBREAK
        "<body style=\"white-space: pre-wrap; width: 10ch;\">" NS_LINEBREAK
        "<pre>" NS_LINEBREAK
        "  first line is too long" NS_LINEBREAK
        "  second line is even loooonger  " NS_LINEBREAK
        "</pre>" NS_LINEBREAK
        "</body>" NS_LINEBREAK "</html>");

    ConvertBufToPlainText(test, nsIDocumentEncoder::OutputWrap);
    // "\n\n  first\nline is\ntoo long\n  second\nline is\neven\nloooonger\n\n\n"
    ASSERT_TRUE(test.EqualsLiteral(NS_LINEBREAK NS_LINEBREAK
                                   "  first" NS_LINEBREAK
                                   "line is" NS_LINEBREAK
                                   "too long" NS_LINEBREAK
                                   "  second" NS_LINEBREAK
                                   "line is" NS_LINEBREAK
                                   "even" NS_LINEBREAK
                                   "loooonger" NS_LINEBREAK
                                   NS_LINEBREAK NS_LINEBREAK)) <<
                                           "Wrong prettyprinted html to text serialization";
}
// Test for CJK with DisallowLineBreaking
nsresult
TestCJKWithDisallowLineBreaking()
{
  nsString test;
  nsString result;

  test.AssignLiteral("<html><body>");
  for (uint32_t i = 0; i < 400; i++) {
    // Insert Kanji (U+5341)
    test.Append(0x5341);
  }
  test.AppendLiteral("</body></html>");

  ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted |
                              nsIDocumentEncoder::OutputCRLineBreak |
                              nsIDocumentEncoder::OutputLFLineBreak |
                              nsIDocumentEncoder::OutputFormatFlowed |
                              nsIDocumentEncoder::OutputDisallowLineBreaking);

  // create result case
  for (uint32_t i = 0; i < 400; i++) {
    result.Append(0x5341);
  }
  result.AppendLiteral("\r\n");

  if (!test.Equals(result)) {
    fail("Wrong HTML to CJK text serialization with OutputDisallowLineBreaking");
    return NS_ERROR_FAILURE;
  }

  passed("HTML to CJK text serialization with OutputDisallowLineBreaking");

  return NS_OK;
}
TEST(PlainTextSerializer, Simple)
{
    nsString test;
    test.AppendLiteral("<html><base>base</base><head><span>span</span></head>"
                       "<body>body</body></html>");
    ConvertBufToPlainText(test, 0);
    ASSERT_TRUE(test.EqualsLiteral("basespanbody")) <<
            "Wrong html to text serialization";
}
TEST(PlainTextSerializer, PrettyPrintedHtml)
{
  nsString test;
  test.AppendLiteral("<html>" NS_LINEBREAK "<body>" NS_LINEBREAK
                     "  first<br>" NS_LINEBREAK "  second<br>" NS_LINEBREAK
                     "</body>" NS_LINEBREAK "</html>");

  ConvertBufToPlainText(test, 0);
  ASSERT_TRUE(test.EqualsLiteral("first" NS_LINEBREAK "second" NS_LINEBREAK))
  << "Wrong prettyprinted html to text serialization";
}
Example #11
0
NS_IMETHODIMP nsMsgCompFields::ConvertBodyToPlainText()
{
  nsresult rv = NS_OK;
  
  if (!m_body.IsEmpty())
  {
    nsAutoString body;
    rv = GetBody(body);
    if (NS_SUCCEEDED(rv))
    {
      rv = ConvertBufToPlainText(body, UseFormatFlowed(GetCharacterSet()));
      if (NS_SUCCEEDED(rv))
        rv = SetBody(body);
    }
  }
  return rv;
}
nsresult
TestPrettyPrintedHtml()
{
  nsString test;
  test.AppendLiteral(
    "<html>" NS_LINEBREAK
    "<body>" NS_LINEBREAK
    "  first<br>" NS_LINEBREAK
    "  second<br>" NS_LINEBREAK
    "</body>" NS_LINEBREAK "</html>");

  ConvertBufToPlainText(test, 0);
  if (!test.EqualsLiteral("first" NS_LINEBREAK "second" NS_LINEBREAK)) {
    fail("Wrong prettyprinted html to text serialization");
    return NS_ERROR_FAILURE;
  }

  passed("prettyprinted HTML to text serialization test");
  return NS_OK;
}
// Test for CJK with format=flowed; delsp=yes
nsresult
TestCJKWithFlowedDelSp()
{
  nsString test;
  nsString result;

  test.AssignLiteral("<html><body>");
  for (PRUint32 i = 0; i < 40; i++) {
    // Insert Kanji (U+5341)
    test.Append(0x5341);
  }
  test.AppendLiteral("</body></html>");

  ConvertBufToPlainText(test, nsIDocumentEncoder::OutputFormatted |
                              nsIDocumentEncoder::OutputCRLineBreak |
                              nsIDocumentEncoder::OutputLFLineBreak |
                              nsIDocumentEncoder::OutputFormatFlowed |
                              nsIDocumentEncoder::OutputFormatDelSp);

  // create result case
  for (PRUint32 i = 0; i < 36; i++) {
    result.Append(0x5341);
  }
  result.Append(NS_LITERAL_STRING(" \r\n"));
  for (PRUint32 i = 0; i < 4; i++) {
    result.Append(0x5341);
  }
  result.Append(NS_LITERAL_STRING("\r\n"));

  if (!test.Equals(result)) {
    fail("Wrong HTML to CJK text serialization with format=flowed; delsp=yes");
    return NS_ERROR_FAILURE;
  }

  passed("HTML to CJK text serialization with format=flowed; delsp=yes");

  return NS_OK;
}
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;
}