commits@javamail.java.net

[javamail~mercurial:463] Properly ignore blank lines when ignoring missing "begin" line.

From: <shannon_at_kenai.com>
Date: Wed, 15 Aug 2012 23:47:51 +0000

Project: javamail
Repository: mercurial
Revision: 463
Author: shannon
Date: 2012-08-14 22:25:48 UTC
Link:

Log Message:
------------
Set proper Extension-Name for API jar file.
Add an example of how to use the UIDFolder interface.
When looking for boundary string in body, only skip lines that are all dashes.
Can't clone Threads in JDK 7.
MailHandlerTest better timeout support.
MailHandlerTest ensure unknown host can't be resolved.
(From Jason)
Update license URL.
Add email address.
Change vendor name to Oracle.
First pass at refactoring IMAP provider to better enable subclasses
to add support for product-secific features.
Further simplifications of IMAP provider to handle subclasses that add
support for protocol extensions.
Add @since; other cleanup.
Make the doList method protected, so subclasses can use it.
Add versions for more plugins.
Allow mbox to build on more than just SPARC based on the MACH environment var.
First version of the Gmail IMAP provider.
Oops, forgot CHANGES.txt entry for Gmail IMAP provider.
MailHandlerTest better timeout support.
MailHandlerTest ensure unknown host can't be resolved.
(This time the correct version from Jason.)
MailHandler force sort to always expose comparator bugs.
MailHandler explain null checks on return value of toString.
MailHandlerTest add sorting tests.
MailHandlerTest enable testGuessContentTypeReadlimit
MailHandlerTest fix unchecked cast warnings.
(From Jason)
Properly ignore blank lines when ignoring missing "begin" line.
(Patch from joegallo)


Revisions:
----------
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463


Modified Paths:
---------------
mailapijar/pom.xml
mail/src/main/java/javax/mail/UIDFolder.java
mail/src/main/java/javax/mail/internet/MimeMultipart.java
mail/src/test/java/com/sun/mail/imap/IMAPHandler.java
mail/src/test/java/com/sun/mail/imap/IMAPServer.java
mail/src/test/java/com/sun/mail/pop3/POP3Handler.java
mail/src/test/java/com/sun/mail/pop3/POP3Server.java
mail/src/test/java/com/sun/mail/smtp/SMTPHandler.java
mail/src/test/java/com/sun/mail/smtp/SMTPServer.java
mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
pom.xml
imap/src/main/resources/META-INF/javamail.providers
mail/src/main/resources/META-INF/javamail.default.providers
mbox/src/main/resources/META-INF/javamail.providers
pop3/src/main/resources/META-INF/javamail.providers
smtp/src/main/resources/META-INF/javamail.providers
mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
mail/src/main/java/com/sun/mail/imap/IMAPMessage.java
mail/src/main/java/com/sun/mail/imap/IMAPStore.java
mail/src/main/java/com/sun/mail/imap/MessageCache.java
mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPResponse.java
mail/src/main/java/com/sun/mail/imap/protocol/SearchSequence.java
mail/src/main/java/com/sun/mail/imap/protocol/FetchItem.java
mbox/native/pom.xml
javadoc/pom.xml
doc/release/CHANGES.txt
mail/src/main/java/com/sun/mail/util/logging/MailHandler.java
mail/src/main/java/com/sun/mail/util/UUDecoderStream.java
mail/src/test/resources/com/sun/mail/util/uudata


Added Paths:
------------
mail/src/main/java/com/sun/mail/imap/protocol/FetchItem.java
gimap/pom.xml
gimap/src/main/java/com/sun/mail/gimap/GmailFolder.java
gimap/src/main/java/com/sun/mail/gimap/GmailMessage.java
gimap/src/main/java/com/sun/mail/gimap/GmailMsgIdTerm.java
gimap/src/main/java/com/sun/mail/gimap/GmailRawSearchTerm.java
gimap/src/main/java/com/sun/mail/gimap/GmailSSLStore.java
gimap/src/main/java/com/sun/mail/gimap/GmailStore.java
gimap/src/main/java/com/sun/mail/gimap/GmailThrIdTerm.java
gimap/src/main/java/com/sun/mail/gimap/LongTerm.java
gimap/src/main/java/com/sun/mail/gimap/package.html
gimap/src/main/java/com/sun/mail/gimap/protocol/GmailProtocol.java
gimap/src/main/java/com/sun/mail/gimap/protocol/GmailSearchSequence.java
gimap/src/main/resources/META-INF/MANIFEST.MF
gimap/src/main/resources/META-INF/javamail.providers


Diffs:
------
diff -r bc39523cca98 -r 727ed6537a58 mailapijar/pom.xml
--- a/mailapijar/pom.xml Mon Jul 02 11:50:56 2012 -0700
+++ b/mailapijar/pom.xml Wed Jul 18 17:15:23 2012 -0700
@@ -3,7 +3,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-2012 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
@@ -64,6 +64,9 @@
     <name>JavaMail API jar</name>
 
     <properties>
+ <mail.extensionName>
+ javax.mail
+ </mail.extensionName>
         <mail.packages.export>
             javax.mail.*; version=${mail.spec.version}
         </mail.packages.export>


diff -r 727ed6537a58 -r 9e6993e66889 mail/src/main/java/javax/mail/UIDFolder.java
--- a/mail/src/main/java/javax/mail/UIDFolder.java Wed Jul 18 17:15:23 2012 -0700
+++ b/mail/src/main/java/javax/mail/UIDFolder.java Wed Jul 18 17:16:01 2012 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2012 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
@@ -62,8 +62,18 @@
  * <strong>must</strong> be greater than the one used in the earlier
  * session. <p>
  *
- * Refer to RFC 2060 <A HREF="http://www.ietf.org/rfc/rfc2060.txt">
- * http://www.ietf.org/rfc/rfc2060.txt</A> for more information.
+ * Refer to <A HREF="http://www.ietf.org/rfc/rfc2060.txt">RFC 2060</A>
+ * for more information.
+ *
+ * All the Folder objects returned by the default IMAP provider implement
+ * the UIDFolder interface. Use it as follows: <p>
+ * <blockquote><pre>
+ *
+ * Folder f = store.getFolder("whatever");
+ * UIDFolder uf = (UIDFolder)f;
+ * long uid = uf.getUID(msg);
+ *
+ * </pre></blockquote><p>
  *
  * @author John Mani
  */


diff -r 9e6993e66889 -r 2e74437e3dae mail/src/main/java/javax/mail/internet/MimeMultipart.java
--- a/mail/src/main/java/javax/mail/internet/MimeMultipart.java Wed Jul 18 17:16:01 2012 -0700
+++ b/mail/src/main/java/javax/mail/internet/MimeMultipart.java Fri Jul 20 13:25:06 2012 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2012 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
@@ -566,7 +566,7 @@
                      * the boundary and save it.
                      */
                     if (line.length() > 2 && line.startsWith("--")) {
- if (line.length() > 4 && line.endsWith("--")) {
+ if (line.length() > 4 && allDashes(line)) {
                             /*
                              * The first boundary-like line we find is
                              * probably *not* the end-of-multipart boundary
@@ -839,7 +839,7 @@
                      * the boundary and save it.
                      */
                     if (line.length() > 2 && line.startsWith("--")) {
- if (line.length() > 4 && line.endsWith("--")) {
+ if (line.length() > 4 && allDashes(line)) {
                             /*
                              * The first boundary-like line we find is
                              * probably *not* the end-of-multipart boundary
@@ -1115,6 +1115,17 @@
     }
 
     /**
+ * Is the string all dashes ('-')?
+ */
+ private static boolean allDashes(String s) {
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) != '-')
+ return false;
+ }
+ return true;
+ }
+
+ /**
      * Read data from the input stream to fill the buffer starting
      * at the specified offset with the specified number of bytes.
      * If len is zero, return zero. If at EOF, return -1. Otherwise,


diff -r 2e74437e3dae -r ce7a3e1035b7 mail/src/test/java/com/sun/mail/imap/IMAPHandler.java
--- a/mail/src/test/java/com/sun/mail/imap/IMAPHandler.java Fri Jul 20 13:25:06 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/imap/IMAPHandler.java Fri Jul 20 16:39:15 2012 -0700
@@ -57,7 +57,7 @@
  * @author sbo
  * @author Bill Shannon
  */
-public class IMAPHandler extends Thread implements Cloneable {
+public class IMAPHandler implements Runnable, Cloneable {
 
     /** Logger for this class. */
     private static final Logger LOGGER =

diff -r 2e74437e3dae -r ce7a3e1035b7 mail/src/test/java/com/sun/mail/imap/IMAPServer.java
--- a/mail/src/test/java/com/sun/mail/imap/IMAPServer.java Fri Jul 20 13:25:06 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/imap/IMAPServer.java Fri Jul 20 16:39:15 2012 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2009-2010 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2012 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
@@ -123,7 +123,7 @@
                     final IMAPHandler imapHandler =
                         (IMAPHandler)handler.clone();
                     imapHandler.setClientSocket(clientSocket);
- imapHandler.start();
+ new Thread(imapHandler).start();
                 } catch (final IOException e) {
                     //e.printStackTrace();
                 }

diff -r 2e74437e3dae -r ce7a3e1035b7 mail/src/test/java/com/sun/mail/pop3/POP3Handler.java
--- a/mail/src/test/java/com/sun/mail/pop3/POP3Handler.java Fri Jul 20 13:25:06 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/pop3/POP3Handler.java Fri Jul 20 16:39:15 2012 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2009-2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2012 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
@@ -54,7 +54,7 @@
  *
  * @author sbo
  */
-public class POP3Handler extends Thread implements Cloneable {
+public class POP3Handler implements Runnable, Cloneable {
     
     /** Logger for this class. */
     private static final Logger LOGGER =

diff -r 2e74437e3dae -r ce7a3e1035b7 mail/src/test/java/com/sun/mail/pop3/POP3Server.java
--- a/mail/src/test/java/com/sun/mail/pop3/POP3Server.java Fri Jul 20 13:25:06 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/pop3/POP3Server.java Fri Jul 20 16:39:15 2012 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2009-2010 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2012 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
@@ -121,7 +121,7 @@
                     final POP3Handler pop3Handler =
                         (POP3Handler)this.handler.clone();
                     pop3Handler.setClientSocket(clientSocket);
- pop3Handler.start();
+ new Thread(pop3Handler).start();
                 } catch (final IOException e) {
                     //e.printStackTrace();
                 }

diff -r 2e74437e3dae -r ce7a3e1035b7 mail/src/test/java/com/sun/mail/smtp/SMTPHandler.java
--- a/mail/src/test/java/com/sun/mail/smtp/SMTPHandler.java Fri Jul 20 13:25:06 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/smtp/SMTPHandler.java Fri Jul 20 16:39:15 2012 -0700
@@ -58,7 +58,7 @@
  * @author Bill Shannon
  * @author sbo
  */
-public class SMTPHandler extends Thread implements Cloneable {
+public class SMTPHandler implements Runnable, Cloneable {
 
     /** Logger for this class. */
     private static final Logger LOGGER =

diff -r 2e74437e3dae -r ce7a3e1035b7 mail/src/test/java/com/sun/mail/smtp/SMTPServer.java
--- a/mail/src/test/java/com/sun/mail/smtp/SMTPServer.java Fri Jul 20 13:25:06 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/smtp/SMTPServer.java Fri Jul 20 16:39:15 2012 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 2009-2011 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2012 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
@@ -123,7 +123,7 @@
                     final SMTPHandler smtpHandler =
                         (SMTPHandler)handler.clone();
                     smtpHandler.setClientSocket(clientSocket);
- smtpHandler.start();
+ new Thread(smtpHandler).start();
                 } catch (final IOException e) {
                     //e.printStackTrace();
                 }


diff -r ce7a3e1035b7 -r 9c5f0e24be47 mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Jul 20 16:39:15 2012 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Mon Jul 23 16:19:17 2012 -0700
@@ -1401,8 +1401,8 @@
         if (verify != null) {
             props.put(p.concat(".verify"), verify);
         }
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1");
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9");
 
         read(manager, props);
 
@@ -1784,8 +1784,9 @@
             InternalErrorManager em = (InternalErrorManager) target.getErrorManager();
             for (int i = 0; i < em.exceptions.size(); i++) {
                 Exception t = em.exceptions.get(i);
- if (t instanceof MessagingException
- && t.getCause() instanceof UnknownHostException) {
+ if (isUnknownOrTimeout(t)) {
+ //if (t instanceof MessagingException
+ //&& t.getCause() instanceof UnknownHostException) {
                     continue;
                 }
                 dump(t);
@@ -3560,8 +3561,8 @@
             props.put(p.concat(".mail.from"), "localhost_at_localdomain");
             props.put(p.concat(".mail.sender"), "mail_at_handler");
             props.put(p.concat(".errorManager"), VerifyErrorManager.class.getName());
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1");
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9");
             props.put(p.concat(".verify"), "remote");
 
             read(manager, props);
@@ -3595,8 +3596,8 @@
         props.put("mail.host", "bad-host-name");
         props.put("mail.smtp.host", "bad-host-name");
         props.put("mail.smtp.port", Integer.toString(OPEN_PORT));
- props.put("mail.smtp.connectiontimeout", "1");
- props.put("mail.smtp.timeout", "1");
+ props.put("mail.smtp.connectiontimeout", "9");
+ props.put("mail.smtp.timeout", "9");
 
         Session session = Session.getInstance(new Properties());
         MimeMessage msg = new MimeMessage(session);
@@ -3627,8 +3628,8 @@
         props.put("mail.host", "bad-host-name");
         props.put("mail.smtp.host", "bad-host-name");
         props.put("mail.smtp.port", Integer.toString(OPEN_PORT));
- props.put("mail.smtp.connectiontimeout", "1");
- props.put("mail.smtp.timeout", "1");
+ props.put("mail.smtp.connectiontimeout", "9");
+ props.put("mail.smtp.timeout", "9");
 
         MailHandler target = new MailHandler();
         Session session = Session.getInstance(new Properties());
@@ -3665,8 +3666,8 @@
             props.put(p.concat(".subject"), p.concat(" test"));
             props.put(p.concat(".mail.from"), "badAddress");
             props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1");
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9");
             props.put(p.concat(".verify"), "local");
 
             read(manager, props);
@@ -3723,8 +3724,8 @@
         props.put("mail.cc", "badAddress");
         props.put("subject", "test");
         props.put("mail.from", "badAddress");
- props.put("mail.smtp.connectiontimeout", "1");
- props.put("mail.smtp.timeout", "1");
+ props.put("mail.smtp.connectiontimeout", "9");
+ props.put("mail.smtp.timeout", "9");
         props.put("verify", "local");
 
         InternalErrorManager em = new InternalErrorManager();
@@ -3783,8 +3784,8 @@
             props.put(p.concat(".subject"), p.concat(" test"));
             props.put(p.concat(".mail.from"), "badAddress");
             props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1"); //no verify.
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9"); //no verify.
 
             read(manager, props);
 
@@ -3796,8 +3797,8 @@
             props.put("mail.cc", "badAddress");
             props.put("subject", "test");
             props.put("mail.from", "badAddress");
- props.put("mail.smtp.connectiontimeout", "1");
- props.put("mail.smtp.timeout", "1");
+ props.put("mail.smtp.connectiontimeout", "9");
+ props.put("mail.smtp.timeout", "9");
             props.put("verify", "local");
 
             MailHandler instance = new MailHandler(props);
@@ -3859,8 +3860,8 @@
             props.put(p.concat(".subject"), p.concat(" test"));
             props.put(p.concat(".mail.from"), "badAddress");
             props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1");
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9");
             props.put(p.concat(".verify"), "remote");
 
             read(manager, props);
@@ -3895,8 +3896,8 @@
         props.put(p.concat(".mail.to"), "badAddress");
         props.put(p.concat(".mail.cc"), "badAddress");
         props.put(p.concat(".mail.from"), "badAddress");
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1");
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9");
         props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
 
         //test class cast.
@@ -3965,8 +3966,8 @@
         props.put(p.concat(".mail.to"), "badAddress");
         props.put(p.concat(".mail.cc"), "badAddress");
         props.put(p.concat(".mail.from"), "badAddress");
- props.put(p.concat(".mail.smtp.connectiontimeout"), "1");
- props.put(p.concat(".mail.smtp.timeout"), "1");
+ props.put(p.concat(".mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat(".mail.smtp.timeout"), "9");
         props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
 
         //test class cast.
@@ -4524,8 +4525,8 @@
         props.put(p.concat("mail.to"), "badAddress");
         props.put(p.concat("mail.cc"), "badAddress");
         props.put(p.concat("mail.from"), "badAddress");
- props.put(p.concat("mail.smtp.connectiontimeout"), "1");
- props.put(p.concat("mail.smtp.timeout"), "1");
+ props.put(p.concat("mail.smtp.connectiontimeout"), "9");
+ props.put(p.concat("mail.smtp.timeout"), "9");
         props.put(p.concat("errorManager"), InternalErrorManager.class.getName());
         return props;
     }
@@ -4857,6 +4858,15 @@
         }
     }
 
+ private static boolean isUnknownOrTimeout(Throwable t) {
+ if (t instanceof MessagingException) {
+ return isUnknownOrTimeout(t.getCause());
+ } else {
+ return t instanceof java.net.UnknownHostException
+ || t instanceof java.net.SocketTimeoutException;
+ }
+ }
+
     /**
      * http://www.iana.org/assignments/port-numbers
      * @return a open dynamic port.


diff -r 9c5f0e24be47 -r 0ed158377423 pom.xml
--- a/pom.xml Mon Jul 23 16:19:17 2012 -0700
+++ b/pom.xml Fri Jul 27 23:47:59 2012 -0700
@@ -79,7 +79,7 @@
       </license>
       <license>
         <name>GPLv2+CE</name>
- <url>https://glassfish.dev.java.net/public/CDDL+GPL.html</url>
+ <url>https://glassfish.java.net/public/CDDL+GPL_1_1.html</url>
         <distribution>repo</distribution>
         <comments>GPL version 2 plus the Classpath Exception</comments>
       </license>
@@ -141,6 +141,7 @@
         <developer>
             <id>shannon</id>
             <name>Bill Shannon</name>
+ <email>bill.shannon_at_oracle.com</email>
             <organization>Oracle</organization>
             <roles>
                 <role>lead</role>


diff -r 0ed158377423 -r c52880c12a3f imap/src/main/resources/META-INF/javamail.providers
--- a/imap/src/main/resources/META-INF/javamail.providers Fri Jul 27 23:47:59 2012 -0700
+++ b/imap/src/main/resources/META-INF/javamail.providers Tue Jul 31 13:50:38 2012 -0700
@@ -1,3 +1,3 @@
-# JavaMail IMAP provider Sun Microsystems, Inc
-protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Sun Microsystems, Inc;
-protocol=imaps; type=store; class=com.sun.mail.imap.IMAPSSLStore; vendor=Sun Microsystems, Inc;
+# JavaMail IMAP provider Oracle
+protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle;
+protocol=imaps; type=store; class=com.sun.mail.imap.IMAPSSLStore; vendor=Oracle;

diff -r 0ed158377423 -r c52880c12a3f mail/src/main/resources/META-INF/javamail.default.providers
--- a/mail/src/main/resources/META-INF/javamail.default.providers Fri Jul 27 23:47:59 2012 -0700
+++ b/mail/src/main/resources/META-INF/javamail.default.providers Tue Jul 31 13:50:38 2012 -0700
@@ -1,9 +1,9 @@
-# JavaMail IMAP provider Sun Microsystems, Inc
-protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Sun Microsystems, Inc;
-protocol=imaps; type=store; class=com.sun.mail.imap.IMAPSSLStore; vendor=Sun Microsystems, Inc;
-# JavaMail SMTP provider Sun Microsystems, Inc
-protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Sun Microsystems, Inc;
-protocol=smtps; type=transport; class=com.sun.mail.smtp.SMTPSSLTransport; vendor=Sun Microsystems, Inc;
-# JavaMail POP3 provider Sun Microsystems, Inc
-protocol=pop3; type=store; class=com.sun.mail.pop3.POP3Store; vendor=Sun Microsystems, Inc;
-protocol=pop3s; type=store; class=com.sun.mail.pop3.POP3SSLStore; vendor=Sun Microsystems, Inc;
+# JavaMail IMAP provider Oracle
+protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle;
+protocol=imaps; type=store; class=com.sun.mail.imap.IMAPSSLStore; vendor=Oracle;
+# JavaMail SMTP provider Oracle
+protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle;
+protocol=smtps; type=transport; class=com.sun.mail.smtp.SMTPSSLTransport; vendor=Oracle;
+# JavaMail POP3 provider Oracle
+protocol=pop3; type=store; class=com.sun.mail.pop3.POP3Store; vendor=Oracle;
+protocol=pop3s; type=store; class=com.sun.mail.pop3.POP3SSLStore; vendor=Oracle;

diff -r 0ed158377423 -r c52880c12a3f mbox/src/main/resources/META-INF/javamail.providers
--- a/mbox/src/main/resources/META-INF/javamail.providers Fri Jul 27 23:47:59 2012 -0700
+++ b/mbox/src/main/resources/META-INF/javamail.providers Tue Jul 31 13:50:38 2012 -0700
@@ -1,1 +1,1 @@
-protocol=mbox; type=store; class=com.sun.mail.mbox.MboxStore; vendor=Sun Microsy stems, Inc;
+protocol=mbox; type=store; class=com.sun.mail.mbox.MboxStore; vendor=Oracle;

diff -r 0ed158377423 -r c52880c12a3f pop3/src/main/resources/META-INF/javamail.providers
--- a/pop3/src/main/resources/META-INF/javamail.providers Fri Jul 27 23:47:59 2012 -0700
+++ b/pop3/src/main/resources/META-INF/javamail.providers Tue Jul 31 13:50:38 2012 -0700
@@ -1,3 +1,3 @@
-# JavaMail POP3 provider Sun Microsystems, Inc
-protocol=pop3; type=store; class=com.sun.mail.pop3.POP3Store; vendor=Sun Microsy stems, Inc;
-protocol=pop3s; type=store; class=com.sun.mail.pop3.POP3SSLStore; vendor=Sun Microsystems, Inc;
+# JavaMail POP3 provider Oracle
+protocol=pop3; type=store; class=com.sun.mail.pop3.POP3Store; vendor=Oracle;
+protocol=pop3s; type=store; class=com.sun.mail.pop3.POP3SSLStore; vendor=Oracle;

diff -r 0ed158377423 -r c52880c12a3f smtp/src/main/resources/META-INF/javamail.providers
--- a/smtp/src/main/resources/META-INF/javamail.providers Fri Jul 27 23:47:59 2012 -0700
+++ b/smtp/src/main/resources/META-INF/javamail.providers Tue Jul 31 13:50:38 2012 -0700
@@ -1,3 +1,3 @@
-# JavaMail SMTP provider Sun Microsystems, Inc
-protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Sun Microsystems, Inc;
-protocol=smtps; type=transport; class=com.sun.mail.smtp.SMTPSSLTransport; vendor=Sun Microsystems, Inc;
+# JavaMail SMTP provider Oracle
+protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle;
+protocol=smtps; type=transport; class=com.sun.mail.smtp.SMTPSSLTransport; vendor=Oracle;


diff -r c52880c12a3f -r c5dfaf269e6c mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Tue Jul 31 13:50:38 2012 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Mon Aug 06 15:08:23 2012 -0700
@@ -1018,7 +1018,186 @@
     public synchronized void fetch(Message[] msgs, FetchProfile fp)
                         throws MessagingException {
         checkOpened();
- IMAPMessage.fetch(this, msgs, fp);
+
+ StringBuffer command = new StringBuffer();
+ boolean first = true;
+ boolean allHeaders = false;
+
+ if (fp.contains(FetchProfile.Item.ENVELOPE)) {
+ command.append(getEnvelopeCommand());
+ first = false;
+ }
+ if (fp.contains(FetchProfile.Item.FLAGS)) {
+ command.append(first ? "FLAGS" : " FLAGS");
+ first = false;
+ }
+ if (fp.contains(FetchProfile.Item.CONTENT_INFO)) {
+ command.append(first ? "BODYSTRUCTURE" : " BODYSTRUCTURE");
+ first = false;
+ }
+ if (fp.contains(UIDFolder.FetchProfileItem.UID)) {
+ command.append(first ? "UID" : " UID");
+ first = false;
+ }
+ if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS)) {
+ allHeaders = true;
+ if (protocol.isREV1())
+ command.append(first ?
+ "BODY.PEEK[HEADER]" : " BODY.PEEK[HEADER]");
+ else
+ command.append(first ? "RFC822.HEADER" : " RFC822.HEADER");
+ first = false;
+ }
+ if (fp.contains(IMAPFolder.FetchProfileItem.SIZE)) {
+ command.append(first ? "RFC822.SIZE" : " RFC822.SIZE");
+ first = false;
+ }
+
+ // if we're not fetching all headers, fetch individual headers
+ String[] hdrs = null;
+ if (!allHeaders) {
+ hdrs = fp.getHeaderNames();
+ if (hdrs.length > 0) {
+ if (!first)
+ command.append(" ");
+ command.append(createHeaderCommand(hdrs));
+ }
+ }
+
+ createFetchCommand(command, fp);
+
+ Utility.Condition condition = newFetchProfileCondition(fp);
+
+ // Acquire the Folder's MessageCacheLock.
+ synchronized(messageCacheLock) {
+
+ // Apply the test, and get the sequence-number set for
+ // the messages that need to be prefetched.
+ MessageSet[] msgsets = Utility.toMessageSet(msgs, condition);
+
+ if (msgsets == null)
+ // We already have what we need.
+ return;
+
+ Response[] r = null;
+ Vector v = new Vector(); // to collect non-FETCH responses &
+ // unsolicited FETCH FLAG responses
+ try {
+ r = getProtocol().fetch(msgsets, command.toString());
+ } catch (ConnectionException cex) {
+ throw new FolderClosedException(this, cex.getMessage());
+ } catch (CommandFailedException cfx) {
+ // Ignore these, as per RFC 2180
+ } catch (ProtocolException pex) {
+ throw new MessagingException(pex.getMessage(), pex);
+ }
+
+ if (r == null)
+ return;
+
+ for (int i = 0; i < r.length; i++) {
+ if (r[i] == null)
+ continue;
+ if (!(r[i] instanceof FetchResponse)) {
+ v.addElement(r[i]); // Unsolicited Non-FETCH response
+ continue;
+ }
+
+ // Got a FetchResponse.
+ FetchResponse f = (FetchResponse)r[i];
+ // Get the corresponding message.
+ IMAPMessage msg = getMessageBySeqNumber(f.getNumber());
+
+ int count = f.getItemCount();
+ boolean unsolicitedFlags = false;
+
+ for (int j = 0; j < count; j++) {
+ Item item = f.getItem(j);
+ // Check for the FLAGS item
+ if (item instanceof Flags &&
+ (!fp.contains(FetchProfile.Item.FLAGS) ||
+ msg == null)) {
+ // Ok, Unsolicited FLAGS update.
+ unsolicitedFlags = true;
+ } else if (msg != null)
+ msg.handleFetchItem(item, hdrs, allHeaders);
+ }
+
+ // If this response contains any unsolicited FLAGS
+ // add it to the unsolicited response vector
+ if (unsolicitedFlags)
+ v.addElement(f);
+ }
+
+ // Dispatch any unsolicited responses
+ int size = v.size();
+ if (size != 0) {
+ Response[] responses = new Response[size];
+ v.copyInto(responses);
+ handleResponses(responses);
+ }
+
+ } // Release messageCacheLock
+ }
+
+ /**
+ * Return the IMAP FETCH items to request in order to load
+ * all the "envelope" data.
+ */
+ protected String getEnvelopeCommand() {
+ return IMAPMessage.EnvelopeCmd;
+ }
+
+ /**
+ * Add any FETCH commands to the command buffer that are necessary
+ * to fetch the items in the FetchProfile. Subclasses of IMAPFolder
+ * may override this method to handle additional custom FetchProfile items.
+ */
+ protected void createFetchCommand(StringBuffer command, FetchProfile fp) {
+ }
+
+ /**
+ * Create a new FetchProfileCondition object.
+ * Subclasses of IMAPFolder may override this method to create a
+ * subclass of IMAPMessage.FetchProfileCondition.
+ */
+ protected Utility.Condition newFetchProfileCondition(FetchProfile fp) {
+ return new IMAPMessage.FetchProfileCondition(fp);
+ }
+
+ /**
+ * Create a new IMAPMessage object to represent the given message number.
+ * Subclasses of IMAPFolder may override this method to create a
+ * subclass of IMAPMessage.
+ */
+ protected IMAPMessage newIMAPMessage(int msgnum) {
+ return new IMAPMessage(this, msgnum);
+ }
+
+ /**
+ * Create the appropriate IMAP FETCH command items to fetch the
+ * requested headers.
+ */
+ private String createHeaderCommand(String[] hdrs) {
+ StringBuffer sb;
+
+ if (protocol.isREV1())
+ sb = new StringBuffer("BODY.PEEK[HEADER.FIELDS (");
+ else
+ sb = new StringBuffer("RFC822.HEADER.LINES (");
+
+ for (int i = 0; i < hdrs.length; i++) {
+ if (i > 0)
+ sb.append(" ");
+ sb.append(hdrs[i]);
+ }
+
+ if (protocol.isREV1())
+ sb.append(")]");
+ else
+ sb.append(")");
+
+ return sb.toString();
     }
 
     /**

diff -r c52880c12a3f -r c5dfaf269e6c mail/src/main/java/com/sun/mail/imap/IMAPMessage.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPMessage.java Tue Jul 31 13:50:38 2012 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPMessage.java Mon Aug 06 15:08:23 2012 -0700
@@ -113,7 +113,7 @@
     private Hashtable loadedHeaders = new Hashtable(1);
 
     // This is our Envelope
- private static String EnvelopeCmd = "ENVELOPE INTERNALDATE RFC822.SIZE";
+ protected static String EnvelopeCmd = "ENVELOPE INTERNALDATE RFC822.SIZE";
 
     /**
      * Constructor.
@@ -955,261 +955,208 @@
     }
 
     /**
- * The prefetch method. Called from IMAPFolder.fetch()
+ * This class implements the test to be done on each
+ * message in the folder. The test is to check whether the
+ * message has already cached all the items requested in the
+ * FetchProfile. If any item is missing, the test succeeds and
+ * breaks out.
      */
- static void fetch(IMAPFolder folder, Message[] msgs,
- FetchProfile fp) throws MessagingException {
+ public static class FetchProfileCondition implements Utility.Condition {
+ private boolean needEnvelope = false;
+ private boolean needFlags = false;
+ private boolean needBodyStructure = false;
+ private boolean needUID = false;
+ private boolean needHeaders = false;
+ private boolean needSize = false;
+ private String[] hdrs = null;
 
- /* This class implements the test to be done on each
- * message in the folder. The test is to check whether the
- * message has already cached all the items requested in the
- * FetchProfile. If any item is missing, the test succeeds and
- * breaks out.
+ /**
+ * Create a FetchProfileCondition to determine if we need to fetch
+ * any of the information specified in the FetchProfile.
          */
- class FetchProfileCondition implements Utility.Condition {
- private boolean needEnvelope = false;
- private boolean needFlags = false;
- private boolean needBodyStructure = false;
- private boolean needUID = false;
- private boolean needHeaders = false;
- private boolean needSize = false;
- private String[] hdrs = null;
+ public FetchProfileCondition(FetchProfile fp) {
+ if (fp.contains(FetchProfile.Item.ENVELOPE))
+ needEnvelope = true;
+ if (fp.contains(FetchProfile.Item.FLAGS))
+ needFlags = true;
+ if (fp.contains(FetchProfile.Item.CONTENT_INFO))
+ needBodyStructure = true;
+ if (fp.contains(UIDFolder.FetchProfileItem.UID))
+ needUID = true;
+ if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS))
+ needHeaders = true;
+ if (fp.contains(IMAPFolder.FetchProfileItem.SIZE))
+ needSize = true;
+ hdrs = fp.getHeaderNames();
+ }
 
- public FetchProfileCondition(FetchProfile fp) {
- if (fp.contains(FetchProfile.Item.ENVELOPE))
- needEnvelope = true;
- if (fp.contains(FetchProfile.Item.FLAGS))
- needFlags = true;
- if (fp.contains(FetchProfile.Item.CONTENT_INFO))
- needBodyStructure = true;
- if (fp.contains(UIDFolder.FetchProfileItem.UID))
- needUID = true;
- if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS))
- needHeaders = true;
- if (fp.contains(IMAPFolder.FetchProfileItem.SIZE))
- needSize = true;
- hdrs = fp.getHeaderNames();
+ /**
+ * Return true if we NEED to fetch the requested information
+ * for the specified message.
+ */
+ public boolean test(IMAPMessage m) {
+ if (needEnvelope && m._getEnvelope() == null)
+ return true; // no envelope
+ if (needFlags && m._getFlags() == null)
+ return true; // no flags
+ if (needBodyStructure && m._getBodyStructure() == null)
+ return true; // no BODYSTRUCTURE
+ if (needUID && m.getUID() == -1) // no UID
+ return true;
+ if (needHeaders && !m.areHeadersLoaded()) // no headers
+ return true;
+ if (needSize && m.size == -1) // no size
+ return true;
+
+ // Is the desired header present ?
+ for (int i = 0; i < hdrs.length; i++) {
+ if (!m.isHeaderLoaded(hdrs[i]))
+ return true; // Nope, return
             }
 
- // The actual test.
- public boolean test(IMAPMessage m) {
- if (needEnvelope && m._getEnvelope() == null)
- return true; // no envelope
- if (needFlags && m._getFlags() == null)
- return true; // no flags
- if (needBodyStructure && m._getBodyStructure() == null)
- return true; // no BODYSTRUCTURE
- if (needUID && m.getUID() == -1) // no UID
- return true;
- if (needHeaders && !m.areHeadersLoaded()) // no headers
- return true;
- if (needSize && m.size == -1) // no size
- return true;
+ return false;
+ }
+ }
 
- // Is the desired header present ?
- for (int i = 0; i < hdrs.length; i++) {
- if (!m.isHeaderLoaded(hdrs[i]))
- return true; // Nope, return
- }
+ /**
+ * Apply the data in the FETCH item to this message.
+ *
+ * ASSERT: Must hold the messageCacheLock.
+ */
+ protected boolean handleFetchItem(Item item,
+ String[] hdrs, boolean allHeaders)
+ throws MessagingException {
+ // Check for the FLAGS item
+ if (item instanceof Flags)
+ flags = (Flags)item;
+ // Check for ENVELOPE items
+ else if (item instanceof ENVELOPE)
+ envelope = (ENVELOPE)item;
+ else if (item instanceof INTERNALDATE)
+ receivedDate = ((INTERNALDATE)item).getDate();
+ else if (item instanceof RFC822SIZE)
+ size = ((RFC822SIZE)item).size;
 
- return false;
- }
+ // Check for the BODYSTRUCTURE item
+ else if (item instanceof BODYSTRUCTURE)
+ bs = (BODYSTRUCTURE)item;
+ // Check for the UID item
+ else if (item instanceof UID) {
+ UID u = (UID)item;
+ uid = u.uid; // set uid
+ // add entry into uid table
+ if (((IMAPFolder)folder).uidTable == null)
+ ((IMAPFolder)folder).uidTable = new Hashtable();
+ ((IMAPFolder)folder).uidTable.put(new Long(u.uid), this);
         }
 
- StringBuffer command = new StringBuffer();
- boolean first = true;
- boolean allHeaders = false;
-
- if (fp.contains(FetchProfile.Item.ENVELOPE)) {
- command.append(EnvelopeCmd);
- first = false;
- }
- if (fp.contains(FetchProfile.Item.FLAGS)) {
- command.append(first ? "FLAGS" : " FLAGS");
- first = false;
- }
- if (fp.contains(FetchProfile.Item.CONTENT_INFO)) {
- command.append(first ? "BODYSTRUCTURE" : " BODYSTRUCTURE");
- first = false;
- }
- if (fp.contains(UIDFolder.FetchProfileItem.UID)) {
- command.append(first ? "UID" : " UID");
- first = false;
- }
- if (fp.contains(IMAPFolder.FetchProfileItem.HEADERS)) {
- allHeaders = true;
- if (folder.protocol.isREV1())
- command.append(first ?
- "BODY.PEEK[HEADER]" : " BODY.PEEK[HEADER]");
- else
- command.append(first ? "RFC822.HEADER" : " RFC822.HEADER");
- first = false;
- }
- if (fp.contains(IMAPFolder.FetchProfileItem.SIZE)) {
- command.append(first ? "RFC822.SIZE" : " RFC822.SIZE");
- first = false;
- }
-
- // if we're not fetching all headers, fetch individual headers
- String[] hdrs = null;
- if (!allHeaders) {
- hdrs = fp.getHeaderNames();
- if (hdrs.length > 0) {
- if (!first)
- command.append(" ");
- command.append(craftHeaderCmd(folder.protocol, hdrs));
- }
- }
-
- Utility.Condition condition = new FetchProfileCondition(fp);
-
- // Acquire the Folder's MessageCacheLock.
- synchronized(folder.messageCacheLock) {
-
- // Apply the test, and get the sequence-number set for
- // the messages that need to be prefetched.
- MessageSet[] msgsets = Utility.toMessageSet(msgs, condition);
-
- if (msgsets == null)
- // We already have what we need.
- return;
-
- Response[] r = null;
- Vector v = new Vector(); // to collect non-FETCH responses &
- // unsolicited FETCH FLAG responses
- try {
- r = folder.getProtocol().fetch(msgsets, command.toString());
- } catch (ConnectionException cex) {
- throw new FolderClosedException(folder, cex.getMessage());
- } catch (CommandFailedException cfx) {
- // Ignore these, as per RFC 2180
- } catch (ProtocolException pex) {
- throw new MessagingException(pex.getMessage(), pex);
+ // Check for header items
+ else if (item instanceof RFC822DATA ||
+ item instanceof BODY) {
+ InputStream headerStream;
+ if (item instanceof RFC822DATA) // IMAP4
+ headerStream =
+ ((RFC822DATA)item).getByteArrayInputStream();
+ else // IMAP4rev1
+ headerStream =
+ ((BODY)item).getByteArrayInputStream();
+
+ // Load the obtained headers.
+ InternetHeaders h = new InternetHeaders();
+ // Some IMAP servers (e.g., gmx.net) return NIL
+ // instead of a string just containing a CR/LF
+ // when the header list is empty.
+ if (headerStream != null)
+ h.load(headerStream);
+ if (headers == null || allHeaders)
+ headers = h;
+ else {
+ /*
+ * This is really painful. A second fetch
+ * of the same headers (which might occur because
+ * a new header was added to the set requested)
+ * will return headers we already know about.
+ * In this case, only load the headers we haven't
+ * seen before to avoid adding duplicates of
+ * headers we already have.
+ *
+ * XXX - There's a race condition here if another
+ * thread is reading headers in the same message
+ * object, because InternetHeaders is not thread
+ * safe.
+ */
+ Enumeration e = h.getAllHeaders();
+ while (e.hasMoreElements()) {
+ Header he = (Header)e.nextElement();
+ if (!isHeaderLoaded(he.getName()))
+ headers.addHeader(
+ he.getName(), he.getValue());
+ }
             }
 
- if (r == null)
- return;
-
- for (int i = 0; i < r.length; i++) {
- if (r[i] == null)
- continue;
- if (!(r[i] instanceof FetchResponse)) {
- v.addElement(r[i]); // Unsolicited Non-FETCH response
- continue;
- }
+ // if we asked for all headers, assume we got them
+ if (allHeaders)
+ setHeadersLoaded(true);
+ else {
+ // Mark all headers we asked for as 'loaded'
+ for (int k = 0; k < hdrs.length; k++)
+ setHeaderLoaded(hdrs[k]);
+ }
+ } else
+ return false; // not handled
+ return true; // something above handled it
+ }
 
- // Got a FetchResponse.
- FetchResponse f = (FetchResponse)r[i];
- // Get the corresponding message.
- IMAPMessage msg = folder.getMessageBySeqNumber(f.getNumber());
+ /**
+ * Fetch an individual item for the current message.
+ */
+ protected Item fetchItem(String itemName, Class itemClass)
+ throws MessagingException {
 
- int count = f.getItemCount();
- boolean unsolicitedFlags = false;
+ // Acquire MessageCacheLock, to freeze seqnum.
+ synchronized(getMessageCacheLock()) {
+ Item ritem = null;
 
- for (int j = 0; j < count; j++) {
- Item item = f.getItem(j);
+ try {
+ IMAPProtocol p = getProtocol();
 
- // Check for the FLAGS item
- if (item instanceof Flags) {
- if (!fp.contains(FetchProfile.Item.FLAGS) ||
- msg == null)
- // Ok, Unsolicited FLAGS update.
- unsolicitedFlags = true;
- else
- msg.flags = (Flags)item;
- }
+ checkExpunged(); // Insure that this message is not expunged
 
- // Check for ENVELOPE items
- else if (item instanceof ENVELOPE)
- msg.envelope = (ENVELOPE)item;
- else if (item instanceof INTERNALDATE)
- msg.receivedDate = ((INTERNALDATE)item).getDate();
- else if (item instanceof RFC822SIZE)
- msg.size = ((RFC822SIZE)item).size;
+ int seqnum = getSequenceNumber();
+ Response[] r = p.fetch(seqnum, itemName);
 
- // Check for the BODYSTRUCTURE item
- else if (item instanceof BODYSTRUCTURE)
- msg.bs = (BODYSTRUCTURE)item;
- // Check for the UID item
- else if (item instanceof UID) {
- UID u = (UID)item;
- msg.uid = u.uid; // set uid
- // add entry into uid table
- if (folder.uidTable == null)
- folder.uidTable = new Hashtable();
- folder.uidTable.put(new Long(u.uid), msg);
- }
+ for (int i = 0; i < r.length; i++) {
+ // If this response is NOT a FetchResponse or if it does
+ // not match our seqnum, skip.
+ if (r[i] == null ||
+ !(r[i] instanceof FetchResponse) ||
+ ((FetchResponse)r[i]).getNumber() != seqnum)
+ continue;
 
- // Check for header items
- else if (item instanceof RFC822DATA ||
- item instanceof BODY) {
- InputStream headerStream;
- if (item instanceof RFC822DATA) // IMAP4
- headerStream =
- ((RFC822DATA)item).getByteArrayInputStream();
- else // IMAP4rev1
- headerStream =
- ((BODY)item).getByteArrayInputStream();
+ FetchResponse f = (FetchResponse)r[i];
+
+ // Look for the Envelope items.
+ int count = f.getItemCount();
+ for (int j = 0; j < count; j++) {
+ Item item = f.getItem(j);
                         
- // Load the obtained headers.
- InternetHeaders h = new InternetHeaders();
- // Some IMAP servers (e.g., gmx.net) return NIL
- // instead of a string just containing a CR/LF
- // when the header list is empty.
- if (headerStream != null)
- h.load(headerStream);
- if (msg.headers == null || allHeaders)
- msg.headers = h;
- else {
- /*
- * This is really painful. A second fetch
- * of the same headers (which might occur because
- * a new header was added to the set requested)
- * will return headers we already know about.
- * In this case, only load the headers we haven't
- * seen before to avoid adding duplicates of
- * headers we already have.
- *
- * XXX - There's a race condition here if another
- * thread is reading headers in the same message
- * object, because InternetHeaders is not thread
- * safe.
- */
- Enumeration e = h.getAllHeaders();
- while (e.hasMoreElements()) {
- Header he = (Header)e.nextElement();
- if (!msg.isHeaderLoaded(he.getName()))
- msg.headers.addHeader(
- he.getName(), he.getValue());
- }
- }
-
- // if we asked for all headers, assume we got them
- if (allHeaders)
- msg.setHeadersLoaded(true);
- else {
- // Mark all headers we asked for as 'loaded'
- for (int k = 0; k < hdrs.length; k++)
- msg.setHeaderLoaded(hdrs[k]);
- }
+ if (itemClass.isInstance(item))
+ ritem = item;
                     }
                 }
 
- // If this response contains any unsolicited FLAGS
- // add it to the unsolicited response vector
- if (unsolicitedFlags)
- v.addElement(f);
+ // ((IMAPFolder)folder).handleResponses(r);
+ p.notifyResponseHandlers(r);
+ p.handleResult(r[r.length - 1]);
+ } catch (ConnectionException cex) {
+ throw new FolderClosedException(folder, cex.getMessage());
+ } catch (ProtocolException pex) {
+ forceCheckExpunged();
+ throw new MessagingException(pex.getMessage(), pex);
             }
+ return ritem;
 
- // Dispatch any unsolicited responses
- int size = v.size();
- if (size != 0) {
- Response[] responses = new Response[size];
- v.copyInto(responses);
- folder.handleResponses(responses);
- }
-
- } // Release messageCacheLock
+ } // Release MessageCacheLock
     }
 
     /*
@@ -1271,28 +1218,6 @@
             throw new MessagingException("Failed to load IMAP envelope");
     }
 
- private static String craftHeaderCmd(IMAPProtocol p, String[] hdrs) {
- StringBuffer sb;
-
- if (p.isREV1())
- sb = new StringBuffer("BODY.PEEK[HEADER.FIELDS (");
- else
- sb = new StringBuffer("RFC822.HEADER.LINES (");
-
- for (int i = 0; i < hdrs.length; i++) {
- if (i > 0)
- sb.append(" ");
- sb.append(hdrs[i]);
- }
-
- if (p.isREV1())
- sb.append(")]");
- else
- sb.append(")");
-
- return sb.toString();
- }
-
     /*
      * Load the BODYSTRUCTURE
      */

diff -r c52880c12a3f -r c5dfaf269e6c mail/src/main/java/com/sun/mail/imap/IMAPStore.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Tue Jul 31 13:50:38 2012 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPStore.java Mon Aug 06 15:08:23 2012 -0700
@@ -156,9 +156,9 @@
      */
     public static final int RESPONSE = 1000;
 
- private final String name; // name of this protocol
- private final int defaultPort; // default IMAP port
- private final boolean isSSL; // use SSL?
+ protected final String name; // name of this protocol
+ protected final int defaultPort; // default IMAP port
+ protected final boolean isSSL; // use SSL?
 
     private final int blksize; // Block size for data requested
                                         // in FETCH requests. Defaults to
@@ -175,12 +175,12 @@
     private volatile int port = -1; // port to use
 
     // Auth info
- private String host;
- private String user;
- private String password;
- private String proxyAuthUser;
- private String authorizationID;
- private String saslRealm;
+ protected String host;
+ protected String user;
+ protected String password;
+ protected String proxyAuthUser;
+ protected String authorizationID;
+ protected String saslRealm;
 
     private Namespaces namespaces;
 
@@ -211,7 +211,7 @@
 
     private boolean debugusername; // include username in debug output?
     private boolean debugpassword; // include password in debug output?
- private PrintStream out; // debug output stream
+ protected PrintStream out; // debug output stream
 
     private boolean messageCacheDebug;
 
@@ -642,12 +642,7 @@
                 if (debug)
                     out.println("DEBUG: trying to connect to host \"" + host +
                                 "\", port " + port + ", isSSL " + isSSL);
- protocol = new IMAPProtocol(name, host, port,
- session.getDebug(),
- session.getDebugOut(),
- session.getProperties(),
- isSSL
- );
+ protocol = newIMAPProtocol(host, port);
                 if (debug)
                     out.println("DEBUG: protocolConnect login" +
                                 ", host=" + host +
@@ -685,6 +680,16 @@
         return true;
     }
 
+ protected IMAPProtocol newIMAPProtocol(String host, int port)
+ throws IOException, ProtocolException {
+ return new IMAPProtocol(name, host, port,
+ session.getDebug(),
+ session.getDebugOut(),
+ session.getProperties(),
+ isSSL
+ );
+ }
+
     private void login(IMAPProtocol p, String u, String pw)
                 throws ProtocolException {
         // turn on TLS if it's been enabled or required and is supported
@@ -841,12 +846,7 @@
                     if (forcePasswordRefresh)
                         refreshPassword();
                     // Use cached host, port and timeout values.
- p = new IMAPProtocol(name, host, port,
- session.getDebug(),
- session.getDebugOut(),
- session.getProperties(),
- isSSL
- );
+ p = newIMAPProtocol(host, port);
                     // Use cached auth info
                     login(p, user, password);
                 } catch(Exception ex1) {
@@ -949,12 +949,7 @@
                     if (forcePasswordRefresh)
                         refreshPassword();
                     // Use cached host, port and timeout values.
- p = new IMAPProtocol(name, host, port,
- session.getDebug(),
- session.getDebugOut(),
- session.getProperties(),
- isSSL
- );
+ p = newIMAPProtocol(host, port);
                     // Use cached auth info
                     login(p, user, password);
                 } catch(Exception ex1) {

diff -r c52880c12a3f -r c5dfaf269e6c mail/src/main/java/com/sun/mail/imap/MessageCache.java
--- a/mail/src/main/java/com/sun/mail/imap/MessageCache.java Tue Jul 31 13:50:38 2012 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/MessageCache.java Mon Aug 06 15:08:23 2012 -0700
@@ -135,7 +135,7 @@
         if (msg == null) {
             if (debug)
                 out.println("DEBUG IMAP MC: create message number " + msgnum);
- msg = new IMAPMessage(folder, msgnum);
+ msg = folder.newIMAPMessage(msgnum);
             messages[msgnum-1] = msg;
             // mark message expunged if no seqnum
             if (seqnumOf(msgnum) <= 0) {

diff -r c52880c12a3f -r c5dfaf269e6c mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java Tue Jul 31 13:50:38 2012 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/FetchResponse.java Mon Aug 06 15:08:23 2012 -0700
@@ -50,6 +50,7 @@
  * of an IMAP server.
  *
  * @author John Mani
+ * @author Bill Shannon
  */
 
 public class FetchResponse extends IMAPResponse {
@@ -108,7 +109,6 @@
     private final static char[] HEADER = {'.','H','E','A','D','E','R'};
     private final static char[] TEXT = {'.','T','E','X','T'};
 
-
     private void parse() throws ParsingException {
         skipSpaces();
         if (buffer[index] != '(')
@@ -124,67 +124,11 @@
                 throw new ParsingException(
                 "error in FETCH parsing, ran off end of buffer, size " + size);
 
- switch(buffer[index]) {
- case 'E': case 'e':
- if (match(ENVELOPE.name)) {
- index += ENVELOPE.name.length; // skip "ENVELOPE"
- i = new ENVELOPE(this);
- }
- break;
- case 'F': case 'f':
- if (match(FLAGS.name)) {
- index += FLAGS.name.length; // skip "FLAGS"
- i = new FLAGS((IMAPResponse)this);
- }
- break;
- case 'I': case 'i':
- if (match(INTERNALDATE.name)) {
- index += INTERNALDATE.name.length; // skip "INTERNALDATE"
- i = new INTERNALDATE(this);
- }
- break;
- case 'B': case 'b':
- if (match(BODY.name)) {
- if (buffer[index+4] == '[') {
- index += BODY.name.length; // skip "BODY"
- i = new BODY(this);
- }
- else {
- if (match(BODYSTRUCTURE.name))
- index += BODYSTRUCTURE.name.length;
- // skip "BODYSTRUCTURE"
- else
- index += BODY.name.length; // skip "BODY"
- i = new BODYSTRUCTURE(this);
- }
- }
- break;
- case 'R': case 'r':
- if (match(RFC822SIZE.name)) {
- index += RFC822SIZE.name.length; // skip "RFC822.SIZE"
- i = new RFC822SIZE(this);
- }
- else {
- if (match(RFC822DATA.name)) {
- index += RFC822DATA.name.length;
- if (match(HEADER))
- index += HEADER.length; // skip ".HEADER"
- else if (match(TEXT))
- index += TEXT.length; // skip ".TEXT"
- i = new RFC822DATA(this);
- }
- }
- break;
- case 'U': case 'u':
- if (match(UID.name)) {
- index += UID.name.length;
- i = new UID(this);
- }
- break;
- default:
- }
- if (i != null)
- v.addElement(i);
+ i = parseItem();
+ if (i == null)
+ throw new ParsingException(
+ "error in FETCH parsing, unrecognized item at index " + index);
+ v.addElement(i);
         } while (buffer[index] != ')');
 
         index++; // skip ')'
@@ -192,17 +136,71 @@
         v.copyInto(items);
     }
 
- /*
+ /**
+ * Parse the item at the current position in the buffer,
+ * skipping over the item if successful. Otherwise, return null
+ * and leave the buffer position unmodified.
+ */
+ protected Item parseItem() throws ParsingException {
+ switch (buffer[index]) {
+ case 'E': case 'e':
+ if (match(ENVELOPE.name))
+ return new ENVELOPE(this);
+ break;
+ case 'F': case 'f':
+ if (match(FLAGS.name))
+ return new FLAGS((IMAPResponse)this);
+ break;
+ case 'I': case 'i':
+ if (match(INTERNALDATE.name))
+ return new INTERNALDATE(this);
+ break;
+ case 'B': case 'b':
+ if (match(BOD
[truncated due to length]