commits@javamail.java.net

[javamail~mercurial:148] Fix startTLS method to detect certificate problems immediately

From: <shannon_at_kenai.com>
Date: Fri, 10 Jul 2009 22:22:07 +0000

Project: javamail
Repository: mercurial
Revision: 148
Author: shannon
Date: 2009-07-10 22:19:57 UTC
Link: http://kenai.com/projects/javamail/sources/mercurial/revision/148

Log Message:
------------
Analyze and exclude FindBugs errors except synchronization errors.
Update to the latest FindBugs plugin.
return correct message in event when message is expunged - bug 6850882
fix POP3Folder.isOpen if server fails and is then reconnected;
insist that NOOP succeed (may return -ERR if server is disconnecting)
update DSN reference
ignore RFC 2231 "language" in encoded word
Add a constructor that takes a Throwable cause.
Fix startTLS method to detect certificate problems immediately
and throw an appropriate exception.


Revisions:
----------
142
143
144
145
146
147
148


Modified Paths:
---------------
mail/pom.xml
doc/release/CHANGES.txt
mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
mail/src/main/java/com/sun/mail/pop3/POP3Folder.java
mail/src/main/java/com/sun/mail/pop3/POP3Store.java
mail/src/main/java/com/sun/mail/smtp/package.html
mail/src/main/java/javax/mail/internet/MimeUtility.java
mail/src/main/java/com/sun/mail/iap/ProtocolException.java
mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
mail/src/main/java/com/sun/mail/util/SocketFetcher.java


Added Paths:
------------
mail/exclude.xml


Diffs:
------
diff -r 1f0625bf9aee -r 17c2d3fc4b44 mail/exclude.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mail/exclude.xml Wed May 13 15:06:55 2009 -0700
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- FindBugs exclude list for JavaMail -->
+
+<FindBugsFilter>
+ <!--
+ There are a bunch of places where FindBugs complains about
+ exposing internal representations. We exclude cases where
+ this only happens in internal classes that are never visible
+ through the public JavaMail API, or cases where the user
+ passes in an object (usually an array) and can only hurt
+ themselves by modifying the array while a method is in progress,
+ or where the implementation is passing the data back to the user
+ (e.g., in an Exception) and never uses it again.
+ -->
+ <Match>
+ <Or>
+ <Class name="com.sun.mail.iap.ByteArray"/>
+ <Class name="javax.mail.SendFailedException"/>
+ <Class name="javax.mail.event.MessageCountEvent"/>
+ <Class name="javax.mail.event.TransportEvent"/>
+ </Or>
+ <Or>
+ <Bug pattern="EI_EXPOSE_REP"/>
+ <Bug pattern="EI_EXPOSE_REP2"/>
+ </Or>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.smtp.SMTPTransport"/>
+ <Method name="sendMessage"/>
+ <!-- passed in Address array -->
+ <Bug pattern="EI_EXPOSE_REP2"/>
+ </Match>
+ <Match>
+ <Class name="javax.mail.internet.MimeBodyPart"/>
+ <Method name="&lt;init&gt;"/> <!-- match constructor -->
+ <!-- passed in byte array -->
+ <Bug pattern="EI_EXPOSE_REP2"/>
+ </Match>
+ <Match>
+ <Class name="javax.mail.util.ByteArrayDataSource"/>
+ <Method name="&lt;init&gt;"/> <!-- match constructor -->
+ <!-- passed in byte array -->
+ <Bug pattern="EI_EXPOSE_REP2"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.util.MailSSLSocketFactory"/>
+ <Method name="setTrustManagers"/>
+ <!-- passed in TrustManager array -->
+ <Bug pattern="EI_EXPOSE_REP2"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.util.MailSSLSocketFactory"/>
+ <Method name="getTrustManagers"/>
+ <!-- returned TrustManager array -->
+ <Bug pattern="EI_EXPOSE_REP"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.imap.protocol.INTERNALDATE"/>
+ <Method name="getDate"/>
+ <!--
+ Returned Date object; it's only ever stored in
+ IMAPMessage.receivedDate and is always used to
+ construct a new Date object before returning to
+ users.
+ -->
+ <Bug pattern="EI_EXPOSE_REP"/>
+ </Match>
+
+ <!--
+ A few places where it complains about wait not being in a loop.
+ This purposely doesn't loop so that the application
+ calling idle can check whether the idle should continue.
+ -->
+ <Match>
+ <!-- an anonymous inner class of the idle method -->
+ <Class name="~com\.sun\.mail\.imap\.IMAPFolder.*"/>
+ <Method name="doCommand"/>
+ <Bug pattern="WA_NOT_IN_LOOP"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.imap.IMAPStore"/>
+ <Method name="idle"/>
+ <Bug pattern="WA_NOT_IN_LOOP"/>
+ </Match>
+
+ <!--
+ A few places where we catch Exception even though it's not
+ explicitly thrown. We need to make sure that if anything
+ goes wrong we clean things up. Perhaps these should be
+ converted to a finally block and a boolean "success" flag?
+ -->
+ <Match>
+ <Class name="com.sun.mail.imap.IMAPStore"/>
+ <Method name="getProtocol"/>
+ <Bug pattern="REC_CATCH_EXCEPTION"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.imap.IMAPStore"/>
+ <Method name="getStoreProtocol"/>
+ <Bug pattern="REC_CATCH_EXCEPTION"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.imap.protocol.IMAPSaslAuthenticator"/>
+ <Method name="authenticate"/>
+ <Bug pattern="REC_CATCH_EXCEPTION"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.pop3.POP3Folder"/>
+ <Method name="createMessage"/>
+ <Or>
+ <Bug pattern="REC_CATCH_EXCEPTION"/>
+ <Bug pattern="DE_MIGHT_IGNORE"/>
+ </Or>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.util.SocketFetcher"/>
+ <Method name="startTLS"/>
+ <Bug pattern="REC_CATCH_EXCEPTION"/>
+ </Match>
+ <Match>
+ <Class name="javax.mail.Session"/>
+ <Method name="loadAllResources"/>
+ <Bug pattern="REC_CATCH_EXCEPTION"/>
+ </Match>
+
+ <!--
+ FindBugs complains about a possible double check of headersLoaded,
+ but it seems to be just wrong; I don't see it.
+ -->
+ <Match>
+ <Class name="com.sun.mail.imap.IMAPMessage"/>
+ <Method name="loadHeaders"/>
+ <Bug pattern="DC_DOUBLECHECK"/>
+ </Match>
+
+ <!--
+ These IMAP-specific subclasses of standard classes don't override
+ equals because all they add are constructors and optimized access
+ methods; everything else, including the way to test for equality,
+ is the same.
+ -->
+ <Match>
+ <Class name="com.sun.mail.imap.protocol.FLAGS"/>
+ <Bug pattern="EQ_DOESNT_OVERRIDE_EQUALS"/>
+ </Match>
+ <Match>
+ <Class name="com.sun.mail.imap.protocol.IMAPAddress"/>
+ <!-- defined in ENVELOPE.java -->
+ <Bug pattern="EQ_DOESNT_OVERRIDE_EQUALS"/>
+ </Match>
+
+ <!--
+ FindBugs complains of an unitialized read of the "capabilities"
+ field. Since the superclass might initialize the field (via a
+ call into the overridden processGreeting method), any initialization
+ done in the IMAPProtocol class will undo any initialization done
+ as a side effect of calling the superclass constructor. Thus, we
+ need to depend on the field being initialized to the default value.
+ -->
+ <Match>
+ <Class name="com.sun.mail.imap.protocol.IMAPProtocol"/>
+ <Method name="&lt;init&gt;"/> <!-- match constructor -->
+ <Bug pattern="UR_UNINIT_READ"/>
+ </Match>
+
+ <!--
+ This use of string concatenation only occurs when creating a
+ string for an error message in an exception. The simpler code
+ is better here; performance is not an issue.
+ -->
+ <Match>
+ <Class name="com.sun.mail.util.BASE64DecoderStream"/>
+ <Method name="recentChars"/>
+ <Bug pattern="SBSC_USE_STRINGBUFFER_CONCATENATION"/>
+ </Match>
+
+ <!--
+ Yes, the "next" element in my linked list isn't ever actually
+ used, but it feels weird to only have a "prev" element.
+ -->
+ <Match>
+ <Class name="javax.mail.EventQueue$QueueElement"/>
+ <Field name="next"/>
+ <Bug pattern="URF_UNREAD_FIELD"/>
+ </Match>
+
+ <!--
+ Stupid Serializable EventObject class causes FindBugs to complain
+ about transient fields in subclasses. I don't know why it's
+ complaining about these fields but not others, but since I don't
+ really expect anyone to serialize these events I'm just ignoring
+ this complaint.
+ -->
+ <Match>
+ <Class name="javax.mail.event.TransportEvent"/>
+ <Or>
+ <Field name="invalid"/>
+ <Field name="validSent"/>
+ <Field name="validUnsent"/>
+ </Or>
+ <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/>
+ </Match>
+
+ <!--
+ This string comparison using == is just an optimization.
+ -->
+ <Match>
+ <Class name="javax.mail.internet.InternetAddress"/>
+ <Method name="equals"/>
+ <Bug pattern="ES_COMPARING_STRINGS_WITH_EQ"/>
+ </Match>
+
+ <!--
+ This string comparison using == is to determine whether the
+ String object is a different String object.
+ -->
+ <Match>
+ <Class name="javax.mail.internet.MimeUtility"/>
+ <Method name="decodeText"/>
+ <Bug pattern="ES_COMPARING_STRINGS_WITH_EQ"/>
+ </Match>
+
+ <!--
+ ByteArrayInputStream.available guarantees to return the full number
+ of bytes left in the buffer, and ByteArrayInputStream.read guarantees
+ to read all the bytes, so we don't really need to check the return
+ value. Ignore this complaint.
+ -->
+ <Match>
+ <Class name="com.sun.mail.util.ASCIIUtility"/>
+ <Method name="getBytes"/>
+ <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
+ </Match>
+
+ <!--
+ We extract the "lang" field of an encoded string but we don't
+ currently do anything with it. Ignore this complaint.
+ -->
+ <Match>
+ <Class name="javax.mail.internet.ParameterList"/>
+ <Method name="decodeValue"/>
+ <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
+ </Match>
+
+ <!--
+ The call ParameterList.set(null, "DONE") is a kludge used by the
+ IMAP provider to indicate that it's done setting parameters.
+ In other cases we *want* a null name to cause a NullPointerException.
+ -->
+ <Match>
+ <Class name="javax.mail.internet.ParameterList"/>
+ <Method name="set"/>
+ <Bug pattern="NP_NULL_ON_SOME_PATH"/>
+ </Match>
+
+ <!--
+ We purposely don't close these streams, which are just wrappers
+ around the original stream that needs to remain open.
+ -->
+ <Match>
+ <Class name="javax.mail.internet.MimeMultipart"/>
+ <Or>
+ <Method name="parse"/>
+ <Method name="parsebm"/>
+ </Or>
+ <Bug pattern="OS_OPEN_STREAM"/>
+ </Match>
+</FindBugsFilter>

diff -r 1f0625bf9aee -r 17c2d3fc4b44 mail/pom.xml
--- a/mail/pom.xml Thu May 07 10:10:39 2009 -0700
+++ b/mail/pom.xml Wed May 13 15:06:55 2009 -0700
@@ -83,22 +83,11 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>findbugs-maven-plugin</artifactId>
- <version>2.0-SNAPSHOT</version>
                 <configuration>
                     <threshold>Normal</threshold>
+ <excludeFilterFile>exclude.xml</excludeFilterFile>
                 </configuration>
             </plugin>
         </plugins>
     </reporting>
-
- <pluginRepositories>
- <!-- Repository for the SNAPSHOT version of findbugs plugin -->
- <pluginRepository>
- <id>codehaus-snapshot-repository</id>
- <url>http://snapshots.repository.codehaus.org/</url>
- <snapshots>
- <updatePolicy>daily</updatePolicy>
- </snapshots>
- </pluginRepository>
- </pluginRepositories>
 </project>


diff -r 17c2d3fc4b44 -r 2a59d1d60a66 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Wed May 13 15:06:55 2009 -0700
+++ b/doc/release/CHANGES.txt Mon Jun 29 16:30:37 2009 -0700
@@ -13,6 +13,7 @@
                   ----------------------------
 The following bugs have been fixed in the 1.4.3 release.
 
+6850882 IMAPMessage returns wrong getMessageNumber() from messageRemovedEvent
 <no id> add starttls support to POP3
 <no id> fix deadlock in IMAP IDLE support
 <no id> add mail.transport.protocol.<address-type> property

diff -r 17c2d3fc4b44 -r 2a59d1d60a66 mail/src/main/java/com/sun/mail/imap/IMAPFolder.java
--- a/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Wed May 13 15:06:55 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/IMAPFolder.java Mon Jun 29 16:30:37 2009 -0700
@@ -2364,16 +2364,20 @@
             // EXPUNGE response.
 
             int seqnum = ir.getNumber();
+ Message[] msgs = null;
+ if (doExpungeNotification && hasMessageCountListener) {
+ // save the Message object first; can't look it
+ // up after it's expunged
+ msgs = new Message[] { getMessageBySeqNumber(seqnum) };
+ }
+
             messageCache.expungeMessage(seqnum);
 
             // decrement 'realTotal'; but leave 'total' unchanged
             realTotal--;
 
- if (doExpungeNotification && hasMessageCountListener) {
- // Do the notification here.
- Message[] msgs = { getMessageBySeqNumber(seqnum) };
+ if (msgs != null) // Do the notification here.
                 notifyMessageRemovedListeners(false, msgs);
- }
 
         } else if (ir.keyEquals("FETCH")) {
             // The only unsolicited FETCH response that makes sense


diff -r 2a59d1d60a66 -r 1e516895aab1 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Mon Jun 29 16:30:37 2009 -0700
+++ b/doc/release/CHANGES.txt Mon Jun 29 16:48:32 2009 -0700
@@ -18,6 +18,7 @@
 <no id> fix deadlock in IMAP IDLE support
 <no id> add mail.transport.protocol.<address-type> property
 <no id> fail POP3Folder.open if STAT command fails
+<no id> fix POP3Folder.isOpen if POP3 server fails and is then reconnected
 
 
                   CHANGES IN THE 1.4.2 RELEASE

diff -r 2a59d1d60a66 -r 1e516895aab1 mail/src/main/java/com/sun/mail/pop3/POP3Folder.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Folder.java Mon Jun 29 16:30:37 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Folder.java Mon Jun 29 16:48:32 2009 -0700
@@ -263,15 +263,22 @@
         }
     }
 
- public boolean isOpen() {
+ public synchronized boolean isOpen() {
         if (!opened)
             return false;
- if (store.isConnected())
- return true;
         try {
- close(false);
- } catch (MessagingException ex) { }
- return false;
+ if (!port.noop())
+ throw new IOException("NOOP failed");
+ } catch (IOException ioex) {
+ try {
+ close(false);
+ } catch (MessagingException mex) {
+ // ignore it
+ } finally {
+ return false;
+ }
+ }
+ return true;
     }
 
     /**

diff -r 2a59d1d60a66 -r 1e516895aab1 mail/src/main/java/com/sun/mail/pop3/POP3Store.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Mon Jun 29 16:30:37 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Mon Jun 29 16:48:32 2009 -0700
@@ -196,22 +196,20 @@
             // if we haven't been connected at all, don't bother with
             // the NOOP.
             return false;
- synchronized (this) {
+ try {
+ if (port == null)
+ port = getPort(null);
+ else if (!port.noop())
+ throw new IOException("NOOP failed");
+ return true;
+ } catch (IOException ioex) {
+ // no longer connected, close it down
             try {
- if (port == null)
- port = getPort(null);
- else
- port.noop();
- return true;
- } catch (IOException ioex) {
- // no longer connected, close it down
- try {
- super.close(); // notifies listeners
- } catch (MessagingException mex) {
- // ignore it
- } finally {
- return false;
- }
+ super.close(); // notifies listeners
+ } catch (MessagingException mex) {
+ // ignore it
+ } finally {
+ return false;
             }
         }
     }


diff -r 1e516895aab1 -r e1a5d1b304f1 mail/src/main/java/com/sun/mail/smtp/package.html
--- a/mail/src/main/java/com/sun/mail/smtp/package.html Mon Jun 29 16:48:32 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/smtp/package.html Mon Jun 29 16:49:03 2009 -0700
@@ -5,7 +5,7 @@
 
   DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  
- Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
+ Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
  
   The contents of this file are subject to the terms of either the GNU
   General Public License Version 2 only ("GPL") or the Common Development
@@ -125,9 +125,10 @@
 message type with a "message/delivery-status"
 (<A HREF="http://www.ietf.org/rfc/rfc1894.txt" TARGET="_top">RFC 1894</A>)
 part.
-JavaMail does not currently provide direct support for these new MIME types,
-but you can process them as any other "multipart" or "message" content,
-using <code>MimeMultipart</code> and <code>MimeMessage</code> objects.
+You can use the classes in the {_at_link com.sun.mail.dsn} package to
+handle these MIME types.
+Note that you'll need to include <code>dsn.jar</code> in your CLASSPATH
+as this support is not included in <code>mail.jar</code>.
 <P>
 See below for the properties to enable these features.
 <P>


diff -r e1a5d1b304f1 -r d8aa0b7200e3 mail/src/main/java/javax/mail/internet/MimeUtility.java
--- a/mail/src/main/java/javax/mail/internet/MimeUtility.java Mon Jun 29 16:49:03 2009 -0700
+++ b/mail/src/main/java/javax/mail/internet/MimeUtility.java Mon Jun 29 16:49:41 2009 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -755,15 +755,15 @@
     }
 
     /**
- * The string is parsed using the rules in RFC 2047 for parsing
- * an "encoded-word". If the parse fails, a ParseException is
+ * The string is parsed using the rules in RFC 2047 and RFC 2231 for
+ * parsing an "encoded-word". If the parse fails, a ParseException is
      * thrown. Otherwise, it is transfer-decoded, and then
      * charset-converted into Unicode. If the charset-conversion
      * fails, an UnsupportedEncodingException is thrown.<p>
      *
      * @param eword the encoded value
      * @exception ParseException if the string is not an
- * encoded-word as per RFC 2047.
+ * encoded-word as per RFC 2047 and RFC 2231.
      * @exception UnsupportedEncodingException if the charset
      * conversion failed.
      */
@@ -779,7 +779,11 @@
         if ((pos = eword.indexOf('?', start)) == -1)
             throw new ParseException(
                 "encoded word does not include charset: " + eword);
- String charset = javaCharset(eword.substring(start, pos));
+ String charset = eword.substring(start, pos);
+ int lpos = charset.indexOf('*'); // RFC 2231 language specified?
+ if (lpos >= 0) // yes, throw it away
+ charset = charset.substring(0, lpos);
+ charset = javaCharset(charset);
 
         // get encoding
         start = pos+1;


diff -r d8aa0b7200e3 -r 3c3e70f21e29 mail/src/main/java/com/sun/mail/iap/ProtocolException.java
--- a/mail/src/main/java/com/sun/mail/iap/ProtocolException.java Mon Jun 29 16:49:41 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/iap/ProtocolException.java Fri Jul 10 15:18:56 2009 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -54,10 +54,20 @@
 
     /**
      * Constructs a ProtocolException with the specified detail message.
- * @param s the detail message
+ * @param message the detail message
      */
- public ProtocolException(String s) {
- super(s);
+ public ProtocolException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a ProtocolException with the specified detail message
+ * and cause.
+ * @param message the detail message
+ * @param cause the cause
+ */
+ public ProtocolException(String message, Throwable cause) {
+ super(message, cause);
     }
 
     /**


diff -r 3c3e70f21e29 -r 539ca970d47e mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java
--- a/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Fri Jul 10 15:18:56 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/imap/protocol/IMAPProtocol.java Fri Jul 10 15:19:57 2009 -0700
@@ -1,7 +1,7 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  *
- * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
  *
  * The contents of this file are subject to the terms of either the GNU
  * General Public License Version 2 only ("GPL") or the Common Development
@@ -610,16 +610,21 @@
         try {
             super.startTLS("STARTTLS");
         } catch (ProtocolException pex) {
+ if (debug)
+ out.println("IMAP DEBUG: STARTTLS ProtocolException: " + pex);
             // ProtocolException just means the command wasn't recognized,
             // or failed. This should never happen if we check the
             // CAPABILITY first.
             throw pex;
         } catch (Exception ex) {
+ if (debug)
+ out.println("IMAP DEBUG: STARTTLS Exception: " + ex);
             // any other exception means we have to shut down the connection
             // generate an artificial BYE response and disconnect
             Response[] r = { Response.byeResponse(ex) };
             notifyResponseHandlers(r);
             disconnect();
+ throw new ProtocolException("STARTTLS failure", ex);
         }
     }
 

diff -r 3c3e70f21e29 -r 539ca970d47e mail/src/main/java/com/sun/mail/util/SocketFetcher.java
--- a/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri Jul 10 15:18:56 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri Jul 10 15:19:57 2009 -0700
@@ -432,7 +432,7 @@
      * mail.<protocol>.ssl.ciphersuites properties.
      */
     private static void configureSSLSocket(Socket socket, Properties props,
- String prefix) {
+ String prefix) throws IOException {
         if (!(socket instanceof SSLSocket))
             return;
         SSLSocket sslsocket = (SSLSocket)socket;
@@ -458,6 +458,13 @@
             System.out.println("DEBUG SocketFetcher: SSL ciphers after " +
                 Arrays.asList(sslsocket.getEnabledCipherSuites()));
         }
+
+ /*
+ * Force the handshake to be done now so that we can report any
+ * errors (e.g., certificate errors) to the caller of the startTLS
+ * method.
+ */
+ sslsocket.startHandshake();
     }
 
     /**