commits@javamail.java.net

[javamail~mercurial:878] MailHandler support for non-multipart messages - Bug K8540

From: <shannon_at_java.net>
Date: Wed, 9 Nov 2016 22:47:07 +0000

Project: javamail
Repository: mercurial
Revision: 878
Author: shannon
Date: 2016-11-08 23:27:35 UTC
Link:

Log Message:
------------
use of YoungerTerm/OlderTerm on server without WITHIN support fails - bug 8550
MailHandler support for non-multipart messages - Bug K8540
MailHandlerTest test for content type of single body part.

(From Jason)


Revisions:
----------
877
878


Modified Paths:
---------------
doc/release/CHANGES.txt
gimap/src/main/java/com/sun/mail/gimap/protocol/GmailProtocol.java
gimap/src/main/java/com/sun/mail/gimap/protocol/GmailSearchSequence.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
mail/src/main/java/com/sun/mail/imap/protocol/SearchSequence.java
mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java


Added Paths:
------------
mail/src/test/java/com/sun/mail/imap/IMAPSearchTest.java


Diffs:
------
diff -r d0e30f93a591 -r 8757f3b67c17 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Wed Nov 02 13:11:51 2016 -0700
+++ b/doc/release/CHANGES.txt Tue Nov 08 15:12:17 2016 -0800
@@ -38,6 +38,7 @@
 K 8486 Protocol#command method call readResponse after IOException is thrown
 K 8487 Possible NPE in Status.<init> line 96
 K 8492 MailHandler should support 'login' verify type.
+K 8550 use of YoungerTerm/OlderTerm on server without WITHIN support fails
 
 
                   CHANGES IN THE 1.5.6 RELEASE

diff -r d0e30f93a591 -r 8757f3b67c17 gimap/src/main/java/com/sun/mail/gimap/protocol/GmailProtocol.java
--- a/gimap/src/main/java/com/sun/mail/gimap/protocol/GmailProtocol.java Wed Nov 02 13:11:51 2016 -0700
+++ b/gimap/src/main/java/com/sun/mail/gimap/protocol/GmailProtocol.java Tue Nov 08 15:12:17 2016 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -206,7 +206,7 @@
      */
     protected SearchSequence getSearchSequence() {
         if (searchSequence == null)
- searchSequence = new GmailSearchSequence();
+ searchSequence = new GmailSearchSequence(this);
         return searchSequence;
     }
 }

diff -r d0e30f93a591 -r 8757f3b67c17 gimap/src/main/java/com/sun/mail/gimap/protocol/GmailSearchSequence.java
--- a/gimap/src/main/java/com/sun/mail/gimap/protocol/GmailSearchSequence.java Wed Nov 02 13:11:51 2016 -0700
+++ b/gimap/src/main/java/com/sun/mail/gimap/protocol/GmailSearchSequence.java Tue Nov 08 15:12:17 2016 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -58,6 +58,10 @@
  */
 
 public class GmailSearchSequence extends SearchSequence {
+ public GmailSearchSequence(IMAPProtocol p) {
+ super(p);
+ }
+
     public Argument generateSequence(SearchTerm term, String charset)
                                 throws SearchException, IOException {
         if (term instanceof GmailMsgIdTerm)

diff -r d0e30f93a591 -r 8757f3b67c17 mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Wed Nov 02 13:11:51 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Tue Nov 08 15:12:17 2016 -0800
@@ -2605,7 +2605,7 @@
      */
     protected SearchSequence getSearchSequence() {
         if (searchSequence == null)
- searchSequence = new SearchSequence();
+ searchSequence = new SearchSequence(this);
         return searchSequence;
     }
 

diff -r d0e30f93a591 -r 8757f3b67c17 mail/src/main/java/com/sun/mail/imap/protocol/SearchSequence.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/SearchSequence.java Wed Nov 02 13:11:51 2016 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/SearchSequence.java Tue Nov 08 15:12:17 2016 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -59,9 +59,29 @@
  * support for additional product-specific search terms.
  *
  * @author John Mani
+ * @author Bill Shannon
  */
 public class SearchSequence {
 
+ private IMAPProtocol protocol; // for hasCapability checks; may be null
+
+ /**
+ * Create a SearchSequence for this IMAPProtocol.
+ *
+ * @param p the IMAPProtocol object for the server
+ * @since JavaMail 1.6.0
+ */
+ public SearchSequence(IMAPProtocol p) {
+ protocol = p;
+ }
+
+ /**
+ * Create a SearchSequence.
+ */
+ @Deprecated
+ public SearchSequence() {
+ }
+
     /**
      * Generate the IMAP search sequence for the given search expression.
      *
@@ -486,6 +506,8 @@
      * @since JavaMail 1.5.1
      */
     protected Argument older(OlderTerm term) throws SearchException {
+ if (protocol != null && !protocol.hasCapability("WITHIN"))
+ throw new SearchException("Server doesn't support OLDER searches");
         Argument result = new Argument();
         result.writeAtom("OLDER");
         result.writeNumber(term.getInterval());
@@ -501,6 +523,8 @@
      * @since JavaMail 1.5.1
      */
     protected Argument younger(YoungerTerm term) throws SearchException {
+ if (protocol != null && !protocol.hasCapability("WITHIN"))
+ throw new SearchException("Server doesn't support YOUNGER searches");
         Argument result = new Argument();
         result.writeAtom("YOUNGER");
         result.writeNumber(term.getInterval());
@@ -517,6 +541,8 @@
      */
     protected Argument modifiedSince(ModifiedSinceTerm term)
                                 throws SearchException {
+ if (protocol != null && !protocol.hasCapability("CONDSTORE"))
+ throw new SearchException("Server doesn't support MODSEQ searches");
         Argument result = new Argument();
         result.writeAtom("MODSEQ");
         result.writeNumber(term.getModSeq());

diff -r d0e30f93a591 -r 8757f3b67c17 mail/src/test/java/com/sun/mail/imap/IMAPSearchTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/com/sun/mail/imap/IMAPSearchTest.java Tue Nov 08 15:12:17 2016 -0800
@@ -0,0 +1,116 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2009-2016 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.mail.imap;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.mail.Folder;
+import javax.mail.Session;
+import javax.mail.Store;
+import javax.mail.Message;
+import javax.mail.search.*;
+
+import com.sun.mail.test.TestServer;
+
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.Timeout;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Test the search method.
+ */
+public final class IMAPSearchTest {
+
+ // timeout the test in case of deadlock
+ @Rule
+ public Timeout deadlockTimeout = Timeout.seconds(20);
+
+ @Test
+ public void testWithinNotSupported() {
+ TestServer server = null;
+ try {
+ server = new TestServer(new IMAPHandler() {
+ @Override
+ public void search(String line) throws IOException {
+ bad("WITHIN not supported");
+ }
+ });
+ server.start();
+
+ final Properties properties = new Properties();
+ properties.setProperty("mail.imap.host", "localhost");
+ properties.setProperty("mail.imap.port", "" + server.getPort());
+ properties.setProperty("mail.imap.throwsearchexception", "true");
+ final Session session = Session.getInstance(properties);
+ //session.setDebug(true);
+
+ final Store store = session.getStore("imap");
+ Folder folder = null;
+ try {
+ store.connect("test", "test");
+ folder = store.getFolder("INBOX");
+ folder.open(Folder.READ_ONLY);
+ Message[] msgs = folder.search(new YoungerTerm(1));
+ fail("search didn't fail");
+ } catch (SearchException ex) {
+ // success!
+ } catch (Exception ex) {
+ System.out.println(ex);
+ //ex.printStackTrace();
+ fail(ex.toString());
+ } finally {
+ if (folder != null)
+ folder.close(false);
+ store.close();
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ } finally {
+ if (server != null) {
+ server.quit();
+ }
+ }
+ }
+}


diff -r 8757f3b67c17 -r f627c0ed80b9 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Tue Nov 08 15:12:17 2016 -0800
+++ b/doc/release/CHANGES.txt Tue Nov 08 15:27:35 2016 -0800
@@ -38,6 +38,7 @@
 K 8486 Protocol#command method call readResponse after IOException is thrown
 K 8487 Possible NPE in Status.<init> line 96
 K 8492 MailHandler should support 'login' verify type.
+K 8540 MailHandler support for non-multipart messages
 K 8550 use of YoungerTerm/OlderTerm on server without WITHIN support fails
 
 

diff -r 8757f3b67c17 -r f627c0ed80b9 mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
--- a/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Tue Nov 08 15:12:17 2016 -0800
+++ b/mail/src/main/java/com/sun/mail/util/logging/MailHandler.java Tue Nov 08 15:27:35 2016 -0800
@@ -298,17 +298,18 @@
  *
  * <p>
  * <b>Attachments:</b>
- * This <tt>Handler</tt> allows multiple attachments per each email.
- * The attachment order maps directly to the array index order in this
- * <tt>Handler</tt> with zero index being the first attachment. The number of
- * attachment formatters controls the number of attachments per email and
- * the content type of each attachment. The attachment filters determine if a
- * <tt>LogRecord</tt> will be included in an attachment. If an attachment
- * filter is <tt>null</tt> then all records are included for that attachment.
- * Attachments without content will be omitted from email message. The
- * attachment name formatters create the file name for an attachment.
- * Custom attachment name formatters can be used to generate an attachment name
- * based on the contents of the attachment.
+ * This <tt>Handler</tt> allows multiple attachments per each email message.
+ * The presence of an attachment formatter will change the content type of the
+ * email message to a multi-part message. The attachment order maps directly to
+ * the array index order in this <tt>Handler</tt> with zero index being the
+ * first attachment. The number of attachment formatters controls the number of
+ * attachments per email and the content type of each attachment. The
+ * attachment filters determine if a <tt>LogRecord</tt> will be included in an
+ * attachment. If an attachment filter is <tt>null</tt> then all records are
+ * included for that attachment. Attachments without content will be omitted
+ * from email message. The attachment name formatters create the file name for
+ * an attachment. Custom attachment name formatters can be used to generate an
+ * attachment name based on the contents of the attachment.
  *
  * <p>
  * <b>Push Level and Push Filter:</b>
@@ -1825,7 +1826,7 @@
      * @param type the mime type or null, meaning text/plain.
      * @throws MessagingException if there is a problem.
      */
- private void setContent(MimeBodyPart part, CharSequence buf, String type) throws MessagingException {
+ private void setContent(MimePart part, CharSequence buf, String type) throws MessagingException {
         final String charset = getEncodingName();
         if (type != null && !"text/plain".equalsIgnoreCase(type)) {
             type = contentWithEncoding(type, charset);
@@ -1853,7 +1854,7 @@
             final ContentType ct = new ContentType(type);
             ct.setParameter("charset", MimeUtility.mimeCharset(encoding));
             encoding = ct.toString(); //See javax.mail.internet.ContentType.
- if (!isEmpty(encoding)) {
+ if (!isEmpty(encoding)) { //Support pre K5687.
                 type = encoding;
             }
         } catch (final MessagingException ME) {
@@ -2826,7 +2827,6 @@
             initSession();
         }
         MimeMessage msg = new MimeMessage(session);
- msg.setDescription(descriptionFrom(comparator, pushLevel, pushFilter));
 
         /**
          * Parts are lazily created when an attachment performs a getHead
@@ -2839,12 +2839,19 @@
          * The buffers are lazily created when the part requires a getHead.
          */
         StringBuilder[] buffers = new StringBuilder[parts.length];
-
         StringBuilder buf = null;
+ final MimePart body;
+ if (parts.length == 0) {
+ msg.setDescription(descriptionFrom(
+ getFormatter(), getFilter(), subjectFormatter));
+ body = msg;
+ } else {
+ msg.setDescription(descriptionFrom(
+ comparator, pushLevel, pushFilter));
+ body = createBodyPart();
+ }
 
         appendSubject(msg, head(subjectFormatter));
-
- final MimeBodyPart body = createBodyPart();
         final Formatter bodyFormat = getFormatter();
         final Filter bodyFilter = getFilter();
 
@@ -2897,7 +2904,8 @@
             }
 
             if (formatted) {
- if (locale != null && !locale.equals(lastLocale)) {
+ if (body != msg && locale != null
+ && !locale.equals(lastLocale)) {
                     appendContentLang(msg, locale);
                 }
             } else { //Belongs to no mime part.
@@ -2937,19 +2945,22 @@
 
         appendSubject(msg, tail(subjectFormatter, ""));
 
- MimeMultipart multipart = new MimeMultipart();
         String contentType = contentTypeOf(buf);
         String altType = contentTypeOf(bodyFormat);
         setContent(body, buf, altType == null ? contentType : altType);
- multipart.addBodyPart(body);
-
- for (int i = 0; i < parts.length; ++i) {
- if (parts[i] != null) {
- multipart.addBodyPart(parts[i]);
+ if (body != msg) {
+ final MimeMultipart multipart = new MimeMultipart();
+ //assert body instanceof BodyPart : body;
+ multipart.addBodyPart((BodyPart) body);
+
+ for (int i = 0; i < parts.length; ++i) {
+ if (parts[i] != null) {
+ multipart.addBodyPart(parts[i]);
+ }
             }
+ msg.setContent(multipart);
         }
 
- msg.setContent(multipart);
         return msg;
     }
 
@@ -3180,6 +3191,7 @@
                 try { //Verify that the DataHandler can be loaded.
                     Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER);
                     try {
+ //Always load the multipart classes.
                         MimeMultipart multipart = new MimeMultipart();
                         MimeBodyPart[] ambp = new MimeBodyPart[atn.length];
                         final MimeBodyPart body;

diff -r 8757f3b67c17 -r f627c0ed80b9 mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Tue Nov 08 15:12:17 2016 -0800
+++ b/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Tue Nov 08 15:27:35 2016 -0800
@@ -2582,9 +2582,23 @@
     }
 
     @Test
- public void testContentTypeOverride() throws Exception {
+ public void testContentTypeNestedMultiFormatter() throws Exception {
         String expected = "application/xml; charset=us-ascii";
- String type = getInlineContentType(new XMLFormatter());
+ String type = getInlineMultiContentType(new CollectorFormatter("{0}{1}{2}",
+ new XMLFormatter(), new SeverityComparator()));
+ assertEquals(expected, type);
+
+
+ expected = "text/plain; charset=us-ascii";
+ type = getInlineMultiContentType(new CollectorFormatter("{0}{1}{2}",
+ new CompactFormatter(), new SeverityComparator()));
+ assertEquals(expected, type);
+ }
+
+ @Test
+ public void testContentTypeMultiOverride() throws Exception {
+ String expected = "application/xml; charset=us-ascii";
+ String type = getInlineMultiContentType(new XMLFormatter());
         assertEquals(expected, type);
 
         MimetypesFileTypeMap m = new MimetypesFileTypeMap();
@@ -2592,20 +2606,23 @@
         final FileTypeMap old = FileTypeMap.getDefaultFileTypeMap();
         FileTypeMap.setDefaultFileTypeMap(m);
         try {
- type = getInlineContentType(new XMLFormatter());
+ type = getInlineMultiContentType(new XMLFormatter());
             assertEquals("text/plain; charset=us-ascii", type);
         } finally {
             FileTypeMap.setDefaultFileTypeMap(old);
         }
 
- type = getInlineContentType(new XMLFormatter());
+ type = getInlineMultiContentType(new XMLFormatter());
         assertEquals(expected, type);
     }
 
- private String getInlineContentType(Formatter f) throws Exception {
+ private String getInlineMultiContentType(Formatter f) throws Exception {
         final String[] value = new String[1];
         MailHandler instance = new MailHandler(createInitProperties(""));
+ instance.setAttachmentFormatters(new SimpleFormatter());
+ instance.setAttachmentFilters(BooleanFilter.FALSE);
         instance.setEncoding("us-ascii");
+
         MessageErrorManager em = new MessageErrorManager(instance.getMailProperties()) {
 
             @Override
@@ -2614,6 +2631,9 @@
                     MimeMultipart multi = (MimeMultipart) msg.getContent();
                     BodyPart body = multi.getBodyPart(0);
                     assertEquals(Part.INLINE, body.getDisposition());
+ String desc = msg.getDescription();
+ assertTrue(desc.contains("Sorted using"));
+ assertTrue(desc.contains("pushed when"));
                     value[0] = body.getContentType();
                 } catch (Throwable E) {
                     dump(E);
@@ -2633,6 +2653,57 @@
     }
 
     @Test
+ public void testContentTypeOverride() throws Exception {
+ String expected = "application/xml; charset=us-ascii";
+ String type = getInlineContentType(new XMLFormatter());
+ assertEquals(expected, type);
+
+ MimetypesFileTypeMap m = new MimetypesFileTypeMap();
+ m.addMimeTypes("text/plain txt TXT XMLFormatter");
+ final FileTypeMap old = FileTypeMap.getDefaultFileTypeMap();
+ FileTypeMap.setDefaultFileTypeMap(m);
+ try {
+ type = getInlineContentType(new XMLFormatter());
+ assertEquals("text/plain; charset=us-ascii", type);
+ } finally {
+ FileTypeMap.setDefaultFileTypeMap(old);
+ }
+
+ type = getInlineContentType(new XMLFormatter());
+ assertEquals(expected, type);
+ }
+
+ private String getInlineContentType(Formatter f) throws Exception {
+ final String[] value = new String[1];
+ MailHandler instance = new MailHandler(createInitProperties(""));
+ instance.setEncoding("us-ascii");
+ MessageErrorManager em = new MessageErrorManager(instance.getMailProperties()) {
+
+ @Override
+ protected void error(MimeMessage msg, Throwable t, int code) {
+ try {
+ String desc = msg.getDescription();
+ assertTrue(desc.contains("filtered with"));
+ assertTrue(desc.contains("named by"));
+ value[0] = msg.getContentType();
+ } catch (Throwable E) {
+ dump(E);
+ fail(E.toString());
+ }
+ }
+ };
+ instance.setErrorManager(em);
+ Properties props = createInitProperties("");
+ props.put("mail.to", "localhost_at_localdomain");
+ instance.setMailProperties(props);
+ instance.setFormatter(f);
+ instance.publish(new LogRecord(Level.SEVERE, "test"));
+ instance.close();
+
+ return value[0];
+ }
+
+ @Test
     public void testAcceptLang() throws Exception {
         class LangManager extends MessageErrorManager {
 
@@ -2746,6 +2817,8 @@
         }
 
         MailHandler target = new MailHandler(createInitProperties(""));
+ target.setAttachmentFormatters(new SimpleFormatter());
+ target.setAttachmentFilters(BooleanFilter.FALSE);
 
         Properties props = new Properties();
         props.put("motd", "Hello MailHandler!");
@@ -2858,12 +2931,17 @@
 
             cl = Locale.US;
             target = new MailHandler(createInitProperties(""));
+ target.setAttachmentFormatters(new SimpleFormatter());
+ target.setAttachmentFilters(BooleanFilter.FALSE);
+
             target.setErrorManager(new Infer(target.getMailProperties(), Locale.ENGLISH));
             logPrefix = p + '.' + f.getName() + cl;
             testContentLangInfer(target, logPrefix, bundleName, cl);
 
             cl = Locale.UK;
             target = new MailHandler(createInitProperties(""));
+ target.setAttachmentFormatters(new SimpleFormatter());
+ target.setAttachmentFilters(BooleanFilter.FALSE);
             target.setErrorManager(new Infer(target.getMailProperties(), Locale.ENGLISH));
             logPrefix = p + '.' + f.getName() + cl;
             testContentLangInfer(target, logPrefix, bundleName, cl);