You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jl...@apache.org on 2020/10/07 15:58:41 UTC

svn commit: r1882306 [11/17] - in /geronimo/javamail/trunk/geronimo-javamail_1.6: ./ geronimo-javamail_1.6_mail/ geronimo-javamail_1.6_mail/src/ geronimo-javamail_1.6_mail/src/site/ geronimo-javamail_1.6_provider/ geronimo-javamail_1.6_provider/src/ ge...

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,260 @@
+/*
+ * 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.nntp;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.Iterator;
+
+import javax.mail.Folder;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Store;
+import javax.mail.URLName;
+
+import org.apache.geronimo.javamail.store.nntp.newsrc.NNTPNewsrc;
+import org.apache.geronimo.javamail.store.nntp.newsrc.NNTPNewsrcFile;
+import org.apache.geronimo.javamail.store.nntp.newsrc.NNTPNewsrcGroup;
+import org.apache.geronimo.javamail.transport.nntp.NNTPConnection;
+import org.apache.geronimo.javamail.util.ProtocolProperties; 
+import org.apache.geronimo.mail.util.SessionUtil;
+
+/**
+ * NNTP implementation of javax.mail.Store POP protocol spec is implemented in
+ * org.apache.geronimo.javamail.store.pop3.NNTPConnection
+ * 
+ * @version $Rev$ $Date$
+ */
+public class NNTPStore extends Store {
+    protected static final String NNTP_NEWSRC = "newsrc";
+
+    protected static final String protocol = "nntp";
+
+    protected static final int DEFAULT_NNTP_PORT = 119;
+    protected static final int DEFAULT_NNTP_SSL_PORT = 563;
+
+    // our accessor for protocol properties and the holder of 
+    // protocol-specific information 
+    protected ProtocolProperties props; 
+    // our active connection object (shared code with the NNTPStore).
+    protected NNTPConnection connection;
+
+    // the root folder
+    protected NNTPRootFolder root;
+    // the newsrc file where we store subscriptions and seen message markers.
+    protected NNTPNewsrc newsrc;
+    
+    /**
+     * Construct an NNTPStore item. This will load the .newsrc file associated
+     * with the server.
+     * 
+     * @param session
+     *            The owning javamail Session.
+     * @param name
+     *            The Store urlName, which can contain server target
+     *            information.
+     */
+    public NNTPStore(Session session, URLName name) {
+        this(session, name, "nntp", DEFAULT_NNTP_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 ("nntp" or "nntps"). 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 NNTPStore(Session session, URLName name, String protocol, int defaultPort, boolean sslConnection) {
+        super(session, name);
+        
+        // create the protocol property holder.  This gives an abstraction over the different 
+        // flavors of the protocol. 
+        props = new ProtocolProperties(session, protocol, sslConnection, defaultPort); 
+
+        // the connection manages connection for the transport 
+        connection = new NNTPConnection(props); 
+    }
+
+    /**
+     * @see Store#getDefaultFolder()
+     * 
+     * This returns a root folder object for all of the news groups.
+     */
+    public Folder getDefaultFolder() throws MessagingException {
+        checkConnectionStatus();
+        if (root == null) {
+            return new NNTPRootFolder(this, connection.getHost(), connection.getWelcomeString());
+        }
+        return root;
+    }
+
+    /**
+     * @see Store#getFolder(String)
+     */
+    public Folder getFolder(String name) throws MessagingException {
+        return getDefaultFolder().getFolder(name);
+    }
+
+    /**
+     * 
+     * @see Store#getFolder(URLName)
+     */
+    public Folder getFolder(URLName url) throws MessagingException {
+        return getDefaultFolder().getFolder(url.getFile());
+    }
+
+    
+    /**
+     * Do the protocol connection for an NNTP transport. This handles server
+     * authentication, if possible. Returns false if unable to connect to the
+     * server.
+     * 
+     * @param host
+     *            The target host name.
+     * @param port
+     *            The server port number.
+     * @param user
+     *            The authentication user (if any).
+     * @param password
+     *            The server password. Might not be sent directly if more
+     *            sophisticated authentication is used.
+     * 
+     * @return true if we were able to connect to the server properly, false for
+     *         any failures.
+     * @exception MessagingException
+     */
+    protected boolean protocolConnect(String host, int port, String username, String password)
+            throws MessagingException {
+        // the connection pool handles all of the details here. But don't proceed 
+        // without a connection 
+        if (!connection.protocolConnect(host, port, username, password)) {
+            return false; 
+        }
+
+        // see if we have a newsrc file location specified
+        String newsrcFile = props.getProperty(NNTP_NEWSRC);
+
+        File source = null;
+
+        // not given as a property? Then look for a file in user.home
+        if (newsrcFile != null) {
+            source = new File(newsrcFile);
+        } else {
+            // ok, look for a file in the user.home directory. If possible,
+            // we'll try for a file
+            // with the hostname appended.
+            String home = SessionUtil.getProperty("user.home");
+
+            // try for a host-specific file first. If not found, use (and
+            // potentially create) a generic
+            // .newsrc file.
+            newsrcFile = ".newsrc-" + host;
+            source = new File(home, newsrcFile);
+            if (!source.exists()) {
+                source = new File(home, ".newsrc");
+            }
+        }
+
+        // now create a newsrc read and load the file.
+        newsrc = new NNTPNewsrcFile(source);
+        newsrc.load();
+
+        // we're going to return success here, but in truth, the server may end
+        // up asking for our bonafides at any time, and we'll be expected to authenticate then.
+        return true;
+    }
+    
+
+    /**
+     * @see javax.mail.Service#close()
+     */
+    public void close() throws MessagingException {
+        // This is done to ensure proper event notification.
+        super.close();
+        // persist the newsrc file, if possible
+        if (newsrc != null) {
+            newsrc.close();
+            newsrc = null; 
+        }
+        connection.close();
+        connection = null;
+    }
+
+    private void checkConnectionStatus() throws MessagingException {
+        if (!this.isConnected()) {
+            throw new MessagingException("Not connected ");
+        }
+    }
+
+    /**
+     * Retrieve the server connection created by this store.
+     * 
+     * @return The active connection object.
+     */
+    NNTPConnection getConnection() {
+        return connection;
+    }
+
+    /**
+     * Retrieve the Session object this Store is operating under.
+     * 
+     * @return The attached Session instance.
+     */
+    Session getSession() {
+        return session;
+    }
+
+    /**
+     * Retrieve all of the groups we nave persistent store information about.
+     * 
+     * @return The set of groups contained in the newsrc file.
+     */
+    Iterator getNewsrcGroups() {
+        return newsrc.getGroups();
+    }
+
+    /**
+     * Retrieve the newsrc group information for a named group. If the file does
+     * not currently include this group, an unsubscribed group will be added to
+     * the file.
+     * 
+     * @param name
+     *            The name of the target group.
+     * 
+     * @return The NNTPNewsrcGroup item corresponding to this name.
+     */
+    NNTPNewsrcGroup getNewsrcGroup(String name) {
+        return newsrc.getGroup(name);
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrc.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrc.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrc.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrc.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,182 @@
+/*
+ * 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.nntp.newsrc;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Base class implementation of a standard news reader news rc file. This is
+ * used to track newsgroup subscriptions and SEEN flags for articles. This is an
+ * abstract class designed for subclasses to bridge to the physical store type
+ * used for the newsgroup information.
+ */
+public abstract class NNTPNewsrc {
+
+    // the group information we've read from the news rc file.
+    Map groups = new HashMap();
+
+    // flag to let us know of we need to persist the newsrc file on close.
+    boolean dirty = false;
+
+    /**
+     * Base class constructor for NNTPNewsrc items. Subclasses provide their own
+     * domain-specific intialization.
+     */
+    protected NNTPNewsrc() {
+    }
+
+    /**
+     * Load the data from the newsrc file and parse into an instore group
+     * database.
+     */
+    public void load() {
+        BufferedReader in = null;
+
+        try {
+            in = getInputReader();
+
+            String line = in.readLine();
+
+            while (line != null) {
+                // parse the line...this returns null if it's something
+                // unrecognized.
+                NNTPNewsrcGroup group = NNTPNewsrcGroup.parse(this, line);
+                // if it parsed ok, add it to the group list, and potentially to
+                // the subscribed list.
+                if (group != null) {
+                    groups.put(group.getName(), group);
+                }
+
+                line = in.readLine();
+            }
+
+            in.close();
+        } catch (IOException e) {
+            // an IOException may mean that the file just doesn't exist, which
+            // is fine. We'll ignore and
+            // proceed with the information we have.
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Save the newsrc file data back to the original source file.
+     * 
+     * @exception IOException
+     */
+    public void save() throws IOException {
+        Writer out = getOutputWriter();
+
+        Iterator i = groups.values().iterator();
+
+        while (i.hasNext()) {
+            NNTPNewsrcGroup group = (NNTPNewsrcGroup) i.next();
+            group.save(out);
+        }
+
+        out.close();
+    }
+
+    /**
+     * Abstract open method intended for sub class initialization. The subclass
+     * is responsible for creating the BufferedReaded used to read the .newsrc
+     * file.
+     * 
+     * @return A BufferedReader for reading the .newsrc file.
+     * @exception IOException
+     */
+    abstract public BufferedReader getInputReader() throws IOException;
+
+    /**
+     * Abstract open for output method intended for subclass implementation. The
+     * subclasses are reponsible for opening the output stream and creating an
+     * appropriate Writer for saving the .newsrc file.
+     * 
+     * @return A Writer target at the .newsrc file save location.
+     * @exception IOException
+     */
+    abstract public Writer getOutputWriter() throws IOException;
+
+    /**
+     * Retrieve the newsrc group information for a named group. If the file does
+     * not currently include this group, an unsubscribed group will be added to
+     * the file.
+     * 
+     * @param name
+     *            The name of the target group.
+     * 
+     * @return The NNTPNewsrcGroup item corresponding to this name.
+     */
+    public NNTPNewsrcGroup getGroup(String name) {
+        NNTPNewsrcGroup group = (NNTPNewsrcGroup) groups.get(name);
+        // if we don't know about this, create a new one and add to the list.
+        // This
+        // will be an unsubscribed one.
+        if (group == null) {
+            group = new NNTPNewsrcGroup(this, name, null, false);
+            groups.put(name, group);
+            // we've added a group, so we need to resave
+            dirty = true;
+        }
+        return group;
+    }
+
+    /**
+     * Mark this newsrc database as dirty.
+     */
+    public void setDirty() {
+        dirty = true;
+    }
+
+    /**
+     * Close the newsrc file, persisting it back to disk if the file has
+     * changed.
+     */
+    public void close() {
+        if (dirty) {
+            try {
+                save();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Retrieve the current set of loaded groups.
+     * 
+     * @return An iterator for traversing the group set.
+     */
+    public Iterator getGroups() {
+        return groups.values().iterator();
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcFile.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcFile.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcFile.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcFile.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,66 @@
+/*
+ * 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.nntp.newsrc;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+public class NNTPNewsrcFile extends NNTPNewsrc {
+    // source for the file data
+    File source;
+
+    /**
+     * Construct a NNTPNewsrc object that is targetted at a file-based backing
+     * store.
+     * 
+     * @param source
+     *            The source File for the .newsrc data.
+     */
+    public NNTPNewsrcFile(File source) {
+        this.source = source;
+    }
+
+    /**
+     * Retrieve an input reader for loading the newsrc file.
+     * 
+     * @return A BufferedReader object for reading from the newsrc file.
+     * @exception IOException
+     */
+    public BufferedReader getInputReader() throws IOException {
+        return new BufferedReader(new InputStreamReader(new FileInputStream(source), "ISO8859-1"));
+    }
+
+    /**
+     * Obtain a writer for saving a newsrc file.
+     * 
+     * @return The output writer targetted to the newsrc file.
+     * @exception IOException
+     */
+    public Writer getOutputWriter() throws IOException {
+        // open this for overwriting
+        return new OutputStreamWriter(new FileOutputStream(source, false), "ISO8859-1");
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcGroup.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcGroup.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcGroup.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/NNTPNewsrcGroup.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,185 @@
+/*
+ * 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.nntp.newsrc;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public class NNTPNewsrcGroup {
+    // the newsrc database we're part of
+    NNTPNewsrc newsrc;
+
+    // the name of the group
+    protected String name;
+
+    // the subscription flage
+    protected boolean subscribed;
+
+    // the range of already seen articles.
+    protected RangeList ranges;
+
+    /**
+     * Construct a NNTPNewsrcGroup item associated with a given .newsrc
+     * database.
+     * 
+     * @param newsrc
+     *            The owning .newsrc database.
+     * @param line
+     *            The .newsrc range entries in .newsrc format. These ranges are
+     *            parsed to create a set of seen flags.
+     * 
+     * @return A created NNTPNewsrcGroup item.
+     */
+    public static NNTPNewsrcGroup parse(NNTPNewsrc newsrc, String line) {
+        String groupName = null;
+        String ranges = null;
+
+        // subscribed lines have a ':' marker acting as a delimiter
+        int marker = line.indexOf(':');
+
+        if (marker != -1) {
+            groupName = line.substring(0, marker);
+            ranges = line.substring(marker + 1);
+            return new NNTPNewsrcGroup(newsrc, groupName, ranges, true);
+        }
+
+        // now check for an unsubscribed group
+        marker = line.indexOf('!');
+
+        if (marker != -1) {
+            groupName = line.substring(0, marker);
+            ranges = line.substring(marker + 1);
+            return new NNTPNewsrcGroup(newsrc, groupName, ranges, false);
+        }
+
+        // must be a comment line
+        return null;
+    }
+
+    /**
+     * Construct a .newsrc group item.
+     * 
+     * @param newsrc
+     *            The owning newsrc database.
+     * @param name
+     *            The group name.
+     * @param newsrcRanges
+     *            The initial set of seen ranges for the group (may be null).
+     * @param subscribed
+     *            The initial group subscription state.
+     */
+    public NNTPNewsrcGroup(NNTPNewsrc newsrc, String name, String newsrcRanges, boolean subscribed) {
+        this.newsrc = newsrc;
+        this.name = name;
+        this.subscribed = subscribed;
+        this.ranges = new RangeList(newsrcRanges);
+    }
+
+    /**
+     * Get the group name.
+     * 
+     * @return The String name of the group.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get the newsrc subscribed status for an article.
+     * 
+     * @return The current subscription flag.
+     */
+    public boolean isSubscribed() {
+        return subscribed;
+    }
+
+    /**
+     * Set the subscription status for an article.
+     * 
+     * @param flag
+     *            The new subscription value.
+     */
+    public void setSubscribed(boolean flag) {
+        // we don't blindly set this to the new value since we only want to
+        // resave the newsrc file if
+        // something changes.
+        if (flag && !subscribed) {
+            subscribed = true;
+            newsrc.setDirty();
+        } else if (!flag && subscribed) {
+            subscribed = false;
+            newsrc.setDirty();
+        }
+    }
+
+    /**
+     * Test if an article has been seen yet.
+     * 
+     * @param article
+     *            The target article.
+     * 
+     * @return The seen mark for the article.
+     */
+    public boolean isArticleSeen(int article) {
+        return ranges.isMarked(article);
+    }
+
+    /**
+     * Mark an article as seen.
+     * 
+     * @param article
+     *            The target article number.
+     */
+    public void markArticleSeen(int article) {
+        ranges.setMarked(article);
+        if (ranges.isDirty()) {
+            newsrc.setDirty();
+        }
+    }
+
+    /**
+     * Mark an article as unseen.
+     * 
+     * @param article
+     *            The target article number.
+     */
+    public void markArticleUnseen(int article) {
+        ranges.setUnmarked(article);
+        if (ranges.isDirty()) {
+            newsrc.setDirty();
+        }
+    }
+
+    /**
+     * Save this group definition to a .newsrc file.
+     * 
+     * @param out
+     *            The output writer to send the information to.
+     * 
+     * @exception IOException
+     */
+    public void save(Writer out) throws IOException {
+        out.write(name);
+        out.write(subscribed ? ": " : "! ");
+        ranges.save(out);
+        // put a terminating line end
+        out.write("\r\n");
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/Range.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/Range.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/Range.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/Range.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,318 @@
+/*
+ * 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.nntp.newsrc;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Represent a single Range in a newsrc file. A Range can be either a single
+ * number (start == end) or a span of article numbers.
+ */
+public class Range {
+    // the low end of the range
+    int start;
+
+    // the high end of the range (start and end are inclusive);
+    int end;
+
+    /**
+     * Construct a Range item for a single digit range.
+     * 
+     * @param spot
+     *            The location of the singleton.
+     */
+    public Range(int spot) {
+        this(spot, spot);
+    }
+
+    /**
+     * Construct a Range item.
+     * 
+     * @param start
+     *            The starting point of the Range.
+     * @param end
+     *            The Range end point (which may be equal to the starting
+     *            point).
+     */
+    public Range(int start, int end) {
+        this.start = start;
+        this.end = end;
+    }
+
+    /**
+     * Parse a section of a .newsrc range string into a single Range item. The
+     * range is either a single number, or a pair of numbers separated by a
+     * hyphen.
+     * 
+     * @param range
+     *            The range string.
+     * 
+     * @return A constructed Range item, or null if there is a parsing error.
+     */
+    static public Range parse(String range) {
+        // a range from a newsrc file is either a single number or in the format
+        // 'nnnn-mmmm'. We need
+        // to figure out which type this is.
+        int marker = range.indexOf('-');
+
+        try {
+            if (marker != -1) {
+                String rangeStart = range.substring(0, marker).trim();
+                String rangeEnd = range.substring(marker + 1).trim();
+
+                int start = Integer.parseInt(rangeStart);
+                int end = Integer.parseInt(rangeEnd);
+
+                if (start >= 0 && end >= 0) {
+                    return new Range(start, end);
+                }
+            } else {
+                // use the entire token
+                int start = Integer.parseInt(range);
+                // and start and the end are the same
+                return new Range(start, start);
+
+            }
+        } catch (NumberFormatException e) {
+        }
+        // return null for any bad values
+        return null;
+    }
+
+    /**
+     * Get the starting point for the Range.
+     * 
+     * @return The beginning of the mark range.
+     */
+    public int getStart() {
+        return start;
+    }
+
+    /**
+     * Set the starting point for a Range.
+     * 
+     * @param start
+     *            The new start value.
+     */
+    public void setStart(int start) {
+        this.start = start;
+    }
+
+    /**
+     * Get the ending point for the Range.
+     * 
+     * @return The end of the mark range.
+     */
+    public int getEnd() {
+        return end;
+    }
+
+    /**
+     * Set the ending point for a Range.
+     * 
+     * @param end
+     *            The new end value.
+     */
+    public void setEnd(int end) {
+        this.end = end;
+    }
+
+    /**
+     * Test if a range contains a point value.
+     * 
+     * @param target
+     *            The article location to test.
+     * 
+     * @return True if the target is between the start and end values,
+     *         inclusive.
+     */
+    public boolean contains(int target) {
+        return target >= start && target <= end;
+    }
+
+    /**
+     * Test if one range is completely contained within another Range.
+     * 
+     * @param other
+     *            The other test range.
+     * 
+     * @return true if the other start and end points are contained within this
+     *         range.
+     */
+    public boolean contains(Range other) {
+        return contains(other.getStart()) && contains(other.getEnd());
+    }
+
+    /**
+     * Tests if two ranges overlap
+     * 
+     * @param other
+     *            The other test range.
+     * 
+     * @return true if the start or end points of either range are contained
+     *         within the range of the other.
+     */
+    public boolean overlaps(Range other) {
+        return other.contains(start) || other.contains(end) || contains(other.getStart()) || contains(other.getEnd());
+    }
+
+    /**
+     * Test if two ranges exactly abutt each other.
+     * 
+     * @param other
+     *            The other Range to test.
+     * 
+     * @return true if the end of one range abutts the start of the other range.
+     */
+    public boolean abutts(Range other) {
+        return other.getStart() == end + 1 || other.getEnd() == start - 1;
+    }
+
+    /**
+     * Tests if a single point abutts either the start or end of this Range.
+     * 
+     * @param article
+     *            The point to test.
+     * 
+     * @return true if test point is equal to start - 1 or end + 1.
+     */
+    public boolean abutts(int article) {
+        return article == start - 1 || article == end + 1;
+    }
+
+    /**
+     * Test if a point is below the test Range.
+     * 
+     * @param article
+     *            The point to test.
+     * 
+     * @return true if the entire range is less than the test point.
+     */
+    public boolean lessThan(int article) {
+        return end < article;
+    }
+
+    /**
+     * Test if another Range is less than this Range.
+     * 
+     * @param other
+     *            The other Range to test.
+     * 
+     * @return true if the other Range lies completely below this Range.
+     */
+    public boolean lessThan(Range other) {
+        return end < other.start;
+    }
+
+    /**
+     * Test if a point is above the test Range.
+     * 
+     * @param article
+     *            The point to test.
+     * 
+     * @return true if the entire range is greater than the test point.
+     */
+    public boolean greaterThan(int article) {
+        return start > article;
+    }
+
+    /**
+     * Test if another Range is greater than this Range.
+     * 
+     * @param other
+     *            The other Range to test.
+     * 
+     * @return true if the other Range lies completely below this Range.
+     */
+    public boolean greaterThan(Range other) {
+        return start > other.end;
+    }
+
+    /**
+     * Merge another Range into this one. Merging will increase the bounds of
+     * this Range to encompass the entire span of the two. If the Ranges do not
+     * overlap, the newly created range will include the gap between the two.
+     * 
+     * @param other
+     *            The Range to merge.
+     */
+    public void merge(Range other) {
+        if (other.start < start) {
+            start = other.start;
+        }
+
+        if (other.end > end) {
+            end = other.end;
+        }
+    }
+
+    /**
+     * Split a range at a given split point. Splitting will truncate at the
+     * split location - 1 and return a new range beginning at location + 1; This
+     * code assumes that the split location is at neither end poing.
+     * 
+     * @param location
+     *            The split location. Location must be in the range start <
+     *            location < end.
+     * 
+     * @return A new Range object for the split portion of the range.
+     */
+    public Range split(int location) {
+        int newEnd = end;
+
+        end = location - 1;
+
+        return new Range(location + 1, newEnd);
+    }
+
+    /**
+     * Save an individual range element to a newsrc file. The range is expressed
+     * either as a single number, or a hypenated pair of numbers.
+     * 
+     * @param out
+     *            The output writer used to save the data.
+     * 
+     * @exception IOException
+     */
+    public void save(Writer out) throws IOException {
+        // do we have a single data point range?
+        if (start == end) {
+            out.write(Integer.toString(start));
+        } else {
+            out.write(Integer.toString(start));
+            out.write("-");
+            out.write(Integer.toString(end));
+        }
+    }
+
+    /**
+     * Convert a Range into String form. Used mostly for debugging.
+     * 
+     * @return The String representation of the Range.
+     */
+    public String toString() {
+        if (start == end) {
+            return Integer.toString(start);
+        } else {
+            return Integer.toString(start) + "-" + Integer.toString(end);
+        }
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/RangeList.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/RangeList.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/RangeList.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/newsrc/RangeList.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,227 @@
+/*
+ * 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.nntp.newsrc;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * Manage a list of ranges values from a newsrc file.
+ */
+public class RangeList {
+    boolean dirty = false;
+
+    ArrayList ranges = new ArrayList();
+
+    /**
+     * Create a RangeList instance from a newsrc range line. Values are saved as
+     * a comma separated set of range values. A range value is either a single
+     * number or a hypenated pair of numbers.
+     * 
+     * @param line
+     *            The newsrc range line.
+     */
+    public RangeList(String line) {
+
+        // we might be creating an first time list, so nothing to parse.
+        if (line != null) {
+            // ranges are comma delimited tokens
+            StringTokenizer tokenizer = new StringTokenizer(line, ",");
+
+            while (tokenizer.hasMoreTokens()) {
+                String rangeString = (String) tokenizer.nextToken();
+                rangeString = rangeString.trim();
+                if (rangeString.length() != 0) {
+                    Range range = Range.parse(rangeString);
+                    if (range != null) {
+                        insert(range);
+                    }
+                }
+            }
+        }
+        // make sure we start out in a clean state. Any changes from this point
+        // will flip on the dirty flat.
+        dirty = false;
+    }
+
+    /**
+     * Insert a range item into our list. If possible, the inserted range will
+     * be merged with existing ranges.
+     * 
+     * @param newRange
+     *            The new range item.
+     */
+    public void insert(Range newRange) {
+        // first find the insertion point
+        for (int i = 0; i < ranges.size(); i++) {
+            Range range = (Range) ranges.get(i);
+            // does an existing range fully contain the new range, we don't need
+            // to insert anything.
+            if (range.contains(newRange)) {
+                return;
+            }
+
+            // does the current one abutt or overlap with the inserted range?
+            if (range.abutts(newRange) || range.overlaps(newRange)) {
+                // rats, we have an overlap...and it is possible that we could
+                // overlap with
+                // the next range after this one too. Therefore, we merge these
+                // two ranges together,
+                // remove the place where we're at, and then recursively insert
+                // the larger range into
+                // the list.
+                dirty = true;
+                newRange.merge(range);
+                ranges.remove(i);
+                insert(newRange);
+                return;
+            }
+
+            // ok, we don't touch the current one at all. If it is completely
+            // above
+            // range we're adding, we can just poke this into the list here.
+            if (newRange.lessThan(range)) {
+                dirty = true;
+                ranges.add(i, newRange);
+                return;
+            }
+        }
+        dirty = true;
+        // this is easy (and fairly common)...we just tack this on to the end.
+        ranges.add(newRange);
+    }
+
+    /**
+     * Test if a given article point falls within one of the contained Ranges.
+     * 
+     * @param article
+     *            The test point.
+     * 
+     * @return true if this falls within one of our current mark Ranges, false
+     *         otherwise.
+     */
+    public boolean isMarked(int article) {
+        for (int i = 0; i < ranges.size(); i++) {
+            Range range = (Range) ranges.get(i);
+            if (range.contains(article)) {
+                return true;
+            }
+            // we've passed the point where a match is possible.
+            if (range.greaterThan(article)) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Mark a target article as having been seen.
+     * 
+     * @param article
+     *            The target article number.
+     */
+    public void setMarked(int article) {
+        // go through the insertion logic.
+        insert(new Range(article, article));
+    }
+
+    /**
+     * Clear the seen mark for a target article.
+     * 
+     * @param article
+     *            The target article number.
+     */
+    public void setUnmarked(int article) {
+        for (int i = 0; i < ranges.size(); i++) {
+            Range range = (Range) ranges.get(i);
+            // does this fall within an existing range? We don't need to do
+            // anything here.
+            if (range.contains(article)) {
+                // ok, we've found where to insert, now to figure out how to
+                // insert
+                // article is at the beginning of the range. We can just
+                // increment the lower
+                // bound, or if this is a single element range, we can remove it
+                // entirely.
+                if (range.getStart() == article) {
+                    if (range.getEnd() == article) {
+                        // piece of cake!
+                        ranges.remove(i);
+                    } else {
+                        // still pretty easy.
+                        range.setStart(article + 1);
+                    }
+                } else if (range.getEnd() == article) {
+                    // pretty easy also
+                    range.setEnd(article - 1);
+                } else {
+                    // split this into two ranges and insert the trailing piece
+                    // after this.
+                    Range section = range.split(article);
+                    ranges.add(i + 1, section);
+                }
+                dirty = true;
+                return;
+            }
+            // did we find a point where any articles are greater?
+            if (range.greaterThan(article)) {
+                // nothing to do
+                return;
+            }
+        }
+        // didn't find it at all. That was easy!
+    }
+
+    /**
+     * Save this List of Ranges out to a .newsrc file. This creates a
+     * comma-separated list of range values from each of the Ranges.
+     * 
+     * @param out
+     *            The target output stream.
+     * 
+     * @exception IOException
+     */
+    public void save(Writer out) throws IOException {
+        // we have an empty list
+        if (ranges.size() == 0) {
+            return;
+        }
+
+        Range range = (Range) ranges.get(0);
+        range.save(out);
+
+        for (int i = 1; i < ranges.size(); i++) {
+            out.write(",");
+            range = (Range) ranges.get(i);
+            range.save(out);
+        }
+    }
+
+    /**
+     * Return the state of the dirty flag.
+     * 
+     * @return True if the range list information has changed, false otherwise.
+     */
+    public boolean isDirty() {
+        return dirty;
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Constants.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Defines a few constants that are used throught the implementation.
+ * 
+ * @version $Rev$ $Date$
+ */
+
+public interface POP3Constants {
+    public final static String SPACE = " ";
+
+    public final static String CRLF = "\r\n";
+
+    public final static int DOT = '.';
+
+    public final static int OK = 0;
+
+    public final static int ERR = 1;
+    
+    public final static int CHALLENGE = 2;
+}
\ No newline at end of file

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java Wed Oct  7 15:58:39 2020
@@ -0,0 +1,515 @@
+/*
+ * 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.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;
+import javax.mail.Session;
+import javax.mail.Store;
+import javax.mail.URLName;
+import javax.mail.event.ConnectionEvent;
+
+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
+ * supported in POP3
+ * <p>
+ * <url>http://www.faqs.org/rfcs/rfc1939.html</url>
+ * </p>
+ * 
+ * @see Folder
+ * 
+ * @version $Rev$ $Date$
+ */
+public class POP3Folder extends Folder {
+
+    protected boolean isFolderOpen = false;
+
+    protected int mode;
+
+    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; 
+    
+    /**
+     * 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.
+     */
+     public POP3Folder(POP3Store store, String name) {
+        super(store);
+        this.fullName = name; 
+        // if this is the input folder, this exists 
+        if (name.equalsIgnoreCase("INBOX")) {
+            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; 
+	}
+
+    /**
+     * 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 {
+        // 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 {
+        // only one folder truely exists...this might be it.
+        return exists; 
+    }
+
+    public Folder[] list(String pattern) throws MessagingException {
+        throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
+    }
+
+    /**
+     * No sub folders, hence there is no notion of a seperator.  This is always a null character. 
+     */
+    public char getSeparator() throws MessagingException {
+        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 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 {
+        return false; 
+    }
+
+    /**
+     * No way to detect new messages, so always return false. 
+     * 
+     * @return Always returns false. 
+     * @exception MessagingException
+     */
+    public boolean hasNewMessages() throws MessagingException {
+        return false; 
+    }
+
+    public Folder getFolder(String name) throws MessagingException {
+        throw new MethodNotSupportedException("Only INBOX is supported in POP3, no sub folders");
+    }
+
+    public boolean delete(boolean recurse) throws MessagingException {
+        throw new MethodNotSupportedException("Only INBOX is supported in POP3 and INBOX cannot be deleted");
+    }
+
+    public boolean renameTo(Folder f) throws MessagingException {
+        throw new MethodNotSupportedException("Only INBOX is supported in POP3 and INBOX cannot be renamed");
+    }
+
+    /**
+     * @see Folder#open(int)
+     */
+    public void open(int mode) throws MessagingException {
+        // Can only be performed on a closed folder
+        checkClosed();
+
+        // get a connection object 
+        POP3Connection connection = getConnection(); 
+        
+        try {
+            POP3StatusResponse res = connection.retrieveMailboxStatus();
+            this.mode = mode;
+            this.isFolderOpen = true;
+            this.msgCount = res.getNumMessages();
+            // JavaMail API has no method in Folder to expose the total
+            // 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 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);
+        }
+        finally {
+            // return the connection when finished 
+            releaseConnection(connection); 
+        }
+
+        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();
+
+        // get a connection object 
+        POP3Connection connection = getConnection(); 
+        try {
+            // 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. 
+            connection.reset(); 
+            // clean up any messages marked for deletion 
+            expungeDeletedMessages(connection); 
+        } finally {
+            // return the connection when finished 
+            releaseConnection(connection); 
+            // cleanup the the state even if exceptions occur when deleting the 
+            // messages. 
+            cleanupFolder(false); 
+        }
+    }
+    
+    /**
+     * Mark any messages we've flagged as deleted from the 
+     * POP3 server before closing. 
+     * 
+     * @exception MessagingException
+     */
+    protected void expungeDeletedMessages(POP3Connection connection) 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 {
+                            connection.deleteMessage(i + 1); 
+                        } catch (MessagingException e) {
+                            throw new MessagingException("Exception deleting message number " + (i + 1), e); 
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * 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;
+		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 {
+        // we always get one from the store.  If we're fully single threaded, then 
+        // we can get away with just a single one. 
+        return getConnection(); 
+    }
+    
+    
+    /**
+     * Release the connection object back to the Folder instance.  
+     * 
+     * @param connection The connection being released.
+     * 
+     * @exception MessagingException
+     */
+    void releaseMessageConnection(POP3Connection connection) throws MessagingException {
+        // give this back to the store 
+        releaseConnection(connection); 
+    }
+
+    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;
+    }
+
+    public Flags getPermanentFlags() {
+        // unfortunately doesn't have a throws clause for this method
+        // throw new MethodNotSupportedException("POP3 doesn't support permanent
+        // flags");
+
+        // Better than returning null, save the extra condition from a user to
+        // check for null
+        // and avoids a NullPointerException for the careless.
+        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;
+    }
+
+    /**
+     * Checks wether the message is in cache, if not will create a new message
+     * object and return it.
+     * 
+     * @see Folder#getMessage(int)
+     */
+    public Message getMessage(int msgNum) throws MessagingException {
+        // Can only be performed on an Open folder
+        checkOpen();
+        if (msgNum < 1 || msgNum > getMessageCount()) {
+            throw new MessagingException("Invalid Message number");
+        }
+
+        Message msg = messageCache[msgNum - 1];
+        if (msg == null) {
+            msg = new POP3Message(this, msgNum); 
+            messageCache[msgNum - 1] = (POP3Message)msg; 
+        }
+
+        return msg;
+    }
+
+    public void appendMessages(Message[] msgs) throws MessagingException {
+        throw new MethodNotSupportedException("Message appending is not supported in POP3");
+
+    }
+
+    public Message[] expunge() throws MessagingException {
+        throw new MethodNotSupportedException("Expunge is not supported in POP3");
+    }
+
+    public int getMode() throws IllegalStateException {
+        // Can only be performed on an Open folder
+        checkOpen();
+        return mode;
+    }
+
+    /**
+     * @see Folder#fetch(Message[],
+     *      FetchProfile)
+     * 
+     * The JavaMail API recommends that this method be overrident to provide a
+     * meaningfull implementation.
+     */
+    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 (fp.contains(FetchProfile.Item.ENVELOPE)) {
+                // 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)) {
+                // 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.getFlags(); 
+            }
+            
+            if (fp.getHeaderNames().length > 0) {
+                // loading any header loads all headers, so just grab the header set. 
+                msg.getHeader("Subject"); 
+            }
+        }
+    }
+    
+    /**
+     * 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
+     * value and throwing an exception
+     */
+
+    /** Ensure the folder is open */
+    private void checkOpen() throws IllegalStateException {
+        if (!isFolderOpen) {
+            throw new IllegalStateException("Folder is not Open");
+        }
+    }
+
+    /** Ensure the folder is not open */
+    private void checkClosed() throws IllegalStateException {
+        if (isFolderOpen) {
+            throw new IllegalStateException("Folder is Open");
+        }
+    }
+
+    /**
+     * @see Folder#notifyMessageChangedListeners(int,
+     *      Message)
+     * 
+     * this method is protected and cannot be used outside of Folder, therefore
+     * had to explicitly expose it via a method in POP3Folder, so that
+     * POP3Message has access to it
+     * 
+     * Bad design on the part of the Java Mail API.
+     */
+    public void notifyMessageChangedListeners(int type, Message m) {
+        super.notifyMessageChangedListeners(type, m);
+    }
+
+    
+    /**
+     * Retrieve the connection attached to this folder.  Throws an
+     * exception if we don't have an active connection.
+     *
+     * @return The current connection object.
+     * @exception MessagingException
+     */
+    protected synchronized POP3Connection getConnection() throws MessagingException {
+        // request a connection from the central store. 
+        return ((POP3Store)store).getFolderConnection(this); 
+    }
+    
+    
+    /**
+     * Release our connection back to the Store.
+     * 
+     * @param connection The connection to release.
+     * 
+     * @exception MessagingException
+     */
+    protected void releaseConnection(POP3Connection connection) throws MessagingException {
+        // we need to release the connection to the Store once we're finished with it 
+        ((POP3Store)store).releaseFolderConnection(this, connection); 
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Message.java Wed Oct  7 15:58:39 2020
@@ -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);
+    }
+}

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3RootFolder.java Wed Oct  7 15:58:39 2020
@@ -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; 
+    }
+}
+
+

Added: geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java
URL: http://svn.apache.org/viewvc/geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java?rev=1882306&view=auto
==============================================================================
--- geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java (added)
+++ geronimo/javamail/trunk/geronimo-javamail_1.6/geronimo-javamail_1.6_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3SSLStore.java Wed Oct  7 15:58:39 2020
@@ -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);
+	}
+}
+
+