GERONIMO-4173 Add SSL support to the NNTP Store and Transport. 



git-svn-id: https://svn.apache.org/repos/asf/geronimo/javamail/trunk@673152 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPGroupFolder.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPGroupFolder.java
index 19e51fd..1c3941f 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPGroupFolder.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPGroupFolder.java
@@ -181,11 +181,11 @@
      * 
      * @exception MessagingException
      */
-    public void openFolder() throws MessagingException {
+    protected void openFolder() throws MessagingException {
         // update the group specifics, especially the message count.
         updateGroupStats();
 
-        // get a cache for retrieve articles
+        // get a cache for retrieved articles
         articles = new HashMap();
     }
 
@@ -252,6 +252,9 @@
      * @return An array of all messages in the group.
      */
     public Message[] getMessages() throws MessagingException {
+        // Can only be performed on an Open folder
+        checkOpen();
+        
         // we're going to try first with XHDR, which will allow us to retrieve
         // everything in one shot. If that
         // fails, we'll fall back on issing STAT commands for the entire article
@@ -273,7 +276,7 @@
                     String messageID = line.substring(pos + 1);
                     Integer key = new Integer(articleID);
                     // see if we have this message cached, If not, create it.
-                    Message message = (Message) articles.get(key);
+                    Message message = (Message)articles.get(key);
                     if (message == null) {
                         message = new NNTPMessage(this, (NNTPStore) store, key.intValue(), messageID);
                         articles.put(key, message);
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPSSLStore.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPSSLStore.java
new file mode 100644
index 0000000..58a0351
--- /dev/null
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPSSLStore.java
@@ -0,0 +1,44 @@
+/**
+ * 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 javax.mail.Session;
+import javax.mail.URLName;
+
+/**
+ * NNTP implementation of javax.mail.Store over an SSL connection.
+ *
+ * @version $Rev$ $Date$
+ */
+public class NNTPSSLStore extends NNTPStore {
+    /**
+     * Construct an NNTPSSLStore item.
+     *
+     * @param session The owning javamail Session.
+     * @param urlName The Store urlName, which can contain server target information.
+     */
+	public NNTPSSLStore(Session session, URLName urlName) {
+        // we're the imaps protocol, our default connection port is 563, and we must use
+        // an SSL connection for the initial hookup 
+		super(session, urlName, "nntps", DEFAULT_NNTP_SSL_PORT, true);
+	}
+}
+
+
+
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java
index b69bea4..0ab30fc 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/nntp/NNTPStore.java
@@ -33,6 +33,7 @@
 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;
 
 /**
@@ -42,45 +43,67 @@
  * @version $Rev$ $Date$
  */
 public class NNTPStore extends Store {
-
-    protected static final String NNTP_AUTH = "auth";
-
-    protected static final String NNTP_PORT = "port";
-
     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;
 
-    // the active connection object.
+    // 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 newsrc file where we store subscriptions and seen message markers.
-    protected NNTPNewsrc newsrc;
-
     // the root folder
     protected NNTPRootFolder root;
-
-    // our session provided debug output stream.
-    protected PrintStream debugStream;
-
+    // 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 urlName
+     * @param name
      *            The Store urlName, which can contain server target
      *            information.
      */
-    public NNTPStore(Session session, URLName urlName) {
-        super(session, urlName);
+    public NNTPStore(Session session, URLName name) {
+        this(session, name, "nntp", DEFAULT_NNTP_PORT, false);
+    }
 
-        // get our debug output.
-        debugStream = session.getDebugOut();
+    /**
+     * 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); 
     }
 
     /**
@@ -111,46 +134,36 @@
         return getDefaultFolder().getFolder(url.getFile());
     }
 
+    
     /**
-     * @see javax.mail.Service#protocolConnect(java.lang.String, int,
-     *      java.lang.String, java.lang.String)
+     * 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 synchronized boolean protocolConnect(String host, int port, String username, String password)
+    protected boolean protocolConnect(String host, int port, String username, String password)
             throws MessagingException {
-        if (debug) {
-            debugOut("Connecting to server " + host + ":" + port + " for user " + username);
+        // 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; 
         }
 
-        // first check to see if we need to authenticate. If we need this, then
-        // we must have a username and
-        // password specified. Failing this may result in a user prompt to
-        // collect the information.
-        boolean mustAuthenticate = getBooleanProperty(NNTP_AUTH, false);
-
-        // if we need to authenticate, and we don't have both a userid and
-        // password, then we fail this
-        // immediately. The Service.connect() method will try to obtain the user
-        // information and retry the
-        // connection one time.
-        if (mustAuthenticate && (username == null || password == null)) {
-            return false;
-        }
-
-        // if the port is defaulted, then see if we have something configured in
-        // the session.
-        // if not configured, we just use the default default.
-        if (port == -1) {
-            // check for a property and fall back on the default if it's not
-            // set.
-            port = getIntProperty(NNTP_PORT, DEFAULT_NNTP_PORT);
-        }
-
-        // create socket and connect to server.
-        connection = new NNTPConnection(protocol, session, host, port, username, password, debug);
-        connection.connect();
-
         // see if we have a newsrc file location specified
-        String newsrcFile = getProperty(NNTP_NEWSRC);
+        String newsrcFile = props.getProperty(NNTP_NEWSRC);
 
         File source = null;
 
@@ -178,10 +191,10 @@
         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.
+        // up asking for our bonafides at any time, and we'll be expected to authenticate then.
         return true;
     }
+    
 
     /**
      * @see javax.mail.Service#close()
@@ -190,7 +203,10 @@
         // This is done to ensure proper event notification.
         super.close();
         // persist the newsrc file, if possible
-        newsrc.close();
+        if (newsrc != null) {
+            newsrc.close();
+            newsrc = null; 
+        }
         connection.close();
         connection = null;
     }
@@ -202,30 +218,6 @@
     }
 
     /**
-     * Internal debug output routine.
-     * 
-     * @param value
-     *            The string value to output.
-     */
-    void debugOut(String message) {
-        debugStream.println("NNTPTransport 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);
-    }
-
-    /**
      * Retrieve the server connection created by this store.
      * 
      * @return The active connection object.
@@ -265,81 +257,4 @@
     NNTPNewsrcGroup getNewsrcGroup(String name) {
         return newsrc.getGroup(name);
     }
-
-    /**
-     * Get a property associated with this mail protocol.
-     * 
-     * @param name
-     *            The name of the property.
-     * 
-     * @return The property value (returns null if the property has not been
-     *         set).
-     */
-    String getProperty(String name) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return session.getProperty(fullName);
-    }
-
-    /**
-     * Get a property associated with this mail session. Returns the provided
-     * default if it doesn't exist.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value (returns defaultValue if the property has not
-     *         been set).
-     */
-    String getProperty(String name, String defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getProperty(session, fullName, defaultValue);
-    }
-
-    /**
-     * Get a property associated with this mail session as an integer value.
-     * Returns the default value if the property doesn't exist or it doesn't
-     * have a valid int value.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value converted to an int.
-     */
-    int getIntProperty(String name, int defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getIntProperty(session, fullName, defaultValue);
-    }
-
-    /**
-     * Get a property associated with this mail session as an boolean value.
-     * Returns the default value if the property doesn't exist or it doesn't
-     * have a valid int value.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value converted to a boolean
-     */
-    boolean getBooleanProperty(String name, boolean defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getBooleanProperty(session, fullName, defaultValue);
-    }
 }
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java
index a8ca219..00e7e8b 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPConnection.java
@@ -20,15 +20,18 @@
 package org.apache.geronimo.javamail.transport.nntp;
 
 import java.io.BufferedReader;
+import java.io.BufferedOutputStream; 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.io.PrintWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.util.ArrayList; 
 import java.util.HashMap;
 import java.util.List;
 import java.util.StringTokenizer;
@@ -37,14 +40,11 @@
 import javax.mail.MessagingException;
 import javax.mail.Session;
 
-import org.apache.geronimo.javamail.authentication.ClientAuthenticator;
-import org.apache.geronimo.javamail.authentication.CramMD5Authenticator;
-import org.apache.geronimo.javamail.authentication.DigestMD5Authenticator;
-import org.apache.geronimo.javamail.authentication.LoginAuthenticator;
-import org.apache.geronimo.javamail.authentication.PlainAuthenticator;
+import org.apache.geronimo.javamail.authentication.ClientAuthenticator; 
+import org.apache.geronimo.javamail.authentication.AuthenticatorFactory; 
+import org.apache.geronimo.javamail.util.MailConnection; 
 import org.apache.geronimo.javamail.util.MIMEOutputStream;
-import org.apache.geronimo.javamail.util.TraceInputStream;
-import org.apache.geronimo.javamail.util.TraceOutputStream;
+import org.apache.geronimo.javamail.util.ProtocolProperties; 
 import org.apache.geronimo.mail.util.Base64;
 import org.apache.geronimo.mail.util.SessionUtil;
 
@@ -56,7 +56,7 @@
  * 
  * @version $Rev$ $Date$
  */
-public class NNTPConnection {
+public class NNTPConnection extends MailConnection {
 
     /**
      * constants for EOL termination
@@ -68,158 +68,85 @@
     /**
      * property keys for protocol properties.
      */
-    protected static final String MAIL_NNTP_AUTH = "auth";
-
-    protected static final String MAIL_NNTP_PORT = "port";
-
-    protected static final String MAIL_NNTP_TIMEOUT = "timeout";
-
-    protected static final String MAIL_NNTP_SASL_REALM = "sasl.realm";
-
-    protected static final String MAIL_NNTP_FACTORY_CLASS = "socketFactory.class";
-
-    protected static final String MAIL_NNTP_FACTORY_FALLBACK = "fallback";
-
-    protected static final String MAIL_NNTP_LOCALADDRESS = "localaddress";
-
-    protected static final String MAIL_NNTP_LOCALPORT = "localport";
-
-    protected static final String MAIL_NNTP_QUITWAIT = "quitwait";
-
-    protected static final String MAIL_NNTP_FACTORY_PORT = "socketFactory.port";
-
-    protected static final String MAIL_NNTP_ENCODE_TRACE = "encodetrace";
-
-    protected static final int MIN_MILLIS = 1000 * 60;
-
-    protected static final int TIMEOUT = MIN_MILLIS * 5;
-
-    protected static final String DEFAULT_MAIL_HOST = "localhost";
-
     protected static final int DEFAULT_NNTP_PORT = 119;
-
-    protected static final String AUTHENTICATION_PLAIN = "PLAIN";
-
-    protected static final String AUTHENTICATION_LOGIN = "LOGIN";
-
-    protected static final String AUTHENTICATION_CRAMMD5 = "CRAM-MD5";
-
-    protected static final String AUTHENTICATION_DIGESTMD5 = "DIGEST-MD5";
-
-    // the protocol in use (either nntp or nntp-post).
-    String protocol;
-
-    // the target host
-    protected String host;
-
-    // the target server port.
-    protected int port;
-
-    // the connection socket...can be a plain socket or SSLSocket, if TLS is
-    // being used.
-    protected Socket socket;
-
-    // input stream used to read data. If Sasl is in use, this might be other
-    // than the
-    // direct access to the socket input stream.
-    protected InputStream inputStream;
-
-    // the test reader wrapped around the input stream.
-    protected BufferedReader in;
-
-    // the other end of the connection pipeline.
-    protected OutputStream outputStream;
-
     // does the server support posting?
     protected boolean postingAllowed = true;
-
-    // the username we connect with
-    protected String username;
-
-    // the authentication password.
-    protected String password;
-
-    // the target SASL realm (normally null unless explicitly set or we have an
-    // authentication mechanism that
-    // requires it.
-    protected String realm;
-
+    
+    // different authentication mechanisms 
+    protected boolean authInfoUserAllowed = false; 
+    protected boolean authInfoSaslAllowed = false; 
+    
     // the last response line received from the server.
     protected NNTPReply lastServerResponse = null;
 
-    // our attached session
-    protected Session session;
-
-    // our session provided debug output stream.
-    protected PrintStream debugStream;
-
-    // our debug flag (passed from the hosting transport)
-    protected boolean debug;
-
-    // list of authentication mechanisms supported by the server
-    protected HashMap serverAuthenticationMechanisms;
-
     // map of server extension arguments
     protected HashMap serverExtensionArgs;
 
     // the welcome string from the server.
     protected String welcomeString = null;
+    
+    // input reader wrapped around the socket input stream 
+    protected BufferedReader reader; 
+    // output writer wrapped around the socket output stream. 
+    protected PrintWriter writer; 
 
     /**
      * Normal constructor for an NNTPConnection() object.
      * 
-     * @param session
-     *            The attached session.
-     * @param host
-     *            The target host name of the NNTP 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 debug
-     *            The session debug flag.
+     * @param props  The property bundle for this protocol instance.
      */
-    public NNTPConnection(String protocol, Session session, String host, int port, String username, String password,
-            boolean debug) {
-        this.protocol = protocol;
-        this.session = session;
-        this.host = host;
-        this.port = port;
-        this.username = username;
-        this.password = password;
-        this.debug = debug;
-
-        // get our debug output.
-        debugStream = session.getDebugOut();
+    public NNTPConnection(ProtocolProperties props) {
+        super(props);
     }
-
+    
+    
     /**
      * Connect to the server and do the initial handshaking.
      * 
+     * @param host     The target host name.
+     * @param port     The target port
+     * @param username The connection username (can be null)
+     * @param password The authentication password (can be null).
+     * 
+     * @return true if we were able to obtain a connection and 
+     *         authenticate.
      * @exception MessagingException
      */
-    public void connect() throws MessagingException {
-        try {
+    public boolean protocolConnect(String host, int port, String username, String password) throws MessagingException {
+        super.protocolConnect(host, port, username, password); 
+        // create socket and connect to server.
+        getConnection();
 
-            // create socket and connect to server.
-            getConnection();
-
-            // receive welcoming message
-            getWelcome();
-
-        } catch (IOException e) {
-            if (debug) {
-                debugOut("I/O exception establishing connection", e);
-            }
-            throw new MessagingException("Connection error", e);
-        }
+        // receive welcoming message
+        getWelcome();
+        
+        return true; 
     }
 
+
+    /**
+     * Create a transport connection object and connect it to the
+     * target server.
+     *
+     * @exception MessagingException
+     */
+    protected void getConnection() throws MessagingException
+    {
+        try {
+            // do all of the non-protocol specific set up.  This will get our socket established 
+            // and ready use. 
+            super.getConnection(); 
+        } catch (IOException e) {
+            throw new MessagingException("Unable to obtain a connection to the NNTP server", e); 
+        }
+        
+        // The NNTP protocol is inherently a string-based protocol, so we get 
+        // string readers/writers for the connection streams 
+        reader = new BufferedReader(new InputStreamReader(inputStream));
+        writer = new PrintWriter(new BufferedOutputStream(outputStream));
+    }
+    
+
     /**
      * Close the connection. On completion, we'll be disconnected from the
      * server and unable to send more data.
@@ -239,164 +166,16 @@
             // make sure the connection
             // is shut down even if quit gets an error.
             closeServerConnection();
+            // get rid of our response processor too. 
+            reader = null; 
+            writer = null; 
         }
     }
 
-    /**
-     * Create a transport connection object and connect it to the target server.
-     * 
-     * @exception MessagingException
-     */
-    protected void getConnection() throws IOException {
-        // We might have been passed a socket to connect with...if not, we need
-        // to create one of the correct type.
-        if (socket == null) {
-            getConnectedSocket();
-        }
-        // if we already have a socket, get some information from it and
-        // override what we've been passed.
-        else {
-            port = socket.getPort();
-            host = socket.getInetAddress().getHostName();
-        }
-
-        // now set up the input/output streams.
-        inputStream = new TraceInputStream(socket.getInputStream(), debugStream, debug, getBooleanProperty(
-                MAIL_NNTP_ENCODE_TRACE, false));
-        ;
-        outputStream = new TraceOutputStream(socket.getOutputStream(), debugStream, debug, getBooleanProperty(
-                MAIL_NNTP_ENCODE_TRACE, false));
-
-        // get a reader to read the input as lines
-        in = new BufferedReader(new InputStreamReader(inputStream));
+    public String toString() {
+        return "NNTPConnection host: " + serverHost + " port: " + serverPort;
     }
-
-    /**
-     * Close the server connection at termination.
-     */
-    public void closeServerConnection() {
-        try {
-            socket.close();
-        } catch (IOException ignored) {
-        }
-
-        socket = null;
-        inputStream = null;
-        outputStream = null;
-        in = null;
-    }
-
-    /**
-     * Creates a connected socket
-     * 
-     * @exception MessagingException
-     */
-    public void getConnectedSocket() throws IOException {
-        if (debug) {
-            debugOut("Attempting plain socket connection to server " + host + ":" + port);
-        }
-
-        // the socket factory can be specified via a session property. By
-        // default, we just directly
-        // instantiate a socket without using a factor.
-        String socketFactory = getProperty(MAIL_NNTP_FACTORY_CLASS);
-
-        // there are several protocol properties that can be set to tune the
-        // created socket. We need to
-        // retrieve those bits before creating the socket.
-        int timeout = getIntProperty(MAIL_NNTP_TIMEOUT, -1);
-        InetAddress localAddress = null;
-        // see if we have a local address override.
-        String localAddrProp = getProperty(MAIL_NNTP_LOCALADDRESS);
-        if (localAddrProp != null) {
-            localAddress = InetAddress.getByName(localAddrProp);
-        }
-
-        // check for a local port...default is to allow socket to choose.
-        int localPort = getIntProperty(MAIL_NNTP_LOCALPORT, 0);
-
-        socket = null;
-
-        // if there is no socket factory defined (normal), we just create a
-        // socket directly.
-        if (socketFactory == null) {
-            socket = new Socket(host, port, localAddress, localPort);
-        }
-
-        else {
-            try {
-                int socketFactoryPort = getIntProperty(MAIL_NNTP_FACTORY_PORT, -1);
-
-                // we choose the port used by the socket based on overrides.
-                Integer portArg = new Integer(socketFactoryPort == -1 ? port : socketFactoryPort);
-
-                // use the current context loader to resolve this.
-                ClassLoader loader = Thread.currentThread().getContextClassLoader();
-                Class factoryClass = loader.loadClass(socketFactory);
-
-                // done indirectly, we need to invoke the method using
-                // reflection.
-                // This retrieves a factory instance.
-                Method getDefault = factoryClass.getMethod("getDefault", new Class[0]);
-                Object defFactory = getDefault.invoke(new Object(), new Object[0]);
-
-                // now that we have the factory, there are two different
-                // createSocket() calls we use,
-                // depending on whether we have a localAddress override.
-
-                if (localAddress != null) {
-                    // retrieve the createSocket(String, int, InetAddress, int)
-                    // method.
-                    Class[] createSocketSig = new Class[] { String.class, Integer.TYPE, InetAddress.class, Integer.TYPE };
-                    Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
-
-                    Object[] createSocketArgs = new Object[] { host, portArg, localAddress, new Integer(localPort) };
-                    socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
-                } else {
-                    // retrieve the createSocket(String, int) method.
-                    Class[] createSocketSig = new Class[] { String.class, Integer.TYPE };
-                    Method createSocket = factoryClass.getMethod("createSocket", createSocketSig);
-
-                    Object[] createSocketArgs = new Object[] { host, portArg };
-                    socket = (Socket) createSocket.invoke(defFactory, createSocketArgs);
-                }
-            } catch (Throwable e) {
-                // if a socket factor is specified, then we may need to fall
-                // back to a default. This behavior
-                // is controlled by (surprise) more session properties.
-                if (getBooleanProperty(MAIL_NNTP_FACTORY_FALLBACK, false)) {
-                    if (debug) {
-                        debugOut("First plain socket attempt faile, falling back to default factory", e);
-                    }
-                    socket = new Socket(host, port, localAddress, localPort);
-                }
-                // we have an exception. We're going to throw an IOException,
-                // which may require unwrapping
-                // or rewrapping the exception.
-                else {
-                    // we have an exception from the reflection, so unwrap the
-                    // base exception
-                    if (e instanceof InvocationTargetException) {
-                        e = ((InvocationTargetException) e).getTargetException();
-                    }
-
-                    if (debug) {
-                        debugOut("Plain socket creation failure", e);
-                    }
-
-                    // throw this as an IOException, with the original exception
-                    // attached.
-                    IOException ioe = new IOException("Error connecting to " + host + ", " + port);
-                    ioe.initCause(e);
-                    throw ioe;
-                }
-            }
-        }
-
-        if (timeout >= 0) {
-            socket.setSoTimeout(timeout);
-        }
-    }
+    
 
     /**
      * Get the servers welcome blob from the wire....
@@ -423,21 +202,14 @@
         getExtensions();
     }
 
+    
     /**
      * Sends the QUIT message and receieves the response
      */
     public void sendQuit() throws MessagingException {
-        // there's yet another property that controls whether we should wait for
-        // a
-        // reply for a QUIT command. If on, just send the command and get outta
-        // here.
-        if (getBooleanProperty(MAIL_NNTP_QUITWAIT, false)) {
-            sendLine("QUIT");
-        } else {
-            // handle as a real command...we're going to ignore the response.
-            sendCommand("QUIT");
-        }
+        sendLine("QUIT");
     }
+    
 
     /**
      * Tell the server to switch to a named group.
@@ -451,6 +223,7 @@
         // send the GROUP command
         return sendCommand("GROUP " + name);
     }
+    
 
     /**
      * Ask the server what extensions it supports.
@@ -462,15 +235,15 @@
         NNTPReply reply = sendCommand("LIST EXTENSIONS", NNTPReply.EXTENSIONS_SUPPORTED);
 
         // we get a 202 code back. The first line is just a greeting, and
-        // extensions are deliverd as data
+        // extensions are delivered as data
         // lines terminated with a "." line.
         if (reply.getCode() != NNTPReply.EXTENSIONS_SUPPORTED) {
             return;
         }
 
         // get a fresh extension mapping table.
-        serverExtensionArgs = new HashMap();
-        serverAuthenticationMechanisms = new HashMap();
+        capabilities = new HashMap();
+        authentications = new ArrayList(); 
 
         // get the extension data lines.
         List extensions = reply.getData();
@@ -482,8 +255,9 @@
         }
     }
 
+    
     /**
-     * Process an extension string passed back as the EHLP response.
+     * Process an extension string passed back as the LIST EXTENSIONS response.
      * 
      * @param extension
      *            The string value of the extension (which will be of the form
@@ -502,12 +276,22 @@
         }
 
         // add this to the map so it can be tested later.
-        serverExtensionArgs.put(extensionName, argument);
+        capabilities.put(extensionName, argument);
 
-        // process a few special ones that don't require extra parsing.
-        // AUTHINFO is entered in as a auth mechanism.
+        // we need to determine which authentication mechanisms are supported here 
         if (extensionName.equals("AUTHINFO")) {
-            serverAuthenticationMechanisms.put("AUTHINFO", "AUTHINFO");
+            StringTokenizer tokenizer = new StringTokenizer(argument); 
+            
+            while (tokenizer.hasMoreTokens()) {
+                // we only know how to do USER or SASL 
+                String mechanism = tokenizer.nextToken().toUpperCase();
+                if (mechanism.equals("SASL")) {
+                    authInfoSaslAllowed = true; 
+                }
+                else if (mechanism.equals("USER")) {
+                    authInfoUserAllowed = true; 
+                }
+            }
         }
         // special case for some older servers.
         else if (extensionName.equals("SASL")) {
@@ -516,10 +300,11 @@
 
             while (tokenizer.hasMoreTokens()) {
                 String mechanism = tokenizer.nextToken().toUpperCase();
-                serverAuthenticationMechanisms.put(mechanism, mechanism);
+                authentications.add(mechanism);
             }
         }
     }
+    
 
     /**
      * Retrieve any argument information associated with a extension reported
@@ -554,19 +339,7 @@
         return extensionParameter(name) != null;
     }
 
-    /**
-     * Determine if the target server supports a given authentication mechanism.
-     * 
-     * @param mechanism
-     *            The mechanism name.
-     * 
-     * @return true if the server EHLO response indicates it supports the
-     *         mechanism, false otherwise.
-     */
-    protected boolean supportsAuthentication(String mechanism) {
-        return serverAuthenticationMechanisms.get(mechanism) != null;
-    }
-
+    
     /**
      * Sends the data in the message down the socket. This presumes the server
      * is in the right place and ready for getting the DATA message and the data
@@ -598,20 +371,20 @@
             // The MIME output stream performs those two functions on behalf of
             // the content
             // writer.
-            OutputStream mimeOut = new MIMEOutputStream(outputStream);
+            MIMEOutputStream mimeOut = new MIMEOutputStream(outputStream);
 
             msg.writeTo(mimeOut);
-            mimeOut.flush();
+
+            // now to finish, we send a CRLF sequence, followed by a ".".
+            mimeOut.writeSMTPTerminator();           
+            // and flush the data to send it along 
+            mimeOut.flush();   
         } catch (IOException e) {
             throw new MessagingException("I/O error posting message", e);
         } catch (MessagingException e) {
             throw new MessagingException("Exception posting message", e);
         }
 
-        // now to finish, we send a CRLF sequence, followed by a ".".
-        sendLine("");
-        sendLine(".");
-
         // use a longer time out here to give the server time to process the
         // data.
         line = new NNTPReply(receiveLine());
@@ -637,7 +410,7 @@
     public synchronized NNTPReply sendCommand(String command, int success) throws MessagingException {
         NNTPReply reply = sendCommand(command);
         if (reply.getCode() == success) {
-            reply.retrieveData(in);
+            reply.retrieveData(reader);
         }
         return reply;
     }
@@ -660,9 +433,7 @@
         // response to be sent at any time, so we need to try to authenticate
         // and then retry the command.
         if (reply.getCode() == NNTPReply.AUTHINFO_REQUIRED || reply.getCode() == NNTPReply.AUTHINFO_SIMPLE_REQUIRED) {
-            if (debug) {
-                debugOut("Authentication required received from server.");
-            }
+            debugOut("Authentication required received from server.");
             // authenticate with the server, if necessary
             processAuthentication(reply.getCode());
             // if we've safely authenticated, we can reissue the command and
@@ -740,7 +511,7 @@
         }
 
         try {
-            String line = in.readLine();
+            String line = reader.readLine();
             if (line == null) {
                 throw new MessagingException("Unexpected end of stream");
             }
@@ -750,31 +521,7 @@
         }
     }
 
-    /**
-     * Retrieve the SASL realm used for DIGEST-MD5 authentication. This will
-     * either be explicitly set, or retrieved using the mail.nntp.sasl.realm
-     * session property.
-     * 
-     * @return The current realm information (which can be null).
-     */
-    public String getSASLRealm() {
-        // if the realm is null, retrieve it using the realm session property.
-        if (realm == null) {
-            realm = getProperty(MAIL_NNTP_SASL_REALM);
-        }
-        return realm;
-    }
-
-    /**
-     * Explicitly set the SASL realm used for DIGEST-MD5 authenticaiton.
-     * 
-     * @param name
-     *            The new realm name.
-     */
-    public void setSASLRealm(String name) {
-        realm = name;
-    }
-
+    
     /**
      * Authenticate with the server, if necessary (or possible).
      */
@@ -789,7 +536,7 @@
         if (request == NNTPReply.AUTHINFO_SIMPLE_REQUIRED) {
             processAuthinfoSimple();
         } else {
-            if (!processAuthinfoSasl()) {
+            if (!processSaslAuthentication()) {
                 processAuthinfoUser();
             }
         }
@@ -812,49 +559,53 @@
         }
     }
 
+    
     /**
-     * Process AUTHINFO GENERIC. Right now, this appears not to be widely used
-     * and information on how the conversations are handled for different auth
-     * types is lacking, so right now, this just returns false to force the
-     * userid/password form to be used.
+     * Process SASL-type authentication.
      * 
-     * @return Always returns false.
+     * @return Returns true if the server support a SASL authentication mechanism and
+     *         accepted reponse challenges.
      * @exception MessagingException
      */
-    protected boolean processAuthinfoGeneric() throws MessagingException {
-        return false;
+    protected boolean processSaslAuthentication() throws MessagingException {
+        // only do this if permitted 
+        if (!authInfoSaslAllowed) {
+            return false; 
+        }
+        // if unable to get an appropriate authenticator, just fail it. 
+        ClientAuthenticator authenticator = getSaslAuthenticator(); 
+        if (authenticator == null) {
+            throw new MessagingException("Unable to obtain SASL authenticator"); 
+        }
+        
+        // go process the login.
+        return processLogin(authenticator);
+    }
+    
+    /**
+     * Attempt to retrieve a SASL authenticator for this 
+     * protocol. 
+     * 
+     * @return A SASL authenticator, or null if a suitable one 
+     *         was not located.
+     */
+    protected ClientAuthenticator getSaslAuthenticator() {
+        return AuthenticatorFactory.getAuthenticator(props, selectSaslMechanisms(), serverHost, username, password, authid, realm); 
     }
 
+
     /**
-     * Process AUTHINFO SASL.
+     * Process a login using the provided authenticator object.
      * 
-     * @return Returns true if the server support a SASL authentication
-     *         mechanism and accepted reponse challenges.
+     * NB:  This method is synchronized because we have a multi-step process going on 
+     * here.  No other commands should be sent to the server until we complete. 
+     *
+     * @return Returns true if the server support a SASL authentication mechanism and
+     * accepted reponse challenges.
      * @exception MessagingException
      */
-    protected boolean processAuthinfoSasl() throws MessagingException {
-        ClientAuthenticator authenticator = null;
-
-        // now go through the progression of mechanisms we support, from the
-        // most secure to the
-        // least secure.
-
-        if (supportsAuthentication(AUTHENTICATION_DIGESTMD5)) {
-            authenticator = new DigestMD5Authenticator(host, username, password, getSASLRealm());
-        } else if (supportsAuthentication(AUTHENTICATION_CRAMMD5)) {
-            authenticator = new CramMD5Authenticator(username, password);
-        } else if (supportsAuthentication(AUTHENTICATION_LOGIN)) {
-            authenticator = new LoginAuthenticator(username, password);
-        } else if (supportsAuthentication(AUTHENTICATION_PLAIN)) {
-            authenticator = new PlainAuthenticator(username, password);
-        } else {
-            // can't find a mechanism we support in common
-            return false;
-        }
-
-        if (debug) {
-            debugOut("Authenticating for user: " + username + " using " + authenticator.getMechanismName());
-        }
+    protected synchronized boolean processLogin(ClientAuthenticator authenticator) throws MessagingException {
+        debugOut("Authenticating for user: " + username + " using " + authenticator.getMechanismName());
 
         // if the authenticator has some initial data, we compose a command
         // containing the initial data.
@@ -891,9 +642,7 @@
             // if we get a completion return, we've passed muster, so give an
             // authentication response.
             if (line.getCode() == NNTPReply.AUTHINFO_ACCEPTED || line.getCode() == NNTPReply.AUTHINFO_ACCEPTED_FINAL) {
-                if (debug) {
-                    debugOut("Successful SMTP authentication");
-                }
+                debugOut("Successful SMTP authentication");
                 return true;
             }
             // we have an additional challenge to process.
@@ -902,9 +651,7 @@
                 // an additional challenge,
                 // so fail this.
                 if (authenticator.isComplete()) {
-                    if (debug) {
-                        debugOut("Extra authentication challenge " + line);
-                    }
+                    debugOut("Extra authentication challenge " + line);
                     return false;
                 }
 
@@ -919,14 +666,13 @@
             // handle. Anything else must
             // be a failure.
             else {
-                if (debug) {
-                    debugOut("Authentication failure " + line);
-                }
+                debugOut("Authentication failure " + line);
                 return false;
             }
         }
     }
 
+    
     /**
      * Process an AUTHINFO USER command. Most common form of NNTP
      * authentication.
@@ -934,6 +680,10 @@
      * @exception MessagingException
      */
     protected void processAuthinfoUser() throws MessagingException {
+        // only do this if allowed by the server 
+        if (!authInfoUserAllowed) {
+            return; 
+        }
         NNTPReply reply = sendAuthCommand("AUTHINFO USER " + username);
         // accepted without a password (uncommon, but allowed), we're done
         if (reply.getCode() == NNTPReply.AUTHINFO_ACCEPTED) {
@@ -950,30 +700,7 @@
         }
     }
 
-    /**
-     * Internal debug output routine.
-     * 
-     * @param value
-     *            The string value to output.
-     */
-    protected void debugOut(String message) {
-        debugStream.println("NNTPTransport DEBUG: " + message);
-    }
-
-    /**
-     * Internal debugging routine for reporting exceptions.
-     * 
-     * @param message
-     *            A message associated with the exception context.
-     * @param e
-     *            The received exception.
-     */
-    protected void debugOut(String message, Throwable e) {
-        debugOut("Received exception -> " + message);
-        debugOut("Exception message -> " + e.getMessage());
-        e.printStackTrace(debugStream);
-    }
-
+    
     /**
      * Indicate whether posting is allowed for a given server.
      * 
@@ -992,90 +719,4 @@
     public String getWelcomeString() {
         return welcomeString;
     }
-
-    /**
-     * Return the server host for this connection.
-     * 
-     * @return The String name of the server host.
-     */
-    public String getHost() {
-        return host;
-    }
-
-    /**
-     * Get a property associated with this mail protocol.
-     * 
-     * @param name
-     *            The name of the property.
-     * 
-     * @return The property value (returns null if the property has not been
-     *         set).
-     */
-    String getProperty(String name) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return session.getProperty(fullName);
-    }
-
-    /**
-     * Get a property associated with this mail session. Returns the provided
-     * default if it doesn't exist.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value (returns defaultValue if the property has not
-     *         been set).
-     */
-    String getProperty(String name, String defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getProperty(session, fullName, defaultValue);
-    }
-
-    /**
-     * Get a property associated with this mail session as an integer value.
-     * Returns the default value if the property doesn't exist or it doesn't
-     * have a valid int value.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value converted to an int.
-     */
-    int getIntProperty(String name, int defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getIntProperty(session, fullName, defaultValue);
-    }
-
-    /**
-     * Get a property associated with this mail session as an boolean value.
-     * Returns the default value if the property doesn't exist or it doesn't
-     * have a valid int value.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value converted to a boolean
-     */
-    boolean getBooleanProperty(String name, boolean defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getBooleanProperty(session, fullName, defaultValue);
-    }
 }
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPReply.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPReply.java
index 6328b92..676458b 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPReply.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPReply.java
@@ -33,6 +33,8 @@
  */
 public class NNTPReply {
     // general server responses
+    public static final int CAPABILITY_LIST = 101; 
+    
     public static final int POSTING_ALLOWED = 200;
 
     public static final int NO_POSTING_ALLOWED = 201;
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPSSLTransport.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPSSLTransport.java
new file mode 100644
index 0000000..e27a064
--- /dev/null
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPSSLTransport.java
@@ -0,0 +1,34 @@
+/*
+ * 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.transport.nntp;
+
+import javax.mail.Session;
+import javax.mail.URLName;
+
+public class NNTPSSLTransport extends NNTPTransport {
+    /**
+     * @param session
+     * @param name
+     */
+    public NNTPSSLTransport(Session session, URLName name) {
+        super(session, name, "nntp-posts", DEFAULT_NNTP_SSL_PORT, true);
+    }
+}
+
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPTransport.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPTransport.java
index 8942944..93f4060 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPTransport.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/transport/nntp/NNTPTransport.java
@@ -33,7 +33,7 @@
 import javax.mail.internet.MimeMessage;
 import javax.mail.internet.NewsAddress;
 
-import org.apache.geronimo.mail.util.SessionUtil;
+import org.apache.geronimo.javamail.util.ProtocolProperties; 
 
 /**
  * Simple implementation of NNTP transport. Just does plain RFC977-ish delivery.
@@ -44,26 +44,20 @@
  * @version $Rev$ $Date$
  */
 public class NNTPTransport extends Transport {
-
     /**
      * property keys for protocol properties.
      */
-    protected static final String NNTP_AUTH = "auth";
-
-    protected static final String NNTP_PORT = "port";
-
     protected static final String NNTP_FROM = "from";
 
-    protected static final String protocol = "nntp-post";
-
     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;
 
-    // our session provided debug output stream.
-    protected PrintStream debugStream;
-
     /**
      * Normal constructor for an NNTPTransport() object. This constructor is
      * used to build a transport instance for the "smtp" protocol.
@@ -74,10 +68,37 @@
      *            An optional URLName object containing target information.
      */
     public NNTPTransport(Session session, URLName name) {
-        super(session, name);
+        this(session, name, "nntp-post", DEFAULT_NNTP_PORT, false);
+    }
 
-        // get our debug output.
-        debugStream = session.getDebugOut();
+    /**
+     * Common constructor used by the POP3Store and POP3SSLStore classes
+     * to do common initialization of defaults.
+     *
+     * @param session
+     *            The host session instance.
+     * @param name
+     *            The URLName of the target.
+     * @param protocol
+     *            The protocol type ("pop3"). This helps us in
+     *            retrieving protocol-specific session properties.
+     * @param defaultPort
+     *            The default port used by this protocol. For pop3, this will
+     *            be 110. The default for pop3 with ssl is 995.
+     * @param sslConnection
+     *            Indicates whether an SSL connection should be used to initial
+     *            contact the server. This is different from the STARTTLS
+     *            support, which switches the connection to SSL after the
+     *            initial startup.
+     */
+    protected NNTPTransport(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); 
     }
 
     /**
@@ -101,43 +122,10 @@
      */
     protected boolean protocolConnect(String host, int port, String username, String password)
             throws MessagingException {
-        if (debug) {
-            debugOut("Connecting to server " + host + ":" + port + " for user " + username);
-        }
-
-        // first check to see if we need to authenticate. If we need this, then
-        // we must have a username and
-        // password specified. Failing this may result in a user prompt to
-        // collect the information.
-        boolean mustAuthenticate = SessionUtil.getBooleanProperty(session, NNTP_AUTH, false);
-
-        // if we need to authenticate, and we don't have both a userid and
-        // password, then we fail this
-        // immediately. The Service.connect() method will try to obtain the user
-        // information and retry the
-        // connection one time.
-        if (mustAuthenticate && (username == null || password == null)) {
-            return false;
-        }
-
-        // if the port is defaulted, then see if we have something configured in
-        // the session.
-        // if not configured, we just use the default default.
-        if (port == -1) {
-            // check for a property and fall back on the default if it's not
-            // set.
-            port = SessionUtil.getIntProperty(session, NNTP_PORT, DEFAULT_NNTP_PORT);
-        }
-
-        // create socket and connect to server.
-        connection = new NNTPConnection(protocol, session, host, port, username, password, debug);
-        connection.connect();
-
-        // 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;
+        // the connection pool handles all of the details here. 
+        return connection.protocolConnect(host, port, username, password);
     }
+    
 
     /**
      * Send a message to multiple addressees.
@@ -178,7 +166,7 @@
         // the property version, if available.
         if (fromAddresses == null || fromAddresses.length == 0) {
             // the from value can be set explicitly as a property
-            String defaultFrom = session.getProperty(NNTP_FROM);
+            String defaultFrom = props.getProperty(NNTP_FROM);
             if (defaultFrom == null) {
                 message.setFrom(new InternetAddress(defaultFrom));
             }
@@ -269,105 +257,4 @@
         connection.close();
         connection = null;
     }
-
-    /**
-     * Internal debug output routine.
-     * 
-     * @param value
-     *            The string value to output.
-     */
-    protected void debugOut(String message) {
-        debugStream.println("NNTPTransport DEBUG: " + message);
-    }
-
-    /**
-     * Internal debugging routine for reporting exceptions.
-     * 
-     * @param message
-     *            A message associated with the exception context.
-     * @param e
-     *            The received exception.
-     */
-    protected void debugOut(String message, Throwable e) {
-        debugOut("Received exception -> " + message);
-        debugOut("Exception message -> " + e.getMessage());
-        e.printStackTrace(debugStream);
-    }
-
-    /**
-     * Get a property associated with this mail protocol.
-     * 
-     * @param name
-     *            The name of the property.
-     * 
-     * @return The property value (returns null if the property has not been
-     *         set).
-     */
-    String getProperty(String name) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return session.getProperty(fullName);
-    }
-
-    /**
-     * Get a property associated with this mail session. Returns the provided
-     * default if it doesn't exist.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value (returns defaultValue if the property has not
-     *         been set).
-     */
-    String getProperty(String name, String defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getProperty(session, fullName, defaultValue);
-    }
-
-    /**
-     * Get a property associated with this mail session as an integer value.
-     * Returns the default value if the property doesn't exist or it doesn't
-     * have a valid int value.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value converted to an int.
-     */
-    int getIntProperty(String name, int defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getIntProperty(session, fullName, defaultValue);
-    }
-
-    /**
-     * Get a property associated with this mail session as an boolean value.
-     * Returns the default value if the property doesn't exist or it doesn't
-     * have a valid int value.
-     * 
-     * @param name
-     *            The name of the property.
-     * @param defaultValue
-     *            The default value to return if the property doesn't exist.
-     * 
-     * @return The property value converted to a boolean
-     */
-    boolean getBooleanProperty(String name, boolean defaultValue) {
-        // the name we're given is the least qualified part of the name. We
-        // construct the full property name
-        // using the protocol (either "nntp" or "nntp-post").
-        String fullName = "mail." + protocol + "." + name;
-        return SessionUtil.getBooleanProperty(session, fullName, defaultValue);
-    }
 }
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java
index 35127c8..e8475b5 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/util/MailConnection.java
@@ -67,6 +67,7 @@
     protected static final String MAIL_TIMEOUT = "timeout";
     protected static final String MAIL_SASL_ENABLE = "sasl.enable";
     protected static final String MAIL_SASL_REALM = "sasl.realm";
+    protected static final String MAIL_AUTHORIZATIONID = "sasl.authorizationid"; 
     protected static final String MAIL_SASL_MECHANISMS = "sasl.mechanisms";
     protected static final String MAIL_PLAIN_DISABLE = "auth.plain.disable";
     protected static final String MAIL_LOGIN_DISABLE = "auth.login.disable";
@@ -151,8 +152,6 @@
     // property list of authentication mechanisms
     protected List mechanisms; 
     
-
-    
     protected MailConnection(ProtocolProperties props) 
     {
         // this is our properties retriever utility, which will look up 
@@ -172,6 +171,54 @@
     
     
     /**
+     * Connect to the server and do the initial handshaking.
+     * 
+     * @param host     The target host name.
+     * @param port     The target port
+     * @param username The connection username (can be null)
+     * @param password The authentication password (can be null).
+     * 
+     * @return true if we were able to obtain a connection and 
+     *         authenticate.
+     * @exception MessagingException
+     */
+    public boolean protocolConnect(String host, int port, String username, String password) throws MessagingException {
+        // NOTE:  We don't check for the username/password being null at this point.  It's possible that 
+        // the server will send back a PREAUTH response, which means we don't need to go through login 
+        // processing.  We'll need to check the capabilities response after we make the connection to decide 
+        // if logging in is necesssary. 
+        
+        // save this for subsequent connections.  All pool connections will use this info.
+        // if the port is defaulted, then see if we have something configured in the session.
+        // if not configured, we just use the default default.
+        if (port == -1) {
+            // check for a property and fall back on the default if it's not set.
+            port = props.getIntProperty(MAIL_PORT, props.getDefaultPort());
+            // it's possible that -1 might have been explicitly set, so one last check. 
+            if (port == -1) {
+                port = props.getDefaultPort(); 
+            }
+        }
+    	
+    	// Before we do anything, let's make sure that we succesfully received a host
+    	if ( host == null ) {
+    		host = DEFAULT_MAIL_HOST;
+    	}
+        
+        this.serverHost = host;
+        this.serverPort = port;
+        this.username = username;
+        this.password = password;
+        
+        // make sure we have the realm information 
+        realm = props.getProperty(MAIL_SASL_REALM); 
+        // get an authzid value, if we have one.  The default is to use the username.
+        authid = props.getProperty(MAIL_AUTHORIZATIONID, username);
+        return true; 
+    }
+    
+    
+    /**
      * Create a transport connection object and connect it to the
      * target server.
      *
@@ -232,9 +279,7 @@
      * @exception MessagingException
      */
     protected void getConnectedSocket() throws IOException {
-        if (debug) {
-            debugOut("Attempting plain socket connection to server " + serverHost + ":" + serverPort);
-        }
+        debugOut("Attempting plain socket connection to server " + serverHost + ":" + serverPort);
 
         // check the properties that control how we connect. 
         getConnectionProperties(); 
@@ -290,9 +335,7 @@
                 // if a socket factor is specified, then we may need to fall back to a default.  This behavior
                 // is controlled by (surprise) more session properties.
                 if (props.getBooleanProperty(MAIL_FACTORY_FALLBACK, false)) {
-                    if (debug) {
-                        debugOut("First plain socket attempt failed, falling back to default factory", e);
-                    }
+                    debugOut("First plain socket attempt failed, falling back to default factory", e);
                     socket = new Socket(serverHost, serverPort, localAddress, localPort);
                 }
                 // we have an exception.  We're going to throw an IOException, which may require unwrapping
@@ -303,9 +346,7 @@
                         e = ((InvocationTargetException)e).getTargetException();
                     }
 
-                    if (debug) {
-                        debugOut("Plain socket creation failure", e);
-                    }
+                    debugOut("Plain socket creation failure", e);
 
                     // throw this as an IOException, with the original exception attached.
                     IOException ioe = new IOException("Error connecting to " + serverHost + ", " + serverPort);
@@ -327,9 +368,7 @@
      * @exception MessagingException
      */
     protected void getConnectedSSLSocket() throws IOException {
-        if (debug) {
-            debugOut("Attempting SSL socket connection to server " + serverHost + ":" + serverPort);
-        }
+        debugOut("Attempting SSL socket connection to server " + serverHost + ":" + serverPort);
         // the socket factory can be specified via a protocol property, a session property, and if all else
         // fails (which it usually does), we fall back to the standard factory class.
         String socketFactory = props.getProperty(MAIL_SSL_FACTORY_CLASS, props.getSessionProperty(MAIL_SSL_FACTORY_CLASS, "javax.net.ssl.SSLSocketFactory"));
@@ -342,9 +381,7 @@
 
         while (true) {
             try {
-                if (debug) {
-                    debugOut("Creating SSL socket using factory " + socketFactory);
-                }
+                debugOut("Creating SSL socket using factory " + socketFactory);
 
                 int socketFactoryPort = props.getIntProperty(MAIL_SSL_FACTORY_PORT, -1);
 
@@ -385,9 +422,7 @@
                 // if we're allowed to fallback, then use the default factory and try this again.  We only
                 // allow this to happen once.
                 if (fallback) {
-                    if (debug) {
-                        debugOut("First attempt at creating SSL socket failed, falling back to default factory");
-                    }
+                    debugOut("First attempt at creating SSL socket failed, falling back to default factory");
                     socketFactory = "javax.net.ssl.SSLSocketFactory";
                     fallback = false;
                     continue;
@@ -400,10 +435,7 @@
                         e = ((InvocationTargetException)e).getTargetException();
                     }
 
-                    if (debug) {
-                        debugOut("Failure creating SSL socket", e);
-                    }
-
+                    debugOut("Failure creating SSL socket", e);
                     // throw this as an IOException, with the original exception attached.
                     IOException ioe = new IOException("Error connecting to " + serverHost + ", " + serverPort);
                     ioe.initCause(e);
@@ -450,9 +482,7 @@
      * switching to an SSL socket.
      */
     protected void getConnectedTLSSocket() throws MessagingException {
-        if (debug) {
-            debugOut("Attempting to negotiate STARTTLS with server " + serverHost);
-        }
+        debugOut("Attempting to negotiate STARTTLS with server " + serverHost);
      	// it worked, now switch the socket into TLS mode
      	try {
 
@@ -497,9 +527,7 @@
             getConnectionStreams(); 
      	}
         catch (Exception e) {
-            if (debug) {
-                debugOut("Failure attempting to convert connection to TLS", e);
-            }
+            debugOut("Failure attempting to convert connection to TLS", e);
      	    throw new MessagingException("Unable to convert connection to SSL", e);
      	}
     }
@@ -690,7 +718,9 @@
      * @param value  The string value to output.
      */
     protected void debugOut(String message) {
-        debugStream.println("IMAPStore DEBUG: " + message);
+        if (debug) {
+            debugStream.println("IMAPStore DEBUG: " + message);
+        }
     }
 
     /**
@@ -700,9 +730,11 @@
      * @param e       The received exception.
      */
     protected void debugOut(String message, Throwable e) {
-        debugOut("Received exception -> " + message);
-        debugOut("Exception message -> " + e.getMessage());
-        e.printStackTrace(debugStream);
+        if (debug) {
+            debugOut("Received exception -> " + message);
+            debugOut("Exception message -> " + e.getMessage());
+            e.printStackTrace(debugStream);
+        }
     }
     
     
@@ -738,4 +770,14 @@
     public boolean supportsMechanism(String mech) {
         return authentications.contains(mech); 
     }
+    
+    
+    /**
+     * Retrieve the connection host. 
+     * 
+     * @return The host name. 
+     */
+    public String getHost() {
+        return serverHost; 
+    }
 }
diff --git a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers
index 80f342e..ab30cdf 100644
--- a/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers
+++ b/geronimo-javamail_1.4/geronimo-javamail_1.4_provider/src/main/resources/META-INF/javamail.default.providers
@@ -33,7 +33,9 @@
 protocol=smtp; type=transport; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apache Software Foundation; version=1.0

 protocol=smtps; type=transport; class=org.apache.geronimo.javamail.transport.smtp.SMTPTSransport; vendor=Apache Software Foundation; version=1.0

 protocol=nntp-post; type=transport; class=org.apache.geronimo.javamail.transport.nntp.NNTPTransport; vendor=Apache Software Foundation; version=1.0

+protocol=nntp-posts; type=transport; class=org.apache.geronimo.javamail.transport.nntp.NNTPSSLTransport; vendor=Apache Software Foundation; version=1.0

 protocol=nntp; type=store; class=org.apache.geronimo.javamail.store.nntp.NNTPStore; vendor=Apache Software Foundation; version=1.0

+protocol=nntps; type=store; class=org.apache.geronimo.javamail.store.nntp.NNTPSSLStore; vendor=Apache Software Foundation; version=1.0

 protocol=pop3; type=store; class=org.apache.geronimo.javamail.store.pop3.POP3Store; vendor=Apache Software Foundation; version=1.0

 protocol=pop3s; type=store; class=org.apache.geronimo.javamail.store.pop3.POP3SSLStore; vendor=Apache Software Foundation; version=1.0

 protocol=imap; type=store; class=org.apache.geronimo.javamail.store.imap.IMAPStore; vendor=Apache Software Foundation; version=1.0