geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rickmcgu...@apache.org
Subject svn commit: r597135 [1/2] - in /geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main: java/org/apache/geronimo/javamail/store/imap/ java/org/apache/geronimo/javamail/store/imap/connection/ java/org/apache/geronimo/javam...
Date Wed, 21 Nov 2007 16:26:59 GMT
Author: rickmcguire
Date: Wed Nov 21 08:26:57 2007
New Revision: 597135

URL: http://svn.apache.org/viewvc?rev=597135&view=rev
Log:
GERONIMO-3623 javamail POP3 implementation has numerous incompatibilities with Sun impl.


Added:
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3Connection.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3ConnectionPool.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3ListResponse.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3Response.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/connection/POP3StatusResponse.java   (with props)
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MIMEInputReader.java   (with props)
Removed:
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Command.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3CommandFactory.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Connection.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Response.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3ResponseBuilder.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/message/
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/response/
Modified:
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPSSLStore.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnectionPool.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
    geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPSSLStore.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPSSLStore.java?rev=597135&r1=597134&r2=597135&view=diff
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPSSLStore.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/IMAPSSLStore.java Wed Nov 21 08:26:57 2007
@@ -22,9 +22,7 @@
 import javax.mail.URLName;
 
 /**
- * IMAP implementation of javax.mail.Store
- * POP protocol spec is implemented in
- * org.apache.geronimo.javamail.store.pop3.IMAPConnection
+ * IMAP implementation of javax.mail.Store for SSL connections. 
  *
  * @version $Rev$ $Date$
  */

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java?rev=597135&r1=597134&r2=597135&view=diff
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnection.java Wed Nov 21 08:26:57 2007
@@ -101,18 +101,10 @@
 
     /**
      * Normal constructor for an IMAPConnection() object.
-     *
-     * @param store    The store we're associated with (source of parameter values).
-     * @param host     The target host name of the IMAP server.
-     * @param port     The target listening port of the server.  Defaults to 119 if
-     *                 the port is specified as -1.
-     * @param username The login user name (can be null unless authentication is
-     *                 required).
-     * @param password Password associated with the userid account.  Can be null if
-     *                 authentication is not required.
-     * @param sslConnection
-     *                 True if this is targetted as an SSLConnection.
-     * @param debug    The session debug flag.
+     * 
+     * @param props  The protocol properties abstraction containing our
+     *               property modifiers.
+     * @param pool
      */
     public IMAPConnection(ProtocolProperties props, IMAPConnectionPool pool) {
         super(props);

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnectionPool.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnectionPool.java?rev=597135&r1=597134&r2=597135&view=diff
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnectionPool.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/imap/connection/IMAPConnectionPool.java Wed Nov 21 08:26:57 2007
@@ -90,26 +90,19 @@
     protected Map capabilities; 
 
     /**
-     * Create a connection pool associated with a give IMAPStore instance.  The 
-     * connection pool manages handing out connections for both the Store and 
-     * Folder and Message usage.  
+     * Create a connection pool associated with a give IMAPStore instance.  The
+     * connection pool manages handing out connections for both the Store and
+     * Folder and Message usage.
      * 
-     * Depending on the session properties, the Store may be given a dedicated 
-     * connection, or will share connections with the Folders.  Connections may 
-     * be requested from either the Store or Folders.  Messages must request 
-     * their connections from their hosting Folder, and only one connection is 
-     * allowed per folder. 
+     * Depending on the session properties, the Store may be given a dedicated
+     * connection, or will share connections with the Folders.  Connections may
+     * be requested from either the Store or Folders.  Messages must request
+     * their connections from their hosting Folder, and only one connection is
+     * allowed per folder.
      * 
-     * @param store   The Store we're creating the pool for.
-     * @param session The Session this Store is created under.  This contains the properties
-     *                we used to tailor behavior.
-     * @param sslConnection
-     *                Indicates whether we need to start connections using an SSL connection.
-     * @param defaultPort
-     *                The default port.  Used if we receive a -1 port value on the initial
-     *                connection request.
-     * @param debug   The debug flag.  Tells us whether to wrapper connections with debug
-     *                capture streams.
+     * @param store  The Store we're creating the pool for.
+     * @param props  The property bundle that defines protocol properties
+     *               that alter the connection behavior.
      */
     public IMAPConnectionPool(IMAPStore store, ProtocolProperties props) {
         this.store = store;

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/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/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java?rev=597135&r1=597134&r2=597135&view=diff
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java Wed Nov 21 08:26:57 2007
@@ -30,10 +30,6 @@
 
     public final static String CRLF = "\r\n";
 
-    public final static int LF = '\n';
-
-    public final static int CR = '\r';
-
     public final static int DOT = '.';
 
     public final static int OK = 0;

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java?rev=597135&r1=597134&r2=597135&view=diff
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java Wed Nov 21 08:26:57 2007
@@ -19,11 +19,12 @@
 
 package org.apache.geronimo.javamail.store.pop3;
 
-import java.util.Vector;
+import java.util.List;     
 
 import javax.mail.FetchProfile;
 import javax.mail.Flags;
 import javax.mail.Folder;
+import javax.mail.FolderClosedException;
 import javax.mail.Message;
 import javax.mail.MessagingException;
 import javax.mail.MethodNotSupportedException;
@@ -32,10 +33,8 @@
 import javax.mail.URLName;
 import javax.mail.event.ConnectionEvent;
 
-import org.apache.geronimo.javamail.store.pop3.message.POP3Message;
-import org.apache.geronimo.javamail.store.pop3.message.POP3MessageFactory;
-import org.apache.geronimo.javamail.store.pop3.response.POP3ResponseFactory;
-import org.apache.geronimo.javamail.store.pop3.response.POP3StatusResponse;
+import org.apache.geronimo.javamail.store.pop3.connection.POP3Connection; 
+import org.apache.geronimo.javamail.store.pop3.connection.POP3StatusResponse; 
 
 /**
  * The POP3 implementation of the javax.mail.Folder Note that only INBOX is
@@ -50,53 +49,90 @@
  */
 public class POP3Folder extends Folder {
 
-    private boolean isFolderOpen = false;
+    protected boolean isFolderOpen = false;
 
-    private int mode;
+    protected int mode;
 
-    private POP3Connection pop3Con;
+    protected POP3Connection currentConnection; 
 
-    private int msgCount;
-
-    private Session session;
+    protected int msgCount;
 
+    private POP3Message[] messageCache; 
+    // The fully qualified name of the folder.  For a POP3 folder, this is either "" for the root or 
+    // "INPUT" for the in-basket.  It is possible to create other folders, but they will report that 
+    // they don't exist. 
+    protected String fullName;  
+    // indicates whether this folder exists or not 
+    protected boolean exists = false; 
+    // indicates the type of folder this is. 
+    protected int folderType; 
+    
     /**
-     * Vector is synchronized so choose over the other Collection impls This is
-     * initialized on open A chache will save the expensive operation of
-     * retrieving the message again from the server.
+     * Create a new folder associate with a POP3 store instance.
+     * 
+     * @param store  The owning Store.
+     * @param name   The name of the folder.  Note that POP3 stores only
+     *               have 2 real folders, the root ("") and the in-basket
+     *               ("INBOX").  It is possible to create other instances
+     *               of Folder associated with the Store, but they will
+     *               be non-functional.
      */
-    private Vector msgCache;
-
-    protected POP3Folder(Store store, URLName url) {
-        super(store);
-    }
-
-    protected POP3Folder(Store store, Session session, POP3Connection pop3Con) {
+     public POP3Folder(POP3Store store, String name) {
         super(store);
-        this.pop3Con = pop3Con;
-        this.session = session;
-    }
-
-    public String getName() {
-        return "INBOX";
+        this.fullName = name; 
+        // if this is the input folder, this exists 
+        if (name.equalsIgnoreCase("INPUT")) {
+            exists = true; 
+        }
+        // by default, we're holding messages. 
+        folderType = Folder.HOLDS_MESSAGES; 
     }
+    
+    
+    /**
+     * Retrieve the folder name.  This is the simple folder
+     * name at the its hiearchy level.  This can be invoked when the folder is closed.
+     * 
+     * @return The folder's name.
+     */
+	public String getName() {
+        // the name and the full name are always the same
+        return fullName; 
+	}
 
-    public String getFullName() {
-        return "INBOX";
-    }
+    /**
+     * Retrieve the folder's full name (including hierarchy information).
+     * This can be invoked when the folder is closed.
+     *
+     * @return The full name value.
+     */
+	public String getFullName() {
+        return fullName;
+	}
 
+    
     /**
      * Never return "this" as the parent folder. Somebody not familliar with
      * POP3 may do something like while(getParent() != null) or something
      * simmilar which will result in an infinte loop
      */
     public Folder getParent() throws MessagingException {
-        throw new MethodNotSupportedException("INBOX is the root folder");
+        // the default folder returns null.  We return the default 
+        // folder 
+        return store.getDefaultFolder(); 
     }
 
+    /**
+     * Indicate whether a folder exists.  Only the root 
+     * folder and "INBOX" will ever return true. 
+     * 
+     * @return true for real POP3 folders, false for any other 
+     *         instances that have been created.
+     * @exception MessagingException
+     */
     public boolean exists() throws MessagingException {
-        // INBOX always exists at the backend
-        return true;
+        // only one folder truely exists...this might be it.
+        return exists; 
     }
 
     public Folder[] list(String pattern) throws MessagingException {
@@ -104,22 +140,44 @@
     }
 
     /**
-     * No sub folders, hence there is no notion of a seperator
+     * No sub folders, hence there is no notion of a seperator.  This is always a null character. 
      */
     public char getSeparator() throws MessagingException {
-        throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
+        return '\0';
     }
 
+    /**
+     * There's no hierarchy in POP3, so the only type 
+     * is HOLDS_MESSAGES (and only one of those exists).
+     * 
+     * @return Always returns HOLDS_MESSAGES. 
+     * @exception MessagingException
+     */
     public int getType() throws MessagingException {
-        return HOLDS_MESSAGES;
+        return folderType;      
     }
 
+    /**
+     * Always returns false as any creation operation must 
+     * fail. 
+     * 
+     * @param type   The type of folder to create.  This is ignored.
+     * 
+     * @return Always returns false. 
+     * @exception MessagingException
+     */
     public boolean create(int type) throws MessagingException {
-        throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
+        return false; 
     }
 
+    /**
+     * No way to detect new messages, so always return false. 
+     * 
+     * @return Always returns false. 
+     * @exception MessagingException
+     */
     public boolean hasNewMessages() throws MessagingException {
-        throw new MethodNotSupportedException("POP3 doesn't support this operation");
+        return false; 
     }
 
     public Folder getFolder(String name) throws MessagingException {
@@ -142,13 +200,14 @@
         checkClosed();
 
         try {
+            
+            // ask the store to kindly hook us up with a connection.
+            // We're going to hang on to this until we're closed, so store it in 
+            // the Folder field.  We need to make sure our mailbox is selected while 
+            // we're working things. 
+            currentConnection = ((POP3Store)store).getFolderConnection(this); 
 
-            POP3StatusResponse res = (POP3StatusResponse) POP3ResponseFactory.getStatusResponse(pop3Con
-                    .sendCommand(POP3CommandFactory.getCOMMAND_STAT()));
-
-            // I am not checking for the res == null condition as the
-            // try catch block will handle it.
-
+            POP3StatusResponse res = currentConnection.retrieveMailboxStatus();
             this.mode = mode;
             this.isFolderOpen = true;
             this.msgCount = res.getNumMessages();
@@ -156,11 +215,9 @@
             // size (no of bytes) of the mail drop;
 
             // NB:  We use the actual message number to access the messages from 
-            // the cache, which is origin 1.  Vectors are origin 0, so we add one additional 
-            // element and burn the 
-            msgCache = new Vector(msgCount + 1);
-            msgCache.setSize(msgCount + 1);
-
+            // the cache, which is origin 1.  Vectors are origin 0, so we have to subtract each time 
+            // we access a messagge.  
+            messageCache = new POP3Message[msgCount]; 
         } catch (Exception e) {
             throw new MessagingException("Unable to execute STAT command", e);
         }
@@ -168,57 +225,137 @@
         notifyConnectionListeners(ConnectionEvent.OPENED);
     }
 
+    /**
+     * Close a POP3 folder.
+     * 
+     * @param expunge The expunge flag (ignored for POP3).
+     * 
+     * @exception MessagingException
+     */
     public void close(boolean expunge) throws MessagingException {
         // Can only be performed on an open folder
         checkOpen();
-
         try {
-            if (mode == READ_WRITE) {
-                // find all messages marked deleted and issue DELE commands
-                POP3Message m;
-                // NB: the first element in the cache is not used.
-                for (int i = 1; i < msgCache.size(); i++) {
-                    if ((m = (POP3Message) msgCache.elementAt(i)) != null) {
-                        if (m.isSet(Flags.Flag.DELETED)) {
-                            try {
-                                pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_DELE(i + 1));
-                            } catch (Exception e) {
-                                throw new MessagingException("Exception deleting message no [" + (i + 1)
-                                        + "] during close", e);
-                            }
+            // we might need to reset the connection before we 
+            // process deleted messages and send the QUIT.  The 
+            // connection knows if we need to do this. 
+            currentConnection.reset(); 
+            // clean up any messages marked for deletion 
+            expungeDeletedMessages(); 
+        } finally {
+            // cleanup the the state even if exceptions occur when deleting the 
+            // messages. 
+            cleanupFolder(false); 
+        }
+    }
+    
+    /**
+     * Mark any messages we've flagged as deleted from the 
+     * IMAP server before closing. 
+     * 
+     * @exception MessagingException
+     */
+    protected void expungeDeletedMessages() throws MessagingException {
+        if (mode == READ_WRITE) {
+            for (int i = 0; i < messageCache.length; i++) {
+                POP3Message msg = messageCache[i]; 
+                if (msg != null) {
+                    // if the deleted flag is set, go delete this 
+                    // message. NB:  We adjust the index back to an 
+                    // origin 1 value 
+                    if (msg.isSet(Flags.Flag.DELETED)) {
+                        try {
+                            currentConnection.deleteMessage(i + 1); 
+                        } catch (MessagingException e) {
+                            throw new MessagingException("Exception deleting message number " + (i + 1), e); 
                         }
                     }
                 }
             }
-
-            try {
-                pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_QUIT());
-            } catch (Exception e) {
-                // doesn't really care about the response
+        }
+    }
+    
+    
+    /**
+     * Do folder cleanup.  This is used both for normal
+     * close operations, and adnormal closes where the
+     * server has sent us a BYE message.
+     * 
+     * @param expunge Indicates whether open messages should be expunged.
+     * @param disconnected
+     *                The disconnected flag.  If true, the server has cut
+     *                us off, which means our connection can not be returned
+     *                to the connection pool.
+     * 
+     * @exception MessagingException
+     */
+    protected void cleanupFolder(boolean disconnected) throws MessagingException {
+        messageCache = null;
+        isFolderOpen = false;
+        // if we have a connection active at the moment
+        if (currentConnection != null) {
+            // was this a forced disconnect by the server?
+            if (disconnected) {
+                currentConnection.setClosed(); 
             }
-            // dosn't need a catch block here, but added incase something goes
-            // wrong
-            // so that the finnaly is garunteed to execute in such a case.
-        } finally {
-            try {
-                pop3Con.close();
-            } catch (Exception e) {
-                // doesn't really care about the response
-                // all we can do is to set the reference explicitly to null
-                pop3Con = null;
+            else {
+                // have this close the selected mailbox 
+                currentConnection.logout();           
             }
-
-            /*
-             * The message numbers depend on the mail drop if the connection is
-             * closed, then purge the cache
-             */
-            msgCache = null;
-            isFolderOpen = false;
-            notifyConnectionListeners(ConnectionEvent.CLOSED);
+            // we need to release the connection to the Store once we're closed 
+            ((POP3Store)store).releaseFolderConnection(this, currentConnection); 
+            currentConnection = null; 
+        }
+		notifyConnectionListeners(ConnectionEvent.CLOSED);
+    }
+    
+    
+    /**
+     * Obtain a connection object for a Message attached to this Folder.  This 
+     * will be the Folder's connection, which is only available if the Folder 
+     * is currently open.
+     * 
+     * @return The connection object for the Message instance to use. 
+     * @exception MessagingException
+     */
+    synchronized POP3Connection getMessageConnection() throws MessagingException {
+        // if we're not open, the messages can't communicate either
+        if (currentConnection == null) {
+            throw new FolderClosedException(this, "No Folder connections available"); 
         }
+        // return the current Folder connection.  At this point, we'll be sharing the 
+        // connection between the Folder and the Message (and potentially, other messages).  The 
+        // command operations on the connection are synchronized so only a single command can be 
+        // issued at one time. 
+        return currentConnection; 
+    }
+    
+    
+    /**
+     * Release the connection object back to the Folder instance.  
+     * 
+     * @param connection The connection being released.
+     * 
+     * @exception MessagingException
+     */
+    void releaseMessageConnection(POP3Connection connection) throws MessagingException {
+        // This is a NOP for this folder type. 
     }
 
     public boolean isOpen() {
+        // if we're not open, we're not open 
+        if (!isFolderOpen) {
+            return false; 
+        }
+        
+        try {
+            // we might be open, but the Store has been closed.  In which case, we're not any more
+            // closing also changes the isFolderOpen flag. 
+            if (!((POP3Store)store).isConnected()) {
+                close(false); 
+            }
+        } catch (MessagingException e) {
+        }
         return isFolderOpen;
     }
 
@@ -233,7 +370,14 @@
         return new Flags();
     }
 
+    /**
+     * Get the folder message count.
+     * 
+     * @return The number of messages in the folder.
+     * @exception MessagingException
+     */
     public int getMessageCount() throws MessagingException {
+        // NB: returns -1 if the folder isn't open. 
         return msgCount;
     }
 
@@ -250,15 +394,10 @@
             throw new MessagingException("Invalid Message number");
         }
 
-        Message msg = null;
-        try {
-            msg = (Message) msgCache.elementAt(msgNum);
-        } catch (RuntimeException e) {
-            session.getDebugOut().println("Message not in cache");
-        }
+        Message msg = messageCache[msgNum - 1];
         if (msg == null) {
-            msg = POP3MessageFactory.createMessage(this, session, pop3Con, msgNum);
-            msgCache.setElementAt(msg, msgNum);
+            msg = new POP3Message(this, msgNum); 
+            messageCache[msgNum - 1] = (POP3Message)msg; 
         }
 
         return msg;
@@ -286,29 +425,50 @@
      * The JavaMail API recommends that this method be overrident to provide a
      * meaningfull implementation.
      */
-    public void fetch(Message[] msgs, FetchProfile fp) throws MessagingException {
+    public synchronized void fetch(Message[] msgs, FetchProfile fp) throws MessagingException {
         // Can only be performed on an Open folder
         checkOpen();
         for (int i = 0; i < msgs.length; i++) {
             Message msg = msgs[i];
-            if (msg == null) {
-                msg = POP3MessageFactory.createMessage(this, session, pop3Con, i);
-            }
+            
             if (fp.contains(FetchProfile.Item.ENVELOPE)) {
-                msg = POP3MessageFactory.createMessageWithEvelope((POP3Message) msg);
+                // fetching the size and the subject will force all of the 
+                // envelope information to load 
+                msg.getHeader("Subject"); 
+                msg.getSize(); 
             }
-
             if (fp.contains(FetchProfile.Item.CONTENT_INFO)) {
-                msg = POP3MessageFactory.createMessageWithContentInfo((POP3Message) msg);
+                // force the content to load...this also fetches the header information. 
+                // C'est la vie. 
+                ((POP3Message)msg).loadContent(); 
+                msg.getSize(); 
             }
-
+            // force flag loading for this message 
             if (fp.contains(FetchProfile.Item.FLAGS)) {
-                msg = POP3MessageFactory.createMessageWithFlags((POP3Message) msg);
+                msg.getFlags(); 
+            }
+            
+            if (fp.getHeaderNames().length > 0) {
+                // loading any header loads all headers, so just grab the header set. 
+                msg.getHeader("Subject"); 
             }
-
-            msgs[i] = msg;
         }
     }
+    
+    /**
+     * Retrieve the UID for a given message.
+     * 
+     * @param msg    The message of interest.
+     * 
+     * @return The String UID value for this message.
+     * @exception MessagingException
+     */
+    public synchronized String getUID(Message msg) throws MessagingException {
+        checkOpen(); 
+        // the Message knows how to do this 
+        return ((POP3Message)msg).getUID(); 
+    }
+    
 
     /**
      * Below is a list of covinience methods that avoid repeated checking for a

Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java?rev=597135&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java Wed Nov 21 08:26:57 2007
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.geronimo.javamail.store.pop3;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+
+import javax.mail.Flags;
+import javax.mail.Folder;
+import javax.mail.IllegalWriteException;
+import javax.mail.MessagingException;
+import javax.mail.event.MessageChangedEvent;
+import javax.mail.internet.InternetHeaders;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.geronimo.javamail.store.pop3.connection.POP3Connection;
+
+/**
+ * POP3 implementation of javax.mail.internet.MimeMessage
+ * 
+ * Only the most basic information is given and Message objects created here is
+ * a light-weight reference to the actual Message As per the JavaMail spec items
+ * from the actual message will get filled up on demand
+ * 
+ * If some other items are obtained from the server as a result of one call,
+ * then the other details are also processed and filled in. For ex if RETR is
+ * called then header information will also be processed in addition to the
+ * content
+ * 
+ * @version $Rev$ $Date$
+ */
+public class POP3Message extends MimeMessage {
+    // the size of the message, in bytes
+    protected int msgSize = -1;
+    // the size of the headers.  We keep this around, as it's needed to 
+    // properly calculate the size of the message 
+    protected int headerSize = -1;
+    // the UID value retrieved from the server 
+    protected String uid; 
+    // the raw message data from loading the message
+    protected byte[] messageData; 
+
+    /**
+     * Create a new POP3 message associated with a folder.
+     * 
+     * @param folder The owning folder.
+     * @param msgnum The message sequence number in the folder.
+     */
+    protected POP3Message(Folder folder, int msgnum) {
+        super(folder, msgnum);
+        this.session = session;
+        // force the headers to empty so we'll load them the first time they're referenced. 
+        this.headers = null; 
+    }
+
+    /**
+     * Get an InputStream for reading the message content. 
+     * 
+     * @return An InputStream instance initialized to read the message 
+     *         content.
+     * @exception MessagingException
+     */
+    protected InputStream getContentStream() throws MessagingException {
+        // make sure the content is loaded first 
+        loadContent(); 
+        // allow the super class to handle creating it from the loaded content.
+        return super.getContentStream();
+    }
+
+
+    /**
+     * Write out the byte data to the provided output stream.
+     *
+     * @param out    The target stream.
+     *
+     * @exception IOException
+     * @exception MessagingException
+     */
+    public void writeTo(OutputStream out) throws IOException, MessagingException {
+        // make sure we have everything loaded 
+        loadContent(); 
+        // just write out the raw message data 
+        out.write(messageData); 
+    }
+    
+
+    /**
+     * Set a flag value for this Message.  The flags are 
+     * only set locally, not the server.  When the folder 
+     * is closed, any messages with the Deleted flag set 
+     * will be removed from the server. 
+     * 
+     * @param newFlags The new flag values.
+     * @param set      Indicates whether this is a set or an unset operation.
+     * 
+     * @exception MessagingException
+     */
+    public void setFlags(Flags newFlags, boolean set) throws MessagingException {
+        Flags oldFlags = (Flags) flags.clone();
+        super.setFlags(newFlags, set);
+
+        if (!flags.equals(oldFlags)) {
+            ((POP3Folder) folder).notifyMessageChangedListeners(MessageChangedEvent.FLAGS_CHANGED, this);
+        }
+    }
+
+    /**
+     * Unconditionally load the headers from an inputstream. 
+     * When retrieving content, we get back the entire message, 
+     * including the headers.  This allows us to skip over 
+     * them to reach the content, even if we already have 
+     * headers loaded. 
+     * 
+     * @param in     The InputStream with the header data.
+     * 
+     * @exception MessagingException
+     */
+    protected void loadHeaders(InputStream in) throws MessagingException {
+        try {
+            headerSize = in.available(); 
+            // just load and replace the haders 
+            headers = new InternetHeaders(in);
+            headerSize -= in.available(); 
+        } catch (IOException e) {
+            // reading from a ByteArrayInputStream...this should never happen. 
+        }
+    }
+    
+    /**
+     * Lazy loading of the message content. 
+     * 
+     * @exception MessagingException
+     */
+    protected void loadContent() throws MessagingException {
+        if (content == null) {
+            POP3Connection connection = getConnection(); 
+            try {
+                // retrieve (and save the raw message data 
+                messageData = connection.retrieveMessageData(msgnum);
+            } finally {
+                // done with the connection
+                releaseConnection(connection); 
+            }
+            // now create a input stream for splitting this into headers and 
+            // content 
+            ByteArrayInputStream in = new ByteArrayInputStream(messageData); 
+            
+            // the Sun implementation has an option that forces headers loaded using TOP 
+            // should be forgotten when retrieving the message content.  This is because 
+            // some POP3 servers return different results for TOP and RETR.  Since we need to 
+            // retrieve the headers anyway, and this set should be the most complete, we'll 
+            // just replace the headers unconditionally. 
+            loadHeaders(in);
+            // load headers stops loading at the header terminator.  Everything 
+            // after that is content. 
+            loadContent(in);
+        }
+    }
+
+    /**
+     * Load the message content from the server.
+     * 
+     * @param stream A ByteArrayInputStream containing the message content.
+     *               We explicitly use ByteArrayInputStream because
+     *               there are some optimizations that can take advantage
+     *               of the fact it is such a stream.
+     * 
+     * @exception MessagingException
+     */
+    protected void loadContent(ByteArrayInputStream stream) throws MessagingException {
+        // since this is a byte array input stream, available() returns reliable value. 
+        content = new byte[stream.available()];
+        try {
+            // just read everything in to the array 
+            stream.read(content); 
+        } catch (IOException e) {
+            // should never happen 
+            throw new MessagingException("Error loading content info", e);
+        }
+    }
+
+    /**
+     * Get the size of the message.
+     * 
+     * @return The calculated message size, in bytes. 
+     * @exception MessagingException
+     */
+    public int getSize() throws MessagingException {
+        if (msgSize < 0) {
+            // we need to get the headers loaded, since we need that information to calculate the total 
+            // content size without retrieving the content. 
+            loadHeaders();  
+            
+            POP3Connection connection = getConnection(); 
+            try {
+
+                // get the total message size, and adjust by size of the headers to get the content size. 
+                msgSize = connection.retrieveMessageSize(msgnum) - headerSize; 
+            } finally {
+                // done with the connection
+                releaseConnection(connection); 
+            }
+        }
+        return msgSize;
+    }
+
+    /**
+     * notice that we pass zero as the no of lines from the message,as it
+     * doesn't serv any purpose to get only a certain number of lines.
+     * 
+     * However this maybe important if a mail client only shows 3 or 4 lines of
+     * the message in the list and then when the user clicks they would load the
+     * message on demand.
+     * 
+     */
+    protected void loadHeaders() throws MessagingException {
+        if (headers == null) {
+            POP3Connection connection = getConnection(); 
+            try {
+                loadHeaders(connection.retrieveMessageHeaders(msgnum)); 
+            } finally {
+                // done with the connection
+                releaseConnection(connection); 
+            }
+        }
+    }
+    
+    /**
+     * Retrieve the message UID from the server.
+     * 
+     * @return The string UID value. 
+     * @exception MessagingException
+     */
+    protected String getUID() throws MessagingException {
+        if (uid == null) {
+            POP3Connection connection = getConnection(); 
+            try {
+                uid = connection.retrieveMessageUid(msgnum); 
+            } finally {
+                // done with the connection
+                releaseConnection(connection); 
+            }
+        }
+        return uid; 
+    }
+    
+    // The following are methods that deal with all header accesses.  Most of the 
+    // methods that retrieve information from the headers funnel through these, so we 
+    // can lazy-retrieve the header information. 
+
+    public String[] getHeader(String name) throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getHeader(name); 
+    }
+
+    public String getHeader(String name, String delimiter) throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getHeader(name, delimiter); 
+    }
+
+    public Enumeration getAllHeaders() throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getAllHeaders(); 
+    }
+
+    public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getMatchingHeaders(names); 
+    }
+
+    public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getNonMatchingHeaders(names); 
+    }
+
+    public Enumeration getAllHeaderLines() throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getAllHeaderLines();       
+    }
+
+    public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getMatchingHeaderLines(names); 
+    }
+
+    public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
+        // make sure the headers are loaded 
+        loadHeaders(); 
+        // allow the super class to handle everything from here 
+        return super.getNonMatchingHeaderLines(names); 
+    }
+
+    // the following are overrides for header modification methods. These
+    // messages are read only,
+    // so the headers cannot be modified.
+    public void addHeader(String name, String value) throws MessagingException {
+        throw new IllegalWriteException("POP3 messages are read-only");
+    }
+
+    public void setHeader(String name, String value) throws MessagingException {
+        throw new IllegalWriteException("POP3 messages are read-only");
+    }
+
+    public void removeHeader(String name) throws MessagingException {
+        throw new IllegalWriteException("POP3 messages are read-only");
+    }
+
+    public void addHeaderLine(String line) throws MessagingException {
+        throw new IllegalWriteException("POP3 messages are read-only");
+    }
+
+    /**
+     * We cannot modify these messages
+     */
+    public void saveChanges() throws MessagingException {
+        throw new IllegalWriteException("POP3 messages are read-only");
+    }
+
+    
+    /**
+     * get the current connection pool attached to the folder.  We need
+     * to do this dynamically, to A) ensure we're only accessing an
+     * currently open folder, and B) to make sure we're using the
+     * correct connection attached to the folder.
+     *
+     * @return A connection attached to the hosting folder.
+     */
+    protected POP3Connection getConnection() throws MessagingException {
+        // the folder owns everything.
+        return ((POP3Folder)folder).getMessageConnection();
+    }
+    
+    /**
+     * Release the connection back to the Folder after performing an operation 
+     * that requires a connection.
+     * 
+     * @param connection The previously acquired connection.
+     */
+    protected void releaseConnection(POP3Connection connection) throws MessagingException {
+        // the folder owns everything.
+        ((POP3Folder)folder).releaseMessageConnection(connection);
+    }
+}

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java?rev=597135&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java Wed Nov 21 08:26:57 2007
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.geronimo.javamail.store.pop3;
+
+import javax.mail.Folder; 
+import javax.mail.Message; 
+import javax.mail.MessagingException; 
+import javax.mail.MethodNotSupportedException;
+import javax.mail.Store; 
+
+import org.apache.geronimo.javamail.store.pop3.connection.POP3Connection; 
+
+/**
+ * An POP3 folder instance for the root of POP3 folder tree.  This has 
+ * some of the folder operations disabled. 
+ */
+public class POP3RootFolder extends POP3Folder {
+    // the inbox folder is the only one that exists 
+    protected Folder inbox; 
+    
+    /**
+     * Create a default POP3RootFolder attached to a specific Store instance.
+     * 
+     * @param store  The Store instance this is the root for.
+     */
+    public POP3RootFolder(POP3Store store) {
+        // create a folder with a null string name and the default separator. 
+        super(store, ""); 
+        // this only holds folders 
+        folderType = HOLDS_FOLDERS; 
+        // this folder does exist
+        exists = true; 
+        // no messages in this folder 
+        msgCount = 0; 
+    }
+
+    
+    /**
+     * Get the parent.  This is the root folder, which 
+     * never has a parent. 
+     * 
+     * @return Always returns null. 
+     */
+    public Folder getParent() {
+        // we never have a parent folder 
+        return null; 
+    }
+
+    /**
+     * We have a separator because the root folder is "special". 
+     */
+    public char getSeparator() throws MessagingException {
+        return '/';
+    }
+    
+    /**
+     * Retrieve a list of folders that match a pattern.
+     * 
+     * @param pattern The match pattern.
+     * 
+     * @return An array of matching folders.
+     * @exception MessagingException
+     */
+    public Folder[] list(String pattern) throws MessagingException {
+        // I'm not sure this is correct, but the Sun implementation appears to 
+        // return a array containing the inbox regardless of what pattern was specified. 
+        return new Folder[] { getInbox() };
+    }
+    
+    /**
+     * Get a folder of a given name from the root folder.
+     * The Sun implementation seems somewhat inconsistent 
+     * here.  The docs for Store claim that only INBOX is 
+     * supported, but it will return a Folder instance for any 
+     * name.  On the other hand, the root folder raises 
+     * an exception for anything but the INBOX.
+     * 
+     * @param name   The folder name (which must be "INBOX".
+     * 
+     * @return The inbox folder instance. 
+     * @exception MessagingException
+     */
+    public Folder getFolder(String name) throws MessagingException {
+        if (!name.equalsIgnoreCase("INBOX")) {
+            throw new MessagingException("Only the INBOX folder is supported"); 
+        }
+        // return the inbox folder 
+        return getInbox(); 
+    }
+    
+    /**
+     * Override for the isOpen method.  The root folder can 
+     * never be opened. 
+     * 
+     * @return always returns false. 
+     */
+    public boolean isOpen() {
+        return false; 
+    }
+    
+    public void open(int mode) throws MessagingException {
+        throw new MessagingException("POP3 root folder cannot be opened"); 
+    }
+    
+    public void open(boolean expunge) throws MessagingException {
+        throw new MessagingException("POP3 root folder cannot be close"); 
+    }
+    
+    
+    /**
+     * Retrieve the INBOX folder from the root. 
+     * 
+     * @return The Folder instance for the inbox. 
+     * @exception MessagingException
+     */
+    protected Folder getInbox() throws MessagingException {
+        // we're the only place that creates folders, and 
+        // we only create the single instance. 
+        if (inbox == null) {
+            inbox = new POP3Folder((POP3Store)store, "INBOX"); 
+        }
+        return inbox; 
+    }
+}
+
+

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java?rev=597135&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java Wed Nov 21 08:26:57 2007
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.geronimo.javamail.store.pop3;
+
+import javax.mail.Session;
+import javax.mail.URLName;
+
+/**
+ * POP3 implementation of javax.mail.Store over an SSL connection.
+ *
+ * @version $Rev$ $Date$
+ */
+public class POP3SSLStore extends POP3Store {
+    /**
+     * Construct an POP3SSLStore item.
+     *
+     * @param session The owning javamail Session.
+     * @param urlName The Store urlName, which can contain server target information.
+     */
+	public POP3SSLStore(Session session, URLName urlName) {
+        // we're the imaps protocol, our default connection port is 993, and we must use
+        // an SSL connection for the initial hookup 
+		super(session, urlName, "pop3s", DEFAULT_POP3_SSL_PORT, true);
+	}
+}
+
+

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: geronimo/javamail/trunk/geronimo-javamail_1.4/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/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java?rev=597135&r1=597134&r2=597135&view=diff
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java (original)
+++ geronimo/javamail/trunk/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java Wed Nov 21 08:26:57 2007
@@ -18,6 +18,10 @@
  */
 
 package org.apache.geronimo.javamail.store.pop3;
+ 
+import java.io.PrintStream; 
+import java.util.LinkedList;
+import java.util.List;
 
 import javax.mail.AuthenticationFailedException;
 import javax.mail.Folder;
@@ -26,6 +30,10 @@
 import javax.mail.Store;
 import javax.mail.URLName;
 
+import org.apache.geronimo.javamail.store.pop3.connection.POP3Connection; 
+import org.apache.geronimo.javamail.store.pop3.connection.POP3ConnectionPool; 
+import org.apache.geronimo.javamail.util.ProtocolProperties;
+
 /**
  * POP3 implementation of javax.mail.Store POP protocol spec is implemented in
  * org.apache.geronimo.javamail.store.pop3.POP3Connection
@@ -34,16 +42,28 @@
  */
 
 public class POP3Store extends Store {
-
-    private POP3Connection pop3Con;
-
-    protected static final int DEFAULT_MAIL_POP3_PORT = 110;
-    private boolean sslConnection;
-    private int defaultPort;
+    protected static final int DEFAULT_POP3_PORT = 110;
+    protected static final int DEFAULT_POP3_SSL_PORT = 995;
+    
+    
+    // our accessor for protocol properties and the holder of 
+    // protocol-specific information 
+    protected ProtocolProperties props; 
+    // our connection object    
+    protected POP3ConnectionPool connectionPool; 
+    // our session provided debug output stream.
+    protected PrintStream debugStream;
+    // the debug flag 
+    protected boolean debug; 
+    // the root folder 
+    protected POP3RootFolder root; 
+    // until we're connected, we're closed 
+    boolean closedForBusiness = true; 
+    protected LinkedList openFolders = new LinkedList(); 
+    
     
-    private String protocol;
     public POP3Store(Session session, URLName name) {
-        this(session, name, "pop3", DEFAULT_MAIL_POP3_PORT, false);
+        this(session, name, "pop3", DEFAULT_POP3_PORT, false);
     }
 
     /**
@@ -68,173 +88,227 @@
      */
     protected POP3Store(Session session, URLName name, String protocol, int defaultPort, boolean sslConnection) {
         super(session, name);
-        this.protocol = protocol;
+        
+        // create the protocol property holder.  This gives an abstraction over the different 
+        // flavors of the protocol. 
+        props = new ProtocolProperties(session, protocol, sslConnection, defaultPort); 
+
+        // get our debug settings
+        debugStream = session.getDebugOut();
+        debug = session.getDebug(); 
+        // the connection pool manages connections for the stores, folder, and message usage. 
+        connectionPool = new POP3ConnectionPool(this, props); 
+    }
 
-        // 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
+     * Return a Folder object that represents the root of the namespace for the current user.
+     *
+     * Note that in some store configurations (such as IMAP4) the root folder might
+     * not be the INBOX folder.
+     *
+     * @return the root Folder
+     * @throws MessagingException if there was a problem accessing the store
      */
-    public Folder getDefaultFolder() throws MessagingException {
-        return getFolder("INBOX");
-    }
+	public Folder getDefaultFolder() throws MessagingException {
+		checkConnectionStatus();
+        // if no root yet, create a root folder instance. 
+        if (root == null) {
+            return new POP3RootFolder(this);
+        }
+        return root;
+	}
 
     /**
-     * @see javax.mail.Store#getFolder(java.lang.String)
+     * Return the Folder corresponding to the given name.
+     * The folder might not physically exist; the {@link Folder#exists()} method can be used
+     * to determine if it is real.
+     * 
+     * @param name   the name of the Folder to return
+     * 
+     * @return the corresponding folder
+     * @throws MessagingException
+     *                if there was a problem accessing the store
      */
-    public Folder getFolder(String name) throws MessagingException {
-
-        checkConnectionStatus();
-
-        if (!"INBOX".equalsIgnoreCase(name)) {
-            throw new MessagingException("Only INBOX is supported in POP3");
-        }
-        return new POP3Folder(this, session, pop3Con);
-    }
+	public Folder getFolder(String name) throws MessagingException {
+        return getDefaultFolder().getFolder(name);
+	}
 
+    
     /**
-     * @see javax.mail.Store#getFolder(javax.mail.URLName)
+     * Return the folder identified by the URLName; the URLName must refer to this Store.
+     * Implementations may use the {@link URLName#getFile()} method to determined the folder name.
+     * 
+     * @param url
+     * 
+     * @return the corresponding folder
+     * @throws MessagingException
+     *                if there was a problem accessing the store
      */
-    public Folder getFolder(URLName url) throws MessagingException {
-        return getFolder(url.getFile());
-    }
+	public Folder getFolder(URLName url) throws MessagingException {
+        return getDefaultFolder().getFolder(url.getFile());
+	}
 
+    
     /**
      * @see javax.mail.Service#protocolConnect(java.lang.String, int,
      *      java.lang.String, java.lang.String)
      */
-    protected synchronized boolean protocolConnect(String host, int portNum, String user, String passwd)
-            throws MessagingException {
-
-        // Never store the user, passwd for security reasons
-
-        // if these values are null, no connection attempt should be made
-        if (host == null || passwd == null || user == null) {
-            return false;
-        }
-
-        // validate port num
-        if (portNum < 1) {
-            String portstring = session.getProperty("mail.pop3.port");
-            if (portstring != null) {
-                try {
-                    portNum = Integer.parseInt(portstring);
-                } catch (NumberFormatException e) {
-                    portNum = defaultPort;
-                }
-            }
-        }
-
-        /*
-         * Obtaining a connection to the server.
-         * 
-         */
-        pop3Con = new POP3Connection(this.session, host, portNum, sslConnection, protocol);
-        try {
-            pop3Con.open();
-        } catch (Exception e) {
-            throw new MessagingException("Connection failed", e);
+    protected synchronized boolean protocolConnect(String host, int port, String username, String password) throws MessagingException {
+        
+        if (debug) {
+            debugOut("Connecting to server " + host + ":" + port + " for user " + username);
         }
 
-        /*
-         * Sending the USER command with username
-         * 
-         */
-        POP3Response resUser = null;
-        try {
-            resUser = pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_USER(user));
-        } catch (Exception e) {
-            throw new MessagingException("Connection failed", e);
+        // the connection pool handles all of the details here. 
+        if (connectionPool.protocolConnect(host, port, username, password)) 
+        {
+            // the store is now open 
+            closedForBusiness = false; 
+            return true; 
         }
-
-        if (POP3Constants.ERR == resUser.getStatus()) {
-
-            /*
-             * Authentication failed so sending QUIT
-             * 
-             */
-            try {
-                pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_QUIT());
-            } catch (Exception e) {
-                // We don't care about the response or if any error happens
-                // just trying to comply with the spec.
-                // Most likely the server would have terminated the connection
-                // by now.
+        return false; 
+    }
+    
+    
+    protected POP3Connection getConnection() throws MessagingException {
+        return connectionPool.getConnection(); 
+    }
+    
+    protected void releaseConnection(POP3Connection connection) throws MessagingException {
+        connectionPool.releaseConnection(connection); 
+    }
+    
+    synchronized POP3Connection getFolderConnection(POP3Folder folder) throws MessagingException {
+        POP3Connection connection = connectionPool.getConnection(); 
+        openFolders.add(folder);
+        return connection; 
+    }
+    
+    synchronized void releaseFolderConnection(POP3Folder folder, POP3Connection connection) throws MessagingException {
+        openFolders.remove(folder); 
+        // a connection returned from a folder is no longer usable. Just close it and 
+        // let it drift off. 
+        connection.close(); 
+    }
+    
+    /**
+     * Close all open folders.  We have a small problem here with a race condition.  There's no safe, single
+     * synchronization point for us to block creation of new folders while we're closing.  So we make a copy of
+     * the folders list, close all of those folders, and keep repeating until we're done.
+     */
+    protected void closeOpenFolders() {
+        // we're no longer accepting additional opens.  Any folders that open after this point will get an
+        // exception trying to get a connection.
+        closedForBusiness = true;
+
+        while (true) {
+            List folders = null;
+
+            // grab our lock, copy the open folders reference, and null this out.  Once we see a null
+            // open folders ref, we're done closing.
+            synchronized(connectionPool) {
+                folders = openFolders;
+                openFolders = new LinkedList();
             }
 
-            throw new AuthenticationFailedException(resUser.getFirstLine());
-        }
-
-        /*
-         * Sending the PASS command with password
-         * 
-         */
-        POP3Response resPwd = null;
-        try {
-            resPwd = pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_PASS(passwd));
-        } catch (Exception e) {
-            throw new MessagingException("Connection failed", e);
-        }
-
-        if (POP3Constants.ERR == resPwd.getStatus()) {
-
-            /*
-             * Authentication failed so sending QUIT
-             * 
-             */
-            try {
-                pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_QUIT());
-            } catch (Exception e) {
-                // We don't care about the response or if any error happens
-                // just trying to comply with the spec.
-                // Most likely the server would have terminated the connection
-                // by now.
+            // null folder, we're done
+            if (folders.isEmpty()) {
+                return;
+            }
+            // now close each of the open folders.
+            for (int i = 0; i < folders.size(); i++) {
+                POP3Folder folder = (POP3Folder)folders.get(i);
+                try {
+                    folder.close(false);
+                } catch (MessagingException e) {
+                }
             }
-
-            throw new AuthenticationFailedException(resPwd.getFirstLine());
         }
-
-        return true;
     }
+    
 
     /**
      * @see javax.mail.Service#isConnected()
      */
     public boolean isConnected() {
-        POP3Response res = null;
         try {
-            res = pop3Con.sendCommand(POP3CommandFactory.getCOMMAND_NOOP());
-        } catch (Exception e) {
-            return false;
+            POP3Connection connection = getConnection(); 
+            try {
+                connection.pingServer(); 
+                return true; 
+            }
+            finally {
+                releaseConnection(connection); 
+            }
+        } catch (MessagingException e) {
         }
-
-        return (POP3Constants.OK == res.getStatus());
+        return false; 
     }
 
     /**
-     * @see javax.mail.Service#close()
+     * Close the store, and any open folders associated with the 
+     * store. 
+     * 
+     * @exception MessagingException
      */
-    public void close() throws MessagingException {
-        // This is done to ensure proper event notification.
-        super.close();
-        try {
-            pop3Con.close();
-        } catch (Exception e) {
-            // A message is already set at the connection level
-            // unfortuantely there is no constructor that takes only
-            // the root exception
-            new MessagingException("", e);
-        }
-    }
+	public synchronized void close() throws MessagingException{
+        // if already closed, nothing to do. 
+        if (closedForBusiness) {
+            return; 
+        }
+        
+        // close the folders first, then shut down the Store. 
+        closeOpenFolders();
+        
+        connectionPool.close(); 
+        connectionPool = null; 
+
+		// make sure we do the superclass close operation first so 
+        // notification events get broadcast properly. 
+		super.close();
+	}
 
+    /**
+     * Check the status of our connection. 
+     * 
+     * @exception MessagingException
+     */
     private void checkConnectionStatus() throws MessagingException {
         if (!this.isConnected()) {
             throw new MessagingException("Not connected ");
         }
+    }
+
+    /**
+     * Internal debug output routine.
+     *
+     * @param value  The string value to output.
+     */
+    void debugOut(String message) {
+        debugStream.println("POP3Store DEBUG: " + message);
+    }
+
+    /**
+     * Internal debugging routine for reporting exceptions.
+     *
+     * @param message A message associated with the exception context.
+     * @param e       The received exception.
+     */
+    void debugOut(String message, Throwable e) {
+        debugOut("Received exception -> " + message);
+        debugOut("Exception message -> " + e.getMessage());
+        e.printStackTrace(debugStream);
+    }
+    
+    /**
+     * Finalizer to perform IMAPStore() cleanup when 
+     * no longer in use. 
+     * 
+     * @exception Throwable
+     */
+    protected void finalize() throws Throwable {
+        super.finalize(); 
+        close(); 
     }
 }



Mime
View raw message