commits@javamail.java.net

[javamail~mercurial:590] Fix off-by-one bug in handling of uidmax in UIDSet.toArray(set, uidmax)

From: <shannon_at_java.net>
Date: Thu, 29 Aug 2013 00:05:04 +0000

Project: javamail
Repository: mercurial
Revision: 590
Author: shannon
Date: 2013-08-29 00:04:20 UTC
Link:

Log Message:
------------
Better defaults for getTransport() method if mail.transport.protocol isn't set.
copying a DataHandler from a parsed message to a new message fails - bug 6072
Parameterize the native options using Maven properties.
Can't call initCause on a MessageRemovedException, use the new constructor.
Fix off-by-one bug in handling of uidmax in UIDSet.toArray(set, uidmax)


Revisions:
----------
586
587
588
589
590


Modified Paths:
---------------
mail/src/main/java/javax/mail/Session.java
doc/release/CHANGES.txt
mail/src/main/java/javax/mail/internet/MimeBodyPart.java
mail/src/main/java/javax/mail/internet/MimeMessage.java
mail/src/test/java/javax/mail/internet/MimeBodyPartTest.java
mail/src/test/java/javax/mail/internet/MimeMessageTest.java
mbox/native/pom.xml
mbox/src/main/java/com/sun/mail/mbox/MboxFolder.java
mail/src/main/java/com/sun/mail/imap/protocol/UIDSet.java
mail/src/test/java/com/sun/mail/imap/protocol/UIDSetTest.java
mail/src/test/resources/com/sun/mail/imap/protocol/uiddata


Diffs:
------
diff -r 3447c93b5147 -r 6e76be8fbfca mail/src/main/java/javax/mail/Session.java
--- a/mail/src/main/java/javax/mail/Session.java Fri Jul 19 13:52:46 2013 -0700
+++ b/mail/src/main/java/javax/mail/Session.java Mon Aug 26 16:26:21 2013 -0700
@@ -625,7 +625,14 @@
      * @exception NoSuchProviderException If the provider is not found.
      */
     public Transport getTransport() throws NoSuchProviderException {
- return getTransport(getProperty("mail.transport.protocol"));
+ String prot = getProperty("mail.transport.protocol");
+ if (prot != null)
+ return getTransport(prot);
+ // if the property isn't set, use the protocol for "rfc822"
+ prot = (String)addressMap.get("rfc822");
+ if (prot != null)
+ return getTransport(prot);
+ return getTransport("smtp"); // if all else fails
     }
 
     /**


diff -r 6e76be8fbfca -r a584b6eec3d5 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Mon Aug 26 16:26:21 2013 -0700
+++ b/doc/release/CHANGES.txt Mon Aug 26 16:27:15 2013 -0700
@@ -26,6 +26,7 @@
 K 5987 support RFC 2359 COPYUID response code
 K 5989 Empty FROM Field causes Exception
 K 6004 Filename isn't parsed correctly if charset is not set
+K 6072 copying a DataHandler from a parsed message to a new message fails
 
 
                   CHANGES IN THE 1.5.0 RELEASE

diff -r 6e76be8fbfca -r a584b6eec3d5 mail/src/main/java/javax/mail/internet/MimeBodyPart.java
--- a/mail/src/main/java/javax/mail/internet/MimeBodyPart.java Mon Aug 26 16:26:21 2013 -0700
+++ b/mail/src/main/java/javax/mail/internet/MimeBodyPart.java Mon Aug 26 16:27:15 2013 -0700
@@ -611,7 +611,7 @@
      */
     public DataHandler getDataHandler() throws MessagingException {
         if (dh == null)
- dh = new MimePartDataHandler(new MimePartDataSource(this));
+ dh = new MimePartDataHandler(this);
         return dh;
     }
 
@@ -1451,11 +1451,27 @@
             }
 
             /*
- * If the data for this part comes from a stream,
- * we can't update it.
+ * If this is our own MimePartDataHandler, we can't update any
+ * of the headers.
+ *
+ * If this is a MimePartDataHandler coming from another part,
+ * we need to copy over the content headers from the other part.
+ * Note that the MimePartDataHandler still refers to the original
+ * data and the original MimePart.
              */
- if (dh instanceof MimePartDataHandler)
- return; // can't update it
+ if (dh instanceof MimePartDataHandler) {
+ MimePartDataHandler mdh = (MimePartDataHandler)dh;
+ MimePart mpart = mdh.getPart();
+ if (mpart != part) {
+ // XXX - can't change the encoding of the data from the
+ // other part without decoding and reencoding it, so
+ // we just force it to match the original
+ setEncoding(part, mpart.getEncoding());
+ if (needCTHeader)
+ part.setHeader("Content-Type", mpart.getContentType());
+ }
+ return;
+ }
 
             // Content-Transfer-Encoding, but only if we don't
             // already have one
@@ -1554,6 +1570,8 @@
             if (dh instanceof MimePartDataHandler) {
                 // call getContentStream to give subclass a chance to
                 // provide the data on demand
+ is = ((MimePartDataHandler)dh).getContentStream();
+ /*
                 if (part instanceof MimeBodyPart) {
                     MimeBodyPart mbp = (MimeBodyPart)part;
                     is = mbp.getContentStream();
@@ -1561,6 +1579,7 @@
                     MimeMessage msg = (MimeMessage)part;
                     is = msg.getContentStream();
                 }
+ */
             }
             if (is != null) {
                 // now copy the data to the output stream
@@ -1590,8 +1609,27 @@
      * Otherwise the data would need to be decoded and reencoded.
      */
     static class MimePartDataHandler extends DataHandler {
- public MimePartDataHandler(DataSource ds) {
- super(ds);
+ MimePart part;
+ public MimePartDataHandler(MimePart part) {
+ super(new MimePartDataSource(part));
+ this.part = part;
+ }
+
+ InputStream getContentStream() throws MessagingException {
+ InputStream is = null;
+
+ if (part instanceof MimeBodyPart) {
+ MimeBodyPart mbp = (MimeBodyPart)part;
+ is = mbp.getContentStream();
+ } else if (part instanceof MimeMessage) {
+ MimeMessage msg = (MimeMessage)part;
+ is = msg.getContentStream();
+ }
+ return is;
+ }
+
+ MimePart getPart() {
+ return part;
         }
     }
 }

diff -r 6e76be8fbfca -r a584b6eec3d5 mail/src/main/java/javax/mail/internet/MimeMessage.java
--- a/mail/src/main/java/javax/mail/internet/MimeMessage.java Mon Aug 26 16:26:21 2013 -0700
+++ b/mail/src/main/java/javax/mail/internet/MimeMessage.java Mon Aug 26 16:27:15 2013 -0700
@@ -1382,8 +1382,8 @@
     /**
      * Return a DataHandler for this Message's content. <p>
      *
- * The implementation provided here works as follows. Note the use of
- * the <code>getContentStream</code> method to
+ * The implementation provided here works approximately as follows.
+ * Note the use of the <code>getContentStream</code> method to
      * generate the byte stream for the content. Also note that
      * any transfer-decoding is done automatically within this method.<p>
      *
@@ -1410,8 +1410,7 @@
     public synchronized DataHandler getDataHandler()
                 throws MessagingException {
         if (dh == null)
- dh = new MimeBodyPart.MimePartDataHandler(
- new MimePartDataSource(this));
+ dh = new MimeBodyPart.MimePartDataHandler(this);
         return dh;
     }
 

diff -r 6e76be8fbfca -r a584b6eec3d5 mail/src/test/java/javax/mail/internet/MimeBodyPartTest.java
--- a/mail/src/test/java/javax/mail/internet/MimeBodyPartTest.java Mon Aug 26 16:26:21 2013 -0700
+++ b/mail/src/test/java/javax/mail/internet/MimeBodyPartTest.java Mon Aug 26 16:27:15 2013 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011-2013 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
@@ -40,8 +40,16 @@
 
 package javax.mail.internet;
 
+import java.io.*;
+import java.util.Properties;
+
+import javax.activation.DataHandler;
+
+import javax.mail.*;
+
 import org.junit.*;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertArrayEquals;
 
 /**
@@ -69,4 +77,85 @@
         String[] langs = mbp.getContentLanguage();
         assertArrayEquals(languages, langs);
     }
+
+ /**
+ * Test that copying a DataHandler from one message to another
+ * has the desired effect.
+ */
+ @Test
+ public void testCopyDataHandler() throws Exception {
+ Session s = Session.getInstance(new Properties());
+ // create a message and extract the DataHandler for a part
+ MimeMessage orig = createMessage(s);
+ MimeMultipart omp = (MimeMultipart)orig.getContent();
+ MimeBodyPart obp = (MimeBodyPart)omp.getBodyPart(0);
+ DataHandler dh = obp.getDataHandler();
+ // create a new message and use the DataHandler
+ MimeMessage msg = new MimeMessage(s);
+ MimeMultipart mp = new MimeMultipart();
+ MimeBodyPart mbp = new MimeBodyPart();
+ mbp.setDataHandler(dh);
+ mp.addBodyPart(mbp);
+ msg.setContent(mp);
+ // depend on copy constructor streaming the data
+ msg = new MimeMessage(msg);
+ mp = (MimeMultipart)msg.getContent();
+ mbp = (MimeBodyPart)mp.getBodyPart(0);
+ assertEquals("text/x-test", mbp.getContentType());
+ assertEquals("quoted-printable", mbp.getEncoding());
+ assertEquals("test part", getString(mbp.getInputStream()));
+ }
+
+ /**
+ * Test that copying a DataHandler from one message to another
+ * by setting the "dh" filed in a subclass has the desired effect.
+ */
+ @Test
+ public void testSetDataHandler() throws Exception {
+ Session s = Session.getInstance(new Properties());
+ // create a message and extract the DataHandler for a part
+ MimeMessage orig = createMessage(s);
+ MimeMultipart omp = (MimeMultipart)orig.getContent();
+ MimeBodyPart obp = (MimeBodyPart)omp.getBodyPart(0);
+ final DataHandler odh = obp.getDataHandler();
+ // create a new message and use the DataHandler
+ MimeMessage msg = new MimeMessage(s);
+ MimeMultipart mp = new MimeMultipart();
+ MimeBodyPart mbp = new MimeBodyPart() {
+ { dh = odh; }
+ };
+ mp.addBodyPart(mbp);
+ msg.setContent(mp);
+ // depend on copy constructor streaming the data
+ msg = new MimeMessage(msg);
+ mp = (MimeMultipart)msg.getContent();
+ mbp = (MimeBodyPart)mp.getBodyPart(0);
+ assertEquals("text/x-test", mbp.getContentType());
+ assertEquals("quoted-printable", mbp.getEncoding());
+ assertEquals("test part", getString(mbp.getInputStream()));
+ }
+
+ private static MimeMessage createMessage(Session s)
+ throws MessagingException {
+ String content =
+ "Mime-Version: 1.0\n" +
+ "Subject: Example\n" +
+ "Content-Type: multipart/mixed; boundary=\"-\"\n" +
+ "\n" +
+ "preamble\n" +
+ "---\n" +
+ "Content-Type: text/x-test\n" +
+ "Content-Transfer-Encoding: quoted-printable\n" +
+ "\n" +
+ "test part\n" +
+ "\n" +
+ "-----\n";
+
+ return new MimeMessage(s, new StringBufferInputStream(content));
+ }
+
+ private static String getString(InputStream is) throws IOException {
+ BufferedReader r = new BufferedReader(new InputStreamReader(is));
+ return r.readLine();
+ }
 }

diff -r 6e76be8fbfca -r a584b6eec3d5 mail/src/test/java/javax/mail/internet/MimeMessageTest.java
--- a/mail/src/test/java/javax/mail/internet/MimeMessageTest.java Mon Aug 26 16:26:21 2013 -0700
+++ b/mail/src/test/java/javax/mail/internet/MimeMessageTest.java Mon Aug 26 16:27:15 2013 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2013 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
@@ -40,8 +40,11 @@
 
 package javax.mail.internet;
 
+import java.io.*;
 import java.util.Properties;
 
+import javax.activation.DataHandler;
+
 import javax.mail.*;
 import static javax.mail.Message.RecipientType.*;
 
@@ -72,4 +75,63 @@
         m.setRecipients(TO, (String)null);
         assertEquals("To: is removed", null, m.getRecipients(TO));
     }
+
+ /**
+ * Test that copying a DataHandler from one message to another
+ * has the desired effect.
+ */
+ @Test
+ public void testCopyDataHandler() throws Exception {
+ Session s = Session.getInstance(new Properties());
+ // create a message and extract the DataHandler
+ MimeMessage orig = createMessage(s);
+ DataHandler dh = orig.getDataHandler();
+ // create a new message and use the DataHandler
+ MimeMessage msg = new MimeMessage(s);
+ msg.setDataHandler(dh);
+ // depend on copy constructor streaming the data
+ msg = new MimeMessage(msg);
+ assertEquals("text/x-test", msg.getContentType());
+ assertEquals("quoted-printable", msg.getEncoding());
+ assertEquals("test message", getString(msg.getInputStream()));
+ }
+
+ /**
+ * Test that copying a DataHandler from one message to another
+ * by setting the "dh" filed in a subclass has the desired effect.
+ */
+ @Test
+ public void testSetDataHandler() throws Exception {
+ Session s = Session.getInstance(new Properties());
+ // create a message and extract the DataHandler for a part
+ MimeMessage orig = createMessage(s);
+ final DataHandler odh = orig.getDataHandler();
+ // create a new message and use the DataHandler
+ MimeMessage msg = new MimeMessage(s) {
+ { dh = odh; }
+ };
+ // depend on copy constructor streaming the data
+ msg = new MimeMessage(msg);
+ assertEquals("text/x-test", msg.getContentType());
+ assertEquals("quoted-printable", msg.getEncoding());
+ assertEquals("test message", getString(msg.getInputStream()));
+ }
+
+ private static MimeMessage createMessage(Session s)
+ throws MessagingException {
+ String content =
+ "Mime-Version: 1.0\n" +
+ "Subject: Example\n" +
+ "Content-Type: text/x-test\n" +
+ "Content-Transfer-Encoding: quoted-printable\n" +
+ "\n" +
+ "test message\n";
+
+ return new MimeMessage(s, new StringBufferInputStream(content));
+ }
+
+ private static String getString(InputStream is) throws IOException {
+ BufferedReader r = new BufferedReader(new InputStreamReader(is));
+ return r.readLine();
+ }
 }


diff -r a584b6eec3d5 -r 81bb6175860f mbox/native/pom.xml
--- a/mbox/native/pom.xml Mon Aug 26 16:27:15 2013 -0700
+++ b/mbox/native/pom.xml Mon Aug 26 17:14:41 2013 -0700
@@ -59,32 +59,49 @@
     <description>JavaMail API mbox native library</description>
     <url>http://java.sun.com/projects/javamail</url>
 
+ <properties>
+ <compiler.name>
+ c89
+ </compiler.name>
+ <compiler.start.options>
+ -Xa -xO2 -v -D_REENTRANT
+ -I${env.JAVA_HOME}/include -I${env.JAVA_HOME}/include/solaris
+ </compiler.start.options>
+ <linker.name>
+ c89
+ </linker.name>
+ <linker.start.options>
+ -G
+ </linker.start.options>
+ <linker.end.options>
+ -L${env.JAVA_HOME}/jre/lib/${env.MACH} -lmail -ljava -lc
+ </linker.end.options>
+ </properties>
+
     <build>
         <plugins>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>native-maven-plugin</artifactId>
+ <version>1.0-alpha-7</version>
                 <extensions>true</extensions>
                 <configuration>
                     <compilerProvider>generic</compilerProvider>
- <compilerExecutable>c89</compilerExecutable>
- <linkerExecutable>c89</linkerExecutable>
+ <compilerExecutable>${compiler.name}</compilerExecutable>
+ <linkerExecutable>${linker.name}</linkerExecutable>
                     <compilerStartOptions>
                         <compilerStartOption>
- -Xa -xO2 -v -D_REENTRANT
- -I/usr/java/include
- -I/usr/java/include/solaris
+ ${compiler.start.options}
                         </compilerStartOption>
                     </compilerStartOptions>
                     <linkerStartOptions>
                         <linkerStartOption>
- -G
+ ${linker.start.options}
                         </linkerStartOption>
                     </linkerStartOptions>
                     <linkerEndOptions>
                         <linkerEndOption>
- -L/usr/java/jre/lib/${env.MACH}
- -lmail -ljava -lc
+ ${linker.end.options}
                         </linkerEndOption>
                     </linkerEndOptions>
                     <sources>


diff -r 81bb6175860f -r d8695b4ee774 mbox/src/main/java/com/sun/mail/mbox/MboxFolder.java
--- a/mbox/src/main/java/com/sun/mail/mbox/MboxFolder.java Mon Aug 26 17:14:41 2013 -0700
+++ b/mbox/src/main/java/com/sun/mail/mbox/MboxFolder.java Tue Aug 27 10:56:48 2013 -0700
@@ -698,8 +698,7 @@
                 m = loadMessage(is, msgno, mode == READ_WRITE);
             } catch (IOException ex) {
                 MessagingException mex =
- new MessageRemovedException("mbox message gone: " + ex);
- mex.initCause(ex);
+ new MessageRemovedException("mbox message gone", ex);
                 throw mex;
             }
             md.message = m;


diff -r d8695b4ee774 -r cd8bd0e46fa8 mail/src/main/java/com/sun/mail/imap/protocol/UIDSet.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/UIDSet.java Tue Aug 27 10:56:48 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/UIDSet.java Wed Aug 28 17:04:20 2013 -0700
@@ -228,7 +228,7 @@
             for (UIDSet u : uidset) {
                 if (uidmax < 0)
                     count += u.size();
- else if (u.start < uidmax) {
+ else if (u.start <= uidmax) {
                     if (u.end < uidmax)
                         count += u.end - u.start + 1;
                     else

diff -r d8695b4ee774 -r cd8bd0e46fa8 mail/src/test/java/com/sun/mail/imap/protocol/UIDSetTest.java
--- a/mail/src/test/java/com/sun/mail/imap/protocol/UIDSetTest.java Tue Aug 27 10:56:48 2013 -0700
+++ b/mail/src/test/java/com/sun/mail/imap/protocol/UIDSetTest.java Wed Aug 28 17:04:20 2013 -0700
@@ -67,6 +67,8 @@
     static class TestData {
         public String name;
         public String uids;
+ public long max;
+ public String maxuids;
         public long[] expect;
     }
 
@@ -158,9 +160,24 @@
             t.uids = tok;
 
         line = in.readLine();
- List<Long> uids = new ArrayList<Long>();
         st = new StringTokenizer(line);
         tok = st.nextToken();
+ if (tok.equals("MAX")) {
+ tok = st.nextToken();
+ try {
+ t.max = Long.valueOf(tok);
+ } catch (NumberFormatException ex) {
+ throw new Exception("Bad MAX value in line: " + line);
+ }
+ if (st.hasMoreTokens())
+ t.maxuids = st.nextToken();
+ else
+ t.maxuids = t.uids;
+ line = in.readLine();
+ st = new StringTokenizer(line);
+ tok = st.nextToken();
+ }
+ List<Long> uids = new ArrayList<Long>();
         if (!tok.equals("EXPECT"))
             throw new Exception("Bad test data format: " + line);
         while (st.hasMoreTokens()) {
@@ -195,7 +212,11 @@
 
         // first, test string to array
         UIDSet[] uidset = UIDSet.parseUIDSets(t.uids);
- long[] uids = UIDSet.toArray(uidset);
+ long[] uids;
+ if (t.max > 0)
+ uids = UIDSet.toArray(uidset, t.max);
+ else
+ uids = UIDSet.toArray(uidset);
         if (junit)
             Assert.assertArrayEquals(t.expect, uids);
         else if (!arrayEquals(t.expect, uids)) {
@@ -207,9 +228,10 @@
         // now, test the reverse
         UIDSet[] uidset2 = UIDSet.createUIDSets(uids);
         String suid = UIDSet.toString(uidset2);
+ String euid = t.max > 0 ? t.maxuids : t.uids;
         if (junit)
- Assert.assertEquals(t.uids, suid);
- else if (!t.uids.equals(suid)) {
+ Assert.assertEquals(euid, suid);
+ else if (!euid.equals(suid)) {
             System.out.println("Test: " + t.name);
             System.out.println("FAIL2");
             errors++;

diff -r d8695b4ee774 -r cd8bd0e46fa8 mail/src/test/resources/com/sun/mail/imap/protocol/uiddata
--- a/mail/src/test/resources/com/sun/mail/imap/protocol/uiddata Tue Aug 27 10:56:48 2013 -0700
+++ b/mail/src/test/resources/com/sun/mail/imap/protocol/uiddata Wed Aug 28 17:04:20 2013 -0700
@@ -70,6 +70,31 @@
 DATA 1,3,5,7,9
 EXPECT 1 3 5 7 9
 
+TEST max
+DATA 1
+MAX 1
+EXPECT 1
+
+TEST max2
+DATA 2
+MAX 2
+EXPECT 2
+
+TEST max3
+DATA 1:2
+MAX 2
+EXPECT 1 2
+
+TEST max4
+DATA 1:2
+MAX 1 1
+EXPECT 1
+
+TEST max5
+DATA 1:4
+MAX 3 1:3
+EXPECT 1 2 3
+
 TEST empty
 DATA EMPTY
 EXPECT EMPTY