commits@javamail.java.net

[javamail~mercurial:579] Add support for write timeouts - bug 5933.

From: <shannon_at_java.net>
Date: Mon, 24 Jun 2013 20:31:10 +0000

Project: javamail
Repository: mercurial
Revision: 579
Author: shannon
Date: 2013-06-22 00:14:03 UTC
Link:

Log Message:
------------
Refer to RFC 2822 instead of its early draft. The actual syntax hasn't changed.
Remove references to obsolete versions of J2SE and JDK.
Replace "Sun" references with "Oracle".
Update JavaMail email address.
Replace "Sun" with "Oracle".
Remove remaining references to "Sun".
Fix potential NPE in MimeUtility.quote() - bug 5978
Add support for the RFC 2359 COPYUID response code - bug 5987.
LogManagerProperties handle JDK8 reverseOrder renamed to reversed.
LogManagerProperties ignore SecurityException in reverseOrder.
MailHandlerTest handle SocketConnectException.

(From Jason)
Add support for write timeouts - bug 5933.


Revisions:
----------
570
571
572
573
574
575
576
577
578
579


Modified Paths:
---------------
mail/src/main/java/javax/mail/internet/MailDateFormat.java
mail/src/main/java/com/sun/mail/util/SocketFetcher.java
mail/src/main/java/javax/mail/Session.java
mail/src/main/java/javax/mail/internet/package.html
mail/src/main/java/javax/mail/search/SearchTerm.java
servlet/src/main/java/JavaMail.html
demo/src/main/java/registry.java
javadoc/pom.xml
mail/src/main/java/javax/mail/package.html
mail/src/main/java/overview.html
doc/release/CHANGES.txt
mail/src/main/java/javax/mail/internet/MimeUtility.java
mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java
mail/src/test/java/com/sun/mail/util/logging/LogManagerPropertiesTest.java
mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
mail/src/main/java/com/sun/mail/imap/package.html
mail/src/main/java/com/sun/mail/pop3/package.html
mail/src/main/java/com/sun/mail/smtp/package.html
mail/src/test/java/com/sun/mail/smtp/SMTPHandler.java


Added Paths:
------------
mail/src/main/java/com/sun/mail/imap/CopyUID.java
mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java
mail/src/test/java/com/sun/mail/smtp/SMTPWriteTimeoutTest.java


Diffs:
------
diff -r e393f183a3e2 -r 1440f000276d mail/src/main/java/javax/mail/internet/MailDateFormat.java
--- a/mail/src/main/java/javax/mail/internet/MailDateFormat.java Tue May 14 14:07:13 2013 -0700
+++ b/mail/src/main/java/javax/mail/internet/MailDateFormat.java Fri May 17 14:51:25 2013 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -56,84 +56,84 @@
 import com.sun.mail.util.MailLogger;
 
 /**
- * Formats and parses date specification based on the
- * draft-ietf-drums-msg-fmt-08 dated January 26, 2000. This is a followup
- * spec to RFC822.<p>
+ * Formats and parses date specification based on
+ * <a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>. <p>
  *
  * This class does not take pattern strings. It always formats the
  * date based on the specification below.<p>
  *
- * 3.3 Date and Time Specification<p>
+ * 3.3. Date and Time Specification
+ * <p>
+ * Date and time occur in several header fields. This section specifies
+ * the syntax for a full date and time specification. Though folding
+ * white space is permitted throughout the date-time specification, it is
+ * RECOMMENDED that a single space be used in each place that FWS appears
+ * (whether it is required or optional); some older implementations may
+ * not interpret other occurrences of folding white space correctly.
+ * <pre>
+ * date-time = [ day-of-week "," ] date FWS time [CFWS]
  *
- * Date and time occur in several header fields of a message. This section
- * specifies the syntax for a full date and time specification. Though folding
- * whitespace is permitted throughout the date-time specification, it is
- * recommended that only a single space be used where FWS is required and no
- * space be used where FWS is optional in the date-time specification; some
- * older implementations may not interpret other occurrences of folding
- * whitespace correctly.<p>
+ * day-of-week = ([FWS] day-name) / obs-day-of-week
  *
- * date-time = [ day-of-week "," ] date FWS time [CFWS]<p>
+ * day-name = "Mon" / "Tue" / "Wed" / "Thu" /
+ * "Fri" / "Sat" / "Sun"
  *
- * day-of-week = ([FWS] day-name) / obs-day-of-week<p>
+ * date = day month year
  *
- * day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"<p>
+ * year = 4*DIGIT / obs-year
  *
- * date = day month year<p>
+ * month = (FWS month-name FWS) / obs-month
  *
- * year = 4*DIGIT / obs-year<p>
+ * month-name = "Jan" / "Feb" / "Mar" / "Apr" /
+ * "May" / "Jun" / "Jul" / "Aug" /
+ * "Sep" / "Oct" / "Nov" / "Dec"
  *
- * month = (FWS month-name FWS) / obs-month<p>
+ * day = ([FWS] 1*2DIGIT) / obs-day
  *
- *<pre>month-name = "Jan" / "Feb" / "Mar" / "Apr" /
- * "May" / "Jun" / "Jul" / "Aug" /
- * "Sep" / "Oct" / "Nov" / "Dec"
- * </pre><p>
- * day = ([FWS] 1*2DIGIT) / obs-day<p>
+ * time = time-of-day FWS zone
  *
- * time = time-of-day FWS zone<p>
+ * time-of-day = hour ":" minute [ ":" second ]
  *
- * time-of-day = hour ":" minute [ ":" second ]<p>
+ * hour = 2DIGIT / obs-hour
  *
- * hour = 2DIGIT / obs-hour<p>
+ * minute = 2DIGIT / obs-minute
  *
- * minute = 2DIGIT / obs-minute<p>
+ * second = 2DIGIT / obs-second
  *
- * second = 2DIGIT / obs-second<p>
- *
- * zone = (( "+" / "-" ) 4DIGIT) / obs-zone<p>
- *
- *
- * The day is the numeric day of the month. The year is any numeric year in
- * the common era.<p>
- *
+ * zone = (( "+" / "-" ) 4DIGIT) / obs-zone
+ * </pre>
+ * The day is the numeric day of the month. The year is any numeric year
+ * 1900 or later.
+ * <p>
  * The time-of-day specifies the number of hours, minutes, and optionally
- * seconds since midnight of the date indicated.<p>
- *
- * The date and time-of-day SHOULD express local time.<p>
- *
+ * seconds since midnight of the date indicated.
+ * <p>
+ * The date and time-of-day SHOULD express local time.
+ * <p>
  * The zone specifies the offset from Coordinated Universal Time (UTC,
  * formerly referred to as "Greenwich Mean Time") that the date and
- * time-of-day represent. The "+" or "-" indicates whether the time-of-day is
- * ahead of or behind Universal Time. The first two digits indicate the number
- * of hours difference from Universal Time, and the last two digits indicate
- * the number of minutes difference from Universal Time. (Hence, +hhmm means
- * +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm) minutes). The form
- * "+0000" SHOULD be used to indicate a time zone at Universal Time. Though
- * "-0000" also indicates Universal Time, it is used to indicate that the time
- * was generated on a system that may be in a local time zone other than
- * Universal Time.<p>
+ * time-of-day represent. The "+" or "-" indicates whether the
+ * time-of-day is ahead of (i.e., east of) or behind (i.e., west of)
+ * Universal Time. The first two digits indicate the number of hours
+ * difference from Universal Time, and the last two digits indicate the
+ * number of minutes difference from Universal Time. (Hence, +hhmm means
+ * +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm) minutes). The
+ * form "+0000" SHOULD be used to indicate a time zone at Universal Time.
+ * Though "-0000" also indicates Universal Time, it is used to indicate
+ * that the time was generated on a system that may be in a local time
+ * zone other than Universal Time and therefore indicates that the
+ * date-time contains no information about the local time zone.
+ * <p>
+ * A date-time specification MUST be semantically valid. That is, the
+ * day-of-the-week (if included) MUST be the day implied by the date, the
+ * numeric day-of-month MUST be between 1 and the number of days allowed
+ * for the specified month (in the specified year), the time-of-day MUST
+ * be in the range 00:00:00 through 23:59:60 (the number of seconds
+ * allowing for a leap second; see [STD12]), and the zone MUST be within
+ * the range -9959 through +9959.
  *
- * A date-time specification MUST be semantically valid. That is, the
- * day-of-the week (if included) MUST be the day implied by the date, the
- * numeric day-of-month MUST be between 1 and the number of days allowed for
- * the specified month (in the specified year), the time-of-day MUST be in the
- * range 00:00:00 through 23:59:60 (the number of seconds allowing for a leap
- * second; see [STD-12]), and the zone MUST be within the range -9959 through
- * +9959.<p>
- *
- * @author Max Spivak
- * @since JavaMail 1.2
+ * @author Max Spivak
+ * @since JavaMail 1.2
  */
 
 public class MailDateFormat extends SimpleDateFormat {


diff -r 1440f000276d -r caaf1dc2767a mail/src/main/java/com/sun/mail/util/SocketFetcher.java
--- a/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri May 17 14:51:25 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri May 17 15:01:49 2013 -0700
@@ -284,7 +284,12 @@
                                 new java.net.Proxy(java.net.Proxy.Type.SOCKS,
                                 new InetSocketAddress(socksHost, socksPort)));
             else
+ { String s = System.getenv("WRITE_TIMEOUT");
+ if (s != null)
+ socket = new WriteTimeoutSocket(Integer.parseInt(s));
+ else
                 socket = new Socket();
+ }
         }
         if (to >= 0)
             socket.setSoTimeout(to);

diff -r 1440f000276d -r caaf1dc2767a mail/src/main/java/javax/mail/Session.java
--- a/mail/src/main/java/javax/mail/Session.java Fri May 17 14:51:25 2013 -0700
+++ b/mail/src/main/java/javax/mail/Session.java Fri May 17 15:01:49 2013 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -91,13 +91,7 @@
  * File location depends upon how the <code>ClassLoader</code> method
  * <code>getResource</code> is implemented. Usually, the
  * <code>getResource</code> method searches through CLASSPATH until it
- * finds the requested file and then stops. JDK 1.1 has a limitation that
- * the number of files of each name that will be found in the CLASSPATH is
- * limited to one. However, this only affects method two, above; method
- * one is loaded from a specific location (if allowed by the
- * SecurityManager) and method three uses a different name to ensure that
- * the default resource file is always loaded successfully. J2SE 1.2 and
- * later are not limited to one file of a given name. <p>
+ * finds the requested file and then stops. <p>
  *
  * The ordering of entries in the resource files matters. If multiple
  * entries exist, the first entries take precedence over the later
@@ -292,7 +286,7 @@
      * <code>getInstance</code> method to get a new Session object every
      * time the method is called. <p>
      *
- * In JDK 1.2, additional security Permission objects may be used to
+ * Additional security Permission objects may be used to
      * control access to the default session.
      *
      * @param props Properties object. Used only if a new Session

diff -r 1440f000276d -r caaf1dc2767a mail/src/main/java/javax/mail/internet/package.html
--- a/mail/src/main/java/javax/mail/internet/package.html Fri May 17 14:51:25 2013 -0700
+++ b/mail/src/main/java/javax/mail/internet/package.html Fri May 17 15:01:49 2013 -0700
@@ -58,7 +58,7 @@
 The JavaMail API specification requires support for the following properties,
 which must be set in the <code>System</code> properties.
 The properties are always set as strings; the Type column describes
-how the string is interpreted. For example, use (in J2SE 1.2 and newer)
+how the string is interpreted. For example, use
 <PRE>
         System.setProperty("mail.mime.address.strict", "false");
 </PRE>

diff -r 1440f000276d -r caaf1dc2767a mail/src/main/java/javax/mail/search/SearchTerm.java
--- a/mail/src/main/java/javax/mail/search/SearchTerm.java Fri May 17 14:51:25 2013 -0700
+++ b/mail/src/main/java/javax/mail/search/SearchTerm.java Fri May 17 15:01:49 2013 -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-2013 Oracle and/or its affiliates. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -59,15 +59,6 @@
  * JavaMail API releases. The current serialization support is
  * appropriate for short term storage. <p>
  *
- * <strong>Warning:</strong>
- * Search terms that include references to objects of type
- * <code>Message.RecipientType</code> will not be deserialized
- * correctly on JDK 1.1 systems. While these objects will be deserialized
- * without throwing any exceptions, the resulting objects violate the
- * <i>type-safe enum</i> contract of the <code>Message.RecipientType</code>
- * class. Proper deserialization of these objects depends on support
- * for the <code>readReplace</code> method, added in JDK 1.2.
- *
  * @author Bill Shannon
  * @author John Mani
  */


diff -r caaf1dc2767a -r ace4c9c3f13d mail/src/main/java/javax/mail/Session.java
--- a/mail/src/main/java/javax/mail/Session.java Fri May 17 15:01:49 2013 -0700
+++ b/mail/src/main/java/javax/mail/Session.java Fri May 17 15:04:12 2013 -0700
@@ -146,8 +146,8 @@
  * Here's an example of <code>META-INF/javamail.default.providers</code>
  * file contents:
  * <pre>
- * protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Sun Microsystems, Inc.;
- * protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Sun Microsystems, Inc.;
+ * protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle;
+ * protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle;
  * </pre><p>
  *
  * <b><code>javamail.address.map</code></b> and
@@ -910,22 +910,22 @@
             // failed to load any providers, initialize with our defaults
             addProvider(new Provider(Provider.Type.STORE,
                         "imap", "com.sun.mail.imap.IMAPStore",
- "Sun Microsystems, Inc.", Version.version));
+ "Oracle", Version.version));
             addProvider(new Provider(Provider.Type.STORE,
                         "imaps", "com.sun.mail.imap.IMAPSSLStore",
- "Sun Microsystems, Inc.", Version.version));
+ "Oracle", Version.version));
             addProvider(new Provider(Provider.Type.STORE,
                         "pop3", "com.sun.mail.pop3.POP3Store",
- "Sun Microsystems, Inc.", Version.version));
+ "Oracle", Version.version));
             addProvider(new Provider(Provider.Type.STORE,
                         "pop3s", "com.sun.mail.pop3.POP3SSLStore",
- "Sun Microsystems, Inc.", Version.version));
+ "Oracle", Version.version));
             addProvider(new Provider(Provider.Type.TRANSPORT,
                         "smtp", "com.sun.mail.smtp.SMTPTransport",
- "Sun Microsystems, Inc.", Version.version));
+ "Oracle", Version.version));
             addProvider(new Provider(Provider.Type.TRANSPORT,
                         "smtps", "com.sun.mail.smtp.SMTPSSLTransport",
- "Sun Microsystems, Inc.", Version.version));
+ "Oracle", Version.version));
         }
 
         if (logger.isLoggable(Level.CONFIG)) {


diff -r ace4c9c3f13d -r 9b7f47800399 servlet/src/main/java/JavaMail.html
--- a/servlet/src/main/java/JavaMail.html Fri May 17 15:04:12 2013 -0700
+++ b/servlet/src/main/java/JavaMail.html Fri May 17 15:14:45 2013 -0700
@@ -2,7 +2,7 @@
 <HTML>
 <!--
 
- Copyright (c) 1998-2010 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1998-2013 Oracle and/or its affiliates. All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions
@@ -128,8 +128,8 @@
 </P>
 
 <P><FONT FACE="Arial, Helvetica">Feedback to </FONT>
-<A HREF="mailto:javamail_at_Sun.COM">
-<FONT FACE="Arial, Helvetica">javamail_at_Sun.COM</FONT></A>
+<A HREF="mailto:javamail_ww_at_oracle.com">
+<FONT FACE="Arial, Helvetica">javamail_ww_at_oracle.com</FONT></A>
 </FORM>
 
 </BODY>


diff -r 9b7f47800399 -r 8ca6d89c6fe9 demo/src/main/java/registry.java
--- a/demo/src/main/java/registry.java Fri May 17 15:14:45 2013 -0700
+++ b/demo/src/main/java/registry.java Fri May 17 15:19:07 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,7 +37,7 @@
 /**
  * This class demonstrates how to query the registry for available
  * Providers, set default providers, etc. See section 5.2 in the
- * JavaMail 1.0 Spec for details on how to use the registry.
+ * JavaMail Spec for details on how to use the registry.
  *
  * See the comments inline for what's happening.
  *
@@ -89,11 +89,11 @@
                 _sunIMAP = providers[i];
             }
 
- // this Provider will be found as well since there is a
- // Sun Microsystems SMTP transport configured by
+ // this Provider will be found as well since there is an
+ // Oracle SMTP transport configured by
             // default in javamail.default.providers
             if (((s = providers[i].getVendor()) != null) &&
- s.startsWith("Sun Microsystems") &&
+ s.startsWith("Oracle") &&
                 providers[i].getType() == Provider.Type.TRANSPORT &&
                 providers[i].getProtocol().equalsIgnoreCase("smtp")) {
                 _sunSMTP = providers[i];


diff -r 8ca6d89c6fe9 -r 7c86c4e543ab javadoc/pom.xml
--- a/javadoc/pom.xml Fri May 17 15:19:07 2013 -0700
+++ b/javadoc/pom.xml Fri May 17 15:19:25 2013 -0700
@@ -181,7 +181,7 @@
                                     <packages>javax.*</packages>
                                 </group>
                                 <group>
- <title>Sun-specific Packages</title>
+ <title>RI-specific Packages</title>
                                     <packages>com.sun.*</packages>
                                 </group>
                             </groups>

diff -r 8ca6d89c6fe9 -r 7c86c4e543ab mail/src/main/java/javax/mail/internet/package.html
--- a/mail/src/main/java/javax/mail/internet/package.html Fri May 17 15:19:07 2013 -0700
+++ b/mail/src/main/java/javax/mail/internet/package.html Fri May 17 15:19:25 2013 -0700
@@ -250,7 +250,7 @@
 
 
 <P>
-The following properties are supported by Sun's implementation of
+The following properties are supported by the reference implementation (RI) of
 JavaMail, but are not currently a required part of the specification.
 As above, these must be set as <CODE>System</CODE> properties.
 The names, types, defaults, and semantics of these properties may

diff -r 8ca6d89c6fe9 -r 7c86c4e543ab mail/src/main/java/javax/mail/package.html
--- a/mail/src/main/java/javax/mail/package.html Fri May 17 15:19:07 2013 -0700
+++ b/mail/src/main/java/javax/mail/package.html Fri May 17 15:19:25 2013 -0700
@@ -219,7 +219,7 @@
 </TABLE>
 
 <P>
-The following properties are supported by Sun's implementation of
+The following properties are supported by the reference implementation (RI) of
 JavaMail, but are not currently a required part of the specification.
 The names, types, defaults, and semantics of these properties may
 change in future releases.
@@ -267,18 +267,18 @@
 
 <P>
 The JavaMail reference
-implementation from Sun includes protocol providers in subpackages of
+implementation includes protocol providers in subpackages of
 <code>com.sun.mail</code>. Note that the APIs to these protocol
 providers are not part of the standard JavaMail API. Portable
 programs will not use these APIs.
 <P>
-Nonportable programs may use the APIs of the Sun protocol providers
+Nonportable programs may use the APIs of the protocol providers
 by (for example) casting a returned <code>Folder</code> object to a
 <code>com.sun.mail.imap.IMAPFolder</code> object. Similarly for
 <code>Store</code> and <code>Message</code> objects returned from the
 standard JavaMail APIs.
 <P>
-The Sun protocol providers also support properties that are specific to
+The protocol providers also support properties that are specific to
 those providers. The package documentation for the
 {_at_link com.sun.mail.imap IMAP}, {_at_link com.sun.mail.pop3 POP3},
 and {_at_link com.sun.mail.smtp SMTP} packages provide details.

diff -r 8ca6d89c6fe9 -r 7c86c4e543ab mail/src/main/java/overview.html
--- a/mail/src/main/java/overview.html Fri May 17 15:19:07 2013 -0700
+++ b/mail/src/main/java/overview.html Fri May 17 15:19:25 2013 -0700
@@ -219,7 +219,7 @@
 </TABLE>
 
 <P>
-The following properties are supported by Sun's implementation of
+The following properties are supported by the reference implementation (RI) of
 JavaMail, but are not currently a required part of the specification.
 The names, types, defaults, and semantics of these properties may
 change in future releases.
@@ -267,18 +267,18 @@
 
 <P>
 The JavaMail reference
-implementation from Sun includes protocol providers in subpackages of
+implementation includes protocol providers in subpackages of
 <code>com.sun.mail</code>. Note that the APIs to these protocol
 providers are not part of the standard JavaMail API. Portable
 programs will not use these APIs.
 <P>
-Nonportable programs may use the APIs of the Sun protocol providers
+Nonportable programs may use the APIs of the protocol providers
 by (for example) casting a returned <code>Folder</code> object to a
 <code>com.sun.mail.imap.IMAPFolder</code> object. Similarly for
 <code>Store</code> and <code>Message</code> objects returned from the
 standard JavaMail APIs.
 <P>
-The Sun protocol providers also support properties that are specific to
+The protocol providers also support properties that are specific to
 those providers. The package documentation for the
 {_at_link com.sun.mail.imap IMAP}, {_at_link com.sun.mail.pop3 POP3},
 and {_at_link com.sun.mail.smtp SMTP} packages provide details.


diff -r 7c86c4e543ab -r da36b3d12a39 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri May 17 15:19:25 2013 -0700
+++ b/doc/release/CHANGES.txt Thu Jun 13 11:12:19 2013 -0700
@@ -21,6 +21,7 @@
 K 5924 IMAP provider should support the QRESYNC extension (RFC 5162)
 K 5925 IMAP provider should support the WITHIN search extension (RFC 5032)
 K 5934 method fill() isn't synchronized correctly in SharedFileInputStream
+K 5978 NullPointerException in MimeUtility#quote()
 
 
                   CHANGES IN THE 1.5.0 RELEASE

diff -r 7c86c4e543ab -r da36b3d12a39 mail/src/main/java/javax/mail/internet/MimeUtility.java
--- a/mail/src/main/java/javax/mail/internet/MimeUtility.java Fri May 17 15:19:25 2013 -0700
+++ b/mail/src/main/java/javax/mail/internet/MimeUtility.java Thu Jun 13 11:12:19 2013 -0700
@@ -981,7 +981,7 @@
      * @see javax.mail.internet.HeaderTokenizer#RFC822
      */
     public static String quote(String word, String specials) {
- int len = word.length();
+ int len = word == null ? 0 : word.length();
         if (len == 0)
             return "\"\""; // an empty string is handled specially
 


diff -r da36b3d12a39 -r 23bb64d8b374 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Thu Jun 13 11:12:19 2013 -0700
+++ b/doc/release/CHANGES.txt Fri Jun 21 15:23:01 2013 -0700
@@ -22,6 +22,7 @@
 K 5925 IMAP provider should support the WITHIN search extension (RFC 5032)
 K 5934 method fill() isn't synchronized correctly in SharedFileInputStream
 K 5978 NullPointerException in MimeUtility#quote()
+K 5987 support RFC 2359 COPYUID response code
 
 
                   CHANGES IN THE 1.5.0 RELEASE

diff -r da36b3d12a39 -r 23bb64d8b374 mail/src/main/java/com/sun/mail/imap/CopyUID.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/main/java/com/sun/mail/imap/CopyUID.java Fri Jun 21 15:23:01 2013 -0700
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.mail.imap;
+
+import com.sun.mail.imap.protocol.UIDSet;
+
+/**
+ * Information from the COPYUID response code
+ * defined by the UIDPLUS extension -
+ * <A HREF="http://www.ietf.org/rfc/rfc2359.txt">RFC 2359</A>.
+ *
+ * @author Bill Shannon
+ */
+
+public class CopyUID {
+ public long uidvalidity = -1;
+ public UIDSet[] src;
+ public UIDSet[] dst;
+
+ public CopyUID(long uidvalidity, UIDSet[] src, UIDSet[] dst) {
+ this.uidvalidity = uidvalidity;
+ this.src = src;
+ this.dst = dst;
+ }
+}

diff -r da36b3d12a39 -r 23bb64d8b374 mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Thu Jun 13 11:12:19 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Fri Jun 21 15:23:01 2013 -0700
@@ -1850,6 +1850,118 @@
     }
 
     /**
+ * Copy the specified messages from this folder, to the
+ * specified destination.
+ * Return array of AppendUID objects containing
+ * UIDs of these messages in the destination folder.
+ * Each element of the returned array corresponds to
+ * an element of the <code>msgs</code> array. A null
+ * element means the server didn't return UID information
+ * for the copied message. <p>
+ *
+ * Depends on the COPYUID response code defined by the
+ * UIDPLUS extension -
+ * <A HREF="http://www.ietf.org/rfc/rfc2359.txt">RFC 2359</A>.
+ *
+ * @since JavaMail 1.5.1
+ */
+ public synchronized AppendUID[] copyUIDMessages(Message[] msgs,
+ Folder folder) throws MessagingException {
+ checkOpened();
+
+ if (msgs.length == 0) // boundary condition
+ return null;
+
+ // the destination must belong to our same store
+ if (folder.getStore() == store) {
+ synchronized (messageCacheLock) {
+ try {
+ IMAPProtocol p = getProtocol();
+ // XXX - messages have to be from this Folder, who checks?
+ MessageSet[] ms = Utility.toMessageSet(msgs, null);
+ if (ms == null)
+ throw new MessageRemovedException(
+ "Messages have been removed");
+ CopyUID cuid = p.copyuid(ms, folder.getFullName());
+
+ /*
+ * Correlate source UIDs with destination UIDs.
+ * This won't be time or space efficient if there's
+ * a lot of messages.
+ *
+ * In order to make sense of the returned UIDs, we need
+ * the UIDs for every one of the original messages.
+ * If we already have them, great, otherwise we need
+ * to fetch them from the server.
+ *
+ * Assume the common case is that the messages are
+ * in in order by UID. Map the returned source
+ * UIDs to their corresponding Message objects.
+ * Step through the msgs array looking for the
+ * Message object in the returned source message
+ * list. Most commonly the source message (UID)
+ * for the Nth original message will be in the Nth
+ * position in the returned source message (UID)
+ * list. Thus, the destination UID is in the Nth
+ * position in the returned destination UID list.
+ * But if the source message isn't where expected,
+ * we have to search the entire source message
+ * list, starting from where we expect it and
+ * wrapping around until we've searched it all.
+ */
+ long[] srcuids = UIDSet.toArray(cuid.src);
+ long[] dstuids = UIDSet.toArray(cuid.dst);
+ // map source UIDs to Message objects
+ // XXX - could inline/optimize this
+ Message[] srcmsgs = getMessagesByUID(srcuids);
+ AppendUID[] result = new AppendUID[msgs.length];
+ for (int i = 0; i < srcmsgs.length; i++) {
+ int j = i;
+ do {
+ if (msgs[j] == srcmsgs[i]) {
+ result[j] = new AppendUID(
+ cuid.uidvalidity, dstuids[i]);
+ break;
+ }
+ j++;
+ if (j >= msgs.length)
+ j = 0;
+ } while (j != i);
+ }
+ for (int i = 0; i < msgs.length; i++) {
+ int j = i;
+ do {
+ if (msgs[i] == srcmsgs[j]) {
+ result[i] = new AppendUID(
+ cuid.uidvalidity, dstuids[j]);
+ break;
+ }
+ j++;
+ if (j >= msgs.length)
+ j = 0;
+ } while (j != i);
+ }
+ return result;
+ } catch (CommandFailedException cfx) {
+ if (cfx.getMessage().indexOf("TRYCREATE") != -1)
+ throw new FolderNotFoundException(
+ folder,
+ folder.getFullName() + " does not exist"
+ );
+ else
+ throw new MessagingException(cfx.getMessage(), cfx);
+ } catch (ConnectionException cex) {
+ throw new FolderClosedException(this, cex.getMessage());
+ } catch (ProtocolException pex) {
+ throw new MessagingException(pex.getMessage(), pex);
+ }
+ }
+ } else // destination is a different store.
+ throw new MessagingException(
+ "can't copyUIDMessages to a different store");
+ }
+
+ /**
      * Expunge all messages marked as DELETED.
      */
     public synchronized Message[] expunge() throws MessagingException {

diff -r da36b3d12a39 -r 23bb64d8b374 mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Thu Jun 13 11:12:19 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Fri Jun 21 15:23:01 2013 -0700
@@ -57,6 +57,7 @@
 import com.sun.mail.imap.ACL;
 import com.sun.mail.imap.Rights;
 import com.sun.mail.imap.AppendUID;
+import com.sun.mail.imap.CopyUID;
 import com.sun.mail.imap.SortTerm;
 import com.sun.mail.imap.ResyncData;
 import com.sun.mail.imap.Utility;
@@ -1678,17 +1679,33 @@
      */
     public void copy(MessageSet[] msgsets, String mbox)
                         throws ProtocolException {
- copy(MessageSet.toString(msgsets), mbox);
+ copyuid(MessageSet.toString(msgsets), mbox, false);
     }
 
     public void copy(int start, int end, String mbox)
                         throws ProtocolException {
- copy(String.valueOf(start) + ":" + String.valueOf(end),
- mbox);
+ copyuid(String.valueOf(start) + ":" + String.valueOf(end),
+ mbox, false);
     }
 
- private void copy(String msgSequence, String mbox)
+ /**
+ * COPY Command, return uid from COPYUID response code.
+ *
+ * @see "RFC2359, section 4.3"
+ */
+ public CopyUID copyuid(MessageSet[] msgsets, String mbox)
                         throws ProtocolException {
+ return copyuid(MessageSet.toString(msgsets), mbox, true);
+ }
+
+ public CopyUID copyuid(int start, int end, String mbox)
+ throws ProtocolException {
+ return copyuid(String.valueOf(start) + ":" + String.valueOf(end),
+ mbox, true);
+ }
+
+ public CopyUID copyuid(String msgSequence, String mbox, boolean uid)
+ throws ProtocolException {
         // encode the mbox as per RFC2060
         mbox = BASE64MailboxEncoder.encode(mbox);
 
@@ -1696,7 +1713,42 @@
         args.writeAtom(msgSequence);
         args.writeString(mbox);
 
- simpleCommand("COPY", args);
+ Response[] r = command("COPY", args);
+
+ // dispatch untagged responses
+ notifyResponseHandlers(r);
+
+ // Handle result of this command
+ handleResult(r[r.length-1]);
+
+ if (uid)
+ return getCopyUID(r[r.length-1]);
+ else
+ return null;
+ }
+
+ /**
+ * If the response contains a COPYUID response code, extract
+ * it and return a CopyUID object with the information.
+ */
+ private CopyUID getCopyUID(Response r) {
+ if (!r.isOK())
+ return null;
+ byte b;
+ while ((b = r.readByte()) > 0 && b != (byte)'[')
+ ;
+ if (b == 0)
+ return null;
+ String s;
+ s = r.readAtom();
+ if (!s.equalsIgnoreCase("COPYUID"))
+ return null;
+
+ long uidvalidity = r.readLong();
+ String src = r.readAtom();
+ String dst = r.readAtom();
+ return new CopyUID(uidvalidity,
+ UIDSet.parseUIDSets(src), UIDSet.parseUIDSets(dst));
     }
                     
     public void storeFlags(MessageSet[] msgsets, Flags flags, boolean set)


diff -r 23bb64d8b374 -r f689488ebe14 mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java
--- a/mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java Fri Jun 21 15:23:01 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/util/logging/LogManagerProperties.java Fri Jun 21 15:46:31 2013 -0700
@@ -43,6 +43,7 @@
 import java.io.ObjectStreamException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.*;
@@ -198,15 +199,20 @@
      */
     @SuppressWarnings("unchecked")
     static <T> Comparator<T> reverseOrder(final Comparator<T> c) {
+ if (c == null) {
+ throw new NullPointerException();
+ }
+
         Comparator<T> reverse = null;
- //Comparator in Java 1.8 has 'reverseOrder' as a default method.
- //This code calls that method first to allow custom code to define what
- //reverse order means.
+ //Comparator in Java 1.8 has 'reversed' as a default method.
+ //This code calls that method first to allow custom
+ //code to define what reverse order means.
         try {
             //assert Modifier.isPublic(c.getClass().getModifiers()) :
             // Modifier.toString(c.getClass().getModifiers());
- final Method m = c.getClass().getMethod("reverseOrder");
- if (Comparator.class.isAssignableFrom(m.getReturnType())) {
+ final Method m = c.getClass().getMethod("reversed");
+ if (!Modifier.isStatic(m.getModifiers())
+ && Comparator.class.isAssignableFrom(m.getReturnType())) {
                 try {
                     reverse = (Comparator<T>) m.invoke(c);
                 } catch (final ExceptionInInitializerError eiie) {
@@ -215,6 +221,7 @@
             }
         } catch (final NoSuchMethodException ignore) {
         } catch (final IllegalAccessException ignore) {
+ } catch (final RuntimeException ignore) {
         } catch (final InvocationTargetException ite) {
             paramOrError(ite); //Ignore invocation bugs.
         }

diff -r 23bb64d8b374 -r f689488ebe14 mail/src/test/java/com/sun/mail/util/logging/LogManagerPropertiesTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/LogManagerPropertiesTest.java Fri Jun 21 15:23:01 2013 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/LogManagerPropertiesTest.java Fri Jun 21 15:46:31 2013 -0700
@@ -392,7 +392,8 @@
         }
 
         final Class<?> type = ErrorComparator.class;
- final Comparator c = LogManagerProperties.newComparator(type.getName());
+ final Comparator<? super LogRecord> c =
+ LogManagerProperties.newComparator(type.getName());
         assertEquals(type, c.getClass());
 
         setPending(new RuntimeException());
@@ -569,7 +570,7 @@
     public void testEscapingComparator() throws Exception {
         try {
             Class<?> k = ErrorComparator.class;
- Comparator c;
+ Comparator<? super LogRecord> c;
 
             c = LogManagerProperties.newComparator(k.getName());
             assertEquals(k, c.getClass());
@@ -750,7 +751,7 @@
             throw new UnsupportedOperationException();
         }
 
- public Comparator<LogRecord> reverseOrder() {
+ public Comparator<LogRecord> reversed() {
             return new DescComparator();
         }
     }
@@ -763,7 +764,7 @@
             throw new UnsupportedOperationException();
         }
 
- public Comparator<LogRecord> reverseOrder() {
+ public Comparator<LogRecord> reversed() {
             return new AscComparator();
         }
     }

diff -r 23bb64d8b374 -r f689488ebe14 mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java
--- a/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Jun 21 15:23:01 2013 -0700
+++ b/mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java Fri Jun 21 15:46:31 2013 -0700
@@ -40,6 +40,7 @@
  */
 package com.sun.mail.util.logging;
 
+import com.sun.mail.util.SocketConnectException;
 import java.io.*;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -5723,12 +5724,12 @@
 
     private Level[] getAllLevels() {
         Field[] fields = Level.class.getFields();
- List a = new ArrayList(fields.length);
+ List<Level> a = new ArrayList<Level>(fields.length);
         for (int i = 0; i < fields.length; i++) {
             if (Modifier.isStatic(fields[i].getModifiers())
                     && Level.class.isAssignableFrom(fields[i].getType())) {
                 try {
- a.add(fields[i].get((Object) null));
+ a.add((Level) fields[i].get((Object) null));
                 } catch (IllegalArgumentException ex) {
                     fail(ex.toString());
                 } catch (IllegalAccessException ex) {
@@ -5736,11 +5737,11 @@
                 }
             }
         }
- return (Level[]) a.toArray(new Level[a.size()]);
+ return a.toArray(new Level[a.size()]);
     }
 
     private static boolean isConnectOrTimeout(Throwable t) {
- if (t instanceof MessagingException) {
+ if (t instanceof MessagingException || t instanceof SocketConnectException) {
             return isConnectOrTimeout(t.getCause());
         } else {
             return t instanceof java.net.ConnectException
@@ -6041,7 +6042,7 @@
             return s1 < s2 ? -1 : s1 > s2 ? 1 : 0;
         }
 
- public Comparator<LogRecord> reverseOrder() {
+ public Comparator<LogRecord> reversed() {
             return new SequenceDescComparator();
         }
     }


diff -r f689488ebe14 -r b937e559a8ce doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Jun 21 15:46:31 2013 -0700
+++ b/doc/release/CHANGES.txt Fri Jun 21 17:14:03 2013 -0700
@@ -20,6 +20,7 @@
 
 K 5924 IMAP provider should support the QRESYNC extension (RFC 5162)
 K 5925 IMAP provider should support the WITHIN search extension (RFC 5032)
+K 5933 JavaMail does not handle write timeouts
 K 5934 method fill() isn't synchronized correctly in SharedFileInputStream
 K 5978 NullPointerException in MimeUtility#quote()
 K 5987 support RFC 2359 COPYUID response code

diff -r f689488ebe14 -r b937e559a8ce mail/src/main/java/com/sun/mail/imap/package.html
--- a/mail/src/main/java/com/sun/mail/imap/package.html Fri Jun 21 15:46:31 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/package.html Fri Jun 21 17:14:03 2013 -0700
@@ -253,13 +253,27 @@
 <TD>mail.imap.connectiontimeout</TD>
 <TD>int</TD>
 <TD>Socket connection timeout value in milliseconds.
+This timeout is implemented by java.net.Socket.
 Default is infinite timeout.</TD>
 </TR>
 
 <TR>
 <TD>mail.imap.timeout</TD>
 <TD>int</TD>
-<TD>Socket I/O timeout value in milliseconds. Default is infinite timeout.</TD>
+<TD>Socket read timeout value in milliseconds.
+This timeout is implemented by java.net.Socket.
+Default is infinite timeout.</TD>
+</TR>
+
+<TR>
+<TD>mail.imap.writetimeout</TD>
+<TD>int</TD>
+<TD>Socket write timeout value in milliseconds.
+This timeout is implemented by using a
+java.util.concurrent.ScheduledExecutorService per connection
+that schedules a thread to close the socket if the timeout expires.
+Thus, the overhead of using this timeout is one thread per connection.
+Default is infinite timeout.</TD>
 </TR>
 
 <TR>

diff -r f689488ebe14 -r b937e559a8ce mail/src/main/java/com/sun/mail/pop3/package.html
--- a/mail/src/main/java/com/sun/mail/pop3/package.html Fri Jun 21 15:46:31 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/package.html Fri Jun 21 17:14:03 2013 -0700
@@ -5,7 +5,7 @@
 
     DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
- Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
 
     The contents of this file are subject to the terms of either the GNU
     General Public License Version 2 only ("GPL") or the Common Development
@@ -221,13 +221,27 @@
 <TD>mail.pop3.connectiontimeout</TD>
 <TD>int</TD>
 <TD>Socket connection timeout value in milliseconds.
+This timeout is implemented by java.net.Socket.
 Default is infinite timeout.</TD>
 </TR>
 
 <TR>
 <TD>mail.pop3.timeout</TD>
 <TD>int</TD>
-<TD>Socket I/O timeout value in milliseconds. Default is infinite timeout.</TD>
+<TD>Socket read timeout value in milliseconds.
+This timeout is implemented by java.net.Socket.
+Default is infinite timeout.</TD>
+</TR>
+
+<TR>
+<TD>mail.pop3.writetimeout</TD>
+<TD>int</TD>
+<TD>Socket write timeout value in milliseconds.
+This timeout is implemented by using a
+java.util.concurrent.ScheduledExecutorService per connection
+that schedules a thread to close the socket if the timeout expires.
+Thus, the overhead of using this timeout is one thread per connection.
+Default is infinite timeout.</TD>
 </TR>
 
 <TR>

diff -r f689488ebe14 -r b937e559a8ce mail/src/main/java/com/sun/mail/smtp/package.html
--- a/mail/src/main/java/com/sun/mail/smtp/package.html Fri Jun 21 15:46:31 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/smtp/package.html Fri Jun 21 17:14:03 2013 -0700
@@ -5,7 +5,7 @@
 
     DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
- Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
 
     The contents of this file are subject to the terms of either the GNU
     General Public License Version 2 only ("GPL") or the Common Development
@@ -196,13 +196,27 @@
 <TD>mail.smtp.connectiontimeout</TD>
 <TD>int</TD>
 <TD>Socket connection timeout value in milliseconds.
+This timeout is implemented by java.net.Socket.
 Default is infinite timeout.</TD>
 </TR>
 
 <TR>
 <TD>mail.smtp.timeout</TD>
 <TD>int</TD>
-<TD>Socket I/O timeout value in milliseconds. Default is infinite timeout.</TD>
+<TD>Socket read timeout value in milliseconds.
+This timeout is implemented by java.net.Socket.
+Default is infinite timeout.</TD>
+</TR>
+
+<TR>
+<TD>mail.smtp.writetimeout</TD>
+<TD>int</TD>
+<TD>Socket write timeout value in milliseconds.
+This timeout is implemented by using a
+java.util.concurrent.ScheduledExecutorService per connection
+that schedules a thread to close the socket if the timeout expires.
+Thus, the overhead of using this timeout is one thread per connection.
+Default is infinite timeout.</TD>
 </TR>
 
 <TR>

diff -r f689488ebe14 -r b937e559a8ce mail/src/main/java/com/sun/mail/util/SocketFetcher.java
--- a/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri Jun 21 15:46:31 2013 -0700
+++ b/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri Jun 21 17:14:03 2013 -0700
@@ -284,15 +284,14 @@
                                 new java.net.Proxy(java.net.Proxy.Type.SOCKS,
                                 new InetSocketAddress(socksHost, socksPort)));
             else
- { String s = System.getenv("WRITE_TIMEOUT");
- if (s != null)
- socket = new WriteTimeoutSocket(Integer.parseInt(s));
- else
                 socket = new Socket();
- }
         }
         if (to >= 0)
             socket.setSoTimeout(to);
+ int writeTimeout = PropUtil.getIntProperty(props,
+ prefix + ".writetimeout", -1);
+ if (writeTimeout != -1) // wrap original
+ socket = new WriteTimeoutSocket(socket, writeTimeout);
         if (localaddr != null)
             socket.bind(new InetSocketAddress(localaddr, localport));
         try {

diff -r f689488ebe14 -r b937e559a8ce mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/src/main/java/com/sun/mail/util/WriteTimeoutSocket.java Fri Jun 21 17:14:03 2013 -0700
@@ -0,0 +1,361 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.mail.util;
+
+import java.io.*;
+import java.net.*;
+import java.util.concurrent.*;
+
+/**
+ * A special Socket that uses a ScheduledExecutorService to
+ * implement timeouts for writes. The write timeout is specified
+ * (in milliseconds) when the WriteTimeoutSocket is created.
+ *
+ * @author Bill Shannon
+ */
+public class WriteTimeoutSocket extends Socket {
+
+ // delegate all operations to this socket
+ private final Socket socket;
+ // to schedule task to cancel write after timeout
+ private final ScheduledExecutorService ses;
+ // the timeout, in milliseconds
+ private final int timeout;
+
+ public WriteTimeoutSocket(Socket socket, int timeout) throws IOException {
+ this.socket = socket;
+ // XXX - could share executor with all instances?
+ this.ses = Executors.newScheduledThreadPool(1);
+ this.timeout = timeout;
+ }
+
+ public WriteTimeoutSocket(int timeout) throws IOException {
+ this(new Socket(), timeout);
+ }
+
+ public WriteTimeoutSocket(InetAddress address, int port, int timeout)
+ throws IOException {
+ this(timeout);
+ socket.connect(new InetSocketAddress(address, port));
+ }
+
+ public WriteTimeoutSocket(InetAddress address, int port,
+ InetAddress localAddress, int localPort, int timeout)
+ throws IOException {
+ this(timeout);
+ socket.bind(new InetSocketAddress(localAddress, localPort));
+ socket.connect(new InetSocketAddress(address, port));
+ }
+
+ public WriteTimeoutSocket(String host, int port, int timeout)
+ throws IOException {
+ this(timeout);
+ socket.connect(new InetSocketAddress(host, port));
+ }
+
+ public WriteTimeoutSocket(String host, int port,
+ InetAddress localAddress, int localPort, int timeout)
+ throws IOException {
+ this(timeout);
+ socket.bind(new InetSocketAddress(localAddress, localPort));
+ socket.connect(new InetSocketAddress(host, port));
+ }
+
+ // override all Socket methods and delegate to underlying Socket
+
+ @Override
+ public void connect(SocketAddress remote) throws IOException {
+ socket.connect(remote, 0);
+ }
+
+ @Override
+ public void connect(SocketAddress remote, int timeout) throws IOException {
+ socket.connect(remote, timeout);
+ }
+
+ @Override
+ public void bind(SocketAddress local) throws IOException {
+ socket.bind(local);
+ }
+
+ @Override
+ public InetAddress getInetAddress() {
+ return socket.getInetAddress();
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ return socket.getLocalAddress();
+ }
+
+ @Override
+ public int getPort() {
+ return socket.getPort();
+ }
+
+ @Override
+ public int getLocalPort() {
+ return socket.getLocalPort();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return socket.getInputStream();
+ }
+
+ @Override
+ public synchronized OutputStream getOutputStream() throws IOException {
+ // wrap the returned stream to implement write timeout
+ return new TimeoutOutputStream(socket.getOutputStream(), ses, timeout);
+ }
+
+ @Override
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ socket.setTcpNoDelay(on);
+ }
+
+ @Override
+ public boolean getTcpNoDelay() throws SocketException {
+ return socket.getTcpNoDelay();
+ }
+
+ @Override
+ public void setSoLinger(boolean on, int linger) throws SocketException {
+ socket.setSoLinger(on, linger);
+ }
+
+ @Override
+ public int getSoLinger() throws SocketException {
+ return socket.getSoLinger();
+ }
+
+ @Override
+ public void sendUrgentData(int data) throws IOException {
+ socket.sendUrgentData(data);
+ }
+
+ @Override
+ public void setOOBInline(boolean on) throws SocketException {
+ socket.setOOBInline(on);
+ }
+
+ @Override
+ public boolean getOOBInline() throws SocketException {
+ return socket.getOOBInline();
+ }
+
+ @Override
+ public void setSoTimeout(int timeout) throws SocketException {
+ socket.setSoTimeout(timeout);
+ }
+
+ @Override
+ public int getSoTimeout() throws SocketException {
+ return socket.getSoTimeout();
+ }
+
+ @Override
+ public void setSendBufferSize(int size) throws SocketException {
+ socket.setSendBufferSize(size);
+ }
+
+ @Override
+ public int getSendBufferSize() throws SocketException {
+ return socket.getSendBufferSize();
+ }
+
+ @Override
+ public void setReceiveBufferSize(int size) throws SocketException {
+ socket.setReceiveBufferSize(size);
+ }
+
+ @Override
+ public int getReceiveBufferSize() throws SocketException {
+ return socket.getReceiveBufferSize();
+ }
+
+ @Override
+ public void setKeepAlive(boolean on) throws SocketException {
+ socket.setKeepAlive(on);
+ }
+
+ @Override
+ public boolean getKeepAlive() throws SocketException {
+ return socket.getKeepAlive();
+ }
+
+ @Override
+ public void setTrafficClass(int tc) throws SocketException {
+ socket.setTrafficClass(tc);
+ }
+
+ @Override
+ public int getTrafficClass() throws SocketException {
+ return socket.getTraff
[truncated due to length]