Repository: camel
Updated Branches:
  refs/heads/master 1757f959d -> dbbdc490e


CAMEL-11872: Handle MIME folded and MIME encoded email headers


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/87be1a32
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/87be1a32
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/87be1a32

Branch: refs/heads/master
Commit: 87be1a32b90cd1ac9ebbef3c63a5966093e9b11e
Parents: 1757f95
Author: Ion Savin <co...@gmx.net>
Authored: Tue Oct 3 16:17:48 2017 +0300
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Tue Oct 3 19:23:31 2017 +0200

----------------------------------------------------------------------
 .../camel/component/mail/MailBinding.java       |   9 +-
 .../camel/component/mail/MailConfiguration.java |  15 ++-
 .../mail/MailMimeDecodeHeadersTest.java         | 108 +++++++++++++++++++
 3 files changed, 130 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/87be1a32/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java
----------------------------------------------------------------------
diff --git 
a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java
 
b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java
index ec416e8..2220ac1 100644
--- 
a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java
+++ 
b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailBinding.java
@@ -41,6 +41,7 @@ import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeBodyPart;
 import javax.mail.internet.MimeMessage;
 import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.MimeUtility;
 import javax.mail.util.ByteArrayDataSource;
 
 import org.apache.camel.Attachment;
@@ -598,15 +599,21 @@ public class MailBinding {
         Map<String, Object> answer = new TreeMap<String, 
Object>(String.CASE_INSENSITIVE_ORDER);
         Enumeration<?> names = mailMessage.getAllHeaders();
 
+        MailConfiguration mailConfiguration = ((MailEndpoint) 
exchange.getFromEndpoint()).getConfiguration();
         while (names.hasMoreElements()) {
             Header header = (Header) names.nextElement();
+
             String value = header.getValue();
+            if (value != null && mailConfiguration.isMimeDecodeHeaders()) {
+                value = MimeUtility.decodeText(MimeUtility.unfold(value));
+            }
+
             if (headerFilterStrategy != null && 
!headerFilterStrategy.applyFilterToExternalHeaders(header.getName(), value, 
exchange)) {
                 CollectionHelper.appendValue(answer, header.getName(), value);
             }
         }
         // if the message is a multipart message, do not set the content type 
to multipart/*
-        if 
(((MailEndpoint)exchange.getFromEndpoint()).getConfiguration().isMapMailMessage())
 {
+        if (mailConfiguration.isMapMailMessage()) {
             Object content = mailMessage.getContent();
             if (content instanceof MimeMultipart) {
                 MimeMultipart multipart = (MimeMultipart)content;

http://git-wip-us.apache.org/repos/asf/camel/blob/87be1a32/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConfiguration.java
----------------------------------------------------------------------
diff --git 
a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConfiguration.java
 
b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConfiguration.java
index 2ab4b26..f91c608 100644
--- 
a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConfiguration.java
+++ 
b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConfiguration.java
@@ -109,6 +109,8 @@ public class MailConfiguration implements Cloneable {
     private boolean skipFailedMessage;
     @UriParam @Metadata(label = "consumer")
     private boolean handleFailedMessage;
+    @UriParam(defaultValue = "false") @Metadata(label = "consumer")
+    private boolean mimeDecodeHeaders;
     @UriParam(label = "security")
     private SSLContextParameters sslContextParameters;
     @UriParam(label = "advanced", prefix = "mail.", multiValue = true)
@@ -118,7 +120,7 @@ public class MailConfiguration implements Cloneable {
 
     public MailConfiguration() {
     }
-    
+
     public MailConfiguration(CamelContext context) {
         this.applicationClassLoader = 
context.getApplicationContextClassLoader();
     }
@@ -748,4 +750,15 @@ public class MailConfiguration implements Cloneable {
     public void 
setAttachmentsContentTransferEncodingResolver(AttachmentsContentTransferEncodingResolver
 attachmentsContentTransferEncodingResolver) {
         this.attachmentsContentTransferEncodingResolver = 
attachmentsContentTransferEncodingResolver;
     }
+
+    /**
+     * This option enables transparent MIME decoding and unfolding for mail 
headers.
+     */
+    public void setMimeDecodeHeaders(boolean mimeDecodeHeaders) {
+        this.mimeDecodeHeaders = mimeDecodeHeaders;
+    }
+
+    public boolean isMimeDecodeHeaders() {
+        return mimeDecodeHeaders;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/87be1a32/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailMimeDecodeHeadersTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailMimeDecodeHeadersTest.java
 
b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailMimeDecodeHeadersTest.java
new file mode 100644
index 0000000..cafe248
--- /dev/null
+++ 
b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailMimeDecodeHeadersTest.java
@@ -0,0 +1,108 @@
+/**
+ * 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.camel.component.mail;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.jvnet.mock_javamail.Mailbox;
+
+import javax.mail.internet.MimeUtility;
+
+/**
+ * Unit test for Mail header decoding/unfolding support.
+ */
+public class MailMimeDecodeHeadersTest extends CamelTestSupport {
+    private String nonAsciiSubject = "\uD83D\uDC2A rocks!";
+    private String encodedNonAsciiSubject = "=?UTF-8?Q?=F0=9F=90=AA_rocks!?=";
+
+    private String longSubject;
+    {
+        StringBuilder sb = new StringBuilder("Camel rocks!");
+
+        int mimeFoldingLimit = 76;
+        int headerLength = "subject: ".length();
+        for (int i = 0; headerLength + sb.length() <= mimeFoldingLimit; i++) {
+            sb.insert(7, "o");
+        }
+        longSubject = sb.toString();
+    }
+    private String foldedLongSubject = MimeUtility.fold(9, longSubject);
+
+    @Test
+    public void testLongMailSubject() throws Exception {
+        Mailbox.clearAll();
+
+        // The email subject is >76 chars and will get MIME folded.
+        template.sendBody("direct:longSubject", "");
+
+        // When mimeDecodeHeaders=true is used, expect the received subject to 
be MIME unfolded.
+        MockEndpoint mockDecoded = getMockEndpoint("mock:decoded");
+        mockDecoded.expectedMessageCount(1);
+        mockDecoded.expectedHeaderReceived("subject", longSubject);
+        mockDecoded.setResultWaitTime(10000);
+        mockDecoded.assertIsSatisfied();
+
+        // When mimeDecodeHeaders=false or missing, expect the received 
subject to be MIME folded.
+        MockEndpoint mockPlain = getMockEndpoint("mock:plain");
+        mockPlain.expectedMessageCount(1);
+        mockPlain.expectedHeaderReceived("subject", foldedLongSubject);
+        mockPlain.setResultWaitTime(10000);
+        mockPlain.assertIsSatisfied();
+    }
+
+    @Test
+    public void testNonAsciiMailSubject() throws Exception {
+        Mailbox.clearAll();
+
+        // The email subject contains non-ascii characters and will be encoded.
+        template.sendBody("direct:nonAsciiSubject", "");
+
+        // When mimeDecodeHeaders=true is used, expect the received subject to 
be MIME encoded.
+        MockEndpoint mockDecoded = getMockEndpoint("mock:decoded");
+        mockDecoded.expectedMessageCount(1);
+        mockDecoded.expectedHeaderReceived("subject", nonAsciiSubject);
+        mockDecoded.assertIsSatisfied();
+
+        // When mimeDecodeHeaders=false or missing, expect the received 
subject to be MIME encoded.
+        MockEndpoint mockPlain = getMockEndpoint("mock:plain");
+        mockPlain.expectedMessageCount(1);
+        mockPlain.expectedHeaderReceived("subject", encodedNonAsciiSubject);
+        mockPlain.assertIsSatisfied();
+    }
+
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                from("direct:longSubject")
+                        .setHeader("subject", constant(longSubject))
+                        .to("smtp://plain@localhost", 
"smtp://decoded@localhost");
+
+                from("direct:nonAsciiSubject")
+                        .setHeader("subject", constant(nonAsciiSubject))
+                        .to("smtp://plain@localhost", 
"smtp://decoded@localhost");
+
+                
from("pop3://localhost?username=plain&password=secret&consumer.delay=1000")
+                        .to("mock:plain");
+
+                
from("pop3://localhost?username=decoded&password=secret&consumer.delay=1000&mimeDecodeHeaders=true")
+                        .to("mock:decoded");
+            }
+        };
+    }
+}

Reply via email to