MAILET-98 test & refactor AddFooter Mailet
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f91fc653 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f91fc653 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f91fc653 Branch: refs/heads/master Commit: f91fc653f104b865512024b2e4ae9f8470fb0c57 Parents: 4f8d81d Author: Matthieu Baechler <[email protected]> Authored: Wed Aug 24 11:59:10 2016 +0200 Committer: Matthieu Baechler <[email protected]> Committed: Thu Aug 25 14:37:27 2016 +0200 ---------------------------------------------------------------------- .../org/apache/mailet/base/test/FakeMail.java | 13 + .../org/apache/mailet/base/test/MailUtil.java | 15 +- .../transport/mailets/AbstractAddFooter.java | 193 ------ .../james/transport/mailets/AddFooter.java | 184 ++++-- .../james/transport/mailets/AddFooterTest.java | 595 +++++++++++-------- 5 files changed, 516 insertions(+), 484 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/f91fc653/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java ---------------------------------------------------------------------- diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java index 37295a8..c534f32 100644 --- a/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java +++ b/mailet/base/src/test/java/org/apache/mailet/base/test/FakeMail.java @@ -20,7 +20,9 @@ package org.apache.mailet.base.test; +import java.io.ByteArrayInputStream; import java.io.Serializable; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -39,6 +41,17 @@ import org.apache.mailet.MailAddress; public class FakeMail implements Mail { + public static FakeMail fromMime(String text, String javaEncodingCharset, String javamailDefaultEncodingCharset) throws MessagingException, UnsupportedEncodingException { + FakeMail mail = new FakeMail(); + Properties javamailProperties = new Properties(); + javamailProperties.setProperty("mail.mime.charset", javamailDefaultEncodingCharset); + mail.setMessage( + new MimeMessage( + Session.getInstance(javamailProperties), + new ByteArrayInputStream(text.getBytes(javaEncodingCharset)))); + return mail; + } + public static Builder builder() { return new Builder(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/f91fc653/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java ---------------------------------------------------------------------- diff --git a/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java b/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java index 3fc1876..be356b3 100644 --- a/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java +++ b/mailet/base/src/test/java/org/apache/mailet/base/test/MailUtil.java @@ -19,14 +19,17 @@ package org.apache.mailet.base.test; -import org.apache.mailet.MailAddress; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.ParseException; -import java.util.Arrays; +import org.apache.mailet.Mail; +import org.apache.mailet.MailAddress; /** * some utilities for James unit testing @@ -78,5 +81,13 @@ public class MailUtil { mockedMimeMessage.saveChanges(); return mockedMimeMessage; } + + public static String toString(Mail mail, String charset) throws IOException, MessagingException { + ByteArrayOutputStream rawMessage = new ByteArrayOutputStream(); + mail.getMessage().writeTo( + rawMessage, + new String[] { "Bcc", "Content-Length", "Message-ID" }); + return rawMessage.toString(charset); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/f91fc653/mailet/standard/src/main/java/org/apache/james/transport/mailets/AbstractAddFooter.java ---------------------------------------------------------------------- diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AbstractAddFooter.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AbstractAddFooter.java deleted file mode 100644 index e1c9700..0000000 --- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AbstractAddFooter.java +++ /dev/null @@ -1,193 +0,0 @@ -/**************************************************************** - * Licensed to the Apache Software Foundation (ASF) under one * - * or more contributor license agreements. See the NOTICE file * - * distributed with this work for additional information * - * regarding copyright ownership. The ASF licenses this file * - * to you under the Apache License, Version 2.0 (the * - * "License"); you may not use this file except in compliance * - * with the License. You may obtain a copy of the License at * - * * - * http://www.apache.org/licenses/LICENSE-2.0 * - * * - * Unless required by applicable law or agreed to in writing, * - * software distributed under the License is distributed on an * - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * - * KIND, either express or implied. See the License for the * - * specific language governing permissions and limitations * - * under the License. * - ****************************************************************/ - - - -package org.apache.james.transport.mailets; - -import org.apache.mailet.base.GenericMailet; -import org.apache.mailet.Mail; -import org.apache.mailet.base.RFC2822Headers; - -import javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import javax.mail.internet.MimePart; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -/** - * An abstract implementation of a mailet that add a Footer to an email - */ -public abstract class AbstractAddFooter extends GenericMailet { - - /** - * Takes the message and attaches a footer message to it. Right now, it only - * supports simple messages. Needs to have additions to make it support - * messages with alternate content types or with attachments. - * - * @param mail the mail being processed - * - * @throws MessagingException if an error arises during message processing - */ - public void service(Mail mail) throws MessagingException { - try { - MimeMessage message = mail.getMessage(); - - if (attachFooter(message)) { - message.saveChanges(); - } else { - log("Unable to add footer to mail " + mail.getName()); - } - } catch (UnsupportedEncodingException e) { - log("UnsupportedEncoding Unable to add footer to mail " - + mail.getName()); - } catch (IOException ioe) { - throw new MessagingException("Could not read message", ioe); - } - } - - /** - * Prepends the content of the MimePart as text to the existing footer - * - * @param part the MimePart to attach - * - * @throws MessagingException - * @throws IOException - */ - protected void addToText(MimePart part) throws MessagingException, - IOException { - // log("Trying to add footer to " + part.getContent().toString()); - String contentType = part.getContentType(); - String content = (String) part.getContent(); - - if (!content.endsWith("\n")) { - content += "\r\n"; - } - content += getFooterText(); - - part.setContent(content, contentType); - part.setHeader(RFC2822Headers.CONTENT_TYPE, contentType); - // log("After adding footer: " + part.getContent().toString()); - } - - /** - * Prepends the content of the MimePart as HTML to the existing footer - * - * @param part the MimePart to attach - * - * @throws MessagingException - * @throws IOException - */ - protected void addToHTML(MimePart part) throws MessagingException, - IOException { - // log("Trying to add footer to " + part.getContent().toString()); - String contentType = part.getContentType(); - String content = (String) part.getContent(); - - /* This HTML part may have a closing <BODY> tag. If so, we - * want to insert out footer immediately prior to that tag. - */ - int index = content.lastIndexOf("</body>"); - if (index == -1) - index = content.lastIndexOf("</BODY>"); - String insert = "<br>" + getFooterHTML(); - content = index == -1 ? content + insert : content.substring(0, index) - + insert + content.substring(index); - - part.setContent(content, contentType); - part.setHeader(RFC2822Headers.CONTENT_TYPE, contentType); - // log("After adding footer: " + part.getContent().toString()); - } - - /** - * Attach a footer a MimePart - * - * @param part the MimePart to which the footer is to be attached - * - * @return whether a footer was successfully attached - * @throws MessagingException - * @throws IOException - */ - protected boolean attachFooter(MimePart part) throws MessagingException, - IOException { - // log("Content type is " + part.getContentType()); - if (part.isMimeType("text/plain") - && part.getContent() instanceof String) { - addToText(part); - return true; - } else if (part.isMimeType("text/html") - && part.getContent() instanceof String) { - addToHTML(part); - return true; - } else if (part.isMimeType("multipart/mixed") - || part.isMimeType("multipart/related")) { - //Find the first body part, and determine what to do then. - MimeMultipart multipart = (MimeMultipart) part.getContent(); - MimeBodyPart firstPart = (MimeBodyPart) multipart.getBodyPart(0); - boolean isFooterAttached = attachFooter(firstPart); - if (isFooterAttached) { - //We have to do this because of a bug in JavaMail (ref id 4403733) - //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4403733 - part.setContent(multipart); - } - return isFooterAttached; - } else if (part.isMimeType("multipart/alternative")) { - MimeMultipart multipart = (MimeMultipart) part.getContent(); - int count = multipart.getCount(); - // log("number of alternatives = " + count); - boolean isFooterAttached = false; - for (int index = 0; index < count; index++) { - // log("processing alternative #" + index); - MimeBodyPart mimeBodyPart = (MimeBodyPart) multipart - .getBodyPart(index); - isFooterAttached |= attachFooter(mimeBodyPart); - } - if (isFooterAttached) { - //We have to do this because of a bug in JavaMail (ref id 4403733) - //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4403733 - part.setContent(multipart); - } - return isFooterAttached; - } else { - //Give up... we won't attach the footer to this MimePart - return false; - } - } - - /** - * This is exposed as a method for easy subclassing to provide alternate ways - * to get the footer text. - * - * @return the footer text - */ - protected abstract String getFooterText(); - - /** - * This is exposed as a method for easy subclassing to provide alternate ways - * to get the footer text. By default, this will take the footer text, - * converting the linefeeds to <br> tags. - * - * @return the HTML version of the footer text - */ - protected abstract String getFooterHTML(); - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/f91fc653/mailet/standard/src/main/java/org/apache/james/transport/mailets/AddFooter.java ---------------------------------------------------------------------- diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AddFooter.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AddFooter.java index c973fb3..9cf44f9 100644 --- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AddFooter.java +++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AddFooter.java @@ -21,68 +21,160 @@ package org.apache.james.transport.mailets; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.mail.MessagingException; -import java.util.StringTokenizer; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import javax.mail.internet.MimePart; + +import org.apache.mailet.Mail; +import org.apache.mailet.base.GenericMailet; +import org.apache.mailet.base.RFC2822Headers; -/** - * This mailet will attach text to the end of the message (like a footer). Right - * now it only supports simple messages without multiple parts. +import com.google.common.base.Optional; + +/* + * Takes the message and attaches a footer message to it. Right now, it only + * supports simple messages. Needs to have additions to make it support + * messages with alternate content types or with attachments. */ -public class AddFooter extends AbstractAddFooter { +public class AddFooter extends GenericMailet { - /** - * This is the plain text version of the footer we are going to add - */ - String text = ""; + private static final String HTML_BR_TAG = "<br />"; + private static final String CARRIAGE_RETURN = "\r\n"; + private static final Pattern BODY_CLOSING_TAG = Pattern.compile("((?i:</body>))"); + private String plainTextFooter; - /** - * Initialize the mailet - */ + @Override public void init() throws MessagingException { - text = getInitParameter("text"); + plainTextFooter = getInitParameter("text"); } - /** - * This is exposed as a method for easy subclassing to provide alternate ways - * to get the footer text. - * - * @return the footer text - */ - public String getFooterText() { - return text; + @Override + public String getMailetInfo() { + return "AddFooter Mailet"; } + + @Override + public void service(Mail mail) throws MessagingException { + try { + MimeMessage message = mail.getMessage(); - /** - * This is exposed as a method for easy subclassing to provide alternate ways - * to get the footer text. By default, this will take the footer text, - * converting the linefeeds to <br> tags. - * - * @return the HTML version of the footer text - */ - public String getFooterHTML() { - String text = getFooterText(); - StringBuilder sb = new StringBuilder(); - StringTokenizer st = new StringTokenizer(text, "\r\n", true); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (token.equals("\r")) { - continue; - } - if (token.equals("\n")) { - sb.append("<br />\n"); + if (attachFooter(message)) { + message.saveChanges(); } else { - sb.append(token); + log("Unable to add footer to mail " + mail.getName()); } + } catch (UnsupportedEncodingException e) { + log("UnsupportedEncoding Unable to add footer to mail " + + mail.getName()); + } catch (IOException ioe) { + throw new MessagingException("Could not read message", ioe); + } + } + + private boolean attachFooter(MimePart part) throws MessagingException, IOException { + String contentType = part.getContentType(); + + if (part.getContent() instanceof String) { + Optional<String> content = attachFooterToTextPart(part); + if (content.isPresent()) { + part.setContent(content.get(), contentType); + part.setHeader(RFC2822Headers.CONTENT_TYPE, contentType); + return true; + } + } + + if (part.isMimeType("multipart/mixed") + || part.isMimeType("multipart/related")) { + MimeMultipart multipart = (MimeMultipart) part.getContent(); + return attachFooterToFirstPart(multipart); + + } else if (part.isMimeType("multipart/alternative")) { + MimeMultipart multipart = (MimeMultipart) part.getContent(); + return attachFooterToAllSubparts(multipart); } - return sb.toString(); + //Give up... we won't attach the footer to this MimePart + return false; } /** - * Return a string describing this mailet. + * Prepends the content of the MimePart as text to the existing footer * - * @return a string describing this mailet + * @param part the MimePart to attach */ - public String getMailetInfo() { - return "AddFooter Mailet"; - } + private String attachFooterToText(String content) throws MessagingException, + IOException { + + StringBuilder builder = new StringBuilder(content); + ensureTrailingCarriageReturn(content, builder); + builder.append(getFooterText()); + return builder.toString(); + } + + private void ensureTrailingCarriageReturn(String content, StringBuilder builder) { + if (!content.endsWith("\n")) { + builder.append(CARRIAGE_RETURN); + } + } + + /** + * Prepends the content of the MimePart as HTML to the existing footer + */ + private String attachFooterToHTML(String content) throws MessagingException, + IOException { + + /* This HTML part may have a closing <BODY> tag. If so, we + * want to insert out footer immediately prior to that tag. + */ + Matcher matcher = BODY_CLOSING_TAG.matcher(content); + if (!matcher.find()) { + return content + getFooterHTML(); + } + int insertionIndex = matcher.start(matcher.groupCount() - 1); + return new StringBuilder() + .append(content.substring(0, insertionIndex)) + .append(getFooterHTML()) + .append(content.substring(insertionIndex, content.length())) + .toString(); + } + + private Optional<String> attachFooterToTextPart(MimePart part) throws MessagingException, IOException { + String content = (String) part.getContent(); + if (part.isMimeType("text/plain")) { + return Optional.of(attachFooterToText(content)); + } else if (part.isMimeType("text/html")) { + return Optional.of(attachFooterToHTML(content)); + } + return Optional.absent(); + } + + private boolean attachFooterToFirstPart(MimeMultipart multipart) throws MessagingException, IOException { + MimeBodyPart firstPart = (MimeBodyPart) multipart.getBodyPart(0); + return attachFooter(firstPart); + } + + private boolean attachFooterToAllSubparts(MimeMultipart multipart) throws MessagingException, IOException { + int count = multipart.getCount(); + boolean isFooterAttached = false; + for (int index = 0; index < count; index++) { + MimeBodyPart mimeBodyPart = (MimeBodyPart) multipart.getBodyPart(index); + isFooterAttached |= attachFooter(mimeBodyPart); + } + return isFooterAttached; + } + + private String getFooterText() { + return plainTextFooter; + } + + private String getFooterHTML() { + String text = getFooterText(); + return HTML_BR_TAG + text.replaceAll(CARRIAGE_RETURN, HTML_BR_TAG); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/f91fc653/mailet/standard/src/test/java/org/apache/james/transport/mailets/AddFooterTest.java ---------------------------------------------------------------------- diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/AddFooterTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/AddFooterTest.java index 4257ff4..0eaffc4 100644 --- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/AddFooterTest.java +++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/AddFooterTest.java @@ -19,293 +19,402 @@ package org.apache.james.transport.mailets; -import org.apache.james.transport.mailets.AddFooter; -import org.apache.mailet.base.test.FakeMail; -import org.apache.mailet.base.test.FakeMailContext; -import org.apache.mailet.base.test.FakeMailetConfig; -import org.apache.mailet.Mail; -import org.apache.mailet.Mailet; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeUtility; +import static org.assertj.core.api.Assertions.assertThat; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Properties; - -import junit.framework.TestCase; - -/** - * Test encoding issues - * - * This test should also be run with the following JVM options to be sure it tests: - * "-Dfile.encoding=ASCII -Dmail.mime.charset=ANSI_X3.4-1968" - */ -public class AddFooterTest extends TestCase { +import java.util.Collection; +import java.util.List; +import java.util.Set; - public AddFooterTest(String arg0) throws UnsupportedEncodingException { - super(arg0); - - /* - - String encoding = (new InputStreamReader(System.in)).getEncoding(); - System.out.println("System Encoding: "+encoding); - System.out.println("Default Java Charset:"+MimeUtility.getDefaultJavaCharset()); - System.out.println("---------"); - String a = "\u20AC\u00E0"; // euro char followed by an italian a with an accent System.out.println(debugString(a,"UTF-8")); - System.out.println(debugString(a,"UTF8")); - System.out.println(debugString(a,"UTF-16")); - System.out.println(debugString(a,"UNICODE")); - System.out.println(debugString(a,"ISO-8859-15")); - System.out.println(debugString(a,"ISO-8859-1")); - System.out.println(debugString(a,"CP1252")); - System.out.println(debugString(a,"ANSI_X3.4-1968")); - - */ - } +import javax.mail.MessagingException; - private final static char[] hexchars = { '0', '1', '2', '3', '4', '5', '6', - '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - public String debugString(String a, String charset) - throws UnsupportedEncodingException { - byte[] bytes = a.getBytes(charset); - StringBuilder res = new StringBuilder(); - for (int i = 0; i < bytes.length; i++) { - if (i > 0) - res.append("-"); - res.append(hexchars[((bytes[i] + 256) % 256) / 16]); - res.append(hexchars[((bytes[i] + 256) % 256) % 16]); +import org.apache.mailet.Mail; +import org.apache.mailet.Mailet; +import org.apache.mailet.base.test.FakeMail; +import org.apache.mailet.base.test.FakeMailContext; +import org.apache.mailet.base.test.FakeMailetConfig; +import org.apache.mailet.base.test.MailUtil; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +@RunWith(Parameterized.class) +public class AddFooterTest { + + @Rule public ExpectedException exception = ExpectedException.none(); + + private final String javaCharset; + private final String javaMailCharset; + private Mailet mailet; + private FakeMailetConfig mailetConfig; + + @Parameters + public static Collection<String[]> data() { + //javamail has its own charset handling logic, it needs to be exercised + List<String[]> charsets = Lists.newArrayList(); + Set<String> charsetNamesToTest = Sets.newHashSet( + "ANSI_X3.4-1968", + "iso-ir-6", + "ANSI_X3.4-1986", + "ISO_646.irv:1991", + "ASCII", + "ISO646-US", + "US-ASCII", + "us", + "IBM367", + "cp367", + "csASCII"); + Set<List<String>> cartesianProduct = Sets.cartesianProduct(ImmutableList.of(charsetNamesToTest, charsetNamesToTest)); + for (List<String> pair: cartesianProduct) { + charsets.add(new String[]{pair.get(0), pair.get(1)}); } - res.append(" ("); - res.append(MimeUtility.mimeCharset(charset)); - res.append(" / "); - res.append(MimeUtility.javaCharset(charset)); - res.append(")"); - return res.toString(); + return charsets; } + + public AddFooterTest(String javaCharset, String javaMailCharset) { + this.javaCharset = javaCharset; + this.javaMailCharset = javaMailCharset; + } + + @Before + public void setup() { + mailet = new AddFooter(); + mailetConfig = new FakeMailetConfig("Test", new FakeMailContext()); - /* - * Class under test for String getSubject() - */ - public void testAddFooterTextPlain() throws MessagingException, IOException { - - // quoted printable mimemessage text/plain - String asciisource = "Subject: test\r\nContent-Type: text/plain; charset=ISO-8859-15\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and one\r\n"; - - String iso885915qpheader = "------ my footer =E0/=A4 ------"; - String footer = "------ my footer \u00E0/\u20AC ------"; + } + + @Test + public void shouldAddFooterWhenQuotedPrintableTextPlainMessage() throws MessagingException, IOException { - String res = processAddFooter(asciisource, footer); + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String quotedPrintableTextPlainMessage = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: text/plain; charset=ISO-8859-15", + "MIME-Version: 1.0", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and one =A4", + ""); + + String expectedFooter = "------ my footer =E0/=A4 ------"; + + Mail mail = FakeMail.fromMime(quotedPrintableTextPlainMessage, javaCharset, javaMailCharset); + mailet.service(mail); - assertEquals(asciisource + iso885915qpheader, res); + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(quotedPrintableTextPlainMessage + expectedFooter); } - public void testUnsupportedEncoding() throws MessagingException, IOException { + @Test + public void shouldEnsureCarriageReturnWhenAddFooterWithTextPlainMessage() throws MessagingException, IOException { - // quoted printable mimemessage text/plain - String asciisource = "Subject: test\r\nContent-Type: text/plain; charset=UNSUPPORTED_ENCODING\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and one\r\n"; + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String quotedPrintableTextPlainMessage = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: text/plain; charset=ISO-8859-15", + "MIME-Version: 1.0", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and one =A4"); + + String expected = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: text/plain; charset=ISO-8859-15", + "MIME-Version: 1.0", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and one =A4", + "------ my footer =E0/=A4 ------"); + - String footer = "------ my footer \u00E0/\u20AC ------"; + Mail mail = FakeMail.fromMime(quotedPrintableTextPlainMessage, javaCharset, javaMailCharset); + mailet.service(mail); - try { - String res = processAddFooter(asciisource, footer); - assertEquals(asciisource, res); - } catch (Exception e) { - fail("should not throw an exception: "+e.getMessage()); - } + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(expected); + } + + @Test + public void shouldNotAddFooterWhenUnsupportedEncoding() throws MessagingException, IOException { + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String quotedPrintableTextPlainMessage = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: text/plain; charset=UNSUPPORTED_ENCODING", + "MIME-Version: 1.0", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and one", + ""); + + Mail mail = FakeMail.fromMime(quotedPrintableTextPlainMessage, javaCharset, javaMailCharset); + mailet.service(mail); + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(quotedPrintableTextPlainMessage); } - /* - * Test for JAMES-443 - * This should not add the header and should leave the multipart/mixed Content-Type intact - */ - public void testAddFooterMimeNestedUnsupportedMultipart() throws MessagingException, IOException { - - // quoted printable mimemessage text/plain - String asciisource = "MIME-Version: 1.0\r\n" - +"Content-Type: multipart/mixed; boundary=\"===============0204599088==\"\r\n" - +"\r\n" - +"This is a cryptographically signed message in MIME format.\r\n" - +"\r\n" - +"--===============0204599088==\r\n" - +"Content-Type: multipart/unsupported; boundary=\"------------ms050404020900070803030808\"\r\n" - +"\r\n" - +"--------------ms050404020900070803030808\r\n" - +"Content-Type: text/plain; charset=ISO-8859-1\r\n" - +"\r\n" - +"test\r\n" - +"\r\n" - +"--------------ms050404020900070803030808--\r\n" - +"\r\n" - +"--===============0204599088==--\r\n"; - // String asciisource = "Subject: test\r\nContent-Type: multipart/mixed; boundary=\"===============0204599088==\"\r\nMIME-Version: 1.0\r\n\r\nThis is a cryptographically signed message in MIME format.\r\n\r\n--===============0204599088==\r\nContent-Type: text/plain\r\n\r\ntest\r\n--===============0204599088==\r\nContent-Type: text/plain; charset=\"us-ascii\"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline\r\n\r\ntest\r\n--===============0204599088==--\r\n"; - - String footer = "------ my footer \u00E0/\u20AC ------"; - - String res = processAddFooter(asciisource, footer); - - assertEquals(asciisource, res); + @Test + public void shouldNotAddFooterWhenUnsupportedTextContentType() throws MessagingException, IOException { + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String quotedPrintableTextPlainMessage = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: text/calendar; charset=ASCII", + "MIME-Version: 1.0", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and one", + ""); + + Mail mail = FakeMail.fromMime(quotedPrintableTextPlainMessage, javaCharset, javaMailCharset); + mailet.service(mail); + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(quotedPrintableTextPlainMessage); } /* - * Test for JAMES-368 - * AddFooter couldn't process mails which MimeType is multipart/related + * Test for JAMES-443 + * This should not add the header and should leave the multipart/mixed Content-Type intact */ - public void testAddFooterMultipartRelated() throws MessagingException, IOException { - - // quoted printable mimemessage text/plain - String asciisource = "MIME-Version: 1.0\r\n" - +"Subject: test\r\n" - +"Content-Type: multipart/related;\r\n" - +" boundary=\"------------050206010102010306090507\"\r\n" - +"\r\n" - +"--------------050206010102010306090507\r\n" - +"Content-Type: text/html; charset=ISO-8859-15\r\n" - +"Content-Transfer-Encoding: quoted-printable\r\n" - +"\r\n" - +"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n" - +"<html>\r\n" - +"<head>\r\n" - +"<meta content=3D\"text/html;charset=3DISO-8859-15\" http-equiv=3D\"Content-Typ=\r\n" - +"e\">\r\n" - +"</head>\r\n" - +"<body bgcolor=3D\"#ffffff\" text=3D\"#000000\">\r\n" - +"<br>\r\n" - +"<div class=3D\"moz-signature\">-- <br>\r\n" - +"<img src=3D\"cid:[email protected]\" border=3D\"0\"></div>\r\n"; - String asciifoot = "</body>\r\n" - +"</html>\r\n" - +"\r\n" - +"--------------050206010102010306090507\r\n" - +"Content-Type: image/gif\r\n" - +"Content-Transfer-Encoding: base64\r\n" - +"Content-ID: <[email protected]>\r\n" - +"Content-Disposition: inline;\r\n" - +"\r\n" - +"YQ==\r\n" - +"--------------050206010102010306090507--\r\n"; - - // String asciisource = "Subject: test\r\nContent-Type: multipart/mixed; boundary=\"===============0204599088==\"\r\nMIME-Version: 1.0\r\n\r\nThis is a cryptographically signed message in MIME format.\r\n\r\n--===============0204599088==\r\nContent-Type: text/plain\r\n\r\ntest\r\n--===============0204599088==\r\nContent-Type: text/plain; charset=\"us-ascii\"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nContent-Disposition: inline\r\n\r\ntest\r\n--===============0204599088==--\r\n"; - - String footer = "------ my footer \u00E0/\u20AC ------"; - String expectedFooter = "<br>------ my footer =E0/=A4 ------"; - - String res = processAddFooter(asciisource+asciifoot, footer); - - assertEquals(asciisource+expectedFooter+asciifoot, res); + @Test + public void shouldNotAddFooterWhenNestedUnsupportedMultipart() throws MessagingException, IOException { + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String quotedPrintableMultipartMixedMessage = Joiner.on("\r\n").join( + "MIME-Version: 1.0", + "Content-Type: multipart/mixed; boundary=\"===============0204599088==\"", + "", + "This is a cryptographically signed message in MIME format.", + "", + "--===============0204599088==", + "Content-Type: multipart/unsupported; boundary=\"------------ms050404020900070803030808\"", + "", + "--------------ms050404020900070803030808", + "Content-Type: text/plain; charset=ISO-8859-1", + "", + "test", + "", + "--------------ms050404020900070803030808--", + "", + "--===============0204599088==--", + ""); + + Mail mail = FakeMail.fromMime(quotedPrintableMultipartMixedMessage, javaCharset, javaMailCharset); + mailet.service(mail); + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(quotedPrintableMultipartMixedMessage); } - - /* - * Class under test for String getSubject() + * Test for JAMES-368 */ - public void testAddFooterTextPlainISO8859() throws MessagingException, IOException { - - // quoted printable mimemessage text/plain - String asciisource = "Subject: test\r\nContent-Type: text/plain; charset=iso-8859-15\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and one =A4\r\n"; + @Test + public void shouldAddFooterWhenMultipartRelatedHtmlMessage() throws MessagingException, IOException { - String iso885915qpheader = "------ my footer =E0/=A4 ------"; - String footer = "------ my footer \u00E0/\u20AC ------"; - - String res = processAddFooter(asciisource, footer); - - assertEquals(asciisource + iso885915qpheader, res); + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String htmlMultipartRelatedMessagePart1 = Joiner.on("\r\n").join( + "MIME-Version: 1.0", + "Subject: test", + "Content-Type: multipart/related;", + " boundary=\"------------050206010102010306090507\"", + "", + "--------------050206010102010306090507", + "Content-Type: text/html; charset=ISO-8859-15", + "Content-Transfer-Encoding: quoted-printable", + "", + "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">", + "<html>", + "<head>", + "<meta content=3D\"text/html;charset=3DISO-8859-15\" http-equiv=3D\"Content-Typ=", + "e\">", + "</head>", + "<body bgcolor=3D\"#ffffff\" text=3D\"#000000\">", + "<br>", + "<div class=3D\"moz-signature\">-- <br>", + "<img src=3D\"cid:[email protected]\" border=3D\"0\"></div>", + ""); + + String htmlMultipartRelatedMessagePart2 = Joiner.on("\r\n").join( + "</body>", + "</html>", + "", + "--------------050206010102010306090507", + "Content-Type: image/gif", + "Content-Transfer-Encoding: base64", + "Content-ID: <[email protected]>", + "Content-Disposition: inline;", + "", + "YQ==", + "--------------050206010102010306090507--", + ""); + + String expectedFooter = "<br />------ my footer =E0/=A4 ------"; + + Mail mail = FakeMail.fromMime(htmlMultipartRelatedMessagePart1 + htmlMultipartRelatedMessagePart2, javaCharset, javaMailCharset); + mailet.service(mail); + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(htmlMultipartRelatedMessagePart1 + expectedFooter + htmlMultipartRelatedMessagePart2); } - - /* - * Class under test for String getSubject() - */ - public void testAddFooterMultipartAlternative() throws MessagingException, + + @Test + public void shouldAddFooterWhenMultipartAlternivateMessage() throws MessagingException, IOException { - String sep = "--==--"; - String head = "Subject: test\r\nContent-Type: multipart/alternative;\r\n boundary=\"" - + sep - + "\"\r\nMIME-Version: 1.0\r\n"; - String content1 = "Content-Type: text/plain;\r\n charset=\"ISO-8859-15\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nTest=E0 and @=80"; - String c2h = "Content-Type: text/html;\r\n charset=\"CP1252\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n"; - String c2pre = "<html><body>test =80 ss"; - String c2post = "</body></html>"; - - StringBuilder asciisource = new StringBuilder(); - asciisource.append(head); - asciisource.append("\r\n--"); - asciisource.append(sep); - asciisource.append("\r\n"); - asciisource.append(content1); - asciisource.append("\r\n--"); - asciisource.append(sep); - asciisource.append("\r\n"); - asciisource.append(c2h); - asciisource.append(c2pre); - asciisource.append(c2post); - asciisource.append("\r\n--"); - asciisource.append(sep); - asciisource.append("--\r\n"); - - String iso885915qpheader = "------ my footer =E0/=A4 ------"; - String cp1252qpfooter = "------ my footer =E0/=80 ------"; - String footer = "------ my footer \u00E0/\u20AC ------"; - - StringBuilder expected = new StringBuilder(); - expected.append(head); - expected.append("\r\n--"); - expected.append(sep); - expected.append("\r\n"); - expected.append(content1); - expected.append("\r\n"); - expected.append(iso885915qpheader); - expected.append("\r\n--"); - expected.append(sep); - expected.append("\r\n"); - expected.append(c2h); - expected.append(c2pre); - expected.append("<br>"); - expected.append(cp1252qpfooter); - expected.append(c2post); - expected.append("\r\n--"); - expected.append(sep); - expected.append("--\r\n"); + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); - String res = processAddFooter(asciisource.toString(), footer); - - assertEquals(expected.toString(), res); + String multipartAlternativeMessage = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: multipart/alternative;", + " boundary=\"--==--\"", + "MIME-Version: 1.0", + "", + "----==--", + "Content-Type: text/plain;", + " charset=\"ISO-8859-15\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and @=80", + "", + "----==--", + "Content-Type: text/html;", + " charset=\"CP1252\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "<html><body>test =80 ss</body></html>", + "----==----" + ); + + Mail mail = FakeMail.fromMime(multipartAlternativeMessage, javaCharset, javaMailCharset); + mailet.service(mail); + String expected = Joiner.on("\r\n").join( + "Subject: test", + "Content-Type: multipart/alternative;", + " boundary=\"--==--\"", + "MIME-Version: 1.0", + "", + "----==--", + "Content-Type: text/plain;", + " charset=\"ISO-8859-15\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "Test=E0 and @=80", + "------ my footer =E0/=A4 ------", + "----==--", + "Content-Type: text/html;", + " charset=\"CP1252\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "<html><body>test =80 ss<br />------ my footer =E0/=80 ------</body></html>", + "----==----", + "" + ); + + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(expected); } - private String processAddFooter(String asciisource, String footer) - throws MessagingException, IOException { - Mailet mailet = new AddFooter(); + @Test + public void shouldAddFooterWhenHtmlMessageWithMixedCaseBodyTag() throws MessagingException, + IOException { - FakeMailetConfig mci = new FakeMailetConfig("Test",new FakeMailContext()); - mci.setProperty("text",footer); + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String htmlMessage = Joiner.on("\r\n").join( + "Subject: test", + "MIME-Version: 1.0", + "Content-Type: text/html;", + " charset=\"CP1252\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "<html><body>test =80 ss</bOdY></html>", + "" + ); + + Mail mail = FakeMail.fromMime(htmlMessage, javaCharset, javaMailCharset); + mailet.service(mail); - mailet.init(mci); + String expected = Joiner.on("\r\n").join( + "Subject: test", + "MIME-Version: 1.0", + "Content-Type: text/html;", + " charset=\"CP1252\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "<html><body>test =80 ss<br />------ my footer =E0/=80 ------</bOdY></html>", + "" + ); + + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(expected); + } - Mail mail = new FakeMail(); - mail.setMessage(new MimeMessage(Session - .getDefaultInstance(new Properties()), - new ByteArrayInputStream(asciisource.getBytes()))); + @Test + public void shouldAddFooterWhenHtmlMessageWithNoBodyTag() throws MessagingException, + IOException { + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + String htmlMessage = Joiner.on("\r\n").join( + "Subject: test", + "MIME-Version: 1.0", + "Content-Type: text/html;", + " charset=\"CP1252\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "<html><body>test =80 ss", + "" + ); + + Mail mail = FakeMail.fromMime(htmlMessage, javaCharset, javaMailCharset); mailet.service(mail); - ByteArrayOutputStream rawMessage = new ByteArrayOutputStream(); - mail.getMessage().writeTo( - rawMessage, - new String[] { "Bcc", "Content-Length", "Message-ID" }); - return rawMessage.toString(); + String expected = Joiner.on("\r\n").join( + "Subject: test", + "MIME-Version: 1.0", + "Content-Type: text/html;", + " charset=\"CP1252\"", + "Content-Transfer-Encoding: quoted-printable", + "", + "<html><body>test =80 ss", + "<br />------ my footer =E0/=80 ------" + ); + + assertThat(MailUtil.toString(mail, javaCharset)).isEqualTo(expected); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldThrowMessagingExceptionWhenIOExceptionReadingMessage() throws MessagingException { + mailetConfig.setProperty("text", "------ my footer \u00E0/\u20AC ------"); + mailet.init(mailetConfig); + + Mail mail = mock(Mail.class); + when(mail.getMessage()).thenThrow(IOException.class); + exception.expect(MessagingException.class); + + mailet.service(mail); } - } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
