commits@javamail.java.net

[mercurial:135] Add STLS support to POP3.

From: <shannon_at_kenai.com>
Date: Fri, 8 May 2009 20:35:38 +0000 (GMT)

Repository: mercurial
Revision: 135
Author: Bill Shannon <bill.shannon_at_sun.com>
Date: 2009-04-16 22:52:07 UTC
Link:
http://kenai.com/projects/javamail/sources/mercurial/revision/135

Log Message:
-----------
Add STLS support to POP3.

Modified Paths:
--------------
    doc/release/CHANGES.txt
    mail/src/main/java/com/sun/mail/pop3/POP3Store.java
    mail/src/main/java/com/sun/mail/pop3/Protocol.java
    mail/src/main/java/com/sun/mail/pop3/package.html

Diffs:
-----
diff -r 77c64ae830b6 -r cb590f44fcb4 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Wed Apr 15 15:18:59 2009 -0700
+++ b/doc/release/CHANGES.txt Thu Apr 16 15:52:07 2009 -0700
@@ -7,6 +7,13 @@
 (after removing the "GF"):
 
        https://glassfish.dev.java.net/issues
+
+
+ CHANGES IN THE 1.4.3 RELEASE
+ ----------------------------
+The following bugs have been fixed in the 1.4.3 release.
+
+<no id> add starttls support to POP3
 
 
                  CHANGES IN THE 1.4.2 RELEASE
diff -r 77c64ae830b6 -r cb590f44fcb4
mail/src/main/java/com/sun/mail/pop3/POP3Store.java
--- a/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Wed Apr
15 15:18:59 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/POP3Store.java Thu Apr
16 15:52:07 2009 -0700
@@ -43,6 +43,8 @@
 import javax.mail.internet.*;
 import java.io.IOException;
 import java.io.EOFException;
+import java.util.Collections;
+import java.util.Map;
 
 import com.sun.mail.util.PropUtil;
 
@@ -70,6 +72,9 @@
     boolean rsetBeforeQuit = false;
     boolean disableTop = false;
     boolean forgetTopHeaders = false;
+ boolean useStartTLS = false;
+ boolean requireStartTLS = false;
+ Map capabilities;
     Constructor messageConstructor = null;
 
     public POP3Store(Session session, URLName url) {
@@ -100,11 +105,19 @@
        forgetTopHeaders = PropUtil.getBooleanSessionProperty(session,
                                "mail." + name + ".forgettopheaders",
false);
 
+ // mail.pop3.starttls.enable enables use of STLS command
+ useStartTLS = PropUtil.getBooleanSessionProperty(session,
+ "mail." + name + ".starttls.enable",
false);
+
+ // mail.pop3.starttls.required requires use of STLS command
+ requireStartTLS = PropUtil.getBooleanSessionProperty(session,
+ "mail." + name + ".starttls.required",
false);
+
        String s = session.getProperty("mail." + name +
".message.class");
        if (s != null) {
            if (session.getDebug())
                session.getDebugOut().println(
- "DEBUG: POP3 message class: " + s);
+ "DEBUG POP3: message class: " + s);
            try {
                ClassLoader cl = this.getClass().getClassLoader();
 
@@ -127,7 +140,7 @@
            } catch (Exception ex) {
                if (session.getDebug())
                    session.getDebugOut().println(
- "DEBUG: failed to load POP3 message class: " +
ex);
+ "DEBUG POP3: failed to load message class: " +
ex);
            }
        }
     }
@@ -214,6 +227,39 @@
            session.getDebugOut(), session.getProperties(), "mail." +
name,
            isSSL);
 
+ if (useStartTLS || requireStartTLS) {
+ if (p.hasCapability("STLS")) {
+ p.stls();
+ // refresh capabilities
+ p.setCapabilities(p.capa());
+ } else if (requireStartTLS) {
+ if (debug)
+ session.getDebugOut().println(
+ "DEBUG POP3: STLS required but not supported");
+ try {
+ p.quit();
+ } catch (IOException ioex) {
+ } finally {
+ throw new EOFException("STLS required but not
supported");
+ }
+ }
+ }
+
+ capabilities = p.getCapabilities(); // save for later, may
be null
+
+ /*
+ * If we haven't explicitly disabled use of the TOP command,
+ * and the server has provided its capabilities,
+ * and the server doesn't support the TOP command,
+ * disable the TOP command.
+ */
+ if (!disableTop &&
+ capabilities != null &&
capabilities.containsKey("TOP")) {
+ disableTop = true;
+ session.getDebugOut().println(
+ "DEBUG POP3: server doesn't support TOP, disabling
it");
+ }
+
        String msg = null;
        if ((msg = p.login(user, passwd)) != null) {
            try {
@@ -279,6 +325,27 @@
        return new POP3Folder(this, url.getFile());
     }
 
+ /**
+ * Return a Map of the capabilities the server provided,
+ * as per RFC 2449. If the server doesn't support RFC 2449,
+ * an emtpy Map is returned. The returned Map can not be
modified.
+ * The key to the Map is the upper case capability name as
+ * a String. The value of the entry is the entire String
+ * capability line returned by the server. <p>
+ *
+ * For example, to check if the server supports the STLS
capability, use:
+ * <code>if (store.capabilities().containsKey("STLS")) ...</code>
+ *
+ * @return Map of capabilities
+ * @since JavaMail 1.4.3
+ */
+ public Map capabilities() throws MessagingException {
+ if (capabilities != null)
+ return Collections.unmodifiableMap(capabilities);
+ else
+ return Collections.emptyMap();
+ }
+
     protected void finalize() throws Throwable {
        super.finalize();
 
diff -r 77c64ae830b6 -r cb590f44fcb4
mail/src/main/java/com/sun/mail/pop3/Protocol.java
--- a/mail/src/main/java/com/sun/mail/pop3/Protocol.java Wed Apr
15 15:18:59 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/Protocol.java Thu Apr
16 15:52:07 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
@@ -62,6 +62,9 @@
  */
 class Protocol {
     private Socket socket; // POP3 socket
+ private String host; // host we're connected to
+ private Properties props; // session properties
+ private String prefix; // protocol name prefix, for
props
     private DataInputStream input; // input buf
     private PrintWriter output; // output buf
     private static final int POP3_PORT = 110; // standard POP3 port
@@ -69,6 +72,7 @@
     private boolean debug = false;
     private PrintStream out;
     private String apopChallenge = null;
+ private Map capabilities = null;
 
     /**
      * Open a connection to the POP3 server.
@@ -78,6 +82,9 @@
                        throws IOException {
        this.debug = debug;
        this.out = out;
+ this.host = host;
+ this.props = props;
+ this.prefix = prefix;
        Response r;
        boolean enableAPOP = PropUtil.getBooleanProperty(props,
                                        prefix + ".apop.enable",
false);
@@ -89,15 +96,7 @@
                                "\", port " + port + ", isSSL " +
isSSL);
 
            socket = SocketFetcher.getSocket(host, port, props, prefix,
isSSL);
-
- input = new DataInputStream(
- new BufferedInputStream(socket.getInputStream()));
- output = new PrintWriter(
- new BufferedWriter(
- new
OutputStreamWriter(socket.getOutputStream(),
- "iso-8859-1")));
- // should be US-ASCII, but not all
JDK's support
-
+ initStreams();
            r = simpleCommand(null);
        } catch (IOException ioe) {
            try {
@@ -122,6 +121,19 @@
            if (debug)
                out.println("DEBUG POP3: APOP challenge: " +
apopChallenge);
        }
+
+ // if server supports RFC 2449, set capabilities
+ setCapabilities(capa());
+ }
+
+ private void initStreams() throws IOException {
+ input = new DataInputStream(
+ new BufferedInputStream(socket.getInputStream()));
+ output = new PrintWriter(
+ new BufferedWriter(
+ new
OutputStreamWriter(socket.getOutputStream(),
+ "iso-8859-1")));
+ // should be US-ASCII, but not all JDK's
support
     }
 
     protected void finalize() throws Throwable {
@@ -129,6 +141,48 @@
        if (socket != null) { // Forgot to logout ?!
            quit();
        }
+ }
+
+ /**
+ * Parse the capabilities from a CAPA response.
+ */
+ synchronized void setCapabilities(InputStream in) {
+ if (in == null) {
+ capabilities = null;
+ return;
+ }
+
+ capabilities = new HashMap(10);
+ BufferedReader r = new BufferedReader(new
InputStreamReader(in));
+ String s;
+ try {
+ while ((s = r.readLine()) != null) {
+ String cap = s;
+ int i = cap.indexOf(' ');
+ if (i > 0)
+ cap = cap.substring(0, i);
+ capabilities.put(cap.toUpperCase(Locale.ENGLISH), s);
+ }
+ } catch (IOException ex) {
+ // should never happen
+ }
+ }
+
+ /**
+ * Check whether the given capability is supported by
+ * this server. Returns <code>true</code> if so, otherwise
+ * returns false.
+ */
+ synchronized boolean hasCapability(String c) {
+ return capabilities != null &&
+
capabilities.containsKey(c.toUpperCase(Locale.ENGLISH));
+ }
+
+ /**
+ * Return the map of capabilities returned by the server.
+ */
+ synchronized Map getCapabilities() {
+ return capabilities;
     }
 
     /**
@@ -341,6 +395,41 @@
     }
 
     /**
+ * Start TLS using STLS command specified by RFC 2595.
+ */
+ synchronized boolean stls() throws IOException {
+ Response r = simpleCommand("STLS");
+ if (r.ok) {
+ // it worked, now switch the socket into TLS mode
+ try {
+ socket = SocketFetcher.startTLS(socket, host, props,
prefix);
+ initStreams();
+ } catch (IOException ioex) {
+ try {
+ socket.close();
+ } finally {
+ socket = null;
+ input = null;
+ output = null;
+ }
+ throw new IOException("Could not convert socket to
TLS", ioex);
+ }
+ }
+ return r.ok;
+ }
+
+ /**
+ * Get server capabilities using CAPA command specified by RFC
2449.
+ * Returns null if not supported.
+ */
+ synchronized InputStream capa() throws IOException {
+ Response r = multilineCommand("CAPA", 128); // 128 == output
size est
+ if (!r.ok)
+ return null;
+ return r.bytes;
+ }
+
+ /**
      * Issue a simple POP3 command and return the response.
      */
     private Response simpleCommand(String cmd) throws IOException {
diff -r 77c64ae830b6 -r cb590f44fcb4
mail/src/main/java/com/sun/mail/pop3/package.html
--- a/mail/src/main/java/com/sun/mail/pop3/package.html Wed Apr 15
15:18:59 2009 -0700
+++ b/mail/src/main/java/com/sun/mail/pop3/package.html Thu Apr 16
15:52:07 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
@@ -353,6 +353,31 @@
 </TR>
 
 <TR>
+<TD>mail.pop3.starttls.enable</TD>
+<TD>boolean</TD>
+<TD>
+If true, enables the use of the <code>STLS</code> command (if
+supported by the server) to switch the connection to a TLS-protected
+connection before issuing any login commands. Note that an
appropriate
+trust store must configured so that the client will trust the server's
+certificate.
+Defaults to false.
+</TD>
+</TR>
+
+<TR>
+<TD>mail.pop3.starttls.required</TD>
+<TD>boolean</TD>
+<TD>
+If true, requires the use of the <code>STLS</code> command.
+If the server doesn't support the STLS command, or the command
+fails, the connect method will fail.
+Defaults to false.
+</TD>
+</TR>
+
+
+<TR>
 <TD>mail.pop3.disabletop</TD>
 <TD>boolean</TD>
 <TD>