You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ri...@apache.org on 2006/12/07 23:05:26 UTC

svn commit: r483693 - in /geronimo/javamail/trunk: geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/ geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/

Author: rickmcguire
Date: Thu Dec  7 14:05:25 2006
New Revision: 483693

URL: http://svn.apache.org/viewvc?view=rev&rev=483693
Log:
GERONIMO-2439 add secure transport support to POP3 (i.e., SSL)


Modified:
    geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java
    geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java
    geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java
    geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java
    geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java
    geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
    geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java
    geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java
    geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java
    geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java
    geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java
    geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java

Modified: geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java Thu Dec  7 14:05:25 2006
@@ -184,5 +184,52 @@
             }
         };
     }
+    
+    public static POP3Command getCOMMAND_CAPA() {
+    	return new POP3Command() {
+    		public String getCommand() {
+                return "CAPA" + CRLF;
+    		}
+    		
+    		public boolean isMultiLineResponse() {
+    			return true;
+    		}
+    	};
+    }
 
+    public static POP3Command getCOMMAND_AUTH(final String protocol) {
+    	return new POP3Command() {
+    		public String getCommand() {
+    			return "AUTH " + protocol + CRLF;
+    		}
+    		
+    		public boolean isMultiLineResponse() {
+    			return false;
+    		}
+    	};
+    }
+    
+    public static POP3Command getCOMMAND_AUTH(final String protocol, final String initialResponse) {
+    	return new POP3Command() {
+    		public String getCommand() {
+    			return "AUTH " + protocol + " " + initialResponse + CRLF;
+    		}
+    		
+    		public boolean isMultiLineResponse() {
+    			return false;
+    		}
+    	};
+    }
+    
+    public static POP3Command getCOMMAND_ChallengeReply(final String command) {
+    	return new POP3Command() {
+    			public String getCommand() {
+   						return command + CRLF;
+   				}
+    			
+    			public boolean isMultiLineResponse() {
+    				return false;
+    			}	
+    		};
+    }
 }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java Thu Dec  7 14:05:25 2006
@@ -24,7 +24,9 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.net.InetSocketAddress;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
 import java.net.Socket;
 
 import javax.mail.MessagingException;
@@ -38,9 +40,24 @@
  * @version $Rev$ $Date$
  */
 
+
 public class POP3Connection {
 
-    private Socket soc;
+	protected static final String MAIL_SSLFACTORY_CLASS = "mail.SSLSocketFactory.class";
+	
+    protected static final String MAIL_POP3_FACTORY_CLASS = "socketFactory.class";
+
+    protected static final String MAIL_POP3_FACTORY_FALLBACK = "socketFactory.fallback";
+
+    protected static final String MAIL_POP3_FACTORY_PORT = "socketFactory.port";
+    
+    protected static final String MAIL_POP3_LOCALADDRESS = "localAddress";
+    
+    protected static final String MAIL_POP3_LOCALPORT = "localPort";
+    
+    protected static final String MAIL_POP3_TIMEOUT = "timeout";
+	
+    private Socket socket;
 
     private Session session;
 
@@ -51,18 +68,28 @@
     private PrintWriter writer;
 
     private BufferedReader reader;
+    
+    private String protocol;
+    
+    private boolean sslConnection;
 
-    POP3Connection(Session session, String host, int port) {
+    POP3Connection(Session session, String host, int port, boolean sslConnection, String protocol) {
 
         this.session = session;
         this.host = host;
         this.port = port;
+        this.sslConnection = sslConnection;
+        this.protocol = protocol;
     }
 
     public void open() throws Exception {
         try {
-            soc = new Socket();
-            soc.connect(new InetSocketAddress(host, port));
+
+        	if (!sslConnection) {
+        		getConnectedSocket();
+        	} else {
+        		getConnectedSSLSocket();
+        	}
 
             if (session.getDebug()) {
                 session.getDebugOut().println("Connection successful " + this.toString());
@@ -86,7 +113,7 @@
 
     void close() throws Exception {
         try {
-            soc.close();
+            socket.close();
             if (session.getDebug()) {
                 session.getDebugOut().println("Connection successfuly closed " + this.toString());
             }
@@ -99,17 +126,17 @@
     }
 
     public synchronized POP3Response sendCommand(POP3Command cmd) throws MessagingException {
-        if (soc.isConnected()) {
+        if (socket.isConnected()) {
 
             // if the underlying output stream is down
             // attempt to rebuild the writer
-            if (soc.isOutputShutdown()) {
+            if (socket.isOutputShutdown()) {
                 buildOutputWriter();
             }
 
             // if the underlying inout stream is down
             // attempt to rebuild the reader
-            if (soc.isInputShutdown()) {
+            if (socket.isInputShutdown()) {
                 buildInputReader();
             }
 
@@ -135,7 +162,7 @@
 
     private void buildInputReader() throws MessagingException {
         try {
-            reader = new BufferedReader(new InputStreamReader(soc.getInputStream()));
+            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
         } catch (IOException e) {
             throw new MessagingException("Error obtaining input stream " + this.toString(), e);
         }
@@ -143,7 +170,7 @@
 
     private void buildOutputWriter() throws MessagingException {
         try {
-            writer = new PrintWriter(new BufferedOutputStream(soc.getOutputStream()));
+            writer = new PrintWriter(new BufferedOutputStream(socket.getOutputStream()));
         } catch (IOException e) {
             throw new MessagingException("Error obtaining output stream " + this.toString(), e);
         }
@@ -151,5 +178,387 @@
 
     public String toString() {
         return "POP3Connection host: " + host + " port: " + port;
+    }
+
+
+	/**
+	 * Creates a connected socket
+	 *
+	 * @exception MessagingException
+	 */
+	protected void getConnectedSocket() throws IOException {
+	
+	    // the socket factory can be specified via a session property. By
+	    // default, we just directly
+	    // instantiate a socket without using a factor.
+	    String socketFactory = getProtocolProperty(MAIL_POP3_FACTORY_CLASS);
+	
+	    // there are several protocol properties that can be set to tune the
+	    // created socket. We need to
+	    // retrieve those bits before creating the socket.
+	    int timeout = getIntProtocolProperty(MAIL_POP3_TIMEOUT, -1);
+	    InetAddress localAddress = null;
+	    // see if we have a local address override.
+	    String localAddrProp = getProtocolProperty(MAIL_POP3_LOCALADDRESS);
+	    if (localAddrProp != null) {
+	        localAddress = InetAddress.getByName(localAddrProp);
+	    }
+	
+	    // check for a local port...default is to allow socket to choose.
+	    int localPort = getIntProtocolProperty(MAIL_POP3_LOCALPORT, 0);
+	
+	    socket = null;
+	
+	    // if there is no socket factory defined (normal), we just create a
+	    // socket directly.
+	    if (socketFactory == null) {
+	        socket = new Socket(host, port, localAddress, localPort);
+	    }
+	
+	    else {
+	        try {
+	            int socketFactoryPort = getIntProtocolProperty(MAIL_POP3_FACTORY_PORT, -1);
+	
+	            // we choose the port used by the socket based on overrides.
+	            Integer portArg = new Integer(socketFactoryPort == -1 ? port : socketFactoryPort);
+	
+	            // use the current context loader to resolve this.
+	            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+	            Class factoryClass = loader.loadClass(socketFactory);
+	
+	            // done indirectly, we need to invoke the method using
+	            // reflection.
+	            // This retrieves a factory instance.
+	            Method getDefault = factoryClass.getMethod("getDefault", new Class[0]);
+	            Object defFactory = getDefault.invoke(new Object(), new Object[0]);
+	
+	            // now that we have the factory, there are two different
+	            // createSocket() calls we use,
+	            // depending on whether we have a localAddress override.
+	
+	            if (localAddress != null) {
+	                // retrieve the createSocket(String, int, InetAddress, int)
+	                // method.
+	                Class[] createSocketSig = new Class[] { String.class, Integer.TYPE, InetAddress.class, Integer.TYPE };
+	                Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                Object[] createSocketArgs = new Object[] { host, portArg, localAddress, new Integer(localPort) };
+	                socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	            } else {
+	                // retrieve the createSocket(String, int) method.
+	                Class[] createSocketSig = new Class[] { String.class, Integer.TYPE };
+	                Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                Object[] createSocketArgs = new Object[] { host, portArg };
+	                socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	            }
+	        } catch (Throwable e) {
+	            // if a socket factory is specified, then we may need to fall
+	            // back to a default. This behavior
+	            // is controlled by (surprise) more session properties.
+	            if (isProtocolPropertyTrue(MAIL_POP3_FACTORY_FALLBACK)) {
+	                socket = new Socket(host, port, localAddress, localPort);
+	            }
+	            // we have an exception. We're going to throw an IOException,
+	            // which may require unwrapping
+	            // or rewrapping the exception.
+	            else {
+	                // we have an exception from the reflection, so unwrap the
+	                // base exception
+	                if (e instanceof InvocationTargetException) {
+	                    e = ((InvocationTargetException) e).getTargetException();
+	                }
+
+	
+	                // throw this as an IOException, with the original exception
+	                // attached.
+	                IOException ioe = new IOException("Error connecting to " + host + ", " + port);
+	                ioe.initCause(e);
+	                throw ioe;
+	            }
+	        }
+	    }
+	
+	    if (timeout >= 0) {
+	        socket.setSoTimeout(timeout);
+	    }
+	}
+
+	/**
+	 * Creates a connected SSL socket for an initial SSL connection.
+	 *
+	 * @exception MessagingException
+	 */
+	protected void getConnectedSSLSocket() throws IOException {
+
+	    if (session.getDebug()) {
+	        session.getDebugOut().println("Attempting SSL socket connection to server " + host + ":" + port);
+	    }
+	    // the socket factory can be specified via a protocol property, a
+	    // session property, and if all else
+	    // fails (which it usually does), we fall back to the standard factory
+	    // class.
+	    String socketFactory = getProtocolProperty(MAIL_POP3_FACTORY_CLASS, getSessionProperty(MAIL_SSLFACTORY_CLASS,
+	            "javax.net.ssl.SSLSocketFactory"));
+	
+	    // there are several protocol properties that can be set to tune the
+	    // created socket. We need to
+	    // retrieve those bits before creating the socket.
+	    int timeout = getIntProtocolProperty(MAIL_POP3_TIMEOUT, -1);
+	    InetAddress localAddress = null;
+	    // see if we have a local address override.
+	    String localAddrProp = getProtocolProperty(MAIL_POP3_LOCALADDRESS);
+	    if (localAddrProp != null) {
+	        localAddress = InetAddress.getByName(localAddrProp);
+	    }
+	
+	    // check for a local port...default is to allow socket to choose.
+	    int localPort = getIntProtocolProperty(MAIL_POP3_LOCALPORT, 0);
+	
+	    socket = null;
+	
+	    // if there is no socket factory defined (normal), we just create a
+	    // socket directly.
+	    if (socketFactory == null) {
+	    	System.out.println("SocketFactory was null so creating the connection using a default");
+	        socket = new Socket(host, port, localAddress, localPort);
+	    }
+	
+	    else {
+	        // we'll try this with potentially two different factories if we're
+	        // allowed to fall back.
+	        boolean fallback = isProtocolPropertyTrue(MAIL_POP3_FACTORY_FALLBACK);
+	        while(true) {
+	            try {
+	            	
+	            	
+	            	if (socket != null) {
+	            		if (socket.isConnected())
+	            		break;
+	            	}
+	            	
+	                if (session.getDebug()) {
+	                    session.getDebugOut().println("Creating SSL socket using factory " + socketFactory);
+	                }
+	                
+	                int socketFactoryPort = getIntProtocolProperty(MAIL_POP3_FACTORY_PORT, -1);
+	
+	                // we choose the port used by the socket based on overrides.
+	                Integer portArg = new Integer(socketFactoryPort == -1 ? port : socketFactoryPort);
+	
+	                // use the current context loader to resolve this.
+	                ClassLoader loader = Thread.currentThread().getContextClassLoader();
+	                Class factoryClass = loader.loadClass(socketFactory);
+	
+	                // done indirectly, we need to invoke the method using
+	                // reflection.
+	                // This retrieves a factory instance.
+	                Method getDefault = factoryClass.getMethod("getDefault", new Class[0]);
+	                Object defFactory = getDefault.invoke(new Object(), new Object[0]);
+	
+	                // now that we have the factory, there are two different
+	                // createSocket() calls we use,
+	                // depending on whether we have a localAddress override.
+	
+	                if (localAddress != null) {
+	                    // retrieve the createSocket(String, int, InetAddress,
+	                    // int) method.
+	                    Class[] createSocketSig = new Class[] { String.class, Integer.TYPE, InetAddress.class,
+	                            Integer.TYPE };
+	                    Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                    Object[] createSocketArgs = new Object[] { host, portArg, localAddress, new Integer(localPort) };
+	                    socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	                } else {
+	                    // retrieve the createSocket(String, int) method.
+	                    Class[] createSocketSig = new Class[] { String.class, Integer.TYPE };
+	                    Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                    Object[] createSocketArgs = new Object[] { host, portArg };
+	                    socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	                }
+	            } catch (Throwable e) {
+	                // if we're allowed to fallback, then use the default
+	                // factory and try this again. We only
+	                // allow this to happen once.
+                    if (session.getDebug()) {
+                        session.getDebugOut().println("First attempt at creating SSL socket failed, falling back to default factory");
+                    }
+	                if (fallback) {
+	                    socketFactory = "javax.net.ssl.SSLSocketFactory";
+	                    fallback = false;
+	                    continue;
+	                }
+	                // we have an exception. We're going to throw an
+	                // IOException, which may require unwrapping
+	                // or rewrapping the exception.
+	                else {
+	                    // we have an exception from the reflection, so unwrap
+	                    // the base exception
+	                    if (e instanceof InvocationTargetException) {
+	                        e = ((InvocationTargetException) e).getTargetException();
+	                    }
+	
+	                    if (session.getDebug()) {
+	                        session.getDebugOut().println("Failure creating SSL socket: " + e);
+	                    }
+	                    // throw this as an IOException, with the original
+	                    // exception attached.
+	                    IOException ioe = new IOException("Error connecting to " + host + ", " + port);
+	                    ioe.initCause(e);
+	                    throw ioe;
+	                }
+	            }
+	        }
+	    }
+	
+	    if (timeout >= 0) {
+	        socket.setSoTimeout(timeout);
+	    }
+	}
+	
+    /**
+     * Process a session property as a boolean value, returning either true or
+     * false.
+     *
+     * @return True if the property value is "true". Returns false for any other
+     *         value (including null).
+     */
+    protected boolean isProtocolPropertyTrue(String name) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol ("pop3").
+        String fullName = "mail." + protocol + "." + name;
+        return isSessionPropertyTrue(fullName);
+    }
+
+    /**
+     * Process a session property as a boolean value, returning either true or
+     * false.
+     *
+     * @return True if the property value is "true". Returns false for any other
+     *         value (including null).
+     */
+    protected boolean isSessionPropertyTrue(String name) {
+        String property = session.getProperty(name);
+        if (property != null) {
+            return property.equals("true");
+        }
+        return false;
+    }
+    
+    /**
+     * Get a property associated with this mail session as an integer value.
+     * Returns the default value if the property doesn't exist or it doesn't
+     * have a valid int value.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value converted to an int.
+     */
+    protected int getIntProtocolProperty(String name, int defaultValue) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol (pop3).
+        String fullName = "mail." + protocol + "." + name;
+        return getIntSessionProperty(fullName, defaultValue);
+    }
+    
+    /**
+     * Get a property associated with this mail session as an integer value.
+     * Returns the default value if the property doesn't exist or it doesn't
+     * have a valid int value.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value converted to an int.
+     */
+    protected int getIntSessionProperty(String name, int defaultValue) {
+        String result = getSessionProperty(name);
+        if (result != null) {
+            try {
+                // convert into an int value.
+                return Integer.parseInt(result);
+            } catch (NumberFormatException e) {
+            }
+        }
+        // return default value if it doesn't exist is isn't convertable.
+        return defaultValue;
+    }
+
+    /**
+     * Get a property associated with this mail session. Returns the provided
+     * default if it doesn't exist.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value (returns defaultValue if the property has not
+     *         been set).
+     */
+    protected String getSessionProperty(String name, String defaultValue) {
+        String result = session.getProperty(name);
+        if (result == null) {
+            return defaultValue;
+        }
+        return result;
+    }
+
+    /**
+     * Get a property associated with this mail session. Returns the provided
+     * default if it doesn't exist.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value (returns defaultValue if the property has not
+     *         been set).
+     */
+    protected String getProtocolProperty(String name, String defaultValue) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol ("pop3").
+        String fullName = "mail." + protocol + "." + name;
+        return getSessionProperty(fullName, defaultValue);
+    }
+    
+    /**
+     * Get a property associated with this mail protocol.
+     *
+     * @param name
+     *            The name of the property.
+     *
+     * @return The property value (returns null if the property has not been
+     *         set).
+     */
+    protected String getProtocolProperty(String name) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol ("pop3").
+        String fullName = "mail." + protocol + "." + name;
+        return getSessionProperty(fullName);
+    }
+
+    /**
+     * Get a property associated with this mail session.
+     *
+     * @param name
+     *            The name of the property.
+     *
+     * @return The property value (returns null if the property has not been
+     *         set).
+     */
+    protected String getSessionProperty(String name) {
+        return session.getProperty(name);
     }
 }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java Thu Dec  7 14:05:25 2006
@@ -39,4 +39,6 @@
     public final static int OK = 0;
 
     public final static int ERR = 1;
+    
+    public final static int CHALLENGE = 2;
 }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java Thu Dec  7 14:05:25 2006
@@ -33,9 +33,10 @@
 public interface POP3Response {
 
     /**
-     * Returns the response OK or ERR
+     * Returns the response OK, CHALLENGE or ERR
      * <ul>
      * <li>OK --> +OK in pop3 spec
+     * <li>CHALLENGE --> + in pop3 spec
      * <li>ERR --> -ERR in pop3 spec
      * </ul>
      */

Modified: geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java Thu Dec  7 14:05:25 2006
@@ -76,6 +76,12 @@
         } else if (line.startsWith("-ERR")) {
             status = ERR;
             line = removeStatusField(line);
+        }else if (line.startsWith("+")) {
+        	status = CHALLENGE;
+        	line = removeStatusField(line);
+        	if (isMultiLineResponse) {
+        		data = getMultiLineResponse(session, reader);
+        	}
         } else {
             throw new MessagingException("Unexpected response: " + line);
         }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.3.1_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java Thu Dec  7 14:05:25 2006
@@ -37,11 +37,45 @@
 
     private POP3Connection pop3Con;
 
-    public POP3Store(Session session, URLName urlName) {
-        super(session, urlName);
+    protected static final int DEFAULT_MAIL_POP3_PORT = 110;
+    private boolean sslConnection;
+    private int defaultPort;
+    
+    private String protocol;
+    public POP3Store(Session session, URLName name) {
+        this(session, name, "pop3", DEFAULT_MAIL_POP3_PORT, false);
     }
 
     /**
+     * Common constructor used by the POP3Store and POP3SSLStore classes
+     * to do common initialization of defaults.
+     *
+     * @param session
+     *            The host session instance.
+     * @param name
+     *            The URLName of the target.
+     * @param protocol
+     *            The protocol type ("pop3"). This helps us in
+     *            retrieving protocol-specific session properties.
+     * @param defaultPort
+     *            The default port used by this protocol. For pop3, this will
+     *            be 110. The default for pop3 with ssl is 995.
+     * @param sslConnection
+     *            Indicates whether an SSL connection should be used to initial
+     *            contact the server. This is different from the STARTTLS
+     *            support, which switches the connection to SSL after the
+     *            initial startup.
+     */
+    protected POP3Store(Session session, URLName name, String protocol, int defaultPort, boolean sslConnection) {
+        super(session, name);
+        this.protocol = protocol;
+
+        // these are defaults based on what the superclass specifies.
+        this.sslConnection = sslConnection;
+        this.defaultPort = defaultPort;
+
+    }
+    /**
      * @see javax.mail.Store#getDefaultFolder()
      * 
      * There is only INBOX supported in POP3 so the default folder is inbox
@@ -91,7 +125,7 @@
                 try {
                     portNum = Integer.parseInt(portstring);
                 } catch (NumberFormatException e) {
-                    portNum = 110;
+                    portNum = defaultPort;
                 }
             }
         }
@@ -100,7 +134,7 @@
          * Obtaining a connection to the server.
          * 
          */
-        pop3Con = new POP3Connection(this.session, host, portNum);
+        pop3Con = new POP3Connection(this.session, host, portNum, sslConnection, protocol);
         try {
             pop3Con.open();
         } catch (Exception e) {

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java Thu Dec  7 14:05:25 2006
@@ -184,5 +184,52 @@
             }
         };
     }
+    
+    public static POP3Command getCOMMAND_CAPA() {
+    	return new POP3Command() {
+    		public String getCommand() {
+                return "CAPA" + CRLF;
+    		}
+    		
+    		public boolean isMultiLineResponse() {
+    			return true;
+    		}
+    	};
+    }
 
+    public static POP3Command getCOMMAND_AUTH(final String protocol) {
+    	return new POP3Command() {
+    		public String getCommand() {
+    			return "AUTH " + protocol + CRLF;
+    		}
+    		
+    		public boolean isMultiLineResponse() {
+    			return false;
+    		}
+    	};
+    }
+    
+    public static POP3Command getCOMMAND_AUTH(final String protocol, final String initialResponse) {
+    	return new POP3Command() {
+    		public String getCommand() {
+    			return "AUTH " + protocol + " " + initialResponse + CRLF;
+    		}
+    		
+    		public boolean isMultiLineResponse() {
+    			return false;
+    		}
+    	};
+    }
+    
+    public static POP3Command getCOMMAND_ChallengeReply(final String command) {
+    	return new POP3Command() {
+    			public String getCommand() {
+   						return command + CRLF;
+   				}
+    			
+    			public boolean isMultiLineResponse() {
+    				return false;
+    			}	
+    		};
+    }
 }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java Thu Dec  7 14:05:25 2006
@@ -24,7 +24,9 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.net.InetSocketAddress;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
 import java.net.Socket;
 
 import javax.mail.MessagingException;
@@ -38,9 +40,24 @@
  * @version $Rev$ $Date$
  */
 
+
 public class POP3Connection {
 
-    private Socket soc;
+	protected static final String MAIL_SSLFACTORY_CLASS = "mail.SSLSocketFactory.class";
+	
+    protected static final String MAIL_POP3_FACTORY_CLASS = "socketFactory.class";
+
+    protected static final String MAIL_POP3_FACTORY_FALLBACK = "socketFactory.fallback";
+
+    protected static final String MAIL_POP3_FACTORY_PORT = "socketFactory.port";
+    
+    protected static final String MAIL_POP3_LOCALADDRESS = "localAddress";
+    
+    protected static final String MAIL_POP3_LOCALPORT = "localPort";
+    
+    protected static final String MAIL_POP3_TIMEOUT = "timeout";
+	
+    private Socket socket;
 
     private Session session;
 
@@ -51,18 +68,28 @@
     private PrintWriter writer;
 
     private BufferedReader reader;
+    
+    private String protocol;
+    
+    private boolean sslConnection;
 
-    POP3Connection(Session session, String host, int port) {
+    POP3Connection(Session session, String host, int port, boolean sslConnection, String protocol) {
 
         this.session = session;
         this.host = host;
         this.port = port;
+        this.sslConnection = sslConnection;
+        this.protocol = protocol;
     }
 
     public void open() throws Exception {
         try {
-            soc = new Socket();
-            soc.connect(new InetSocketAddress(host, port));
+
+        	if (!sslConnection) {
+        		getConnectedSocket();
+        	} else {
+        		getConnectedSSLSocket();
+        	}
 
             if (session.getDebug()) {
                 session.getDebugOut().println("Connection successful " + this.toString());
@@ -86,7 +113,7 @@
 
     void close() throws Exception {
         try {
-            soc.close();
+            socket.close();
             if (session.getDebug()) {
                 session.getDebugOut().println("Connection successfuly closed " + this.toString());
             }
@@ -99,17 +126,17 @@
     }
 
     public synchronized POP3Response sendCommand(POP3Command cmd) throws MessagingException {
-        if (soc.isConnected()) {
+        if (socket.isConnected()) {
 
             // if the underlying output stream is down
             // attempt to rebuild the writer
-            if (soc.isOutputShutdown()) {
+            if (socket.isOutputShutdown()) {
                 buildOutputWriter();
             }
 
             // if the underlying inout stream is down
             // attempt to rebuild the reader
-            if (soc.isInputShutdown()) {
+            if (socket.isInputShutdown()) {
                 buildInputReader();
             }
 
@@ -135,7 +162,7 @@
 
     private void buildInputReader() throws MessagingException {
         try {
-            reader = new BufferedReader(new InputStreamReader(soc.getInputStream()));
+            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
         } catch (IOException e) {
             throw new MessagingException("Error obtaining input stream " + this.toString(), e);
         }
@@ -143,7 +170,7 @@
 
     private void buildOutputWriter() throws MessagingException {
         try {
-            writer = new PrintWriter(new BufferedOutputStream(soc.getOutputStream()));
+            writer = new PrintWriter(new BufferedOutputStream(socket.getOutputStream()));
         } catch (IOException e) {
             throw new MessagingException("Error obtaining output stream " + this.toString(), e);
         }
@@ -151,5 +178,387 @@
 
     public String toString() {
         return "POP3Connection host: " + host + " port: " + port;
+    }
+
+
+	/**
+	 * Creates a connected socket
+	 *
+	 * @exception MessagingException
+	 */
+	protected void getConnectedSocket() throws IOException {
+	
+	    // the socket factory can be specified via a session property. By
+	    // default, we just directly
+	    // instantiate a socket without using a factor.
+	    String socketFactory = getProtocolProperty(MAIL_POP3_FACTORY_CLASS);
+	
+	    // there are several protocol properties that can be set to tune the
+	    // created socket. We need to
+	    // retrieve those bits before creating the socket.
+	    int timeout = getIntProtocolProperty(MAIL_POP3_TIMEOUT, -1);
+	    InetAddress localAddress = null;
+	    // see if we have a local address override.
+	    String localAddrProp = getProtocolProperty(MAIL_POP3_LOCALADDRESS);
+	    if (localAddrProp != null) {
+	        localAddress = InetAddress.getByName(localAddrProp);
+	    }
+	
+	    // check for a local port...default is to allow socket to choose.
+	    int localPort = getIntProtocolProperty(MAIL_POP3_LOCALPORT, 0);
+	
+	    socket = null;
+	
+	    // if there is no socket factory defined (normal), we just create a
+	    // socket directly.
+	    if (socketFactory == null) {
+	        socket = new Socket(host, port, localAddress, localPort);
+	    }
+	
+	    else {
+	        try {
+	            int socketFactoryPort = getIntProtocolProperty(MAIL_POP3_FACTORY_PORT, -1);
+	
+	            // we choose the port used by the socket based on overrides.
+	            Integer portArg = new Integer(socketFactoryPort == -1 ? port : socketFactoryPort);
+	
+	            // use the current context loader to resolve this.
+	            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+	            Class factoryClass = loader.loadClass(socketFactory);
+	
+	            // done indirectly, we need to invoke the method using
+	            // reflection.
+	            // This retrieves a factory instance.
+	            Method getDefault = factoryClass.getMethod("getDefault", new Class[0]);
+	            Object defFactory = getDefault.invoke(new Object(), new Object[0]);
+	
+	            // now that we have the factory, there are two different
+	            // createSocket() calls we use,
+	            // depending on whether we have a localAddress override.
+	
+	            if (localAddress != null) {
+	                // retrieve the createSocket(String, int, InetAddress, int)
+	                // method.
+	                Class[] createSocketSig = new Class[] { String.class, Integer.TYPE, InetAddress.class, Integer.TYPE };
+	                Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                Object[] createSocketArgs = new Object[] { host, portArg, localAddress, new Integer(localPort) };
+	                socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	            } else {
+	                // retrieve the createSocket(String, int) method.
+	                Class[] createSocketSig = new Class[] { String.class, Integer.TYPE };
+	                Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                Object[] createSocketArgs = new Object[] { host, portArg };
+	                socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	            }
+	        } catch (Throwable e) {
+	            // if a socket factory is specified, then we may need to fall
+	            // back to a default. This behavior
+	            // is controlled by (surprise) more session properties.
+	            if (isProtocolPropertyTrue(MAIL_POP3_FACTORY_FALLBACK)) {
+	                socket = new Socket(host, port, localAddress, localPort);
+	            }
+	            // we have an exception. We're going to throw an IOException,
+	            // which may require unwrapping
+	            // or rewrapping the exception.
+	            else {
+	                // we have an exception from the reflection, so unwrap the
+	                // base exception
+	                if (e instanceof InvocationTargetException) {
+	                    e = ((InvocationTargetException) e).getTargetException();
+	                }
+
+	
+	                // throw this as an IOException, with the original exception
+	                // attached.
+	                IOException ioe = new IOException("Error connecting to " + host + ", " + port);
+	                ioe.initCause(e);
+	                throw ioe;
+	            }
+	        }
+	    }
+	
+	    if (timeout >= 0) {
+	        socket.setSoTimeout(timeout);
+	    }
+	}
+
+	/**
+	 * Creates a connected SSL socket for an initial SSL connection.
+	 *
+	 * @exception MessagingException
+	 */
+	protected void getConnectedSSLSocket() throws IOException {
+
+	    if (session.getDebug()) {
+	        session.getDebugOut().println("Attempting SSL socket connection to server " + host + ":" + port);
+	    }
+	    // the socket factory can be specified via a protocol property, a
+	    // session property, and if all else
+	    // fails (which it usually does), we fall back to the standard factory
+	    // class.
+	    String socketFactory = getProtocolProperty(MAIL_POP3_FACTORY_CLASS, getSessionProperty(MAIL_SSLFACTORY_CLASS,
+	            "javax.net.ssl.SSLSocketFactory"));
+	
+	    // there are several protocol properties that can be set to tune the
+	    // created socket. We need to
+	    // retrieve those bits before creating the socket.
+	    int timeout = getIntProtocolProperty(MAIL_POP3_TIMEOUT, -1);
+	    InetAddress localAddress = null;
+	    // see if we have a local address override.
+	    String localAddrProp = getProtocolProperty(MAIL_POP3_LOCALADDRESS);
+	    if (localAddrProp != null) {
+	        localAddress = InetAddress.getByName(localAddrProp);
+	    }
+	
+	    // check for a local port...default is to allow socket to choose.
+	    int localPort = getIntProtocolProperty(MAIL_POP3_LOCALPORT, 0);
+	
+	    socket = null;
+	
+	    // if there is no socket factory defined (normal), we just create a
+	    // socket directly.
+	    if (socketFactory == null) {
+	    	System.out.println("SocketFactory was null so creating the connection using a default");
+	        socket = new Socket(host, port, localAddress, localPort);
+	    }
+	
+	    else {
+	        // we'll try this with potentially two different factories if we're
+	        // allowed to fall back.
+	        boolean fallback = isProtocolPropertyTrue(MAIL_POP3_FACTORY_FALLBACK);
+	        while(true) {
+	            try {
+	            	
+	            	
+	            	if (socket != null) {
+	            		if (socket.isConnected())
+	            		break;
+	            	}
+	            	
+	                if (session.getDebug()) {
+	                    session.getDebugOut().println("Creating SSL socket using factory " + socketFactory);
+	                }
+	                
+	                int socketFactoryPort = getIntProtocolProperty(MAIL_POP3_FACTORY_PORT, -1);
+	
+	                // we choose the port used by the socket based on overrides.
+	                Integer portArg = new Integer(socketFactoryPort == -1 ? port : socketFactoryPort);
+	
+	                // use the current context loader to resolve this.
+	                ClassLoader loader = Thread.currentThread().getContextClassLoader();
+	                Class factoryClass = loader.loadClass(socketFactory);
+	
+	                // done indirectly, we need to invoke the method using
+	                // reflection.
+	                // This retrieves a factory instance.
+	                Method getDefault = factoryClass.getMethod("getDefault", new Class[0]);
+	                Object defFactory = getDefault.invoke(new Object(), new Object[0]);
+	
+	                // now that we have the factory, there are two different
+	                // createSocket() calls we use,
+	                // depending on whether we have a localAddress override.
+	
+	                if (localAddress != null) {
+	                    // retrieve the createSocket(String, int, InetAddress,
+	                    // int) method.
+	                    Class[] createSocketSig = new Class[] { String.class, Integer.TYPE, InetAddress.class,
+	                            Integer.TYPE };
+	                    Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                    Object[] createSocketArgs = new Object[] { host, portArg, localAddress, new Integer(localPort) };
+	                    socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	                } else {
+	                    // retrieve the createSocket(String, int) method.
+	                    Class[] createSocketSig = new Class[] { String.class, Integer.TYPE };
+	                    Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
+	
+	                    Object[] createSocketArgs = new Object[] { host, portArg };
+	                    socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
+	                }
+	            } catch (Throwable e) {
+	                // if we're allowed to fallback, then use the default
+	                // factory and try this again. We only
+	                // allow this to happen once.
+                    if (session.getDebug()) {
+                        session.getDebugOut().println("First attempt at creating SSL socket failed, falling back to default factory");
+                    }
+	                if (fallback) {
+	                    socketFactory = "javax.net.ssl.SSLSocketFactory";
+	                    fallback = false;
+	                    continue;
+	                }
+	                // we have an exception. We're going to throw an
+	                // IOException, which may require unwrapping
+	                // or rewrapping the exception.
+	                else {
+	                    // we have an exception from the reflection, so unwrap
+	                    // the base exception
+	                    if (e instanceof InvocationTargetException) {
+	                        e = ((InvocationTargetException) e).getTargetException();
+	                    }
+	
+	                    if (session.getDebug()) {
+	                        session.getDebugOut().println("Failure creating SSL socket: " + e);
+	                    }
+	                    // throw this as an IOException, with the original
+	                    // exception attached.
+	                    IOException ioe = new IOException("Error connecting to " + host + ", " + port);
+	                    ioe.initCause(e);
+	                    throw ioe;
+	                }
+	            }
+	        }
+	    }
+	
+	    if (timeout >= 0) {
+	        socket.setSoTimeout(timeout);
+	    }
+	}
+	
+    /**
+     * Process a session property as a boolean value, returning either true or
+     * false.
+     *
+     * @return True if the property value is "true". Returns false for any other
+     *         value (including null).
+     */
+    protected boolean isProtocolPropertyTrue(String name) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol ("pop3").
+        String fullName = "mail." + protocol + "." + name;
+        return isSessionPropertyTrue(fullName);
+    }
+
+    /**
+     * Process a session property as a boolean value, returning either true or
+     * false.
+     *
+     * @return True if the property value is "true". Returns false for any other
+     *         value (including null).
+     */
+    protected boolean isSessionPropertyTrue(String name) {
+        String property = session.getProperty(name);
+        if (property != null) {
+            return property.equals("true");
+        }
+        return false;
+    }
+    
+    /**
+     * Get a property associated with this mail session as an integer value.
+     * Returns the default value if the property doesn't exist or it doesn't
+     * have a valid int value.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value converted to an int.
+     */
+    protected int getIntProtocolProperty(String name, int defaultValue) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol (pop3).
+        String fullName = "mail." + protocol + "." + name;
+        return getIntSessionProperty(fullName, defaultValue);
+    }
+    
+    /**
+     * Get a property associated with this mail session as an integer value.
+     * Returns the default value if the property doesn't exist or it doesn't
+     * have a valid int value.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value converted to an int.
+     */
+    protected int getIntSessionProperty(String name, int defaultValue) {
+        String result = getSessionProperty(name);
+        if (result != null) {
+            try {
+                // convert into an int value.
+                return Integer.parseInt(result);
+            } catch (NumberFormatException e) {
+            }
+        }
+        // return default value if it doesn't exist is isn't convertable.
+        return defaultValue;
+    }
+
+    /**
+     * Get a property associated with this mail session. Returns the provided
+     * default if it doesn't exist.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value (returns defaultValue if the property has not
+     *         been set).
+     */
+    protected String getSessionProperty(String name, String defaultValue) {
+        String result = session.getProperty(name);
+        if (result == null) {
+            return defaultValue;
+        }
+        return result;
+    }
+
+    /**
+     * Get a property associated with this mail session. Returns the provided
+     * default if it doesn't exist.
+     *
+     * @param name
+     *            The name of the property.
+     * @param defaultValue
+     *            The default value to return if the property doesn't exist.
+     *
+     * @return The property value (returns defaultValue if the property has not
+     *         been set).
+     */
+    protected String getProtocolProperty(String name, String defaultValue) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol ("pop3").
+        String fullName = "mail." + protocol + "." + name;
+        return getSessionProperty(fullName, defaultValue);
+    }
+    
+    /**
+     * Get a property associated with this mail protocol.
+     *
+     * @param name
+     *            The name of the property.
+     *
+     * @return The property value (returns null if the property has not been
+     *         set).
+     */
+    protected String getProtocolProperty(String name) {
+        // the name we're given is the least qualified part of the name. We
+        // construct the full property name
+        // using the protocol ("pop3").
+        String fullName = "mail." + protocol + "." + name;
+        return getSessionProperty(fullName);
+    }
+
+    /**
+     * Get a property associated with this mail session.
+     *
+     * @param name
+     *            The name of the property.
+     *
+     * @return The property value (returns null if the property has not been
+     *         set).
+     */
+    protected String getSessionProperty(String name) {
+        return session.getProperty(name);
     }
 }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java Thu Dec  7 14:05:25 2006
@@ -39,4 +39,6 @@
     public final static int OK = 0;
 
     public final static int ERR = 1;
+    
+    public final static int CHALLENGE = 2;
 }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java Thu Dec  7 14:05:25 2006
@@ -33,9 +33,10 @@
 public interface POP3Response {
 
     /**
-     * Returns the response OK or ERR
+     * Returns the response OK, CHALLENGE or ERR
      * <ul>
      * <li>OK --> +OK in pop3 spec
+     * <li>CHALLENGE --> + in pop3 spec
      * <li>ERR --> -ERR in pop3 spec
      * </ul>
      */

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java Thu Dec  7 14:05:25 2006
@@ -76,6 +76,12 @@
         } else if (line.startsWith("-ERR")) {
             status = ERR;
             line = removeStatusField(line);
+        }else if (line.startsWith("+")) {
+        	status = CHALLENGE;
+        	line = removeStatusField(line);
+        	if (isMultiLineResponse) {
+        		data = getMultiLineResponse(session, reader);
+        	}
         } else {
             throw new MessagingException("Unexpected response: " + line);
         }

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java?view=diff&rev=483693&r1=483692&r2=483693
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java Thu Dec  7 14:05:25 2006
@@ -37,11 +37,45 @@
 
     private POP3Connection pop3Con;
 
-    public POP3Store(Session session, URLName urlName) {
-        super(session, urlName);
+    protected static final int DEFAULT_MAIL_POP3_PORT = 110;
+    private boolean sslConnection;
+    private int defaultPort;
+    
+    private String protocol;
+    public POP3Store(Session session, URLName name) {
+        this(session, name, "pop3", DEFAULT_MAIL_POP3_PORT, false);
     }
 
     /**
+     * Common constructor used by the POP3Store and POP3SSLStore classes
+     * to do common initialization of defaults.
+     *
+     * @param session
+     *            The host session instance.
+     * @param name
+     *            The URLName of the target.
+     * @param protocol
+     *            The protocol type ("pop3"). This helps us in
+     *            retrieving protocol-specific session properties.
+     * @param defaultPort
+     *            The default port used by this protocol. For pop3, this will
+     *            be 110. The default for pop3 with ssl is 995.
+     * @param sslConnection
+     *            Indicates whether an SSL connection should be used to initial
+     *            contact the server. This is different from the STARTTLS
+     *            support, which switches the connection to SSL after the
+     *            initial startup.
+     */
+    protected POP3Store(Session session, URLName name, String protocol, int defaultPort, boolean sslConnection) {
+        super(session, name);
+        this.protocol = protocol;
+
+        // these are defaults based on what the superclass specifies.
+        this.sslConnection = sslConnection;
+        this.defaultPort = defaultPort;
+
+    }
+    /**
      * @see javax.mail.Store#getDefaultFolder()
      * 
      * There is only INBOX supported in POP3 so the default folder is inbox
@@ -91,7 +125,7 @@
                 try {
                     portNum = Integer.parseInt(portstring);
                 } catch (NumberFormatException e) {
-                    portNum = 110;
+                    portNum = defaultPort;
                 }
             }
         }
@@ -100,7 +134,7 @@
          * Obtaining a connection to the server.
          * 
          */
-        pop3Con = new POP3Connection(this.session, host, portNum);
+        pop3Con = new POP3Connection(this.session, host, portNum, sslConnection, protocol);
         try {
             pop3Con.open();
         } catch (Exception e) {