You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2017/01/11 09:26:16 UTC

[28/50] [abbrv] james-project git commit: MAILET-115 Move message altering from AbstractRedirect to AlteredMailUtils

MAILET-115 Move message altering from AbstractRedirect to AlteredMailUtils


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6bffadb9
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6bffadb9
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6bffadb9

Branch: refs/heads/master
Commit: 6bffadb90ea3d5b10b09c41a460c3e0efaacff67
Parents: fe3a35e
Author: Antoine Duprat <ad...@apache.org>
Authored: Tue Nov 15 16:22:20 2016 +0100
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Wed Jan 11 10:03:30 2017 +0700

----------------------------------------------------------------------
 .../mailets/utils/MimeMessageUtils.java         |  15 ++
 .../mailets/utils/MimeMessageUtilsTest.java     |  21 +-
 .../apache/james/transport/mailets/Bounce.java  |   2 +-
 .../james/transport/mailets/DSNBounce.java      |   4 +-
 .../apache/james/transport/mailets/Forward.java |   2 +-
 .../transport/mailets/NotifyPostmaster.java     |   2 +-
 .../james/transport/mailets/NotifySender.java   |   2 +-
 .../james/transport/mailets/Redirect.java       |   2 +-
 .../apache/james/transport/mailets/Resend.java  |   2 +-
 .../mailets/redirect/AbstractRedirect.java      | 193 +-------------
 .../redirect/MailMessageAlteringUtils.java      | 257 +++++++++++++++++++
 .../redirect/MailMessageAlteringUtilsTest.java  | 113 ++++++++
 12 files changed, 419 insertions(+), 196 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/mailet/standard/src/main/java/org/apache/james/transport/mailets/utils/MimeMessageUtils.java
----------------------------------------------------------------------
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/utils/MimeMessageUtils.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/utils/MimeMessageUtils.java
index 8f93b65..5186abc 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/utils/MimeMessageUtils.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/utils/MimeMessageUtils.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.james.transport.mailets.utils;
 
+import java.util.Enumeration;
+
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
@@ -68,4 +70,17 @@ public class MimeMessageUtils {
         return Optional.fromNullable(newSubject).or(originalSubject);
     }
 
+    /**
+     * Utility method for obtaining a string representation of a Message's
+     * headers
+     */
+    public String getMessageHeaders() throws MessagingException {
+        @SuppressWarnings("unchecked")
+        Enumeration<String> heads = message.getAllHeaderLines();
+        StringBuilder headBuffer = new StringBuilder(1024);
+        while (heads.hasMoreElements()) {
+            headBuffer.append(heads.nextElement()).append("\r\n");
+        }
+        return headBuffer.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/mailet/standard/src/test/java/org/apache/james/transport/mailets/utils/MimeMessageUtilsTest.java
----------------------------------------------------------------------
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/utils/MimeMessageUtilsTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/utils/MimeMessageUtilsTest.java
index 1af99e6..6a66541 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/utils/MimeMessageUtilsTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/utils/MimeMessageUtilsTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.james.transport.mailets.utils;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.guava.api.Assertions.assertThat;
 
 import java.util.Properties;
@@ -26,7 +27,6 @@ import java.util.Properties;
 import javax.mail.Session;
 import javax.mail.internet.MimeMessage;
 
-import org.apache.james.transport.mailets.utils.MimeMessageUtils;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Test;
 
@@ -133,4 +133,23 @@ public class MimeMessageUtilsTest {
 
         assertThat(newSubject).contains(prefix);
     }
+
+    @Test
+    public void getMessageHeadersShouldReturnEmptyStringWhenNoHeaders() throws Exception {
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        String messageHeaders = new MimeMessageUtils(message).getMessageHeaders();
+
+        assertThat(messageHeaders).isEmpty();
+    }
+
+    @Test
+    public void getMessageHeadersShouldHeadersWhenSome() throws Exception {
+        MimeMessage message = new MimeMessage(Session.getDefaultInstance(new Properties()));
+        message.addHeader("first", "value");
+        message.addHeader("second", "value2");
+        String messageHeaders = new MimeMessageUtils(message).getMessageHeaders();
+
+        String expectedHeaders = "first: value\r\nsecond: value2\r\n";
+        assertThat(messageHeaders).isEqualTo(expectedHeaders);
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Bounce.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Bounce.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Bounce.java
index e78873d..ef770dc 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Bounce.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Bounce.java
@@ -136,7 +136,7 @@ public class Bounce extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return new NotifyMailetsMessage().generateMessage(getInitParameters().getMessage(), originalMail);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
index 617af79..36c099d 100755
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/DSNBounce.java
@@ -129,7 +129,7 @@ public class DSNBounce extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return new NotifyMailetsMessage().generateMessage(getInitParameters().getMessage(), originalMail);
     }
 
@@ -376,7 +376,7 @@ public class DSNBounce extends AbstractRedirect {
         MimeMessage originalMessage = originalMail.getMessage();
 
         if (attachmentType.equals(TypeCode.HEADS)) {
-            part.setContent(getMessageHeaders(originalMessage), "text/plain");
+            part.setContent(new MimeMessageUtils(originalMessage).getMessageHeaders(), "text/plain");
             part.setHeader("Content-Type", "text/rfc822-headers");
         } else {
             part.setContent(originalMessage, "message/rfc822");

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Forward.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Forward.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Forward.java
index 76c4a03..1d62f6a 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Forward.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Forward.java
@@ -106,7 +106,7 @@ public class Forward extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return getInitParameters().getMessage();
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifyPostmaster.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifyPostmaster.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifyPostmaster.java
index 6c54b94..0c3b1a2 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifyPostmaster.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifyPostmaster.java
@@ -143,7 +143,7 @@ public class NotifyPostmaster extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return new NotifyMailetsMessage().generateMessage(getInitParameters().getMessage(), originalMail);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifySender.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifySender.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifySender.java
index fa92a1f..ed4c0ae 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifySender.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/NotifySender.java
@@ -143,7 +143,7 @@ public class NotifySender extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return new NotifyMailetsMessage().generateMessage(getInitParameters().getMessage(), originalMail);
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Redirect.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Redirect.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Redirect.java
index cf86f9b..4cb7295 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Redirect.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Redirect.java
@@ -315,7 +315,7 @@ public class Redirect extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return getInitParameters().getMessage();
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Resend.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Resend.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Resend.java
index 72b8d12..d1b0b78 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Resend.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Resend.java
@@ -308,7 +308,7 @@ public class Resend extends AbstractRedirect {
     }
 
     @Override
-    protected String getMessage(Mail originalMail) throws MessagingException {
+    public String getMessage(Mail originalMail) throws MessagingException {
         return getInitParameters().getMessage();
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/AbstractRedirect.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/AbstractRedirect.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/AbstractRedirect.java
index 8583685..393cbf8 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/AbstractRedirect.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/AbstractRedirect.java
@@ -19,21 +19,15 @@
 
 package org.apache.james.transport.mailets.redirect;
 
-import java.io.ByteArrayOutputStream;
-import java.util.Enumeration;
 import java.util.List;
 
 import javax.inject.Inject;
-import javax.mail.BodyPart;
 import javax.mail.MessagingException;
 import javax.mail.Session;
 import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
 import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
 
 import org.apache.james.core.MailImpl;
-import org.apache.james.core.MimeMessageUtil;
 import org.apache.james.dnsservice.api.DNSService;
 import org.apache.james.transport.mailets.Redirect;
 import org.apache.james.transport.mailets.utils.MimeMessageModifier;
@@ -41,7 +35,6 @@ import org.apache.james.transport.util.SpecialAddressesUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailAddress;
 import org.apache.mailet.base.GenericMailet;
-import org.apache.mailet.base.RFC2822Headers;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
@@ -147,7 +140,6 @@ import com.google.common.collect.ImmutableList;
 
 public abstract class AbstractRedirect extends GenericMailet {
 
-    private static final char LINE_BREAK = '\n';
     public static final List<String> REVERSE_PATH_ALLOWED_SPECIALS = ImmutableList.of("postmaster", "sender", "null", "unaltered");
     public static final List<String> SENDER_ALLOWED_SPECIALS = ImmutableList.of("postmaster", "sender", "unaltered");
 
@@ -168,7 +160,7 @@ public abstract class AbstractRedirect extends GenericMailet {
      *
      * @return {@link #getMessage()}
      */
-    protected abstract String getMessage(Mail originalMail) throws MessagingException;
+    public abstract String getMessage(Mail originalMail) throws MessagingException;
 
     /**
      * Gets the <code>recipients</code> property. Returns the collection of
@@ -388,7 +380,11 @@ public abstract class AbstractRedirect extends GenericMailet {
                 newMail.setMessage(new MimeMessage(Session.getDefaultInstance(System.getProperties(), null)));
 
                 // handle the new message if altered
-                buildAlteredMessage(newMail, originalMail);
+                AlteredMailUtils.builder()
+                    .mailet(this)
+                    .originalMail(originalMail)
+                    .build()
+                    .buildAlteredMessage(newMail);
 
             } else {
                 // if we need the original, create a copy of this message to
@@ -448,183 +444,6 @@ public abstract class AbstractRedirect extends GenericMailet {
     protected abstract MimeMessageModifier getMimeMessageModifier(Mail newMail, Mail originalMail) throws MessagingException;
 
     /**
-     * Utility method for obtaining a string representation of a Message's
-     * headers
-     */
-    protected String getMessageHeaders(MimeMessage message) throws MessagingException {
-        @SuppressWarnings("unchecked")
-        Enumeration<String> heads = message.getAllHeaderLines();
-        StringBuilder headBuffer = new StringBuilder(1024);
-        while (heads.hasMoreElements()) {
-            headBuffer.append(heads.nextElement().toString()).append("\r\n");
-        }
-        return headBuffer.toString();
-    }
-
-    /**
-     * Utility method for obtaining a string representation of a Message's body
-     */
-    private String getMessageBody(MimeMessage message) throws Exception {
-        ByteArrayOutputStream bodyOs = new ByteArrayOutputStream();
-        MimeMessageUtil.writeMessageBodyTo(message, bodyOs);
-        return bodyOs.toString();
-    }
-
-    /**
-     * Builds the message of the newMail in case it has to be altered.
-     *
-     * @param originalMail the original Mail object
-     * @param newMail      the Mail object to build
-     */
-    protected void buildAlteredMessage(Mail newMail, Mail originalMail) throws MessagingException {
-
-        MimeMessage originalMessage = originalMail.getMessage();
-        MimeMessage newMessage = newMail.getMessage();
-
-        // Copy the relevant headers
-        copyRelevantHeaders(originalMessage, newMessage);
-
-        String head = getMessageHeaders(originalMessage);
-        try {
-            // Create the message body
-            MimeMultipart multipart = new MimeMultipart("mixed");
-
-            // Create the message
-            MimeMultipart mpContent = new MimeMultipart("alternative");
-            mpContent.addBodyPart(getBodyPart(originalMail, originalMessage, head));
-
-            MimeBodyPart contentPartRoot = new MimeBodyPart();
-            contentPartRoot.setContent(mpContent);
-
-            multipart.addBodyPart(contentPartRoot);
-
-            if (getInitParameters().isDebug()) {
-                log("attachmentType:" + getInitParameters().getAttachmentType());
-            }
-            if (!getInitParameters().getAttachmentType().equals(TypeCode.NONE)) {
-                multipart.addBodyPart(getAttachmentPart(originalMail, originalMessage, head));
-            }
-
-            if (getInitParameters().isAttachError() && originalMail.getErrorMessage() != null) {
-                multipart.addBodyPart(getErrorPart(originalMail));
-            }
-            newMail.getMessage().setContent(multipart);
-            newMail.getMessage().setHeader(RFC2822Headers.CONTENT_TYPE, multipart.getContentType());
-
-        } catch (Exception ioe) {
-            throw new MessagingException("Unable to create multipart body", ioe);
-        }
-    }
-
-    private BodyPart getBodyPart(Mail originalMail, MimeMessage originalMessage, String head) throws MessagingException, Exception {
-        MimeBodyPart part = new MimeBodyPart();
-        part.setText(getText(originalMail, originalMessage, head));
-        part.setDisposition("inline");
-        return part;
-    }
-
-    private MimeBodyPart getAttachmentPart(Mail originalMail, MimeMessage originalMessage, String head) throws MessagingException, Exception {
-        MimeBodyPart attachmentPart = new MimeBodyPart();
-        switch (getInitParameters().getAttachmentType()) {
-            case HEADS:
-                attachmentPart.setText(head);
-                break;
-            case BODY:
-                try {
-                    attachmentPart.setText(getMessageBody(originalMessage));
-                } catch (Exception e) {
-                    attachmentPart.setText("body unavailable");
-                }
-                break;
-            case ALL:
-                attachmentPart.setText(head + "\r\nMessage:\r\n" + getMessageBody(originalMessage));
-                break;
-            case MESSAGE:
-                attachmentPart.setContent(originalMessage, "message/rfc822");
-                break;
-            case NONE:
-                break;
-            case UNALTERED:
-                break;
-        }
-        if ((originalMessage.getSubject() != null) && (originalMessage.getSubject().trim().length() > 0)) {
-            attachmentPart.setFileName(originalMessage.getSubject().trim());
-        } else {
-            attachmentPart.setFileName("No Subject");
-        }
-        attachmentPart.setDisposition("Attachment");
-        return attachmentPart;
-    }
-
-    private MimeBodyPart getErrorPart(Mail originalMail) throws MessagingException {
-        MimeBodyPart errorPart = new MimeBodyPart();
-        errorPart.setContent(originalMail.getErrorMessage(), "text/plain");
-        errorPart.setHeader(RFC2822Headers.CONTENT_TYPE, "text/plain");
-        errorPart.setFileName("Reasons");
-        errorPart.setDisposition(javax.mail.Part.ATTACHMENT);
-        return errorPart;
-    }
-
-    private String getText(Mail originalMail, MimeMessage originalMessage, String head) throws MessagingException {
-        StringBuilder builder = new StringBuilder();
-
-        String messageText = getMessage(originalMail);
-        if (messageText != null) {
-            builder.append(messageText)
-                .append(LINE_BREAK);
-        }
-
-        if (getInitParameters().isDebug()) {
-            log("inline:" + getInitParameters().getInLineType());
-        }
-        boolean all = false;
-        switch (getInitParameters().getInLineType()) {
-            case ALL:
-                all = true;
-            case HEADS:
-                builder.append("Message Headers:")
-                    .append(LINE_BREAK)
-                    .append(head)
-                    .append(LINE_BREAK);
-                if (!all) {
-                    break;
-                }
-            case BODY:
-                appendBody(builder, originalMessage);
-                break;
-            case NONE:
-                break;
-            case MESSAGE:
-                break;
-            case UNALTERED:
-                break;
-        }
-        return builder.toString();
-    }
-
-    private void appendBody(StringBuilder builder, MimeMessage originalMessage) {
-        builder.append("Message:")
-            .append(LINE_BREAK);
-        try {
-            builder.append(getMessageBody(originalMessage))
-                .append(LINE_BREAK);
-        } catch (Exception e) {
-            builder.append("body unavailable")
-                .append(LINE_BREAK);
-        }
-    }
-
-    private void copyRelevantHeaders(MimeMessage originalMessage, MimeMessage newMessage) throws MessagingException {
-        @SuppressWarnings("unchecked")
-        Enumeration<String> headerEnum = originalMessage.getMatchingHeaderLines(
-                new String[] { RFC2822Headers.DATE, RFC2822Headers.FROM, RFC2822Headers.REPLY_TO, RFC2822Headers.TO, 
-                        RFC2822Headers.SUBJECT, RFC2822Headers.RETURN_PATH });
-        while (headerEnum.hasMoreElements()) {
-            newMessage.addHeaderLine(headerEnum.nextElement());
-        }
-    }
-
-    /**
      * <p>
      * Checks if a sender domain of <i>mail</i> is valid.
      * </p>

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtils.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtils.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtils.java
new file mode 100644
index 0000000..f83adb5
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtils.java
@@ -0,0 +1,257 @@
+/****************************************************************
+ * 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.redirect;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Enumeration;
+
+import javax.mail.BodyPart;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.apache.james.core.MimeMessageUtil;
+import org.apache.james.transport.mailets.utils.MimeMessageUtils;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.RFC2822Headers;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+public class MailMessageAlteringUtils {
+
+    private static final char LINE_BREAK = '\n';
+
+    public static Builder from(AbstractRedirect mailet) {
+        return new Builder(mailet);
+    }
+
+    public static class Builder {
+
+        private AbstractRedirect mailet;
+        private Mail originalMail;
+        private Mail newMail;
+
+        private Builder(AbstractRedirect mailet) {
+            this.mailet = mailet;
+        }
+
+        public Builder originalMail(Mail originalMail) {
+            this.originalMail = originalMail;
+            return this;
+        }
+
+        public Builder newMail(Mail newMail) {
+            this.newMail = newMail;
+            return this;
+        }
+
+        public void alterNewMessage() throws MessagingException {
+            build().alterNewMessage();
+        }
+
+        @VisibleForTesting MailMessageAlteringUtils build() {
+            Preconditions.checkNotNull(mailet, "'mailet' is mandatory");
+            Preconditions.checkNotNull(originalMail, "'originalMail' is mandatory");
+            Preconditions.checkNotNull(newMail, "'newMail' is mandatory");
+            return new MailMessageAlteringUtils(mailet, originalMail, newMail);
+        }
+    }
+
+    private final AbstractRedirect mailet;
+    private final Mail originalMail;
+    private final Mail newMail;
+
+    private MailMessageAlteringUtils(AbstractRedirect mailet, Mail originalMail, Mail newMail) {
+        this.mailet = mailet;
+        this.originalMail = originalMail;
+        this.newMail = newMail;
+    }
+
+    /**
+     * Builds the message of the newMail in case it has to be altered.
+     *
+     * @param originalMail the original Mail object
+     * @param newMail      the Mail object to build
+     */
+    private void alterNewMessage() throws MessagingException {
+
+        MimeMessage originalMessage = originalMail.getMessage();
+        MimeMessage newMessage = newMail.getMessage();
+
+        // Copy the relevant headers
+        copyRelevantHeaders(originalMessage, newMessage);
+
+        String head = new MimeMessageUtils(originalMessage).getMessageHeaders();
+        try {
+            // Create the message body
+            MimeMultipart multipart = new MimeMultipart("mixed");
+
+            // Create the message
+            MimeMultipart mpContent = new MimeMultipart("alternative");
+            mpContent.addBodyPart(getBodyPart(originalMail, originalMessage, head));
+
+            MimeBodyPart contentPartRoot = new MimeBodyPart();
+            contentPartRoot.setContent(mpContent);
+
+            multipart.addBodyPart(contentPartRoot);
+
+            if (mailet.getInitParameters().isDebug()) {
+                mailet.log("attachmentType:" + mailet.getInitParameters().getAttachmentType());
+            }
+            if (!mailet.getInitParameters().getAttachmentType().equals(TypeCode.NONE)) {
+                multipart.addBodyPart(getAttachmentPart(originalMail, originalMessage, head));
+            }
+
+            if (mailet.getInitParameters().isAttachError() && originalMail.getErrorMessage() != null) {
+                multipart.addBodyPart(getErrorPart(originalMail));
+            }
+            newMail.getMessage().setContent(multipart);
+            newMail.getMessage().setHeader(RFC2822Headers.CONTENT_TYPE, multipart.getContentType());
+
+        } catch (Exception ioe) {
+            throw new MessagingException("Unable to create multipart body", ioe);
+        }
+    }
+
+    private BodyPart getBodyPart(Mail originalMail, MimeMessage originalMessage, String head) throws MessagingException, Exception {
+        MimeBodyPart part = new MimeBodyPart();
+        part.setText(getText(originalMail, originalMessage, head));
+        part.setDisposition("inline");
+        return part;
+    }
+
+    private MimeBodyPart getAttachmentPart(Mail originalMail, MimeMessage originalMessage, String head) throws MessagingException, Exception {
+        MimeBodyPart attachmentPart = new MimeBodyPart();
+        switch (mailet.getInitParameters().getAttachmentType()) {
+            case HEADS:
+                attachmentPart.setText(head);
+                break;
+            case BODY:
+                try {
+                    attachmentPart.setText(getMessageBody(originalMessage));
+                } catch (Exception e) {
+                    attachmentPart.setText("body unavailable");
+                }
+                break;
+            case ALL:
+                attachmentPart.setText(head + "\r\nMessage:\r\n" + getMessageBody(originalMessage));
+                break;
+            case MESSAGE:
+                attachmentPart.setContent(originalMessage, "message/rfc822");
+                break;
+            case NONE:
+                break;
+            case UNALTERED:
+                break;
+        }
+        attachmentPart.setFileName(getFileName(originalMessage.getSubject()));
+        attachmentPart.setDisposition("Attachment");
+        return attachmentPart;
+    }
+
+    @VisibleForTesting String getFileName(String subject) {
+        if (subject != null && !subject.trim().isEmpty()) {
+            return subject.trim();
+        }
+        return "No Subject";
+    }
+
+    private MimeBodyPart getErrorPart(Mail originalMail) throws MessagingException {
+        MimeBodyPart errorPart = new MimeBodyPart();
+        errorPart.setContent(originalMail.getErrorMessage(), "text/plain");
+        errorPart.setHeader(RFC2822Headers.CONTENT_TYPE, "text/plain");
+        errorPart.setFileName("Reasons");
+        errorPart.setDisposition(javax.mail.Part.ATTACHMENT);
+        return errorPart;
+    }
+
+    private String getText(Mail originalMail, MimeMessage originalMessage, String head) throws MessagingException {
+        StringBuilder builder = new StringBuilder();
+
+        String messageText = mailet.getMessage(originalMail);
+        if (messageText != null) {
+            builder.append(messageText)
+                .append(LINE_BREAK);
+        }
+
+        if (mailet.getInitParameters().isDebug()) {
+            mailet.log("inline:" + mailet.getInitParameters().getInLineType());
+        }
+        switch (mailet.getInitParameters().getInLineType()) {
+            case ALL:
+                appendHead(builder, head);
+                appendBody(builder, originalMessage);
+                break;
+            case HEADS:
+                appendHead(builder, head);
+                break;
+            case BODY:
+                appendBody(builder, originalMessage);
+                break;
+            case NONE:
+                break;
+            case MESSAGE:
+                break;
+            case UNALTERED:
+                break;
+        }
+        return builder.toString();
+    }
+
+    private void appendHead(StringBuilder builder, String head) {
+        builder.append("Message Headers:")
+            .append(LINE_BREAK)
+            .append(head)
+            .append(LINE_BREAK);
+    }
+
+    private void appendBody(StringBuilder builder, MimeMessage originalMessage) {
+        builder.append("Message:")
+            .append(LINE_BREAK);
+        try {
+            builder.append(getMessageBody(originalMessage))
+                .append(LINE_BREAK);
+        } catch (Exception e) {
+            builder.append("body unavailable")
+                .append(LINE_BREAK);
+        }
+    }
+
+    /**
+     * Utility method for obtaining a string representation of a Message's body
+     */
+    private String getMessageBody(MimeMessage message) throws Exception {
+        ByteArrayOutputStream bodyOs = new ByteArrayOutputStream();
+        MimeMessageUtil.writeMessageBodyTo(message, bodyOs);
+        return bodyOs.toString();
+    }
+
+    private void copyRelevantHeaders(MimeMessage originalMessage, MimeMessage newMessage) throws MessagingException {
+        @SuppressWarnings("unchecked")
+        Enumeration<String> headerEnum = originalMessage.getMatchingHeaderLines(
+                new String[] { RFC2822Headers.DATE, RFC2822Headers.FROM, RFC2822Headers.REPLY_TO, RFC2822Headers.TO, 
+                        RFC2822Headers.SUBJECT, RFC2822Headers.RETURN_PATH });
+        while (headerEnum.hasMoreElements()) {
+            newMessage.addHeaderLine(headerEnum.nextElement());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/6bffadb9/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtilsTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtilsTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtilsTest.java
new file mode 100644
index 0000000..b43d883
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/redirect/MailMessageAlteringUtilsTest.java
@@ -0,0 +1,113 @@
+/****************************************************************
+ * 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.redirect;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.apache.mailet.Mail;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class MailMessageAlteringUtilsTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void buildShouldThrowWhenMailetIsNull() {
+        expectedException.expect(NullPointerException.class);
+        expectedException.expectMessage("'mailet' is mandatory");
+        MailMessageAlteringUtils.from(null).build();
+    }
+
+    @Test
+    public void buildShouldThrowWhenOriginalMailIsNull() {
+        expectedException.expect(NullPointerException.class);
+        expectedException.expectMessage("'originalMail' is mandatory");
+        MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+            .build();
+    }
+
+    @Test
+    public void buildShouldThrowWhenNewMailIsNull() {
+        expectedException.expect(NullPointerException.class);
+        expectedException.expectMessage("'newMail' is mandatory");
+        MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+            .originalMail(mock(Mail.class))
+            .build();
+    }
+
+    @Test
+    public void buildShouldWorkWhenEverythingProvided() {
+        MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+            .originalMail(mock(Mail.class))
+            .newMail(mock(Mail.class))
+            .build();
+    }
+
+    @Test
+    public void getFileNameShouldReturnNoSubjectWhenSubjectIsNull() {
+        MailMessageAlteringUtils alteredMailUtils = MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+                .originalMail(mock(Mail.class))
+                .newMail(mock(Mail.class))
+                .build();
+
+        String fileName = alteredMailUtils.getFileName(null);
+
+        assertThat(fileName).isEqualTo("No Subject");
+    }
+
+    @Test
+    public void getFileNameShouldReturnNoSubjectWhenSubjectContainsOnlySpaces() {
+        MailMessageAlteringUtils alteredMailUtils = MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+                .originalMail(mock(Mail.class))
+                .newMail(mock(Mail.class))
+                .build();
+
+        String fileName = alteredMailUtils.getFileName("    ");
+
+        assertThat(fileName).isEqualTo("No Subject");
+    }
+
+    @Test
+    public void getFileNameShouldReturnSubjectWhenSubjectIsGiven() {
+        MailMessageAlteringUtils alteredMailUtils = MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+                .originalMail(mock(Mail.class))
+                .newMail(mock(Mail.class))
+                .build();
+
+        String fileName = alteredMailUtils.getFileName("my Subject");
+
+        assertThat(fileName).isEqualTo("my Subject");
+    }
+
+    @Test
+    public void getFileNameShouldReturnTrimmedSubjectWhenSubjectStartsWithSpaces() {
+        MailMessageAlteringUtils alteredMailUtils = MailMessageAlteringUtils.from(mock(AbstractRedirect.class))
+                .originalMail(mock(Mail.class))
+                .newMail(mock(Mail.class))
+                .build();
+
+        String fileName = alteredMailUtils.getFileName("    my Subject");
+
+        assertThat(fileName).isEqualTo("my Subject");
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org