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