From 5c9be9af18020870d38562110af9c7ad86f4affa Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Fri, 25 Mar 2011 14:48:24 -0700 Subject: [PATCH] DO NOT MERGE Don't duplicate HTML in reply / forward On exchange servers that support "smart reply", the original message is actually appended by the server. In this situation, we should not append the original HTML text on the client. bug 4177192 Change-Id: I0bdb34cf837e0cc0bfac8917f993ecb764814d97 --- .../emailcommon/internet/Rfc822Output.java | 23 +++--- .../internet/Rfc822OutputTests.java | 73 +++++++++++++++++++ 2 files changed, 84 insertions(+), 12 deletions(-) diff --git a/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java b/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java index 6aa70d334..36b72c5db 100644 --- a/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java +++ b/emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java @@ -29,6 +29,7 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.text.Html; +import android.text.TextUtils; import android.util.Base64; import android.util.Base64OutputStream; @@ -88,17 +89,21 @@ public class Rfc822Output { /** * Returns an HTML encoded message alternate */ - private static String getHtmlAlternate(Body body) { + /*package*/ static String getHtmlAlternate(Body body, boolean useSmartReply) { if (body.mHtmlReply == null) { return null; } StringBuffer altMessage = new StringBuffer(); - altMessage.append(body.mTextContent.replaceAll("\\r?\\n", "
")); + String htmlContent = TextUtils.htmlEncode(body.mTextContent); // Escape HTML reserved chars + altMessage.append(htmlContent.replaceAll("\\r?\\n", "
")); if (body.mIntroText != null) { - altMessage.append(body.mIntroText.replaceAll("\\r?\\n", "
")); + String htmlIntro = TextUtils.htmlEncode(body.mIntroText); + altMessage.append(htmlIntro.replaceAll("\\r?\\n", "
")); + } + if (!useSmartReply) { + String htmlBody = getHtmlBody(body.mHtmlReply); + altMessage.append(htmlBody); } - String htmlBody = getHtmlBody(body.mHtmlReply); - altMessage.append(htmlBody); return altMessage.toString(); } @@ -156,7 +161,7 @@ public class Rfc822Output { } } messageBody[TEXT_BODY_IDX] = text; - messageBody[HTML_BODY_IDX] = getHtmlAlternate(body); + messageBody[HTML_BODY_IDX] = getHtmlAlternate(body, useSmartReply); return messageBody; } @@ -167,13 +172,7 @@ public class Rfc822Output { * @param context system context for accessing the provider * @param messageId the message to write out * @param out the output stream to write the message to -<<<<<<< HEAD:emailcommon/src/com/android/emailcommon/internet/Rfc822Output.java - * @param useSmartReply whether or not quoted text is appended to a reply/forward - * - * TODO alternative parts (e.g. text+html) are not supported here. -======= * @param useSmartReply whether or not to append quoted text if this is a reply/forward ->>>>>>> 5912e7c... Attach original HTML message on forward/reply:src/com/android/emailcommon/internet/Rfc822Output.java */ public static void writeTo(Context context, long messageId, OutputStream out, boolean useSmartReply, boolean sendBcc) throws IOException, MessagingException { diff --git a/tests/src/com/android/emailcommon/internet/Rfc822OutputTests.java b/tests/src/com/android/emailcommon/internet/Rfc822OutputTests.java index dc5999292..07570f32e 100644 --- a/tests/src/com/android/emailcommon/internet/Rfc822OutputTests.java +++ b/tests/src/com/android/emailcommon/internet/Rfc822OutputTests.java @@ -22,6 +22,7 @@ import com.android.emailcommon.internet.Rfc822Output; import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Attachment; +import com.android.emailcommon.provider.EmailContent.Body; import com.android.emailcommon.provider.EmailContent.Message; import org.apache.james.mime4j.field.Field; @@ -52,8 +53,15 @@ public class Rfc822OutputTests extends ProviderTestCase2 { private static final String RECIPIENT_CC = "recipient-cc@android.com"; private static final String SUBJECT = "This is the subject"; private static final String BODY = "This is the body. This is also the body."; + private static final String REPLY_TEXT_BODY = "This is the body. This is also the body."; + /** HTML reply body */ + private static final String BODY_HTML_REPLY = + "This is the body.
This is also the body."; private static final String TEXT = "Here is some new text."; + private static String REPLY_INTRO_TEXT = "\n\n" + SENDER + " wrote:\n\n"; + private static String REPLY_INTRO_HTML = "

" + SENDER + " wrote:

"; + private Context mMockContext; private String mForwardIntro; private String mReplyIntro; @@ -77,6 +85,25 @@ public class Rfc822OutputTests extends ProviderTestCase2 { // TODO Write test that ensures that bcc is handled properly (i.e. sent/not send depending // on the flag passed to writeTo + private Message createTestMessage(String text, boolean save) { + Message message = new Message(); + message.mText = text; + message.mFrom = SENDER; + message.mFlags = Message.FLAG_TYPE_REPLY; + message.mTextReply = REPLY_TEXT_BODY; + message.mHtmlReply = BODY_HTML_REPLY; + message.mIntroText = REPLY_INTRO_TEXT; + if (save) { + message.save(mMockContext); + } + return message; + } + + private Body createTestBody(Message message) { + Body body = Body.restoreBodyWithMessageId(mMockContext, message.mId); + return body; + } + /** * Test for buildBodyText(). * Compare with expected values. @@ -288,6 +315,52 @@ public class Rfc822OutputTests extends ProviderTestCase2 { assertEquals(BODY_RESULT3, actual); } + /** + * Tests that the entire HTML alternate string is valid for text entered by + * the user. We don't test all permutations of forwarded HTML here because + * that is verified by testGetHtmlBody(). + */ + public void testGetHtmlAlternate() { + Message message = createTestMessage(TEXT, true); + Body body = createTestBody(message); + String html; + + // Generic case + html = Rfc822Output.getHtmlAlternate(body, false); + assertEquals(TEXT + REPLY_INTRO_HTML + BODY_HTML_REPLY, html); + + // "smart reply" enabled; html body should not be added + html = Rfc822Output.getHtmlAlternate(body, true); + assertEquals(TEXT + REPLY_INTRO_HTML, html); + + // HTML special characters; dependent upon TextUtils#htmlEncode() + message.mId = -1; // Changing the message; need to reset the id + message.mText = "<>&'\""; + message.save(mMockContext); + body = createTestBody(message); + + html = Rfc822Output.getHtmlAlternate(body, false); + assertEquals("<>&'"" + REPLY_INTRO_HTML + BODY_HTML_REPLY, html); + + // Newlines in user text + message.mId = -1; // Changing the message; need to reset the id + message.mText = "dos\r\nunix\nthree\r\n\n\n"; + message.save(mMockContext); + body = createTestBody(message); + + html = Rfc822Output.getHtmlAlternate(body, false); + assertEquals("dos
unix
three


" + REPLY_INTRO_HTML + BODY_HTML_REPLY, html); + + // Null HTML reply + message.mId = -1; // Changing the message; need to reset the id + message.mHtmlReply = null; + message.save(mMockContext); + body = createTestBody(message); + + html = Rfc822Output.getHtmlAlternate(body, false); + assertNull(html); + } + /** * Confirm that the constructed message includes "MIME-VERSION: 1.0" */