Bug 584313 - if a message contains any style (element or tag attribute), it should not be convertible to plain text. r=mkmelin
This commit is contained in:
Родитель
9905880dd5
Коммит
12b300cf10
|
@ -0,0 +1,23 @@
|
|||
Message-ID: <11111.11111@example.invalid>
|
||||
Date: Sun, 18 May 2014 22:31:12 +0200
|
||||
MIME-Version: 1.0
|
||||
To: test@test.invalid
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>title</title>
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
Line 1<br>
|
||||
<p>
|
||||
Line 2
|
||||
</p>
|
||||
<pre>
|
||||
pre line 1
|
||||
pre line 2
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
Message-ID: <22222222.2222222@example.invalid>
|
||||
Date: Sun, 17 Jun 2012 09:42:45 +0200
|
||||
From: John Doe
|
||||
MIME-Version: 1.0
|
||||
Subject: Testcase - style attribute
|
||||
Content-Type: text/html; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;
|
||||
charset=ISO-8859-1">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
*** This text is "Variable Width" ***<br>
|
||||
<br>
|
||||
<a title="Get the best mailer now! (Caveat: neglected bird with lots
|
||||
of bugs)" style="float: right; background-color: blue; font-size:
|
||||
18px; text-decoration: none; color: white; padding-top: 90px;
|
||||
padding-bottom: 90px; padding-right: 50px; padding-left: 50px;"
|
||||
href="http://www.getthunderbird.com">http://www.getthunderbird.com</a><a
|
||||
title="Get the best browser now!" style="float: right;
|
||||
background-color: orangered; font-size: 18px; text-decoration:
|
||||
none; color: white; padding-top: 90px; padding-bottom: 90px;
|
||||
padding-right: 50px; padding-left: 50px;"
|
||||
href="http://www.getfirefox.com">http://www.getfirefox.com</a>Lorem
|
||||
ipsum
|
||||
dolor sit amet, consectetur adipiscing elit. Vestibulum
|
||||
velit purus, egestas eu commodo ac, imperdiet pretium sem. Nulla
|
||||
pulvinar commodo rutrum. Duis feugiat facilisis libero, id fermentum
|
||||
neque molestie vel. Praesent vel nisi metus, a aliquam tellus. Cras
|
||||
in
|
||||
<pre style="color:blue;background-color:yellow;text-align:center;">
|
||||
Vivamus accumsan bibendum arcu nec egestas. Suspendisse potenti.
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,31 @@
|
|||
Message-ID: <33333.33333@example.invalid>
|
||||
Date: Sun, 17 Jun 2012 09:42:45 +0200
|
||||
MIME-Version: 1.0
|
||||
Subject: <style> element
|
||||
Content-Type: text/html; charset=ISO-8859-1
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<style type="text/css">
|
||||
<!--
|
||||
body {
|
||||
font-size:11.0pt;
|
||||
font-family:"Calibri","sans-serif";
|
||||
}
|
||||
ul, ol, blockquote {
|
||||
margin: 0px 0px;
|
||||
}
|
||||
-->
|
||||
</style>
|
||||
|
||||
</head><body>
|
||||
|
||||
Type text here
|
||||
|
||||
<div id="imageholder">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Tests resulting send format of a message dependent on using HTML features
|
||||
* in the composition.
|
||||
*/
|
||||
|
||||
// make SOLO_TEST=composition/test-send-format.js mozmill-one
|
||||
|
||||
var MODULE_NAME = "test-send-format";
|
||||
|
||||
var RELATIVE_ROOT = "../shared-modules";
|
||||
var MODULE_REQUIRES = ["folder-display-helpers", "compose-helpers", "window-helpers"];
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/mailServices.js");
|
||||
var os = {};
|
||||
Cu.import('resource://mozmill/stdlib/os.js', os);
|
||||
|
||||
const nsIMsgCompConvertible = Components.interfaces.nsIMsgCompConvertible;
|
||||
|
||||
function setupModule(module) {
|
||||
for (let lib of MODULE_REQUIRES) {
|
||||
collector.getModule(lib).installInto(module);
|
||||
}
|
||||
}
|
||||
|
||||
function checkMsgFile(aFilePath, aConvertibility) {
|
||||
let file = os.getFileForPath(os.abspath(aFilePath,
|
||||
os.getFileForPath(__file__)));
|
||||
let msgc = open_message_from_file(file);
|
||||
|
||||
// Creating a reply should not affect convertibility.
|
||||
let cwc = open_compose_with_reply(msgc);
|
||||
|
||||
assert_equals(cwc.window.DetermineConvertibility(), aConvertibility);
|
||||
|
||||
close_compose_window(cwc);
|
||||
close_window(msgc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that we only open one compose window for one instance of a draft.
|
||||
*/
|
||||
function test_msg_convertibility() {
|
||||
checkMsgFile("./format1-plain.eml", nsIMsgCompConvertible.Plain);
|
||||
|
||||
// Bug 584313
|
||||
checkMsgFile("./format2-style-attr.eml", nsIMsgCompConvertible.No);
|
||||
checkMsgFile("./format3-style-tag.eml", nsIMsgCompConvertible.No);
|
||||
}
|
||||
|
||||
function teardownModule() {
|
||||
}
|
|
@ -174,9 +174,12 @@ interface nsIMsgCompose : nsIMsgSendListener {
|
|||
*/
|
||||
long determineHTMLAction(in long aConvertible);
|
||||
|
||||
/* bodyConvertible: The level of "convertibility" to plaintext
|
||||
/**
|
||||
* The level of "convertibility" of the message body (whole HTML document)
|
||||
* to plaintext.
|
||||
*
|
||||
* @return a value from nsIMsgCompConvertible.
|
||||
*/
|
||||
*/
|
||||
long bodyConvertible();
|
||||
|
||||
/**
|
||||
|
|
|
@ -5123,7 +5123,7 @@ nsMsgCompose::DetermineHTMLAction(int32_t aConvertible, int32_t *result)
|
|||
/* Decides which tags trigger which convertible mode, i.e. here is the logic
|
||||
for BodyConvertible */
|
||||
// Helper function. Parameters are not checked.
|
||||
nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
||||
nsresult nsMsgCompose::TagConvertible(nsIDOMElement *node, int32_t *_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -5140,14 +5140,42 @@ nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> pItem;
|
||||
if (
|
||||
nodeType == nsIDOMNode::TEXT_NODE ||
|
||||
|
||||
// style attribute on any element can change layout in any way, so that is not convertible.
|
||||
nsAutoString attribValue;
|
||||
if (NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("style"), attribValue)) &&
|
||||
!attribValue.IsEmpty())
|
||||
{
|
||||
*_retval = nsIMsgCompConvertible::No;
|
||||
return NS_OK;
|
||||
}
|
||||
// moz-txt classes are used internally by the editor, those can be discarded.
|
||||
// But any other ones are unconvertible. Style can be attached to them or any
|
||||
// other context (e.g. in microformats).
|
||||
if (NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("class"), attribValue)) &&
|
||||
!attribValue.IsEmpty() &&
|
||||
!StringBeginsWith(attribValue, NS_LITERAL_STRING("moz-txt"), nsCaseInsensitiveStringComparator()) &&
|
||||
!StringBeginsWith(attribValue, NS_LITERAL_STRING("moz-cite"), nsCaseInsensitiveStringComparator()))
|
||||
{
|
||||
*_retval = nsIMsgCompConvertible::No;
|
||||
return NS_OK;
|
||||
}
|
||||
// ID attributes can contain attached style/context or be target of links
|
||||
// so we should preserve them.
|
||||
if (NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("id"), attribValue)) &&
|
||||
!attribValue.IsEmpty())
|
||||
{
|
||||
*_retval = nsIMsgCompConvertible::No;
|
||||
return NS_OK;
|
||||
}
|
||||
if ( // some "simple" elements without "style" attribute
|
||||
element.LowerCaseEqualsLiteral("br") ||
|
||||
element.LowerCaseEqualsLiteral("p") ||
|
||||
element.LowerCaseEqualsLiteral("pre") ||
|
||||
element.LowerCaseEqualsLiteral("tt") ||
|
||||
element.LowerCaseEqualsLiteral("html") ||
|
||||
element.LowerCaseEqualsLiteral("head") ||
|
||||
element.LowerCaseEqualsLiteral("meta") ||
|
||||
element.LowerCaseEqualsLiteral("title")
|
||||
)
|
||||
{
|
||||
|
@ -5194,46 +5222,38 @@ nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
{
|
||||
*_retval = nsIMsgCompConvertible::Plain;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
|
||||
if (domElement)
|
||||
{
|
||||
bool hasAttribute;
|
||||
nsAutoString color;
|
||||
if (NS_SUCCEEDED(domElement->HasAttribute(NS_LITERAL_STRING("background"), &hasAttribute))
|
||||
if (NS_SUCCEEDED(node->HasAttribute(NS_LITERAL_STRING("background"), &hasAttribute))
|
||||
&& hasAttribute) // There is a background image
|
||||
*_retval = nsIMsgCompConvertible::No;
|
||||
else if (NS_SUCCEEDED(domElement->HasAttribute(NS_LITERAL_STRING("text"), &hasAttribute)) &&
|
||||
else if (NS_SUCCEEDED(node->HasAttribute(NS_LITERAL_STRING("text"), &hasAttribute)) &&
|
||||
hasAttribute &&
|
||||
NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING("text"), color)) &&
|
||||
NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("text"), color)) &&
|
||||
!color.EqualsLiteral("#000000")) {
|
||||
*_retval = nsIMsgCompConvertible::Altering;
|
||||
}
|
||||
else if (NS_SUCCEEDED(domElement->HasAttribute(NS_LITERAL_STRING("bgcolor"), &hasAttribute)) &&
|
||||
else if (NS_SUCCEEDED(node->HasAttribute(NS_LITERAL_STRING("bgcolor"), &hasAttribute)) &&
|
||||
hasAttribute &&
|
||||
NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING("bgcolor"), color)) &&
|
||||
NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("bgcolor"), color)) &&
|
||||
!color.LowerCaseEqualsLiteral("#ffffff")) {
|
||||
*_retval = nsIMsgCompConvertible::Altering;
|
||||
}
|
||||
else if (NS_SUCCEEDED(domElement->HasAttribute(NS_LITERAL_STRING("dir"), &hasAttribute))
|
||||
else if (NS_SUCCEEDED(node->HasAttribute(NS_LITERAL_STRING("dir"), &hasAttribute))
|
||||
&& hasAttribute) // dir=rtl attributes should not downconvert
|
||||
*_retval = nsIMsgCompConvertible::No;
|
||||
|
||||
//ignore special color setting for link, vlink and alink at this point.
|
||||
}
|
||||
|
||||
}
|
||||
else if (element.LowerCaseEqualsLiteral("blockquote"))
|
||||
{
|
||||
// Skip <blockquote type="cite">
|
||||
*_retval = nsIMsgCompConvertible::Yes;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
|
||||
if (domElement)
|
||||
if (NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("type"), attribValue)) &&
|
||||
attribValue.LowerCaseEqualsLiteral("cite"))
|
||||
{
|
||||
nsString typeValue;
|
||||
if (NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING("type"), typeValue)) &&
|
||||
typeValue.LowerCaseEqualsLiteral("cite"))
|
||||
*_retval = nsIMsgCompConvertible::Plain;
|
||||
*_retval = nsIMsgCompConvertible::Plain;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
|
@ -5244,17 +5264,6 @@ nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
{
|
||||
/* Do some special checks for these tags. They are inside this |else if|
|
||||
for performance reasons */
|
||||
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
|
||||
if (domElement)
|
||||
{
|
||||
nsString classValue;
|
||||
if (NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING("class"), classValue)) &&
|
||||
StringBeginsWith(classValue, NS_LITERAL_STRING("moz-txt"), nsCaseInsensitiveStringComparator()))
|
||||
{
|
||||
*_retval = nsIMsgCompConvertible::Plain;
|
||||
return rv; // Inconsistent :-(
|
||||
}
|
||||
}
|
||||
|
||||
// Maybe, it's an <a> element inserted by another recognizer (e.g. 4.x')
|
||||
if (element.LowerCaseEqualsLiteral("a"))
|
||||
|
@ -5263,12 +5272,9 @@ nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
(as inserted by recognizers) */
|
||||
*_retval = nsIMsgCompConvertible::Altering;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
|
||||
if (domElement)
|
||||
{
|
||||
nsString hrefValue;
|
||||
nsAutoString hrefValue;
|
||||
bool hasChild;
|
||||
if (NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING("href"), hrefValue)) &&
|
||||
if (NS_SUCCEEDED(node->GetAttribute(NS_LITERAL_STRING("href"), hrefValue)) &&
|
||||
NS_SUCCEEDED(node->HasChildNodes(&hasChild)) && hasChild)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNodeList> children;
|
||||
|
@ -5283,7 +5289,6 @@ nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
*_retval = nsIMsgCompConvertible::Plain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, test, if it is just a "simple" <div> or <span>
|
||||
|
@ -5292,24 +5297,14 @@ nsresult nsMsgCompose::TagConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
element.LowerCaseEqualsLiteral("span")
|
||||
)
|
||||
{
|
||||
/* skip only if no style attribute */
|
||||
*_retval = nsIMsgCompConvertible::Plain;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(node);
|
||||
if (domElement)
|
||||
{
|
||||
nsAutoString styleValue;
|
||||
if (NS_SUCCEEDED(domElement->GetAttribute(NS_LITERAL_STRING("style"), styleValue)) &&
|
||||
!styleValue.IsEmpty())
|
||||
*_retval = nsIMsgCompConvertible::No;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsMsgCompose::_BodyConvertible(nsIDOMNode *node, int32_t *_retval)
|
||||
nsresult nsMsgCompose::_NodeTreeConvertible(nsIDOMElement *node, int32_t *_retval)
|
||||
{
|
||||
NS_ENSURE_TRUE(node && _retval, NS_ERROR_NULL_POINTER);
|
||||
|
||||
|
@ -5337,10 +5332,16 @@ nsresult nsMsgCompose::_BodyConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
if (NS_SUCCEEDED(children->Item(i, getter_AddRefs(pItem)))
|
||||
&& pItem)
|
||||
{
|
||||
int32_t curresult;
|
||||
rv = _BodyConvertible(pItem, &curresult);
|
||||
if (NS_SUCCEEDED(rv) && curresult > result)
|
||||
result = curresult;
|
||||
// We assume all nodes that are not elements are convertible,
|
||||
// so only test elements.
|
||||
nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(pItem);
|
||||
if (domElement) {
|
||||
int32_t curresult;
|
||||
rv = _NodeTreeConvertible(domElement, &curresult);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && curresult > result)
|
||||
result = curresult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5350,25 +5351,24 @@ nsresult nsMsgCompose::_BodyConvertible(nsIDOMNode *node, int32_t *_retval)
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsMsgCompose::BodyConvertible(int32_t *_retval)
|
||||
NS_IMETHODIMP
|
||||
nsMsgCompose::BodyConvertible(int32_t *_retval)
|
||||
{
|
||||
NS_ENSURE_TRUE(_retval, NS_ERROR_NULL_POINTER);
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
NS_ENSURE_STATE(m_editor);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (!m_editor)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMElement> rootElement;
|
||||
rv = m_editor->GetRootElement(getter_AddRefs(rootElement));
|
||||
if (NS_FAILED(rv) || nullptr == rootElement)
|
||||
nsCOMPtr<nsIDOMDocument> rootDocument;
|
||||
nsresult rv = m_editor->GetDocument(getter_AddRefs(rootDocument));
|
||||
if (NS_FAILED(rv) || !rootDocument)
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(rootElement);
|
||||
if (nullptr == node)
|
||||
return NS_ERROR_FAILURE;
|
||||
// get the top level element, which contains <html>
|
||||
nsCOMPtr<nsIDOMElement> rootElement;
|
||||
rv = rootDocument->GetDocumentElement(getter_AddRefs(rootElement));
|
||||
if (NS_FAILED(rv) || !rootElement)
|
||||
return rv;
|
||||
|
||||
return _BodyConvertible(node, _retval);
|
||||
return _NodeTreeConvertible(rootElement, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -83,8 +83,8 @@ protected:
|
|||
nsCOMArray<nsIAbDirectory> &aDirArray);
|
||||
nsresult BuildMailListArray(nsIAbDirectory* parentDir,
|
||||
nsTArray<nsMsgMailList>& array);
|
||||
nsresult TagConvertible(nsIDOMNode *node, int32_t *_retval);
|
||||
nsresult _BodyConvertible(nsIDOMNode *node, int32_t *_retval);
|
||||
nsresult TagConvertible(nsIDOMElement *node, int32_t *_retval);
|
||||
nsresult _NodeTreeConvertible(nsIDOMElement *node, int32_t *_retval);
|
||||
|
||||
// 3 = To, Cc, Bcc
|
||||
#define MAX_OF_RECIPIENT_ARRAY 3
|
||||
|
|
Загрузка…
Ссылка в новой задаче