commits@javamail.java.net

[javamail~mercurial:231] Add support for ID command required by Yahoo! Mail IMAP server.

From: <shannon_at_kenai.com>
Date: Fri, 8 Jan 2010 21:28:18 +0000

Project: javamail
Repository: mercurial
Revision: 231
Author: shannon
Date: 2010-01-08 20:31:55 UTC
Link:

Log Message:
------------
Add mail.pop3.cachewriteto property, default false.
Property handle messages with a boundary of "-" when ignoring the
boundary parameter.
Add tests for all the MimeMultipart properties.
Fix the bug that the tests uncovered - allowEmpty wasn't being
initialized in writeTo.
Allow displaying more than one message by number.
preLogin method needs an IMAPProtocol object.
More fixes for modifying a message created from a stream,
and some tests to make sure it keeps working.
Convert more tests to JUnit.
Add support for ID command required by Yahoo! Mail IMAP server.


Revisions:
----------
225
226
227
228
229
230
231


Modified Paths:
---------------
doc/release/CHANGES.txt
mail/src/main/java/com/sun/mail/pop3/POP3Message.java
mail/src/main/java/com/sun/mail/pop3/POP3Store.java
mail/src/main/java/com/sun/mail/pop3/Protocol.java
mail/src/main/java/com/sun/mail/pop3/package.html
mail/src/main/java/javax/mail/internet/MimeMultipart.java
demo/src/main/java/msgshow.java
mail/src/main/java/com/sun/mail/imap/IMAPStore.java
mail/src/main/java/javax/mail/internet/MimeBodyPart.java
mail/src/main/java/javax/mail/internet/MimeMessage.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java


Added Paths:
------------
mail/src/test/java/javax/mail/internet/MimeMultipartPropertyTest.java
mail/src/test/java/javax/mail/internet/NullOutputStream.java
mail/src/test/java/javax/mail/internet/ModifyMessageTest.java
mail/src/test/java/com/sun/mail/util/UUDecoderStreamTest.java
mail/src/test/java/javax/mail/internet/ReferencesTest.java
mail/src/test/resources/com/sun/mail/util/uudata


Diffs:
------
diff -r 4e897fce9cf2 -r 007c27bc3ee3 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Dec 18 16:44:07 2009 -0800
+++ b/doc/release/CHANGES.txt Mon Jan 04 13:35:34 2010 -0800
@@ -26,6 +26,7 @@
 <no id> add mail.pop3.disablecapa property to disable use of the CAPA command
 <no id> fix support for Properties objects with default Properties objects
 <no id> integrate NTLM support, no longer needs jcifs.jar
+<no id> add mail.pop3.cachewriteto property, default false
 
 
                   CHANGES IN THE 1.4.3 RELEASE

diff -r 4e897fce9cf2 -r 007c27bc3ee3 mail/src/main/java/com/sun/mail/pop3/POP3Message.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Message.java Fri Dec 18 16:44:07 2009 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Message.java Mon Jan 04 13:35:34 2010 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. 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
@@ -142,7 +142,9 @@
                                         msgSize > 0 ? msgSize + hdrSize : 0);
                 if (rawcontent == null) {
                     expunged = true;
- throw new MessageRemovedException(); // XXX - what else?
+ throw new MessageRemovedException(
+ "can't retrieve message #" + msgnum +
+ " in POP3Message.getContentStream"); // XXX - what else?
                 }
                 if (headers == null ||
                         ((POP3Store)(folder.getStore())).forgetTopHeaders) {
@@ -447,6 +449,33 @@
     }
 
     /**
+ * Output the message as an RFC 822 format stream, without
+ * specified headers. If the property "mail.pop3.cachewriteto"
+ * is set to "true", and ignoreList is null, and the message hasn't
+ * already been cached as a side effect of other operations, the message
+ * content is cached before being written. Otherwise, the message is
+ * streamed directly to the output stream without being cached.
+ *
+ * @exception javax.mail.MessagingException
+ * @exception IOException if an error occurs writing to the stream
+ * or if an error is generated by the
+ * javax.activation layer.
+ * @see javax.activation.DataHandler#writeTo
+ */
+ public synchronized void writeTo(OutputStream os, String[] ignoreList)
+ throws IOException, MessagingException {
+ if (content == null && ignoreList == null &&
+ !((POP3Store)(folder.getStore())).cacheWriteTo) {
+ if (!folder.getProtocol().retr(msgnum, os)) {
+ expunged = true;
+ throw new MessageRemovedException("can't retrieve message #" +
+ msgnum + " in POP3Message.writeTo"); // XXX - what else?
+ }
+ } else
+ super.writeTo(os, ignoreList);
+ }
+
+ /**
      * Load the headers for this message into the InternetHeaders object.
      * The headers are fetched using the POP3 TOP command.
      */

diff -r 4e897fce9cf2 -r 007c27bc3ee3 mail/src/main/java/com/sun/mail/pop3/POP3Store.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Fri Dec 18 16:44:07 2009 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Mon Jan 04 13:35:34 2010 -0800
@@ -79,6 +79,7 @@
     volatile boolean disableTop = false;
     volatile boolean forgetTopHeaders = false;
     volatile boolean supportsUidl = true;
+ volatile boolean cacheWriteTo = false;
 
     public POP3Store(Session session, URLName url) {
         this(session, url, "pop3", false);
@@ -108,6 +109,9 @@
         forgetTopHeaders = PropUtil.getBooleanSessionProperty(session,
                                 "mail." + name + ".forgettopheaders", false);
 
+ cacheWriteTo = PropUtil.getBooleanSessionProperty(session,
+ "mail." + name + ".cachewriteto", false);
+
         // mail.pop3.starttls.enable enables use of STLS command
         useStartTLS = PropUtil.getBooleanSessionProperty(session,
                                 "mail." + name + ".starttls.enable", false);

diff -r 4e897fce9cf2 -r 007c27bc3ee3 mail/src/main/java/com/sun/mail/pop3/Protocol.java
--- a/mail/src/main/java/com/sun/mail/pop3/Protocol.java Fri Dec 18 16:44:07 2009 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/Protocol.java Mon Jan 04 13:35:34 2010 -0800
@@ -343,6 +343,85 @@
     }
 
     /**
+ * Retrieve the specified message and stream the content to the
+ * specified OutputStream. Return true on success.
+ */
+ synchronized boolean retr(int msg, OutputStream os) throws IOException {
+ if (debug)
+ out.println("DEBUG POP3: streaming msg " + msg);
+ Response r = simpleCommand("RETR " + msg);
+ if (!r.ok) {
+ multilineCommandEnd();
+ return false;
+ }
+
+ Throwable terr = null;
+ int b, lastb = '\n';
+ try {
+ while ((b = input.read()) >= 0) {
+ if (lastb == '\n' && b == '.') {
+ if (debug)
+ out.write(b);
+ b = input.read();
+ if (b == '\r') {
+ if (debug)
+ out.write(b);
+ // end of response, consume LF as well
+ b = input.read();
+ if (debug)
+ out.write(b);
+ break;
+ }
+ }
+
+ /*
+ * Keep writing unless we get an error while writing,
+ * which we defer until all of the data has been read.
+ */
+ if (terr == null) {
+ try {
+ os.write(b);
+ } catch (IOException ex) {
+ if (debug)
+ out.println(
+ "DEBUG POP3: exception while streaming: " + ex);
+ terr = ex;
+ } catch (RuntimeException ex) {
+ if (debug)
+ out.println(
+ "DEBUG POP3: exception while streaming: " + ex);
+ terr = ex;
+ }
+ }
+ if (debug)
+ out.write(b);
+ lastb = b;
+ }
+ } catch (InterruptedIOException iioex) {
+ /*
+ * As above in simpleCommand, close the socket to recover.
+ */
+ try {
+ socket.close();
+ } catch (IOException cex) { }
+ throw iioex;
+ }
+ if (b < 0)
+ throw new EOFException("EOF on socket");
+
+ // was there a deferred error?
+ if (terr != null) {
+ if (terr instanceof IOException)
+ throw (IOException)terr;
+ if (terr instanceof RuntimeException)
+ throw (RuntimeException)terr;
+ assert false; // can't get here
+ }
+ multilineCommandEnd();
+ return true;
+ }
+
+ /**
      * Return the message header and the first n lines of the message.
      */
     synchronized InputStream top(int msg, int n) throws IOException {

diff -r 4e897fce9cf2 -r 007c27bc3ee3 mail/src/main/java/com/sun/mail/pop3/package.html
--- a/mail/src/main/java/com/sun/mail/pop3/package.html Fri Dec 18 16:44:07 2009 -0800
+++ b/mail/src/main/java/com/sun/mail/pop3/package.html Mon Jan 04 13:35:34 2010 -0800
@@ -431,6 +431,20 @@
 </TD>
 </TR>
 
+<TR>
+<TD>mail.pop3.cachewriteto</TD>
+<TD>boolean</TD>
+<TD>
+Controls the behavior of the {_at_link POP3Message.writeTo writeTo} method
+on a POP3 message object.
+If set to true, and the message content hasn't yet been cached,
+and ignoreList is null, the message is cached before being written.
+Otherwise, the message is streamed directly
+to the output stream without being cached.
+Defaults to false.
+</TD>
+</TR>
+
 </TABLE>
 <P>
 In general, applications should not need to use the classes in this


diff -r 007c27bc3ee3 -r c92a5cf8d915 mail/src/main/java/javax/mail/internet/MimeMultipart.java
--- a/mail/src/main/java/javax/mail/internet/MimeMultipart.java Mon Jan 04 13:35:34 2010 -0800
+++ b/mail/src/main/java/javax/mail/internet/MimeMultipart.java Mon Jan 04 16:19:34 2010 -0800
@@ -440,6 +440,11 @@
         }
 
         if (parts.size() == 0) {
+ // have to read the property every time because parse won't
+ // read it if the message was *not* constructed from a stream.
+ // default to false
+ allowEmpty = PropUtil.getBooleanSystemProperty(
+ "mail.mime.multipart.allowempty", false);
             if (allowEmpty) {
                 // write out a single empty body part
                 los.writeln(boundary); // put out boundary
@@ -556,8 +561,8 @@
                      * look like a boundary? If so, assume it is
                      * the boundary and save it.
                      */
- if (line.startsWith("--")) {
- if (line.endsWith("--")) {
+ if (line.length() > 2 && line.startsWith("--")) {
+ if (line.length() > 4 && line.endsWith("--")) {
                             /*
                              * The first boundary-like line we find is
                              * probably *not* the end-of-multipart boundary
@@ -829,8 +834,8 @@
                      * look like a boundary? If so, assume it is
                      * the boundary and save it.
                      */
- if (line.startsWith("--")) {
- if (line.endsWith("--")) {
+ if (line.length() > 2 && line.startsWith("--")) {
+ if (line.length() > 4 && line.endsWith("--")) {
                             /*
                              * The first boundary-like line we find is
                              * probably *not* the end-of-multipart boundary

diff -r 007c27bc3ee3 -r c92a5cf8d915 mail/src/test/java/javax/mail/internet/MimeMultipartPropertyTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/javax/mail/internet/MimeMultipartPropertyTest.java Mon Jan 04 16:19:34 2010 -0800
@@ -0,0 +1,212 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. 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.html
+ * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [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 javax.mail.internet;
+
+import java.io.StringBufferInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.mail.Session;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.junit.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the properties that control the MimeMultipart class.
+ * Since the properties are now read in the parse method, all
+ * these tests can be run in the same JVM.
+ */
+public class MimeMultipartPropertyTest {
+
+ private static Session s = Session.getInstance(new Properties());
+
+ /**
+ * Clear all properties before each test.
+ */
+ @Before
+ public void beforeTest() {
+ clearAll();
+ }
+
+ @Test
+ public void testBoundary() throws Exception {
+ MimeMessage m = createMessage("x", "x", true);
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ assertEquals(mp.getCount(), 2);
+ }
+
+ @Test
+ public void testBoundaryIgnore() throws Exception {
+ System.setProperty(
+ "mail.mime.multipart.ignoreexistingboundaryparameter", "true");
+ MimeMessage m = createMessage("x", "-", true);
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ assertEquals(mp.getCount(), 2);
+ }
+
+ @Test
+ public void testBoundaryMissing() throws Exception {
+ MimeMessage m = createMessage(null, "x", true);
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ assertEquals(mp.getCount(), 2);
+ }
+
+ @Test(expected=MessagingException.class)
+ public void testBoundaryMissingEx() throws Exception {
+ System.setProperty(
+ "mail.mime.multipart.ignoremissingboundaryparameter", "false");
+ MimeMessage m = createMessage(null, "x", true);
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ mp.getCount(); // throw exception
+ assertTrue(false); // never get here
+ }
+
+ @Test
+ public void testEndBoundaryMissing() throws Exception {
+ MimeMessage m = createMessage("x", "x", false);
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ assertEquals(mp.getCount(), 2);
+ }
+
+ @Test(expected=MessagingException.class)
+ public void testEndBoundaryMissingEx() throws Exception {
+ System.setProperty(
+ "mail.mime.multipart.ignoremissingendboundary", "false");
+ MimeMessage m = createMessage("x", "x", false);
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ mp.getCount(); // throw exception
+ assertTrue(false); // never get here
+ }
+
+ @Test
+ public void testAllowEmpty() throws Exception {
+ System.setProperty( "mail.mime.multipart.allowempty", "true");
+ MimeMessage m = createEmptyMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ assertEquals(mp.getCount(), 0);
+ }
+
+ @Test(expected=MessagingException.class)
+ public void testAllowEmptyEx() throws Exception {
+ MimeMessage m = createEmptyMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ mp.getCount(); // throw exception
+ assertTrue(false); // never get here
+ }
+
+ @Test
+ public void testAllowEmptyOutput() throws Exception {
+ System.setProperty( "mail.mime.multipart.allowempty", "true");
+ MimeMessage m = new MimeMessage(s);
+ MimeMultipart mp = new MimeMultipart();
+ m.setContent(mp);
+ m.writeTo(new NullOutputStream());
+ assertEquals(mp.getCount(), 0);
+ }
+
+ @Test(expected=IOException.class)
+ public void testAllowEmptyOutputEx() throws Exception {
+ MimeMessage m = new MimeMessage(s);
+ MimeMultipart mp = new MimeMultipart();
+ m.setContent(mp);
+ m.writeTo(new NullOutputStream()); // throw exception
+ assertTrue(false); // never get here
+ }
+
+ /**
+ * Clear all properties after all tests.
+ */
+ @AfterClass
+ public static void after() {
+ clearAll();
+ }
+
+ private static void clearAll() {
+ System.clearProperty(
+ "mail.mime.multipart.ignoreexistingboundaryparameter");
+ System.clearProperty(
+ "mail.mime.multipart.ignoremissingboundaryparameter");
+ System.clearProperty(
+ "mail.mime.multipart.ignoremissingendboundary");
+ System.clearProperty(
+ "mail.mime.multipart.allowempty");
+ }
+
+ /**
+ * Create a test message.
+ * If param is not null, it specifies the boundary parameter.
+ * The actual boundary is specified by "actual".
+ * If "end" is true, include the end boundary.
+ */
+ private static MimeMessage createMessage(String param, String actual,
+ boolean end) throws MessagingException {
+ String content =
+ "Mime-Version: 1.0\n" +
+ "Subject: Example\n" +
+ "Content-Type: multipart/mixed; " +
+ (param != null ? "boundary=\"" + param + "\"" : "") + "\n" +
+ "\n" +
+ "preamble\n" +
+ "--" + actual + "\n" +
+ "\n" +
+ "first part\n" +
+ "\n" +
+ "--" + actual + "\n" +
+ "\n" +
+ "second part\n" +
+ "\n" +
+ (end ? "--" + actual + "--\n" : "");
+
+ return new MimeMessage(s, new StringBufferInputStream(content));
+ }
+
+ /**
+ * Create a test message with no parts.
+ */
+ private static MimeMessage createEmptyMessage() throws MessagingException {
+ String content =
+ "Mime-Version: 1.0\n" +
+ "Subject: Example\n" +
+ "Content-Type: multipart/mixed; boundary=\"x\"\n\n";
+
+ return new MimeMessage(s, new StringBufferInputStream(content));
+ }
+}

diff -r 007c27bc3ee3 -r c92a5cf8d915 mail/src/test/java/javax/mail/internet/NullOutputStream.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/javax/mail/internet/NullOutputStream.java Mon Jan 04 16:19:34 2010 -0800
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. 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.html
+ * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [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 javax.mail.internet;
+
+import java.io.*;
+
+/**
+ * An OutputStream that throws away all data written to it.
+ */
+public class NullOutputStream extends OutputStream {
+
+ public void write(int b) throws IOException {
+ }
+
+ public void write(byte[] b) throws IOException {
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ }
+}


diff -r c92a5cf8d915 -r 5e7b97b3b96e demo/src/main/java/msgshow.java
--- a/demo/src/main/java/msgshow.java Mon Jan 04 16:19:34 2010 -0800
+++ b/demo/src/main/java/msgshow.java Wed Jan 06 15:55:09 2010 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -61,7 +61,6 @@
     static int attnum = 1;
 
     public static void main(String argv[]) {
- int msgnum = -1;
         int optind;
         InputStream msgStream = System.in;
 
@@ -99,7 +98,7 @@
                 System.out.println(
 "Usage: msgshow [-L url] [-T protocol] [-H host] [-p port] [-U user]");
                 System.out.println(
-"\t[-P password] [-f mailbox] [msgnum] [-v] [-D] [-s] [-S] [-a]");
+"\t[-P password] [-f mailbox] [msgnum ...] [-v] [-D] [-s] [-S] [-a]");
                 System.out.println(
 "or msgshow -m [-v] [-D] [-s] [-S] [-f msg-file]");
                 System.exit(1);
@@ -109,9 +108,6 @@
         }
 
         try {
- if (optind < argv.length)
- msgnum = Integer.parseInt(argv[optind]);
-
             // Get a Properties object
             Properties props = System.getProperties();
 
@@ -200,7 +196,7 @@
                 System.out.println("-------------------------------");
             }
 
- if (msgnum == -1) {
+ if (optind >= argv.length) {
                 // Attributes & Flags for all messages ..
                 Message[] msgs = folder.getMessages();
 
@@ -218,14 +214,17 @@
                     // dumpPart(msgs[i]);
                 }
             } else {
- System.out.println("Getting message number: " + msgnum);
- Message m = null;
-
- try {
- m = folder.getMessage(msgnum);
- dumpPart(m);
- } catch (IndexOutOfBoundsException iex) {
- System.out.println("Message number out of range");
+ while (optind < argv.length) {
+ int msgnum = Integer.parseInt(argv[optind++]);
+ System.out.println("Getting message number: " + msgnum);
+ Message m = null;
+
+ try {
+ m = folder.getMessage(msgnum);
+ dumpPart(m);
+ } catch (IndexOutOfBoundsException iex) {
+ System.out.println("Message number out of range");
+ }
                 }
             }
 


diff -r 5e7b97b3b96e -r 0453674cd36a mail/src/main/java/com/sun/mail/imap/IMAPStore.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Wed Jan 06 15:55:09 2010 -0800
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Thu Jan 07 14:31:32 2010 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -640,7 +640,7 @@
             return; // no need to login
 
         // allow subclasses to issue commands before login
- preLogin();
+ preLogin(p);
 
         /*
          * Put a special "marker" in the capabilities list so we can
@@ -702,7 +702,7 @@
      *
      * The implementation of this method in this class does nothing.
      */
- protected void preLogin() throws ProtocolException {
+ protected void preLogin(IMAPProtocol p) throws ProtocolException {
     }
 
     /**


diff -r 0453674cd36a -r e4870216e6ab mail/src/main/java/javax/mail/internet/MimeBodyPart.java
--- a/mail/src/main/java/javax/mail/internet/MimeBodyPart.java Thu Jan 07 14:31:32 2010 -0800
+++ b/mail/src/main/java/javax/mail/internet/MimeBodyPart.java Thu Jan 07 15:34:42 2010 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -566,7 +566,7 @@
         if (content != null)
             return new ByteArrayInputStream(content);
         
- throw new MessagingException("No content");
+ throw new MessagingException("No MimeBodyPart content");
     }
 
     /**
@@ -637,6 +637,12 @@
                 (c instanceof Multipart || c instanceof Message) &&
                 (content != null || contentStream != null)) {
             cachedContent = c;
+ /*
+ * We may abandon the input stream so make sure
+ * the MimeMultipart has consumed the stream.
+ */
+ if (c instanceof MimeMultipart)
+ ((MimeMultipart)c).parse();
         }
         return c;
     }
@@ -1260,8 +1266,6 @@
         DataHandler dh = part.getDataHandler();
         if (dh == null) // Huh ?
             return;
- if (dh instanceof MimePartDataHandler)
- return; // can't update it
 
         try {
             String type = dh.getContentType();
@@ -1269,6 +1273,13 @@
             boolean needCTHeader = part.getHeader("Content-Type") == null;
 
             ContentType cType = new ContentType(type);
+
+ /*
+ * If this is a multipart, give sub-parts a chance to
+ * update their headers. Even though the data for this
+ * multipart may have come from a stream, one of the
+ * sub-parts may have been updated.
+ */
             if (cType.match("multipart/*")) {
                 // If multipart, recurse
                 composite = true;
@@ -1294,6 +1305,13 @@
                 // XXX - call MimeMessage.updateHeaders()?
             }
 
+ /*
+ * If the data for this part comes from a stream,
+ * we can't update it.
+ */
+ if (dh instanceof MimePartDataHandler)
+ return; // can't update it
+
             // Content-Transfer-Encoding, but only if we don't
             // already have one
             if (!composite) { // not allowed on composite parts
@@ -1379,16 +1397,50 @@
 
         // Finally, the content. Encode if required.
         // XXX: May need to account for ESMTP ?
- os = MimeUtility.encode(os, part.getEncoding());
- part.getDataHandler().writeTo(os);
+ InputStream is = null;
+ byte[] buf = null;
+ try {
+ /*
+ * If the data for this part comes from a stream,
+ * just copy it to the output stream without decoding
+ * and reencoding it.
+ */
+ DataHandler dh = part.getDataHandler();
+ if (dh instanceof MimePartDataHandler) {
+ // call getContentStream to give subclass a chance to
+ // provide the data on demand
+ if (part instanceof MimeBodyPart) {
+ MimeBodyPart mbp = (MimeBodyPart)part;
+ is = mbp.getContentStream();
+ } else if (part instanceof MimeMessage) {
+ MimeMessage msg = (MimeMessage)part;
+ is = msg.getContentStream();
+ }
+ }
+ if (is != null) {
+ // now copy the data to the output stream
+ buf = new byte[8192];
+ int len;
+ while ((len = is.read(buf)) > 0)
+ os.write(buf, 0, len);
+ } else {
+ os = MimeUtility.encode(os, part.getEncoding());
+ part.getDataHandler().writeTo(os);
+ }
+ } finally {
+ if (is != null)
+ is.close();
+ buf = null;
+ }
         os.flush(); // Needed to complete encoding
     }
 
     /**
      * A special DataHandler used only as a marker to indicate that
- * the source of the data is a MimePart. This prevents updateHeaders
- * from trying to change the headers for such data. In particular,
- * the original Content-Transfer-Encoding for the data must be preserved.
+ * the source of the data is a MimePart (that is, a byte array
+ * or a stream). This prevents updateHeaders from trying to
+ * change the headers for such data. In particular, the original
+ * Content-Transfer-Encoding for the data must be preserved.
      * Otherwise the data would need to be decoded and reencoded.
      */
     static class MimePartDataHandler extends DataHandler {

diff -r 0453674cd36a -r e4870216e6ab mail/src/main/java/javax/mail/internet/MimeMessage.java
--- a/mail/src/main/java/javax/mail/internet/MimeMessage.java Thu Jan 07 14:31:32 2010 -0800
+++ b/mail/src/main/java/javax/mail/internet/MimeMessage.java Thu Jan 07 15:34:42 2010 -0800
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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
@@ -1307,7 +1307,7 @@
         if (content != null)
             return new SharedByteArrayInputStream(content);
 
- throw new MessagingException("No content");
+ throw new MessagingException("No MimeMessage content");
     }
 
     /**
@@ -1403,6 +1403,12 @@
                 (c instanceof Multipart || c instanceof Message) &&
                 (content != null || contentStream != null)) {
             cachedContent = c;
+ /*
+ * We may abandon the input stream so make sure
+ * the MimeMultipart has consumed the stream.
+ */
+ if (c instanceof MimeMultipart)
+ ((MimeMultipart)c).parse();
         }
         return c;
     }
@@ -1758,14 +1764,19 @@
         if (content == null) {
             // call getContentStream to give subclass a chance to
             // provide the data on demand
- InputStream is = getContentStream();
- // now copy the data to the output stream
+ InputStream is = null;
             byte[] buf = new byte[8192];
- int len;
- while ((len = is.read(buf)) > 0)
- os.write(buf, 0, len);
- is.close();
- buf = null;
+ try {
+ is = getContentStream();
+ // now copy the data to the output stream
+ int len;
+ while ((len = is.read(buf)) > 0)
+ os.write(buf, 0, len);
+ } finally {
+ if (is != null)
+ is.close();
+ buf = null;
+ }
         } else {
             os.write(content);
         }

diff -r 0453674cd36a -r e4870216e6ab mail/src/test/java/javax/mail/internet/ModifyMessageTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/javax/mail/internet/ModifyMessageTest.java Thu Jan 07 15:34:42 2010 -0800
@@ -0,0 +1,190 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Sun Microsystems, Inc. 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.html
+ * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [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 javax.mail.internet;
+
+import java.io.OutputStream;
+import java.io.StringBufferInputStream;
+import java.util.Properties;
+
+import javax.mail.Session;
+import javax.mail.MessagingException;
+import javax.mail.BodyPart;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.junit.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test some of the ways you might modify a message that has been
+ * read from an input stream.
+ */
+public class ModifyMessageTest {
+
+ private static Session s = Session.getInstance(new Properties());
+
+ @Test
+ public void testAddHeader() throws Exception {
+ MimeMessage m = createMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ m.setHeader("a", "b");
+ m.saveChanges();
+
+ MimeMessage m2 = new MimeMessage(m);
+ assertEquals("b", m2.getHeader("a", null));
+ }
+
+ @Test
+ public void testChangeHeader() throws Exception {
+ MimeMessage m = createMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ m.setHeader("Subject", "test");
+ m.saveChanges();
+
+ MimeMessage m2 = new MimeMessage(m);
+ assertEquals("test", m2.getHeader("Subject", null));
+ }
+
+ @Test
+ public void testAddContent() throws Exception {
+ MimeMessage m = createMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ MimeBodyPart mbp = new MimeBodyPart();
+ mbp.setText("test");
+ mp.addBodyPart(mbp);
+ m.saveChanges();
+
+ MimeMessage m2 = new MimeMessage(m);
+ mp = (MimeMultipart)m2.getContent();
+ BodyPart bp = mp.getBodyPart(2);
+ assertEquals("test", bp.getContent());
+ // make sure nothing else changed
+ bp = mp.getBodyPart(0);
+ assertEquals("first part\n", bp.getContent());
+ bp = mp.getBodyPart(1);
+ assertEquals("second part\n", bp.getContent());
+ }
+
+ @Test
+ public void testChangeContent() throws Exception {
+ MimeMessage m = createMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ BodyPart bp = mp.getBodyPart(0);
+ bp.setText("test");
+ m.saveChanges();
+
+ MimeMessage m2 = new MimeMessage(m);
+ mp = (MimeMultipart)m2.getContent();
+ bp = mp.getBodyPart(0);
+ assertEquals("test", bp.getContent());
+ }
+
+ @Test
+ public void testChangeNestedContent() throws Exception {
+ MimeMessage m = createNestedMessage();
+ MimeMultipart mp = (MimeMultipart)m.getContent();
+ mp = (MimeMultipart)mp.getBodyPart(0).getContent();
+ BodyPart bp = mp.getBodyPart(0);
+ bp.setText("test");
+ m.saveChanges();
+
+ MimeMessage m2 = new MimeMessage(m);
+ mp = (MimeMultipart)m2.getContent();
+ mp = (MimeMultipart)mp.getBodyPart(0).getContent();
+ bp = mp.getBodyPart(0);
+ assertEquals("test", bp.getContent());
+ // make sure other content is not changed or re-encoded
+ MimeBodyPart mbp = (MimeBodyPart)mp.getBodyPart(1);
+ assertEquals("second part\n", mbp.getContent());
+ assertEquals("quoted-printable", mbp.getEncoding());
+ mbp = (MimeBodyPart)mp.getBodyPart(2);
+ assertEquals("third part\n", mbp.getContent());
+ assertEquals("base64", mbp.getEncoding());
+ }
+
+ private static MimeMessage createMessage() throws MessagingException {
+ String content =
+ "Mime-Version: 1.0\n" +
+ "Subject: Example\n" +
+ "Content-Type: multipart/mixed; boundary=\"-\"\n" +
+ "\n" +
+ "preamble\n" +
+ "---\n" +
+ "\n" +
+ "first part\n" +
+ "\n" +
+ "---\n" +
+ "\n" +
+ "second part\n" +
+ "\n" +
+ "-----\n";
+
+ return new MimeMessage(s, new StringBufferInputStream(content));
+ }
+
+ private static MimeMessage createNestedMessage() throws MessagingException {
+ String content =
+ "Mime-Version: 1.0\n" +
+ "Subject: Example\n" +
+ "Content-Type: multipart/mixed; boundary=\"-\"\n" +
+ "\n" +
+ "preamble\n" +
+ "---\n" +
+ "Content-Type: multipart/mixed; boundary=\"x\"\n" +
+ "\n" +
+ "--x\n" +
+ "\n" +
+ "first part\n" +
+ "\n" +
+ "--x\n" +
+ "Content-Transfer-Encoding: quoted-printable\n" +
+ "\n" +
+ "second part\n" +
+ "\n" +
+ "--x\n" +
+ "Content-Transfer-Encoding: base64\n" +
+ "\n" +
+ "dGhpcmQgcGFydAo=\n" + // "third part\n", base64 encoded
+ "\n" +
+ "--x--\n" +
+ "-----\n";
+
+ return new MimeMessage(s, new StringBufferInputStream(content));
+ }
+}


diff -r e4870216e6ab -r ebbbd07d77ff mail/src/test/java/com/sun/mail/util/UUDecoderStreamTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/com/sun/mail/util/UUDecoderStreamTest.java Fri Jan 08 11:39:37 2010 -0800
@@ -0,0 +1,288 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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.html
+ * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [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.util;
+
+import java.io.*;
+import java.util.StringTokenizer;
+import com.sun.mail.util.UUDecoderStream;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.framework.Test;
+import junit.framework.Assert;
+
+/**
+ * Test uudecoder.
+ *
+ * @author Bill Shannon
+ */
+
+public class UUDecoderStreamTest extends TestCase {
+ private TestData data;
+
+ private static boolean gen_test_input = false; // output good
+ private static int errors = 0; // number of errors detected
+
+ private static boolean junit;
+ private static TestSuite suite;
+
+ static class TestData {
+ public String name;
+ public boolean ignoreErrors;
+ public boolean ignoreMissingBeginEnd;
+ public byte[] input;
+ public byte[] expectedOutput;
+ public String expectedException;
+ }
+
+ public UUDecoderStreamTest(TestData t) {
+ super("testData");
+ data = t;
+ }
+
+ public void testData() throws Exception {
+ test(data);
+ }
+
+ public static Test suite() throws Exception {
+ suite = new TestSuite();
+ junit = true;
+ BufferedReader in = new BufferedReader(new InputStreamReader(
+ UUDecoderStreamTest.class.getResourceAsStream("uudata")));
+ TestData t;
+ while ((t = parse(in)) != null)
+ suite.addTest(new UUDecoderStreamTest(t));
+ return suite;
+ }
+
+ public static void main(String argv[]) throws Exception {
+ int optind;
+ // XXX - all options currently ignored
+ for (optind = 0; optind < argv.length; optind++) {
+ if (argv[optind].equals("-")) {
+ // ignore
+ } else if (argv[optind].equals("-g")) {
+ gen_test_input = true;
+ } else if (argv[optind].equals("--")) {
+ optind++;
+ break;
+ } else if (argv[optind].startsWith("-")) {
+ System.out.println(
+ "Usage: uutest [-g] [-]");
+ System.exit(1);
+ } else {
+ break;
+ }
+ }
+
+ // read from stdin
+ BufferedReader in =
+ new BufferedReader(new InputStreamReader(System.in));
+
+ TestData t;
+ while ((t = parse(in)) != null)
+ test(t);
+ System.exit(errors);
+ }
+
+ /*
+ * Parse the input, returning a test case.
+ */
+ public static TestData parse(BufferedReader in) throws Exception {
+
+ String line = null;
+ for (;;) {
+ line = in.readLine();
+ if (line == null)
+ return null;
+ if (line.length() == 0 || line.startsWith("#"))
+ continue;
+
+ if (!line.startsWith("TEST"))
+ throw new Exception("Bad test data format");
+ break;
+ }
+
+ TestData t = new TestData();
+ int i = line.indexOf(' '); // XXX - crude
+ t.name = line.substring(i + 1);
+
+ line = in.readLine();
+ StringTokenizer st = new StringTokenizer(line);
+ String tok = st.nextToken();
+ if (!tok.equals("DATA"))
+ throw new Exception("Bad test data format: " + line);
+ while (st.hasMoreTokens()) {
+ tok = st.nextToken();
+ if (tok.equals("ignoreErrors"))
+ t.ignoreErrors = true;
+ else if (tok.equals("ignoreMissingBeginEnd"))
+ t.ignoreMissingBeginEnd = true;
+ else
+ throw new Exception("Bad DATA option in line: " + line);
+ }
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ Writer os = new OutputStreamWriter(bos, "us-ascii");
+ for (;;) {
+ line = in.readLine();
+ if (line.equals("EXPECT"))
+ break;
+ os.write(line);
+ os.write("\n");
+ }
+ os.close();
+ t.input = bos.toByteArray();
+
+ bos = new ByteArrayOutputStream();
+ os = new OutputStreamWriter(bos, "us-ascii");
+ for (;;) {
+ line = in.readLine();
+ if (line.startsWith("EXCEPTION")) {
+ i = line.indexOf(' '); // XXX - crude
+ t.expectedException = line.substring(i + 1);
+ } else if (line.equals("END"))
+ break;
+ os.write(line);
+ os.write("\n");
+ }
+ os.close();
+ if (t.expectedException == null)
+ t.expectedOutput = bos.toByteArray();
+
+ return t;
+ }
+
+ /**
+ * Test the data in the test case.
+ */
+ public static void test(TestData t) throws Exception {
+ InputStream in =
+ new UUDecoderStream(new ByteArrayInputStream(t.input),
+ t.ignoreErrors, t.ignoreMissingBeginEnd);
+
+ // two cases - either we're expecting an exception or we're not
+ if (t.expectedException != null) {
+ try {
+ int c;
+ while ((c = in.read()) >= 0)
+ ; // throw it away
+ // read all the data with no exception - fail
+ if (junit)
+ Assert.fail("Didn't get expected exception: " +
+ t.expectedException);
+ System.out.println("Test: " + t.name);
+ System.out.println("Got no Exception");
+ System.out.println("Expected Exception: " +
+ t.expectedException);
+ errors++;
+ } catch (Exception ex) {
+ if (junit)
+ Assert.assertEquals("For expected exception",
+ ex.getClass().getName(), t.expectedException);
+ if (!ex.getClass().getName().equals(t.expectedException)) {
+ System.out.println("Test: " + t.name);
+ System.out.println("Got Exception: " + ex);
+ System.out.println("Expected Exception: " +
+ t.expectedException);
+ errors++;
+ }
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ioex) { }
+ }
+ } else {
+ InputStream ein = new ByteArrayInputStream(t.expectedOutput);
+ try {
+ int c, ec;
+ boolean gotError = false;
+ while ((c = in.read()) >= 0) {
+ ec = ein.read();
+ if (junit)
+ Assert.assertFalse("For expected EOF, got char " + c,
+ ec < 0);
+ if (ec < 0) {
+ System.out.println("Test: " + t.name);
+ System.out.println("Got char: " + c);
+ System.out.println("Expected EOF");
+ errors++;
+ gotError = true;
+ break;
+ }
+ if (junit)
+ Assert.assertEquals("For expected char " + ec +
+ ", got char " + c, ec, c);
+ if (c != ec) {
+ System.out.println("Test: " + t.name);
+ System.out.println("Got char: " + c);
+ System.out.println("Expected char: " + ec);
+ errors++;
+ gotError = true;
+ break;
+ }
+ }
+ if (!gotError) {
+ ec = ein.read();
+ if (junit)
+ Assert.assertFalse("For expected char " + ec +
+ ", got EOF", ec >= 0);
+ if (ec >= 0) {
+ System.out.println("Test: " + t.name);
+ System.out.println("Got EOF");
+ System.out.println("Expected char: " + ec);
+ errors++;
+ }
+ }
+ } catch (Exception ex) {
+ if (junit)
+ Assert.fail("Got exception: " + ex);
+ System.out.println("Test: " + t.name);
+ System.out.println("Got Exception: " + ex);
+ System.out.println("Expected no Exception");
+ errors++;
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ioex) { }
+ try {
+ ein.close();
+ } catch (IOException ioex) { }
+ }
+ }
+ }
+}

diff -r e4870216e6ab -r ebbbd07d77ff mail/src/test/java/javax/mail/internet/ReferencesTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/java/javax/mail/internet/ReferencesTest.java Fri Jan 08 11:39:37 2010 -0800
@@ -0,0 +1,119 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Sun Microsystems, Inc. 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.html
+ * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
+ * Sun designates this particular file as subject to the "Classpath" exception
+ * as provided by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the License
+ * Header, with the fields enclosed by brackets [] replaced by your own
+ * identifying information: "Portions Copyrighted [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 javax.mail.internet;
+
+import java.util.Properties;
+import javax.mail.*;
+import javax.mail.internet.*;
+
+import org.junit.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test setting of the References header.
+ *
+ * @author Bill Shannon
+ */
+public class ReferencesTest {
+ private static Session session = Session.getInstance(new Properties());
+
+ /*
+ * Test cases:
+ *
+ * Message-Id References In-Reply-To Expected Result
+ */
+
+ @Test
+ public void test1() throws MessagingException {
+ test(null, null, null, null);
+ }
+
+ @Test
+ public void test2() throws MessagingException {
+ test(null, null, "<1_at_a>", "<1_at_a>");
+ }
+
+ @Test
+ public void test3() throws MessagingException {
+ test(null, "<2_at_b>", null, "<2_at_b>");
+ }
+
+ @Test
+ public void test4() throws MessagingException {
+ test(null, "<2_at_b>", "<1_at_a>", "<2_at_b>");
+ }
+
+ @Test
+ public void test5() throws MessagingException {
+ test("<3_at_c>", null, null, "<3_at_c>");
+ }
+
+ @Test
+ public void test6() throws MessagingException {
+ test("<3_at_c>", null, "<1_at_a>", "<1_at_a> <3_at_c>");
+ }
+
+ @Test
+ public void test7() throws MessagingException {
+ test("<3_at_c>", "<2_at_b>", null, "<2_at_b> <3_at_c>");
+ }
+
+ @Test
+ public void test8() throws MessagingException {
+ test("<3_at_c>", "<2_at_b>", "<1_at_a>", "<2_at_b> <3_at_c>");
+ }
+
+ private static void test(String msgid, String ref, String irt, String res)
+ throws MessagingException {
+ MimeMessage msg = new MimeMessage(session);
+ msg.setFrom();
+ msg.setRecipients(Message.RecipientType.TO, "you_at_example.com");
+ msg.setSubject("test");
+ if (msgid != null)
+ msg.setHeader("Message-Id", msgid);
+ if (ref != null)
+ msg.setHeader("References", ref);
+ if (irt != null)
+ msg.setHeader("In-Reply-To", irt);
+ msg.setText("text");
+
+ MimeMessage reply = (MimeMessage)msg.reply(false);
+ String rref = reply.getHeader("References", " ");
+
+ assertEquals(res, rref);
+ }
+}

diff -r e4870216e6ab -r ebbbd07d77ff mail/src/test/resources/com/sun/mail/util/uudata
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/test/resources/com/sun/mail/util/uudata Fri Jan 08 11:39:37 2010 -0800
@@ -0,0 +1,162 @@
+#
+# Data to test uudecoder.
+#
+# Mostly tests error cases and ability to ignore errors.
+#
+
+TEST a simple decode test
+DATA
+begin 644 encoder.buf
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+this is a very very very very very long line to test the decoder
+END
+
+TEST no begin
+DATA
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+EXCEPTION com.sun.mail.util.DecodingException
+END
+
+TEST no end
+DATA
+begin 644 encoder.buf
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+EXPECT
+EXCEPTION com.sun.mail.util.DecodingException
+END
+
+TEST no end, no empty line
+DATA
+begin 644 encoder.buf
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+EXPECT
+EXCEPTION com.sun.mail.util.DecodingException
+END
+
+TEST no begin, ignore errors
+DATA ignoreMissingBeginEnd
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+this is a very very very very very long line to test the decoder
+END
+
+TEST no end, ignore errors
+DATA ignoreMissingBeginEnd
+begin 644 encoder.buf
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+EXPECT
+this is a very very very very very long line to test the decoder
+END
+
+TEST no begin, no end, ignore errors
+DATA ignoreMissingBeginEnd
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+EXPECT
+this is a very very very very very long line to test the decoder
+END
+
+TEST bad mode
+DATA
+begin xxx encoder.buf
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+EXCEPTION com.sun.mail.util.DecodingException
+END
+
+TEST bad mode, ignore errors
+DATA ignoreErrors
+begin xxx encoder.buf
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+this is a very very very very very long line to test the decoder
+END
+
+TEST bad filename
+DATA
+begin 644
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+EXCEPTION com.sun.mail.util.DecodingException
+END
+
+TEST bad filename, ignore errors
+DATA ignoreErrors
+begin 644
+M=&AI<R!I<R!A('9E<GD@=F5R>2!V97)Y('9E<GD@=F5R>2!L;VYG(&QI;F4@
+4=&\@=&5S="!T:&4_at_9&5C;V1E<@H!
+
+end
+EXPECT
+this is a very very very very very long
[truncated due to length]