Bug 1464667 - Remove plaintext tag from HTML. r=mkmelin a=jorgk
authorJorg K <jorgk@jorgk.com>
Mon, 11 Jun 2018 21:43:27 +0200
changeset 31608 69b679d3217a37cc969e4590ef93a1ac269a9a69
parent 31607 9ceb60aadc29bcedb48c8b70715dfec1f9627068
child 31609 55262c232ff6fb12f288c193f060af133dc3e6ff
push id21
push usermozilla@hocat.ca
push dateFri, 13 Jul 2018 19:54:19 +0000
treeherdercomm-esr60@3c593339cb1d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkmelin, jorgk
bugs1464667
Bug 1464667 - Remove plaintext tag from HTML. r=mkmelin a=jorgk
mailnews/compose/src/nsMsgCompose.cpp
mailnews/mime/src/mimeTextHTMLParsed.cpp
mailnews/mime/src/mimethsa.cpp
mailnews/mime/src/mimethtm.cpp
mailnews/mime/src/mimethtm.h
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -593,16 +593,41 @@ nsMsgCompose::InsertDivWrappedTextAtSele
   }
   if (divElem) {
     nsCOMPtr<Element> divElem2 = do_QueryInterface(divElem);
     IgnoredErrorResult rv2;
     divElem2->SetAttribute(NS_LITERAL_STRING("class"), classStr, rv2);
   }
 }
 
+/*
+ * The following function replaces <plaintext> tags with <x-plaintext>.
+ * <plaintext> is a funny beast: It leads to everything following it
+ * being displayed verbatim, even a </plaintext> tag is ignored.
+ */
+static void
+remove_plaintext_tag(nsString &body)
+{
+  // Replace all <plaintext> and </plaintext> tags.
+  int32_t index = 0;
+  bool replaced = false;
+  while ((index = body.Find("<plaintext", /* ignoreCase = */ true, index)) != kNotFound) {
+    body.Insert(u"x-", index+1);
+    index += 12;
+    replaced = true;
+  }
+  if (replaced) {
+    index = 0;
+    while ((index = body.Find("</plaintext", /* ignoreCase = */ true, index)) != kNotFound) {
+      body.Insert(u"x-", index+2);
+      index += 13;
+    }
+  }
+}
+
 NS_IMETHODIMP
 nsMsgCompose::ConvertAndLoadComposeWindow(nsString& aPrefix,
                                           nsString& aBuf,
                                           nsString& aSignature,
                                           bool aQuoted,
                                           bool aHTMLEditor)
 {
   NS_ASSERTION(m_editor, "ConvertAndLoadComposeWindow but no editor\n");
@@ -678,25 +703,27 @@ nsMsgCompose::ConvertAndLoadComposeWindo
 
       InsertDivWrappedTextAtSelection(aPrefix,
                                       NS_LITERAL_STRING("moz-cite-prefix"));
     }
 
     if (!aBuf.IsEmpty() && mailEditor)
     {
       // This leaves the caret at the right place to insert a bottom signature.
-      if (aHTMLEditor)
-        mailEditor->InsertAsCitedQuotation(aBuf,
+      if (aHTMLEditor) {
+        nsAutoString body(aBuf);
+        remove_plaintext_tag(body);
+        mailEditor->InsertAsCitedQuotation(body,
                                            mCiteReference,
                                            true,
                                            getter_AddRefs(nodeInserted));
-      else
+      } else {
         mailEditor->InsertAsQuotation(aBuf,
                                       getter_AddRefs(nodeInserted));
-
+      }
     }
 
     mInsertingQuotedContent = false;
 
     (void)TagEmbeddedObjects(mailEditor);
 
     if (!aSignature.IsEmpty())
     {
@@ -730,16 +757,17 @@ nsMsgCompose::ConvertAndLoadComposeWindo
         // forwarded content like this:
         // <HTML><BODY><BR><BR> + forwarded header + header table.
         // Note: We only do this when we prepare the message to be forwarded,
         // a re-opened saved draft of a forwarded message does not repeat this.
         nsString newBody(aBuf);
         nsString divTag;
         divTag.AssignLiteral("<div class=\"moz-forward-container\">");
         newBody.Insert(divTag, sizeof(MIME_FORWARD_HTML_PREFIX)-1-8);
+        remove_plaintext_tag(newBody);
         htmlEditor->RebuildDocumentFromSource(newBody);
       } else {
         htmlEditor->RebuildDocumentFromSource(aBuf);
       }
       mInsertingQuotedContent = false;
 
       // When forwarding a message as inline, or editing as new (which could
       // contain unsanitized remote content), tag any embedded objects
@@ -3088,21 +3116,24 @@ QuotingOutputStreamListener::InsertToCom
       nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(aEditor));
       if (textEditor)
         textEditor->InsertText(mCitePrefix);
     }
 
     nsCOMPtr<nsIEditorMailSupport> mailEditor (do_QueryInterface(aEditor));
     if (mailEditor)
     {
-      if (aHTMLEditor)
-        mailEditor->InsertAsCitedQuotation(mMsgBody, EmptyString(), true,
+      if (aHTMLEditor) {
+        nsAutoString body(mMsgBody);
+        remove_plaintext_tag(body);
+        mailEditor->InsertAsCitedQuotation(body, EmptyString(), true,
                                            getter_AddRefs(nodeInserted));
-      else
+      } else {
         mailEditor->InsertAsQuotation(mMsgBody, getter_AddRefs(nodeInserted));
+      }
     }
     compose->SetInsertingQuotedContent(false);
   }
 
   if (aEditor)
   {
     nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(aEditor);
     if (textEditor)
--- a/mailnews/mime/src/mimeTextHTMLParsed.cpp
+++ b/mailnews/mime/src/mimeTextHTMLParsed.cpp
@@ -102,16 +102,17 @@ MimeInlineTextHTMLParsed_parse_eof(MimeO
   rv = encoder->Init(document, NS_LITERAL_STRING("text/html"), aFlags);
   NS_ENSURE_SUCCESS(rv, -1);
   rv = encoder->EncodeToString(parsed);
   NS_ENSURE_SUCCESS(rv, -1);
 
   // Write it out.
   NS_ConvertUTF16toUTF8 resultCStr(parsed);
   MimeInlineTextHTML_insert_lang_div(obj, resultCStr);
+  MimeInlineTextHTML_remove_plaintext_tag(obj, resultCStr);
   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_line(
     resultCStr.BeginWriting(), resultCStr.Length(), obj);
   rawHTML.Truncate();
   return status;
 }
 
 void
 MimeInlineTextHTMLParsed_finalize(MimeObject *obj)
--- a/mailnews/mime/src/mimethsa.cpp
+++ b/mailnews/mime/src/mimethsa.cpp
@@ -93,16 +93,18 @@ MimeInlineTextHTMLSanitized_parse_eof(Mi
   nsString sanitized;
 
   // Sanitize.
   HTMLSanitize(cb, sanitized);
 
   // Write it out.
   NS_ConvertUTF16toUTF8 resultCStr(sanitized);
   MimeInlineTextHTML_insert_lang_div(obj, resultCStr);
+  // Call to MimeInlineTextHTML_remove_plaintext_tag() not needed since
+  // sanitization already removes that tag.
   status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_line(
                              resultCStr.BeginWriting(),
                              resultCStr.Length(),
                              obj);
   cb.Truncate();
   return status;
 }
 
--- a/mailnews/mime/src/mimethtm.cpp
+++ b/mailnews/mime/src/mimethtm.cpp
@@ -188,17 +188,17 @@ MimeInlineTextHTML_parse_eof (MimeObject
 void
 MimeInlineTextHTML_insert_lang_div(MimeObject *obj, nsCString &message)
 {
   if (obj->options->format_out != nsMimeOutput::nsMimeMessageBodyDisplay &&
       obj->options->format_out != nsMimeOutput::nsMimeMessagePrintOutput)
     return;
 
   // Make sure we have a <body> before we start.
-  int32_t index = message.Find("<body");
+  int32_t index = message.Find("<body", /* ignoreCase = */ true);
   if (index == kNotFound)
     return;
   index = message.FindChar('>', index) + 1;
 
   // Insert <div class="moz-text-html" lang="..."> for the following two purposes:
   // 1) Users can configure their HTML display via CSS for .moz-text-html.
   // 2) The language group in the 'lang' attribure is used by Gecko to determine
   //    which font to use.
@@ -213,12 +213,42 @@ MimeInlineTextHTML_insert_lang_div(MimeO
                    index);
   }
   else
   {
     message.Insert(NS_LITERAL_CSTRING("<div class=\"moz-text-html\">"),
                    index);
   }
 
-  index = message.RFind("</body>");
+  index = message.RFind("</body>", /* ignoreCase = */ true);
   if (index != kNotFound)
     message.Insert(NS_LITERAL_CSTRING("</div>"), index);
 }
+
+/*
+ * The following function replaces <plaintext> tags with <x-plaintext>.
+ * <plaintext> is a funny beast: It leads to everything following it
+ * being displayed verbatim, even a </plaintext> tag is ignored.
+ */
+void
+MimeInlineTextHTML_remove_plaintext_tag(MimeObject *obj, nsCString &message)
+{
+  if (obj->options->format_out != nsMimeOutput::nsMimeMessageBodyDisplay &&
+      obj->options->format_out != nsMimeOutput::nsMimeMessagePrintOutput)
+    return;
+
+  // Replace all <plaintext> and </plaintext> tags.
+  int32_t index = 0;
+  bool replaced = false;
+  while ((index = message.Find("<plaintext", /* ignoreCase = */ true, index)) != kNotFound) {
+    message.Insert("x-", index+1);
+    index += 12;
+    replaced = true;
+  }
+  if (replaced) {
+    index = 0;
+    while ((index = message.Find("</plaintext", /* ignoreCase = */ true, index)) != kNotFound) {
+      message.Insert("x-", index+2);
+      index += 13;
+    }
+  }
+}
+
--- a/mailnews/mime/src/mimethtm.h
+++ b/mailnews/mime/src/mimethtm.h
@@ -25,9 +25,11 @@ struct MimeInlineTextHTML {
   char            *charset;  /* If we sniffed a charset, do some converting! */
 };
 
 #define MimeInlineTextHTMLClassInitializer(ITYPE,CSUPER) \
   { MimeInlineTextClassInitializer(ITYPE,CSUPER) }
 
 void
 MimeInlineTextHTML_insert_lang_div(MimeObject *obj, nsCString &message);
+void
+MimeInlineTextHTML_remove_plaintext_tag(MimeObject *obj, nsCString &message);
 #endif /* _MIMETHTM_H_ */